Verilog基础:时序调度中的竞争(四)(描述时序逻辑时使用非阻塞赋值)

相关阅读

Verilog基础icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_45791458/category_12263729.html?spm=1001.2014.3001.5482


        作为一个硬件描述语言,Verilog HDL常常需要使用语句描述并行执行的电路,但其实在仿真器的底层,这些并行执行的语句是有先后顺序的,然而Verilog标准并没有将这些事件调度的顺序定死,而是给予了仿真器厂商一定的自由去实现自己的产品,这就导致了设计者如果不遵循一定的编程习惯,会导致意想不到的仿真结果,下面是一些相关的规则。

4、描述时序逻辑时使用非阻塞赋值

        首先以一个三级触发器为例说明描述时序逻辑时使用非阻塞赋值,其电路如图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} = 3'b111; 
    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} <= 3'b111; 
    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 <= 1'b1; 
      q2 <= 1'b1;
      q3 <= 1'b1;
    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 <= 1'b1; 
      q2 <= 1'b1;
      q1 <= 1'b1;
    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 <= 1'b1;
    end
    else begin
      q3 <= q2;
    end   

  always @(posedge clk or negedge pre_n)  
    if (!pre_n) begin
      q2 <= 1'b1;
    end
    else begin
      q2 <= q1^q3;
    end 

  always @(posedge clk or negedge pre_n)  
    if (!pre_n) begin
      q1 <= 1'b1;
    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 <= 1'b1;
    end
    else begin
      q1 <= q3; 
    end 

  always @(posedge clk or negedge pre_n)  
    if (!pre_n) begin
      q2 <= 1'b1;
    end
    else begin
      q2 <= q1^q3;
    end 

  always @(posedge clk or negedge pre_n)  
    if (!pre_n) begin
      q3 <= 1'b1;
    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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/884260.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

重头开始嵌入式第四十四天(硬件 ARM裸机开发)

目录 裸机开发 一、开发背景 二、开发特点 三、开发流程 四、应用领域 使用的软件硬件 软件&#xff1a;keil 硬件&#xff1a;三星S3C2440A JTAG 开发原理 ​编辑 开发步骤 ​编辑 点亮小灯 按键控制亮灭 裸机开发 ARM 裸机开发是指在没有操作系统的情况…

信号处理: Block Pending Handler 与 SIGKILL/SIGSTOP 实验

1. 信号处理机制的 “三张表” kill -l &#xff1a;前 31 个信号为系统标准信号。 block pending handler 三张表保存在每个进程的进程控制块 —— pcb 中&#xff0c;它们分别对应了某一信号的阻塞状态、待处理状态以及处理方式。 block &#xff1a;通过 sigset_t 类型实现&…

【补充】倒易点阵基本性质

&#xff08;1&#xff09;任意倒易矢量 r h k l ∗ h a ∗ k b ∗ l c ∗ \mathbf{r}_{hkl}^* h\mathbf{a^*} k\mathbf{b^*} l\mathbf{c^*} rhkl∗​ha∗kb∗lc∗必然垂直于正空间中的(hkl)晶面。 正空间中的(hkl)晶面的法向是[hkl]&#xff0c;和坐标轴的交点为A、B、…

Steam黑神话悟空禁止更新进入游戏的解决方案

首先打开该网站&#xff1a;https://steamdb.info/app/2358720/ 2358720即为游戏ID 网页下翻&#xff0c;找到更新历史&#xff1a;https://steamdb.info/app/2358720/history/ 然后在Steam的steamapps下&#xff0c;找到后缀为2358720的文件&#xff0c;右击记事本打开 将St…

解决银河麒麟V10向日葵远程连接断开问题

解决银河麒麟V10向日葵远程连接断开问题 方法一&#xff1a;重启系统方法二&#xff1a;执行xhost 命令 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 当你在银河麒麟桌面操作系统V10上使用向日葵进行远程连接时&#xff0c;如果遇到频繁断…

Vue项目快速整合WangEditor富文本编辑器

Vue项目快速整合WangEditor富文本编辑器 一、安装依赖 npm i wangeditor --save //富文本编辑器 npm install highlight.js -S //代码高亮 npm install dompurify vue-dompurify-html // 防xss 库二、app.vue代码案例 已对接图片、视频接口 &#xff0c;具体看如下代码…

基于飞腾平台的OpenCV的编译与安装

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

景联文科技精准数据标注:优化智能标注平台,打造智能未来

景联文科技是一家致力于为人工智能提供全面数据标注解决方案的专业公司。 拥有一支由经验丰富的数据标注师和垂直领域专家组成的团队&#xff0c;确保数据标注的质量和专业性。 自建平台功能一站式服务平台&#xff0c;提供从数据上传、标注、审核到导出的一站式服务&#xff0…

Linux安装tomcat及配置环境变量超详细教程

