Lec 6 时序电路
组合电路的一个重要特性是其固有的有限性:每个组合电路都是由有限多个门电路组成的;有限多个输入-输出路径;执行有限多个基本逻辑运算来计算输出;执行计算所需的时间是有限的--以其
假设我们需要把一列 N 个 32 位数加起来,N 大于 2。我们可以设计一个组合电路加法器,直接接受 N 个 32 位输入。但当 N 很大时,设计变得很繁琐,电路非常复杂。更糟糕的是:它是固定的 —— 如果某天我们需要加 N+1 个数,这个加法器就派不上用场了。组合电路的输入数量和逻辑门数量都是固定的,因此它的计算能力被限制在一个有界范围内。
本章我们将探索,如何把电路从组合逻辑的有限性中解放出来。借助一定的技术和工程手段,让电路能够执行一系列有顺序的操作,也就是说,引入了“时间”这个维度。时序电路的关键区别在于:它的输出不仅仅依赖当前输入,还取决于输入数据在时间上的先后顺序。它具有“记忆”或“状态”的能力。
Outline
- 系统状态
- 存储设备
系统状态
组合逻辑电路若想执行有用的操作序列,显然缺少一个关键功能:对信息的记忆 —— 即能从一个步骤保留信息到下一个步骤。为了实现操作序列,系统需要能够记录并更新“状态”,这个状态必须能够从一步变化到下一步,并影响每一步的计算;如果没有状态信息,第二步及之后的每一步都会只是重复第一步,没有累积效果。
这正是时序电路(sequential circuit)的作用。一种典型的时序电路模型包括两部分:一是能存储有限数量比特的数字存储器,用于表示系统的当前状态;二是组合逻辑块,它根据当前状态和输入,计算系统的输出以及下一状态。数字存储器有两个输入,一个是名为 Step 的控制输入,用来指示电路何时从当前操作步骤进入下一步,另一个是数据输入,它指定“下一状态”的内容。当 Step 被触发时,存储器会加载新的状态信息,并丢弃旧的状态,系统就从原来的状态过渡到了一个新状态。

下面我们将解释如何构建这种数字存储器
存储设备
历史上出现了很多实现数字信息存储的技术,比如机电、化学、音频和光学等方法实现存储器。大致可分为易失性存储器和非易失性存储器。但是,对于像时序电路状态这种短期、小规模的数据存储,我们并不需要复杂的外部存储技术。我们通常会直接用组合逻辑门构造出小型的存储电路,方法是:引入反馈(feedback)环路,从而构建出可以稳定保持两个状态之一(0 或 1)的双稳态电路(bistable circuit)。这听起来很简单 —— 把电路“绕回来”构成环路即可。但实际上,这种看似微小的结构变化,会带来巨大的工程挑战。
双稳态电路
本节,我们将”引导式“地从组合电路构造存储器件。这个构造背后的启示是,通过在组合逻辑电路中引入循环(反馈),可以很容易地创建稳定状态的电路。
考虑通过两个反相器(inverter)首尾相连形成闭环的简单电路。

在逻辑上,这个电路只有两个合法的稳定状态:
- 如果X = 0, 那么 Y = 1,通过反向又让 X= 0,自洽;
- 如果X = 1, 那么 Y = 0,通过反向又让 X= 1
工程挑战:第三个“不稳定状态”。 尽管理论上这两个状态是稳定的,但如果从电压的物理角度分析,就会发现更复杂的问题:将两个反相器看作一个“整体装置”,它的输入输出电压关系(V_IN 和 V_OUT)是一条弯曲的曲线(绿色);而反馈连接引入了一个等式:V_IN = V_OUT,表示为一条红色直线;这两条曲线的交点表示“电压上可能的解”。

有三个交点: 左侧一个稳定点(对应X = 0),与右侧一个稳定点(对应 X = 1);中间还有一个,这个点处于临界态,逻辑值既不是0也不是1。这种不稳定平衡是导致时序电路失败的重要原因之一
D锁存器

