文章目录

  • 前言
  • 数字电路中的隐患
    • 寄存器输出的不稳定态
    • 单触发器寄存器
    • 多触发器寄存器
    • 不稳定态对数字电路的影响
    • 特定情况下去除不稳定态的方法
    • 消除不稳定态的原理
    • 格雷码简介
    • 常用的格雷码编、解码方法
      • 从自然二进制码到格雷码
      • 从格雷码到自然二进制码
    • 从卡诺图看格雷码编码的非唯一性
    • 采用格雷码消除不稳定态

前言

了解数字电路中的隐患十分有必要,只有对此了如指掌,才能在实际问题中能明白出现问题的原因,而不必误认为是玄学问题。
本文节选自《FPGA之道》,一起站在巨人的肩膀上来看看数字电路中的隐患以及如何应对遇到的隐患。

数字电路中的隐患

数字电路由于其自身的特点,总会伴随着一些隐患。有些时候,这些隐患不会对FPGA设计造成影响,而有些时候,这些隐患却是致命的。为了尽量避免在项目开发时由于这些隐患而导致FPGA设计行为出错,本章节将对这些隐患进行一些简单的介绍。

寄存器输出的不稳定态

不稳定态,指的就是不稳定的状态。请注意,寄存器输出的不稳定态并不是由于赋值冲突而导致的不确定态(即‘X’状态),而是由于不同路径的延迟不一致所导致的数据线上出现了一个或多个非预期的中间状态。
有过时序仿真经历的朋友应该都知道,当寄存器的输出从X变到Y时,中间会有一小段毛刺状态。例如下图中就展示了当8位寄存器的输出从"01111111"变化到"10000000"时,过渡部分出现的不稳定状态,并且如果将不稳定态部分放大,可以看到其实这些看似毛刺的地方实际上也是有着确切的取值的(为了能够看清楚毛刺的全貌,在放大的图中改用十六进制显示数据):

由于这些毛刺并不是我们想要的,因此它们就构成了数字电路中的一种隐患,因此在本小节,我们将重点讨论这种隐患的成因、影响及应对策略。

单触发器寄存器

如果寄存器只包含一个触发器,即寄存器的存储容量仅为1bit,那么此时是否还会出现不稳定态呢?例如,如果在下一个有效时钟边沿到来时,要将一个1bit位宽的寄存器的输出从逻辑0变到逻辑1,那么波形图是否会出现若干次0、1之间的震荡呢?
事实证明,对于这类寄存器,无论你做多少次时序仿真,它都不会出现不稳定态。原因很简单:对于触发器来说,其输出只会在有效的时钟沿到来时变化,如果其输出变化了N次,那么其至少经历了N个时钟周期(因为如果连续两个时钟周期输入都一样,那么输出不会改变);反之,如果其经历了N个时钟周期,那么其最多也只能变化N次(理由同前)。因此,回到开始的问题,如果在下一个有效时钟边沿到来时,要将一个1bit位宽的寄存器的输出从逻辑0变到逻辑1,那么波形图是不可能出现0、1之间的震荡的,因为一个时钟有效边沿最多只能改变输出一次。

多触发器寄存器

只包含一个触发器的寄存器不会出现输出的不稳定态,那么为什么包含多个触发器的寄存器会出现不稳定态呢?
有很多FPGA的初学者都会对这个问题表示费解。他们认为,无论寄存器的位宽怎样,它们都是由最基本的触发器构成,而触发器在每个时钟的有效沿只能变化一次,因此,除非经历多个时钟周期,否则寄存器的输出怎么可能变化出多个值呢?
“不管你信不信,总之它就是发生了”。事实上,如果你有仔细观察本节最开始的寄存器输出不稳定态示例波形图,你就会发现,虽然在8位寄存器的输出从“01111111”变化到“10000000”的过程中,寄存器输出的不稳定态包含了若干次看似随机的中间值,但实际上任意两个相邻的中间值都是有一定联系的,那就是——它们之间只发生了1bit的变化。 例如0x76、0x36对应二进制表示分别为0b01110110、0b00110110,可见只有dOut[6]发生了变化;进一步分析这些相邻的中间值,还可以发现dOut[6]只在0x76到0x36之间变化了一次,而在其他相邻的中间值中保持不变;再进一步分析还可以发现对于dOut的其他位也是如此。因此,Nbits寄存器中的每个触发器并没有违背触发器在每个时钟的有效沿只能变化一次的原理。
那么到底是什么原因导致多触发器寄存器的输出在一个时钟有效沿后发生了多次变化呢?为了更加清楚的阐述这个问题,我们可以换个角度来观察dOut的时序仿真图,如下即为dOut的按位展开波形图:

