尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Verilog基础:时序调度中的竞争(四)(描述时序逻辑时使用非阻塞赋值)
相关阅读Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482作为一个硬件描述语言Verilog HDL常常需要使用语句描述并行执行的电路但其实在仿真器的底层这些并行执行的语句是有先后顺序的然而Verilog标准并没有将这些事件调度的顺序定死而是给予了仿真器厂商一定的自由去实现自己的产品这就导致了设计者如果不遵循一定的编程习惯会导致意想不到的仿真结果下面是一些相关的规则。描述时序逻辑时使用非阻塞赋值首先以一个三级触发器为例说明描述时序逻辑时使用非阻塞赋值其电路如图1所示。图1 一个触发器组例1如果使用例1所示的阻塞赋值顺序执行的阻塞赋值会导致d在时钟上升沿被直接传递到q3最后的仿真结果图2和综合结果图3都只有一级触发器。# 例1 module example1 (q3, d, clk); output [7:0] q3; input [7:0] d; input clk; reg [7:0] q3, q2, q1; always (posedge clk) begin q1 d; q2 q1; q3 q2; end endmodule图2 例1的仿真结果图3 例1的综合结果例2例2将例1中的三个阻塞赋值重排序了以描述一个三级触发器的行为q3首先得到q2的值随后q2再得到q1的值最后才更新q1最后的仿真结果图4和综合结果图5都是三级触发器。# 例2 module example2 (q3, d, clk); output [7:0] q3; input [7:0] d; input clk; reg [7:0] q3, q2, q1; always (posedge clk) begin q3 q2; q2 q1; q1 d; end endmodule图4 例2的仿真结果图5 例2的综合结果虽然看起来很完美但例2其实是有问题的如果在该模块后某个触发器采样了q3或与q3有关的组合逻辑则此时q3可能使用未更新的值正确也可能使用已更新的值错误下面的例3说明了这种情况。例3例3在三级触发器后又加了一个触发器在时钟上升沿时q3的值会更新同时q4的值也会谁先执行是一个取决于仿真器的未定义行为。如果q4先更新则q4得到的是q3旧值正确如果q3先更新则q4得到的是q3新值错误如图6的仿真结果所示。即使图7所示的综合结果是正确的但这会造成前仿和后仿的不一致。# 例3 module example3 (q4, d, clk); output [7:0] q4; input [7:0] d; input clk; reg [7:0] q4, q3, q2, q1; always (posedge clk) begin q3 q2; q2 q1; q1 d; end always (posedge clk) begin q4 q3; // q4 q3; 这两种赋值都会导致竞争 end endmodule图6 例3的仿真结果一种可能错误图7 例3的综合结果例4如果理解了上面的例3那么将例3拆成三个always块的例4毫无疑问是一种会导致前仿和后仿不一致的写法因为不同always块的执行顺序是不确定的。图8展示的仿真结果表示该仿真器选择从下到上执行这三个always块因此得到了和例1一样的结果。从图9所示的综合结果来看是正确的。# 例4 module example4 (q3, d, clk); output [7:0] q3; input [7:0] d; input clk; reg [7:0] q3, q2, q1; always (posedge clk) begin q3 q2; end always (posedge clk) begin q2 q1; end always (posedge clk) begin q1 d; end endmodule图8 例4的仿真结果一种可能错误图9 例4的综合结果例5例5在例4的基础上将always块的顺序调换了图10展示的仿真结果表示该仿真器选择从下到上执行这三个always块因此得到了和例2一样的结果。从图11所示的综合结果来看是正确的。# 例5 module example5 (q3, d, clk); output [7:0] q3; input [7:0] d; input clk; reg [7:0] q3, q2, q1; always (posedge clk) begin q1 d; end always (posedge clk) begin q2 q1; end always (posedge clk) begin q3 q2; end endmodule图10 例5的仿真结果一种可能正确图11 例5的综合结果上面四种使用阻塞赋值的方法中只有一种能保证仿真结果正确即使三种的综合结果是正确的。例6例6以非阻塞赋值重写了例1由于非阻塞赋值分两步执行首先是右侧表达式值的计算在当前仿真时间的最后才将右侧表达式值赋值给左值。因此q2得到的是q1的旧值而q3得到的也是q2的旧值如仿真结果图12所示这时的综合结果如图13所示也是正确的。# 例6 module example6 (q3, d, clk); output [7:0] q3; input [7:0] d; input clk; reg [7:0] q3, q2, q1; always (posedge clk) begin q1 d; q2 q1; q3 q2; end endmodule图12 例6的仿真结果图13 例6的综合结果例7例7以非阻塞赋值重写了例2但仿真结果和综合结果依旧如图12和图13所示因为此时所有值的更新都是在最后进行的不会影响右侧表达式的计算结果。# 例7 module example7 (q3, d, clk); output [7:0] q3; input [7:0] d; input clk; reg [7:0] q3, q2, q1; always (posedge clk) begin q3 q2; q2 q1; q1 d; end endmodule例8例8以非阻塞赋值重写了例4虽然不同always块的执行顺序是不确定的但这只表示右侧表达式值的计算顺序是不确定的右侧表达式值赋值给左值的顺序是不确定的这不会对结果有任何影响所有右侧表达式值赋值给左值还是发生在右侧表达式值的计算前。仿真结果和综合结果依旧如图12和图13所示。# 例8 module example8 (q3, d, clk); output [7:0] q3; input [7:0] d; input clk; reg [7:0] q3, q2, q1; always (posedge clk) begin q3 q2; end always (posedge clk) begin q2 q1; end always (posedge clk) begin q1 d; end endmodule例9例9以非阻塞赋值重写了例5与例8同理仿真结果和综合结果依旧如图12和图13所示。# 例9 module example9 (q3, d, clk); output [7:0] q3; input [7:0] d; input clk; reg [7:0] q3, q2, q1; always (posedge clk) begin q1 d; end always (posedge clk) begin q2 q1; end always (posedge clk) begin q3 q2; end endmodule上面四种使用非阻塞赋值的方法中全部能保证仿真结果和综合结果正确。上面的九个例子说明了在描述时序逻辑时最好使用非阻塞赋值。例10例10展示了一个使用阻塞赋值实现的线性反馈移位寄存器(LFSR)关于这种结构的详细介绍可见数字IC前端学习笔记LFSR线性反馈移位寄存器。module example10 (q3, clk, pre_n); output q3; input clk, pre_n; reg q3, q2, q1; always (posedge clk or negedge pre_n) if (!pre_n) {q3,q2,q1} 3b111; else {q3,q2,q1} {q2,(q1^q3),q3}; endmodule例10将所有的赋值写在了一行保证了赋值的正确但这种风格是不建议的会让debug变得更加复杂。可以发现例10无法使用例2中将阻塞赋值重排序的方法实现因为其是有互相依赖即q3依赖q2而q2依赖于q3。而且例10仍然有例3所示的前仿和后仿不一致的问题。例11例11以非阻塞赋值重写了例10解决了例10存在的前仿和后仿不一致的问题。module example11 (q3, clk, pre_n); output q3; input clk, pre_n; reg q3, q2, q1; always (posedge clk or negedge pre_n) if (!pre_n) {q3,q2,q1} 3b111; else {q3,q2,q1} {q2,(q1^q3),q3}; endmodule例12例12将例11拆成了一个always块中的三个非阻塞赋值仿真结果和综合结果和例11一致。module example12 (q3, clk, pre_n); output q3; input clk, pre_n; reg q3, q2, q1; always (posedge clk or negedge pre_n) if (!pre_n) begin q1 1b1; q2 1b1; q3 1b1; end else begin q1 q3; q2 q1^q3; q3 q2; end endmodule例13例13将例12中的三个非阻塞赋值重排序了仿真结果和综合结果和例11一致。module example13 (q3, clk, pre_n); output q3; input clk, pre_n; reg q3, q2, q1; always (posedge clk or negedge pre_n) if (!pre_n) begin q3 1b1; q2 1b1; q1 1b1; end else begin q3 q2; q2 q1^q3; q1 q3; end endmodule例14例14将例11拆成了三always块仿真结果和综合结果和例11一致。module example14 (q3, clk, pre_n); output q3; input clk, pre_n; reg q3, q2, q1; always (posedge clk or negedge pre_n) if (!pre_n) begin q3 1b1; end else begin q3 q2; end always (posedge clk or negedge pre_n) if (!pre_n) begin q2 1b1; end else begin q2 q1^q3; end always (posedge clk or negedge pre_n) if (!pre_n) begin q1 1b1; end else begin q1 q3; end endmodule例15例15在例14的基础上将always块的顺序调换了仿真结果和综合结果和例11一致。module example15 (q3, clk, pre_n); output q3; input clk, pre_n; reg q3, q2, q1; always (posedge clk or negedge pre_n) if (!pre_n) begin q1 1b1; end else begin q1 q3; end always (posedge clk or negedge pre_n) if (!pre_n) begin q2 1b1; end else begin q2 q1^q3; end always (posedge clk or negedge pre_n) if (!pre_n) begin q3 1b1; end else begin q3 q2; end endmodule本文是基于《CUMMINGS, Clifford E., et al. Nonblocking assignments in verilog synthesis, coding styles that kill!.SNUG (Synopsys Users Group) 2000 User Papers, 2000. 》的进一步阐述感谢Clifford E. Cummings对此做出贡献。原文链接http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf
RELATED