尽管我们可以将两个反相器组成的环路视为一个能够存储1位信息的装置,但若不能对其存储内容加以控制,它的实用性便大打折扣。为实现这种控制,我们在类似的反馈结构中使用一个稍微复杂的组合逻辑器件——一个宽容两输入多路选择器(lenient 2-way multiplexor )。该电路具有一个数据输入 D 和一个控制输入 G (Gate)。对该电路的逻辑域分析同样直观简明。 当 G=1 时,D 输入的逻辑值会被选中并输出到 Q;当 G=0 时,从输出 Q 到输入 Q′ 的反馈路径被选中。此时,在逻辑域中再次存在两个稳定解:Q=Q′=0 或 Q=Q′=1。我们设计此结构的意图是:通过输入 G 的不同值切换两种运行模式,如左图所示:

- 当 G=0 时,Q 输出表示已存储的值;
- 当 G=1 时,D 的值通过组合路径传到 Q 输出。
这种装置称为 D 锁存器(D Latch),当 G=0 时充当存储装置,当 G=1 时则表现为一个“透明”的组合电路。设计意图是在 G 从 1 转变为 0 的时刻“锁住”当前 D 的值,从而存入这个值。

下面的时序图显示了锁存器的预期行为:在 G=1 的期间,Q 会在一个传播延迟之后反映 D 的值;若 G 在 D 为某一新值 V₂ 时变为 0,那么锁存器就会存储 V₂,直到 G 变为其他值为止。

可靠的锁存器操作
尽管在 G 从 1→0 的跳变时捕获 D 的值看起来直观简单,但其背后存在微妙且必须谨慎对待的工程问题,此时宽容性就至关重要。如果使用非宽容的多路选择器,当输入发生变化时会导致输出进入未定义状态;一旦 Q 变得无效,Q′ 也会变得无效,从而产生无效性反馈环,即使后续 D 和 G 都变为有效也可能无法恢复。因此,仅仅是输入的短暂扰动,就可能在反馈环中引发失效并丢失已存信息。

而使用宽容多路选择器(其真值表如图所示)则能缓解此问题,在某些情况下允许输入的变化而不污染输出。以下三种情况下,输入可变化而不会污染输出:
- G = 1 且 D = v(v = 0 or 1),且维持有效时间至少为
: 此时Q = v, Q‘的值无关紧要。 - D = Q’ = v, 且维持有效时间至少为
: 此时两个数据输入一致,G的值无关紧要 - G = 0 且 Q‘ = v, 且维持有效时间至少为
,此时选择器选中了Q’, D的值无关紧要
这三种保证对 D 锁存器的可靠性至关重要:第一点允许在G = 1是强制写入新数据;第二点允许在不破坏输出Q的前提下切换G; 第三点确保在G = 0 期间保持Q不变,即使D改变。
锁存器的时间要求:为了确保值 V₂ 被可靠加载到宽容选择器构成的锁存器中(传播延迟为 t_PD),还必须严格控制输入信号的时间:
- 起始条件, 锁存器的当前状态未知,新值V₂被施加到D输入,并使G = 1(允许数据通过)
- 等待
后, Q的输出变为V₂ - 再过
, Q'也变为V₂, 此时Q与Q‘都有效。Q = V₂独立于G,因为此时切换G = 0, 仍保持Q = Q' = V₂ - 再等
,G 变成 0且 Q' = V₂ 被维持了一个传播延迟,因此可以独立于D。至此V₂已经被存入锁存器中。
换言之,为了确保值 V₂ 成功锁存,D 必须在 G 由1→0 转换的前
- 建立时间(
):在 G 变为 0 之前,D 必须已经稳定的时间; - 保持时间(
):在 G 变为 0 之后,D 必须继续保持稳定的时间。 - 转变时间(transition time),发生转变的时间

在本实现中,
<-- Setup --> | <-- Transition --> | <-- Hold -->
-------------------------|--------------------|-------------------------
D = V₂ (保持不变) G 从 1 变为 0 D = V₂ (继续不变)组合逻辑环路

