Verilog语法之延时

说明

  1. LHS: Left-Hand-Side,左式;
  2. RHS: Right-Hand-Side,右式;
  3. `timescale 1ns/100ps;

连续赋值中的延时

LHS中加延时

assign #2 y = ~a;

  • 描述:非门的延时为2ns,输入端信号变化到输出端体现出来需要2ns时间。即a发生变化后,经过2ns时间,y才发生变化。
  • 注意:任意小于2ns的信号变化脉冲都被过滤掉。例如:
    initial begin 
    	a = 1'b0;
    	#3;
    	a = 1'b1;
    	#4;
    	a = 1'b0;
    	#1;
    	a = 1'b1;
    
    在a从1变化为0时,由于0的持续时长仅1ns,变化将不体现在输出端上,输出端在一次变化后将一直维持在0。
  • 解释:无论何时输入信号a发生变化,都会立即产生并执行一个计算事件,计算RHS的值,即~a,这个过程可表示为assign tmp = ~a,并且是立即执行。若a此时为0,则tmp=1。产生并执行计算事件的同时,产生一个更新事件,即assign y = tmp,但并没有被立即执行,而是被调度到当前仿真事件以后的2ns时刻去执行。而在更新事件被执行之前,若产生新的更新事件,即a从0变化为1,旧的更新事件将被替换,即tmp=0,并在新的更新事件产生的时刻之后的2ns执行新的更新事件。所以assign #2 y = ~a; 等价于:
    // assign #2 y = ~a;
    always @(a) begin
    	tmp = ~a;
    	#2;
    	y = tmp;
    end
    
    连续赋值语句中变化小于延时的脉冲被过滤的特点也体现了连续赋值没有记忆功能的特点,不管如何延时,计算事件在何时产生并执行,实际更新事件执行时都是用更新时间执行时刻的输入信号去计算RHS,在赋值给LHS。

assign #(2,3) y = ~a;

  • 描述:非门的上升沿延时(输出变为1)为2ns,下降沿延时(输出变为0)为3ns;关闭延时(输出变成z,高阻态)和输出变为x的延时为2和3中的最小值,即2ns。

assign #(2,3,4) y = ~a;

  • 描述:非门的上升沿延时(输出变为1)为2ns,下降沿延时(输出变为0)为3ns;关闭延时为4ns;输出为x的延时为2,3和4中的最小值,即2ns。

assign #(2:3:4,3:4:5) y = ~a;

  • 描述:表示上升延时的min:typ:max为2:3:4;下降延时的min:typ:max为3:4:5。

RHS中加延时(将产生语法错误)

由于线网类型没有记忆功能,assign 语句中给RHS加延时,将产生语法错误。如:

```verilog
assign y = #2 ~a;
assign y = #(2,3) ~a;
assign y = #(2,3,4) ~a;
assign y = #(2:3:4,3:4:5) ~a;
```

在这里插入图片描述

仿真

```verilog
`timescale 1ns/100ps
module delay (
	input a,
	output y1,y2,y3
);

	assign #2 y1 = ~a;
	assign #(2,3) y2 = ~a;
	assign #(2,3,4) y3 = (a===1'bz)?1'bz:~a;

endmodule

module delay_tb();
	reg a;
	wire y1,y2,y3;
	
	delay delay_u0(a,y1,y2,y3);
	
	initial begin 
	a = 1'b0;
	#3 a = 1'b1;
	#4 a = 1'b0;
	#1 a = 1'b1;
	#5 a = 1'bx;
	#5 a = 1'b0;
	#5 a = 1'bz;
	#5 a = 1'b0;
	end 

endmodule 
```

在这里插入图片描述

阻塞赋值中的延时

LHS中加延时

#5 y = a ^ b;

  • 描述:当某时刻T时,a或b发生了变化,导致always语句开始执行,然后遇到#5,立刻将该always进程挂起。等到5ns后,再将T+5ns时刻的a^b赋值给y。T~T+5ns的时间之内,a和b上的任何变化都被忽略了。

  • 解释:T时刻事件触发,然后执行#5。由于是阻塞赋值,在5ns时间内该always块一直在执行等待操作,触发事件的接收被阻塞,即错过事件触发,故a和b上的任何变化都被忽略了。而与其并行执行的always块的触发事件则不会被阻塞。等价于:

    // always @(a or b)
    //	#5 y = a ^ b;
    always @ (a or b) begin
    	#5;
    	y = a ^ b;
    end
    

