FPGA verilog 三态门设计及在quartus编译和Modelsim里仿真问题

三态门介绍:

三态门包括:输入状态、输出状态、高阻态。三态信号定义:inout

在FPGA设计中,经常会用到数据输入与输出,与外部芯片进行数据传输时,经常会用到三态门,比如我现在正学的SDRAM,为了节约端口资源,通常会将一些数据端口即作为输入又作为输出,这样的端口就叫做三态门。

SDRAM芯片的数据端口dq就是典型的三态门,在执行写操作时,dq作为输入端口;在执行读操作时,dq作为输出端口;其他时间为高阻态。在写FPGA和SDRAM接口时,必然需要一个三态信号dq作为与SDRAM连接的信号。

用一个例子来直观说明一下:
以下是Verilog程序:

module tri_state(
		input				clk     ,
		input				rst_n   ,
		input				data	,
		input 				dout_en	,
		output reg			odata	,
		inout     			dout
		);
				
	assign dout = (dout_en==1)? data : 1'bz;
		
	always@(posedge clk or negedge rst_n)begin
		if(rst_n == 0)
			odata <= 0;
		else if(dout_en!=1)
			odata <= dout;
	end	
		
endmodule

三态信号为dout,其RTL视图:

可以看出,当dout_en为1时,dout输出data数据,当dout_en为0时,dout为高阻,此时,dout可作为输入端口,作为输入端口时,FPGA内部自动生成一个buffer作为输入数据缓冲。

三态门quartus编译及Modelsim仿真问题:

1. quartus编译三态门

以在写的SDRAM接口为例:在verilog代码里有关三态信号dq的代码段如下(有错):

     inout  reg [ 15: 0]   dq        ; //数据线
     output reg [ 15: 0]   rdate     ;

//dq信号输出,数据线
	 always@(posedge clk or negedge rst_n)begin
		  if(rst_n == 0)begin
				dq <= 16'hzzzz;
		  end
		  else if(wr_write_start || state_c==wr_write)
				dq <= wdata;
		  else 
				dq <= 16'hzzzz;
	 end  

     always@(posedge clk or negedge rst_n)begin
		  if(rst_n == 0)
				rdate <= 0;
			else if(state_c==rd_read || state_c==rd_pre)
				rdate <= dq;
	 end

此时在quartus里编译不会报错,但在Modelsim里编译时便会报错,原因在于,三态信号应定义为wire型信号,这样在Modelsim里编译便不会报错。在我的理解看来:其实dq三态信号定义为wire或者reg型都可以,虽然reg型在Modelsim里编译不通过,但下载在板子中结果都是一样的,有兴趣自己可以试一下。但因此默认情况下我们就将三态信号设置成wire型。修改后的代码如下:


     inout         [  15: 0]    dq       ;
     reg           [  15: 0]	dq_t     ;

//dq信号输出,数据线
	 assign dq = dq_t;
	 always@(posedge clk or negedge rst_n)begin
		  if(rst_n == 0)begin
				dq_t <= 16'hzzzz;
		  end
		  else if(wr_write_start || state_c==wr_write)
				dq_t <= wdata;
		  else 
				dq_t <= 16'hzzzz;
	 end  

     always@(posedge clk or negedge rst_n)begin
		  if(rst_n == 0)
				rdate <= 0;
			else if(state_c==rd_read || state_c==rd_pre)
				rdate <= dq;
	 end

主要就是将dq定义成wire型,可以再定义一个reg型中间信号dq_t,在赋值给dq。
2.Modelsim编译三态门

在编写测试文件时,对inout型信号,如果这样写:

wire [15:0]  dq;
initial begin
	for(i=1 ;i<260;i=i+1)begin
			dq = (i==1)? 1:(dq+1'b1);
			#(clk_period);
	end	
end

Modelsim会报错:Illegal reference to net "dq".
dq为三态门,定义wire型,却当reg型给数据,肯定会报错。若定义为reg型,如下:

reg [15:0]  dq;
initial begin
	for(i=1 ;i<260;i=i+1)begin
			dq = (i==1)? 1:(dq+1'b1);
			#(clk_period);
	end	
end

编译不会报错,但是会出现家在错误:# Error loading design.

对三态信号进行这样处理(又用了其他代码,看着很乱,理解意思就行):(加一个reg型中间信号,用assign赋给dq,下边赋值时,就用这个信号)

parameter	WIDTH = 16;

wire	[WIDTH-1 : 0]	dq;

reg		            	tri_en;
reg		[WIDTH-1 : 0]	data_w;

assign  dq = (tri_en) ? data_w : 16'hzzzz;

module_1 u_module_1(
		
		);		
initial begin
	tri_en = 0;
	#(clk_period);
	tri_en = 1;
	data_w = 16'h1111;
	#(clk_period);
	tri_en = 0;
	
	data_w = ......
end

因此在对三态门编写测试文件时应满足:

  1. 三态信号为wire型;
  2. 定义reg型中间信号assign给三态信号;
  3. 在需要三态信号作为输入端时,用中间信号对其赋值。

最后,总结一下:

  • 在工程中写三态信号Verilog代码将三态信号定义为wire型;
  • 测试文件中三态信号也定义为wire型,并用中间信号代替三态信号进行赋值输入。

最后还想说一句,这篇写的很乱,我很难受,但理解意思就好啦,主要看一下总结。后续会对SDRAM接口的编写过程进行分享。

猜你喜欢

转载自blog.csdn.net/qq_33231534/article/details/105129252