jkang
jkang

Reputation: 549

Using SystemVerilog structs that contain parameters as input/output ports to a module

My struct contains parameters that vary per module. I'd like to use this struct to pass input/outputs to these modules. I'm using this for design so it has to be synthesizable and my toolchain doesn't support Interfaces unfortunately.

For example:

`ifdef MY_STRUCTS
`define MY_STRUCTS
typedef struct packed {
  logic [PARAMETER_VAL-1:0] field1;
  logic [PARAMETER1_VAL-1:0] field2;
} myStruct_t;
`endif

module top #(
  parameter PARAMETER_VAL = 8;
  parameter PARAMETER1_VAL = 16;
) (
  input myStruct_t in_packet,
  output myStruct_t out_packet,
);

Unfortunately, this seems to be a chicken-or-egg problem. The struct definition can't be compiled because it relies on the module parameters to define it. However, the input/output declarations can't be declared because it relies on the struct to know what to declare.

Does anyone have a solution to this? Would definitely appreciate suggestions.

Upvotes: 0

Views: 9373

Answers (2)

dave_59
dave_59

Reputation: 42673

Two options:

Instead of passing a list of parameter values, pass a single struct typedef with the field widths you need. You would likely want to use the struct in the upper level anyway.

module upper;
typedef struct packed {
  logic [7:0] field1;
  logic [16:0] field2;
} myStruct_t;
my_Struct in, out;
lower #(.T(my_Struct_t) ins1 (in, out);
...
endmodule
module lower #(type T) (
    input T in_packet,
    output T out_packet,
);
...
endmodule

Create the struct type inside the lower level module, but keep the ports as packed arrays. This works because the struct is packed as well.

module top #(
  parameter PARAMETER_VAL = 8;
  parameter PARAMETER1_VAL = 16;
) (
  input logic [PARAMETER_VAL+PARAMETER_VAL1-1:0] in,
  output logic [PARAMETER_VAL+PARAMETER_VAL1-1:0] out,
);

typedef struct packed {
  logic [PARAMETER_VAL-1:0] field1;
  logic [PARAMETER1_VAL-1:0] field2;
} myStruct_t;
 myStruct_t in_packet, out_packet;
assign in_packet = in;
assign out = out_packet;

Upvotes: 0

Serge
Serge

Reputation: 12354

Potentially you can also use a parameterized interface.

Disclaimer: the following code works with synopsys but fails with cadence in eda playground. I think that Cadence is in violation of the standard here (They might have fixed it in the latest version).

Anyway, here is the example

interface top_if #(int PARAMETER_VAL = 8, PARAMETER1_VAL = 16) ();

   typedef struct packed {
      logic [PARAMETER_VAL-1:0] field1;
      logic [PARAMETER1_VAL-1:0] field2;
   } myStruct_t;

   myStruct_t in_packet, out_packet;

   modport in (input in_packet);
   modport out (output out_packet);

endinterface

module caller();
   top_if #(8,16) top_if();
   always_comb top_if.in_packet = '{11, 22};

   top top(top_if.in, top_if.out);

   logic [top_if.PARAMETER1_VAL-1:0] field2;
   always_comb field2 = top_if.out_packet.field2;
   always @* begin
      $display("out.field2=%0d", field2);
   end
endmodule


module top(
           top_if in,
           top_if out
           );
   logic [in.PARAMETER_VAL-1:0] field1;

   always_comb field1 = in.in_packet.field1;
   always_comb out.out_packet = '{field1, field1+55};

   always @* begin
      $display("input.field1=%d", field1);
   end

endmodule

Upvotes: 2

Related Questions