Search code examples
verilogsystem-verilogtest-bench

SystemVerilog testbench: Making an array of logic with run-time determined width


I have a class in SystemVerilog that represents an abstract data transaction in my system. It looks something like this:

class #(param BIT_DEPTH) MyData;
    logic [BIT_DEPTH-1:0] thedata [];
    metadata_type_t some_info_about_thedata;
    
    //...
endclass

Each data element in the array is an integer representing a measurement of a physical phenomenon from a piece of scientific equipment (unfortunately I can't be more specific than this). There are many valid choices for the length of these integers - they can be any length (any length less than about 32b). The length will be uniform in a single set of physical measurements. Nominally the bitdepth of the measurements is fixed, but varies depending on system configuration.

I want to put a bunch of my_data with BIT_DEPTH that's unknown at simulation time into a queue.

I tried inheriting from a base class...

class MyBaseData;
    int bit_depth;
endclass

class #(param BIT_DEPTH) MyData extends MyBaseData;
    logic [BIT_DEPTH-1:0] thedata [];
    metadata_type_t some_info_about_thedata;
    
    function new(metadata_type_t md);
        this.bit_depth = BIT_DEPTH;
        this.some_info_about_thedata = md;
        this.thedata = new[some_info_about_thedata.thedatasize];
    endfunction
endclass

But obviously this doesn't work: I can't make an object with unknown parameter values at runtime:

    MyBaseData mbd = queue.pop_back();
    MyData#(mbd.bit_depth) mydata;         // obviously not allowed
    $cast(mydata, mbd);

What I really want is to have a packed logic datatype whose width is only known at runtime.

Any workaround for this? I think the obvious solution is to say "store them in an int, record the bitdepth somewhere, and be done with it", but that feels very inelegant to me. It seems like the language should have a mechanism for this; if it does, I'd like to know about it.

To be completely clear: this code is for a testbench. I in no way expect it to be synthesizable.


Solution

  • SystemVerilog is statically typed. The width of a variable whose type is a packed array, must be known before runtime so the code for expressions referencing those variables can be generated.

    The most common way people deal with this is just using a fixed sized packed array with the maximum size you need. Record the actual size you need and use that to mask the upper bits as needed.

    Another option is using a 2-dimensional unpacked dynamic array if bits, or some multiple number of bits

    bit mydata[][];       // dynamic array of a dynamic array of bits
    bit [7:0] mydata[][]; // dynamic array of a dynamic array of bytes
    

    Yet another option is creating an unparameterized abstract base class, and extendit it with a parameterized class.

    interface class base_data;
      pure virtual function void initialize(int size);
      pure virtual function int sum();
      pure virtual function bit sum_compare(base_data rhs);
    endclass
    class mydata#(int WIDTH) implements base_data;
      
      typedef bit [WIDTH-1:0] data_t;
      data_t data[];;
      virtual function void initialize(int size);
        data = new[size];
        void'(std::randomize(data));
      endfunction
      virtual function int sum;
        return data.sum with (int'(item));
      endfunction
      virtual function bit sum_compare(base_data rhs);
        mydata#(WIDTH) R;
        if($cast(R,rhs))
          return data.sum < R.sum;
        else
          $error("widths do not match");
      endfunction
    endclass
    
    module top;
      base_data array[4];
      mydata#(4) C0 = new;
      mydata#(4) C1 = new;
      mydata#(8) C2 = new;
      mydata#(8) C3 = new;
      
      initial 
      begin
        array[0] = C0;
        array[1] = C1;
        array[2] = C2;
        array[3] = C3;
        foreach(array[i]) begin
          array[i].initialize(i+5);
          $display("sum array[%0d] %d",i,array[i].sum);
        end
      end
    endmodule
     
    

    Without knowing why you think you need to store these data elements in arrays of different sizes and not 32-bit integers or what operations you need to perform on these elements, it is difficult to suggest the best solution (XY problem).