第8章 运算器设计
8.1 二进制与逻辑电路
8.1.1 计算机中数的表示
人们使用计算机处理信息。无论被处理信息的实质形态如何千差万别,计算机内部只能处理离散化的编码后的数据。目前,计算机系统内部的所有数据均采用二进制编码。这样做的原因主要有两点。
1)二进制只有“0”和“1”两个数,其编码、计数和运算规则都很简单,特别是其中的符号“0”和“1”恰好可以与逻辑命题的“假”和“真”两个值相对应,因而能通过逻辑电路方便地实现算术运算。
2)二进制只有两种基本状态,使用有两个稳定状态的物理器件就能表示二进制数的每一位,而制造有两个稳定状态的物理器件要比制造有多个稳定状态的物理器件容易得多。例如电压的“高”“低”、磁极的“N”“S”、脉冲的“正”“负”、磁通量的“有”“无”。半导体工艺无论是TTL、ECL还是CMOS,都是用电压的高低来表示二进制的两个基本状态。
所有数据在计算机内部最终都交由机器指令处理,被处理的数据分为数值数据和非数值数据两类。数值数据用于表示数量的多少;非数值数据就是一个二进制比特串,不表示数量多少。对于给定的一个二进制比特串,要确定其表达的数值,需要明确三个要素:进位制、定/浮点表示和编码规则。
1.二进制
二进制同人们日常使用的十进制原理是相同的,区别仅在于两者的基数不同。
一般地,任意一个R进制数(R是正整数)
A=anan-1…a1a0.a-1a-2…a1-ma-m(m,n为正整数)
其值可以通过如下方式求得:
Value(A)=an×Rn+an-1×Rn-1+…+a1×R1+a0×R0+a-1×R-1+a-2×R-2+…+a1-m×R1-m+a-m×R-m
其中R称为基数,代表每个数位上可以使用的不同数字符号的个数。Ri称为第i位上的权,即采用“逢R进一”。
二进制即是上述一般性定义中R=2的具体情况。
上面的定义只回答了非负数或无符号整数的二进制表示问题。有关正负整数的表示问题会在下面讨论。下面举例说明无符号二进制整数的表示和加法。
例 用4位二进制编码,计算5+9。
解 5的4位二进制表示为01012,9的4位二进制表示为10012。5+9列竖式计算如下:
上面的竖式计算过程和人们日常的十进制竖式加法计算过程极为相似。所不同的仅在于,十进制是“逢十进一”,二进制是“逢二进一”。
计算机内部的所有数据都采用二进制编码表示,但是在表示绝对值较大的数据时需要很多位,不利于书写和阅读,因此经常采用十六进制编码来记录数据。因为16恰为24,所以二进制和十六进制相互转换时不会出现除不尽的情况,可以非常快捷地进行两种进制的转换运算。具体做法是,将一个数由二进制编码转换为十六进制编码时,从小数点开始,向左、向右两个方向,每4个二进制位一组(不足时小数点左侧的左补0,小数点右侧的右补0),直接替换为一个十六进制位。十六进制编码转换为二进制编码的方法类似,只是每个十六进制位替换为4个二进制位。
2.定点数的表示
常见的数有整数和实数之分,整数的小数点固定在数的最右边,通常省略不写,而实数的小数点则不是固定的。但是,计算机中只能表示0和1,无法表示小数点,因此计算机中表示数值数据必须要解决小数点的表示问题。我们通过约定小数点的位置来解决该问题。小数点位置约定在固定位置的数称为定点数,小数点位置约定为可以浮动的数称为浮点数。其中浮点数的表示将在下面介绍。这里将介绍计算机中最常见的两种定点数表示方法:原码和补码。
在明确了进位制和小数点位置的约定之后,整数在计算机中的表示还有一个正负号如何表示的问题要解决。针对这一问题,原码和补码这两种编码规则采用了不同的解决思路。
(1)原码
数的原码表示采用“符号-数值”的表示方式,即一个形如A=an-1an-2…a1a0的原码表示,最高位an-1是符号位,0表示正数,1表示负数;其余位an-2…a1a0表示数值的绝对值。如果an-1是0,则A表示正数+an-2…a1a0;如果an-1是1,则A表示负数-an-2…a1a0。例如,对于+19和-19这两个数,如果用8位二进制原码表示,则+19的原码是000100112,-19的原码是100100112。
原码表示有两大优点:
1)与人们日常记录正负数的习惯接近,与真实数值之间的对应关系直观,利于与真实数值相互转换。
2)原码实现乘除运算比较简便直接。
但是原码表示亦存在两个缺点:
1)存在两个0,即一个+0,一个-0。这不仅有悖于人们的习惯,也给使用带来不便。
2)原码的加减运算规则复杂,这对于逻辑实现的影响很大。在进行原码加减运算时,需要首先判断是否为异号相加或同号相减的情况,如果是的话则必须先根据两个数的绝对值的大小关系来决定结果的正负号,再用绝对值大的数减去绝对值小的数。
权衡上述利弊,现代计算机中基本不使用原码来表示整数。原码仅在表示浮点数的尾数部分时采用。
(2)补码
补码是定点数的另一种表示方法。现代计算机中基本都是采用补码来表示整数。它最大的好处就是可以用加法来完成减法运算,实现加减运算的统一。这恰好解决了原码表示所存在的最大问题。
在补码表示中,其最高位同原码一样也作为符号位,0表示正数,1表示负数。补码表示和原码表示的差异在于其数值的计算方法。对于一个形如A=an-1an-2…a1a0的补码表示,其值等于-2n-1×an-1+an-2…a1a0。如果an-1是0,则补码和原码一样,A表示正的an-2…a1a0;如果an-1是1,则A表示an-2…a1a0减去10…02(共n-1个0)得到的数。
求一个数的补码是个取模运算。关于模运算系统的准确数学描述,感兴趣的读者可以自行查阅相关资料。这里举一个最为常见的模运算系统的例子——时钟。这个模系统的模数为12。假定现在时钟指向6点,需要将它拨向10点,那么你有两种拨法,一种是顺时针向前拨4个小时,另一种是逆时针向后拨8个小时。这种相同的效果用数学的语言来说即4≡-8(mod 12)。基于模运算系统的概念,对于具有1位符号位和n-1位数值位的n位二进制整数的补码来说,其补码的定义是:
[X]补=2n+X(mod 2n),-2n-1≤X<2n-1
利用补码基于模运算的这个特点,可以把减法转换成加法来做,因此在计算机中不用把加法器和减法器分开,只要有加法器就可以做减法。
根据上述补码的定义并不容易写出一个数值的补码形式,而前面提到的原码可以很直观地与其数值进行转换。这里介绍一个原码和补码之间的转换方法:最高位为0时,原码与补码相同;最高位为1时,原码的最高位不变,其余位按位取反后末位加1。举个例子,譬如+19这个数,如果用8位二进制原码表示是000100112,最高位是0,所以其二进制补码也是000100112。那么对于-19这个数,其原码就是把+19原码的最高位从0变为1,即100100112。在求-19的补码时,原码最高位的1保持不变,原码余下的7位00100112按位取反得到11011002,末位再加一个1,得到11011012,最终得到-19的8位补码是111011012,这个值实际上是由+19的8位补码减去100000002(12810)得到的。
(3)溢出
无论采用原码表示还是补码表示,当一个二进制数的位数确定后,其能够覆盖的数值范围也就确定了。例如n位的二进制有符号数,其原码表示范围是[-2n-1+1,2n-1-1],其补码表示范围是[-2n-1,2n-1-1]。当同符号数相加或异符号数相减时,结果的数值就可能会超过该长度编码下可表示的范围,称之为溢出。例如,使用4位二进制编码计算-7+5,-7的补码是10012,+5的补码是01012,两者相加是11102(-210),两异号数相加不会溢出。又比如,使用4位二进制编码计算5+4,+5的补码是01012,+4的补码是01002,两者相加得到10012(-710),这显然是溢出,两个正数相加得到了一个负数。
加法溢出的判断方法是:如果A和B的最高位一样,但是A+B结果的最高位与A和B的最高位不一样,表示溢出,即两个正数相加得到负数,或两个负数相加得到正数。减法溢出的判断方法类似,即负数减正数结果是正数,或正数减负数结果是负数,这就表示溢出。
3.浮点数的表示
计算机中用于数据存储、传输和运算的部件的位数都是有限的,所以采用定点数表示数值数据时有一个不足之处,就是表示范围有限,太大或太小的数都不能表示。同时定点数表示精度也有限,用定点做除法不精确。此外,定点数也无法表示数学中的实数。所以,计算机还定义了浮点数,用来表示实数并弥补定点数的不足。
(1)二进制的科学记数法
在具体介绍计算机浮点数表示规格前,我们先回忆一下日常书写实数时所采用的科学记数法。譬如0.00000000110可以记为1.010×10-9,-3157600010可以记为-3.157610×107。一个采用科学记数法表示的数,如果尾数没有前导零且小数点左边只有一位整数,则可称为规格化数。既然我们可以用科学记数法来表示十进制实数,也可以用科学记数法来表示二进制实数。其一般的表示形式为:
(-1)s×f×2e
其中s表示符号,f为尾数域的值,e为指数域的值。
譬如二进制实数的科学记数法表示:1.12×24=2.410×101,-1.02×2-7=-7.812510×10-3。
(2)IEEE 754浮点数标准
计算机中的浮点数表示沿用了科学记数法的表示方式,即包含了符号、尾数和阶码三个域。符号用一位二进制码表示,0为正,1为负。然而在计算机内部位宽是有限的,余下的尾数和阶码两者间存在一个此消彼长的关系,需要设计者在两者间权衡:增加尾数的位宽会提高表示的精度但是会减少表示的范围,而增加阶码的位宽虽然扩大了表示的范围但是会降低表示的精度。因为浮点数规格的定义融入了设计者自身的考虑,所以直到20世纪80年代初,浮点数表示格式还没有统一标准,不同厂商的计算机内部的浮点数表示格式存在差异。这导致在不同厂商计算机之间进行含有浮点数的数据传送或程序移植时,必须进行数据格式的转换,更为糟糕的是,有时这种数据格式转换会带来运算结果不一致的问题。因此,从20世纪70年代后期开始,IEEE成立委员会着手制定统一的浮点数标准,最终在1985年完成了浮点数标准IEEE 754的制定。该标准的主要起草者是美国加州大学伯克利分校数学系教授William Kahan,他帮助Intel公司设计了8087浮点协处理器,并以此为基础形成了IEEE 754标准,他本人也因此获得了1987年的图灵奖。自IEEE 754标准颁布后,目前几乎所有的计算机都遵循该标准来表示浮点数。在过去的几十年间,IEEE 754标准也根据工业界在CPU研发过程中遇到的新需求、实现的新结构,及时进行演进和完善。其中一个比较重要的版本是2008年更新的IEEE 754-2008。该版本中明确了有关融合乘加(Fused Multiply-Add)运算、半精度浮点数等方面的内容。本书仅介绍IEEE 754标准中涉及单精度、双精度浮点数表示的基本内容,对其他内容感兴趣的读者可查阅相关文献。
(3)IEEE 754标准浮点数格式
IEEE 754标准中定义了两种基本的浮点数格式:32位的单精度格式和64位的双精度格式,如图8.1所示。
图8.1 IEEE 754浮点数格式
32位单精度格式中包含1位符号、8位阶码和23位尾数;64位双精度格式中包含1位符号、11位阶码和52位尾数。两种格式下基数均隐含为2。
IEEE 754标准中,尾数用原码表示。由于表示同一个数的时候尾数可以有多种表示,例如0.0012可以表示为0.12×2-2,也可以表示成1.02×2-3,因此需要一个规格化的表示来使得表示唯一。IEEE 754标准中规格化尾数的表示统一为1.xxxx的形式。尾数规格化后第一位总为1,因而可以在尾数中缺省这一位1。隐藏该位后尾数可以多一位表示,精度提高一位。
IEEE 754标准中,阶码用加偏置常量的移码表示,但是所用的偏置常量并不是通常n位移码所用的2n-1,而是(2n-1-1),因此,单精度和双精度浮点数的偏置常量分别为127和1023。
IEEE 754标准对浮点数的一些情况做了特殊的规定,总的来说可以分为5种情况,主要用阶码进行区分,表8.1给出了IEEE 754标准中单精度和双精度不同浮点数的表示。
表8.1 IEEE 754浮点数格式
1)无穷大(阶码全1尾数全0)。引入无穷大是为了在出现浮点计算异常时保证程序能够继续执行下去,同时也为程序提供一种检测错误的途径。+∞在数值上大于所有有限浮点数,-∞在数值上小于所有有限浮点数。无穷大不仅可以是运算的结果,也可以作为运算的源操作数。当无穷大作为源操作数时,根据IEEE 754标准规定,可以得到无穷大或非数的结果。
2)非数(阶码全1尾数非0)。非数(NaN)表示一个没有定义的数。引入非数的目的是检测非初始化值的使用,而且在计算出现异常时程序能够继续执行下去。非数根据尾数的内容又可以分为发信号非数(Signaling NaN)和不发信号非数(Quiet NaN)两种。如果源操作数是Quiet NaN,则运算结果还是Quiet NaN;如果源操作数是Signaling NaN,则会触发浮点异常。
3)规格化非0数(阶码非全0非全1)。阶码e的值落在[1,254](单精度)和[1,2046](双精度)范围内且尾数f是非0值的浮点数是规格化的非0数。其尾数经过规格化处理,最高位的1被省略。因此如果符号位是0,则表示数值为1.f×2e-127(单精度)和1.f×2e-1023(双精度);如果符号位是1,则表示数值为-1.f×2e-127(单精度)和-1.f×2e-1023(双精度)。
4)非规格化非0数(阶码全0尾数非0)。在规格化非0数中,能表示的浮点数的最小阶值是-126(单精度)和-1022(双精度),如果浮点数的绝对值小于1.0×2-126(单精度)和1.0×2-1022(双精度),该如何表示呢?IEEE 754允许特别小的非规格化数,此时阶码为0,尾数的小数点前面的那个1就不再添加了。因此如果符号位是0,则表示数值为0.f×2e-126(单精度)和0.f×2e-1022(双精度);如果符号位是1,则表示数值为-0.f×2e-126(单精度)和-0.f×2e-1022(双精度)。非规格化数填补了最小的规格化数和0之间的一段空隙,使得浮点数值可表示的精度进一步提升了很多。
5)零(阶码全0尾数全0)。根据符号位的取值,分为+0和-0。
8.1.2 MOS晶体管工作原理
从原理上看,只要有一个二值系统,并且系统中能够进行与、或、非这样的基本操作,就能够搭建出一台计算机。最早期的电子计算机使用继电器或电子管实现二值系统,而现代计算机中则采用晶体管来实现二值系统。晶体管可以根据控制端电压或电流的变化来实现“开启”和“关闭”的功能,从而表达二进制。晶体管主要分为双极型晶体管(Bipolar Junction Transistor)和金属-氧化物半导体场效应晶体管(Metal Oxide Semiconductor Field Effect Transistor,简称MOSFET或MOS)。当前绝大多数CPU都采用MOS晶体管实现,其中又以互补金属氧化物半导体(Complementary Metal Oxide Semiconductor,简称CMOS)晶体管电路设计最为常见。
1.半导体
MOS晶体管使用硅作为基本材料。在元素周期表中,硅是IV族元素,它的原子最外层有4个电子,可以与相邻的4个硅原子的最外层电子配对形成共价键。图8.2a给出了纯净硅中原子连接关系的一个简单二维平面示意,实际上纯净硅中原子构成的是一个正四面体立体网格。通过与相邻原子形成的共价键,纯净硅中所有原子的最外层都具有8个电子,达到相对稳定,所以纯净硅的导电性很弱。但是,如果在纯净硅中掺杂少量5价的原子(如磷),这些原子将挤占原有硅原子的位置,而由于这些原子的最外层有5个电子,除了与原有硅原子形成共价键用掉4个电子外,还多余一个处于游离状态的电子,如图8.2b所示。在电场的作用下,处于游离状态的电子就会逆着电场方向流动,形成负电流。这类材料被称为N(Negative)型材料。同样,如果在纯净的硅中掺杂少量3价的原子(如硼),那么这些原子挤占原有硅原子的位置后,其最外层还缺少一个电子和相邻的硅原子形成共价键,形成空穴,如图8.2c所示。在电场的作用下,周围的电子就会跑过来填补这个空穴,从而留下一个新的空穴,相当于空穴也在顺着电场方向流动,形成正电流。这类材料被称为P(Positive)型材料。当非4价元素掺杂的含量较小时,产生的电子和空穴也就比较少,用-号表示;当非4价元素掺杂的含量较大时,产生的电子和空穴也就比较多,用+号表示。因此,P-表示掺杂浓度低的P型材料,里面只有少量的空穴;N+表示掺杂浓度高的N型材料,里面有大量电子。
2.NMOS和PMOS晶体管
如图8.3所示,MOS晶体管是由多层摞放在一起的导电和绝缘材料构建起来的。每个晶体管的底部叫作衬底,是低浓度掺杂的半导体硅。晶体管的上部接出来3个信号端口,分别称为源极(Source)、漏极(Drain)和栅极(Gate)。源极和漏极叫作有源区,该区域内采用与衬底相反极性的高浓度掺杂。衬底是低浓度P型掺杂,有源区是高浓度N型掺杂的MOS晶体管叫作NMOS晶体管;衬底是低浓度N型掺杂,有源区是高浓度P型掺杂的MOS晶体管叫作PMOS晶体管。无论是NMOS管还是PMOS管,其栅极与衬底之间都存在一层绝缘体,叫作栅氧层,其成分通常是二氧化硅(SiO2)。最早期的MOS晶体管栅极由金属制成,后来的栅极采用掺杂后的多晶硅制成。掺杂后的多晶硅尽管其电阻比金属大,但却比半导体硅的电阻小很多,可以作为电极。并且同普通金属相比,多晶硅更耐受高温,不至于在MOS晶体管生产过程中融化。不过最新的工艺又有重新采用金属栅极的。
图8.2 半导体硅原子结构示意图
图8.3 MOS晶体管组成结构示意图
上面简述了MOS晶体管的基本构成,下面以NMOS晶体管为例介绍MOS晶体管的工作原理。如果单纯在源极、漏极之间加上电压,两极之间是不会有电流流过的,因为源极和漏极之间相当于有一对正反相对的PN结,如图8.4a所示。如果先在栅极上加上电压,因为栅氧层是绝缘的,就会在P衬底里形成一个电场。栅极上的正电压会把P衬底里面的电子吸引到栅氧层的底部,形成一个很薄的沟道电子层,相当于在源极和漏极之间架起了一座导电的桥梁。此时如果再在源极、漏极之间加上电压,那么两极之间的电流就能流过来了,如图8.4b所示。NMOS的基本工作原理就是这样,但是其实际的物理现象却很复杂。
图8.4 NMOS晶体管工作原理示意图
当我们屏蔽掉底层的物理现象细节,对MOS晶体管的工作行为进行适度抽象后,NMOS晶体管的工作行为就是:在栅极上加上电就通,不加电就断。PMOS晶体管的工作行为与NMOS晶体管的恰好相反,加上电就断,不加电就通。这样我们可以简单地把MOS晶体管当作开关。
图8.5 MOS晶体管开关行为
NMOS晶体管是栅极电压高时打开,栅极电压低时关闭;PMOS晶体管反过来,栅极电压低时打开,栅极电压高时关闭。如图8.5所示。随着工艺的发展,MOS晶体管中栅氧层的厚度越来越薄,使得开启所需的栅极电压不断降低。晶体管的工作电压从早期工艺的5.0V,降到后来的2.5V、1.8V,现在都是1V左右或更低。
尽管MOS晶体管可以表现出开关的行为,但是单纯的PMOS晶体管或者NMOS晶体管都不是理想的开关。例如,NMOS晶体管适合传输0而不适合传输1;PMOS晶体管恰好相反,适合传输1而不适合传输0。在后面讲述常见CMOS电路时,将会论及如何解决这一问题。
8.1.3 CMOS逻辑电路
在了解了MOS晶体管的组成和基本原理后,我们接下来了解如何用MOS晶体管构建逻辑电路。
1.数字逻辑电路
(1)布尔代数
数字逻辑基于的数学运算体系是布尔代数。布尔代数是在二元集合{0,1}基础上定义的。最基本的逻辑运算有三种:与(AND,&)、或(OR,|)、非(NOT,~)。这三种逻辑关系定义如下:
常用的布尔代数运算定律有:
·恒等律:A|0=A,A&1=A;
·0/1律:A|1=1,A&0=0;
·互补律:A|(~A)=1,A&(~A)=0;
·交换律:A|B=B|A,A&B=B&A;
·结合律:A|(B|C)=(A|B)|C,A&(B&C)=(A&B)&C;
·分配律:A&(B|C)=(A&B)|(A&C),A|(B&C)=(A|B)&(A|C);
·德摩根(DeMorgan)定律:~(A&B)=(~A)|(~B),~(A|B)=(~A)&(~B)。
上述定律虽然很简单,但使用起来变化无穷。
根据电路是否具有数据存储功能,可将数字逻辑电路分为组合逻辑电路和时序逻辑电路两类。
(2)组合逻辑
组合逻辑电路中没有数据存储单元,电路的输出完全由当前的输入决定。在组合逻辑的各种表达方式中,最简单的就是真值表,即对每一种可能的输入组合给出输出值。显然一个N输入的电路就有2N种不同的输入组合。常见的门级组合逻辑除了与门(AND)、或门(OR)、非门(NOT),还有与非门(NAND)、或非门(NOR)、异或门(XOR)。图8.6给出了一些常见的门逻辑符号及其真值表。
图8.6 常用基本逻辑门电路
利用基本逻辑门电路可以构成具有特定功能的更大规模的组合逻辑部件,如译码器、编码器、多路选择器、加法器等。加法器和乘法器两类运算逻辑电路我们将在后续章节中介绍。表8.2所示是3-8译码器真值表,把3位信号译码成8位输出,当输入000时,8个输出里面最低位为1,输入为001时,次低位为1,依次类推。表8.3所示是一个8选1选择器的真值表,当CBA为000的时候选择输出第0路D0,为001的时候选择输出第1路D1,依次类推。可以看出选择器可以用译码器加上与门来实现。
表8.2 3-8译码器真值表
表8.3 8选1选择器真值表
(3)时序逻辑
时序逻辑电路包含时钟信号和数据存储单元两个要素。时序逻辑电路的特点在于,其输出不但与当前输入的逻辑值有关,而且与在此之前曾经输入过的逻辑值有关。
时钟信号是时序逻辑电路的基础,它用于确定时序逻辑元件中的状态在何时发生变化。如图8.7所示,时钟信号是具有固定周期的标准脉冲信号。每个时钟周期分为高、低电平两部分,其中低电平向高电平变化的边沿称为上升沿,高电平向低电平变化的边沿称为下降沿。在CPU设计中,通常使用边沿触发方式来确定时序逻辑状态变化的时间点。所谓边沿触发就是将时钟信号的上升沿或下降沿作为采样的同步点,在每个采样同步点,对时序逻辑电路的状态进行采样,并存储到数据存储单元中。
图8.7 时钟信号
数据存储单元是时序逻辑电路中的核心。数据存储单元多由锁存器构成。首先介绍RS锁存器。图8.8是RS锁存器的逻辑图和真值表。RS锁存器包含置位端S(Set)和复位端R(Reset)两个输入端口,R为0、S为1时置输出为1,R为1、S为0时输出为0。在图8.8中,下面与非门的输出接到上面与非门的一个输入,同样上面与非门的输出接到下面与非门的一个输入,通过两个成蝶形连接的与非门构成RS锁存器。RS锁存器与组合逻辑的不同在于,当(R,S)的值从(0,1)或(1,0)变成(1,1)时能够保持输出值的状态不变,从而实现数据的存储。组合的输出只跟输入相关;但是RS锁存器的输入变了,它的输出还能保持原来的值。
图8.8 RS锁存器
在RS锁存器前面连接上两个与非门,再用时钟C(Clock)控制D输入就构成了如图8.9a所示的电路。当C=0时,R和S都为1,RS锁存器处于保持状态,也就是说当时钟处于低电平时,无论输入D怎样变化,输出都保持原来的值。当C=1时,输出Q与输入D值相同,相当于直通。这就是D锁存器(D Latch)的原理,通过时钟C的电平进行控制,高电平输入,低电平保持。
图8.9 D锁存器和D触发器
两个D锁存器以图8.9b所示的方式串接起来就构成了一个D触发器(D Flip-Flop)。当C=0时,第一个D锁存器直通,第二个D锁存器保持;当C=1时,第一个D锁存器保持,第二个D锁存器直通;C从0变为1时,D的值被锁存起来。这就是D触发器的基本原理,它是通过时钟的边沿进行数据的锁存。
实际情况下,由于器件中电流的速度是有限的,并且电容充放电需要时间,所以电路存在延迟。为了保证D触发器正常工作,需要满足一定的延迟要求。例如为了把D的值通过时钟边沿锁存起来,要求在时钟变化之前的某一段时间内D的值不能改变,这个时间叫作建立时间(Setup Time)。另外,在时钟跳变后的一段时间内,D的值也不能变,这个时间就是保持时间(Hold Time)。建立时间和保持时间可以是负数。此外D触发器还有一个重要的时间参数叫作Clock-to-Q时间,也就是时钟边沿到来后Q端数据更新为新值的时间。D触发器整个的访问延迟是建立时间加上Clock-to-Q时间。图8.10给出了上升沿触发的D触发器的建立时间、保持时间以及Clock-to-Q时间的示意。
图8.10 D触发器建立时间、保持时间和Clock-to-Q时间
2.常见CMOS电路
下面通过若干具体示例,讲述如何用MOS晶体管实现逻辑电路,且所列举的电路都是CMOS电路。关于CMOS电路的基本特点,将在“非门”示例之后予以说明。
(1)非门
图8.11a是非门(也称作反相器)的CMOS电路,它由一个PMOS晶体管和一个NMOS晶体管组成,其中PMOS晶体管(以下简称“P管”)的源极接电源,NMOS晶体管(以下简称“N管”)的源极接地,两管的漏极连在一起作为输出,栅极连在一起作为输入。如果输入为0(接地),则P管导通,N管关闭,P管的电阻为0(实际电路中P管其实有一定的电阻,大约在几千欧姆),N管的电阻无穷大,输出端的电压就是电源电压Vdd,如图8.11b所示。反之,当输入为1的时候,N管导通,P管关闭,N管的电阻为0(实际电路中N管其实有一定的电阻,大约在几千欧姆),P管的电阻无穷大,输出端与电源断开,与地导通,输出端电压为0,如图8.11c所示。这就是反相器CMOS电路的工作原理。
图8.11 CMOS电路:非门
从反相器的工作原理可以看出CMOS电路的基本特征,其关键就在“C”(Complementary,互补)上,即由上下两个互补的部分组成电路,上半部分由P管构成,下半部分由N管构成。上半部分打开的时候下半部分一定关上,下半部分打开的时候上半部分一定关闭。这种电路设计的好处是:在稳定状态,电路中总有一端是关死的,几乎没有直流电流,可以大幅度降低功耗。
(2)与非门
图8.12所示的是一个两输入与非门的CMOS电路,电路上面两个P管并联,下面两个N管串联。两个P管并联后,一头接电源,另一头与两个串联的N管连接。两个N管串联后,一头与并联的P管连接,另一头接地。与非门的两个输入A和B分别连接到一个N管和一个P管,输出端是Y。当A和B中有一个为0,则上面的P管网络导通,下面的N管网络断开,输出端被连接到电源上,即输出Y为1。
图8.12 CMOS电路:与非门
(3)或非门
图8.13所示的是一个两输入或非门的CMOS电路,电路上面两个P管串联,下面两个N管并联。两个P管串联后,一头接电源,另一头与两个并联的N管连接。两个N管并联后,一头与串联的P管连接,另一头接地。或非门的两个输入A和B分别连接到一个N管和一个P管,输出端是Y。当A和B中有一个为1,则上面的P管网络断开,下面的N管网络导通,输出端与电源断开,连通到地上,即输出Y为0。
图8.13 CMOS电路:或非门
(4)传输门
前面提到过单纯的PMOS晶体管或NMOS晶体管都不是理想的开关,但是在设计电路时有时需要一个接近理想状态的开关,该开关无论对于0还是1都可以传递得很好。解决的方式也很直观,如图8.14所示,一个P管和一个N管彼此源极连在一起,漏极连在一起,两者的栅极上接上一对极性相反的使能信号。当EN=0、时,P管和N管都关闭;当EN=1、时,P管和N管都开启。当P管和N管都开启时,无论信号是0还是1,都可以通过最适合传递该信号的MOS晶体管从A端传递到B端。
图8.14 CMOS电路:传输门
(5)D触发器
在前面讲述逻辑电路时介绍过如何用逻辑门搭建D触发器,在用CMOS电路实现D触发器时,我们也可以利用CMOS的逻辑门搭建出RS锁存器,进而搭建出D锁存器,并最终得到D触发器。但是考虑到构建D触发器时我们其实真正需要的是开关电路和互锁电路,所以这种构建D触发器的方式消耗的资源过多。图8.15中给出现代计算机中常用的一种D触发器电路结构。该电路的左边(虚线框内部)可以视作一个去除了输出缓冲器的D锁存器,该锁存器存储的值体现在其内部N1点的状态。当CLK=0,时,传输门G1开启、G2关闭,D点的值经由反相器I1和传输门G1传递进来,并通过反相器I2和三态反相器T1反馈至N1点,使该点到达一个稳定状态。当CLK=1,时,传输门G1关闭、G2开启,D点值的变化不再影响到内部N1点,同时N1点的状态经由传输门G2,并通过反相器I3和三态反相器T2反馈至N2点,使N2点处于稳定状态,并将该值传递至输出端Q。
图8.15 CMOS电路:D触发器
3.CMOS电路延迟
前面在介绍MOS晶体管原理的时候曾经提到过,真实世界中,PMOS晶体管和NMOS晶体管即便是在导通状态下源极和漏极之间也是有电阻的,栅极和地之间也存在寄生电容。因此CMOS电路工作时输入和输出之间存在延迟,该延迟主要由电路中晶体管的RC参数来决定。
图8.16a是一个CMOS反相器的示意图。其输出端有一个对地电容,主要由本身P管和N管漏极的寄生电容、下一级电路的栅电容以及连线电容组成。反相器输出端从0到1变化时,需要通过P管的电阻对该电容充电;从1到0变化时,该电容的电荷需要通过N管的电阻放电到地端。图8.16b示意了输出电容的充放电过程,其中左图代表充电过程,右图代表放电过程。因此,该反相器输出从0到1变化时的延迟由P管打开时的电阻和输出电容决定;从1到0变化时的延迟由N管打开时的电阻和输出电容决定。图8.16c示意了在该反相器输入端从0变到1、再变回到0的过程中(图中虚线表示),输出端值变化的过程。从中可以看出,反相器从输入到输出的变化是有延迟的,而且反相器的输出不是理想的矩形,而是存在一定的斜率。
图8.16 CMOS反相器的延迟
在芯片设计的时候,需要根据单元的电路结构建立每个单元的延迟模型。一般来说,一个单元的延迟由其本身延迟和负载延迟所构成,而负载延迟又与该单元的负载相关。需要指出的是,用早期工艺生成的晶体管,其负载延迟与负载呈线性关系,但对于深亚微米及纳米工艺,晶体管的负载延迟不再与负载呈线性关系。在工艺厂家给出的单元延迟模型中,通常通过一个二维表来描述每个单元的延迟,其中一维是输入信号的斜率,另外一维是输出负载。即一个单元的延迟是由输入信号的斜率和输出负载两个值通过查表得到的。