System verilog 连接分层模块:SystemVerilog中的结构与接口

System verilog 连接分层模块:SystemVerilog中的结构与接口,system-verilog,System Verilog,在SystemVerilog中,分层模块可以通过简单数据类型、复杂数据类型(结构、联合等)或接口连接。我感兴趣的特性是将两个模块之间的所有信号聚合在一个地方,这简化了代码的维护 例如,在以下示例中,在不更改m1、m2和top声明的情况下更改s_点的定义: typedef struct { logic [7:0] x; logic [7:0] y; } s_point; // named structure module m1 (output s_point outPoint); /

在SystemVerilog中,分层模块可以通过简单数据类型、复杂数据类型(结构、联合等)或接口连接。我感兴趣的特性是将两个模块之间的所有信号聚合在一个地方,这简化了代码的维护

例如,在以下示例中,在不更改m1、m2和top声明的情况下更改s_点的定义:

 typedef struct {
  logic [7:0] x;
  logic [7:0] y;
} s_point; // named structure


module m1 (output s_point outPoint);
//
endmodule

module m2 (input s_point inPoint);
//
endmodule

module top ();
    s_point point;
    m1 m1_inst (point);
    m2 m2_inst (point);
endmodule
或者,这可以使用接口来完成。 然而,我相信使用结构更容易,并且它们受到更多CAD工具的支持,并且它们不需要像接口那样实例化(尽管仍然需要在顶部模块中声明它们)


我的问题是,如果综合设计只需要聚合信号(即对接口的任务、功能、模块端口、通用接口、内部始终块等不感兴趣),那么首选哪一种?

接口
是首选的

struct
中的所有信号都遵循相同的端口方向时,A
struct
可以仅使用<代码>输入,
输出
,或
输入输出线
。当行驶方向混合时,使用结构变得很有挑战性。混合方向允许使用
ref
关键字,但是许多合成工具还不支持
ref
关键字<无法使用代码>输入,因为
逻辑
被视为一个变量,§6.5网络和变量。但是,
inout wire
可用于将
struct
转换为网络。stuct的组件不能在always块中赋值,需要使用
assign
语句;就像普通的
电线一样

接口
应该是端口方向不一致的分组信号。三态需要定义为
wire
,变量类型在与
始终{ff | comb | lock}
结合使用时不需要明确的端口方向。如果信号是协议的一部分,也应使用它。这样就可以添加断言,并将其连接到UVM测试台或其他SVTB环境的类

仅传递显式方向数据类型时,使用
sturct
。使用
接口
传递共享信号

示例Senario: 假设有一组信号
x
y
z
,其中
模块m_x
驱动
x
,读取
y
模块m_b
驱动
y
,读取
x
z
,模块
m_z
驱动
z
并读取
x
y
。每个信号只有一个驱动器,可以使用
始终\u ff
来保证这一点

如果我们尝试将双向三态
总线添加到混合中,则无法使用该结构。
wire
解决冲突的驱动程序,同时
logic
/
reg
关闭并保持调度程序运行

示例代码: 使用
struct
使用
ref
(不允许三态):

使用
接口
(带三态):
接口如果_点;
逻辑[7:0]x,y,z;
导线[7:0]总线;//三态必须是有线的
端接口
模块m_x_if(if_point point,输入时钟);
始终_ff@(posedge clk)

点.x一个更正:您可以使用
struct
数据类型作为
连接
,因此可以连接到
inout
端口,但仍然存在每个
struct
端口只有一个方向规范的问题。@dave_59很好,我从“6.7.1内置网络类型的网络声明”中漏掉了这个问题,我已经更新了我的答案。谢谢你的意见。断言和在一个接口中具有多向信号当然是使用接口的一个很好的理由,而不是为输入定义一个结构,为输出定义一个结构。然而,根据我的经验,合成工具仍然需要明确定义信号方向的modports。至少在我的经验中,三州和inout端口并不常见。但是让我使用接口的另一个原因是参数化它们的能力,这与简单结构不同。@Ari,如果这个答案有用,请单击“接受”。如果没有,还需要什么额外的信息?@Greg:我对你的答案投了赞成票,但我不同意界面总是首选的。许多常见的设计没有双向或三向信号。为了使基于接口的设计可以合成,您应该定义modports。如果设计在结构上不需要输入/输出信号的聚合,为什么不在一个结构中有输入,在另一个结构中有输出,以获得大多数合成工具支持的不太复杂的代码(有些工具还不完全支持接口)。根据我的经验,接口在实现复杂的总线事务时最有用。
typedef struct {logic [7:0] x, y, z, bus; } s_point;

module m_x_st (ref s_point point, input clk);
  always_ff @(posedge clk)
    point.x <= func(point.y, point.z);
  //assign point.bus = (point.y!=point.z) ? 'z : point.x; // NO tir-state
endmodule
module m_y_st (ref s_point point, input clk);
  always_ff @(posedge clk)
    point.y <= func(point.x, point.z);
  //assign point.bus = (point.x!=point.z) ? 'z : point.y; // NO tir-state
endmodule
module m_z_st (ref s_point point, input clk);
  always_ff @(posedge clk)
    point.z <= func(point.x, point.y);
  //assign point.bus = (point.x!=point.y) ? 'z : point.z; // NO tir-state
endmodule

module top_with_st (input clk);
    s_point point;
    m_x_st mx_inst (point,clk);
    m_y_st my_inst (point,clk);
    m_z_st mz_inst (point,clk);
endmodule
typedef struct {logic [7:0] x, y, z, bus; } s_point;

module m_x_wst (inout wire s_point point, input clk);
  logic [$size(point.x)-1:0] tmp;
  assign point.x = tmp;
  always_ff @(posedge clk)
    tmp <= func(point.y, point.z);
  assign point.bus = (point.y!=point.z) ? 'z : point.x; // tir-state
endmodule
module m_y_wst (inout wire s_point point, input clk);
  logic [$size(point.y)-1:0] tmp;
  assign point.y = tmp;
  always_ff @(posedge clk)
    tmp <= func(point.x, point.z);
  assign point.bus = (point.x!=point.z) ? 'z : point.y; // tir-state
endmodule
module m_z_wst (inout wire s_point point, input clk);
  logic [$size(point.z)-1:0] tmp;
  assign point.z = tmp;
  always_ff @(posedge clk)
    tmp <= func(point.x, point.y);
  assign point.bus = (point.x!=point.y) ? 'z : point.z; // tri-state
endmodule

module top_with_wst (input clk);
    wire s_point point; // must have the 'wire' keyword
    m_x_wst mx_inst (point,clk);
    m_y_wst my_inst (point,clk);
    m_z_wst mz_inst (point,clk);
endmodule
interface if_point;
  logic [7:0] x, y, z;
  wire  [7:0] bus; // tri-state must be wire
endinterface

module m_x_if (if_point point, input clk);
  always_ff @(posedge clk)
    point.x <= func(point.y, point.z);
  assign point.bus = (point.y!=point.z) ? 'z : point.x;
endmodule
module m_y_if (if_point point, input clk);
  always_ff @(posedge clk)
    point.y <= func(point.x, point.z);
  assign point.bus = (point.x!=point.z) ? 'z : point.y;
endmodule
module m_z_if (if_point point, input clk);
  always_ff @(posedge clk)
    point.z <= func(point.x, point.y);
  assign point.bus = (point.x!=point.y) ? 'z : point.z;
endmodule

module top_with_if (input clk);
    if_point point();
    m_x_if mx_inst (point,clk);
    m_y_if my_inst (point,clk);
    m_z_if mz_inst (point,clk);
endmodule