Three-state door introduction:
The three-state gate includes: input state, output state, and high impedance state. Three-state signal definition: inout
In FPGA design, data input and output are often used. When transmitting data with external chips, three-state gates are often used. For example, the SDRAM I am learning now. In order to save port resources, some data ports are usually used. As input and output, such a port is called a three-state gate.
The data port dq of the SDRAM chip is a typical three-state gate. When performing a write operation, dq is used as an input port; when performing a read operation, dq is used as an output port; other times, it is in a high impedance state. When writing the FPGA and SDRAM interface, a three-state signal dq must be used as the signal connected to the SDRAM.
Use an example to illustrate intuitively: The
following is a Verilog program:
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
The three-state signal is dout, its RTL view:
It can be seen that when dout_en is 1, dout outputs data data, when dout_en is 0, dout is high impedance. At this time, dout can be used as an input port. When used as an input port, a buffer is automatically generated inside the FPGA as an input data buffer. .
Three-state gate quartus compilation and Modelsim simulation problems:
1. quartus compiles three-state gate
Take the SDRAM interface being written as an example: the code segment of the three-state signal dq in the verilog code is as follows (error):
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
At this time, no error will be reported when compiling in quartus, but it will be reported when compiling in Modelsim. The reason is that the three-state signal should be defined as a wire type signal, so that no error will be reported when compiling in Modelsim. From my understanding: In fact, dq three-state signal can be defined as wire or reg type. Although the reg type fails to compile in Modelsim, the results are the same when downloaded on the board. If you are interested, you can try it yourself. But so by default we set the three-state signal to wire type. The modified code is as follows:
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
The main thing is to define dq as wire type, and then define a reg-type intermediate signal dq_t, which is assigned to dq.
2. Modelsim compiles three-state gate
When writing a test file, for inout type signals, if you write:
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 will report an error: Illegal reference to net "dq".
dq is a three-state gate and defines the wire type, but when the reg type is given to the data, it will definitely report an error. If defined as reg type, as follows:
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
The compilation will not report an error, but there will be a home error: # Error loading design.
The three-state signal is processed in this way (other codes are used, it looks very messy, and you understand the meaning): (add a reg-type intermediate signal, assign to dq with assign, and use this signal for the assignment below)
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
Therefore, when writing test files for three-state gates, you should meet:
- The three-state signal is wire type;
- Define the reg type intermediate signal assign to the three-state signal;
- When a three-state signal is required as an input terminal, use an intermediate signal to assign it.
Finally, to summarize:
- Write the three-state signal Verilog code in the project to define the three-state signal as wire type;
- The three-state signal in the test file is also defined as a wire type, and the intermediate signal is used to replace the three-state signal for assignment input.
Finally, I would like to say that the writing of this article is very messy, I feel very uncomfortable, but it is good to understand the meaning, mainly look at the summary. The writing process of the SDRAM interface will be shared later.