5
\$\begingroup\$

I have a project with several inferred dual port RAM blocks. The code for this dual port RAM is as follows:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
use ieee.std_logic_textio.all;

library std;
use std.textio.all;

entity dual_port_ram_w_be is
  generic(
    DATA_WIDTH            : natural := 32;
    ADDR_WIDTH            : natural := 12;
    INITIALIZE_TO_ZERO    : boolean := true;
    MEMTYPE_PAR_DIRECTIVE : string  := "block"
    );
  port(
    -- Port A
    port_a_clk  : in  std_logic;
    port_a_we   : in  std_logic;
    port_a_be   : in  std_logic_vector(DATA_WIDTH/8-1 downto 0);
    port_a_addr : in  std_logic_vector(ADDR_WIDTH-1 downto 0);
    port_a_din  : in  std_logic_vector(DATA_WIDTH-1 downto 0);
    port_a_dout : out std_logic_vector(DATA_WIDTH-1 downto 0);
    -- Port B
    port_b_clk  : in  std_logic;
    port_b_we   : in  std_logic;
    port_b_be   : in  std_logic_vector(DATA_WIDTH/8-1 downto 0);
    port_b_addr : in  std_logic_vector(ADDR_WIDTH-1 downto 0);
    port_b_din  : in  std_logic_vector(DATA_WIDTH-1 downto 0);
    port_b_dout : out std_logic_vector(DATA_WIDTH-1 downto 0)
    );
end dual_port_ram_w_be;

architecture dual_port_ram_w_be_arch of dual_port_ram_w_be is   
  -- Memory formation : Byte enabled RAM is formed by laying byte RAM arrays
  -- side-by-side. Read and write processes are realized by for loops iterating
  -- across the byte array RAMs

  -- Calculate array length, number of byte arrays
  constant MEM_DEPTH      : natural := 2**ADDR_WIDTH;
  constant NUM_BYTE_ARRAY : natural := DATA_WIDTH/8;

  -- Infer memory
  type byte_array is array (0 to MEM_DEPTH-1) of std_logic_vector(7 downto 0);
  type ram_type is array (NUM_BYTE_ARRAY-1 downto 0) of byte_array;

  -- Zero initialize function
  impure function zero_initialize return ram_type is
    variable mem : ram_type;
  begin
    if INITIALIZE_TO_ZERO = true then
      for i in 0 to MEM_DEPTH-1 loop
        for byte_index in 0 to NUM_BYTE_ARRAY-1 loop
          mem(byte_index)(i) := (others => '0');
        end loop;  -- byte_index
      end loop;  -- i      
    end if;
    return mem;
  end zero_initialize;

  -- Constrain RAM memory to use "block", warn if not possible
  shared variable RAM : ram_type := zero_initialize;

  attribute ram_style        : string;
  attribute ram_style of RAM : variable is MEMTYPE_PAR_DIRECTIVE;

  -- Temp signals
  signal port_a_dout_reg : std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0');
  signal port_b_dout_reg : std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0');

begin

  -----------------------------------------------------------------------------
  -- Port A block
  -----------------------------------------------------------------------------
  port_a_dout <= port_a_dout_reg;
  porta_rdwr_blkgen : for i in 0 to NUM_BYTE_ARRAY-1 generate
    porta_proc : process (port_a_clk)
    begin  -- process portb_proc
      if port_a_clk'event and port_a_clk = '1' then
        port_a_dout_reg((i+1)*8-1 downto i*8) <= RAM(i)(conv_integer(port_a_addr));
        if port_a_we = '1' then
          if port_a_be(i) = '1' then
            RAM(i)(conv_integer(port_a_addr)) := port_a_din((i+1)*8-1 downto i*8);
          end if;
        end if;
      end if;
    end process porta_proc;
  end generate porta_rdwr_blkgen;

  -------------------------------------------------------------------------------
  ---- Port B
  -------------------------------------------------------------------------------
  port_b_dout <= port_b_dout_reg;
  portb_rdwr_blkgen : for i in 0 to NUM_BYTE_ARRAY-1 generate
    portb_proc : process (port_b_clk)
    begin  -- process portb_proc
      if port_b_clk'event and port_b_clk = '1' then
        port_b_dout_reg((i+1)*8-1 downto i*8) <= RAM(i)(conv_integer(port_b_addr));
        if port_b_we = '1' then
          if port_b_be(i) = '1' then
            RAM(i)(conv_integer(port_b_addr)) := port_b_din((i+1)*8-1 downto i*8);
          end if;
        end if;
      end if;
    end process portb_proc;
  end generate portb_rdwr_blkgen;

end dual_port_ram_w_be_arch;

The above code is synthesized in XST and Synplify Pro. This compiles correctly and works perfectly on FPGA without problems when synthesized and PARed with XST.

In Synplify Pro, I get an error for the line:

port_a_dout_reg((i+1)*8-1 downto i*8) <= RAM(i)(conv_integer(port_a_addr));

The error I get is: Logic for ram_0_0_4(7 downto 0) does not match a standard flip-flop

It looks like XST is lenient with coding guidelines whereas Synplify is more strict. Can you explain why the error is happening ? How can I solve it ?

I need to use Synplify because I need to back-port my code to an older device.

\$\endgroup\$
5
\$\begingroup\$

Alright... I may have figured out the solution. The solution is to reduce the number of nested conditions. That way the synthesizer does not think of the flip-flop having multiple levels of control signals.

-- Write process
porta_write_blkgen : for i in 0 to NUM_BYTE_ARRAY-1 generate
  porta_wrproc : process (port_a_be, port_a_clk, port_a_we)
  begin  -- process portb_proc
    if port_a_clk'event and port_a_clk = '1' and port_a_we = '1' and port_a_be(i) = '1' then
      RAM(i)(conv_integer(port_a_addr)) := port_a_din((i+1)*8-1 downto i*8);
    end if;
  end process porta_wrproc;
end generate porta_write_blkgen;

Synplify seems to be more pedantic in these matters as compared to the Xilinx tools.

I tested the solution on FPGA and it seems to be okay.

RRS

\$\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.