Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)

sin cos LUT in HEX file

Altera_Forum
Honored Contributor II
5,481 Views

Hello, 

 

I'm need to load a ROM with a cos and sin lookup table. I know Quartus have an auto fill cell function built in but does it support sin and cos? Or does I need a 3d-party program to do that? Also, how do I convert the cos answer to HEX/BIN? For example cos(25)= 0,9063 how do I translate that to HEX? 

 

Thanks for your answer :)
0 Kudos
16 Replies
Altera_Forum
Honored Contributor II
3,184 Views

I suspect you'll need to write a program (probably in C) for your host to generate the hex data in the required format.

0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

Where is your source from? in VHDL, you can infer a rom from a constant, and you can populate the constant from a sin/cos function.

0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

I'm using Quartus MegaWizard to generate a ROM in VHDL. I doesn't really understand what you want me to do, could you be a little more specific and explain a bit more?

0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

Have a read of this document, page 13-13: http://www.altera.co.uk/literature/hb/qts/qts_qii51007.pdf 

 

It explains how to write your VHDL code so that quartus can infer a rom without having to use the megawizard. This way you can use a custom initialisation function to populate the rom contents.
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

If you prefer to use a RAM MegaFunction with an external initialization file, it's probably convenient to use a *.mif instead of *.hex file. It's formatted text and can be easily generated in a spreadsheet calculator.

0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

 

--- Quote Start ---  

Have a read of this document, page 13-13: http://www.altera.co.uk/literature/hb/qts/qts_qii51007.pdf 

 

It explains how to write your VHDL code so that quartus can infer a rom without having to use the megawizard. This way you can use a custom initialisation function to populate the rom contents. 

--- Quote End ---  

 

 

Ok I think i understand what you mean. But when I will initiate the ROM with some sort of funktion, i will need to use some other program to do that, right? 

 

 

 

--- Quote Start ---  

If you prefer to use a RAM MegaFunction with an external initialization file, it's probably convenient to use a *.mif instead of *.hex file. It's formatted text and can be easily generated in a spreadsheet calculator. 

--- Quote End ---  

 

 

So say I use Excel to do my calculation and convert it to a *.mif file. How about the answers in the calculation? They are real numbers, will they automatic be converted?
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

 

--- Quote Start ---  

Ok I think i understand what you mean. But when I will initiate the ROM with some sort of funktion, i will need to use some other program to do that, right? 

--- Quote End ---  

Not necessarily. There is a cos function in VHDL that can be used to directly calculate the correct values. 

--- Quote Start ---  

So say I use Excel to do my calculation and convert it to a *.mif file. How about the answers in the calculation? They are real numbers, will they automatic be converted? 

--- Quote End ---  

No, you will need to use excel functions to convert them to decimal or hexadecimal first.
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

I looked at the function and I found this: 

 

TYPE ROM IS ARRAY(0 TO 511) OF UNSIGNED(8 DOWNTO 0); FUNCTION INIT_ROM RETURN ROM IS VARIABLE romvar: ROM; VARIABLE x: REAL; begin for I in 0 TO 511 loop x:= SIN(real(i)*MATH_PI/real(511)); romvar(i):=CONV_UNSIGNED(INTEGER(x*real(511)),9); end loop; return romvar; end;  

 

I think I understand how the function works but I don't understand how to interface the ROM. 

The ROM I want have the cos/sin value for 0-90 degrees with a resolution of 4096 samples.  

So do i set the array size to 0 to 4096 and the function will create a ROM of that size.  

But how do I do when I want to read a certain address?
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

have a look at the coding guidelines, as I mentioned in post# 5

0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

I have understand how the ROM works and how to interface it. Now it is the SIN function that gives me trouble.  

I have this code: 

