---
schema_version: "library-reader-v1"
source_type: "original_book"
title: "编码 隐匿在计算机软硬件背后的语言"
author: null
edition: null
publisher: null
year: null
isbn: "9787121181184"
library_document_id: "38270854-596f-4a26-8183-db8c968c6020"
source_sha256: "249786274d83909f0bddc34d77f81ed8f0b14d1eac8843c772a37a3ecbfe2cfc"
pdf_physical_page_count: 438
pdf_physical_page_index_base: 0
range_start: 190
range_count: 10
html_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020?start=190&limit=10"
markdown_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=190&limit=10"
previous_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=180&limit=10"
next_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=200&limit=10"
---

# 编码 隐匿在计算机软硬件背后的语言

> 页码规则：PDF_PHYSICAL_PAGE_INDEX 是从 0 开始的权威文件物理页索引；PRINTED_PAGE 是页面中识别出的印刷页码，可能为空，二者不得混用。

## PDF_PHYSICAL_PAGE_INDEX=190 | PRINTED_PAGE=174

通常(先不考虑上一章讲到的减法器)，8个A输入端和8个B输入端连接到开关上，CI（进位输入）接地，而8个S（计算和）输出以及CO（进位输出）端连接到灯泡上。

经过改进，8位加法器的8个S输出端既与灯泡相连，又连接到8位锁存器的数据(D)输入端。标记为“保存”（Save）的开关是锁存器的时钟输入，用来存放加法器的运算结果。

标识为2-1选择器的方块是让你用一个开关来选择加法器的 B端输入是取自第2排开关还是取自锁存器的Q端输出。当开关闭合时，就选择了用8位锁存器的输出作为B端输入。2-1选择器使用了8个如下所示的电路。

编码隐匿在计算机软硬件背后的语言

174

## PDF_PHYSICAL_PAGE_INDEX=191 | PRINTED_PAGE=175

如果选择端（Select）输入是1，那么或门的输出和B端的输入就是一致的。这是因为上面与门的输出和B端输入是一样的，而下面与门的输出是 $\scriptstyle \mathbf { 0 } _ { \circ }$ 类似的，如果选择端的输入是0，那么或门的输出则和A端输入一致。总结起来如下表所示。

改进后的加法器中包含了8个这样的1位选择器。所有的选择端输入信号都是连在一起的。

改进后的加法器不能很好地处理进位输出（CO）信号。如果两个数的相加使得进位输出信号为1，那么当下个数被加进来的时候，这个信号将被忽略掉。一个可能的解决方案是将加法器、锁存器、选择器均设置为16位宽，或者至少应该比你可能遇到的最大的和的位数多一位。这个问题留到第17章具体讲述。

对于加法器来说，一个更好的改进方法是去掉一整排8个开关。但是首先要对D触发器做一些修改，为它加一个或门和一个称为清零（Clear）的输入信号。清零信号通常为0，但当它为1时，Q输出为0，如下图所示。

无论其他信号是什么，清零信号总是强制使Q输出为0，以达到使触发器清零的目的。

14 反馈与触发器

175

## PDF_PHYSICAL_PAGE_INDEX=192 | PRINTED_PAGE=176

也许你还不明白为什么要设置这个信号，为什么不能通过把数据输入端置0和把时钟输入端置1 来使触发器清零呢？这也许是因为我们无法精确控制数据端的输入信息的缘故。我们可能有一组8个锁存器，它们连着8位加法器的输出端，如下图所示。

注意，标识为“相加”（Add）的开关现在控制着锁存器的时钟输入。

你可能会发现这个加法器比前面的那个好用，特别是当你需要加上一长串数字时。首先按下清零开关，这个操作会使锁存器的输出为0，并且熄灭了所有的灯泡，同时使8位加法器的第2行输入全为 $0 _ { \circ }$ 然后，通过开关输入第一个加数，并且闭合“相加”开关，这个加数的值就反映在灯泡上。再输入第二个加数并再次闭合“相加”开关。由开关输入的8位操作数加到前面的结果上，所得的和体现到灯泡上。反复如此操作，可以连续进行很多次加运算。

