Verilog基础:时序调度中的竞争(一)

相关阅读

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


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

1、不要在两个及以上的always或initial结构中对同一个变量赋值

        当两个以上的过程结构同时执行时,它们之间的执行顺序是不一定的,Verilog标准只规定了在一个顺序块(begin end)中的所有语句是按照其先后顺序执行的,但并没有规定同一个时间执行的多个结构的执行顺序,下面举例详细说明。

//例1
`timescale 1ns/1ps
module test();initial $display("The initial_0 execute");initial $display("The initial_1 execute");initial $display("The initial_2 execute");
endmodule

        在上例中,三个initial结构在0ns时同时执行,仿真器执行他们的顺序是不定的,但测试表明,许多仿真器都选择顺序执行这三个initial结构,如下所示。

对于Mentor Modelsim SE,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Aldec Riviera Pro,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Cadence Xcelium,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Mentor Questa,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Synopsys VCS,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Icarus Verilog,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute

         虽然看起来仿真器的行为都是一致的,但其实这只是一个巧合,下面的例子就体现出了各种仿真器对同一段代码之间的不同行为。

//例2
`timescale 1ns/1ps
module test();reg a;initial #5 a = 1;initial @(a) $display("The initial_0 execute");initial @(a) $display("The initial_1 execute");initial @(a) $display("The initial_2 execute");
endmodule

        这段代码的三个initial结构都对事件a敏感,所以在5ns时,三个initial结构同时被触发,而他们的执行顺序是不定的,如下所示。

对于Mentor Modelsim SE,输出结果为
The initial_2 execute
The initial_1 execute
The initial_0 execute对于Aldec Riviera Pro,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Cadence Xcelium,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Mentor Questa,输出结果为
The initial_2 execute
The initial_1 execute
The initial_0 execute对于Synopsys VCS,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execut对于Icarus Verilog,输出结果为
The initial_2 execute
The initial_1 execute
The initial_0 execute

        下面的代码中仍然体现了同一时间的多个结构的执行顺序是不定的,即使触发这些结构的事件在同一时间是有前后关系的。

//例3
`timescale 1ns/1ps
module test();reg a, b, c;initial begin#5;a = 1;b = 1;c = 1;endalways @(a) $display("The initial_0 execute");always @(b) $display("The initial_1 execute");always @(c) $display("The initial_2 execute");
endmodule

        在5ns时,a、b、c先后被赋值为1,Verilog标准保证了begin end块中的赋值顺序从上到下。但由这些赋值语句触发的其他always结构呢?是否也会按照a、b、c的顺序执行呢?

对于Mentor Modelsim SE,输出结果为
The initial_2 execute
The initial_1 execute
The initial_0 execute对于Aldec Riviera Pro,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Cadence Xcelium,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute对于Mentor Questa,输出结果为
The initial_2 execute
The initial_1 execute
The initial_0 execute对于Synopsys VCS,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execut对于Icarus Verilog,输出结果为
The initial_0 execute
The initial_1 execute
The initial_2 execute

        依然可以注意到不同仿真器之间的差异,为什么不都是按照a赋值,always @(a)执行,b赋值,always @(b)执行,c赋值,always @(c)执行的顺序执行呢?还是那句话,Verilog标准只规定了一个顺序块(begin end)中的所有语句是按照其先后顺序执行的,并没有保证其他行为。当a赋值后,always @(a)被调度了,但他不一定会在b赋值之前执行,有可能在执行完b赋值、c赋值之后再来执行always @(a),此时always @(b)和always @(c)也应该在队列中,他们执行的先后顺序是标准没有保证的(但需要注意的是,最基本的调度者和被调度者的先后关系是无法改变的,即always @(a)一定在a赋值后,b、c亦然)。下面是一个经典的两个结构交错执行的例子。

//例4
`timescale 1ns/1ps
module test();reg a;wire b;initial begin#1;a = 1;#1;a = 0;$display("b is %b", b);endassign b = a;endmodule

         当时间来到1ns,a被赋值为1,同时触发assign结构,对b连续赋值为1。1ns后,a被更改为0,紧接着打印b的值,结果是1还是0呢?

对于Mentor Modelsim SE,输出结果为
b is 1对于Aldec Riviera Pro,输出结果为
b is 1对于Cadence Xcelium,输出结果为
b is 1对于Mentor Questa,输出结果为
b is 1对于Synopsys VCS,输出结果为
b is 0对于Icarus Verilog,输出结果为
b is 0

        上面的结果显示,仿真器可能在执行了a=0的赋值后立刻执行被调度的assign连续赋值,再返回initial结构执行显示语句,也可能继续执行下面的显示语句,再去执行被调度的assign连续赋值。

        这就给了我们一个启示,在改变了一个全组合逻辑的电路的输入后,紧接着显示输出,可能无法得到更新后的输出。一个更好的做法是给$display语句一定的延时,这样就能确保在执行$display前,连续赋值已经执行完毕,因为不同时间的语句执行是不会产生竞争的。

