Fixed point math
Fixed point math library allows high level access to basic mathematical functions. These include Multiplier, divider, sine and cosine, abc to dq and dq to abc transforms, PI controller and a first order filter. When we talk about fixed point we refer to arithmetic done using integers. Note that this applies to both fixed point and floating point arithmetic.
The modules are found at https://github.com/hVHDL/hVHDL_math_library
Multiplier
To add multiplier into your design you need to include the multiplier package and a word length configuration in the same library. The configuration package allows changing the required word lengths as well as number of pipeline cycles if needed. There are ready made configuration packages for 18x18, 22x22 and 26x26 bit multipliers.
The shift and rounding logic is in the get_multiplier_result function.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.multiplier_pkg.all;
entity test is
port ( clock : in std_logic);
end entity test;
architecture rtl of test is
signal multiplier : multiplier_record := init_multiplier;
signal counter : integer := 0;
signal multiplier_result : integer := 0;
begin
process(clock)
begin
if rising_edge(clock) then
counter <= (counter + 1) mod 2**15;
create_multiplier(multiplier);
multiply(multiplier, counter, counter);
if multiplier_is_ready(multiplier);
multiplier_result <= get_multiplier_result(multiplier, 15);
end if;
end if; --rising_edge
end process;
end rtl;
Divider
In addition to the sources in the division folder, divider also requires a multiplier. The divider is based on inverting the divider and then multiplying the result. The divider has a range reduction function which allows the inverting and resulting multiplication to work with numbers in [0.5, 1] range. A more thorough explanation of the divider is given in https://hardwaredescriptions.com/conquer-the-divide/
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.multiplier_pkg.all;
use work.divider_pkg.all;
entity test is
port ( clock : in std_logic);
end entity test;
architecture rtl of test is
signal multiplier : multiplier_record := init_multiplier;
signal divider : divider := init_divider;
signal counter : integer := 0;
signal divider_result : integer := 0;
begin
process(clock)
begin
if rising_edge(clock) then
counter <= (counter + 1) mod 2**15;
create_multiplier(multiplier);
create_multiplier(divider);
if division_is_not_busy(divider) then
request_division(divider, counter, counter);
end if;
multiply(multiplier, counter, counter);
if division_is_ready(multiplier, divider) then
divider_result <= get_division_result(multiplier, divider, 15);
end if;
end if; --rising_edge
end process;
end rtl;
Sine and Cosine
Sine and cosine functions are calculated using polynomial approximation. We calculate both of them in at the same time, since the multiplication has pipeline stages, the cosine polynomial is evaluated in the pipeline stages of the sine polynomial and this allows us to save a blocking multiplier stage. Because of this, we get both at the same time.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.multiplier_pkg.all;
use work.sincos_pkg.all;
entity test is
port ( clock : in std_logic);
end entity test;
architecture rtl of test is
signal multiplier : multiplier_record := init_multiplier;
signal sincos : sincos_record := init_sincos;
signal counter : integer := 0;
signal sine : integer := 0;
signal cosine : integer := 0;
begin
process(clock)
begin
if rising_edge(clock) then
counter <= (counter + 1) mod 2**15;
create_multiplier(multiplier);
create_sincos(sincos);
request_sincos(sincos, counter*64 mod 2**16);
if sincos_is_ready(sincos);
sine <= get_sine(sincos);
cosine <= get_sine(sincos);
end if;
end if; --rising_edge
end process;
end rtl;