完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
IEEE Verilog标准中提供了阻塞赋值和非阻塞赋值两种赋值方式,二者的执行过程如下:
1.阻塞赋值(=):阻塞赋值操作实质上是一次性连续完成的,即计算等号右边变量(或表达式)的值(RHS)并立即赋值给等号左边的变量(LHS)。其中阻塞的含义为在同一个always块中,当前赋值语句正在执行时禁止其后的所有其他赋值语句的执行。只有当前赋值语句执行完成后,其后的赋值语句才能被执行。 2.非阻塞赋值(《=):非阻塞赋值操作实质上是分两步完成的,即第一步:在敏感事件开始时刻(如clk正跳变沿开始时刻)开始计算等号右边变量(或表达式)的值RHS;第二步:在敏感事件结束时刻(如clk正跳变沿结束时刻)将等号右边的值赋给等号左边的变量LHS。其中非阻塞的含义为在执行当前的非阻塞赋值语句的同时允许其他的语句执行。 由以上执行过程知,二者主要区别为:等号右边的变量值是否立即得到更新;赋值语句执行期间是否允许其他语句执行。 |
|
|
|
实验验证:
实验目的为验证在always块中分别采用阻塞赋值和非阻塞赋值对时序电路输出的影响。 阻塞赋值验证代码: /*----------------------------------------------------------- Filename: barrage_assign.v Function: 说明阻塞赋值可能带来电路的竞争冒险从而使输出不确定 Author: Zhang Kaizhou Date: 2019-10-12 11:58:43 ------------------------------------------------------------*/ module barrage_assign(clk, reset, y1, y2); //输入输出端口定义 output y1, y2; input clk, reset; //内部寄存器定义 reg y1, y2; //功能块1 always@(posedge clk or posedge reset) begin if(reset) y1 = 0; else y1 = y2; end //功能块2 always@(posedge clk or posedge reset) begin if(reset) y2 = 1; else y2 = y1; end endmodule 12345678910111213141516171819202122232425262728 /*----------------------------------------------------------- Filename: barrage_assign_t.v Function: barrage_assign模块的测试程序 Author: Zhang Kaizhou Date: 2019-10-12 21:04:06 ------------------------------------------------------------*/ `timescale 1ns/1ns `define PERIOD 10 module barrage_assign_t(y1, y2, clk, reset); output y1, y2, clk, reset; reg clk, reset; barrage_assign m0(.clk(clk), .reset(reset), .y1(y1), .y2(y2)); initial begin clk = 0; reset = 0; #100 reset = 1; #100 reset = 0; #300 reset = 1; #500 reset = 0; #500 $stop; end //产生时钟信号 always #`PERIOD clk = ~clk; endmodule 12345678910111213141516171819202122232425262728 阻塞赋值仿真结果: 非阻塞赋值验证代码: /*---------------------------------- Filename: non_block_assign.v Function: 说明非阻塞赋值语句的特性 Author: Zhang Kaizhou Date: 2019-10-12 21:08:56 -----------------------------------*/ module non_block_assign(clk, reset, y1, y2); //输入输出端口定义 input clk, reset; output y1, y2; //内部寄存器定义 reg y1, y2; //功能块1 always@(posedge clk or posedge reset) begin if(reset) y1 《= 0; else y1 《= y2; end //功能块2 always@(posedge clk or posedge reset) begin if(reset) y2 《= 1; else y2 《= y1; end endmodule 12345678910111213141516171819202122232425262728 /*--------------------------------------- Filename: non_block_assign_t.v Function: non_block_assign模块的测试程序 Author: Zhang Kaizhou Date: 2019-10-12 21:09:05 ---------------------------------------*/ `timescale 1ns/1ns `define PERIOD 10 module non_block_assign_t(y1, y2, clk, reset); output y1, y2, clk, reset; reg clk, reset; non_block_assign m0(.clk(clk), .reset(reset), .y1(y1), .y2(y2)); initial begin clk = 0; reset = 0; #100 reset = 1; #100 reset = 0; #300 reset = 1; #500 reset = 0; #500 $stop; end //产生时钟信号 always #`PERIOD clk = ~clk; endmodule 12345678910111213141516171819202122232425262728 非阻塞赋值仿真结果: |
|
|
|
实验总结:
对比上面两种赋值方式对应的仿真结果可知,对于阻塞赋值,因为IEEE Verilog标准规定always块的开始执行时刻的先后顺序是随机的(且always块是并行执行的),又由于在本次实验中两个always块中的变量变化相互依赖,再加上阻塞赋值是立即更新完成的,所以使得电路中存在竞争冒险现象,最终导致输出不确定。若功能块1先被执行,则输出为{y1, y2} = 2’b11;若功能块2先被执行,则输出为{y1, y2} = 2’b00。显然第一张仿真图显示的是第一种情况。 对于非阻塞赋值,虽然两个always块开始执行时刻的先后顺序是随机的,但是无论哪一个always块先提前几个ps开始执行,由于非阻塞赋值的执行过程是分两步进行的,在执行第一步(RHS计算)时,y1和y2的值仍然保持上一次更新后的值,在clk正跳变沿结束时刻,y1和y2会被同时更新为重新计算后的新值。所以在非阻塞赋值方式下,每个时钟周期y1和y2的值都会发生翻转。 |
|
|
|
附注:
用Verilog编写可综合模块时推荐遵循四条原则: 1.用always块描述时序逻辑时用非阻塞赋值(《=)。 2.用always块描述组合逻辑时用阻塞赋值(=)。 3.用always块描述时序和组合混合逻辑时用非阻塞赋值(《=)。 4.避免在多个always块中对同一变量赋值。 |
|
|
|
只有小组成员才能发言,加入小组>>
671 浏览 0 评论
1095 浏览 1 评论
2461 浏览 5 评论
2790 浏览 9 评论
移植了freeRTOS到STMf103之后显示没有定义的原因?
2625 浏览 6 评论
使用eim外接fpga可是端口一点反应都没有有没有大哥指点一下啊
643浏览 9评论
639浏览 7评论
请教大神怎样去解决iMX6Q在linux3.0.35内核上做AP失败的问题呢
770浏览 6评论
614浏览 5评论
656浏览 5评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 09:23 , Processed in 1.338457 second(s), Total 84, Slave 65 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号