-- Quartus II VHDL Template -- Dual-Port ROM library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; USE ieee.std_logic_arith.all; USE ieee.math_real.all; entity dual_port_rom is generic ( DATA_WIDTH : natural := 14; ADDR_WIDTH : natural := 4096 ); port ( clk : in std_logic; addr_a : in integer range 0 to 2**ADDR_WIDTH - 1; q_a : out std_logic_vector((DATA_WIDTH -1) downto 0) ); end entity; architecture rtl of dual_port_rom is subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0); TYPE ROM IS ARRAY((ADDR_WIDTH-1) downto 0) OF word_t; FUNCTION INIT_ROM RETURN ROM IS VARIABLE romvar: ROM; VARIABLE x: REAL; begin for I in 0 TO 2**ADDR_WIDTH-1 loop x:= SIN(real(i)*MATH_PI/real(ADDR_WIDTH-1)); romvar(i):= std_logic_vector(to_unsigned(x*real(ADDR_WIDTH-1),DATA_WIDTH)); end loop; return romvar; end; -- Declare the ROM signal and specify a default value. Quartus II -- will create a memory initialization file (.mif) based on the -- default value. signal rom : memory_t := romvar; begin process(clk) begin if(rising_edge(clk)) then q_a <= rom(addr_a); end if; end process; end rtl;  

 

It is the same code that i posted before except that I have change to bit vectors instead of integers. But I get an error on the line: 

romvar(i):= std_logic_vector(to_unsigned(x*real(ADDR_WIDTH-1),DATA_WIDTH)); 

It say it can't determine definition of operator ""*"". 

I have tried to do some sort of workaround but I can't get it to work:  

Does anybody knows why?
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

first of all, remove the line "use ieee.std_logic_arith.all" 

It is non-standard and conflicts with numeric_std. 

 

Second, you cannot convert a real type to an unsigned type, you need to convert it to integer first: 

 

romvar(i):= std_logic_vector(to_unsigned( integer(x*real(ADDR_WIDTH-1)) ,DATA_WIDTH));
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

Thank you that helped. But now when I run the simulation the output only differs on the 4 MSb the rest are zero. I want an output of 12-14 bit resolution. How do I get that?

0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

I assume you must have changed the code to run a simulation, as there are many syntax errors. 

Once I fixed them, it has populated the ROM correctly, with all bits used.
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

Ooo sorry yes I have change it to work and add some calculations so the value 0-4096 represent 0-90 degrees. When I run the simulation I get the max value of 00000000000110. 

Here is the code I use for simulation: 

-- Quartus II VHDL Template -- Dual-Port ROM library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; USE ieee.math_real.all; entity LUT_ROM is generic ( DATA_WIDTH : natural := 14; ADDR_WIDTH : natural := 12 ); port ( clk : in std_logic; addr_a : in natural range 0 to 2**ADDR_WIDTH - 1; q_a : out std_logic_vector((DATA_WIDTH -1) downto 0) ); end entity; architecture rtl of LUT_ROM is subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0); TYPE ROM IS ARRAY((2**ADDR_WIDTH-1) downto 0) OF word_t; FUNCTION INIT_ROM RETURN ROM IS VARIABLE romvar: ROM; VARIABLE x, i: REAL; begin for samp in 0 TO 2**ADDR_WIDTH-1 loop i := real(0.02197)*real(samp)*MATH_PI/real(180); x:= SIN(real(i)*MATH_PI/real(ADDR_WIDTH-1)); romvar(samp):= std_logic_vector(to_unsigned(integer(x*real(ADDR_WIDTH-1)),DATA_WIDTH)); end loop; return romvar; end; -- Declare the ROM signal and specify a default value. Quartus II -- will create a memory initialization file (.mif) based on the -- default value. signal rom_val : ROM := INIT_ROM; begin process(clk) begin if(rising_edge(clk)) then q_a <= rom_val(addr_a); end if; end process; end rtl;  

 

Thank you for your help :)
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

I would recomend making rom_val a constant rather than a signal - its never going to be updated, so needs to be a constant really. 

 

But your error is because you put ADDR_WIDTH in the init_rom, rather than 2**ADDR_WIDTH.
0 Kudos
Altera_Forum
Honored Contributor II
3,184 Views

Thank you, it looks like it works now.

0 Kudos
Reply