Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

Has anyone successfully inferred read enable ports on true dual-port ram?

The megawizard successfully produces the following true dual-port altsyncram code with read enables:


// synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
module ram_dp (
  address_a,
  address_b,
  clock_a,
  clock_b,
  data_a,
  data_b,
  rden_a,
  rden_b,
  wren_a,
  wren_b,
  q_a,
  q_b);
  input   address_a;
  input   address_b;
  input   clock_a;
  input   clock_b;
  input   data_a;
  input   data_b;
  input   rden_a;
  input   rden_b;
  input   wren_a;
  input   wren_b;
  output    q_a;
  output    q_b;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
  tri1    clock_a;
  tri1    rden_a;
  tri1    rden_b;
  tri0    wren_a;
  tri0    wren_b;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif
  wire  sub_wire0;
  wire  sub_wire1;
  wire  q_a = sub_wire0;
  wire  q_b = sub_wire1;
 altsyncram  altsyncram_component (
        .clock0 (clock_a),
        .wren_a (wren_a),
        .address_b (address_b),
        .clock1 (clock_b),
        .data_b (data_b),
        .rden_a (rden_a),
        .wren_b (wren_b),
        .address_a (address_a),
        .data_a (data_a),
        .rden_b (rden_b),
        .q_a (sub_wire0),
        .q_b (sub_wire1),
        .aclr0 (1'b0),
        .aclr1 (1'b0),
        .addressstall_a (1'b0),
        .addressstall_b (1'b0),
        .byteena_a (1'b1),
        .byteena_b (1'b1),
        .clocken0 (1'b1),
        .clocken1 (1'b1),
        .clocken2 (1'b1),
        .clocken3 (1'b1),
        .eccstatus ());

Since I'd rather use inference, I started with the template wizard.

The template wizard produces the following code for true dual-port ram:

// Quartus II Verilog Template
// True Dual Port RAM with dual clocks
module true_dual_port_ram_dual_clock# (parameter DATA_WIDTH=8, parameter ADDR_WIDTH=6)
(
    input  data_a, data_b,
    input  addr_a, addr_b,
    input we_a, we_b, clk_a, clk_b,
    output reg  q_a, q_b
);
    // Declare the RAM variable
    reg  ram;
    always @ (posedge clk_a)
    begin
        // Port A 
        if (we_a) 
        begin
            ram <= data_a;
            q_a <= data_a;
        end
        else 
        begin
            q_a <= ram;
        end 
    end
    always @ (posedge clk_b)
    begin
        // Port B 
        if (we_b) 
        begin
            ram <= data_b;
            q_b <= data_b;
        end
        else 
        begin
            q_b <= ram;
        end 
    end
endmodule

I've modified it to have read enables like so:

// Quartus II Verilog Template// True Dual Port RAM with dual clocks
module true_dual_port_ram_dual_clock# (parameter DATA_WIDTH=8, parameter ADDR_WIDTH=6)
(
    input  data_a, data_b,
    input  addr_a, addr_b,
    input we_a, we_b, clk_a, clk_b,
        input re_a, re_b,
    output reg  q_a, q_b
);
    // Declare the RAM variable
    reg  ram;
    always @ (posedge clk_a)
    begin
        // Port A 
        if (we_a) 
        begin
            ram <= data_a;
            q_a <= data_a;
        end
        else if (re_a)
        begin
            q_a <= ram;
        end 
    end
    always @ (posedge clk_b)
    begin
        // Port B 
        if (we_b) 
        begin
            ram <= data_b;
            q_b <= data_b;
        end
        else if (re_b)
        begin
            q_b <= ram;
        end 
    end
endmodule

However that produces the following errors:

Info (276014): Found 1 instances of uninferred RAM logic    Info (276007): RAM logic "dual_port_ram:tdp|ram" is uninferred due to asynchronous read logic

Thinking maybe both output flops need the rden, I changed it to:

// Quartus II Verilog Template// True Dual Port RAM with dual clocks
module true_dual_port_ram_dual_clock# (parameter DATA_WIDTH=8, parameter ADDR_WIDTH=6)
(
    input  data_a, data_b,
    input  addr_a, addr_b,
    input we_a, we_b, clk_a, clk_b,
        input re_a, re_b,
    output reg  q_a, q_b
);
    // Declare the RAM variable
    reg  ram;
    always @ (posedge clk_a)
    begin
        // Port A 
        if (we_a) 
        begin
            ram <= data_a;
                        if (re_a)
            q_a <= data_a;
        end
        else if (re_a)
        begin
            q_a <= ram;
        end 
    end
    always @ (posedge clk_b)
    begin
        // Port B 
        if (we_b) 
        begin
            ram <= data_b;
                        if (re_b)
            q_b <= data_b;
        end
        else if (re_b)
        begin
            q_b <= ram;
        end 
    end
endmodule

Which produced the same inference error. I've tried quite a few permutations. Any ideas?

2 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    read enables get no mention in any of the templates in the HDL coding styles:

    http://www.altera.co.uk/literature/hb/qts/qts_qii51007.pdf

    I would raise an enhancement request from altera - but dont expect support any time soon.

    You can work around it by making the read enable control the read_address instead of the data output register. Or just stick with the megawizard function
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok - had another read. Instead of making the read enable and "else if " against the write enable, just make it a stand alone "if". You would never expect the read port to be controlled by the write_enable - they should not be mutually exclusive.

    
    always @ (posedge clk_a)
        begin
            // Port A 
            if (we_a) 
            begin
                ram <= data_a;
          end
            
          if (re_a)
            begin
                q_a <= ram;
            end 
        end