Verilog之非阻塞赋值(三)—— 赋值延后一个周期

总结:(一、二为一组,不延后;三、四为一组,延后1周期)
在Verilog之非阻塞赋值(二)中,相关说法不全面,因为文本编辑器不支持更改,故完善之后,将此文作为第三部分
前提:always块描述的时序逻辑电路,采用非阻塞赋值;组合逻辑采用阻塞赋值。
其一,
当在always块中的每一个条件分支中,仅有一条赋值语句(不管是阻塞与非阻塞),且要满足条件中的条件判断式不含有在本模块中定义并赋值的reg变量(采用非阻塞赋值)或者来自其他模块的非阻塞reg型信号,此时阻塞与非阻塞表现的结果是一样的,都是在时钟边沿瞬间完成的;
理解非阻塞赋值分两个过程,RHS的计算为第一步,LHS的赋值为第二步,这是第一层面;第二,由于两步时间非常短,表现出来就是在时钟边沿瞬间完成,故表现结果非阻塞和阻塞一样,这是第二个层面。

其二,

当条件分支语句中含有的条件判断式是阻塞赋值变量(无论是外部输入的数据,或者是本模块的阻塞赋值变量,此时也包括assign赋值语句的LHS),那么也是在边沿瞬间完成赋值,不会延后1个周期;/下文有完善/
NOTE:assign赋值语句为连续赋值语句,与过程赋值语句并列(过程赋值包括阻塞与非阻塞)。

其三,
如果条件判断式中含有非阻塞赋值的reg变量(无论是本模块的还是其他外部模块的),那么在该条件分支下的非阻塞赋值语句会延后一个周期完成(相对条件判断式中的变量的赋值完成,延后一个周期赋值)。
其四,一个条件分支中含有多条非阻塞语句时,若non1(第一条LHS)出现在第二条语句的RHS中,则会出现non2延迟一个周期的情况,如下(该情形为Case3);

Verilog之非阻塞赋值(三)—— 赋值延后一个周期_第1张图片
Verilog之非阻塞赋值(三)—— 赋值延后一个周期_第2张图片
理解的关键: 要区分赋值和采样的不同,条件判断式中的条件相当于采样,即在时钟边沿条件变量的值被采样并与条件做对比,之所以条件中含有非阻塞变量时会延后一个周期,本质是被采样的reg变量在其他模块使用了非阻塞赋值,而非阻塞赋值完成有两个步骤,在某一个仿真节拍(不是一个仿真周期),被采样的还没有赋值完成(处在RHS的计算阶段),而采样时同时进行,这样,采样到的就是上一个周期的reg变量的值,虽然马上在边沿完成赋值,但采样已经结束,故在这个仿真周期结束时,被采样的完成赋值,但条件分支(含有被采样reg的判断表达式)下的变量赋值在下一个周期得到目标值,故而表现为相对被采样的变量的赋值,延后一个周期完成赋值。
同理,条件分支下含有多条非阻塞赋值语句时,理解也是一样:在同一个仿真节拍(RHS的计算),下一条非阻塞赋值的变量non2的右端得得到的是上一周期的前一非阻塞赋值的reg的值(non1),而在第二仿真节拍(赋值),non2和non1得到的值就不是一样的,故non2会表现的延后一个周期。

–>总结:非阻塞赋值延后一个周期2种情况
1、条件分支中非阻塞reg型变量(不管是外部输入,还是本模块的)的边沿对齐时钟边沿时,采样采的是上一周期的值(历史值),故分支下的非阻塞赋值会延后一个周期。

2、多条非阻塞赋值语句;

举例说明延后1个周期的case:

Case1:本模块的reg型(非阻塞赋值),send_en与send_bit_cnt;

Verilog之非阻塞赋值(三)—— 赋值延后一个周期_第3张图片

Case2:见前一页总结的图片(分支下还有多条非阻塞赋值);
Case3:外部输入信号(wire型),在条件判断式中出现,波形上与时钟边沿对齐
(实际属于条件分支中含有其他模块的非阻塞reg型变量);

在这里插入图片描述
说明:虽然条件分支中的条件判断式含有的是wire型变量(来自其他模块),但注意,本质上,该wire型变量本质上是来自其他模块的非阻塞reg型变量,故在上文已经进行了修改。该情况下的代码如下,上述datain_en就是下文的dout,因为模块的输入只能是线网类型,该种情况实质上为条件分支中含有其他模块的非阻塞reg型变量:

always @ (posedge clk, negedge rst_n)
begin
	if (!rst_n)
	begin
		dout_en <= 1'b0;
		dout <= {DO_WID{1'b1}};
	end
	else if (clk_cnt == TIME_20MS && data_high) 	 	 		
	begin 	 	  	 	   	 	  	  	 	  	 	 	 	 						
		dout_en <= 1'b1;				 	  		 		 			
		dout <= dout_n; 	 		 	   	 	  	  	      	
	end
	else begin
		dout_en <= 1'b0;
		dout <= {DO_WID{1'b1}};
	end
end

补充: 1、verilog中事件的分层队列机制; 2、更正上述说法,“其二”中说法更正为: 仅当条件分支中含有的阻塞赋值或assign赋值的变量本身与非阻塞赋值的reg型变量无关时,此时条件分支下的非阻塞赋值才是不会延后1 周期;否则,依然会延后1个周期;

NOTE:上述所说的 “变量本身与非阻塞赋值的reg型变量无关” ,特作如下解释:
/条件分支中的阻塞赋值变量val3本身与非阻塞reg变量cnt有关(间接),因为cnt_n与cnt有关/

always @ (posedge clk, negedge rst_n) begin
	if (!rst_n)
		cnt <= 4’d0;
	else
		cnt <= cnt_n;
end
	
always @ (*) begin
	if (cnt == 4’d14)
		cnt_n = 4’d0;
	else
		cnt_n = cnt + 1’b1;
end

always @ (*) begin
	if (!rst_n)
		val3 = 1’b0;
	else if (cnt_n == 4’d10)
		val3 = 1’b1;
	else
		val3 = 1’b0;
end

always @ (posedge clk, negedge rst_n) begin
	if (!rst_n) 
		val4 <= 1’b0;
	else if (val3)
		val4 <= 1’b1;
	else
		val4 <= 1’b0;
end
/***********************END**********************/

注意到,上述代码描述中val3是阻塞赋值的,但因为其与cnt(非阻塞赋值的reg变量)有关,故条件分支else if (val3)下的val4的非阻塞赋值依然会延后一个周期。

Verilog之非阻塞赋值(三)—— 赋值延后一个周期_第4张图片
而,对于条件分支下的条件判断式是与非阻塞赋值无关的阻塞赋值或者是assign赋值,则条件分支下的非阻塞赋值不会延后1个周期;见上述val6(条件是val5,val5的赋值采用阻塞或者assign赋值且与其他reg型非阻塞赋值的变量无关),则val6的赋值是瞬间完成的。

综上,其二应如下修改:

其二,当条件分支语句中含有的条件判断式是阻塞赋值变量(无论是外部输入的数据,或者是本模块的阻塞赋值变量,此时也包括assign赋值语句的LHS),若该变量与其他reg型非阻塞赋值变量无关时,则条件分支下的非阻塞赋值瞬间完成;反之,赋值会延后1个周期。

你可能感兴趣的:(数字电路设计)