前面提到过，我们所设计的D触发器是电平触发的，也就是说为了使数据端的值保存在锁存器中，必须把时钟端的输入从0变为1（即高电平）。但是，当时钟端输入为1时，数据端的输入是可以改变的，这时数据端输入的任何改变都会反映在 $\mathbf { Q }$ 和 $\overline { { \mathbf { Q } } }$ 的输出值中。

对某些应用而言，电平触发时钟输入已经足够用了；但是对另外一些应用来说，边沿触发（edge-triggered)时钟输入则更有效。对于边沿触发器而言，只有当时钟从0跳变到1时，才会引起输出的改变。它们的区别在于，在电平触发器中，当时钟输入为0时，数据端输入的任何改变都不会影响输出；而在边沿触发器中，当时钟输入为1时，数据端输入的改变也不会影响输出。只有在时钟输入从0变到1的瞬间，数据端的输入才会影响边沿触发器的输出。

编码—隐匿在计算机软硬件背后的语言

176

## PDF_PHYSICAL_PAGE_INDEX=193 | PRINTED_PAGE=177

边沿触发的D型触发器是由两级R-S触发器按如下方式连接而成的。

这里，时钟端的输入既控制着第一级 R-S触发器，也控制着第二级，但是要注意的是时钟信号在第一级中进行了取反操作，这意味着除了当时钟信号为0时保存数据外，第一级R-S 触发器和D型触发器工作原理完全一致。第二级R-S 触发器的输出是第一级的输入，当时钟信号为1时，它们都被保存。一言概之，只有当时钟信号由0变为1时，数据端输入才被保存下来。

进一步分析，下图为一个处于非工作状态的触发器，其数据输入和时钟输入均为0，且Q输出也为0。

14 反馈与触发器

177

## PDF_PHYSICAL_PAGE_INDEX=194 | PRINTED_PAGE=178

这改变了第一级触发器的状态，因为时钟输入取反变为 $1 _ { \circ }$ 但第二级触发器状态保持不变，因为时钟输入仍然为 $0 _ { \circ }$ 现在把时钟输入变为1。

这就引起了第二级触发器输出的改变，使Q输出变为 $1 _ { \mathrm { ~ c ~ } }$ 不同点在于，无论数据端输入发生何种变化（比方说变为0）都不会影响Q的输出。

边沿触发的D型触发器的功能表需要一个新的符号来表示从0到1的瞬时变化，即用一个向上的箭头（↑）表示，如下表所示。

编码—隐匿在计算机软硬件背后的语言

178

## PDF_PHYSICAL_PAGE_INDEX=195 | PRINTED_PAGE=179

表中箭头表示当时钟端由0变为1时（称为时钟信号的“正跳变”，“负跳变”是指从1变为0)，Q端输出与数据端输入是相同的。触发器的符号如下图所示。

图中的小三角符号表示触发器是边沿触发的。

下面展示的是一个使用边沿D型触发器的电路，这个电路是不能用电平触发形式复制出来的。先回忆一下本章开始构造的振荡器，其输出在0和1之间变化。

把振荡器的输出与边沿触发的D型触发器的时钟端输入连接，同时把 $\overline { { \mathbf { Q } } }$ 端输出连接到本身的D输入端。

这个触发器的输出同时又是它自己的输入。反馈紧接着反馈！（实际上，这种构造可能是有问题的，振荡器是由状态来回迅速改变的继电器构成的，其输出与构成触发器的继电器相连，而这些其他的继电器不一定能跟得上振荡器的速度。为了避免这些问题，这里假设振荡器中的继电器比电路中其他地方的继电器速度要慢得多)

仔细看一看下面的功能表就可以明白在电路中发生的情况了，电路启动时，假设时钟输入为0且Q输出也为0，则 $\overline { { \mathbf { Q } } }$ 端输出为1，而 $\mathbf { \widehat { Q } }$ 是和D端输入相连的。

14 反馈与触发器

179

## PDF_PHYSICAL_PAGE_INDEX=196 | PRINTED_PAGE=180

