Why isn't this VHDL inferring BRAM in XST?
Question
I have an array of vectors that I want to be stored in Block RAM on a Virtex-5 using ISE 13.4. It is 32Kb which should fit in 1 BRAM but it is all being stored in logic. My system uses an AMBA APB bus so I check for a select line and an enable line. Please help me understand why this code isn't inferring a BRAM. Note: this is a dummy example which is simpler to understand and should help me with my other code.
architecture Behavioral of top is
type memory_array is array (63 downto 0) of std_logic_vector(31 downto 0);
signal memory : memory_array;
attribute ram_style: string;
attribute ram_style of memory : signal is "block";
begin
process(Clk)
begin
if(rising_edge(Clk)) then
if(Sel and Wr_en and Enable) = '1' then
memory(to_integer(Paddr(5 downto 0))) <= Data_in;
elsif(Sel and not Wr_en and Enable) = '1' then
Data_out <= memory(to_integer(Paddr(5 downto 0)));
end if;
end if;
end process;
end Behavioral;
I declare the ram_style
of the array as block
but the XST report says: WARNING:Xst:3211 - Cannot use block RAM resources for signal <Mram_memory>. Please check that the RAM contents is read synchronously.
It appears that the problem lies in a read_enable condition, but the Virtex 5 User Guide makes it sound like there is an enable
and a write_enable
on the BRAM hard blocks. I could drive the output all the time, but I don't want to and that would waste power. Any other ideas?
Solution 3
I tried many different combinations and here is the only one I got to work:
en_BRAM <= Sel and Enable;
process(Clk)
begin
if(rising_edge(Clk)) then
if(en_BRAM = '1')then
if(Wr_en = '1') then
icap_memory(to_integer(Paddr(5 downto 0))) <= Data_in;
else
Data_out <= icap_memory(to_integer(Paddr(5 downto 0)));
end if;
end if;
end if;
end process;
So I think the enable needs to be on the whole RAM and it can only be 1 signal. Then the write enable can also only be 1 signal and the read has to be only an else
statement (not if/elsif
). This instantiates a BRAM according to XST in ISE 13.3 on Windows 7 64-bit.
OTHER TIPS
Your logic may not match how your device's BRAM works (there are various limitations depending on the device). Usually, the data_out
is updated on every clock cycle the RAM is enabled for, not just "when not writing" - try this:
process(Clk)
begin
if(rising_edge(Clk)) then
if(Sel and Enable) = '1' then
Data_out <= memory(to_integer(Paddr(5 downto 0)));
if wr_en = '1' then
memory(to_integer(Paddr(5 downto 0))) <= Data_in;
end if;
end if;
end if;
end process;
I moved the Data_out assignment "upwards" to make it clear that it gets the "old" value - that's the default behaviour of the BRAM, although other styles can also be set up.
Alternatively, the tools may be being confused by the sel
and enable
and write
all in a single if
statement - this is because they are mainly "template matching" rather than "function matching" when inferring BRAM. You may find that simply splitting out an "enable if" and a "write if" (as I did above) whilst keeping the rest of the functionality the same is sufficient to make the synthesiser do what is required.
If you are using Xilinx's XST then you can read all about inferring RAMs in the docs (page 204 onwards of my XST user guide - the chapter is called "RAM HDL Coding techniques")
Use the appropriate macro for the BRAM block on your device? I found that to work much better than relying on the synthesis tool not beeing stupid.