微服务Linux解析部署使用全流程 linux系统的常用命令 Linux安装vim超详细教程 Linux安装JDK及配置环境变量超详细教程 1、上传压缩包 统一创建目录&#xff1a;/usr/local/tomcat&#xff0c;将压缩包上传到这个目录下。拖动文件到这个目录下即可。 2、执行解压命令 先进…

Sentinel-1 数据处理时如何手动下载高程数据

在Sentinel-1 数据数据预处理时&#xff0c;会使用高程数据进行地形校正。但选择自动下载高程时&#xff0c;由于网络原因经常会卡死&#xff0c;造成预处理过程不能正常进行&#xff01; 这个问题经过我的反复实践&#xff0c;可以通过手动下载高程数据来解决。下面是具体方法…

章管家 listUploadIntelligent.htm SQL注入漏洞

漏洞描述&#xff1a; 章管家 listUploadIntelligent.htm 接口处存在SQL注入漏洞&#xff0c;未经身份验证的远程攻击者除了可以利用 SQL 注入漏洞获取数据库中的信息&#xff08;例如&#xff0c;管理员后台密码、站点的用户个人信息&#xff09;之外&#xff0c;甚至在高权限…

软件功能测试需进行哪些测试?第三方软件测评机构有哪些测试方法?

在信息化社会迅速发展的今天&#xff0c;软件功能测试在软件开发生命周期中占据着不可或缺的地位。软件功能测试是评估软件系统是否符合预期功能和用户需求的过程。其重要性体现在提升软件质量、确保用户满意度以及降低维护成本等方面。 软件功能测试是对软件应用程序进行的一…

robomimic应用教程(二)——策略运行与评估

得到训练好的pth后&#xff0c;下一并将其进行部署及效果评估 可以在jupyter notebook中进行此操作&#xff0c;文件为robomimic文件夹中的examples/notebooks/run_policy.ipynb 本文采用pycharm调试 该脚本用于在环境中评估策略&#xff0c;主要包括从model zoo下载checkpoi…

【web开发】Spring Boot 快速搭建Web项目(三)

Date: 2024.08.31 18:01:20 author: lijianzhan 简述&#xff1a;根据上篇原文Spring Boot 快速搭建Web项目&#xff08;二&#xff09;&#xff0c;由于已经搭建好项目初始的框架&#xff0c;以及自动创建了一个启动类文件&#xff08;TestWebApplication.java&#xff09; …

【Python】Daphne:Django 异步服务的桥梁

Daphne 是 Django Channels 项目的一部分&#xff0c;专门用于为 Django 提供支持 HTTP、WebSocket、HTTP2 和 ASGI 协议的异步服务器。Daphne 是一个开源的 Python 异步服务器&#xff0c;它可以帮助开发者运行异步应用程序&#xff0c;并且非常适合与 Django Channels 一起使…

电子电路的基础知识

电子电路是现代电子技术的基础&#xff0c;由电子元件&#xff08;如电阻、电容、电感、二极管、晶体管等&#xff09;和无线电元件通过一定方式连接而成的电路系统。 以下是对电子电路的详细概述&#xff1a; 一、定义与分类 定义&#xff1a;电子电路是指由电子器件和有关无…

解压视频素材下载网站推荐

在制作抖音小说推文或其他短视频时&#xff0c;找到合适的解压视频素材非常重要。以下是几个推荐的网站&#xff0c;可以帮助你轻松下载高质量的解压视频素材&#xff1a; 蛙学网 蛙学网是国内顶尖的短视频素材网站&#xff0c;提供大量4K高清无水印的解压视频素材&#xff0c;…

【记录】Excel|不允许的操作:合并或隐藏单元格出现的问题列表及解决方案

人话说在前&#xff1a;这篇的内容是2022年5月写的&#xff0c;当时碰到了要批量处理数据的情况&#xff0c;但是又不知道数据为啥一直报错报错报错&#xff0c;说不允许我操作&#xff0c;最终发现是因为存在隐藏的列或行&#xff0c;于是就很无语地写了博客&#xff0c;但内容…

如何使用Flux+lora进行AI模型文字生成图片

目录 概要 前期准备 部署安装与运行 1. 部署ComfyUI 本篇的模型部署是在ComfyUI的基础上进行&#xff0c;如果没有部署过ComfyUI&#xff0c;请按照下面流程先进行部署&#xff0c;如已安装请跳过该步&#xff1a; &#xff08;1&#xff09;使用命令克隆 ComfyUI &…

【友元补充】【动态链接补充】

友元 友元的目的是让一个函数或者类&#xff0c;访问另一个类中的私有成员。 友元的关键字friend是一个修饰符。 友元分为友元类和友元函数 1.全局函数作友元 2.类作友元 3.类的一个成员函数作友元 好处&#xff1a;可以通过友元在类外访问类内的私有和受保护类型的成员 坏处…