当时钟输入从0变为1时，Q输出与D输入相同。

但是由于 $\overline { { \mathbf { Q } } }$ 的输出变为0，因此D输入也变为 $0 _ { \circ }$ 现在时钟输入为1，如下表所示。

当时钟输入变回0时，不会影响到输出，如下表所示。

现在时钟端输入又变为1。由于D输入为0，那么Q输出为0且 $\overline { { \mathbf { Q } } }$ 输出为1。

编码隐匿在计算机软硬件背后的语言

180

## PDF_PHYSICAL_PAGE_INDEX=197 | PRINTED_PAGE=181

所以D输入也变为1，如下表所示。

以上发生的现象可以简单总结为：每当时钟输入由0变为1时，Q端输出就发生变化，或者从0到1，或者由1到 $0 _ { \circ }$ 下面的时序图可以更加清楚地说明这个问题。

当时钟端Clk输入由0变为1时，D的值（与 $\overline { { \mathbf { Q } } }$ 的值相同）被输出到Q端。当下一次Clk信号由0变为1时，D和 $\overline { { \mathbf { Q } } }$ 的值同样会改变。

如果这个振荡器的频率是20Hz(即20个周期的时间为1s)，那么Q的输出频率是它的一半，即 10Hz，由于这个原因，这种电路称为分频器（frequency divider)，它的 $\overline { { \mathbf { Q } } }$ 输出反馈到触发器的数据端输入 $\mathbf { D } _ { \mathrm { c } }$

当然，分频器的输出可以作为另一个分频器的Clk输入，并再一次进行分频。下面是三个分频器连接在一起的示意图。

14 反馈与触发器

181

## PDF_PHYSICAL_PAGE_INDEX=198 | PRINTED_PAGE=182

上图顶部的4个信号变化规律如下图所示。

$$
\arcsin \angle B D C = \arcsin \angle B D C
$$

$$
a _ { 1 } \sqcup \square \square \square _ { 2 } \square \square \square _ { 3 } \square \square _ { 2 } \square _ { 3 }
$$

$$
q _ { 2 } \sqcup \square \square \square \square ^ { - 1 }
$$

$$
\mathrm { \Delta _ { Q _ { 3 } } } \bigcup \qquad \longmapsto
$$

这里只给出了这幅图的一部分，因为这个电路会重复上述过程周而复始地变化下去。在这幅图中，你有没有发现眼熟的东西呢？

提示一下，把这些信号标上0和1。

