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: 
Highlighted
Scholar dpaul24
Scholar
690 Views
Registered: ‎08-07-2014

Why is my asym DP BRAM not populated?

Jump to solution

I am trying to fill a "True Dual-Port Asymmetric Ram Write First VHDL" as given in UG901 Vivado Synthesis Guide. I am just changing the generics, nothing else.

 

RAM RTL is given below.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;


entity asym_ram_tdp is
    generic (
        WIDTHA      : integer := 4;
        SIZEA       : integer := 1024;
        ADDRWIDTHA  : integer := 10;
        WIDTHB      : integer := 16;
        SIZEB       : integer := 256;
        ADDRWIDTHB  : integer := 8 
    );
    port (
        clkA        : in  std_logic;
        clkB        : in  std_logic;
        enA         : in  std_logic;
        enB         : in  std_logic;
        weA         : in  std_logic;
        weB         : in  std_logic;
        addrA       : in  std_logic_vector(ADDRWIDTHA-1 downto 0);
        addrB       : in  std_logic_vector(ADDRWIDTHB-1 downto 0);
        diA         : in  std_logic_vector(WIDTHA-1 downto 0);
        diB         : in  std_logic_vector(WIDTHB-1 downto 0);
        doA         : out std_logic_vector(WIDTHA-1 downto 0);
        doB         : out std_logic_vector(WIDTHB-1 downto 0)
    );
end asym_ram_tdp;


architecture asym_ram_tdp_arc of asym_ram_tdp is

function max(L, R: INTEGER) return INTEGER is
begin
    if L > R then
        return L;
    else
        return R;
    end if;
end;

function min(L, R: INTEGER) return INTEGER is
begin
    if L < R then
        return L;
    else
        return R;
    end if;
end;

function log2 (val: INTEGER) return natural is
    variable res : natural;
begin
    for i in 0 to 31 loop
        if (val <= (2**i)) then
            res := i;
            exit;
        end if;
    end loop;
    return res;
end function Log2;

constant minWIDTH : integer := min(WIDTHA,WIDTHB);
constant maxWIDTH : integer := max(WIDTHA,WIDTHB);
constant maxSIZE  : integer := max(SIZEA,SIZEB);
constant RATIO    : integer := maxWIDTH / minWIDTH;

-- An asymmetric RAM is modeled in a similar way as a symmetric RAM, with an array of array object.
-- Its aspect ratio corresponds to the port with the lower data width (larger depth).
type ramType is array (0 to maxSIZE-1) of std_logic_vector(minWIDTH-1 downto 0);
signal my_ram                 : ramType := (others => (others => '0'));

signal readA  : std_logic_vector(WIDTHA-1 downto 0):= (others => '0');
signal readB  : std_logic_vector(WIDTHB-1 downto 0):= (others => '0');
signal regA   : std_logic_vector(WIDTHA-1 downto 0):= (others => '0');
signal regB   : std_logic_vector(WIDTHB-1 downto 0):= (others => '0');
  
begin

    process (clkA)
    begin
      if rising_edge(clkA) then
        if enA = '1' then
          if weA = '1' then
              my_ram(conv_integer(addrA)) <= diA;
              readA <= diA;
          else
              readA <= my_ram(conv_integer(addrA)); 
          end if;
        end if;
        regA <= readA;
      end if;
    end process;
        
    process (clkB)
    begin
      if rising_edge(clkB) then
          for i in 0 to RATIO-1 loop
              if enB = '1' then        
                  if weB = '1' then
                      my_ram(  conv_integer( addrB & conv_std_logic_vector(i,log2(RATIO)) )  ) <= diB((i+1)*minWIDTH-1 downto i*minWIDTH);
                  end if;
                  -- The read statement below is placed after the write statement on purpose to ensure write-first synchronization
                  -- through the variable mechanism
                  
                  readB((i+1)*minWIDTH-1 downto i*minWIDTH) <= my_ram(  conv_integer( addrB & conv_std_logic_vector(i,log2(RATIO)) )  );
              end if;
          end loop;
          regB <= readB;
      end if;
    end process;
  
    doA <= regA;
    doB <= regB;

