UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Adventurer
Adventurer
4,457 Views
Registered: ‎03-16-2010

Problem with inferred RAM blocks

Jump to solution

When inferring a RAM block with a preloaded value, write enables for an LMB bus I get weird behavior: when writing bytes, some bits seem to 'bleed' through to other bytes within a single word. Same thing happens with half words but writing full words seems to work.

 

Example: I connect XMD to the microblaze and tell it to wipe 0x0 using 'mwr 0x0 0', reading the value back works (all zeroes). Then, I write a byte to address 0: 'mwr 0x0 0xab 1 b', the resulting word read from address zero should be 'AB000000', instead it is 'ABA80000'.

 

I've tried everything, the simulation seems to be working fine but the inferred RAM blocks all have this behavior. I've tried multiple examples from the 11.5 XST guide and all of them do this. Since the RAM is inserted using a macro, I can only guess the error lies in the inferring itself....

 

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

entity xram is
        generic (
                C_LMB_AWIDTH: integer := 32;
                C_LMB_DWIDTH: integer := 32;
                XRAM_SIZE:    natural := 16384
                --XRAM_SIZE : integer := 32768
        );
        port (
                -- BRAM Port A
                rsta    : in  std_logic;
                clka    : in  std_logic;
                ena             : in  std_logic;
                wea             : in  std_logic_vector( 0 to (C_LMB_DWIDTH / 8 - 1));
                addra   : in  std_logic_vector( 0 to (C_LMB_AWIDTH - 1));
                douta   : out std_logic_vector( 0 to (C_LMB_DWIDTH - 1));
                dina    : in  std_logic_vector( 0 to (C_LMB_DWIDTH - 1));

                -- BRAM Port B - Instruction Port (does not support writing)
                rstb    : in  std_logic;
                clkb    : in  std_logic;
                enb             : in  std_logic;
                web             : in  std_logic_vector( 0 to (C_LMB_DWIDTH / 8 - 1));
                addrb   : in  std_logic_vector( 0 to (C_LMB_AWIDTH - 1));
                doutb   : out std_logic_vector( 0 to (C_LMB_DWIDTH - 1));
                dinb    : in  std_logic_vector( 0 to (C_LMB_DWIDTH - 1))
        );
end xram;

architecture xram_i of xram is
        -- Define the size and depth of the ram
        type ram_type is array (0 to (XRAM_SIZE / (C_LMB_DWIDTH / 8) - 1)) of std_logic_vector (0 to (C_LMB_DWIDTH - 1));
        shared variable MyRAM : ram_type :=
        ( ...
        );
        -- Hardcode to BRAM
        attribute ram_style : string;
        attribute ram_style of MyRAM: variable is "block";

        -------------------------------------------------------------------------------------------
        -- internal signals
        -------------------------------------------------------------------------------------------
        -- signals for BRAM bus A
        signal i_dina0          : std_logic_vector(0 to 7);
        signal i_dina1          : std_logic_vector(0 to 7);
        signal i_dina2          : std_logic_vector(0 to 7);
        signal i_dina3          : std_logic_vector(0 to 7);

        -- signals for BRAM bus B
        signal i_dinb0          : std_logic_vector(0 to 7);
        signal i_dinb1          : std_logic_vector(0 to 7);
        signal i_dinb2          : std_logic_vector(0 to 7);
        signal i_dinb3          : std_logic_vector(0 to 7);

        -------------------------------------------------------------------------------------------
        -- component declarations
        -------------------------------------------------------------------------------------------

begin

process(wea, dina, addra)
begin
        if wea(0) = '1' then
                i_dina0 <= dina(0 to 7);
        else
                i_dina0 <= MyRAM(conv_integer(addra(0 to 29)))(0 to 7);
        end if;

        if wea(1) = '1' then
                i_dina1 <= dina(8 to 15);
        else
                i_dina1 <= MyRAM(conv_integer(addra(0 to 29)))(8 to 15);
        end if;

        if wea(2) = '1' then
                i_dina2 <= dina(16 to 23);
        else
                i_dina2 <= MyRAM(conv_integer(addra(0 to 29)))(16 to 23);
        end if;

        if wea(3) = '1' then
                i_dina3 <= dina(24 to 31);
        else
                i_dina3 <= MyRAM(conv_integer(addra(0 to 29)))(24 to 31);
        end if;
end process;

process (clka)
begin
        if (rising_edge(clka)) then
                -- Only when the memory port is enabled...
                if (ena = '1') then
                        MyRAM(conv_integer(addra(0 to 29))) := i_dina0 & i_dina1 & i_dina2 & i_dina3;
                        douta <= i_dina0 & i_dina1 & i_dina2 & i_dina3;
                end if;
        end if;
end process;

