Parameterizing the Bit Widths of fields in a packed struct so that modules can infer bit width if used in port map - virtual interface - interface - compile time configured struct bit width

Also discussed at:
https://forums.xilinx.com/t5/Synthesis/Parameterizing-the-Bit-Widths-of-fields-in-a-packed-struct-so/td-p/1191678

I am having trouble accomplishing my intent in SystemVerilog trying to use the latest language features to make my code more elegant and less verbose.

I would like to accomplish the following:

  • be able to parameterize the bit widths of fields in a packed struct that I want to define … I have attempted to accomplish this using a parameterized interface construct
  • I would like for modules with that parameterized interface as an INPUT to the module to be able to infer the bit width of a field inside that packed struct defined inside the interface

I have been mostly successful in past experiments but I have run into an issue.

Please see the following simple interface definition:


interface MyInterface #(int DATA_W, ADDR_W) () ;

  typedef struct packed
    { logic                valid
    ; logic [ADDR_W-1:0]   addr
    ; logic [DATA_W-1:0]   data
    ; } SimpleStruct;

  SimpleStruct bus;
  logic ready;
  
  modport SNK (input  bus, output ready);
  modport SRC (output bus, input  ready);

endinterface

It is easy enough to instantiate an interface and use it at the input of a simple module in my Top module for this example:


module TopTest 
  ( input wire Clock
  , input wire Reset
  , input wire [31:0] In
  , output wire dummyOut
  ) ;

  MyInterface # ( 32, 3 ) my_interface ();

  assign my_interface.bus.data = In ;
  assign my_interface.bus.addr = 3'h3 ;

  InnerTest inst_mod_inner_test
    ( .Clock( Clock )
    , .Reset( Reset )
    , .Sink( my_interface )
    ) ;

  assign dummyOut = my_interface.ready ;

end module

The problem that I am running into is that I do not want to parameterize the actual module with field bit widths, because I believe that at compile time the bit widths of the fields should be already established and accessible. This seems to not be the case, and I am wondering if there is anything I can do to accomplish inferring the bit width of the packed struct in the interface (remember that is the case because I want it parameterized, I know it is easy to get $bits of a field of a struct that is not defined in an interface but instead defined in a package or module)


module InnerTest 
  ( input wire Clock
  , input wire Reset
  , MyInterface.SNK Sink
  ) ;

  localparam BIT_WIDTH_SINK_DATA = $bits( Sink.bus.data ) // this line errors out b/c sink is 'virtual'

  RAM # ( .DATA_WIDTH( BIT_WIDTH_SINK_DATA ) ) ram ( ... // etc

  ... other code to drive output ready of interface ...

end module

There are many reasons why a designer would want to make a module “parameterizable” and I have taken that approach in the past, but I am very interested in not duplicating information. If I were to take the easy approach, I would simply parameterize my inner test module so that I provided it DATA_WIDTH, but I would then have two numbers to update and a lot of parameters that I feel I do not need. I think it would be most elegant if I could simply infer characteristics of the parameterized struct somehow. The information I am looking for is truly known at compile time in my opinion. I just can’t seem to access it, or this is another shortfall of SystemVerilog.

In reply to Ian.L.Kennedy:

The current SystemVerilog BNF does not allow any dotted “.” names in a parameter initialization. But you can get around this by using a typedef instead

interface MyInterface #(int DATA_W=0, ADDR_W=0) () ;
  typedef  logic [DATA_W-1:0]   data_t;
  ...
endinterface

module InnerTest 
  ( input wire Clock
  , input wire Reset
  , MyInterface.SNK Sink
  ) ;
 
  typedef Sink.data_t data_t;
  localparam BIT_WIDTH_SINK_DATA = $bits( data_t );
  ...
endmodule

In reply to dave_59:

What is BNF?

The formal syntax of SystemVerilog is described using Backus-Naur Form (BNF). The syntax of SystemVerilog source is derived from the starting symbol source_text?

In reply to Ian.L.Kennedy:

BNF defines the syntax rules of the language. For example, the BNF grammar rules determines whether the symbol ‘<=’ represents a non-blocking assignment operator or a less-than or equal relational operator. Once you know which operator you have, the LRM describes the behavior of each operator.

The BNF rules for the dot ‘.’ operator are complex. Just remember that a parameter cannot be assigned with an expression containing hierarchical references.

In reply to dave_59:

Interesting! Thanks for explaining.

If you are interested, this syntax is synthesizable in vivado

https://forums.xilinx.com/t5/Synthesis/Parameterizing-the-Bit-Widths-of-fields-in-a-packed-struct-so/td-p/1191678