Lec 5 CMOS技术 & 布尔运算到门电路
实验2的目标是设计一个32位的ALU,这是计算机中极为常见的组件。已经见过两位全加器(FA)串联组成的 2-bit ripple-carry adder,如果要扩展成 W 位加法器,该怎么办?今天要讲如何通过循环来描述参数化的电路(比如位宽是参数)。在硬件中是没有真正“循环”的——组合逻辑电路本质上就是盒子之间的循环连接。
在硬件设计语言(比如 BlueSpec)中,所有数据结构最终都会被转换为位向量(bit vectors)。不管是整数、布尔值、颜色等等,最后统统是0和1。
循环:必须是可以在编译时完全展开的。如果循环依赖数据(动态条件),编译器会直接报错,因为硬件是静态的、不能在运行时决定循环次数。
函数调用:也不会有动态调用或堆栈,而是通过内联(inlining)——函数体在编译时直接展开,变成一块具体电路。
最终生成的硬件结构是一个无环图(DAG):节点是逻辑门、运算器,连线是信号传递,没有循环反馈。
最重要的是记住:Bluespec 的目标是描述电路,电路本质上像是画图(画出各种盒子和连线),只不过每个盒子(比如与门、或门或者更大的模块)都有具体、可定义的功能,可以用真值表来描述。这和普通画图不同,它们有确定的意义。
虽然 Bluespec 设计的首要目的是描述并综合硬件,但同样重要的是,它也能模拟电路,以验证功能正确性(functional correctness)。所以,每当你写一个 Bluespec 程序时,除了可以综合成电路,还能通过输入输出测试来验证其行为。Bluespec 存在的根本原因是为了生成电路,而不是为了计算答案。因此,Bluespec 的编译过程与传统软件语言不同。Bluespec 在编译过程中会执行大量静态展开(static elaboration):比如所有数据结构最终都会转换成位向量(bit vectors),整数、布尔值、枚举颜色等在电路中统统变成 0 和 1;
需要特别小心的是,优化器(compiler)可能会对电路做大量优化,导致生成的电路和你原本写的程序结构差异很大。比如,如果你只想让电路做“加 4”的操作,编译器可能合成出比一般加法器更小、更快的专用电路。通过 Lab 2,你会慢慢体会这种优化带来的不同。
回到 ripple-carry adder。展开(unfold)循环时,如果你设定了宽度 W,比如 2 位,就可以按照如下步骤进行静态展开:首先用 i=0 替换循环体,得到第一个 full-adder,输出 c1 和 s0;接着用 i=1 替换,第二个 full-adder 输入 c1,输出 c2 和 s1。这样,carry 位的连接关系是自动建立起来的。编译器也会确保命名的一致性,比如 c1 始终表示同一根连线。
Minispec 的参数化与静态展开
手工把全加器拼成 rca2、再拼 rca4、rca8…… 既冗长又易错。Minispec 让编译器在编译期(静态展开 static elaboration)替我们展开这些重复结构。
参数化类型(parametric type):Bit#(n) 其实就是参数化类型,n 是一个编译期必须确定的整数参数。还有 Vector#(n, T)(n 个 T 类型元素),如 Vector#(4, Bit#(8))。给定参数后才得到一个具体类型。
参数化函数(parametric function):相当于其他语言里的“泛型/模板”,把工作从运行期转移到编译期。可以对参数(而非数据)做递归:
// n 位奇偶校验:对参数 n 递归
function Bit#(1) parity#(Integer n)(Bit#(n) x);
return (n == 1) ? x : x[n-1] ^ parity#(n-1)(x[n-2:0]);
endfunction
// n 位行波进位加法器:把一个全加器接到 rca#(n-1) 上
function Bit#(n+1) rca#(Integer n)(Bit#(n) a, Bit#(n) b, Bit#(1) cin);
Bit#(n) lower = rca#(n-1)(a[n-2:0], b[n-2:0], cin);
Bit#(2) upper = fullAdder(a[n-1], b[n-1], lower[n-1]);
return {upper, lower[n-2:0]};
endfunction
// 还需定义基例 rca#(1)(即一个全加器),否则编译期无限递归调用 parity#(3) 时,编译器把 3 代入,进而需要 parity#(2)、parity#(1)……一路实例化成嵌套的硬件盒子。这是编译期递归,最终全部综合成门和线。
Integer 类型:位数无界,只能在编译期求值(不可综合)。它支持算术/逻辑/比较运算,但这些运算不生成任何硬件——专门用来驱动参数和展开。
其他常用特性:
let:让编译器推断类型,如let y = x;(x 是 4 位则 y 也是 4 位),let n = 42;(n 是 Integer)。typedef:类型别名,如typedef Bit#(8) Byte;。struct:一组(可不同类型的)值,如Pixel { Byte red; Byte green; Byte blue; }。enum:一组符号常量,如typedef enum { Ready, Busy, Error } State;,编译器自动用若干位编码。
踩坑(务必牢记):Minispec 语法像软件,但语义是描述电路——
for循环次数必须编译期固定,编译器会把它完全展开;写出依赖运行时数据的循环会报错,且不小心会展开出庞大低效的电路。if/?:/case在组合逻辑里一律变成 mux,每个分支的硬件都真实存在。- 函数调用都是内联(inlining),没有运行时调用栈。
- 最终得到的是一张无环图(DAG)——本质上只有“组合环路连接”,没有真正的循环或递归在运行时发生。
Outline
- CMOS技术
- 组合逻辑的时序
CMOS技术
结构特性
这里有一个显示N-Channel MOSFET(Metal-oxide-semiconductor field-effect transistors,N沟道金属氧化物半导体场效应晶体管)截面的3D图。

