Electronic – Why Xilinx ISE doesn’t infer Block Ram for this Array

fpgaiseramvhdlxilinx

I have an Entity that has an array type as below :

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

Entity LCD_Memory is
  port (CLK, Reset, WR : IN std_logic;
        I : IN std_logic_vector(7 Downto 0); 
        Addr : IN std_logic_vector(7 Downto 0);

        O : OUT std_logic_vector(7 Downto 0));
End LCD_Memory;

Architecture Behavier of LCD_Memory is
 Type LCD_Memory_Array is Array(1 to 200) of std_logic_vector(7 Downto 0);
 Signal LCDMem : LCD_Memory_Array :=

          ("01010000", "01010010", "01001111", "01000111", "01010010", "01000001", "01001101", "00100000", -- Line_PK - 1
           "10110000", "00100000", "01001011", "01000101", "01011001", "00100000", "00111010", "00100000", -- Line_PK - 9

           "01000101", "01001110", "01010100", "01000101", "01010010", "00100000", "01010010", "01010101", -- Line_GM - 17
           "01001110", "00100000", "01001101", "01001111", "01000100", "01000101", "00100000", "00111010", -- Line_GM - 25

           "01000101", "01001110", "01010100", "01000101", "01010010", "00100000", "01010010", "01010101", -- Line_GD - 33
              "01001110", "00100000", "01000100", "01000101", "01001100", "01000001", "01011001", "00111010", -- Line_GD - 41

           "01010010", "01010101", "01001110", "10110000", "01000100", "00100000", "00100000", "00100000", -- Line_RD - 49        

           "01010010", "01010101", "01001110", "10110000", "01001110", "00100000", "00100000", "00100000", -- Line_RN - 57

           "01000100", "01001111", "01001110", "01000101", "00100000", "00100000", "00100000", "00100000", -- Line_DN - 65

           "01001101", "01000101", "01001101", "01001111", "01010010", "01011001", "00100000", "00111010", -- Line_Mem - 73
           "01000001", "01000011", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_AC - 81
           "01000100", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_DR - 89
           "01001001", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_IR - 97
           "01010100", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_TR - 105
           "01000001", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_AR - 113
           "01001001", "01001110", "01010000", "01010010", "00100000", "00111010", "00100000", "00100000", -- Line_INPR - 121
           "01001111", "01010101", "01010100", "01010010", "00100000", "00111010", "00100000", "00100000", -- Line_OUTR - 129

           "01001001", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_I - 137
           "01010011", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_S - 145
           "01000101", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_E - 153
           "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_R - 161
           "01001001", "01000101", "01001110", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_IEN - 169
           "01000110", "01000111", "01001001", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_FGI - 177
           "01000110", "01000111", "01001111", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_FGO - 185
           "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000"); -- Null_1 - 193
--            "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000"); -- Null_2 - 201

 attribute ram_style : string;
 attribute ram_style of LCDMem : signal is "block";
begin

 Process(CLK)
 begin
  if (CLK'Event and CLK = '1') then
   if Reset = '0' then
     if WR = '1' then
      LCDMem(conv_integer(Addr)) <= I;
      O <= I;
     else
      O <= LCDMem(conv_integer(Addr));
     end if;
    end if;
  end if;
 end Process;

end Behavier;

I want to put this array in a Block RAM to reduce used LUTs, but when I synthesize this code, XST is unable to infer a Block RAM and shows this warning :

INFO:Xst – HDL ADVISOR – Unable to extract a block RAM for signal
. The read/write synchronization appears to be READ_FIRST
and is not available for the selected family.
A distributed RAM will usually be created instead. To take advantage
of block RAM resources, you may want to revisit your RAM
synchronization or check available device families.

But this code is in write-first mode !. I have another Memory that is exactly same as this and XST extracted a Block Ram for it.

This RAM should be read-only ( like a ROM ) so I have mapped Reset, WR and I signals to '0'. Is it the reason ?

I`m using XIlinx Spartan 2 XC2S50 FPGA Chip, it supports Write-First mode for Block Rams. what changes I should made on my entity to get work ?

Edit :

When I set this Entity as a Top Module, XST implement it as a Block Ram. I think there is no problem in the entity, the problem is that Reset, WR, and I are mapped to '0', now the question is how to use a Block RAM as a Block ROM in Write-First mode ?

Best Answer

Maybe something like that :

Process(CLK)
 begin
  if (CLK'Event and CLK = '1') then

     O <= LCDMem(conv_integer(Addr));

     if WR = '1' then
      LCDMem(conv_integer(Addr)) <= I;
     end if;

    end if;
  end if;
 end Process;
  • There are hardware read and write ports in block RAMs. Read occurs at the same time as writes.
  • You can swap the read and writes parts above if ISE still complains about "read first", there are also attributes, You may try "no_rw_check" if you don't care about having direct propagation of data between reads and writes.
  • And of course, if it is a ROM, you can entirely discard the write part.
Related Topic