#(3,5) y = a ^ b; //产生语法错误

在这里插入图片描述

RHS中加延时

y = #5 a ^ b;

  • 描述:当某个时刻T时,a或b发生了变化,导致always 语句开始执行,先将T时刻变化后的a和b异或,然后该always进程挂起。等5ns以后,再将T时刻的a^b的结果赋值给y。在T到T+5ns的时间之内,a和b上的任何变化都被忽略了。
  • 解释:等价于:
    // always @(a or b)
    // y = #5 a ^ b;
    always @ (a or b) begin
    	tmp  = a ^ b;
    	#5;
     	y = tmp;
    end
    

y = #(3,5) a ^ b; //将产生语法错误

仿真

module delay2 (
		input a, b,
		output reg y1,y2,y3,y4
		// output reg y1,y3
	);
	
		always @ (a or b) begin
			#5 y1 = a ^ b;
		end
		always @ (a or b) begin
			#4 y2 = a ^ b;
		end
		always @ (a or b) begin
			y3 = #5 a ^ b;
		end
	 	always @ (a or b) begin
			y4 = #4 a ^ b;
		end
	endmodule
	
	module delay2_tb();
		reg a, b;
		wire y1,y2,y3,y4;
		// wire y1, y3;
	
		delay2 delay_u1(a,b,y1,y2,y3,y4);
		// delay2 delay_u1(a,b,y1,y3);
	
		initial begin 
		a = 1'b0; b = 1'b0;
		#6 a = 1'b1;
		#4 a = 1'b0;
		#6 a = 1'b1;
		#5 a = 1'b0;
		#6 a = 1'b1;
		end 
	endmodule

在这里插入图片描述

非阻塞赋值中的延时

LHS中加延时

#5 y <= a ^ b;

  • 描述:当某个时刻T,a发生了变化,导致always语句开始执行,然后遇到#5,立刻将该always进程挂起。等到5ns以后,always语句被重新激活,将T+5ns时刻的a^b赋值给y。在T~T+5ns时间之内,a和b上的任何变化都被忽略了。
  • 解释:由于先进行延迟再进行非阻塞赋值,故结果与阻塞赋值时一样。而#5延时先执行,没有产生事件调度,所以触发事件也可以理解为被阻塞了。等价于:
    	// always @(a or b)
    	//	#5 y <= a ^ b;
    	always @ (a or b) begin
    		#5;
    		y <= a ^ b;
    	end
    	```
    

#(4,5) y <= a ^ b; // 产生语法错误

RHS中加延时

y <= #5 a ^ b;

  • 描述:当某个时刻T,a发生了变化,导致always语句开始执行y = a ^ b。首先计算a^b的值,然后将赋值给y的更新事件调度到T+5ns以后执行。在T~T+5ns上a和b的任何变化都不会忽略,总是在变化后的5ns时刻体现在y上。

  • 解释:更新事件调度会在等待执行队列中等待,由于非阻塞赋值具有记忆性,所以不会被替换。等价于:

    // always @(a or b) begin
    //	y <= #5 a ^ b;
    //	end
    always @(a or b) begin
    	tmp <= a ^ b;
    	# 5;
    	y <= tmp;
    end	
    

y <= #(4,5) a ^ b; //产生语法错误

仿真

module delay3 (
	input a, b,
	output reg y1,y2,y3,y4
	// output reg y1,y3
);

	always @ (a or b) begin
		#5 y1 <= a ^ b;
	end
	always @ (a or b) begin
		#4 y2 <= a ^ b;
	end
	always @ (a or b) begin
		y3 <= #5 a ^ b;
	end
 	always @ (a or b) begin
		y4 <= #4 a ^ b;
	end
endmodule

module delay3_tb();
	reg a, b;
	wire y1,y2,y3,y4;
	// wire y1, y3;

	delay3 delay_u2(a,b,y1,y2,y3,y4);
	// delay2 delay_u1(a,b,y1,y3);

	initial begin 
	a = 1'b0; b = 1'b0;
	#6 a = 1'b1;
	#2 a = 1'b0;
	#4 a = 1'b1;
	#5 a = 1'b0;
	#3 a = 1'b1;
	end 

endmodule

在这里插入图片描述

参考

  1. 《轻松成为设计高手:Verilog HDL实用精解》
  2. verilog中仿真延迟的添加
  • 15
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值