在SystemVerilog中,可以通过简单的数据类型,复杂的数据类型(结构,联合等)或接口来连接分层模块。我感兴趣的功能是在一个地方聚合两个模块之间的所有信号,这简化了代码的维护。
例如,在下面的一个更改s_point的定义而不更改m1,m2和top的声明:
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工具的支持,并且它们不需要像接口那样被实例化(尽管仍然必须在顶层模块中声明它们)。
我的问题是,对于可综合设计,是否只需要聚合信号(即对接口的任务,函数,模型,通用接口,内部总是块等没有兴趣),哪一个更受欢迎?
interface
是首选。
只有当struct
内的所有信号都遵循相同的端口方向时,struct
才可以使用; input
,output
或inout wire
。当驾驶方向变得混杂时使用结构变得具有挑战性。混合方向是使用ref
关键字的允许,但是许多综合工具不支持ref
关键字。 inout
不能使用,因为logic
被认为是变量,IEEE Std 1800-2012§6.5网络和变量。但是,inout wire
可以用来投射struct
作为网。 stuct的组件不能在always-block中分配,而是需要assign
语句;就像一个普通的wire
。
interface
应该将端口方向不一致的信号分组。需要将三态定义为wire
,并且当与always_{ff|comb|latch}
一起使用时,变量类型不需要显式的端口方向。如果信号是协议的一部分,也应该使用它。这样可以添加断言,并且可以将其连接到UVM测试平台或其他SVTB环境的类。
仅传递显式方向数据类型时使用sturct
。使用interface
传递共享信号。
想象一下,有一组信号x
,y
和z
,其中module m_x
驱动x
并读取y
和z
,module m_b
驱动y
并读取x
和z
,模块m_z
驱动z
并读取x
和y
。每个信号只有一个驱动器,always_ff
可用于保证这一点。
如果我们尝试添加双向三态bus
,则不能使用结构。一个wire
解决了冲突的驱动程序,而logic
/ reg
clobber并保持调度程序运行。
使用struct
使用ref
(不允许三态):
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
使用struct
使用inout wire
(网必须用assign
驱动,失去单个驱动程序保证):
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
(具有三态):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