2
votes

I'm attempting to create an interface that is an array of a simpler interface. In VHDL I could simply define two types, a record and an array of records. But how to do this in SystemVerilog? Here's what I've tried:

`define MAX_TC 15

...

interface scorecard_if;
    score_if if_score [`MAX_TC];
endinterface

interface score_if;
    integer tc;
    integer pass;
    integer fail;
    bit     flag_match;
    real    bandwidth;
endinterface

But I get an error from Aldec Active-HDL:

Error: VCP2571 TestBench/m3_test_load_tb_interfaces.sv : (53, 34): Instantiations must have brackets (): if_score.

I also tried

interface scorecard_if;
    score_if  [`MAX_TC] if_score;
endinterface

and

interface scorecard_if;
    score_if [`MAX_TC];
endinterface

but both of those just resulted in "Unexpected token" syntax errors.

Is it even possible to do this? There are two workarounds that I can think of if there isn't a way to do this. First I could define all the individual elements of score_if as unpacked arrays:

interface score_if;
    integer tc         [1:`MAX_TC];
    integer pass       [1:`MAX_TC];
    integer fail       [1:`MAX_TC];
    bit     flag_match [1:`MAX_TC];
    real    bandwidth  [1:`MAX_TC];
endinterface

This compiles, but it's ugly in that I can no longer refer to a single score as a group.

I might also be to instantiate an array of score_if (using the original code), but I really want to instantiate scorecard_if inside a generate loop that would allow me instantiate a variable number of scorecard_if interfaces based on a parameter.

Just to provide a bit of explanation of what I'me trying to do, score_if is supposed to be a record of the score for a given test case, and scorecard_if an array for all of the test cases. But my testbench has multiple independent stimulus generators, monitors and scorecards to deal with multiple independent modules inside the DUT where the multiple is a parameter.

2
Try `` score_if if_score [`MAX_TC] (); `` - Greg
Thanks @Greg. That line compiles for me, but I've run into another issue when I try to reference the interface later in the code. This part works fine: score_if if_scorecard[MAX_TC]();` but later on I try to reference the interface as follows:` for (tc_idx = 1; tc_idx <= (tc_count-1); tc_idx++) begin $display(" %3d %3d %3d %g", if_scorecard[tc_idx].tc, if_scorecard[tc_idx].pass, if_scorecard[tc_idx].fail, if_scorecard[tc_idx].bandwidth); total_failures = total_failures + if_scorecard[tc_idx].fail; end //for` - Barry Moss
Sorry about the formatting, but while the formatting in the original question was really easy, I can't seem to get it to work properly in the comments and the five minute limit on editing comments doesn't allow for a lot of second chances. :( - Barry Moss
Inserting two spaces or <br/> doesn't seem to insert a carriage return. - Barry Moss
The error I get from Aldec Active-HDL regarding the reference to the if array is as follows: Instance/Gate selection with variable index is forbidden: tc_idx - Barry Moss

2 Answers

3
votes

Part 1 : Declaring an array of interfaces

Add parentheses to the end of the interface instantiation. According to IEEE Std 1800-2012, all instantiations of hierarchical instances need the parentheses for the port list even if the port list is blank. Some tools allow dropping the parentheses if the interfaces doesn't have any ports in the declaration and and the instantiation is simple; but this is not part of the standard. Best practice is to use parentheses for all hierarchical instantiation.

Solution:

score_if if_score [`MAX_TC] () ;

Syntax Citations:

  • § 25.3 Interface syntax & § A.4.1.2 Interface instantiation

    interface_instantiation ::= // from A.4.1.2
    interface_identifier [ parameter_value_assignment ] hierarchical_instance { , hierarchical_instance } ;

  • § A.4.1.1 Module instantiation

    hierarchical_instance ::= name_of_instance ( [ list_of_port_connections ] )


Part 2: Accessing elements for that array

Hierarchical references must be constant. Arrayed hierarchical instances cannot be accessed by dynamic indexes. It is an rule/limitation since at least IEEE Std 1364. Read more about it in IEEE Std 1800-2012 § 23.6 Hierarchical names, and the syntax rule is:

hierarchical_identifier ::= [ $root . ] { identifier constant_bit_select . } identifier

You could use a generate-for-loop, as it does an static unroll at compile/elaboration time. The limitation is you cannot use your display message our accumulate your fail count in the loop. You could use the generate loop to copy data to a local array and sum that, but that defeated your intention.

An interface is normally a bundle of nets used to connect modules with class-base test-bench or shared bus protocols. You are using it as a nested score card. A typedef struct would likely be better suited to your purpose. A struct is a data type and does not have the hierarchical reference limitation as modules and interfaces. It looked like you were already trying rout in your previous question. Not sure why you switched to nesting interfaces.

It looks like you are trying to create a fairly complex test environment. If so, I suggest learning UVM before spending to much time reinventing for a advance testbench architecture. Start with 1.1d as 1.2 isn't mainstream yet.

0
votes

This also works: 1. define a "container" interface:

interface environment_if (input serial_clk);
    serial_if               eng_if[`NUM_OF_ENGINES](serial_clk);
    virtual serial_if       eng_virtual_if[`NUM_OF_ENGINES];
endinterface

2. in the testbench instantiate env_if connect serial_if with generate, connect the virtual if with the non virtual and pass the virtual if to the verification env:

module testbench;
   ....
   environment_if   env_if(serial_clk);
   .....
   dut   i_dut(...);
   genvar eng_idx
   generate
   for(eng_idx=0; eng_idx<`NUM_OF_ENGINES; eng_idx++) begin
       env_if.eng_if[eng_idx].serial_bit = assign i_dut.engine[eng_idx].serial_bit;
   end
   endgenerate
   ......

   initial begin
      env_if.eng_virtual_if = env_if.eng_if[0:`NUM_OF_ENGINES-1]; 
      //now possible to iterate over eng_virtual_if[]
      for(int eng_idx=0; eng_idx<`NUM_OF_ENGINES; eng_idx++)
          uvm_config_db#(virtual serial_if)::set(null, "uvm_test_top.env", "tx_vif", env_if.env_virtual_if[eng_idx]);
   end
endmodule