Kraken
Kraken

Reputation: 200

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?

Upvotes: 3

Views: 1049

Answers (2)

Greg
Greg

Reputation: 19094

Both the generate loop and unrolled versions should not have passed synthesis. In both cases the same address in ram can be assigned by both always blocks. Worse, if both bits of wren are high with both addresses being the same and data being different, then the result is indeterminable. The Verilog LRM states last assignment on a register wins and always blocks with the same trigger could be evaluated in any order.

Synthesis requires assignments to registers to be deterministic. Two (or more) always blocks having write access to the same bit is illegal because nondeterministic. If the unrolled is synthesizing correctly, then that means there are constants on wren and addr outside of the shown module that make it logically impossible for write conflict; for some reason the generate loop version is not getting the same optimization. Example of constraints that would allow optimization to prevent multi-always block write access:

  1. One wren is hard coded to 0. Therefore only one block has exclusive access
  2. Address have non overlapping sets of possible values. Ex addr[0] can only be even while addr[1] can only be odd, or addr[0] < 2**(ADDR_WIDTH/2) and addr[1] >= 2**(ADDR_WIDTH/2).

Synthesis is okay with dOut being assigned by two always blocks because each block has exclusive write access to its target bits (non overlapping sets of possible address values).

The single always block in mcleod_ideafix answer is the preferred solution. If both bits of wren are high with both addresses being the same, then wren[1] will always win. If wren[0] should have priority, then make the for-loop a count down.

Upvotes: 1

mcleod_ideafix
mcleod_ideafix

Reputation: 11418

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.

Upvotes: 4

Related Questions