相关推荐

AMBA:APB的历史(从APB1到APB5)

AMBA:APB的历史(从APB1到APB5)

相关阅读 AMBAhttps://blog.csdn.net/weixin_45791458/category_12800219.html?spm1001.2014.3001.5482 APB 版本信息 AMBA 1 APB Specification 最初于1996年推出,最后在1998年更新(文档名为APB Specification Rev E),该版本的…

📅 2026/10/27 9:28:01
AMBA:AHB的历史(从AHB2到AHB5)

AMBA:AHB的历史(从AHB2到AHB5)

相关阅读 AMBAhttps://blog.csdn.net/weixin_45791458/category_12800219.html?spm1001.2014.3001.5482 AHB版本信息 AMBA 2 AHB Specification 于1999年推出(文档名为AMBA Specification Rev 2),该版本的AHB被认为是AHB2。 Multi-layer …

📅 2026/10/27 9:28:01
LLM时代下,如何用项目思维打造可复用的个人技能提升体系

LLM时代下,如何用项目思维打造可复用的个人技能提升体系

我见过太多人一看到“skills”这个词就划走,觉得这是老生常谈的鸡汤。但恰恰是这个看似平淡的英文单词,在过去几年里,成了我折腾自我提升、做个人项目乃至带新人时,最值得写进“核心配置文件”的东西。如果你把它当成一个项目来打…

