VHDL SINE LUT using type "real"

Status
Not open for further replies.

shaiko

Advanced Member level 5
Joined
Aug 20, 2011
Messages
2,644
Helped
303
Reputation
608
Reaction score
297
Trophy points
1,363
Activity points
18,302
Hello,

I'm trying to design a generic synthesizable SINE LUT in VHDL.
I'm using the "real" type to compute the LUT's values during compile time.

This is my code:

Code:
library ieee ;
	use ieee.std_logic_1164.all ;
	use ieee.numeric_std.all ;
	use ieee.math_real.all ;
 
entity sine_lut is

generic
(
    WIDTH_FRACTION_ANGLE    : natural := 4  ; -- 4 gives us a resolution of 1/16
    WIDTH_FRACTION_RESULT   : natural := 10 
) ;

port 
(
	IN_CLOCK    :   in  std_logic                                                   ;																		    
	IN_ANGLE    :   in  std_logic_vector ( 7 + WIDTH_FRACTION_ANGLE - 1 downto 0 )  ;   -- 90 is 1011010 ( 7 bits ). A sign bit isn't needed ( the user shall exploit the sine symmetry ).	     
            
	OUT_RESULT  :   out std_logic_vector ( WIDTH_FRACTION_RESULT downto 0 )             -- One integer bit + WIDTH_FRACTION_RESULT
) ; 
    
end entity sine_lut ;

architecture rtl_sine_lut of sine_lut is 

type type_lut_sine_real     is array ( 0 to 2 ** ( IN_ANGLE ' length ) - 1 ) of real ;
type type_lut_sine_slv      is array ( 0 to 2 ** ( IN_ANGLE ' length ) - 1 ) of std_logic_vector ( OUT_RESULT ' range ) ;

[COLOR="#FF0000"]signal lut_sine_real    : type_lut_sine_real ;
signal lut_sine_slv     : type_lut_sine_slv ;[/COLOR]

begin 

    generate_sine_lut : for index in 0 to 2 ** ( IN_ANGLE ' length ) - 1
    generate 
                
        lut_sine_real ( index ) <= sin ( real ( index ) * ( MATH_PI / 180.0 ) / ( real ( 2 ** WIDTH_FRACTION_ANGLE ) ) ) ;  -- Multiplying by ( MATH_PI / 180.0 ) converts from degrees to radians. 
        lut_sine_slv ( index )  <= std_logic_vector ( to_unsigned ( integer ( lut_sine_real ( index ) * ( real ( 2 ** WIDTH_FRACTION_RESULT ) ) ) , OUT_RESULT ' length ) ) ;  
    
    end generate ;

    reading_from_memory : process ( IN_CLOCK ) is
    begin 
        if rising_edge ( IN_CLOCK ) then 
            OUT_RESULT <= lut_sine_slv ( to_integer ( unsigned ( IN_ANGLE ) ) ) ;
        end if ;
    end process reading_from_memory ;
 
end architecture rtl_sine_lut ;

Unfortunately,
Quartus can't synthesize type "real" for arguments that are defined as signals. The following error is shown:
Error (10414): VHDL Unsupported Feature error at sine_lut.vhd(29): cannot synthesize non-constant real objects or values
But if I define the arrays as constants I can't use the neat "for loop" method to instantiate their values.

How can I work around this problem ?
 

Yes you can - define it all in an initialisation function:


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
constant sin_rom : type_lut
 
function define_rom return type_lut_sine_slv is
  variable ret_rl : type_lut_sine_real;
  variable ret : type_lut_sine_slv;
begin
  for index in ret'range loop
    ret_rl( index ) := sin ( real ( index ) * ( MATH_PI / 180.0 ) / ( real ( 2 ** WIDTH_FRACTION_ANGLE ) ) ) ;  -- Multiplying by ( MATH_PI / 180.0 ) converts from degrees to radians. 
    ret ( index )  := std_logic_vector ( to_unsigned ( integer ( lut_sine_real ( index ) * ( real ( 2 ** WIDTH_FRACTION_RESULT ) ) ) , OUT_RESULT ' length ) ) ;  
  end loop;
end function;
 
constant rom : type_lut_sine_slv := define_rom;



Please put cheque in the post!
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…