这下我们可以非常明显的看到,造成多触发器寄存器输出出现不稳定态的原因,就是组成寄存器的各个触发器变化不一致造成的。当然了,更为精确的描述应该是——由于线延迟的存在,导致时钟信号到达各个寄存器的时间可能不一样,也导致各个触发器的输出端口到信号接收端所需的时间可能不一样,再加上各个触发器的tco等参数不可能精确的一样,所以当我们改变多触发器寄存器的输出时,就会出现不稳定态。

不稳定态对数字电路的影响

如果寄存器的输出用于产生同步逻辑中另一个或多个寄存器的输入,那么其不稳定态对FPGA设计的影响并不大。因为寄存器仅要求其输入在时钟有效沿时刻稳定即可(其实是在时钟有效沿附近一个比较小的范围内稳定即可),所以只要通过规范时钟信号的使用以及时序分析等手段,确保寄存器时钟有效沿到来的时刻及其需要数据稳定的时间窗口不要落入寄存器出现不稳定态的时间窗口内,就可以保证FPGA设计行为的正确性。

不过对于异步逻辑来说,不稳定态的危害就会凸显出来。
首先,如果一个寄存器的输出用于产生另一个时钟域中寄存器的输入,那么另一个时钟域的有效时钟沿几乎必定会落入不稳定态的窗口中(注意,不是每次时钟有效沿都会采样到不稳定态)。具体的分析请参阅【本篇->编程思路->时钟及时钟域->跨时钟域问题】章节的分析。
其次,如果寄存器的输出用于产生一个电平敏感的信号,那么肯定会导致出错。例如,下图中电路的设计初衷是当计数器的输出b等于3(二进制为11)时对后续电路进行异步复位,不过很可惜,由于寄存器输出不稳定态的存在,导致后续电路在计数器的输出从1变到2(二进制为从01变到10)时,如果计数器的高位稍微先于低位发生变话,就可能发生复位。

因此,当我们知道了寄存器的输出存在不稳定态后,就要在FPGA设计中杜绝出现上述这两种异步逻辑的情况,否则,隐患就会导致失败。

特定情况下去除不稳定态的方法

难道碰到不稳定态的情况只能小心躲过,绕着它走么?当然不是,对于寄存器输出的不稳定态,我们并不是完全束手无策的,不过能用的上的方法也比较有限,其中最典型的就是使用格雷码,介绍如下:

消除不稳定态的原理