📅 2026/10/27 9:28:01
MORE NEWS

更多资讯

📰

Genkit skills本质解析:可编排的LLM能力契约单元

1. 这个“skills”到底指什么?别被热搜词带偏了方向 最近刷技术社区、开发者论坛,甚至朋友圈里都频繁跳出“skills”这个词——不是英文单词本意的“技能”,而是某种具体可安装、可调用、可配置的实体模块。它和 Gemini、GKE、Genkit、Googl…

📰

MonitorControl 快速上手:3 分钟找回外接显示器的亮度与音量快捷键

MonitorControl 快速上手:3 分钟找回外接显示器的亮度与音量快捷键 【免费下载链接】MonitorControl 🖥 Control your displays brightness & volume on your Mac as if it was a native Apple Display. Use Apple Keyboard keys or custom shortcut…

📰

【跑包网】wifi握手包跑包网站 cap在线分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

CNN为何在MNIST上远超全连接网络?局部感受野与权值共享的数学本质

简介:本资源是一份面向深度学习初学者与实践者的MNIST手写数字识别完整项目包,聚焦神经网络与卷积神经网络(CNN)在图像分类任务中的落地应用。项目基于TensorFlow框架,涵盖数据加载、CNN模型构建、训练调优、性能评估及…

📰

大模型应用开发入门:吴恩达课程提示工程、RAG与避坑指南

简介:面向希望快速上手大模型与人工智能应用开发的开发者,这是一份完整中文化吴恩达大模型系列课程并复现范例代码的入门教程,适合具备基础 Python 知识、希望系统学习 LLM 开发流程的技术人群。内容围绕提示工程、检索增强生成、函数调用等课…

📰

NVMe Write Zeroes及周边命令:语义、命令帧与实测坑

盘一台机器上的盘,最容易被忽略的往往不是读带宽、写带宽这些跑分指标,而是“这块区间我想让它变成干净的零”这类管理动作。几年前给一批测试机做批量镜像还原,脚本里老老实实地用dd往整盘灌/dev/zero,一块 1.6 TB 的企业级盘要跑…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