【Verilog 教程】6.4Verilog竞争与冒险

news2024/11/17 15:49:49

关键字:竞争,冒险,书写规范
产生原因

数字电路中,信号传输与状态变换时都会有一定的延时。

在组合逻辑电路中,不同路径的输入信号变化传输到同一点门级电路时,在时间上有先有后,这种先后所形成的时间差称为竞争(Competition)。
由于竞争的存在,输出信号需要经过一段时间才能达到期望状态,过渡时间内可能产生瞬间的错误输出,例如尖峰脉冲。这种现象被称为冒险(Hazard)。
竞争不一定有冒险,但冒险一定会有竞争。
例如,对于给定逻辑 F = A & A’,电路如左下图所示。
由于反相器电路的存在,信号 A’ 传递到与门输入端的时间相对于信号 A 会滞后,这就可能导致与门最后的输出结果 F 会出现干扰脉冲。如右下图所示。
在这里插入图片描述
在这里插入图片描述
其实实际硬件电路中,只要门电路各个输入端延时不同,就有可能产生竞争与冒险。

例如一个简单的与门,输入信号源不一定是同一个信号变换所来,由于硬件工艺、其他延迟电路的存在,也可能产生竞争与冒险,如下图所示。
在这里插入图片描述

在这里插入图片描述

判断方法
代数法

在逻辑表达式,保持一个变量固定不动,将剩余其他变量用 0 或 1 代替,如果最后逻辑表达式能化简成

Y = A + A'
或者

Y = A · A'

的形式,则可判定此逻辑存在竞争与冒险。

例如逻辑表达式 Y = AB + A’C,在 B=C=1 的情况下,可化简为 Y = A + A’。显然,A 状态的改变,势必会造成电路存在竞争冒险。

卡诺图法

有两个相切的卡诺圈,并且相切处没有其他卡诺圈包围,可能会出现竞争与冒险现象。

例如左下图所存在竞争与冒险,右下图则没有。
在这里插入图片描述
其实,卡诺图本质上还是对逻辑表达式的一个分析,只是可以进行直观的判断。

例如,左上图逻辑表达式可以简化为 Y = A’B’ + AC,当 B=0 且 C=1 时,此逻辑表达式又可以表示为 Y = A’ + A。所以肯定会存在竞争与冒险。

右上图逻辑表达式可以简化为 Y = A’B’ + AB,显然 B 无论等于 1 还是 0,此式都不会化简成 Y = A’ + A。所以此逻辑不存在竞争与冒险。

需要注意的是,卡诺图是首尾相临的。如下图所示,虽然看起来两个卡诺圈并没有相切,但实际上,m6 与 m4 也是相邻的,所以下面卡诺图所代表的数字逻辑也会产生竞争与冒险。
在这里插入图片描述
其他较为复杂的情况,可能需要采用 “计算机辅助分析 + 实验” 的方法。

消除方法
对数字电路来说,常见的避免竞争与冒险的方法主要有 4 种。

1)增加滤波电容,滤除窄脉冲
此种方法需要在输出端并联一个小电容,将尖峰脉冲的幅度削弱至门电路阈值以下。

此方法虽然简单,但是会增加输出电压的翻转时间,易破坏波形。

2)修改逻辑,增加冗余项
利用卡诺图,在两个相切的圆之间,增加一个卡诺圈,并加在逻辑表达式之中。

如下图所示,对数字逻辑 Y = A’B’ + AC 增加冗余项 B’C,则此电路逻辑可以表示为 Y = A’B’ + AC + B’C。此时电路就不会再存在竞争与冒险。
在这里插入图片描述
3)使用时钟同步电路,利用触发器进行打拍延迟
同步电路信号的变化都发生在时钟边沿。对于触发器的 D 输入端,只要毛刺不出现在时钟的上升沿并且不满足数据的建立和保持时间,就不会对系统造成危害,因此可认为 D 触发器的 D 输入端对毛刺不敏感。 利用此特性,在时钟边沿驱动下,对一个组合逻辑信号进行延迟打拍,可消除竞争冒险。

延迟一拍时钟时,会一定概率的减少竞争冒险的出现。实验表明,最安全的打拍延迟周期是 3 拍,可有效减少竞争冒险的出现。

