Systemverilog Testbench how to deal with configurable number of interfaces

558 views Asked by At

I have a design to verify. The design is similar to a network router. It has a number of FIFO input interfaces and a number of FIFO output interfaces. So the same group of interfaces will repeat over and over. DUT example:

module router(
    input logic [0:NUM_IN] sop_i,
    input logic [0:NUM_IN] eop_i,
    input logic [0:NUM_IN][128:0] data_i,

    output logic [0:NUM_OUT] sop_o,
    output logic [0:NUM_OUT] eop_o,
    output logic [0:NUM_OUT][128:0] data_o,
)
......
endmodule

So I think in my testbench the number of drivers should also be configurable, since I want to drive each FIFO interface separately.

interface fifo_intf;
    logic sop;
    logic eop;
    logic [128:0] data
endinterface

So the first issue is how to connect this interface to DUT. I am looking at something like

module tb_top;
...
top_intf top_if();

router dut (.sop_i(top_if.connect_if.sop)
            .eop_i(top_if.connect_if.eop),
            .data_i(top_if.connect_if.data))
endmodule

interface connect_intf #(NUM);
    logic [0:NUM-1] sop;
    logic [0:NUM-1] eop;
    logic [0:NUM-1][128:0] data;
endinterface

I also think it might be easier to pass a top interface wrapper to the env since, the number of FIFO interfaces are parameterized. So,

interface top_intf:
    fifo_intf fifo_if_input[`NUM_IN]();
    fifo_intf fifo_if_output[`NUM_OUT]();
    connect_intf #(`NUM_IN)connect_if();
endinterface

Then I need to do some routing from connect interface to fifo interface

   genvar i;
    generate
        for (i = 0; i < NUM_IN; i++) begin
            assign connect_if.sop[i]   = fifo_if_i[i].sop;
    endgenerate

But there are some issues when I pass the top_intf into testbench environment.

class env;
// local interfaces to avoid hierarchical reference??
virtual fifo_intf fifo_if_i[`NUM_IN];
virtual fifo_intf fifo_if_o[`NUM_OUT];

function env::new(virtual top_intf top_vif);
    this.top_vif = top_vif;
    fifo_if_i[0:`NUM_IN-1] = top_vif.fifo_if_input[0:`NUM_IN-1];
    fifo_if_o[0:`NUM_OUT-1] = top_vif.fifo_if_output[0:`NUM_OUT-1];
endfunction: new
endclass;

This works fine with NUM_In andNUM_OUT greater than 1. But having some issues when the NUM is 1. the error is

  Incompatible complex type assignment
  Type of source expression is incompatible with type of target expression. 
  Mismatching types cannot be used in assignments, initializations and 
  instantiations. The type of the target is 'virtual interface 
  fifo_intf$[0:0]', while the type of the source is 'interface fifo_intf'.
  Source Expression: this.top_vif.fifo_if_input[0]

What I am doing now is setting some defines to indicate what the NUM_IN value is, for example

`ifdef PROJ_A
    `define NUM_IN_IS_1
`elsif PROJ_B
    `define NUM_IN_IS_2
`endif

then

in another include file

`ifdef NUM_IN_IS_1
    fifo_if_i[0] = top_vif.fifo_if_input[0];
`elsif NUM_IN_IS_2
    fifo_if_i[0] = top_vif.fifo_if_input[0];
    fifo_if_i[1] = top_vif.fifo_if_input[1];  
`endif 

I think we can use some script to generate the testbench code, but I am trying to look for a way without scripting. I am open to suggestions. How do you deal with this design situation in you testbench?

Thanks a lot!

1

There are 1 answers

9
Tudor Timi On

To avoid the array to array assignments, roll them up inside for loops:

function env::new(virtual top_intf top_vif);
    this.top_vif = top_vif;

    foreach (fifo_if_i[i])
      fifo_if_i[i] = top_vif.fifo_if_input[i];

    foreach (fifo_if_o[i])
      fifo_if_o[i] = top_vif.fifo_if_output[i];
endfunction: new