Search code examples
system-verilogmodelsimquartus

SystemVerilog error in multiplexing channels : nonconstant index into instance array


I'm designing a module that accepts multiple channels and outputs one channel. Each channel consists of valid signal and data of some widths. If a channel has valid data, the module should output that channel. If multiple channels have valid data, the module should output one of them (in my case, channel with highest index) and rests are dropped.

My simple implementation looks like this:

module test1 #(
  parameter NUM_CHANNEL = 8,
  parameter DATA_WIDTH = 512
) (
  input logic [DATA_WIDTH - 1 : 0] data_in [NUM_CHANNEL],
  input logic valid_in [NUM_CHANNEL],
  output logic [DATA_WIDTH - 1 : 0] data_out,
  output logic valid_out
);

  always_comb begin
    valid_out = 0;
    for (int i = 0; i < NUM_CHANNEL; ++i) begin
      if (valid_in[i]) begin
        valid_out = 1;
        data_out = data_in[i];
      end
    end
  end

endmodule

This works perfectly in both simulation and real circuit (FPGA).

However, channel can be complex type so I used interface like this:

interface channel #(
  parameter DATA_WIDTH = 512
);

  logic valid;
  logic [DATA_WIDTH - 1 : 0] data;

  modport in (
    input valid,
    input data
  );

  modport out (
    output valid,
    output data
  );

endinterface // sub_csr_if

module test #(
  parameter NUM_CHANNEL = 8,
  parameter DATA_WIDTH = 512
) (
  channel.in in[NUM_CHANNEL],
  channel.out out
);

  always_comb begin
    out.valid = 0;
    for (int i = 0; i < NUM_CHANNEL; ++i) begin
      if (in[i].valid) begin
        out.valid = 1;
        out.data = in[i].data;
      end
    end
  end

endmodule

Then, this code gets Nonconstant index into instance array 'sub_port'. error in ModelSim, and i is not a constant error in Quartus.

If I unroll the loop, it works but it becomes non-parametric code. (only works for fixed NUM_CHANNEL)

Why the latter one does not work, while the first one works flawlessly?


Solution

  • An array of instances (module or interface) is not a true array type. As your error message indicates, you cannot select a particular instance with a variable index. With a true array, every element is identical. Because of the way parameterization, defparam, and port connections work, each instance element could have differences. The elaboration process essentially flattens all hierarchy before simulation begins.

    What you can do is use a generate construct to select your instance as follows ;

    module test #(
      parameter NUM_CHANNEL = 8,
      parameter DATA_WIDTH = 512
    ) (
      channel.in in[NUM_CHANNEL],
      channel.out out
    );
    
    logic                     _valid[NUM_CHANNEL];
    logic [DATA_WIDTH - 1 : 0] _data[NUM_CHANNEL];
    
    for (genvar ii=0;ii<NUM_CHANNEL;ii++) begin
         assign _valid[ii] = in[ii].valid;
         assign _data[ii] = in[ii].data;
    end
      always_comb begin
        out.valid = 0;
        for (int i = 0; i < NUM_CHANNEL; ++i) begin
          if (_valid[i]) begin
            out.valid = 1;
            out.data = _data[i];
          end
        end
      end
    
    endmodule