集成电路(IC)所构建的基底(衬底)是一种经过掺杂的硅晶片,通过添加杂质使其具有导电性。在此案例中,所添加的杂质为受主原子(如硼),因此我们将掺杂后的硅称为p型半导体。集成电路将包含与p型衬底的电气连接,称为基极(bulk terminal),从而实现对其电压的控制。
当我们希望在导电材料之间提供电气绝缘时,我们会使用一层二氧化硅(SiO2)。通常,绝缘体的厚度并不是特别重要,除了用于隔离晶体管的栅极(gate, 这里显示为红色)和衬底时。该区域的绝缘层非常薄,因此栅导体上的电荷的电场可以轻易影响衬底。
晶体管的栅极是导体,在这种情况下是多晶硅。栅极、薄氧化物绝缘层和p型衬底共同构成一个电容器,其中改变栅极电压会引起栅极下方p型衬底的电气变化。在早期制造工艺中,栅极是金属制成的,金属氧化物半导体(MOS)一词就是指这种特殊结构。
栅极就位后,将磷等掺杂原子注入栅极两侧的p型衬底中的两个矩形区域。这些区域变为n型半导体,这将这些区域转变为n型半导体,最终成为MOSFET的两个终端。请注意,源极和漏极通常在物理上是相同的,通过它们在设备操作中扮演的角色加以区分。
MOSFET的功能是作为一个电压控制开关,连接设备的源极(Source)和漏极(Drain)。当开关导通时,电流将穿过作为栅电容第二极板的导电通道从漏极流向源极(第一极板是前面提到的Gate与衬底之间的薄氧化层)。MOSFET有两个关键尺寸:测量电流在从漏极流向源极时必须跨越的距离L以及其宽度W,决定有多少通道可用于导电。通过开关的电流,称为
通常,IC设计师会尽可能缩短长度——当新闻文章提到14纳米工艺时,14纳米指的是通道长度的最小允许值。设计师选择通道宽度来设定所需的电流流量。如果
总结一下:MOSFET有四个电气端子:基极、栅极、源极和漏极。设计师可以控制设备的两个尺寸:通道长度,通常选择尽可能小,通道宽度选择设定所需的电流流量。这是一个固态开关——没有活动部件,开关操作由四个端子相对电压确定的电场控制
电气特性