我们可能会想尝试使用锁存器(latch)来为一个时序电路存储一位状态,如右图所示。的确,只要锁存器的控制信号 G = 0,它就能够保持一个“当前状态”位;这个状态位可以用来计算“下一状态”位,并将其送到锁存器的 D 输入端。然而,要把这个“下一状态”位加载进锁存器却是个难题。显然,我们必须将 G 提高为有效的 1(至少要暂时为 1),才能将新值加载进去。但问题来了:G 到底要保持为 1 多久?
我们注意到,在 G = 1 时,电路中会形成一个组合逻辑环路(combinational cycle):组合逻辑计算出一个新状态位,这个位通过锁存器传回组合逻辑,然后组合逻辑又计算出一个更新的新状态位,如此往复。在这个环路中,信号以无法控制的速率传播,我们无法确定什么时候(甚至是否)能得到一个有效的逻辑值。
因此,锁存器很少直接用作数字电路中的存储单元。相反,我们更常将锁存器作为构建 行为更受控的触发器(flip-flop) 的基本组成部分,而后者将作为我们基本的状态存储元件。
边沿触发触发器

锁存器在 G=1 时是“透明”的,即输入 D 立即通过组合逻辑路径传到输出 Q。这种透明性会导致组合逻辑环路(combinational cycle),从而引发振荡或不稳定,无法控制何时存储数据。为了解决这个问题,我们将两个锁存器串联起来构建一个主从触发器(master-slave flip-flop)或者 边沿触发触发器(edge-triggered flip-flop),并交替控制它们的透明状态:
- 主锁存器在
CLK = 0时透明 - 从锁存器在
CLK = 1时透明
这种结构确保了时钟任意时刻只有一个锁存器是透明的,另外一个则在其输出保持存储值。主从触发器的结构图如下。

CLK输入三角形代表时钟设备的时钟输入,这是一类使用时钟输入边缘来制定关键事件时序的顺序设备。我们将使用触发器和组合逻辑来构建时钟设备。

工作原理。假设我们输入一个新的数据 D,并使用一个周期性的方波作为时钟 CLK:
- CLK = 上升沿(0→1)
- 主锁存器变为不透明,D 被锁住。
- 从锁存器变为透明,主锁存器输出被传给从锁存器输出 Q。
- 此时整个 flip-flop “采样”了 D 的值,输出 Q 更新。
- CLK = 1:
- 主锁存器关闭——输出其存储值
- 从锁存器透明。
- CLK = 下降沿(1→0):
- 从锁存器关闭——输出其存储值,Q 输出保持不变。
- 主锁存器重新打开,准备接收下一轮 D。
- CLK = 0:
- 主锁存器是透明的,D 的值会传到主锁存器输出。
- 从锁存器是关闭的,它保持其先前输出值。

