Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] specify a ROM in VHDL based on a generic

Status
Not open for further replies.

frznchckn

Member level 1
Joined
Jul 20, 2010
Messages
36
Helped
4
Reputation
8
Reaction score
4
Trophy points
1,288
Location
California
Activity points
1,521
I need to model a ROM of twiddle factors for an FFT implementation. The FFT is supposed to be parameterized for input data sample size (ie number of samples to have the FFT performed on). This means that the twiddle ROM will be of a varying size.

The perl code below generates the real and imaginary twiddle factors. Basically, how can I initialize ROM locations using the type of expressions below? Is this even possible or do I need to specify the ROM using an external file (I have seen this process in a few locations including Xilinx's XST manual).

Thanks!

$PI = 3.14159_26535_89793_23846_26433_83279_50288_41971_69399_37510;
$PI2 = $PI * 2.;
$K1 = $PI2 / $FFT_SIZE;

for ($i = 0; $i <= ($FFT_SIZE-1); $i++) {

$twiddle_rl[$i] = cos($K1 * $i);
$twiddle_im[$i] = sin($K1 * $i);
}
 

because it is a rom, all you nee to do is declare a constant in VHDL and have a function initialise the contents. I assume you want fixed point?

You can use the math_real package to generate all the values then use the fixed point libraries to convert to fixed point.

Code:
library floatfixlib;
use floatfixlib.fixed_pkg.all;

library ieee;
use ieee.math_real.all;

......

subtype rom_word_t is sfixed(0 downto -15) --16 bit signed range -1 to +1
type rom_t is array(0 to FFT_SIZE-1) of rom_word_t;


function set_cos_rom return rom_t is
	variable ret  : rom_t;
	variable temp : real
	
	constant K1  : real := math_2_pi / real(FFT_SIZE);
begin
	for i in 0 to FFT_SIZE-1 loop
		temp   := cos(K1 * real(i));
		
		ret(i) := to_sfixed(temp, rom_word_t'high, rom_word_t'low);
	end loop;
		
	return ret;
end function set_cos_rom;

--same function for sin.

constant COS_ROM   : rom_t := set_cos_rom;
constant SIN_ROM   : rom_t := set_sin_rom;
 

Thanks, I got it to compile and I see values in my ROM during simulation.

Now, I need to believe that they are the values I need. I've had some trouble finding good documentation on floatfixlib. Could you point me in the right direction?

I'm trying to understand the following 2 lines:

subtype rom_word_t is sfixed(0 downto -15); --16 bit signed range -1 to +1
ret(i) := to_sfixed(temp, rom_word_t'high, rom_word_t'low);

The easiest example is the first cos twiddle value which is 1. For a 16 bit-wide signed value I would, say scale this by 2^14 ending up with 0x4000. However, the first value in my rom using your code is 0x7FFF.

Would you shed some light on this?

Thanks again.:D
 

I suspect the code is more for a DDS.

the difference is that a DDS should use 0x7FFF for +1 and 0x8001 for -1, as that gives a large dynamic range.

for an FFT though, 0x4000 for +1 and 0xC000 for -1 are common. this is because the coefficients "+1" and "-1" are intentionally made very common in the calculations. multiplication by 0x4000 or 0xC000 are both simple operations, while multiplication by 0x7FFF is more difficult.

using the above code, you can scale the values to get +1 = 0x4000 and -1 = 0xC000.

as always, ROM compression can be done, as the sine function can be defined with only 1/4th of a cycle.
 

    frznchckn

    Points: 2
    Helpful Answer Positive Rating
frznchckn said:
Thanks, I got it to compile and I see values in my ROM during simulation.

Now, I need to believe that they are the values I need. I've had some trouble finding good documentation on floatfixlib. Could you point me in the right direction?

I'm trying to understand the following 2 lines:

subtype rom_word_t is sfixed(0 downto -15); --16 bit signed range -1 to +1
ret(i) := to_sfixed(temp, rom_word_t'high, rom_word_t'low);

The easiest example is the first cos twiddle value which is 1. For a 16 bit-wide signed value I would, say scale this by 2^14 ending up with 0x4000. However, the first value in my rom using your code is 0x7FFF.

Would you shed some light on this?

Thanks again.:D

the great thing about the fixed point libraries is that it tells you instantly what power of 2 the bit represents. It also allows to to easily convert real types to fixed point - another bonus.

The problem you have is that I did not specify enough bits to represent 1. In all signed systems, the range is always -n to (n-1). so the system I gave you it will represent -1 to (1 - 2^-15), which is why the first result (that you expected to be 0x8000) was 0x7FFF, as this is as close to 1 as it can get without overflowing to -1.

To actually include 1 in the range, you need to specify the type as:
subtype rom_word_t is sfixed(1 downto -15); --16 bit signed range -2 to +(2-2^-15)

It is simply integer mathmatics, but with a much easier to understand representation than having a load of bit and having an implied division by 2^n.

This VHDL package is new, and so not many people are using it. You can download VHDL 93 compatible versions (so you can compile them with most synthesisors) from **broken link removed**. Or ask more questions on here or of me. Ive just finished a large project using it and it works a treat (lots of convolvers, downsamplers and upsamplers)

The second line you questioned:
ret(i) := to_sfixed(temp, rom_word_t'high, rom_word_t'low);

is converting a floating point number (in VHDL real types are not bit array types) to an "sfixed". sfixed is a type that is an array of bits. The function to_sfixed converts the real "temp", which is not a bit array type, and it is floating point, into fixed point. The 'high and 'low bits are specifying the length of the fixed point output. In the case from the quote these values are 0 and -15.
 

    frznchckn

    Points: 2
    Helpful Answer Positive Rating
Thanks for the explanations, I finally did find the library documentation and am getting familiar with it.

You said you just finished a design using this library. May I ask what tool flow / target device you had? My design target is initially a Xilinx FPGA and then an to-be-determined CMOS technology. I'm concerned that using this lib may paint me into a corner down the road. What's your opinion on this?
 

It is part of the VHDL 2008 standard, so should get better supported as vendors get up to speed. As a library, it tidies up crappy things you have to do with the numeric_std library when doing fixed point, mainly the maintining of bit alignment. Other than that and some nice conversion functions, it isnt any different at the bit level.

I have used Modelsim + Altera Quartus all the way through. All inferences have worked, including RAMs and multiplers. No problems for me.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top