通过对多触发器寄存器的分析,我们知道了产生不稳定态的原因,那就是组成寄存器的各个触发器输出变化时刻的客观不一致性。因此,要想消除不稳定态,就必须消除多触发器输出变化时刻的不一致才行。可是这个世界上没有两个长得一模一样的人,也没有两个一摸一样的触发器,更没有两段精确等长的物理连线,所以,想要通过协调一致多个触发器的输出变化时刻来消除寄存器输出的不稳定态,几乎是不可能的。不过换个思路来看,如果能够让寄存器中的多个触发器每次只有一个的输出会发生变化,那么自然也就不存在变化时刻不一致的问题,从而从根本上杜绝了不稳定态的产生。 例如,当8位寄存器的输出从“10000000”变化到“10000001”时,寄存器的输出就不会出现不稳定态,因为此时仅有寄存器中表示最低位触发器的输出发生了变化。
通过以上分析可以得出,只要能够保证在时钟有效沿时刻,寄存器的输入端与输出端的数据最多只有1个bit不同,就可以消除寄存器输出时的不稳定态。不过这个要求比较苛刻,仍以8位寄存器来说,在任一时刻,如果输出端数据为“00000000”,那么为了消除不稳定态,其输入端的数据只可能有8种选择,即:
“00000001”、
“00000010”、
“00000100”、
“00001000”、
“00010000”、
“00100000”、
“01000000”、
“10000000”;
可是该寄存器输入端的数据可以有256种形式,即从“00000000”~“11111111”。由此可见,如果寄存器的输入与其输出之间没有什么必然联系,是不可能有方法能够消除不稳定态的,请注意,即使寄存器的输入、输出之间有联系,但如果相关性不强,也可能无法消除其不稳定态。所以寄存器输出不稳定态这样一个隐患是无法在FPGA中彻底杜绝的,接下来将要详细介绍的格雷码,也只能够在某些特定应用条件下消除寄存器输出的不稳定态。当然,格雷码的应用并不仅限于此,在后续的章节中本书也会陆续地讲到。

格雷码简介

格雷码,英文全称:Gray code。由于自然二进制码在相邻数据之间可能存在多个bit的变化,例如自然数7和8对应的4bits自然二进制码分别“0111”、“1000”,因此当寄存器的输出从7变到8时,寄存器的每一位都会发生变化,从而造成不稳定态,并且会使得数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,因为格雷码是一种数字排序系统,其中的所有相邻整数在它们的二进制表示中仅有一位不同。例如下表给出了4bits自然二进制码、格雷码与十进制整数的对照表:

十进制数 自然二进制编码 格雷码
0 0000 0000
1 0001 0001
2 0010 0011
3 0011 0010
4 0100 0110
5 0101 0111
6 0110 0101
7 0111 0100
8 1000 1100
9 1001 1101
10 1010 1111
11 1011 1110
12 1100 1010
13 1101 1011
14 1110 1001
15 1111 1000

从上表我们看出,格雷码在任意两个相邻的数之间转换时,只有1个bit发生了变化,所以它有效的避免了寄存器由一个数值到下一个数值时的不稳定态。并且由于格雷码中最大数与最小数之间也仅1个bit不同,因此通常又被称作循环二进制码或者反射二进制码。
不过格雷码也有一个缺点,那就是相比于自然二进制码来说,它是一种无权码,因此很难直接进行比较和数学运算,所以一般都需要将采集到的以格雷码为表示形式的数据先转换成自然二进制码,然后再参与运算。因此接下来我们将介绍格雷码与自然二进制码之间的转换方法。

常用的格雷码编、解码方法

我们一般采用以下方法对数据进行格雷码的编解码:

从自然二进制码到格雷码

该过程也称为格雷码的编码,方法是从二进制码的最右边一位(最低位)起,依次将每一位与左边一位进行异或运算,作为对应格雷码该位的值,而最左边一位(最高位)不变。 对应公式如下:
g[n] = b[n],
g[i] = b[i] xor b[i+1] (i∈N,n-1≥i≥0);
其中g、b分别对应n位的格雷码和二进制码。
例如,将自然二进制码“10110”转换为格雷码,可以形象的用下图表示其转换过程:

从格雷码到自然二进制码

该过程也称为格雷码的解码,方法是从格雷码左边第二位(次高位)起,将每一位与其左边一位解码后的值异或,作为该位解码后的值,而最左边一位(最高位)的解码结果就是它本身。对应公式如下:
b[n] = g[n],
b[i] = g[i] xor b[i+1] (i∈N, n-1≥i≥0)。
其中g、b分别对应n位的格雷码和二进制码。
例如,将格雷码“11101”转换为自然二进制码,可以形象的用下图表示其转换过程:

从卡诺图看格雷码编码的非唯一性

格雷码其实并不唯一,这点可以从卡诺图上看出。例如对于2位宽的寄存器b,如果将b[1]、b[0]分别看做卡诺图的两个变量的话,并用b对应的自然二进制数值来填充卡诺图,可作出卡诺图如下:

