VIPs come with pre-coded interfaces which are required to be used by the integrator. There are a number of different interface coding methods which include bi-direction ports and require different wire-up connection methods to a DUT. This post presents different interface/DUT connection implementations and to limitations found in each different methodology.
Interface Nets Defined in its Port List
When the interface is coded with connection nets in its port list, a connecting wire between the interface and DUT instances is sufficient to create a connection between the two.
An interface with nets defined in its port list gives the most flexibility for wire-up connections. In some cases the connection could be simplified even more if the DUT and interface have the same port names by using the ".name" or ".*" conventions described in sections 23.3.2.3 and 23.3.2.4 of the SV2012 LRM. However, when using third party IPs and VIPs, the probability of design and interface ports having the same naming convention is not high and cannot be expected.
This implementation has a limitation: if the DUT is auto-instantiated, the connection to the DUT can be overridden when modifications are made to the port list.
interface some_interface(inout wire bidir1, inout wire bidir2, input logic in1 ); endinterface: some_interface //----------------------------// module tb(); wire sig1; wire sig2; wire sig3; . . some_interface s_if( .bidir1(sig1), .bidir2(sig2), .in1( sig3) ); dut my_dut(.sig1(sig1), .sig2(sig2), .sig3(sig3), . . ); endmodule: tb
An interface with nets defined in its port list gives the most flexibility for wire-up connections. In some cases the connection could be simplified even more if the DUT and interface have the same port names by using the ".name" or ".*" conventions described in sections 23.3.2.3 and 23.3.2.4 of the SV2012 LRM. However, when using third party IPs and VIPs, the probability of design and interface ports having the same naming convention is not high and cannot be expected.
Interface Nets Defined in the Interface
Another popular method is to define the interface nets within the interface and then create a connection via a cross module reference between the DUT port and the interface signal. A number of different connection implementations for this coding method are detailed in the subsequent sections.
Use Assign Statements in the TB
Connect the nets by assigning either the DUT or interface with the directional continuous assign statement. This method is feasible for directional nets, in or out, but will not suffice for a bi-directional net as only one of the sides can be the driver.
interface some_interface(); wire bidir1; wire bidir2; logic in1; endinterface: some_interface //----------------------------// module tb(); wire sig1; wire sig2; wire sig3; . . some_interface s_if(); dut my_dut(.sig1(sig1), .sig2(sig2), .sig3(sig3), . . ); assign s_if.in1 = sig3; // Can't connect bi-direction ports using this method! //assign bidir1 //assign bidir2 endmodule: tb
Direct Instantiation of interface signals to the DUT Instance
A solution which works for both directional and bi-directional port types is to embed the interface nets to the DUT instance ports using cross module references.
interface some_interface(); wire bidir1; wire bidir2; logic in1; endinterface: some_interface //----------------------------// module tb(); some_interface s_if(); // can be an issue for auto-instatiated DUT dut my_dut(.sig1(s_if.bidir1), .sig2(s_if.bidir2), .sig3(s_if.in1), . . ); endmodule: tb
This implementation has a limitation: if the DUT is auto-instantiated, the connection to the DUT can be overridden when modifications are made to the port list.
Connecting Ports to Interface nets with Verilog Primitives
Verilog provides many primitives to model hardware behavior. These primitives, used in the TB, can bridge between the DUT and interface internal nets including bi-directional ports. The Verilog primitive tran can create connections which allow bi-directional drivers.
interface some_interface(); wire bidir1; wire bidir2; logic in1; endinterface: some_interface //----------------------------// module tb(); wire sig1; wire sig2; wire sig3; some_interface s_if(); dut my_dut(.sig1(sig1), .sig2(sig2), .sig3(sig3), . . ); // create connection with tran primitive tran(s_if.bidir1, sig1); tran(s_if.bidir2, sig2); // directional nets can use continuous assign statements assign s_if.in1 = sig3; endmodule: tb
Controllable Connectivity
Sometimes it is necessary to create different connections for pins with multiple functionality. The Verilog primitives of tranif0 or tranif1 provide a controlled connection to the DUT. These primitives behave the same as the tran primitive with the exception of an enable input connecting or disconnecting the terminals accordingly.interface some_interface(); wire bidir1; wire bidir2; logic in1; endinterface: some_interface //----------------------------// module tb(); wire sig1; wire sig2; wire sig3; wire s_if_control = 1; // default is to short the terminals some_interface s_if(); dut my_dut(.sig1(sig1), .sig2(sig2), .sig3(sig3), . . ); // create connection with tranif1 primitive tranif1(s_if.bidir1, sig1, s_if_control); tranif1(s_if.bidir2, sig2, s_if_control); // directional nets can use continuous assign statements assign s_if.in1 = sig3; endmodule: tb
No comments:
Post a Comment