A
Acciduzzu
Guest
Hi all,
I'd like to bring a more delicate issue to your attention, regarding a synthesis limitation in VHDL,
or in my tool. Maybe I'm lucky and I can even get some help from the VHDL gurus around.
I am trying to develop a number of parametrizable models for various DSP algorithms, including FFT
and CORDIC. The implementations of these algorithms require some look-up tables, for instance an
arctan table for CORDIC and a sine table for the tweedle factors of the FFT.
In order for the design to be generic, the look-up tables will have to be parametrizable, depending
on the generic parameters of the design, like datapath bitwidth or FFT size. The standard solution
to this problem is to write a script which generates a parametrized configuration file. Whenever you
want to change one of the parameters a new has to be generated. This can hardly be called a generic
solution.
The ideal scenario is to let the synthesis tool build these tables, based on the parameters you
supply. This is possible in VHDL using the so called constant functions. As far as I know, Verilog
tools do not support them yet, although they have been added in the Verilog 2001 standard.
Basically, constant functions are functions called when defining a constant, like in the example
below, for a pipeline stage of the CORDIC algorithm. However, since we need to work with real
numbers to compute the arctangent, the synthesis tool (Synopsys DC) will complain about that. This
should not happen, since the real numbers are not used in a synthesizable context. This is where my
knowledge of VHDL stops. Is there any workaround possible? If I don't use real types, everything
goes well and I can assign the value returned by the function to my constant.
--------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use work.cordic_pack.all;
entity cordic_pipestage is
generic(
INDEX : integer -- index of the pipeline stage
);
port(
clk : in std_logic;
rst : in std_logic;
en : in std_logic;
-- COORD_BITS and ANGLE_BITS are defined in cordic_pack
x_in : in signed(COORD_BITS-1 downto 0);
y_in : in signed(COORD_BITS-1 downto 0);
z_in : in signed(ANGLE_BITS-1 downto 0);
x_out : out signed(COORD_BITS-1 downto 0);
y_out : out signed(COORD_BITS-1 downto 0);
z_out : out signed(ANGLE_BITS-1 downto 0)
);
end entity;
architecture rtl of cordic_pipestage is
-- This function returns atan(1/2^n) values on a specified number of bits
function get_arctan(num_bits : natural; index : natural) return signed is
variable atan_int : integer;
variable result : signed(num_bits-1 downto 0);
begin
atan_int := integer(ROUND(ATAN(1.0/(2**real(index)))*(2**real(num_bits-1))));
result := TO_SIGNED(atan_int, num_bits);
return result;
end function;
-- the arctangent associated with the current index
-- here is where we call the constant function
constant atan : signed(ANGLE_BITS-1 downto 0) := get_arctan(ANGLE_BITS, INDEX);
begin
-- Architecture body goes here
end architecture;
--------------------------------------------------------------------------------------
I would also appreciate any comments on the topic of generic/reusable constant/table generation.
Regards,
Acciduzzu
I'd like to bring a more delicate issue to your attention, regarding a synthesis limitation in VHDL,
or in my tool. Maybe I'm lucky and I can even get some help from the VHDL gurus around.
I am trying to develop a number of parametrizable models for various DSP algorithms, including FFT
and CORDIC. The implementations of these algorithms require some look-up tables, for instance an
arctan table for CORDIC and a sine table for the tweedle factors of the FFT.
In order for the design to be generic, the look-up tables will have to be parametrizable, depending
on the generic parameters of the design, like datapath bitwidth or FFT size. The standard solution
to this problem is to write a script which generates a parametrized configuration file. Whenever you
want to change one of the parameters a new has to be generated. This can hardly be called a generic
solution.
The ideal scenario is to let the synthesis tool build these tables, based on the parameters you
supply. This is possible in VHDL using the so called constant functions. As far as I know, Verilog
tools do not support them yet, although they have been added in the Verilog 2001 standard.
Basically, constant functions are functions called when defining a constant, like in the example
below, for a pipeline stage of the CORDIC algorithm. However, since we need to work with real
numbers to compute the arctangent, the synthesis tool (Synopsys DC) will complain about that. This
should not happen, since the real numbers are not used in a synthesizable context. This is where my
knowledge of VHDL stops. Is there any workaround possible? If I don't use real types, everything
goes well and I can assign the value returned by the function to my constant.
--------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use work.cordic_pack.all;
entity cordic_pipestage is
generic(
INDEX : integer -- index of the pipeline stage
);
port(
clk : in std_logic;
rst : in std_logic;
en : in std_logic;
-- COORD_BITS and ANGLE_BITS are defined in cordic_pack
x_in : in signed(COORD_BITS-1 downto 0);
y_in : in signed(COORD_BITS-1 downto 0);
z_in : in signed(ANGLE_BITS-1 downto 0);
x_out : out signed(COORD_BITS-1 downto 0);
y_out : out signed(COORD_BITS-1 downto 0);
z_out : out signed(ANGLE_BITS-1 downto 0)
);
end entity;
architecture rtl of cordic_pipestage is
-- This function returns atan(1/2^n) values on a specified number of bits
function get_arctan(num_bits : natural; index : natural) return signed is
variable atan_int : integer;
variable result : signed(num_bits-1 downto 0);
begin
atan_int := integer(ROUND(ATAN(1.0/(2**real(index)))*(2**real(num_bits-1))));
result := TO_SIGNED(atan_int, num_bits);
return result;
end function;
-- the arctangent associated with the current index
-- here is where we call the constant function
constant atan : signed(ANGLE_BITS-1 downto 0) := get_arctan(ANGLE_BITS, INDEX);
begin
-- Architecture body goes here
end architecture;
--------------------------------------------------------------------------------------
I would also appreciate any comments on the topic of generic/reusable constant/table generation.
Regards,
Acciduzzu