Search code examples
system-verilogverilator

SystemVerilog Dataflow Modeling Ripple-Adder with array instances


I've implemented a (working) ripple-carry adder using generation to create 16 different full_adder instances (the full_adder works as intended):

module ripple_adder16 (a, b, cin, sum, cout);

input [15:0] a, b; input cin;
output [15:0] sum; output cout;
wire [15:0] a, b; wire [15:0] sum; wire cout;

// intermediate nets.
// Since the carries cascade, we have to tell
// verilator that it can't "flatten" or whatever.
/* verilator lint_off UNOPTFLAT */
wire [16:0] carries;
/* verilator lint_on UNOPTFLAT */

assign carries[0] = cin;
assign cout = carries[16]; // output.

genvar i;
generate for(i=0; i < 16; i = i + 1)
  begin
    full_adder adder (
      .a(a[i]),
      .b(b[i]),
      .sum(sum[i]),
      .cin(carries[i]),
      .cout(carries[i+1])
    );
  end
endgenerate

endmodule

Now I'm trying to modify the adder so that I can keep an array of adders. Below is an example of the code I'm trying to get working:


input [15:0] a, b; input cin;
output [15:0] sum; output cout;
wire [15:0] a, b; wire [15:0] sum; wire cout;

full_adder adders [15:0] (
  .a(a),
  .b(b),
  .cin(),
  .sum(sum), // output.
  .cout()
);

// DIFFERENCES START HERE
assign adders[0].cin = cin;
assign cout = adders[15].cout; // output.

genvar i;
generate
for(i=0; i < 15; i = i + 1)
  assign adders[i+1].cin = adders[i].cout;
endgenerate
// DIFFERENCES END HERE

endmodule

However, I get a ASSIGNIN error from Verilator (documentation says "Error that an assignment is being made to an input signal. This is almost certainly a mistake, though technically legal.") on the lines assign adders[0].cin = cin; and assign adders[i+1].cin = adders[i].cout;. I have two questions:

  1. What am I doing wrong here and how can I fix it? The error doesn't make sense to me since the left hand side of both assign equations is an input to a submodule, not an argument to the ripple_adder16 module.
  2. I want to ideally replace the for loop with the following line assign adders[15:1].cin = adders[14:0].cout;, though this is a syntax error by itself. Is there any way to do something like this without straight-up inlining the full_adder?

Thank you!

PS. If it's relevant, the full_adder is implemented entirely with wires.


Solution

  • Array of instances in verilog is a type of a generate block and instantiates a module several times, adding array index to its name and doing some job with ports. Array of instances are usually not well understood and seldom used in behavioral verilog.

    Since it is a generate block, you cannot use ranges on array instances. 'adders[15:1]' is illegal. You need to use a generate loop to access them instance by instance. Also 'assign adders[15:1].cin' represents a connection to an internal signal of the submodule instance, not to its input port. So, the compiler is absolutely correct.

    You left unconnected ports of the module instances and trying to access their internal signals. It is a bad practice in the first place. To fix it you should figure out how to use port connections instead. An extra code will be needed to reassign vector to satisfy your algorithm, at least around 'carries'.