1
\$\begingroup\$

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 ?

\$\endgroup\$
  • \$\begingroup\$ Try 0 to 255 instead of 1 to 200. \$\endgroup\$ – Brian Carlton Aug 5 '17 at 22:35
  • \$\begingroup\$ Your code looks in parallel with Xilinx's single-port write-first RAM example on page 132, but I would try an active-high signal (e.g. en) instead of Reset. \$\endgroup\$ – ahmedus Aug 5 '17 at 23:58
  • \$\begingroup\$ @BrianCarlton, thanks, but there is no problem in array index, see Edit section \$\endgroup\$ – G3ntle_Man Aug 6 '17 at 9:32
  • \$\begingroup\$ @ahmedus thanks but that is not the problem, see Edit section \$\endgroup\$ – G3ntle_Man Aug 6 '17 at 9:48
3
\$\begingroup\$

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.
\$\endgroup\$
1
\$\begingroup\$

I changed my Entity to this :

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 : IN std_logic;
        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);
 Constant 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 rom_style : string;
-- attribute rom_style of LCDMem : signal is "block";
begin

 Process(CLK)
 begin
  if (CLK'Event and CLK = '1') then
    O <= LCDMem(conv_integer(Addr));
  end if;
 end Process;

end Behavier;

Now, XST implements it as a Read-Only Block RAM. maybe useful for someone ...

\$\endgroup\$
  • 3
    \$\begingroup\$ If you think this is the best solution, you may accept your own answer as well. \$\endgroup\$ – ahmedus Aug 7 '17 at 11:11
0
\$\begingroup\$

You should never use resets for RAM. Remember this is put down in hardware, so when you are using a reset signal to control the output of the memory then that behavior is not explicitly defined for the BRAM block. If you want to reset anything surrounding the BRAM block it should be its output registers. So what needs to be done is take the clocked read RAM data and store it in an additional register which can be reset synchronously. Active high is preferred. I would highly suggest adding an additional register process taking:

O_reg <= O;

in a clocked process with sync reset. This will infer output regs on your memory and aid in placement/improve timing.

\$\endgroup\$
0
\$\begingroup\$

You could have also used a BRAM IP and put the array in a coefficient file which goes inside the BRAM.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.