FPGA verilog three-state gate design and simulation problems in quartus compilation and Modelsim

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:

  1. The three-state signal is wire type;
  2. Define the reg type intermediate signal assign to the three-state signal;
  3. 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.

Guess you like

Origin blog.csdn.net/qq_33231534/article/details/105129252