首先,我们将在栅极两侧的两个扩散极上标注名称:按照约定,电压最高的扩散极称为漏极(drain),电压较低的扩散极称为源极(source)。根据这种标记,如果有电流流过MOSFET开关,它将从漏极流向源极。在制造MOSFET时,它被设计为具有特定的阈值电压 $V_{TH} $,该电压决定了开关从非导通转变为导通的临界点。对于这里显示的n沟道MOSFET,我们预计 $V_{TH} $在现代工艺中约为0.5V。
图左侧的P+端子是与p型衬底的连接。为了使MOSFET正常工作,衬底的电压必须始终小于或等于源极和漏极的电压。MOSFET由栅极电压 $V_{G} $ 和源极电压 $V_{S} $之间的差异控制,根据电压的常用术语,我们将其称为
第一张图显示了当
PN结机制
当一个 P 区和 N 区形成接触(也就是形成 PN 结)时,会发生:
- 载流子扩散:
- N 区中的电子会扩散进入 P 区(空穴多的地方)
- P 区中的空穴会扩散进入 N 区(电子多的地方)
- 空间电荷区/耗尽层(Depletion Region)形成:
- 扩散之后,两边的自由载流子减少,留下带电离子,形成耗尽层
- 这个区域本身是没有自由载流子的,只剩下“固定电荷”,所以叫“耗尽”
- 内建电场(built-in electric field)建立:
- 防止进一步扩散,形成稳定的结
现在,随着
从价带(valence band)拉入导带(conduction band)是指电子在半导体材料中从一个能量带跃迁到另一个能量带的过程。具体来说,价带是半导体中能量较低、被电子填充的能带,而导带是能量较高、电子可以自由移动的能带。这个过程是半导体开关操作的基础。
此时,导电的反型层表现得像一个受欧姆定律控制的电阻,因此
当
和 关系

每条曲线都是在特定的
- 当
小于等于阈值电压时, 为0 - 当超过阈值电压时,
不为0,并随着 的增加而增加,因为 的越大,越多的衬底电子电子被吸引到栅电容的下衬底,反型层更厚,允许更多的电流通过。 - 当
小于 时,MOSFET表现得像一个电阻。曲线的线性部分的斜率与导电的MOSFET通道成反比。通道随着 增加变的更厚,更多的电流流过,曲线的斜率变陡,表明通道电阻更小 - 当
大于 ,通道在漏极被夹断,电流不在随着 的增加而增加,相反, 是恒定,说明MOSFET达到了饱和。 - 注意到$ I_{DS}$ 曲线的饱和部分并不完全平坦,
随着 增大略有增加。这种效应称为通道长度调制
MOSFET 的工作原理真复杂!幸运的是,作为设计师,只要在设计 MOSFET 电路时遵循一些简单规则,我们就能使用一个简单得多的开关模型。
CMOS抽象为电压控制开关

在p型衬底中有n型源/漏扩散。这些被称为n沟道MOSFET,因为反型层形成时是n型半导体。这里展示了n沟道MOSFET的示意符号,四个端子如图所示排列。在我们的MOSFET电路中,我们会将MOSFET的基端连接到地,这将确保p型衬底的电压始终小于或等于源和漏扩散的电压。
我们还可以通过翻转所有材料类型来构建MOSFET,创建n型衬底中的p型源/漏扩散。这称为p沟道MOSFET,其也表现为电压控制开关,只是所有电压电势都是反向的!正如我们将看到的那样,使n沟道开关处于开启状态的控制电压将使p沟道开关处于关闭状态,反之亦然。
使用这两种类型的MOSFET将为我们提供行为互补的开关。因此,使用这两种MOSFET的电路被称为互补金属氧化物半导体(Complementary MOS),简称CMOS。现在我们有了这两种电压控制开关,我们的下一个任务是弄清楚如何使用它们来构建对编码为电压的信息进行操作的电路。