process(web, dinb, addrb)
begin
        if web(0) = '1' then
                i_dinb0 <= dinb(0 to 7);
        else
                i_dinb0 <= MyRAM(conv_integer(addrb(0 to 29)))(0 to 7);
        end if;

        if web(1) = '1' then
                i_dinb1 <= dinb(8 to 15);
        else
                i_dinb1 <= MyRAM(conv_integer(addrb(0 to 29)))(8 to 15);
        end if;

        if web(2) = '1' then
                i_dinb2 <= dinb(16 to 23);
        else
                i_dinb2 <= MyRAM(conv_integer(addrb(0 to 29)))(16 to 23);
        end if;

        if web(3) = '1' then
                i_dinb3 <= dinb(24 to 31);
        else
                i_dinb3 <= MyRAM(conv_integer(addrb(0 to 29)))(24 to 31);
        end if;
end process;

-- Port B - Instruction Port (no writing)
process (clkb)
begin
        if (rising_edge(clkb)) then
                -- Only when the memory port is enabled...
                if (enb = '1') then
                        MyRAM(conv_integer(addrb(0 to 29))) := i_dinb0 & i_dinb1 & i_dinb2 & i_dinb3;
                        doutb <= i_dinb0 & i_dinb1 & i_dinb2 & i_dinb3;
                end if;
        end if;
end process;

end xram_i;

 

I'm a bit at a loss here why the examples from XST do not work at all, or rather why they result in weird behavior.

 

Btw, the 0 to 29 range with the address is needed because the Microblaze addresses the bytes in the memory by address while the RAM stores entire words. This means the 2 least significant bits are irrelevant. Perhaps this messes up the BRAM parser?

 

Can someone provide a working VHDL example to infer a BRAM block with all features needed to hook it up to the LMB?

 

Edit: the inferral macro is broken when used with byte-write enables: http://forums.xilinx.com/t5/EDK-and-Platform-Studio/Bug-Report-Memory-inferral-macro-is-broken/td-p/71035

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Adventurer
Adventurer
5,745 Views
Registered: ‎03-16-2010

Re: Problem with inferred RAM blocks

Jump to solution

I've upgraded from 11.5 to 12.1 and it still doesn't work. Nobody has ever done this before? I find that hard to believe...

 

Edit: the inferral macro is broken when used with byte-write enables: http://forums.xilinx.com/t5/EDK-and-Platform-Studio/Bug-Report-Memory-inferral-macro-is-broken/td-p/71035

0 Kudos
4 Replies
Xilinx Employee
Xilinx Employee
4,433 Views
Registered: ‎08-08-2007

Re: Problem with inferred RAM blocks

Jump to solution

The LMB interface is very particular.  If you want to infer your block RAM, then the block RAM has to be exactly like the isntantiated block RAM that is used in an EDK system.  Build a sample project in EDK with your LMB block RAM, check for all of the particulars of that instantiated block RAM (dig out that library guide and read up on block RAM!) and use the BRAM templates in the XST User Guide to infer the same BRAMs.

 

0 Kudos
Adventurer
Adventurer
4,429 Views
Registered: ‎03-16-2010

Re: Problem with inferred RAM blocks

Jump to solution

That seems to be the problem: the VHDL I posted is based on the byte-write enable sample from the XST manual and it doesn't work.

 

The problem with the sample code is that the address passed to the BRAM is not the byte address (such as used by the LMB controller or MicroBlaze) but rather the word index in the array.

 

It is possible that removing the address modifier (removing the last 2 bits) 'fixes' the resulting BRAM in the sense that the macro parser generates a working block but then the result would no longer work on the LMB controller (since everything is a factor 4 off). This also means that I don't know how to test the resulting BRAM without being able to hook it up to a LMB controller.

 

I've read through all the RAM inferring examples from multiple versions of XST and it seems that all examples address the array index rather than the bytes. I've tried removing the address shift from the BRAM description and adding it to a wrapper, the result however, is another crippled memory block.

 

So is this really a limitation in the BRAM inferring macro? If so, the only solution is probably to instantiate the raw primitive BRAM blocks and wrap 4 of the 4k blocks together - a solution which is not so portable and requires a lot more code.

 

Also, it is weird that numerous examples for BRAM inferral are provided, except for the type which is a drop-in replacement for the BRAM core which is actually used in XPS as a default solution (2 ports, byte-write enabled and 32-bit word values - the type I am trying to infer).

0 Kudos
Adventurer
Adventurer
4,409 Views
Registered: ‎03-16-2010

Re: Problem with inferred RAM blocks

Jump to solution

Perhaps I am wording it wrong when I say I want to use the LMB interface. I meant, I am using a LMB controller which provides me a BRAM interface. Two interfaces in fact since the MB has a data and instruction bus.

 

So I don't need to interact with the LMB protocol but only with the BRAM interface.

 

Does anyone have a working example of that?

0 Kudos
Highlighted
Adventurer
Adventurer
5,746 Views
Registered: ‎03-16-2010

Re: Problem with inferred RAM blocks

Jump to solution

I've upgraded from 11.5 to 12.1 and it still doesn't work. Nobody has ever done this before? I find that hard to believe...

 

Edit: the inferral macro is broken when used with byte-write enables: http://forums.xilinx.com/t5/EDK-and-Platform-Studio/Bug-Report-Memory-inferral-macro-is-broken/td-p/71035

0 Kudos