1
votes

I'm trying to design some hardware in SystemVerilog and I've run into a problem I can't find the answer to. The situation is that I have a top level module (tracer), which needs to have an output port of a particular type. This type is a typedefed struct which is specified inside an parameterised interface, as this type definition needs to be shared among some of the submodules of the top level module. I want to be able to have an output port that is of a type specified in the interface and to be able to pass that type into various submodules for other purposes.

Crucially I'm also trying to make this hardware as a piece of Custom IP in Vivado (this is one part of a larger project) so I'm aiming for a top-level module where there are some parameters I can define and the rest of the module is fully encapsulated. I realise this will involve placing a Verilog wrapper on top of everything in the end but at the moment I'm just focussing on getting it to run in simulation correctly.

The problem I've had is that because interfaces have to be instantiated you can't use one as a top-level port because where would you instantiate the interface? However because all I'm doing is referring to typedefs inside the interface surely I can forward declare these somehow so that I can refer to the type as a port type and pass it into other submodules?

So essentially does anyone have any idea as to how I might achieve this? If I'm going about this entirely incorrectly then feel free to tell me, the idea of bundling up the typedefs into an interface was provided by dave59 here (https://verificationacademy.com/forums/systemverilog/parameterized-struct-systemverilog-design), and I've spent a day trying to solve this and have got nowhere. Any help gratefully appreciated and any further clarifications I'll happily provide.

Here is the code for each as it currently stands. These are both declared in the same file just for clarity.

Interface Definition

interface trace_if #(
parameter TDATA_WIDTH = 32, 
parameter INSTR_ADDR_WIDTH = 32, 
parameter INSTR_DATA_WIDTH = 32,
parameter DATA_ADDR_WIDTH = 32);

... (IF_DATA etc. defined here)

typedef struct packed {
    bit [INSTR_DATA_WIDTH-1:0] instruction;
    bit [INSTR_ADDR_WIDTH-1:0] addr;
    bit pass_through;
    IF_data if_data;
    ID_data id_data;
    EX_data ex_data;
    WB_data wb_data;
 } trace_format;

 trace_format trace_output;

endinterface

Top-Level Module

module tracer
#(
parameter INSTR_ADDR_WIDTH = 32,
parameter INSTR_DATA_WIDTH = 32,
parameter DATA_ADDR_WIDTH = 32,
parameter TDATA_WIDTH = 32,
parameter TRACE_BUFFER_SIZE = 64
)
(   
... other ports declared
trace_if.trace_output trace_data_o
);
// Instantiating the interfaces for communication between submodules

logic if_data_valid;
trace_if #(TDATA_WIDTH, INSTR_ADDR_WIDTH, INSTR_DATA_WIDTH, DATA_ADDR_WIDTH) if_data_o();
logic id_data_ready;
trace_if #(TDATA_WIDTH, INSTR_ADDR_WIDTH, INSTR_DATA_WIDTH, DATA_ADDR_WIDTH) id_data_o();
logic ex_data_ready;
trace_if #(TDATA_WIDTH, INSTR_ADDR_WIDTH, INSTR_DATA_WIDTH, DATA_ADDR_WIDTH) ex_data_o();
logic wb_data_ready;

// Instantiating the submodules

if_tracker if_tr (.*);
id_tracker #(INSTR_DATA_WIDTH, DATA_ADDR_WIDTH, TRACE_BUFFER_SIZE) id_tr(.if_data_i(if_data_o), .*);
ex_tracker #(DATA_ADDR_WIDTH, 256, TRACE_BUFFER_SIZE) ex_tr(.id_data_i(id_data_o), .wb_previous_end_i(previous_end_o), .*);
wb_tracker #(TRACE_BUFFER_SIZE) wb_tr(.ex_data_i(ex_data_o), .wb_data_o(trace_data_o), .*);

... other module related stuff

endmodule
1
FYI, some synthesis tools let you have a top level module with interface ports. They have special commands (DC) for providing the paramterized interface infrmation they would be connected to.dave_59
Do you know if Vivado supports this?Jonathan Rainer

1 Answers

1
votes

These things are easier if you publish an MCVE. I think what you are asking is this:

interface i #(parameter p = 1);

  typedef struct packed {
    bit [p-1:0] b;
  } s_t;

  s_t s;

endinterface

module m #(parameter p = 1) ( /* how can I have a port of type s_t ? */ );

  i i0 ();

endmodule

If so, I think you need to put your struct in a package:

package pkg;

  localparam l = 1;

  typedef struct packed {
    bit [l-1:0] b;
  } s_t;

endpackage

interface i #(parameter p = pkg::l);

  pkg::s_t s;

endinterface

module m #(parameter p = pkg::l) ( pkg::s_t s );

  i i0 ();

endmodule

https://www.edaplayground.com/x/4zQ_