现在我们对MOSFET的工作原理有了基本了解,接下来我们将利用它们构建电路来处理数字编码信息。在构建电路时,我们将遵循两条简单规则,只要严格遵守这些规则,就能将MOSFET的行为抽象为一个简单的电压控制开关。
规则1: 我们在构建下拉电路时只使用n沟道MOSFET,简称为NFET,下拉电路将信号节点连接到电源的接地(GND)。当下拉电路导通时,信号节点将为0V,并视为数字0。
如果我们遵循这条规则,NFET将作为由
PFET开关的情况与此类似, PFET只能用于上拉电路,将信号节点连接到电源电压,我们称之为
为什么不能在上拉电路中使用NFET或在下拉电路中使用PFET?
简而言之,使用NFET或PFET会导致信号节点出现信号电平劣化,从而失去我们辛辛苦苦建立的噪声裕度!
CMOS反相器的VTC

现在考虑CMOS实现的组合逻辑反相器。如果反相器的输入是数字0,那么它的输出是数字1,反之亦然。反相器电路包括一个用于下拉电路的单一NFET开关,将输出节点连接到接地(GND),和一个用于上拉电路的单一PFET开关,将输出连接到
当
当输入电压处于其电压范围的中间位置时,根据所用电源电压和MOSFET的阈值电压,上拉和下拉电路可能在短时间内同时导通。这是正常的。事实上,当两个MOSFET开关同时导通时,输入电压的微小变化会导致输出电压发生较大变化,从而展现出CMOS器件的高增益特性。这意味着我们可以选择包含较大噪声裕度的信号阈值,使CMOS器件能在多种不同的工作环境中可靠运行。这是我们的第一个CMOS组合逻辑门。
CMOS的互补特性

现在进入有趣的部分!为了构建其他逻辑门电路,我们将设计互补的上拉和下拉电路,如右图所示连接起来,以控制输出节点的电压。互补指的是当一个电路导通时,另一个电路不导通的特性。当上拉电路导通而下拉电路不导通时,输出节点与
如果电路设计不正确,导致它们不是互补的,并且可能在一段时间内都导通,那么在
另一种可能的情况是上拉和下拉电路都不导通,输出节点没有连接到任何电源电压。此时,输出节点电气上是浮动的,节点电容存储的电荷将保持在那里,至少一段时间。这是一种存储形式。现在,我们将集中讨论具有互补上拉和下拉电路的设备的行为。

由于上拉和下拉电路是互补的,我们会看到它们的设计有一种漂亮的对称性。我们已经看到了最简单的互补电路:一个NFET下拉和一个PFET上拉。如果同一个信号控制这两个开关,很容易看到当一个开关打开时,另一个开关关闭。现在考虑一个由两个串联的NFET开关组成的下拉电路。NFET串联开关的互补电路是并联的PFET开关。
、、
要设计一个更复杂的逻辑门,首先确定PFET开关的串联和并联连接,这些开关将在正确的输入组合下连接门的输出到VDD。在这个例子中,当A为0或者当B为0且C为0时,输出F将为1。OR逻辑对应于并联连接,而AND逻辑对应于串联连接,这给出了你在右侧看到的上拉电路。
为了构建互补的下拉电路,系统地遍历上拉连接的层次结构,用NFET替换PFET,将串联子电路替换为并联子电路,将并联子电路替换为串联子电路。在所示的例子中,上拉电路中有一个由A控制的开关与一个由B和C控制的串联子电路并联连接。互补的下拉电路使用NFET,由A控制的开关与由B和C控制的并联子电路串联连接。
最后,将上拉和下拉电路组合起来,形成完全互补的CMOS实现。这可能有点快,但通过实践,你会逐渐熟悉CMOS设计过程。
这种方法能适用于所有逻辑函数吗?
不行
CMOS门的反向逻辑特性

