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接口的編寫過程進行分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章