inout
https://blog.csdn.net/wordwarwordwar/article/details/78076120
下面是一种典型的inout端口使用方法:
inout io_data; //inout口
reg out_data; //需要输出的数据
reg io_link; //inout口方向控制
assign io_data = io_link?out_data:1'bz; //这个是关键
- 当inout端口作为输入口使用时,一定要把它置为高阻态,让例子中的io_link=0即可;
- 当inout端口作为输出口使用时,则将实例中的io_link=1,对out_data赋值就可以了。
介绍
芯片外部引脚很多都使用 inout 类型的,为的是节省管腿。一般信号线用做总线等双向数据传输的时候就要用到 INOUT类型了。就是一个端口同时做输入和 输出。 inout 在具体实现上一般用三态门来实现。三态门的第三个状态就是高阻
'Z'。当 inout 端口不输出时,将三态门置高阻。这样信号就不会因为两端同时 输出而出错了
编写测试模块时,对于 inout 类型的端口,需要定义成 wire 类型变量,而其它输入端口都定义成 reg 类型,这两者是有区别的.
当上面例子中的 data_inout 用作输入时,需要赋值给 data_inout,其余情况可以断开.此时可以用 assign 语句实现:assign data_inout = link ? data_in_t : 1’bz;其中的 link ,data_in_t 是 reg 类型变量,在测试模块中赋值.
另外,可以设置一个输出端口观察 data_inout 用作输出的情况:
Wire data_out;
assign data_out_t = (!link) ? data_inout : 1’bz;
else, in RTL
inout use in top module(PAD)
dont use inout(tri) in sub module
原因
也就是说, 在内部模块最好不要出现 inout,如果确实需要,那么用两个 port 实现,到顶层的时候再用三态实现。理由是:在非顶层模块用双向口的话,该双向口必然有它的上层跟它相连。既然是双向口,则上层至少有一个输入口和一个输出口联到该双向口上,则发生两个内部输出单元连接到一起的情况出现,这样在综合时往往会出错。
对双向口,我们可以将其理解为 2 个分量:一个输入分量,一个输出分量。另外还需要一个控制信号控制输出分量何时输出。此时,我们就可以很容易地对双向端口建模。
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 : 高阻;
endmodule
inout testbench
-- 当 out_en 端口为 1 时,testbench 驱动 inner_port 端口,然后检查 outer_port 端口输出的数据是否正确;
- 当 out_en 端口为 0 时, testbench 驱动outer_port 端口,然后检查 inner_port 端口读入的数据是否正确。
由于 inner_port 和 outer_port 端口都是双向端口 (在 VHDL和 Verilog 语言中都用 inout 定义),因此驱动方法与单向端口有所不同。
`timescale 1ns/10ps
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;
//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 ******
always@(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

浙公网安备 33010602011771号