b b[0] = 0 b[0] = 1
b[1] = 0 0 1
b[1] = 1 2 3

我们可以知道,在卡诺图中,“相邻”(不仅仅是空间相邻)的小方块之间,只有一个变量发生了变化。这也就是说,从上述卡诺图中任意一个方格出发,每次仅能移动到其相邻的、未被遍历的方格中,如此往复,直到再次回到出发点时,能够将卡诺图中除出发点外所有的小方格遍历且仅遍历一遍,那么沿着这条路线就可以得到一组格雷码。
对于上述卡诺图,如果出发点选择在1,沿顺时针方向走一圈,可以得到1、3、2、0,将其转化为二进制编码,为01、11、10、00,可见是一组格雷码;如果出发点选择在2,逆时针方向走一圈,可以得到2、3、1、0,将其转换为二进制编码,为10、11、01、00,可见仍是一组格雷码。按照如上思路,我们还可以得到更多的格雷码分组。如果对于更多触发器组成的寄存器,其可得到的格雷码组数就更加多样了。
由此可见,格雷码并不唯一,不过建议大家还是采用前面小节介绍的常用的格雷码编、解码方法,因为这种方法能够更加方便我们在格雷码和自然二进制码之间进行转化,否则我们可能需要建立和传送专门的查找表来进行格雷码的编、解码工作。
但是,利用卡诺图,我们可以得到一些状态空间不是2的整数次幂的格雷码编码集合,而这是【常用的格雷码编、解码方法】小节中的公式所不能解决的。其基本思路为:按照相邻格移动规则,当再次回到出发点时,故意让一些小方格没有被遍历到。例如对于3位宽的寄存器c,如果将c[2]、c[1]、c[0]分别看做卡诺图的三个变量的话,并用c对应的自然二进制数值来填充卡诺图,可作出卡诺图如下:

对于上述卡诺图,如果遍历环路为2、3、1、5、7、6(最后再回到2),将其转化为二进制编码,为010、011、001、101、111、110,可见这是一组格雷码,并且是一组元素为6的格雷码。此时,如果你需要实现一个6进制的计数器,采用这组格雷码就能保证任何时候计数器的输出在外界看来都只有一bit的翻转。但是请注意,采用上述方法虽然可以得到一些非2的整数次幂的格雷码编码集合,但这并不意味着你可以得到任意元素数的格雷码编码集合,例如,你无法得到只含有3个元素的格雷码集合。

采用格雷码消除不稳定态

了解了格雷码的概念和特性后,我们就可以利用格雷码来消除一些特定情况下的不稳定态。就拿在【不稳定态对数字电路的影响】小节给出的那个可能会提早给出复位行为的电路为例,如果我们将原先的自然二进制码计数器改为格雷码计数器,并在其输出等于格雷码的“3”时给出后续电路的复位信号,则复位行为就不会出现任何问题。修改后的电路如下:

格雷码的应用地方还有很多,在后续的章节中我们还会继续介绍,例如【本篇->编程思路->数据的存储->异步FIFO的HDL描述与用法】小节中,就利用了格雷码来保证跨时钟域读、写地址传递的稳定性,并对格雷码的应用做了更进一步的探讨。

