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  
posted @ 2020-03-08 20:56  friedCoder  阅读(1193)  评论(0)    收藏  举报