Search code examples
initializationvhdllattice-diamond

How does Lattice Diamond map initial RAM values to the EBR primitives?


I'm reading initial RAM values for a 4 KiB (1Ki x 32-Bit) True-Dual-Port RAM from disk. Because my Lattice ECP5 devices has only 18-bit wide Embedded Block RAMs (EBRs), 2 RAMs are combined to match the word size of 32 bit.

My ocram.mem file has 4 data lines, and 8 hex digits on each line (=> 32 bit word line).
The file looks as follows:

@000
44332211
88776655
CCBBAA99
00FFEEDD

My read function reports these lines in the LSE log:

INFO - synthesis: d:/git/poc/src/mem/mem.pkg.vhdl(144): Note: "44332211". VHDL-1533
INFO - synthesis: d:/git/poc/src/mem/mem.pkg.vhdl(144): Note: "88776655". VHDL-1533
INFO - synthesis: d:/git/poc/src/mem/mem.pkg.vhdl(144): Note: "CCBBAA99". VHDL-1533
INFO - synthesis: d:/git/poc/src/mem/mem.pkg.vhdl(144): Note: "00FFEEDD". VHDL-1533

So, the first line is skipped as intended and the following line strings are OK, too. After line reading and char to std_logic_vector conversion, I outputted my 2D STD_LOGIC matrix into the LSE log, again:

INFO - synthesis: d:/git/poc/src/mem/ocram/ocram_tdp.vhdl(123): Note: "Memory: => 
0100 0100 0011 0011 0010 0010 0001 0001
1000 1000 0111 0111 0110 0110 0101 0101
1100 1100 1011 1011 1010 1010 1001 1001
0000 0000 1111 1111 1110 1110 1101 1101
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 00   ....   000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
". VHDL-1533

As one can see, the values are still unimpaired.
Synthesis finishes without errors.

So I started map and P&R in Lattice Diamond. The floorplan view shows me 2 used Embedded Block RAMs - that's intended. But when I click onto the RAM, the INIT values look strange.

RAM0 INITVAL_00 = 0x0000...000000000000003FF332EE221DD110CC
RAM0 INITVAL_01 = 0x0000...00000000000000000000000000000000
RAM0 INITVAL_.. = 0x.......................................
RAM0 INITVAL_3F = 0x0000...00000000000000000000000000000000

RAM1 INITVAL_00 = 0x0000...00000000000002EDD02A990265502211
RAM1 INITVAL_01 = 0x0000...00000000000000000000000000000000
RAM1 INITVAL_.. = 0x.......................................
RAM1 INITVAL_3F = 0x0000...00000000000000000000000000000000

I recognize some of my values, but not all. I haven't found any clue in the EBR or ECP5 documentation.

  • How is the initial value mapped to the RAM?

Solution

  • I found the RAM mapping pattern...

    Values from Lattice Diamond Floorplaner:

    RAM 0
    .....    ..................
    00000 => 000000000000000000
    02EDD => 000010111011011101
    02A99 => 000010101010011001
    02655 => 000010011001010101
    02211 => 000010001000010001
    
    RAM 1
    .....    ..................
    00000 => 000000000000000000
    003FF => 000000001111111111
    332EE => 110011001011101110
    221DD => 100010000111011101
    110CC => 010001000011001100
    

    When I combine the two parts and introduce new delimiters, it can be decoded to the original content:

    RAM 1 RAM 0          RAM 1 (17:0)             RAM 0 (13:0)      original
    00000 00000 => 0000.0000.0000.0000.00 --.--00.0000.0000.0000 ~> 0000-0000
    003FF 02EDD => 0000.0000.1111.1111.11 --.--10.1110.1101.1101 ~> 00FF-EEDD
    332EE 02A99 => 1100.1100.1011.1011.10 --.--10.1010.1001.1001 ~> CCDD-AA99
    221DD 02655 => 1000.1000.0111.0111.01 --.--10.0110.0101.0101 ~> 8877-6655
    110CC 02211 => 0100.0100.0011.0011.00 --.--10.0010.0001.0001 ~> 4433-2211
    

    The RAM is organized as follows:

    • memory lines: 64
    • words per line: 64
    • bits per word: 18 (encoded as 5 hex digits)

    DataIn/DataOut to internal RAM mapping:

    ram0(13 downto 0) <= DataIn(13 downto 0);
    ram1(17 downto 0) <= DataIn(31 downto 14);
    
    DataOut(13 downto 0)  <= rom0(13 downto 0);
    DataOut(31 downto 14) <= rom1(17 downto 0);