如上图所示,我们可以总结出触发器的时序特性。要加载一个新值,要求 D 必须在时钟的上升沿前至少稳定 t_SETUP 时间;上升沿后还需保持稳定 t_HOLD 时间。
我们也用传播延迟CLK 边沿开始,Q 输出会至少在 t_CD 时间内保持先前的值,并且最迟会在 t_PD 时间内呈现新值。
当然,为了确保电路可靠运行,我们必须确保送入触发器的每个锁存器的输入信号满足其建立时间(setup time)和保持时间(hold time)的要求。触发器的整体 setup 和 hold 时间规范,必须能覆盖主锁存器(master latch)的这些时间要求;而这也间接确保了从锁存器(slave latch)的 setup 要求得到满足。
然而,从锁存器(slave)的保持时间(hold time)要求,带来了一个较难控制的约束要满足这个要求,必须确保在 CLK 的下降沿时,主锁存器(master)的输出值(电路中标有星号的节点)在该时刻之后仍然保持有效,至少持续 slave 所需的 hold time 时间。然而,正是在这个时钟下降沿,主锁存器变为透明,这意味着它的输出值可能会在这一刻发生变化。这就带来了一个风险:主锁存器输出过早变化,可能会破坏从锁存器的 hold time 约束。唯一能保证满足这个 hold time 的方法是:确保主锁存器的污染延迟(contamination delay)大于或等于从锁存器的 hold time 要求。也就是说,主锁存器在重新变为透明后,它的输出不会立即变化,而是有足够的延迟,让 slave 来得及锁定这个值。
我们将引入一个新的抽象——记忆组件,用于存储我们希望构建的数字系统的当前状态。记忆组件存储一个或多个位,这些位编码了系统的当前状态。这些位作为数字值可用于记忆组件的输出,如标有“current state”的线所示。
当前状态和当前输入值作为输入进入一个组合逻辑块,该块产生两组输出。一组输出是设备的下一个状态,使用与当前状态相同数量的位编码。另一组输出是作为数字系统输出的信号。组合逻辑的功能规范(可能是真值表,或者是一组布尔方程)指定了下一个状态和系统输出如何与当前状态和当前输入相关联。
记忆组件有两个输入:一个LOAD控制信号,指示何时用下一个状态替换当前状态;一个数据输入,指定下一个状态应该是什么。我们的计划是定期触发LOAD控制,这将产生一个当前状态序列的值。序列中的每个状态都是根据前一个状态和触发LOAD时的输入确定的。
包含组合逻辑和记忆组件的电路称为时序逻辑。记忆组件有特定的容量,以位数来衡量。如果记忆组件存储了K位,那么设备的状态使用这K位存储,最多可以有2^K个可能的状态。
因此,我们需要找出如何构建一个可以定期加载新值的记忆组件。这是本章的主题。我们还需要一种系统化的方法来设计时序逻辑,以实现所需的动作序列。这是下一章的主题。
动态约束
我们在第 5 章介绍数字抽象(Digital Abstraction)时,讨论了如何将由连续变量构成的物理世界嵌入到由 1 和 0 构成的抽象数字领域中。在从连续值到离散值的这个转变中,我们发现了一个不可避免的后果:并非所有的连续电压值都能表示有效的逻辑电平。这就带来了一个设计挑战:我们必须设计电路,使其输出至少在特定时间区间内是有效的。
第 5.3.1 节中的静态约束(Static Discipline)规定了:对于组合逻辑电路,只要输入是有效的,那么在适当的传播延迟之后,输出也将是有效的。
但是,当我们进入时钟控制的时序电路(clocked sequential circuits)*后,这种情况就变得更加复杂了,因为*时间被引入了我们的模型中。导线上可能传递的是一连串的有效值,这些值之间可能夹杂着无效期;因此,我们需要一个额外的工程约束,来可靠地区分信号的有效时间段,并防止无效信号在电路中传播。
我们在基础时钟元件——触发器(flip-flop)上推导出的建立时间(setup time)和保持时间(hold time)约束,就构成了这种额外工程约束的一种典型模型,也正是本课程将采用的模型。
动态约束(Dynamic Discipline)(其时序图如右图所示)要求:时钟器件的输入信号在每一个有效时钟边沿的前后时间窗口内必须保持稳定且有效。这个时间窗口包括:
- 边沿之前的 setup 时间;
- 边沿之后的 hold 时间。
只要输入变化满足这一时序要求,那么输出的有效性就可以得到保证 —— 输出信号将在该时钟边沿之后的某个时间(具体由污染延迟和传播延迟决定)变得有效。需要注意的是,这些延迟是相对于时钟边沿测量的,而不是像组合逻辑中那样相对于输入变化来测量。
通过将触发器与组合逻辑相结合,我们可以构造出任意复杂的时钟控制时序电路。
寄存器

我们常常将多个共享同一个时钟的触发器(flip-flops)组合在一起,如左图所示,构成一个 N 位寄存器(N-bit register)。这是一个基本的时钟控制存储器件,能够存储一个多位的数值
在这样的寄存器中,所有的位都会在同一个有效的时钟边沿被同时加载,并且对于这一边沿,每一位都必须满足相同的 setup time和 hold time 要求。
、
寄存器的各个位的输出也会同时出现,不过这同样要遵守组成该寄存器的触发器的 污染延迟(contamination delay) 和 传播延迟(propagation delay) 规范。
为时钟设备添加逻辑

