01-16-2020 07:13 AM
Hi,
I'm building a quarter wave lookup table for sin/cos.
I know in VHDL, that it is possible in design rtl to write a behavioral function and then reference that function to set the values of a ROM, like below, and it will synthesize in Vivado:
-------------------------------------------------------------------------------- -- sin function -------------------------------------------------------------------------------- function generate_sin_rom ( addr_width : natural; data_width : natural; scale_factor: real ) return rom_t is variable sin_rom_v : rom_t; begin for i in 0 to ((2**addr_width) - 1) loop sin_rom_v(i) := to_unsigned(integer(((2.0**data_width)-1.0) * scale_factor * sin((math_pi/2.0) * (real(i) / real(2**addr_width)))), data_width); end loop; return sin_rom_v; end function generate_sin_rom; -------------------------------------------------------------------------------- constant SIN_ROM : rom_t := generate_sin_rom(ADDR_WIDTH, DATA_WIDTH, SCALE_FACTOR); -- Sine quantized generated look-up table begin -------------------------------------------------------------------------------- -- Describes the behavior of a trigonometric sine ROM. -------------------------------------------------------------------------------- Sine_ROM: process(CLOCK) begin if rising_edge(CLOCK) then SINE_Z <= SIN_ROM(to_integer(SIN_ADDR)); end if; end process Sine_ROM;
Is that possible in verilog? If so, how might I go about doing it, and will the vivado synthesis tool handle it?
If it's not possible, are there any alternative ways I could initialize my lookup table without pre-building with .hex files or scripts?
The idea is to make the whole thing a parameterizable IP.
Thanks,
Stephen
01-16-2020 01:53 PM
I am pretty sure (but not 100%) that you can do it in an initial block; put the same kind of for loop in the initial block that sets a value for each value in the lookup function. This will result in an initialized array (at time 0), which can then be dereferenced using sin_rom[sin_addr].
The sysnthesis tool should accept this as initialization of the block memory based ROM...
(But I haven't tried something like this since the XST days, so I don't know for sure that it will work in Vivado).
Avrum
01-16-2020 01:53 PM
I am pretty sure (but not 100%) that you can do it in an initial block; put the same kind of for loop in the initial block that sets a value for each value in the lookup function. This will result in an initialized array (at time 0), which can then be dereferenced using sin_rom[sin_addr].
The sysnthesis tool should accept this as initialization of the block memory based ROM...
(But I haven't tried something like this since the XST days, so I don't know for sure that it will work in Vivado).
Avrum
01-20-2020 10:13 AM - edited 01-20-2020 10:21 AM
@avrumw thanks for the idea.
I put together some verilog code along those lines, and realized that I have another problem: If I want to use a math library to calculate sin/cos, I would have to call the library with something like this:
//////////////////////////////////////////////////////////////// //Behavioral math function package setup //NOTE: Relies on the libmath.so library built into linux //////////////////////////////////////////////////////////////// import "DPI-C" pure function real sin (input real rTheta); import "DPI-C" pure function real cos (input real rTheta); const real pi = 3.141592653589793; //IEEE double precision
I got a synthesis error: [Synth 8-27] DPI function not supported
From what I gather, it generally isn't possible to synthesize DPI calls. But in this special case where I'm only using it to generate initial ROM values, is there any chance that Vivado can handle it, and I'm just missing something?
I suppose in the worst case I can write my lookup table in VHDL (I know that vivado supports the vhdl IEEE math library), but I was hoping to avoid mixed-language simulation.
Thanks,
Stephen
01-20-2020 08:10 PM
I'm not sure why you are trying to work with a DPI function. Verilog and SystemVerilog have trig functions built in - just use $sin(x) and $cos(x) - these accept an angle (x) as a real operand and return a real value. The LRM for both Verilog and SystemVerilog say they are the equivalents of the C functions sin(x) and cos(x) - (I would have to go look at a C manual to remember if these functions take degrees or radians)...
However, I haven't tried these to know if they are synthesizable (as elaboration constants).
Avrum
01-21-2020 06:36 AM
@avrumw well frankly I went in the DPI direction because every google result seemed to point that way! I couldn't find any reference to a built in sin/cos system task.
Also, I couldn't locate anything about $sin/$cos in the SystemVerilog LRM...however when I tried it, it passed Vivado synthesis. For my reference could you kindly tell me what page of the LRM that was on? Just cannot seem to find it.
Will go and build a testbench on this just to make sure it works...
01-21-2020 03:08 PM - edited 01-21-2020 03:09 PM
For my reference could you kindly tell me what page of the LRM that was on?
In the last few versions of the SystemVerilog LRM (IEEE 1800-2012 and 1800-2017) these functions are described in section 20.8.2 "Real math functions".
In the last Verilog LRM (IEEE 1364-2005) they are in section 17.11.2 "Real math functions".
Avrum
01-22-2020 03:47 PM
Much appreciated @avrumw . My LRM copy was evidently horribly outdated. closing as synthesis seemed to pass.