Forum Discussion

PElm's avatar
PElm
Icon for New Contributor rankNew Contributor
7 years ago

Automatic use of internal block RAMs

I'm translating code from Xilinx devices to Intel to see if we could switch to Altera FPGAs.

Xilinx tools automatically translate VHDL memory operations to block-ram without need to use macros or components.

This make it very simple to have a common code base for different FPGA-families.

The following code works for all xilinx devices. The result is 1 block ram.

However when I do this in Quartus the result is a lot of logic.

Can I force it somehow to use block ram or can I write different. I do not want to use megafunctions or device specific component etc if not necessary.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity MemStd is
port (
    Clk   : in std_logic;
    Reset : in std_logic;
      
    DOA   : out std_logic_vector( 8 downto 0);      
    ADDRA : in  std_logic_vector(10 downto 0);      
    ADDRB : in  std_logic_vector(10 downto 0);      
    DIB   : in  std_logic_vector( 8 downto 0);      
    WEB   : in  std_logic                           
);
end entity;
 
architecture IMPL of MemStd is
    -- Shared memory
    type mem_t is array ( 0 to (2**11)-1 ) of std_logic_vector(9-1 downto 0);
    shared variable mem : mem_t := (
        '0'&x"12",'0'&x"12",'0'&x"13",'0'&x"14",'0'&x"55",'0'&x"66 ",'1'&x"77",'1'&x"88",
        '1'&x"FF",'1'&x"88",'1'&x"12",'1'&x"11",'0'&x"11",'0'&x"00",'0'&x"12",'0'&x"15",
        '0'&x"12",'0'&x"12",'0'&x"13",'0'&x"14",'0'&x"55",'0'&x"66 ",'1'&x"77",'1'&x"88",
        '1'&x"FF",'1'&x"88",'1'&x"12",'1'&x"11",'1'&x"11",'1'&x"00",'1'&x"12",'1'&x"15",
        '0'&x"12",'0'&x"12",'0'&x"13",'0'&x"14",'0'&x"55",'0'&x"66 ",'0'&x"77",'0'&x"88",
        -- Rest of memory init...
        ,others=>"000000000");
        
begin
 
-- Port A Write
WRP : process(Clk)
begin
    if rising_edge(Clk) then
        if(WEB='1') then
            mem(conv_integer(ADDRB)) := DIB;
        end if;
    end if;
end process;
 
-- Port B Read
process(Clk)
begin
    if rising_edge(Clk) then
        DOA <= mem(conv_integer(ADDRA));
    end if;
end process;
 
end IMPL;		

8 Replies

  • Tricky's avatar
    Tricky
    Icon for Occasional Contributor rankOccasional Contributor

    Using a shared variable implies write-before-read behaviour. Historically Altera could only infer read-before-write behaviour and if you needed write-before-read it had to be done using an altsyncram with the appropriate generic.

    It now appears that write-before-read can be infered, but using a variable in a single process, rather than a shared variable over 2 processes.

    To be safe, Both Xilinx and Altera will always infer a ram using a signal rather than shared variable.

  • PElm's avatar
    PElm
    Icon for New Contributor rankNew Contributor

    @Daixiwen@Tricky

    I changed to using signals instead and read/write in the same process.

    It works fine and one memory is created. However this only works when I'm not initializing the memory content. Then everything becomes logic again.

    I don't understand how Altera want me to write the initialization of the memory content in VHDL.

  • Tricky's avatar
    Tricky
    Icon for Occasional Contributor rankOccasional Contributor

    Intel should accept initialisation just like Xilinx. What family are you targetting?

  • If you right-click in a VHDL windows, there is an "Insert Template" option that can be useful. There is a ROM example.

    I've used the memory initialization and it works within limits. The templates use functions.

    Just a side note, for VHDL 2008, instead of:

    '1'&x"12"

    you could use:

    9x"112" 
     
    or 
     
    9x"1_12"
  • Dear Intel, some of us are really really trying to use the forums you made a mess of, but I'm awfully tired of hitting "Show More" and "Latest Posts" instead of "Top Posts".