构建复杂的时序系统有多种方法。上述图中的寄存器强加了一种动态约束,即必须满足它的建立时间(setup time)和保持时间(hold time)要求,分别记为 t_SETUP 和 t_HOLD。假设组合逻辑的传播延迟为 t_PD/LOGIC,污染延迟为 t_CD/LOGIC,寄存器的传播延迟和污染延迟分别为 t_PD/REG 和 t_CD/REG,那么动态约束要求满足以下几点:
- 为了确保新状态数据能满足寄存器的建立时间要求,必须有:
t_PD/REG + t_PD/LOGIC + t_SETUP <时钟周期。 - 为了确保寄存器的保持时间要求被满足,必须有:
t_CD/REG + t_CD/LOGIC ≥ t_HOLD。 - 为了确保输入数据的建立时间要求,输入数据的建立时间应至少为:
t_PD/LOGIC + t_SETUP, 以确保输入的变化能及时传播到寄存器并满足其建立时间要求。 - 为了确保输入数据的保持时间要求,输入数据的保持时间应至少为:
t_HOLD − t_CD/LOGIC, 以确保输入的变化不会过早导致寄存器失效。
在构建复杂系统时,将状态信息分散到各个子系统中通常更为方便,这样可以通过组合多个时序组件来构建系统。然而,这种分布式状态的做法会导致建立时间和保持时间要求数量急剧增加,因此有必要引入一种额外的工程约束来进行有序的系统构建。
尽管存在多种选择,但最简单、最常用的方法是第 8.3.3 节中介绍的单时钟同步约束。这种方法在工程实践中被广泛采用,用于管理复杂时序系统中的同步问题。
基于电容器的存储设备

我们一直将位表示为电压,因此可以考虑使用电容器来存储特定的电压。电容器是一种被动的两端设备。两个端子连接在平行的导电板上,之间有绝缘体隔开。通过向电容器的一个板上添加电荷Q,可以在两个板之间产生电压差V。电荷Q和电压V之间通过电容C的关系来表示:Q = CV。
当我们通过将一个板端子连接到较高电压来向电容器充电时,这称为“给电容器充电”。当我们通过将板端子连接到较低电压来去除电荷时,这称为“放电电容器”。
因此,基于电容器的记忆设备可能的工作方式如下:电容器的一个端子连接到某个稳定的参考电压。我们将使用一个NFET开关将电容器的另一个板连接到一个称为bit line的导线上。NFET开关的栅极连接到一个称为word line的导线上。
要向记忆设备写入一位信息,将bit line驱动到所需的电压(即数字0或数字1)。然后将word line设置为高电平,打开NFET开关。电容器将充电或放电,直到其电压与bit line相同。此时,将word line设置为低电平,关闭NFET开关,并隔离电容器板上的电荷。在理想情况下,电容器板上的电荷会无限期地保持。
稍后,要访问存储的信息,首先将bit line充电到一些中间电压。然后将word line设置为高电平,打开NFET开关,将bit line上的电荷连接到电容器上的电荷。bit line和电容器之间的电荷共享将对bit line上的电荷产生一些小的影响,从而改变其电压。如果电容器存储的是数字1,因此处于较高电压,电荷将从电容器流向bit line,提高bit line的电压。如果电容器存储的是数字0,并且电压较低,电荷将从bit line流向电容器,降低bit line的电压。bit line电压的变化取决于bit line电容与存储电容器电容C之间的比率,但通常非常小。一个非常敏感的放大器,称为感应放大器,用于检测这种小的变化,并产生从存储单元读取的合法数字电压。
嗯!读写操作需要一整套操作序列,以及精心设计的模拟电子设备。好消息是,单个存储电容器非常小——在现代集成电路中,我们可以在相对廉价的芯片上容纳数十亿比特的存储单元,简称DRAM(动态随机存取存储器)。DRAM的单位存储成本非常低。
坏消息是,用于读写操作的复杂操作序列需要一段时间,因此访问时间相对较慢。而且,我们必须注意在外部电气噪声的影响下仔细维护存储电容器上的电荷。真正的坏消息是,NFET开关并非完美,即使在正式关闭时也会有微小的漏电流。随着时间的推移,这种漏电流可能会对存储电荷产生明显影响,因此我们必须定期刷新存储器,读取并重新写入存储的值,以防止漏电损坏存储信息。在当前技术中,这大约需要每10毫秒进行一次刷新。
嗯。也许我们可以通过设计一个利用反馈提供持续刷新存储信息的电路来避开电容存储的缺点...
非CMOS内存
前面提到的基于 CMOS 的触发器和寄存器非常适合临时存储大小适中的数字值(如状态信息),而其他技术则广泛用于满足更大规模的存储需求。其中某些技术(如用于计算机主存储器的动态 RAM)是易失性的,即所含信息只有在存储器通电和运行时才会持续存在。磁盘或光盘等其他技术则是非易失性的,适用于长期和离线存储。
大多数现代大容量存储方法都比以下章节中介绍的方法要复杂得多。通常,现代存储器将比特存储密度推向极限,并依靠纠错来确保可靠存储。
RAM 阵列
术语RAM是一种存储器架构,用来存储数据,他的特点是随机访问(你可以用地址直接访问任意一个数据存储位置,访问时间是一样的)。RAM 结构可以理解成一个 存储单元数组,有
其代表模型如下图,对于指定参数N和k,它们能够存储

