Verilog中 inout端口的使用方法
Verilog中 inout端口的使用方法
(本文中所有 Verilog描述仅为展示 inout端口的用法,实际描述则需要更丰富的功能描述)
Inout端口的使用
在芯片中为了管脚复用,很多管脚都是双向的,既可以输入也可以输出。在 Verilog中即为
inout型端口。Inout端口的实现是使用三态门,如 FPGA中的管脚复用部分:
三态门的第三个状态是高阻态 Z。在实际电路中高阻态意味着响应的管脚悬空、断开。当
三态门的控制信号为真时,三态门导通;控制信号为假时,三态门的输出端是高阻态。
Verilog中的 inout端口被综合为如下形式:
Inout端口是一个很容易出错的地方,理解 inout端口模型必须要抓住三点:
inout端口不可能独立存在;
作为输入必须有 reg型缓冲(一个 inout两个控制信号);
相连的两个 inout端口由一对信号交错控制;
下面一一
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
。
inout端口不可能独立存在:
分析 inout的端口特性,对于一个模块来说,inout端口既可以当做输入,又可以当做输出,
那么,与 inout端口相连的另一模块是什么情形呢?显然,另一模块也应该是 inout端口,inout
端口不可能独立存在。但是在实际编写 Verilog代码的过程中,却常常忽略这一点,而仅仅
是另一模块的一条输出线和一条输入线同时连接到 inout端口上,乍看起来符合逻辑,实则
不然。
以下图为例:
图中的存储器Memory用RAM实现,无论 CPU还是 RAM都只有一组数据总线,而图中
输入给Memory的有WriteData,从Memory输出的有MemData,这两组其实是一组数据总
线,而实现此管脚复用功能的就是管脚复用。在用 Verilog描述的过程中,只考虑 CPU的数
据通路结构时,就容易忽略它的双向端口的具体实现,并非如图中一般,简简单单的与 RAM
模块的 inout端口相连。所以,一定要注意到 inout端口不能独立存在,用 Verilog描述上图
中的 CPU模块时也要描述一个 inout端口及相关逻辑。
作为输入必须有 reg型缓冲:
考虑到这种情况:当 control信号为真时,三态门导通,这时,DataOut的输出通过双向端
口传输到 DataBus上。但是 DataIn与 DataOut直接相连,如何保证 DataOut的数据不会影响
到 DataIn相连的电路呢?
解决这个问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
的办法是把 DataIn声明为 reg型,而 reg型的变量在 always过程块中被复制,
需要再增加一个控制信号,由 always敏感表列监控,以此保证 inout端口作为输出时不会影
响 DataIn。
实际用 Verilog描述的过程中,常常容易忽略某一个 inout端口的 reg声明。以 CPU和RA
M为例,RAM本身作为存储器就是用 reg声明的,所以不需要这个 reg缓冲(前提是写 RAM
时一定要在 always敏感表列中添加控制信号);而 CPU模块的 inout端口的 reg声明却常常
被忽略,因为这个东西看上去"画蛇添足"。这也是初学者使用 inout端口时最容易犯错的地
方。
相连的两个 inout端口由一对信号交叉控制:
前面提到 inout端口不能独立存在,进一步考虑,当一个模块的 inout端口作为输出时,那
么另一个模块的 inout端口必然作为输入;反之,当一个模块的 inout端口作为输入时,那
么另一个模块的 inout端口必然作为输出。因此,这两个 inout端口的控制信号实际上是由
一对信号交叉控制。
以下图为例:
CPU控制读写 RAM的信号有一对:ReadRAM和WriteRAM。
当 ReadRAM有效时,CPU从 RAM中读取数据,这时 RAM的三态门导通,RAM的 inout
端口作为输出用,CPU的 inout端口作为输入用,并且用 ReadRAM信号控制 CPU读取;
当WriteRAM有效时,CPU向 RAM写入数据,这时 CPU的三态门导通,CPU的 inout端
口作为输出用,RAM的 inout端口作为输入用,并且用WriteRAM信号控制 RAM写数据。
理解 inout端口的实现,并且注意到上面三点,就可以开始用 Verilog描述 inout端口了。进
行抽象:
1.三态门及其高阻态的实现(输出):
Inout DataBus;
Assign DataBus=(Control[0]==1)?DataOut:32'bz;//位宽由实际情况决定
2.输入缓冲(输入):
Reg DataIn;
Always @(Control[1])
If(Control[1])
DataIn<=DataBus;
下面给出真正的 inout端口的应用描述,仍以上图中 CPU和 RAM为例(注意到 RAM中
没有声明 reg型缓冲而 CPU则显示声明 reg型缓冲,以及两个模块中的一对控制信号的交
叉):
module DRAM(DataBus,AddressBus,ReadRAM,WriteRAM);
inout [31:0]DataBus;
input [9:0]AddressBus;
input ReadRAM,WriteRAM;
reg [31:0]RAM[0:1023];
parameter insfile="InstructionFile.txt",
datafile="DataFile.txt";
initial
begin
$readmemh(insfile,RAM,0);
$readmemh(datafile,RAM,512);
End
assign DataBus=(ReadRAM==1)? RAM[AddressBus]:32'bz;
always @(WriteRAM or DataBus)
if(WriteRAM)
RAM[AddressBus] =DataBus;
Endmodule
//仅仅为了说明 inout端口用法,真实的 CPU描述远非如此
module CPU(DataBus,AddressBus,ReadRAM,WriteRAM,Clock,Reset);
inout [31:0]DataBus;
output [9:0]AddressBus;
output ReadRAM,WriteRAM;
input Clock,Reset;
reg [31:0]DataRead;
assign DataBus=(WriteRAM==1)?DataWrite:32'bz;
always @(ReadRAM)
if(ReadRAM)
DataRead=DataBus;
//CPU中以后的代码就是用 DataRead和 DataWrite来完成和 RAM的数据交换
endmodule
误解:用一对相反的信号控制两个 inout端口实现双向传输。
造成这种误解的原因是在两个 module中的 inout端口中,三态门不可能同时导通,默认两
个三态门总是一个导通另一个不导通,忽略了两个都不导通的情况。所以在实际电路中,用
于控制两个 inout端口的,必然是一对控制信号的交叉形式。
Inout端口的仿真
有关包含 inout端口模块的单独仿真和 inout端口的应用情况类似,只不过两个模块间的关
系不同,需要做一下变动。
Testbench作为最顶层模块,是没有端口列表的,也就不可能为其声明一个 inout端口。如
前所述,inout端口不可能独立存在。这时候,虽然不能声明一个 inout端口,但是可以描述
一个和 inout端口有相同功能的逻辑。
把 inout端口拆分为两个连在一起的输入端口和输出端口,如下图所示。在 testbench中,
用于给实例输入的信号是 reg型,从实例输出的信号被声明为 wire型,而 inout端口本身必
须被声明为 wire 型。因此,需要定义一个 wire型的 TestOut和 reg型的 TestIn。Testbench
的目的是为了测试模块的功能而不是跟模块交换数据,因此,在 testbench中的"类 inout端
口"没有真正的 inout端口那么多约束。唯一需要注意的是 reg型的 TestIn向 inout被测试模
块的 inout 端口写数据时需要有一个控制信号,这个控制信号就是被测模块内部的
WriteRAM。
这样,用于测试上面的 RAM模块的 Verilog描述如下:
`include "DRAM.v"
module test;
reg [9:0]AddressBus;
reg Read,Write;
wire [31:0]DataBus,TestOut;
reg [31:0]TestIn;
DRAM dram(DataBus,AddressBus,Read,Write);
assign DataBus=(Write==1)?TestIn:32'bz;
assign TestOut=(Read==1)?DataBus:32'bz;
initial
begin
Write=1'b0;Read=1'b0;AddressBus=1'b0;TestIn=1'b0;
#100 Write=1'b1;AddressBus=10'd4;TestIn=32'd64;
#10 Write=1'b0;
#10 Read=1'b1;AddressBus=10'd8;
#30 $stop;
end
endmodule
进一步考虑,testbench中的"inout端口"本身已被声明为 wire类型,显然 wire型的 TestOut
就失去了意义,可以将它们合并:wire型的 inout足以显示输出信号的变化。最终的 testbench
模型如下:
改进后的 testbench用 Verilog描述为:
`include "DRAM.v"
module test;
reg [9:0]AddressBus;
reg Read,Write;
wire [31:0]DataBus;
reg [31:0]TestIn;
DRAM dram(DataBus,AddressBus,Read,Write);
assign DataBus=(Write==1)?TestIn:32'bz;
initial
begin
Write=1'b0;Read=1'b0;AddressBus=1'b0;TestIn=1'b0;
#100 Write=1'b1;AddressBus=10'd4;TestIn=32'd64;
#10 Write=1'b0;
#10 Read=1'b1;AddressBus=10'd8;
#30 $stop;
end
endmodule
总线上的 inout端口
实际应用中最常见的应用 inout端口的地方是总线,如数据总线、控制总线、地址总线,
而总线绝大多数都是双向总线,挂接在总线上的部件往往很多。如果总线上只挂接了两个部
件,这种情况就是前面描述的两个 inout端口相连接的问题。但是总线上挂接的部件往往很
多,这时候应该怎么 Verilog描述呢?
其实原理是一样的,最基本的原则就是:
在同一时刻,一条总线上最多只能有一个 inout端口作为输出部件。
换句话说,即是在某一时刻,一条总线上最多有一个 inout端口作输出,其余的部件要么
作为输入部件,要么就是高阻态。这样才能避免数字电路中一个很尴尬的问题:多驱动。
因此,在描述总线的时候,挂接在总线上的部件只要注意到上面的规则避免多驱动,即可实
现所需的功能。