【Verilog】inout 端口信号的使用

inout 介绍

芯片的许多外部引脚使用输入式来节省管脚。通常,当信号线用于双向数据传输(例如总线)时,使用 inout 类型。也就是说,端口同时用于输入和输出。inout 通常在特定实现中通过三态门实现。三态栅极的第三种状态是高阻抗'Z'。当输入端口不输出时,将三态栅极设置为高阻抗。这样,信号就不会因为两端同时输出而出错。

使用说明

1. 使用 inout 类型数据,可以这样写:

 inout    data_inout;
 input    data_in;
 reg      data_reg;
 reg      link_data;
assign data_inout = link_data? data_reg: 1'bz;

对于 data_reg,可以通过组合逻辑或顺序逻辑根据data_in进行分配。

通过控制 link_data 级的高、低功率,从而设置 data_inout 输出数据或处于高阻抗状态,如果处于高阻抗状态,此时作为输入端口可以通过使用 link_data 相关电路进行控制。

2. 写入测试模块,对于输入类型的端口,需要定义为 wire 类型变量,而其他输入端口都定义为 reg 类型,

两者是有区别的。

当将上面示例中的data_inout用作输入时,需要将其分配给data_inout,其余部分可以断开连接。

这时,可以使用 assign 语句来实现:assign data_inout = link?Data_in_t: 1'bz;

其中 link 和 data_in_t 是 reg 类型变量,在测试模块中分配值。

此外,可以设置输出端口以观察 data_inout 用作输出的情况:

并且在 RTL 中,inout 在顶部模块中输入使用  不要在子模块中使用 inout(tri)  

换句话说,最好不要在内部模块中有 inout。如果确实需要它,请使用两个端口来实现它,然后在达到顶层时使用三态实现。原因是:如果一个非顶层模块中使用了一个双向端口,那么这个双向端口的上层必须连接到它。由于是双向端口,因此至少将一个输入端口和一个输出端口连接到上层的双向端口,并且将两个内部输出单元连接在一起,这在合成过程中经常出错。对于双向端口,我们可以将其理解为两个组件:输入组件和输出组件。此外,还需要一个控制信号来控制输出组件的输出时间。

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: 1'bz;      
endmodule  

可以看出,此时 input_of_inout 和 output_of_inout 可以作为普通信号使用。

在仿真过程中,要注意双向端口的处理。如果直接连接到另一个模块的双向端口,就足以保证当一个模块输出时,另一个模块没有输出(处于高阻抗状态)。

如果在 ModelSim 中作为单独的模块进行仿真,那么当模块输出时,不能使用 force 命令将其设置为高阻抗,而是使用释放命令来释放总线。

源代码:

module xx(data_inout , ........);  
inout data_inout;
assign data_inout = (!link) ? datareg : 1'bz;  
endmodule  

方法一:使用相反的控制信号输入端口,相当于在两个模块之间使用 inout 双向端口互连。这种方法应该注意,赋值语句只能放在 initial 和 always 块中。

module test();
   wire  data_inout; 
   reg   data_reg; 
   reg   link; 
initial begin
 .......... 
end 
assign data_inout = link ? data_reg : 1'bz; 

endmodule

方法2:使用force和reless语句,但这种方法不能准确反映双向端口的信号变化,但这种方法可以在块中反转。

module test();  
wire    data_inout;
reg     data_reg;
reg     link;
initial begin  
  .....
end
assign data_inout = link ? data_reg : 1'bz;
endmodule  

示例

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  

在仿真过程中,需要验证双向端口是否正确输出数据并正确读取数据。因此,有必要驱动out_en端口。

当 out_en 端口为1时,测试平台驱动 inner_port 端口,然后检查 outer_port 端口输出的数据是否正确;当 out_en 端口为0时,测试台驱动 outer_port 端口,然后检查 inner_port 端口读取的数据是否正确。由于 inner_port 和 outer_port 端口都是双向端口,因此驱动方法与单向端口不同。

用Verilog代码编写的 testbench 如下。

`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]; 
      inner_port_tb_reg=$random;
      outer_port_tb_reg=$random;
   end
end
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;
bidirection_io bidirection_io_inst(
    .inner_port (inner_port_tb_wire),
    .out_en     (out_en_tb),
    .outer_port (outer_port_tb_wire)
);
endmodule  

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...