Verilog 双向端口

1、双向端口简介

实现双向端口的典型方法是三态缓冲器也称三态门,它常用于双向数据总线的构建。在数字电路中,逻辑输出有两个正常态:低电平状态(对应逻辑0)和高电平状态(对应逻辑1);此外,电路还有不属于0和1状态的高阻态(对应逻辑Z  )。所谓高阻,即输出端属于浮空状态,只有很小的漏电流流动,其电平随外部电平高低而定,门电平放弃对输出电路的控制。或者可以理解为输出与电路是断开的。最基本的三态缓冲器的逻辑符号如下图:

当OE为高电平时,Dataout与Datain相连;而OE为低时,Dataout为高阻态,相当于与Datain之间的连线断开。

在应用代码中,Verilog HDL程序模块首先要进行I/O端口(input:输入端口;output:输出端口;inout:双向端口,同时具有输入输出功能的端口)的定义,然后是逻辑功能的描述。在Verilog HDL中,output端口可以定义为寄存器型变量,并在always块内可以被赋值使用,而inout型双向端口信号不能被定义为寄存器型变量,因此在always块内不能直接被赋值。

由于现在FPGA设计和外部存储器或CPU数据交换的频繁运用,以及引脚资源有限,使用双向端口设计可以成倍地节省数据引脚线,所以利用Verilog HDL实现双向端口至关重要。在设计双向端口时应注意两点:其一,要用三态门的控制来处理实现双向端口;其二,要分别指定双向端口作为输出口和输入口时,其外部对象的数据操作。

2、双向端口应用实例

实例假设输入输出数据的位宽为8,使用双向端口设计,需要8根数据线。

例:双向端口的Verilog实例。

module dinout(din,z,clk,dout,dinout)
	input [7:0] din;
	input z;
	input clk;
	output [7:0] dout;
	inout [7:0] dinout;
	
	reg [7:0] dout;
	reg [7:0] din_reg;

	assign dinout = (!z)?din_reg:8’bz;
	
	always @(posedge clk)
		begin
			if(!z)
			 din_reg=din;
			else
			 dout=dinout;
		end
endmodule

 程序在ISE中综合后的RTL级结构图如下图所示。dinout定义为双向端口,即可作为输入端口,又可作为输出端口;当双向端口dinout作为输出口时,从输入端口din输入数据到模块中,让数据从dinout端口输出;当双向端口dinout作为输入口时,数据从dinout口输入,从输出端口dout输出。z为三态门选通信号,当z=1时,三态门置于高阻态,这是dinout作为输入口;当z=0时,开通三态门,dinout作为输出端口。

3、双向端口的仿真

编写测试模块时,对于inout类型的端口,与输出端口一样,需要定义成wire类型的变量,而输入端口定义为reg类型,这两者是有区别的。此外,对于双向端口本身,仿真其输出端口和输入端口的语法是不同的。下面分别给出上例中双向端口的输入、输出特性仿真。

(一)双向端口作为输出端口时仿真

当双向端口作为输出口时,不需要对其进行初始化,只要开通三态门即可。输出端口特性仿真代码如下所示。假设在100ns后,让数据10-20依次从din口输入,然后用10ns的采样时钟从双向端口dinout输出。

module tb_dout
	reg [7:0] din;
	reg z;
	reg clk;
	wire [7:0] dout;
	wire [7:0] dinout;
	integer i;
	
	dinout uut(
		.din(din),
		.z(z),
		.clk(clk),
        .dout(dout),
		.dinout(dinout)
	);
	
	always #5 clk = ~clk;
	
	initial
	begin
		din=0;
		z=0;
		clk=0;
		#100 din=10;
		for(i=0;i<10;i=i+1)
			#10 din=din+1;
	end
endmoudle

 (二)双向端口作为输入端口时仿真

当双向端口dinout作为输入口时,需要对它进行初始化赋值并关闭三态门。而如果把它跟一般的输入口一样直接初始化赋值,则会出错,这是因为在定义它的时候是wire型的数据变量,而不是reg型数据类型。因此,这里需要用到force命令,用来强制给dinout赋值。同样,下面给出一个Verilog HDL仿真实例,设定在100ns后,让数据20-10从dinout口输入模块,然后用10ns的采样时钟从输出口dout输出。

module tb_din
	reg [7:0] din;
	reg z;
	reg clk;
	wire [7:0] dout;
	wire [7:0] dinout;
	integer i;
	
	dinout uut(
		.din(din),
		.z(z),
		.clk(clk),
		.dout(dout),
		.dinout(dinout)
	);
	
	always #5 clk = ~clk;
	
	initial
	begin
		z=1;
		clk=0;
		force dinout = 20;
		#100
		#100 din=10;
		for(i=0;i<10;i=i+1)
			#10 dinout=dinout-1;
	end
endmoudle

参考文件:

《Verilog HDL程序设计与实践(云创工作室)》

猜你喜欢

转载自blog.csdn.net/weixin_38621214/article/details/84569468
今日推荐