使用CMOS,单个门电路(具有一个上拉网络和一个下拉网络的电路)只能实现所谓的反向函数,即输入电平上升时输出电平下降,反之亦然。要理解原因,当门电路的一个输入电平从0变为1时的情况。
任何由上升输入控制的NFET开关将从关闭状态转为打开状态。这可能会在门的输出与GND之间启用一个或多个路径。而由上升输入控制的PFET开关将从打开状态转为关闭状态。这可能会禁用一个或多个路径在门的输出与VDD之间。因此,如果门的输出由于上升输入而发生变化,必须是因为某些下拉路径被启用,某些上拉路径被禁用。换句话说,由于上升输入引起的输出电压变化必定是从1到0的下降过渡。
类似的推理告诉我们,下降输入必定导致上升输出。这意味着所谓的正逻辑无法通过单个CMOS门实现。看看AND函数的真值表。当两个输入都为0或都为1时,其值与我们关于CMOS门输出的推断不一致。此外,我们可以看到当A为1且B从0上升到1时,输出上升而不是下降。故事的寓意是:当你是CMOS设计师时,你会非常擅长使用反向逻辑来实现功能
CMOS 的时间规范
我们已经理解如何使用CMOS来实现组合逻辑门电路,我们接下来关注其时间规范。这是一个简单的两个CMOS反相器串行连接的例子,我们用它来理解如何表征左侧反相器的时序特性。为了更好理解,我们需要构建一个电气模型,描述当输入电压

当
,输出波形具有电容通过电阻放电或充电时的特征指数形状。指数形波形由其相关的 R-C 时间常数决定,其中 R 是导线和 MOSFET 沟道总电阻,C 是导线和 MOSFET 栅极终端总电容。由于输入和输出过渡均非瞬时,我们需要选择测量反相器传播延迟的方法。幸运的是,我们正好可以参考信号阈值的指导原则。
传播延迟

组合逻辑门的传播延迟(Propagation Delay)被定义为从有效输入到有效输出的延迟上限。有效输入电压由
要测量
由于传播延迟
从设计师的角度来看,我们可以依靠每个组件的这个上限来计算更大数字系统的
污染延迟

尽管静态分析规范并未严格要求,但定义另一个时序规格——称为“污染延迟”(contamination delay)。该规格衡量门电路的上一输出值在输入开始变化并失效后,仍保持有效的时间长度。从技术上讲,污染延迟是输入失效到输出失效之间延迟的下限。我们将采用与传播延迟测量类似的方法进行延迟测量。
在输入上升过渡时,延迟开始于输入不再是有效数字0的时刻,即
我们真的需要污染延迟规范吗?通常不需要。如果未指定,设计师应假设组合设备的
组合逻辑的时序

以下是组合逻辑时序规格的简要总结。这些规格告诉我们输出波形(本例中标记为B)的变化时序与输入波形(本例中标记为A)的变化时序之间的关系。
组合设备在输入过渡后的一段时间内可能会保留其先前的输出值。设备的污染延迟保证了该时间间隔的最小值,即
同样地,了解B在输入过渡后何时保证完成变化也很重要。换句话说,我们需要等待多长时间才能使输入的变化反映在输出的更新值上?这就是
通常在从输入过渡开始测量的
如何根据组合电路时序规格计算较大组合电路的传播延迟和污染延迟呢?
示例

我们的示例是一个由四个NAND门组成的电路,其中每个NAND门的
要找到更大电路的污染延迟,我们再次调查所有从输入到输出的路径,但这次我们寻找从一个无效输入到一个无效输出的最短路径。我们沿每条路径求和各组件的tCD值,并选择最短路径的延迟作为整个电路的tCD。在我们的示例中,最短延迟路径包含两个NAND门,累计污染延迟为2 ns。换言之,当其中一个输入变为无效时,输出Y将至少保持其前一状态2 ns。
一般来说,我们不能对 tCD 和 tPD 之间的 Z 的值做出任何假设。Z 在该时间间隔内可以表现出任何行为,而设备仍被视为合法的组合逻辑电路。
宽容组合逻辑器件
你可以用 X(don't care) 表示那些不影响输出的输入。CMOS NOR 门具有一种“宽容”行为 —— 当某个输入已经足以决定输出时,其它输入的变化不会影响输出结果。这种特性使得电路在输入变化期间仍能保持稳定输出,是设计复杂逻辑系统(比如存储器)时非常重要的属性。
