三態門介紹:
三態門包括:輸入狀態、輸出狀態、高阻態。三態信號定義: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
因此在對三態門編寫測試文件時應滿足:
- 三態信號爲wire型;
- 定義reg型中間信號assign給三態信號;
- 在需要三態信號作爲輸入端時,用中間信號對其賦值。
最後,總結一下:
- 在工程中寫三態信號Verilog代碼將三態信號定義爲wire型;
- 測試文件中三態信號也定義爲wire型,並用中間信號代替三態信號進行賦值輸入。
最後還想說一句,這篇寫的很亂,我很難受,但理解意思就好啦,主要看一下總結。後續會對SDRAM接口的編寫過程進行分享。