Use and Simulation of two-way inout port of OpenGL
Many external pins of the chip use the inout type to save the pipe leg. Generally, the inout type is used for bidirectional data transmission such as bus. A port is used for both input and output. Inout is generally implemented using a three-state gate. The third state of the three-state gate is the high impedance 'Z '. When the inout port is not output, the three-state gate is set to high resistance. In this way, the signal will not be wrong because both ends are output at the same time. For more details, you can search for information about the Tri-State of the three-state gate.
1. Use the inout data as follows:
Inout data_inout;
Input data_in;
Reg data_reg; // data_inout image register
Reg link_data;
Assign data_inout = link_data? Data_reg: 1 'bz; // link_data controls the three-state gate.
// For data_reg, you can assign values to data_in based on the combination logic or time series logic. by controlling the level of link_data, you can set whether the output data is in the high-impedance state. If the output data is in the high-impedance state, it is used as the input port. link_data can be controlled through related circuits.
2. When writing a test module, the inout port must be defined as a wire variable, while other input ports must be defined as Reg. There is a difference between the two.
When data_inout is used as the input in the preceding example, You need to assign a value to data_inout. In other cases, you can disconnect it. In this case, you can use the assign statement to implement: Assign data_inout = link? Data_in_t: 1' BZ; the link and data_in_t are Reg type variables, which are assigned values in the test module.
In addition, you can set an output port to observe how data_inout is used as the output:
Wire data_out_t;
Assign data_out_t = (! Link )? Data_inout: 1' BZ;
3 else, in RTL
Inout use in top module (PAD)
Dont use inout (TRI) in sub module
That is to say, it is better to avoid inout in the internal module. If it is necessary, use two ports for implementation and use three States for implementation at the top layer. The reason is: if a non-top-layer module uses a bidirectional port, the bidirectional port must have its upper layer connected to it. Since it is a bidirectional port, at least one input port and one output port are connected to the bidirectional port on the upper layer. When two internal output units are connected, in this way, errors often occur during integration.
For bidirectional interfaces, we can understand them as two components: one input component and one output component. In addition, a control signal is also required to control when the output component is output. In this case, we can easily model two-way ports.
Example:
Code:
Module dual_port (
....
Inout_pin,
....
);
Inout inout_pin;
Wire inout_pin;
Wire input_of_inout;
Wire output_of_inout;
Wire out_en;
Assign input_of_inout = inout_pin;
Assign inout_pin = out_en? Output_of_inout: high impedance; // problem. If out_en is false, inout_pin is high.
// Blocking, what about input_of_inout?
// If out_en is true, then input_of_inout cannot be used.
// Is also equal to inout_pin? How is input?
Endmodule
It can be seen that input_of_inout and output_of_inout can be used as common signals.
4. Simulation (O (lead _ simulation) O... haha, this is what I want to see)
During simulation, you must pay attention to the processing of Bidirectional ports. If it is directly connected to the two-way port of another module, you only need to ensure that when one module is output, the other module has no output (in the high-impedance state.
If it is used as a separate module simulation in Modelsim, you cannot use the force command to set it to a high-impedance state when outputting the module. Instead, you can use the release command to release the bus.
Many beginners are overwhelmed by the inout bidirectional port when writing testbench for simulation and verification. The simulator always prompts that the error cannot be performed. The following is my personal summary of writing testbench simulation on the inout port and an example is provided. The inout port must be defined as a wire variable in testbench.
Assume that the source code is:
Module XX (data_inout ,........);
Inout data_inout;
........................
Assign data_inout = (! Link )? Datareg: 1' BZ;
Endmodule
Method 1: The inout port of the opposite control signal is used to interconnect two modules with the inout bidirectional port. Note that the assign statement can only be placed in the initial and always blocks.
Module test ();
Wire data_inout;
Reg data_reg;
Reg link;
Initial begin
..........
End
Assign data_inout = link? Data_reg: 1' BZ;
Endmodule
Method 2: Use the force and release statements, but this method cannot accurately reflect the signal changes of the two-way port, but this method can be reversed within the block.
Module test ();
Wire data_inout;
Reg data_reg;
Reg link;
# Xx; // latency
Force data_inout = 1' BX; // force it as the input port
...............
# Xx;
Release data_inout; // release the input port
Endmodule
Simulation
Many readers have encountered difficulties in simulating two-way ports. Here we will introduce the two-way port simulation method. A typical bidirectional Port 1 is shown.
Inner_port is connected to other internal logic of the chip, outer_port is the external Chip Pin, out_en is used to control the direction of the two-way port, when out_en is 1, the port is the output direction, and when out_en is 0, port is the input direction.
The following is a description in the language of OpenGL:
Module bidirection_io (inner_port, out_en, outer_port );
Input out_en;
Inout [7:0] inner_port;
Inout [7:0] outer_port;
Assign outer_port = (out_en = 1 )? Inner_port: 8 'hzz;
Assign inner_port = (out_en = 0 )? Outer_port: 8 'hzz;
Endmodule
The two-way port is described in VHDL as follows:
Library IEEE;
Use IEEE. std_logic_00004.all;
Entity bidirection_io is
Port (inner_port: inout std_logic_vector (7 downto 0 );
Out_en: In std_logic;
Outer_port: inout std_logic_vector (7 downto 0 ));
End bidirection_io;
Architecture behavioral of bidirection_io is
Begin
Outer_port <= inner_port when out_en = '1' else (Others => 'Z ');
Inner_port <= outer_port when out_en = '0' else (Others => 'Z ');
End behavioral;
During simulation, You need to verify that the two-way port can output data correctly and read data correctly. Therefore, you need to drive the out_en port. When the out_en port is 1, testbench drives the inner_port port, then, check whether the data output from the outer_port is correct. When the out_en port is 0, testbench drives the outer_port port, and then checks whether the data read from the inner_port is correct. Because both inner_port and outer_port are two-way ports (which are defined by inout in both the language of VHDL and the language of OpenGL), the driving method is different from that of one-way ports.
Verify the testbench structure 2 of the two-way port.
This is a self-checking testking, which can automatically check whether the simulation results are correct and print the prompt information on The Modelsim console. In the figure above, the monitor function can sample signals and automatically compare the results.
The working process of testbench is
1) When out_en = 1, the two-way port is in the output state, testbench assigns a value to the inner_port_tb_reg signal, and then reads the value of outer_port_tb_wire. If the two are the same, the two-way port works normally.
2) When out_en = 0, the bidirectional port is in the input state. testbench assigns a value to the outer_port_tb_reg signal and then reads the value of inner_port_tb_wire. If the two are the same, the bidirectional port works normally.
The following is the testbench written in the sample code. technologies such as automatic result comparison and randomization excitation are used.
'Timescale 1ns/10 ps
Module Tb ();
Reg [7:0] inner_port_tb_reg;
Wire [7:0] inner_port_tb_wire;
Reg [7:0] outer_port_tb_reg;
Wire [7:0] outer_port_tb_wire;
Reg out_en_tb;
Integer I;
Initial
Begin
Out_en_tb = 0;
Inner_port_tb_reg = 0;
Outer_port_tb_reg = 0;
I = 0;
Repeat (20)
Begin
#50
I = $ random;
Out_en_tb = I [0]; // randomize out_en_tb
Inner_port_tb_reg = $ random; // randomize data
Outer_port_tb_reg = $ random;
End
End
// *** Drive the ports connecting to bidirction_io
Assign inner_port_tb_wire = (out_en_tb = 1 )? Inner_port_tb_reg: 8 'hzz;
Assign outer_port_tb_wire = (out_en_tb = 0 )? Outer_port_tb_reg: 8 'hzz;
// This is what you do not understand most. It is estimated that it is also the most important place.
// Instatiate the bidirction_io Module
Bidirection_io bidirection_io_inst (. inner_port (inner_port_tb_wire ),
. Out_en (out_en_tb ),
. Outer_port (outer_port_tb_wire ));
// ****** Monitor ******
[Email protected] (out_en_tb, inner_port_tb_wire, outer_port_tb_wire)
Begin
#1;
If (outer_port_tb_wire === inner_port_tb_wire)
Begin
$ Display ("\ n ***** time = % t *****", $ time );
$ Display ("OK! Out_en = % d ", out_en_tb );
$ Display ("OK! Outer_port_tb_wire = % d, inner_port_tb_wire = % d ",
Outer_port_tb_wire, inner_port_tb_wire );
End
Else
Begin
$ Display ("\ n ***** time = % t *****", $ time );
$ Display ("error! Out_en = % d ", out_en_tb );
$ Display ("error! Outer_port_tb_wire! = Inner_port_tb_wire ");
$ Display ("error! Outer_port_tb_wire = % d, inner_port_tb_wire = % d ",
Outer_port_tb_wire, inner_port_tb_wire );
End
End
Endmodule
Inout of OpenGL