Can anybody please help me out with how to write test benches for inout ports in Verilog? I can't instantiate them as reg type variables in the test bench.
Verilog testbench for inout
verilog
Related Solutions
If you have two modules, and you want to use one in the other then you instantiate and connect the desired ports together.
For instance, if you have a top module with the signals clk
, rst_count
, inc_count
and count_out
and you are wanting to instantiate a (already written) Counter module with the name "MyCount" and with port names clk
, rst
, inc
and data_out
in it:
Counter MyCount (.clk(clk),
.rst(rst_count),
.inc(inc_count),
.data_out(count_out));
An excellent starting book that will take you through Verilog for synthesis (as opposed to the large part of the language which cannot be used in this way, and is primarily for simulation) is Pong Chu's "FPGA Prototyping with Verilog Examples".
The simplest solution is split output and input for the driver modules.
module driver0 #(paramerter N=8)(input [N-1:0] sig_in, output sig_out);
assign sig_out = 'b1; // drive with some real value
endmodule
module driver1 #(paramerter N=8)(input [N-1:0] sig_in, output sig_out);
assign sig_out = 'b1; // drive with some real value
endmodule
You can allow the output to also be an input of the same module in top
module top();
paramerter N=8;
wire [N-1:0] sig;
driver0 #(N) u0(.sig_in(sig), .sig_out(sig[0]));
driver1 #(N) u1(.sig_in(sig), .sig_out(sig[1]));
endmodule
Or you can prevent the driver's output to feedback by slicking the array for the input. This may take a bit more caution. You could partition the inputs signals as two or more as well. Which ever is more intuitive easier manage for the project.
module top();
paramerter N=8;
wire [N-1:0] sig;
driver0 #(N-1) u0(.sig_in(sig[N-1:1]), .sig_out(sig[0]));
driver1 #(N-1) u1(.sig_in({sig[N-1:2],sig[0]}), .sig_out(sig[1]));
endmodule
Since IEEE Std 1364-2001, Verilog allows some fancy port definitions. See IEEE Std 1364-2001 § 12.3.3 Port declarations or SystemVerilog's IEEE Std 1800-2012 § 23.2.2 Port declarations
Support for this may very across tools as this practices is not common. If your synthesizer has issues with interface
it may have issues with port aliasing as well.
module driver0 ( .sig({sig_in,sig_out}) );
input sig_in;
output sig_out;
assign sig_out = 'b1; // drive with some real value
endmodule
module driver1 ( .sig({sig_in,sig_out}) );
input sig_in;
output sig_out;
assign sig_out = 'b1; // drive with some real value
endmodule
module top();
wire [1:0] sig;
driver0 u0(.sig(sig));
driver1 u1(.sig(sig));
endmodule
If the bus is going across several lays of hierarchy then the above solution will likely be tedious to manage. An interface
should be used. Some guidelines to reduce synthesis limitations:
- Define all signals as a
logic
type. Only exception are tri-states where the bits are expected to have two or more drivers. - Define all tri-states as
wire
ortri
- Assign all
logic
types within aalways_ff
,always_comb
,always_latch
(if latch is necessary block.logic
types can be assigned withassign
statements, but not all tools validate driving conflicts withassign
- Keep tri-states assignments as simple of possible
- Ex:
assign myif.io = drive_enable ? io_out : 'z;
- Ex:
Do not use
interface
as a port in the top most module that will be synthesized. Many current synthesizers will flatten and localize interfaces with escaped names. If needed, create wrapper module as a translation layer between interface and top most port signals. Ex:interface my_interface(input clk, /*May need to declare top port level tri-stats as an interface port*/ inout [7:0] io, ... /*Optional output logic ... , input ... */ ); logic in_a, in_b, out; //wire [7:0] io; // internal tri-state ... endinterface : my_interface module same_port #(parameter N=1) (a,a); // Synthesizer might support this, see manual inout [N-1:0] a; endmodule : same_port ... // RTL top with interface as port module my_top(my_interface myif); ... sub sub0 ( .myif(myif), .*); ... endmodule : my_top // wrapper to use for synthesis module synth_top( output logic out, input in_a, in_b, clk, inout [7:0] io, ...); my_interface myif( .* ); my_top mytop( .myif(myif) ); // connect myif sigs with port sigs thate are not already connected with .* always_comb begin : conn_in myif.in_a = in_a; myif.in_b = in_b; ... end : conn_in always_comb begin : conn_out out = myif.out; ... end : conn_out /* connect tri-state this way may not be supported by all synthesizers, * refer to manual */ //same_port #(8) conn_inout_io(io, myif.io); ... endmodule : synth_top
Best Answer
You can't drive an
inout
directly as areg
.inout
types need to bewire
. So, you need a workaround.The workaround is creating a driver pin that shares the same wire as the module signal. To do this, define a
reg
variable for your 3-state test signal, thenassign
it to theinout
pin to connect it.As follows:
then later in your testbench, you can manipulate the drive state of the tristate pin:
later....
As you expect, the
inout_pin
will assume the value you drive it withinout_drive
as long as the DUT signal is in high-Z state. Likewise,inout_recv
will follow the value driven ontoinout_pin
.Strictly speaking, you don't need
inout_recv
to use the value present oninout_pin
in your test bench, but it reflects modeling a tristate I/O pin connected to the DUT.