Search code examples
verilogfpgaxilinxintel-fpga

Inferring a True Dual Port RAM (Xilinx and Intel compatible) in Verilog


I tried to write my own true dual-port memory module, hoping that it would infer as a BRAM:

module dp_async_ram (clk, rst, rd0, rd1, wr0, wr1, in1, in0, out1,out0, addr0, addr1);
  parameter DEPTH = 16;
  parameter WIDTH = 8;
  parameter ADDR = 4;

  input clk, rst;
  input rd0, rd1;
  input wr0, wr1;
  input [WIDTH-1:0] in0, in1;
  input [ADDR-1:0] addr0, addr1;

  output [WIDTH-1:0] out0, out1;

  //Define Memory
  logic [WIDTH-1:0] mem [0:DEPTH-1];
  logic [WIDTH-1:0] data0, data1;

  //Write Logic
  always_ff @ (posedge clk) begin
      if (wr0 && ~rd0)
        mem[addr0] <= in0;
      if (wr1 && ~rd1)
        mem[addr1] <= in1;
      if (rd0 && ~wr0)
        data0 <= mem[addr0];
      if (rd1 && ~wr1)
        data1 <= mem[addr1];
  end

  //Read Logic
  assign out0 = (rd0 && (!wr0))? data0: {WIDTH{1'bz}}; //High Impedance Mode here
  assign out1 = (rd0 && (!wr0))? data1: {WIDTH{1'bz}};


endmodule // dp_async_ram

After running synthesis in Vivado, in the report says the following:

 WARNING: [Synth 8-4767] Trying to implement RAM 'mem_reg' in registers. Block RAM or DRAM implementation is not possible; see log for reasons.
Reason is one or more of the following :
    1: RAM has multiple writes via different ports in same process. If RAM inferencing intended, write to one port per process. 
    2: Unable to determine number of words or word size in RAM. 
    3: No valid read/write found for RAM. 
RAM "mem_reg" dissolved into registers

Number 1 Strikes me the most since this implies there is no way to code a portable true dual port BRAM. I was wondering if I am wrong with this or if I should just use ip generation. Thanks


Solution

  • I don't think #1 means that you can't do multiple writes--just that you can't do them from the same process. Try splitting them up:

    always @ (posedge clk) begin
        if (wr0 && ~rd0)
            mem[addr0] <= in0;
        if (rd0 && ~wr0)
            data0 <= mem[addr0];
    end
    always @ (posedge clk) begin
        if (wr1 && ~rd1)
            mem[addr1] <= in1;
        if (rd1 && ~wr1)
            data1 <= mem[addr1];
    end
    

    For more information on how to infer things in Vivado, look in the 'UG901 Vivado Synthesis' doc. For TDP BRAM, look under "RAM HDL Coding Techniques".

    Alternately, if you don't mind being locked in to Xilinx, you can use the xpm_memory_tdpram module.