读写机制如下。 RAM的接口有两个部分:
写端口:包含一个k位地址(指定要写入的位置)、一个N位的是数据(要写入的数据);一个写使能信号;如果时钟信号到来时,写使能有效,数据就会写入对应的地址。
读端口 :包含一个k位地址(指定要读取的位置)、读使能信号;也是在时钟信号到来时触发。
RAM 通常实现为 二维数组,每个存储单元存储一位数据。这些单元可以是以下两种实现方式之一:SRAM(静态,用反馈保持)或 DRAM(动态,用电容保持)。
SRAM
静态 RAM(SRAM)正是“用反馈避开电容存储缺点”这一思路的产物。每个单元用一对交叉耦合的反相器(即前面的双稳态电路)来保持 1 位,只要供电就一直保持,无需刷新。典型实现是 6 晶体管(6T)单元:2 个反相器(共 4 个 MOSFET)+ 2 个由 word line 控制的访问 NFET,把内部节点连到一对(互补的)bit line 上。
| SRAM | DRAM | |
|---|---|---|
| 存储机制 | 交叉耦合反相器(反馈) | 电容电荷 |
| 单元面积 | 大(约 6 个晶体管) | 小(1 晶体管 + 1 电容) |
| 速度 | 快 | 慢(读破坏 + 充放电) |
| 刷新 | 不需要 | 需要(约每 10 ms) |
| 读破坏 | 否 | 是(读后须回写) |
| 典型用途 | 寄存器堆、Cache | 主存 |
权衡很清楚:SRAM 快但贵(面积大),DRAM 密度高、便宜但慢且需刷新。因此处理器里靠近核心的小而快的存储(寄存器、Cache)用 SRAM,大容量主存用 DRAM——这正是存储层次(见 lec13)的物理基础。
DRAM

对大型、廉价计算机主存储器的需求推动了dynamic RAM 或 DRAM技术的发展,这种技术以复杂的周边电路为代价,最大限度地缩小了每个存储单元的尺寸。
DRAM 采用上图所示的结构,以电容器上电荷的形式在每个单元中存储一个信息位。电容器的底端连接到固定的参考电压(如接地),而另一个端子则处于 “浮动”(断开)状态,这样就不会有电流干扰存储的电荷。单个 NFET 能够将电容器的浮动端瞬时连接到垂直bit line上;这种瞬时连接既可用于设置单元存储的值,也可用于读取存储的值。图中的单元也是二维阵列中排列的众多单元之一,垂直排列的单元共享一条bit line,水平排列的单元共享word line。
要在单元中存储一个值,需要将相应的bit line预充电到相应的电压,并短暂升高word line上的电压,使 NFET 导通并对电容器充电。一旦 NFET 恢复到通常的非导通状态,电容器上的电荷将不受bit line电压变化的影响。
为了读取存储在单元中的值,word line会再次断开,这样 NFET 就会短暂地将bit line连接到电容器上。在这种情况下,与bit line相连的灵敏感应放大器会检测到bit line连接对其电压的影响,并确定存储在电容器上的电荷是 0 还是 1。读取操作是破坏性的(因为它会导致存储的电荷耗散),因此每次读取操作之后都要立即对同一单元进行写入操作,以恢复存储的信息。
由于每个动态 RAM 单元中存储的电荷会有一些泄漏,因此 DRAM 必须定期刷新。这就需要读取每个单元并重写它们的值,这也是该技术名称中 “动态 ”一词的由来
总结
我们的数字抽象扩展到包括具有内部状态的系统,增加了几个关键概念:由于设计具有来自基本电路元件的状态的基本元件既复杂又容易出错,因此我们选择精心设计一小部分存储器件,并将复杂的顺序系统的设计限制在这些存储器件和组合器件的混合范围内,按照精心规定的规则进行。我们的存储器件包括大型动态 RAM阵列和磁/光存储器,以及使用精心设计的反馈回路和组合器件的触发器