end asym_ram_tdp_arc;

 

Given below is the sim screen-shot. Only PortA is being WRITTEN with data from the TB. Why I am getting those X's inside the memory? Any clues?

 

 

ramsim.jpg

 

 

Testbench is here:

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;


entity asym_ram_tdp_tb is
--  Port ( );
end asym_ram_tdp_tb;


architecture asym_ram_tdp_tb_arc of asym_ram_tdp_tb is

component asym_ram_tdp is
    generic (
        WIDTHA      : integer := 4;
        SIZEA       : integer := 1024;
        ADDRWIDTHA  : integer := 10;
        WIDTHB      : integer := 16;
        SIZEB       : integer := 256;
        ADDRWIDTHB  : integer := 8 
    );
    port (
        clkA        : in  std_logic;
        clkB        : in  std_logic;
        enA         : in  std_logic;
        enB         : in  std_logic;
        weA         : in  std_logic;
        weB         : in  std_logic;
        addrA       : in  std_logic_vector(ADDRWIDTHA-1 downto 0);
        addrB       : in  std_logic_vector(ADDRWIDTHB-1 downto 0);
        diA         : in  std_logic_vector(WIDTHA-1 downto 0);
        diB         : in  std_logic_vector(WIDTHB-1 downto 0);
        doA         : out std_logic_vector(WIDTHA-1 downto 0);
        doB         : out std_logic_vector(WIDTHB-1 downto 0)
    );
end component;

-- Denfine clocks
constant CLK_111M111_PERIOD : time      := 9.000 ns;
constant CLK_100_PERIOD     : time      := 5.000 ns;
signal   clk_111M111        : std_logic := '0';
signal   clk_100M           : std_logic := '0';

-- Port B
constant DATA_WIDTH_B : integer                                   := 1280; 
constant SIZE_B       : integer                                   := 32 ; 
constant ADDR_WIDTH_B : integer                                   := 5   ;
signal   en_b         : std_logic                                 := '0' ;
signal   w_en_b       : std_logic                                 := '0' ;
signal   addr_b       : std_logic_vector(ADDR_WIDTH_B-1 downto 0) := (others => '0');
signal   d_in_b       : std_logic_vector(DATA_WIDTH_B-1 downto 0) := (others => '0');
signal   d_out_b      : std_logic_vector(DATA_WIDTH_B-1 downto 0)                   ;
signal   addr_b_cnt   : integer range 0 to 127                    := 0              ;

-- Port A
constant DATA_WIDTH_A : integer                                   := 32  ; 
constant SIZE_A       : integer                                   := 2048; 
constant ADDR_WIDTH_A : integer                                   := 11  ; 
signal   en_a         : std_logic                                 := '0' ;
signal   w_en_a       : std_logic                                 := '0' ;
signal   addr_a       : std_logic_vector(ADDR_WIDTH_A-1 downto 0) := (others => '0');
signal   d_in_a       : std_logic_vector(DATA_WIDTH_A-1 downto 0) := (others => '0');
signal   d_out_a      : std_logic_vector(DATA_WIDTH_A-1 downto 0)                   ;
signal   addr_a_cnt   : integer range 0 to 8191                   := 0              ; 

