【问题标题】:Can you either, forward declare a type to be used as a port type or can you use an interface as an external port?您可以转发声明一个用作端口类型的类型,还是可以将接口用作外部端口?
【发布时间】:2026-02-10 11:25:02
【问题描述】:

我正在尝试在 SystemVerilog 中设计一些硬件,但遇到了一个我无法找到答案的问题。情况是我有一个*模块(跟踪器),它需要有一个特定类型的输出端口。此类型是在参数化接口内指定的类型定义结构,因为此类型定义需要在*模块的某些子模块之间共享。我希望能够拥有接口中指定类型的输出端口,并能够将该类型传递给各种子模块以用于其他目的。

至关重要的是,我还在尝试将此硬件作为 Vivado 中的自定义 IP 的一部分(这是一个更大项目的一部分),因此我的目标是创建一个*模块,其中有一些我可以定义的参数并且模块的其余部分被完全封装。我意识到这最终将涉及在所有内容之上放置一个 Verilog 包装器,但目前我只专注于让它在模拟中正确运行。

我遇到的问题是,由于必须实例化接口,因此您不能将其用作*端口,因为您将在哪里实例化接口?但是,因为我所做的只是在接口内引用 typedef,所以我可以以某种方式转发声明这些,以便我可以将类型称为端口类型并将其传递给其他子模块?

所以基本上有人对我如何实现这一点有任何想法吗?如果我完全不正确地解决这个问题,请随时告诉我,将 typedef 捆绑到接口中的想法是由 dave59 提供的 (https://verificationacademy.com/forums/systemverilog/parameterized-struct-systemverilog-design),我花了一天试图解决这个问题,但一无所获。非常感谢任何帮助,我很乐意提供任何进一步的说明。

这里是每个当前的代码。为了清楚起见,它们都在同一个文件中声明。

接口定义

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

*模块

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

【问题讨论】:

  • 仅供参考,一些综合工具让您拥有一个带接口端口的*模块。它们具有特殊的命令 (DC),用于提供它们将连接到的参数化接口信息。
  • 你知道 Vivado 是否支持这个?

标签: system-verilog vivado


【解决方案1】:

如果您发布MCVE,这些事情会更容易。我想你要问的是:

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

如果是这样,我认为您需要将您的 struct 放入一个包中:

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_

【讨论】:

  • 您能否像使用模块参数一样将 localparams 指定为 Vivado 自定义 IP 的一部分?
  • 我不知道,对不起。这个参数需要从外面指定吗?
  • 我正在努力使硬件完全封装,因为目前它依赖于一个充满定义宏的文件,该文件在此和处理器之间共享,我正在尝试将它们分开。我想我可能会坚持这种方法。这似乎比它的价值更麻烦
  • 潜在地,该标准提供了type 运算符,它可以用于以更自然的方式处理这种情况。但是,我不知道任何实现它的编译器。