Connecting hierarchical modules: struct vs interface in SystemVerilog

做~自己de王妃 提交于 2019-12-04 11:23:22

interface is preferred.

A struct okay to use only when all the signals within the struct all follow the same port direction; input, output, or inout wire. It becomes challenging to use structs when driving directions become mixed. Mixed direction is a allow using the ref keyword, however the ref keyword is not supported by many synthesis tools, yet. inout cannot be used because logic is considered a variable, IEEE Std 1800-2012 § 6.5 Nets and variables. However, inout wire can be used to cast the struct as a net. The components of a stuct can not be assigned within an always-block and needs an assign statement instead; just like a regular wire.

An interface should be grouping signals where the port direction is not consistent. Tri-states need to be defined as wire and the variable types do not require explicit port direction when used in conjunction with always_{ff|comb|latch}. It should also be used if the signals are part of a protocol. This way assertions can be added and it can be connected to a classes for an UVM test-bench or other SVTB environment.

Use a sturct when only passing a explicit direction data type. Use an interface for passing shared signals.

Example Senario:

Imagine there is a collection of signals x,y,&z, where module m_x drives x and reads y&z, module m_b drive y and reads x&z, and module m_z drives z and reads x&y. Each signals have only one driver and always_ff can be used to guarantee this.

If we try adding a bidirectional tri-state bus, to the mix then the struct cannot be used. A wire resolves conflicting drivers while logic/reg clobber and keep the scheduler running.

Sample code:

Using struct using ref (no tri-state allowed):

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

Using struct using inout wire (nets must be driven with assign, loses single driver guarantee):

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

Using interface (with tri-state):

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

Running code: http://www.edaplayground.com/s/6/1150

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!