begin

    dp_filterset_ram : asym_ram_tdp
    generic map(
        WIDTHA      => DATA_WIDTH_A,
        SIZEA       => SIZE_A      ,
        ADDRWIDTHA  => ADDR_WIDTH_A,
        WIDTHB      => DATA_WIDTH_B,
        SIZEB       => SIZE_B      ,
        ADDRWIDTHB  => ADDR_WIDTH_B 
    )
    port map(
        clkA        => clk_111M111,
        clkB        => clk_100M   ,
        enA         => en_a       ,
        enB         => en_b       ,
        weA         => w_en_a     ,
        weB         => w_en_b     ,
        addrA       => addr_a     ,
        addrB       => addr_b     ,
        diA         => d_in_a     ,
        diB         => d_in_b     ,
        doA         => d_out_a    ,
        doB         => d_out_b
    );
    

    -- Generate clocks
    clk_111M111 <= not(clk_111M111) after CLK_111M111_PERIOD/2;
    clk_100M <= not(clk_100M) after CLK_100_PERIOD/2;   
    
    ------------
    -- Write RAM
    ------------    
    write_p : process
    
    begin    
    
       
        en_a   <= '0';
        w_en_a <= '0';
        addr_a <= (others => '0');    
        wait for CLK_111M111_PERIOD*20; 
        
        fill_ram_1: for i in 0 to 19 loop
            en_a       <= '1';
            w_en_a     <= '1';
            addr_a     <= std_logic_vector(to_unsigned(i, 11));
            d_in_a     <= std_logic_vector(to_unsigned(i, 32));
            addr_a_cnt <= i; 
            wait until rising_edge(clk_111M111);        
        end loop fill_ram_1;
        
        en_a   <= '0';
        w_en_a <= '0';
        addr_a <= (others => '0');
        wait for CLK_111M111_PERIOD*1;    
        
        fill_ram_2: for i in addr_a_cnt+1 to addr_a_cnt+1+20 loop
            en_a       <= '1';
            w_en_a     <= '1';
            addr_a     <= std_logic_vector(to_unsigned(i, 11));
            d_in_a     <= std_logic_vector(to_unsigned(i, 32));
            addr_a_cnt <= i; 
            wait until rising_edge(clk_111M111);        
        end loop fill_ram_2; 
        
        en_a   <= '0';
        w_en_a <= '0';
        addr_a <= (others => '0');
        wait for CLK_111M111_PERIOD*1;
        
        wait;

    end process write_p;        
        
    ------------
    -- Read RAM
    ------------
    -- read_p : process
        -- begin
                
            -- wait;

    -- end process read_p;        
    
    
end asym_ram_tdp_tb_arc;

 

 

--------------------------------------------------------------------------------------------------------
FPGA enthusiast!
--------------------------------------------------------------------------------------------------------
0 Kudos
1 Solution

Accepted Solutions
Scholar jmcclusk
Scholar
1,101 Views
Registered: ‎02-24-2014

Re: Why is my asym DP BRAM not populated?

Jump to solution

I think it's because you have 2 sets of drivers on the signal array, with the potential for two sources to drive the same wire.  Normally, with 2 write ports, the BRAM memory is inferred using a shared variable array, which doesn't have any problems with driver resolution like a signal.    Try converting to a shared variable array, and see what happens.  UG901 shows an example.

Don't forget to close a thread when possible by accepting a post as a solution.
3 Replies
Scholar jmcclusk
Scholar
1,102 Views
Registered: ‎02-24-2014

Re: Why is my asym DP BRAM not populated?

Jump to solution

I think it's because you have 2 sets of drivers on the signal array, with the potential for two sources to drive the same wire.  Normally, with 2 write ports, the BRAM memory is inferred using a shared variable array, which doesn't have any problems with driver resolution like a signal.    Try converting to a shared variable array, and see what happens.  UG901 shows an example.

Don't forget to close a thread when possible by accepting a post as a solution.
Scholar dpaul24
Scholar
644 Views
Registered: ‎08-07-2014

Re: Why is my asym DP BRAM not populated?

Jump to solution

Thanks for the hint @jmcclusk.

Using shared variable it is possible to Write and Read from the RAM.

 

But I am sure I copied it correctly from a UG901 (v2017.1) April 19, 2017) where signal type was used.

See page 141, signal my_ram : ramType := (others => (others => '0'));  -- is used.

 

BUT.... There would be synthesis error because of the use of protected type.

In UG901, v2017.1 I didn't find any reference to support of protected types. I guess this is the reason why Xilinx was using using signals.

Do you have a solution for this?

 

 

 

 

--------------------------------------------------------------------------------------------------------
FPGA enthusiast!
--------------------------------------------------------------------------------------------------------
0 Kudos
Scholar jmcclusk
Scholar
618 Views
Registered: ‎02-24-2014

Re: Why is my asym DP BRAM not populated?

Jump to solution

Long ago, it's true that shared variables could not be synthesized..   but that restriction has been lifted for many years now.

Don't forget to close a thread when possible by accepting a post as a solution.
0 Kudos