当然,最终还是需要根据自己的设计需求,对信号进行合理的打拍延迟。

为说明对信号进行打拍延迟可以消除竞争冒险,我们建立下面的代码模型。

module competition_hazard
    (
      input             clk ,
      input             rstn ,
      input             en ,
      input             din_rvs ,
      output reg        flag
    );

    wire    condition = din_rvs & en ;  //combination logic
    always @(posedge clk or negedge !rstn) begin
        if (!rstn) begin
            flag   <= 1'b0 ;
        end
        else begin
            flag   <= condition ;
        end
    end 

endmodule

testbench 描述如下:

`timescale 1ns/1ns

module test ;
    reg          clk, rstn ;
    reg          en ;
    reg          din_rvs ;
    wire         flag_safe, flag_dgs ;

    //clock and rstn generating 
    initial begin
        rstn              = 1'b0 ;
        clk               = 1'b0 ;
        #5 rstn           = 1'b1 ;
        forever begin
            #5 clk = ~clk ;
        end
    end

    initial begin
        en        = 1'b0 ;
        din_rvs   = 1'b1 ;
        #19 ;      en        = 1'b1 ;
        #1 ;       din_rvs   = 1'b0 ;
    end

    competition_hazard         u_dgs
     (
      .clk              (clk           ),
      .rstn             (rstn          ),
      .en               (en            ),
      .din_rvs          (din_rvs       ),
      .flag             (flag_dgs      ));

    initial begin
        forever begin
            #100;
            if ($time >= 1000)  $finish ;
        end
    end

endmodule // test

仿真结果如下:

由图可知,信号 condition 出现了一个尖峰脉冲,这是由于信号 din_rvs 与信号 en 相对于模块内部时钟都是异步的,所以到达内部门电路时的延时是不同的,就有可能造成竞争冒险。

虽然最后的仿真结果 flag 一直为 0,似乎是我们想要的结果。但是实际电路中,这个尖峰脉冲在时间上非常靠近时钟边沿,就有可能被时钟采集到而产生错误结果。
在这里插入图片描述
下面我们对模型进行改进,增加打拍延时的逻辑,如下:

module clap_delay
    (
      input             clk ,
      input             rstn ,
      input             en ,
      input             din_rvs ,
      output reg        flag
    );

    reg                  din_rvs_r ;
    reg                  en_r ;
    always @(posedge clk or !rstn) begin
        if (!rstn) begin
            din_rvs_r      <= 1'b0 ;
            en_r           <= 1'b0 ;
        end
        else begin
            din_rvs_r      <= din_rvs ;
            en_r           <= en ;
        end
    end

    wire                 condition = din_rvs_r & en_r ;
    always @(posedge clk or negedge !rstn) begin
        if (!rstn) begin
            flag   <= 1'b0 ;
        end
        else begin

            flag   <= condition ;
        end
    end // always @ (posedge clk or negedge !rstn)

endmodule

将此模块例化到上述 testbench 中,得到如下仿真结果。

由图可知,信号 condition 没有尖峰脉冲的干扰了,仿真结果中 flag 为 0 也如预期。

其实,输入信号与时钟边沿非常接近的情况下,时钟对输入信号的采样也存在不确定性,但是不会出现尖峰脉冲的现象。对输入信号多打 2 拍,是更好的处理方式,对竞争与冒险有更好的抑制作用。
在这里插入图片描述
4)采用格雷码计数器
递加的多 bit 位计数器,计数值有时候会发生多个 bit 位的跳变。

例如计数器变量 counter 从 5 计数到 6 时, 对应二进制数字为 4’b101 到 4’b110 的转换。因为各 bit 数据位的延时,counter 的变换过程可能是: 4’b101 -> 4’b111 -> 4’b110。如果有以下逻辑描述,则信号 cout 可能出现短暂的尖峰脉冲,这显然是与设计相悖的。

cout = counter[3:0] == 4’d7 ;
而格雷码计数器,计数时相邻的数之间只有一个数据 bit 发生了变化,所以能有效的避免竞争冒险。

好在 Verilog 设计时,计数器大多都是同步设计。即便计数时存在多个 bit 同时翻转的可能性,但在时钟驱动的触发器作用下,只要信号间满足时序要求,就能消除掉 100% 的竞争与冒险。

小结

一般来说,为消除竞争冒险,增加滤波电容和逻辑冗余,都不是 Verilog 设计所考虑的。

计数采用格雷码计数器,大多数也是应用在高速时钟下减少信号翻转率来降低功耗的场合。

利用触发器在时钟同步电路下对异步信号进行打拍延时,是 Verilog 设计中经常用到的方法。

除此之外,为消除竞争冒险,Verilog 编码时还需要注意一些问题,详见下一小节。
Verilog 书写规范
在编程时多注意以下几点,也可以避免大多数的竞争与冒险问题。

1)时序电路建模时,用非阻塞赋值。
2)组合逻辑建模时,用阻塞赋值。
3)在同一个 always 块中建立时序和组合逻辑模型时,用非阻塞赋值。
4)在同一个 always 块中不要既使用阻塞赋值又使用非阻塞赋值。
5)不要在多个 always 块中为同一个变量赋值。
6)避免 latch 产生。

下面,对以上注意事项逐条分析。

1)时序电路建模时,用非阻塞赋值
前面讲述非阻塞赋值时就陈述过,时序电路中非阻塞赋值可以消除竞争冒险。

例如下面代码描述,由于无法确定 a 与 b 阻塞赋值的操作顺序,就有可能带来竞争冒险。

always @(posedge clk) begin
    a = b ;
    b = a ;
end

而使用非阻塞赋值时,赋值操作是同时进行的,所以就不会带来竞争冒险,如以下代码描述。

always @(posedge clk) begin
    a <= b ;
    b <= a ;
end

2)组合逻辑建模时,用阻塞赋值
例如,我们想实现 C = A&B, F=C&D 的组合逻辑功能,用非阻塞赋值语句如下。
两条赋值语句同时赋值,F <= C & D 中使用的是信号 C 的旧值,所以导致此时的逻辑是错误的,F 的逻辑值不等于 A&B&D。

而且,此时要求信号 C 具有存储功能,但不是时钟驱动,所以 C 可能会被综合成锁存器(latch),导致竞争冒险。

always @(*) begin
    C <= A & B ;
    F <= C & D ;
end

对代码进行如下修改,F = C & D 的操作一定是在 C = A & B 之后,此时 F 的逻辑值等于 A&B&D,符合设计。

always @(*) begin
    C = A & B ;
    F = C & D ;
end

3)在同一个 always 块中建立时序和组合逻辑模型时,用非阻塞赋值
虽然时序电路中可能涉及组合逻辑,但是如果赋值操作使用非阻塞赋值,仍然会导致如规范 1 中所涉及的类似问题。

例如在时钟驱动下完成一个与门的逻辑功能,代码参考如下。

always @(posedge clk or negedge rst_n)
    if (!rst_n) begin
        q <= 1'b0;
    end
    else begin
        q <= a & b;  //即便有组合逻辑,也不要写成:q = a & b 
     end
end

4)在同一个 always 块中不要既使用阻塞赋值又使用非阻塞赋值
always 涉及的组合逻辑中,既有阻塞赋值又有非阻塞赋值时,会导致意外的结果,例如下面代码描述。

此时信号 C 阻塞赋值完毕以后,信号 F 才会被非阻塞赋值,仿真结果可能正确。

但如果 F 信号有其他的负载,F 的最新值并不能马上传递出去,数据有效时间还是在下一个触发时刻。此时要求 F 具有存储功能,可能会被综合成 latch,导致竞争冒险。

always @(*) begin
    C = A & B ;
    F <= C & D ;
end

如下代码描述,仿真角度看,信号 C 被非阻塞赋值,下一个触发时刻才会有效。而 F = C & D 虽然是阻塞赋值,但是信号 C 不是阻塞赋值,所以 F 逻辑中使用的还是 C 的旧值。

always @(*) begin
    C <= A & B ;
    F = C & D ;
end

下面分析假如在时序电路里既有阻塞赋值,又有非阻塞赋值会怎样,代码如下。

假如复位端与时钟同步,那么由于复位导致的信号 q 为 0,是在下一个时钟周期才有效。

而如果是信号 a 或 b 导致的 q 为 0,则在当期时钟周期内有效。

如果 q 还有其他负载,就会导致 q 的时序特别混乱,显然不符合设计需求。

always @(posedge clk or negedge rst_n)
    if (!rst_n) begin  //假设复位与时钟同步
        q <= 1'b0;
    end
    else begin
        q = a & b;   
    end
end

需要说明的是,很多编译器都支持这么写,上述的分析也都是建立在仿真角度上。实际中如果阻塞赋值和非阻塞赋值混合编写,综合后的电路时序将是错乱的,不利于分析调试。

5)不要在多个 always 块中为同一个变量赋值
与 C 语言有所不同,Verilog 中不允许在多个 always 块中为同一个变量赋值。此时信号拥有多驱动端(Multiple Driver),是禁止的。当然,也不允许 assign 语句为同一个变量进行多次连线赋值。 从信号角度来讲,多驱动时,同一个信号变量在很短的时间内进行多次不同的赋值结果,就有可能产生竞争冒险。

从语法来讲,很多编译器检测到多驱动时,也会报 Error。

6)避免 latch 产生
具体分析见下一章:《避免 Latch》。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试题:Java8 lambda 表达式 forEach 如何提前终止?

文章目录 1.情景展示2.原因分析3.解决方案方案一&#xff1a;使用原始的foreach循环方式一&#xff1a;break方式二&#xff1a;return(不推荐使用) 方案二&#xff1a;抛出异常 1.情景展示 如上图所示&#xff0c;我们想要终止for循环&#xff0c;使用return。 执行结果如下&…

成为吃鸡战场的王者!分享顶级战术干货,助您提高战斗力!

各位吃鸡战场的玩家们&#xff0c;欢迎来到本视频&#xff01;在这里&#xff0c;我将为您呈现一些与众不同的吃鸡干货&#xff0c;帮助您提高战斗力、轻松吃鸡&#xff01; 首先&#xff0c;让我们谈一谈作图工具推荐。绝地求生作图工具是吃鸡玩家们的必备利器。我将给大家推荐…

python+vue电子资源管理系统

能实现不出家门就可以通过网络进行系统管理&#xff0c;交易等&#xff0c;而且过程简单、快捷。同样的&#xff0c;在人们的工作生活中&#xff0c;也就需要互联网技术来方便人们的日常工作生活&#xff0c;实现工作办公的自动化处理&#xff0c;实现信息化&#xff0c;无纸化…

1.物联网射频识别

1.RFID概念 RFID是Radio Frequency Identification的缩写&#xff0c;又称无线射频识别&#xff0c;是一种通信技术&#xff0c;可通过无线电讯号识别特定目标并读写相关数据&#xff0c;而无需与被识别物体建立机械或光学接触。 RFID&#xff08;Radio Frequency Identificati…

传染病学模型 | Python实现基于SIR模型分析Covid19爆发

效果一览 文章概述 传染病学模型 | Python实现基于SIR 模型分析Covid19爆发 源码设计 import jax.numpy as npimport matplotlib.pyplot

向量数据库库Milvus Cloud2.3 运维可靠,秒级故障恢复

Milvus 2.3.0 已经发布有一段时间了,正如二选一的选择题总会让人陷入纠结一般,不少社区用户反馈对于选择 Milvus 2.2.x 还是 Milvus 2.3.x 犹豫不已。 对此,我们的回答是:强烈建议升级至 Milvus 2.3.x 版本。 为什么?在回答此问题之前,先回顾一下近一年来业界发生了哪些变…

RabbitMQ的基本介绍

什么是MQ 本质是一个队列&#xff0c;只不过队列中存放的信息是message罢了&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递信息。在互联网架构中&#xff0c;MQ是一种非常常见的上下游“逻辑解耦物理解耦”的消息通信服务。使用了MQ之后&#xff0c;信息发送…

Flutter笔记:滚动之-无限滚动与动态加载的实现

Flutter笔记 无限滚动与动态加载的实现 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133342307 本文还…

C++的内存管理和模板

文章目录 一、内存管理1.内存的分布2.C中的动态内存管理3.重载new和重载delete4.new和delete的实现原理5.定位new 二、模板1.泛型编程2.函数模板1.定义模板2.实例化模板3.模板类型的参数4.非类型模板参数 3.类模板1.定义模板2.实例化模板3.模板的成员函数 总结 一、内存管理 1…

蓝桥杯每日一题2023.9.27

4408. 李白打酒加强版 - AcWing题库 题目描述 题目分析 对于这题我们发现有三个变量&#xff0c;店&#xff0c;花&#xff0c;酒的数量&#xff0c;对于这种范围我们使用DP来进行分析。 dp[i][j][k]我们表示有i个店&#xff0c;j朵花&#xff0c;k单位酒的集合&#xff0c…

逆向入门及实战

一、逆向工程介绍 1.1 什么是逆向工程 提到逆向工程可能大多数人第一印象就是非道德层面的软件破解&#xff0c;其实不然&#xff0c;逆向工程又称为逆向技术&#xff0c;是一种产品设计技术再现过程&#xff0c;即对一项目产品进行逆向分析及研究&#xff0c;从而演绎并得出该…

git 过滤不需要提交的目录和文件

项目根目录下&#xff08;.git同级目录&#xff09;添加.gitignore文件 .DS_Store .idea npm-debug.log yarn-error.log /node_modules /log/**.log /config.js

【2023年11月第四版教材】第15章《风险管理》(合集篇)

第15章《风险管理》&#xff08;合集篇&#xff09; 1 章节说明2 管理基础2.1 风险的属性2.2 风险的分类★★★2.3 风险成本★★★2.4 管理新实践 3 管理过程4 管理ITTO汇总★★★5 过程1-规划风险管理6 过程2-识别风险6.1 识别风险★★★6.2 数据收集★★★6.3 数据分析★★★…

第一次作业题解

第一次作业题解 P5717 【深基3.习8】三角形分类 思路 考的是if()的使用,还要给三条边判断大小 判断优先级&#xff1a; 三角形&#xff1f;直角、钝角、锐角等腰等边 判断按题给顺序来 代码 #include <stdio.h> int main() {int a 0, b 0, c 0, x 0, y 0, z 0…

使用vpn/代理后电脑无法正常上网

有时候当我们关闭VPN后&#xff0c;却发现不能正常连接到互联网了。 解决步骤&#xff1a; 办法一&#xff1a; 1. 找到右下角wifi图标&#xff0c;鼠标右键点击然后点击网络和Internet 设置 2. 进入控制面板选择代理 3. 将自动检测打开&#xff0c;把使用代理服务器关闭 办法…

【C++入门指南】类和对象(上)

【C杂货店】类和对象&#xff08;上&#xff09; 一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装4.1 访问限定符4.2 封装 五、类的作用域六、类的实例化七、类对象模型7.1 类对象的存储规则7.2 例题7.3结构体内存对齐规则 八、this指针8.2 t…

【Java 进阶篇】使用 SQL 进行排序查询

在数据库中&#xff0c;我们经常需要对查询的结果进行排序&#xff0c;以便更容易地理解和分析数据。SQL&#xff08;Structured Query Language&#xff09;提供了强大的排序功能&#xff0c;允许我们按照指定的列对数据进行升序或降序排序。本文将详细介绍如何使用 SQL 进行排…

windows系统删除网络适配器

此电脑&#xff0c;右键&#xff0c;管理 打开本机设备管理器 其中找到网络适配器&#xff1a; 选中要删除的&#xff0c;右键点击“卸载设备”&#xff0c;点击卸载即可完成。

玩转Mysql系列 - 第24篇:如何正确的使用索引?

这是Mysql系列第24篇。 学习索引&#xff0c;主要是写出更快的sql&#xff0c;当我们写sql的时候&#xff0c;需要明确的知道sql为什么会走索引&#xff1f;为什么有些sql不走索引&#xff1f;sql会走那些索引&#xff0c;为什么会这么走&#xff1f;我们需要了解其原理&#…

GEO生信数据挖掘(三)芯片探针ID与基因名映射处理

检索到目标数据集后&#xff0c;开始数据挖掘&#xff0c;本文以阿尔兹海默症数据集GSE1297为例 目录 处理一个探针对应多个基因 1.删除该行 2.保留分割符号前面的第一个基因 处理多个探针对应一个基因 详细代码案例一删除法 详细代码案例二 多个基因名时保留第一个基因名…