$$
\operatorname { \mathbb { C } } \mathbb { K } \ \left\lfloor \ { \boldsymbol { \theta } } \ \right\rfloor \ { \boldsymbol { \updownarrow } } \ \left\lfloor \ { \boldsymbol { \theta } } \ \right\rfloor \ { \boldsymbol { \updownarrow } } \ \left\lfloor \ { \boldsymbol { \theta } } \ \right\rfloor \ { \boldsymbol { \updownarrow } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor \ { \boldsymbol { \updownarrow } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor \ { \boldsymbol { \updownarrow } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor \ { \boldsymbol { \updownarrow } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor ^ { \ { \boldsymbol { \updownarrow } } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor ^ { \ { \boldsymbol { \updownarrow } } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor ^ { \ { \boldsymbol { \updownarrow } } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor ^ { \ { \boldsymbol { \updownarrow } } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor ^ { \ { \boldsymbol { \updownarrow } } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor ^ { \ { \boldsymbol { \updownarrow } } } \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor ^ { \ { \boldsymbol { \updownarrow } } } \ \left\lfloor \ { \boldsymbol { \theta } } \right\rfloor ^ { \ { \boldsymbol { \updownarrow } } } \ \left\lfloor { \boldsymbol { \theta } } \right\rfloor ^ { { \boldsymbol { \updownarrow } } } \ \left\lfloor { \boldsymbol { \theta } } \right\rfloor ^ { { \boldsymbol { \updownarrow } } } \left\lfloor { \boldsymbol { \theta } } \right\rfloor ^ { { \boldsymbol { \updownarrow } } } \ \left\lfloor { \boldsymbol { \theta } } \right\rfloor ^ { { \boldsymbol { \updownarrow } } } \left\lfloor { \boldsymbol { \theta } } \right\rfloor ^ { { \boldsymbol { \updownarrow } } } \left\lfloor { \boldsymbol { \theta } } \right\rfloor ^ { { \boldsymbol { \updownarrow } } } \left\lfloor { \boldsymbol { \theta } } \right\rfloor ^ { { \boldsymbol { \updownarrow } } }
$$

$$
\operatorname { Q } _ { 1 } ~ \left\lfloor \theta ~ \theta \sqrt { 1 ~ 1 ~ 1 } ~ \right\rfloor ~ \theta ~ \theta \sqrt { 1 ~ 1 ~ 1 } ~ \left\lfloor ~ \theta ~ \theta \sqrt { 1 ~ 1 ~ 1 } ~ \right\rfloor ~ \theta ~ \theta \sqrt { 1 ~ 1 ~ 1 } ~ \left\lfloor ~ \theta ~ \theta \sqrt { 1 ~ 1 ~ 1 } ~ \right\rfloor ,
$$

$$
\begin{array} { r } { \mathrm { ~ Q _ { 2 } ~ } \left\lfloor \begin{array} { c c c c c } { 0 } & { \theta } & { \theta } & { \theta } \end{array} \right\rfloor \overline { { 1 \quad 1 \quad 1 \quad 1 \quad 1 } } \left\lfloor \begin{array} { c c c c c } { 0 } & { \theta } & { \theta } & { \theta } \end{array} \right\rfloor \overline { { 1 \quad 1 \quad 1 \quad 1 } } \left\lfloor \begin{array} { c c c c c } \end{array} \right\rfloor } \end{array}
$$

$$
\begin{array}{c} \begin{array} { r } { \mathrm { ~ Q _ 3 ~ } \lfloor \begin{array} { c c c c c c c c c c c c } { 0 } & { \theta } & { 0 } & { 0 } & { 0 } & { 0 } & { \theta } & { 0 } & { \theta } \end{array} \rfloor \mathrm { ~ 1 ~ } } & { \mathrm { ~ 1 ~ } } & { \mathrm { ~ 1 ~ } } & { \mathrm { ~ 1 ~ } } & { \mathrm { ~ 1 ~ } } & { \mathrm { ~ 1 ~ } } \end{array} \rceil  \end{array}
$$

现在看出来了么？试着把这个图顺时针旋转 $9 0 °$ ，然后读一读每一行的4位数字，它们分别对应了十进制中的0\~15中的一个数。

编码隐匿在计算机软硬件背后的语言

182

## PDF_PHYSICAL_PAGE_INDEX=199 | PRINTED_PAGE=183

可以看出，这个电路不仅仅具备了一个计数功能。当然，如果在这个电路中添加更多的触发器，其计数范围就会更大。在第8章中提到一个顺序递增的二进制序列，每一列数字在0和1之间的变化频率是其右边那一列数字变化频率的一半，这个计数器就是模仿了这一点。在每一次时钟信号的正跳变时，计数器的输出是增加的，即递增1。

把8个触发器连接在一起，然后放入一个盒子中，构成了一个8位计数器。

这个计数器称为 $^ { * } { } 8$ 位行波计数器”，因为每一个触发器的输出都是下一个触发器的时钟输入。变化是在触发器中---级一级地顺序传递的，最后一级触发器的变化必定会有一些延迟，更先进的计数器是“并行（同步）计数器”，这种计数器的所有输出是在同一时刻改变的。

在计数器中输出端用 ${ \bf Q } _ { 0 } \sim { \bf Q } _ { 7 }$ 标记，在最右边的 $\mathbf { Q } _ { 0 }$ 是第一个触发器的输出。如果将灯泡连到这些输出端上，就可以将8位数字读出来。

这样一个计数器的时序图可以将8个输出分别表示出来，也可以将它们作为整体一起表示出来，如下图所示。

14 反馈与触发器

183

下一段：[继续读取](https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=200&limit=10)
