Search code examples
verilogfpgahdlquartusintel-fpga

Quartus does not allow using a Generate block in Verilog


Pretty simple problem. Given the following code:

module main(
    output reg  [1:0][DATA_WIDTH-1:0] dOut,
    input  wire [1:0][DATA_WIDTH-1:0] dIn,
    input  wire [1:0][ADDR_WIDTH-1:0] addr,
    input  wire [1:0] wren,
    input  wire clk
);
    parameter DATA_WIDTH = 16;
    parameter ADDR_WIDTH = 6;

    reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];

    generate
        genvar k;
        for(k=0; k<2; k=k+1) begin: m
            always @(posedge clk) begin
                if(wren[k])
                    ram[addr[k]] <= dIn[k];
                dOut[k] <= ram[addr[k]];
            end
        end
    endgenerate
endmodule

quarus 13.0sp1 gives this error (and its 20 other ill-begotten fraternally equivalent siblings):

Error (10028): Can't resolve multiple constant drivers for net "ram[63][14]" at main.v(42)

But if I manually un-roll the generate loop:

module main(
    output reg  [1:0][DATA_WIDTH-1:0] dOut,
    input  wire [1:0][DATA_WIDTH-1:0] dIn,
    input  wire [1:0][ADDR_WIDTH-1:0] addr,
    input  wire [1:0] wren,
    input  wire clk
);
    parameter DATA_WIDTH = 16;
    parameter ADDR_WIDTH = 6;

    reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];

    always @(posedge clk) begin
        if(wren[0])
            ram[addr[0]] <= dIn[0];
        dOut[0] <= ram[addr[0]];
    end

    always @(posedge clk) begin
        if(wren[1])
            ram[addr[1]] <= dIn[1];
        dOut[1] <= ram[addr[1]];
    end
endmodule

It all becomes okay with the analysis & synthesis step.

What's the cure to get the generate loop running?


Solution

  • I think the correct way is in the lines of what it's explained in this question: Using a generate with for loop in verilog

    Which would be transferred to your code as this:

    module main(
        output reg  [1:0][DATA_WIDTH-1:0] dOut,
        input  wire [1:0][DATA_WIDTH-1:0] dIn,
        input  wire [1:0][ADDR_WIDTH-1:0] addr,
        input  wire [1:0] wren,
        input  wire clk
    );
        parameter DATA_WIDTH = 16;
        parameter ADDR_WIDTH = 6;
    
        reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];    
        integer k;
    
        always @(posedge clk) begin
          for(k=0; k<2; k=k+1) begin:
            if(wren[k])
              ram[addr[k]] <= dIn[k];
            dOut[k] <= ram[addr[k]];
          end
        end
    endmodule
    

    Keeping all accesses to your dual port RAM in one always block is convenient so the synthesizer can safely detect that you are efefctively using a dual port RAM at register ram.