//例5
`timescale 1ns/1ps
module test();reg a;wire b;initial begin#1;a = 1;#1;a = 0;#0.01 $display("b is %b", b);endassign b = a;endmodule

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

管理类联考——数学——汇总篇——知识点突破——应用题——路程——记忆

路程——【考频:高】——【解题提示:根据题意画图,找等量关系(一般是时间和路程),列方程求解。】 【 应用题 ⟹ \Longrightarrow ⟹ 路程 ⟹ \Longrightarrow ⟹ 直线 ⟹ \Longrightarrow ⟹ 匀速、相遇、…

【ArcGIS Pro微课1000例】0036:栅格影像裁剪与提取(矢量范围裁剪dem高程数据)

本实验讲解在ArcGIS Pro中进行栅格影像裁剪与提取(矢量范围裁剪dem高程数据)的方法。DEM、DOM、DSM等栅格数据方法也可以实现。 文章目录 一、加载实验数据二、裁剪工具的使用1. 裁剪栅格2. 按掩膜提取一、加载实验数据 加载配套实验数据包中的0036.rar中的dem数据和矢量裁剪…

【经典小练习】简单的文件加密解密

文章目录 🌹什么是文件加密⭐应用场景 🛸案例🌺描述🌺代码 🌹什么是文件加密 Java文件加密是指使用Java编程语言和相关的加密算法对文件进行加密处理。通过这种方式,可以将文件内容转换为一种非常规的形式…

【数据结构】树与二叉树(廿二):树和森林的遍历——后根遍历(递归算法PostOrder、非递归算法NPO)

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语 5.2 二叉树5.3 树5.3.1 树的存储结构1. 理论基础2. 典型实例3. Father链接结构4. 儿子链表链接结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法5.3.3 树和森林的遍历1. 先根遍历(递归、非…

Go语言网络爬虫工程经验分享:pholcus库演示抓取头条新闻的实例

网络爬虫是一种自动从互联网上获取数据的程序,它可以用于各种目的,如数据分析、信息检索、竞争情报等。网络爬虫的实现方式有很多,不同的编程语言和框架都有各自的优势和特点。在本文中,我将介绍一种使用Go语言和pholcus库的网络爬…

力扣刷题篇之排序算法

系列文章目录 前言 本系列是个人力扣刷题汇总,本文是排序算法。刷题顺序按照[力扣刷题攻略] Re:从零开始的力扣刷题生活 - 力扣(LeetCode) 这个之前写的左神的课程笔记里也有: 左程云算法与数据结构代码汇总之排序&am…

OpenCV快速入门:特征点检测与匹配

文章目录 前言一、角点检测1.1 角点特征1.1.1 角点特征概念1.1.2 角点的特点1.1.3 关键点绘制代码实现1.1.4 函数解析 1.2 Harris角点检测1.2.1 Harris角点检测原理1.2.2 Harris角点检测公式1.2.3 代码实现1.2.4 函数解析 1.3 Shi-Tomasi角点检测1.3.1 Shi-Tomasi角点检测原理1…

C语言——从终端(键盘)将 5 个整数输入到数组 a 中,然后将 a 逆序复制到数组 b 中,并输出 b 中 各元素的值。

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int i;int a[5];int b[5];printf("输入5个整数&#xff1a;\n");for(i0;i<5;i){scanf("%d",&a[i]);}printf("数组b的元素值为&#xff1a;\n");for(i4;i>0;i--…

【免费使用】基于PaddleSeg开源项目开发的人像抠图Web API接口

基于PaddleSeg开源项目开发的人像抠图API接口&#xff0c;服务器不存储照片大家可放心使用。 1、请求接口 请求地址&#xff1a;http://apiseg.hysys.cn/predict_img 请求方式&#xff1a;POST 请求参数&#xff1a;{"image":"/9j/4AAQ..."} 参数是jso…

ddns-go部署在linux虚拟机

ddns-go部署ubuntu1804 1.二进制部署 1.虚拟机部署 1.下载linux的x86二进制包 wget https://github.com/jeessy2/ddns-go/releases/download/v5.6.3/ddns-go_5.6.3_linux_x86_64.tar.gz2.解压 tar -xzf ddns-go_5.6.3_linux_x86_64.tar.gz3.拷贝执行文件到PATH下&#xff0c…

Flink Flink中的分流

一、什么是分流 所谓“分流”&#xff0c;就是将一条数据流拆分成完全独立的两条、甚至多条流。也就是基于一个DataStream&#xff0c;定义一些筛选条件&#xff0c;将符合条件的数据拣选出来放到对应的流里。 二、基于filter算子的简单实现分流 其实根据条件筛选数据的需求…

Linux 家目录和根目录

摘要&#xff1a; 在 Linux 操作系统中&#xff0c;家目录和根目录是两个非常重要的概念。它们是 Linux 文件系统中的两个关键节点&#xff0c;为用户和系统进程提供存储、管理和访问文件和目录的接口。本文旨在深入探讨和理解这两个目录的结构、功能和使用方式&#xff0c;同时…