FPGA之道(46)数字电路中的隐患相关推荐

  1. FPGA之道(56)状态的编码方式

    文章目录 前言 状态的编码方式 binary one-hot gray johnson auto compact sequential user speed none safe mode 前言 据我说 ...

  2. FPGA之道(48)跨时钟域问题

    文章目录 前言 跨时钟域问题 什么是跨时钟域问题 解决跨时钟域问题的原理 两级采样法 为什么要对非本时钟域的信号用本时钟域的时钟进行采样呢? 为什么要采样两次呢? 握手法 对于时钟域A: 对于时钟域B ...

  3. FPGA之道(51)数据的存储

    文章目录 前言 数据的存储 为什么需要数据存储 数据存储的载体 FPGA芯片内部的载体 触发器 查找表 块存储 FPGA芯片外部的资源 数据存储的形式.实现及应用场合 寄存器 特征简介 实现载体 应用 ...

  4. FPGA之道(44)HDL中的隐患写法

    文章目录 前言 有隐患的混写逻辑 VHDL中应该禁止的写法 在时序process中使用variable 在组合process中使用variable 鲁莽的process糅合 Verilog中应该禁止的 ...

  5. FPGA之道(35)Verilog中的并行与串行语句

    文章目录 前言 Verilog的并行语句 Verilog连续赋值语句 普通连续赋值语句 条件连续赋值语句 Verilog程序块语句 沿事件 纯组合always 纯时序always 具有同步复位的alw ...

  6. FPGA之道(67)代码中的约束信息(四)状态机的相关约束

    文章目录 前言 状态机的相关约束 fsm_extract fsm_style fsm_encoding enum_encoding safe_implementation safe_recovery_ ...

  7. FPGA之道(66)代码中的约束信息(三)存储器以及寄存器的相关约束

    文章目录 前言 存储器的相关约束 ram_extract ram_style rom_extract rom_style 寄存器的相关约束 前言 这是这个话题的第三篇,最重要的前言是本文节选自:< ...

  8. FPGA之道(65)代码中的约束信息(二)乘法器的相关约束

    文章目录 前言 乘法器的相关约束 use_dsp48 mult_style 前言 这是这个话题的第二篇,最重要的前言是本文节选自:<FPGA之道>. 乘法器的相关约束 通常,FPGA开发者 ...

  9. FPGA之道(64)代码中的约束信息(一)保持约束

    文章目录 前言 HDL中的常用约束示例 保持约束 keep keep_hierarchy 前言 这一节的内容很有意思也很有用,对于我们主动地操作我们的Verilog代码很有帮助.众所周知,通过设置工具 ...

最新文章

  1. Java集合:set的遍历方式
  2. Red Hat Enterprise Linux Server release 5.6 安装 MongoDB 2.6.4
  3. soapui模拟桩mockservice---模拟后台服务器
  4. 13个知识点,系统整理Python时间处理模块Datetime
  5. muduo网络库学习(五)服务器监听类Acceptor及Tcp连接TcpConnection的建立与关闭
  6. java sqlmap_sqlmap 学习指南
  7. fedora27 GPaste
  8. java 返回值给c_Java有陷阱,用时需谨慎——慎用入参做返回值
  9. 快学Scala习题解答—第四章 映射和元组
  10. 简单python脚本实例-你用 Python 写过哪些有趣的脚本?
  11. c++ 度分秒相互转化
  12. JLink的JTag和SWD引脚定义及接线说明
  13. html页面调节图片大小,怎么用css设置图片大小?
  14. matlab中样本相关系数的计算与测试
  15. 【科创人独家】云风:从创业到招安,自由的游戏玩家+务实的程序员
  16. 2018BDWF大数据世界论坛主题内容公布!
  17. HNUSTOJ-1621 Picking Cabbage(状态压缩DP)
  18. android方法apply,SharedPreferences的apply和Commit方法的那些坑
  19. 快速创建React Native App
  20. 高端访谈实录:访思科英国CEO菲尔·史密斯

热门文章

  1. Canvas3 汉化QA和BUG反馈
  2. prototype.js 1.4版开发者手册
  3. 联想sr950配置raid卡_联想服务器ThinkSeverRAID卡设置教程
  4. python语言函数库_Python 的标准库,从0到1学Python
  5. 计算机专业python教材_计算机专业几本必看的书!
  6. js调用python脚本_javascript – 如何从NodeJs调用python脚本
  7. 五元一次方程组计算器_人教版初中数学七年级下册列一元一次不等式解实际问题公开课优质课课件教案视频...
  8. php自定义表单数据库字段,自定义填写表格字段
  9. aauto+java_高可用数据采集平台(如何玩转3门语言php+.net+aauto)
  10. 色环电感外部磁场泄漏