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.

Xilinx ROM inference not working using VHDL

Status
Not open for further replies.

GhostInABox

Junior Member level 2
Joined
Sep 3, 2009
Messages
22
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,543
I have the following VHDL implementation of a 4-tap FIR filter , I have looked at the VIVADO user guide on ROM generation , while the code from the user guide works i dont see any ROM's generated in my design when i used it.

1. I dont know if it makes sense but i am defining a ROM that has singed values , this makes it easy for me to specify values in decimal form,

2. I would like to load the coefficients from the ROM

3. Do i have to have the ROM in a seperate module for the inference to work


Thanks in advance


Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
package temp is
type tapType is array (integer range <>) of signed(7 downto 0);
end package temp;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

use work.temp.all;

entity FIR_SLOW2 is
port( clk : in std_logic;
en : in std_logic;
reset : in std_logic;
input : in signed(7 downto 0);
output : out signed(7 downto 0));
end FIR_SLOW2;

architecture Behavioral of FIR_SLOW2 is


signal tap : tapType(3 downto 0);
signal coefficent : tapType(3 downto 0);
type tapType_internal is array (integer range <>) of signed(15 downto 0);
signal tap_internal : tapType_internal(3 downto 0);
signal add3 : signed(17 downto 0);
signal data : signed(7 downto 0 );
signal addr : std_logic_vector(3 downto 0);

type rom_type is array (3 downto 0) of signed (7 downto 0);
signal ROM : rom_type:= (to_signed(2,8),to_signed(2,8),to_signed(2,8),to_signed(2,8));
   
ATTRIBUTE rom_style : STRING;
ATTRIBUTE rom_style OF ROM : SIGNAL IS "BLOCK";

signal data1 : signed(7 downto 0 );
   
begin

process (clk)
 begin
    if (clk'event and clk = '1') then
        if (en = '1') then
            data <= ROM(to_integer(unsigned(addr)));
        end if;
    end if;
 end process;

coefficent(0)  <= ROM(0);--to_signed(8,8);
coefficent(1)  <= ROM(1);--to_signed(10,8);
coefficent(2)  <= ROM(2);--to_signed(4,8);
coefficent(3)  <= ROM(3);--to_signed(6,8);

tap_proc:process(reset,clk)
begin
if(reset = '1') then
    for i in 0 to 3 loop
        tap(i)  <= to_signed(0,8);
    end loop;
    output <= to_signed(0,8);
elsif(rising_edge(clk)) then
    for i in 3 downto 1 loop
        tap(i) <= tap(i-1);
    end loop;
    tap(0) <= input;
    output <= add3(17 downto 10);
end if;
end process;

process(tap,coefficent)
begin
    for i in 0 to 3 loop
     tap_internal(i)  <= tap(i) * coefficent(i);
    end loop;
end process;

process(tap,tap_internal)

variable add1 : signed(16 downto 0);
variable add2 : signed(16 downto 0);

begin

add1 := resize(tap_internal(0),17) + resize(tap_internal(1),17);
add2 := resize(tap_internal(2),17) + resize(tap_internal(3),17);
add3 <= resize(add1,18) + resize(add2,18);
end process;

end Behavioral;
 

You have to code it in a way that fits the block RAM if you want a ROM, which usually means it has to have a registered address/write_enable/etc. otherwise it ends up being sucked into the LUTs as a bunch of constants, which end up getting optimized.

I personally never try to infer stuff like ROMs or RAMs, I normally just instantiate the core along with a script/hand_written memory file to initialize the ROM.
 

Below code lines prevent ROM inference because ROM memory locations can be only read out sequentially in a clocked process, at best two values per clock cycle if the FPGA family supports dual port RAM/ROM.

Code:
coefficent(0)  <= ROM(0);--to_signed(8,8);
coefficent(1)  <= ROM(1);--to_signed(10,8);
coefficent(2)  <= ROM(2);--to_signed(4,8);
coefficent(3)  <= ROM(3);--to_signed(6,8);

In case of a FIR filter, ROM coefficients are possible with sequential filter topology where the sampling clock is a fraction of the system clock. Otherwise coefficient storage in registers respectively fixed constants compiled into the hardware are the only options.
 

@ads-ee i am learning fast that inferring blocks that you want is painful :(... I spend a bunch of time trying to infer a ROM

@FvM and you are right in pointing out why it wont infer, i dont know what i was thinking when i wrote that piece of code, i totally forgot that a ROM element can only give out one value per clock cycle. I guess if I myself dont understand how the component works there is no hope for the compiler....

As i am not designing a sequential filter i guess there are 2 options that i saw , i am just wondering if one of them is better.

Option 1

Initialize a set of registers to the coefficient value.

in Xilnx tools do i need to specify a INIT property for registers or is it just enough to specify the value at reset time and the tool can infer that i want that value when the device starts up

i.e

Code:
process(clk)
begin 
    if( reset = '1')
        coefficent(0) <= to_signed( 10,8);
    elsif( rising_edge(clk) then
         coefficent(0) <= to_signed( 10,8);
   end if 
    
end process

Option 2
if i write code like this , this should mean that the coefficent(0) is tied to a fixed value ( an 8 bit vector of VDD and GND)

Code:
coefficent(0)  <= to_signed(10,8);

Option 2 would not need registers but the coefficet signal will be directly tied to the multiplier
 

Xilinx will initialize FFs with the values you have in the reset code. This is done during configuration before the done pin goes high (using default settings of bitgen). There is also the possibility that the FFs may end up being removed as they contain a static value that never changes. I've seen this happen before with FFs that contain a static value.

The second method will result in all the coefficients being sucked into the lookup tables that make up the rest of the logic as they are all static values.

You might be surprised to find out that both methods result in the same circuit. I don't know if this will happen in this case, as I create ROMs using an IP core and supplying the memory file to initialize the contents.
 
@ads-ee

Well I dont think a ROM is suitable in this specific problem, and I understood that after realizing that it was a clocked element that would not give me 4 coefficient values at the same time.

I have done ASIC in the past so i thought

Code:
coefficent(0)  <= to_signed(10,8);

would give me values that are tied to GND and VDD. But since we are talking about FPGA's, yes i guess it will be implemented in LUT's , because after all a LUT is memory right and the value can be accessed without clocking it.

There is also the possibility that the FFs may end up being removed as they contain a static value that never changes. I've seen this happen before with FFs that contain a static value.

I think this is perfectly fine and i am not surprised if it got optimized away because , the actual value is in a LUT which is fed to a redundant register which we use , so the tool just gets rid of the register. and both of the implementations i talked about result in the same circuit realization.

Thank you for your comments i am learning every post :)
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top