1 前言
本文是基于《编码》、《穿越计算机的迷雾》两部著作进行读后整理的记录性博客。对书中较为重要的内容进行归纳整理进行二次创作,略去了繁琐的讲述细节,力求简明扼要。
编码:一种由若干符号和规则组成的系统,用来向计算机表述指令。
2 正文
2.1 存储器
日常生活中,我们习惯于将可能用到的事物先存起来,在需要时将他们取出。从技术角度来讲,这个过程称为先存储后访问。存储器的职责和作用就在于此,它负责保障这两个过程之间信息完好无损。
在前面的内容中,我们讨论过一个触发器可以对 1 位信息进行存储,这样的存储能力要存储一大堆的信息还远远不够。但其实知道了如何存储 1 位信息,很容易就可以想象出如何存储 2 位、3 位或更多位信息。
在之前的讨论中,我们利用 D 型触发器实现了对 1 比特信息的存储,并介绍了触发器可以由两种不同特性的电路来实现(电平、边沿触发)。这里为例更加清楚地进行表述,我们给输入和输出端重新命名,使其名称和功能相符,如下图所示。
从结构上来讲,这套电路与先前所学到的是同一种触发器,只是命名的方式不尽相同,现在 Q 输出端被称为数据输出端(Data Out),时钟输入端命名为写操作端(Write)。相应的,我们也可以利用下图来简化表示上述结构:
我们可以把多个 1 位锁存器(D 触发器)组织成为多位锁存器,所要做的就是把写操作端的信号连接到系统中,就像下面这样。
图中显示的 8 位锁存器其输入和输出端各有 8 个。另外还包括一个写操作端,在非工作状态下一般为 0。如果要把一个 8 位二进制数存储在锁存器中,首先要把写操作端置 1,然后置 0。我们同样可以把这个锁存器以框图的形式表现出来,就像下面这样。
为了和先前提到的 1 位锁存器保持一致,我们将它可以画成下面这种形式。
利用上述结构,我们可以存储一个 8 位二进制数,但如果我们想在这种锁存器中存储 8 个单独的比特,而不是存储 1 个 8 位二进制数呢?我们只想用一个数据输入和输出信号端,而且希望锁存器能将输入信号数据分 8 次独立存储。
也即我们希望锁存器的作用并不只仅仅将单独的一个 8 位二进制数作为整体进行存储,我们希望锁存器同时能够针对传入的 8 比特位的数据进行单个比特位进行存储。同时简化输入和输出端,不再使用多个数据的输出和输出。8 位锁存器对应 8 个 1 位锁存器,因此针对输入和输出端的优化需要围绕这几个锁存器进行优化。
先不去考虑数据如何存储在这些锁存器中,把重点放在如何用一个灯泡来确定单个 1 位锁存器的数据输出信号。最简单的方法就是把这个灯泡依次连接到每个锁存器上,分若干次来测试各个锁存器的输出,但是我们要追求更加自动化的方法。用开关来选择想要检查的锁存器是一个好的办法。
究竟需要多少个开关才能解决问题呢?我们可以把这个过程进一步抽象,问题变成了怎么样从 8 个物体中选出一个我们想要的,我们需要 3 个开关。这是因为通过 3 个开关连通与闭合的排列组合,总共可表示出 8 个不同的值:000、001、010、011、100、101、110 和 111。
现在我们手头上已有 8 个 1 位锁存器、3 个开关、1 个灯泡,此外在开关和灯泡之间还有另外一种装置,如下图所示。
这个 “额外装置” 就是图中的神秘盒子,顶部带有 8 个输入端,左侧也带有 3 个输入端。通过三个开关的闭合和断开,对顶部的输入进行 8 选 1 操作,输出结果被传递到其底部连接的灯泡,使其发光。
这个装置和我们之前介绍的 2-1 选择器类似,我们这里需要的正是 8-1 选择器。
8-1 选择器有 8 个数据输入端(在其顶部),以及 3 个选择输入端(在其左侧)。选择输入端的功能就是选择一个输入端数据,然后使其在输出端输出。根据下列所示的真值表,我们可以根据选择端的输入输出相应的锁存器的值。
[了解] 8-1 选择器主要组成部件为:三个反向器、八个 4 端口输入与门、一个 8 端口输入或门,系统的组织结构如下图所示。
这个电路看上去线路密布,要理解它是如何工作的,最好方式就是一起来看一个例子。假设 S2 初始化为 1,S1 初始化为 0,S0 初始化为 1。从顶部开始的第 6 个与门的输入由 S0、S1反、S2 组成,初始状态下它们全为 1。其余与门的这三项输入数据都与第 6 个与门不尽相同,这使得其余与门输出全部为 0。若 D5 变为 0 意味着第 6 个与门输出为 0;反之第 6 个与门输出则为 1。对最右边的或门也可以按照同样的方式理解。我们可以总结出下面这个结论:若选择端为 101,则数据输出端与 D5 的输出保持一致。
将 8-1 选择器加入电路中,下面是电路的结构图:
输入端包括了数据输入信号及写操作信号。可以把所有数据输入信号在锁存器的输入端连接在一起。但 8 个写入信号是不可以连在一起的,因为我们很可能要向每个锁存器依次写入数据。除此之外还需要一个独立的写入信号,它能被路由到任意(且唯一)的锁存器上,系统的结构可用下图表示。
和前面类似,我们需要设计一个设备以满足我们的需求。这里我们采用的是 3-8 译码器,和前面的 8-1 选择器功能相似,但它的作用正好相反。忽略其名称,只需知道它是一类具备选择功能的设备,能够用来优化我们的数据输入,针对输入选择对应的锁存器。
3-8 译码器的输出端口共有 8 个。在任何时刻,译码器只会有一个锁存器的输出为 1,其余均为 0。每一个输出端的结果都是由 S0、S1、S2 这三个信号的排列组合决定的。而数据的输出和输入一致,如下图所示。
我想再次强调一遍:注意从上往下数的第 6 个与门,它的输入包括 S0、S1反、S2。没有任何一个与门具有和它相同的三个输入。在这种情况下,如果选择输入端为 101,则除了 O5 要根据情况进行判定外,其余与门输出都为 0。这个时候,若数据端输入为 0,则 O5 随之输出为 0;相应的,若数据端输入为 1,则 O5 输出为 1。译码器的逻辑表可以如下表所示。
对比上述 8-1 选择器的输入输出表,我们不难发现三个开关输入相同时,对应着的操作位是一致的。例如,S2=0、S1=0、S0=0 的输入状态下,对应着锁存器的输入和输出端的位是一致的,都是对应着第一位。
将 8 个锁存器加入到电路就形成了完整的系统。
值得注意的是,译码器和选择器具有相同的选择信号,在上图中这三个信号一起被称为地址端口(Address)。地址的作用就像我们平时使用的邮箱号,长度为三位的地址决定了 8 个锁存器中的哪一个将被引用。在 3-8 译码器的输入端,地址起到了决定哪些锁存器可以被写操作端的信号触发来保存数据的作用。在输出端(图的下半部分),8-1 选择器通过地址来选择 8 个锁存器中的一个,最后将其输出。
在上述电路中,我们分别利用 3-8 译码器和 8-1 选择器处理了数据端和输出端。它们的共同作用是根据地址端口的输入选择相应的比特位后续我们可以执行存入数据以及取出数据的操作。而我们的触发器都是之前已经介绍过的存储单个比特信息的锁存器,这样的话,我们就实现了通过地址端口对单个比特位的读写操作。
针对上述具体介绍不感兴趣可以直接略去,只要知道相应设备的作用即可。
这种配置下的锁存器在有的资料中也被称为读/写存储器(read/write memory),但更普遍的叫法是随机访问存储器(Random Access Memory),或RAM。可以认为我们讨论的这种存储器是可存储 8 个独立比特的 RAM,它的简化结构图如下所示。
上图所示的电路之所以能够被称为存储器是因为它可以保存信息。而能够被称为读/写存储器是因为它不仅可以在每个锁存器中存储新的数据(写数据),而且我们还可以检查每个锁存器都保存了什么数据(读数据)。之所以可以被称为随机访问存储器,是因为读写操作很自由,我们只需要改变地址及相关的输入,就可以从 8 个锁存器中读出或写入需要的数据。
一些其他类型的存储器(顺序存储器)必须顺序读取——这种存储器在使用时有一定的限制,如果想要读取地址为 101 的数据,不得不先把地址为 100 的数据读取出来。
将 RAM 进行特殊的配置可形成 RAM 阵列(Array),我们所讨论的这种 RAM 阵列以 8×1(读做 8 乘 1)的方式组织起来。阵列以 1 比特作为存储单位,共存储 8 个单位的数据。所以这个 RAM 阵列中能存储的位数等于 8 与 1 的乘积。
RAM 阵列的组合形式多种多样。比如我们可以通过共享地址的方式可以把两个 8×1 的 RAM 阵列连接起来,如下图所示。
我们把这两个 8×1 的 RAM 阵列的地址和输出都分别看成一个整体,这样就得到了一个 8×2 的 RAM 阵列,如下图所示。
这个 RAM 阵列可存储的二进制数依然是 8 个,但每个数的位宽为 2 位。
分析上述电路结构,我们可以发现同一个地址对应着两个 8×1 RAM,因此我们针对单个地址操作时,相当于同时操作两个比特位。而两个 RAM 都有自己的数据输入,因此可以存入不同的数据。
我们还可以把两个 8×1 的 RAM 阵列看做是两个锁存器,使用一个 2-1 选择器和一个 1-2 译码器就可以把它们按照单个锁存器连接方式进行集成,下面给出了这种方案的电路图(和上面介绍的电路类似,这里不展开解释)。
“选择” 端之所以连接到译码器和选择器,主要作用是在两个 8×1 RAM 阵列中选择一个,本质上它扮演了第 4 根地址线的角色。因此这种结构实质上是一种 16×1 的 RAM 阵列,如下图所示。
上图所示的 RAM 阵列存储容量为 16 个单位,每个单位占 1 位。
RAM 阵列的存储容量与其地址输入端的数量有直接的联系。在没有地址输入端的情况下(只有 1 位锁存器和 8 位锁存器的情况),只能存储 1 个单位的数据;当存在 1 个地址输入端时,可以存储 2 个单位的数据;有两个地址输入端时,可以存储 4 个单位的数据;有 3 个地址输入端时,可以存储 8 个单位的数据;有 4 个地址输入端时,可以存储 16 个单位的数据。我们可以把它们之间的关系归纳成如下等式:
基于上述介绍,我们可以搭建更大规模的 RAM 阵列,如下图所示。这个 RAM 阵列可以存储 8192 个比特的信息。
字节
在之间内容的讲述中我们不难发现在构建各类设备时,我们的数据路径都是以 8 个比特流为一组。至于为什么是 8 位,主要是原始加法机的位宽是 8 位。在这里我们介绍另一个概念:8 比特代表一个字节(byte)。
字节这个词由 IBM 公司提出。最早的拼写方式是 bite,但为了避免与 bit 混淆用 y 代替了 i。曾几何时,字节仅表示某一数据路径上的位数,直到 20 世纪 60 年代中叶,在 IBM 的 360 系统的发展下(一种大规模复杂的商用计算机),字节这个词逐渐开始用来表示一组 8 比特数据。
结合字节的概念,上述的 RAM 阵列的存储容量为 1024 个字节。1024 字节通常简称为 1 千字节(kilobyte),但是这种称呼很容易和其他十进制的转换混淆。而且 1000 和 1024 值相差不大,因此,1 KB = 1024 B(字节)常被用作 1 KB = 1000 B。在日常购买硬盘时标注的 64 GB,实际上的真实容量为:
而在电脑中 64 GB 的实际容量应该为:
关于存储器有一个问题尤其值得我们注意,而且需要特别注意。在前面的文章中,我们曾介绍过逻辑门的概念及原理,但是没有画出组成逻辑门的单个继电器的结构图。特别是,当时没有指明每个继电器都与某个电源连接在一起。只要继电器连通,电流就会流过电磁线圈并产生磁场,继而吸下金属片。
一个装满字节数据的 RAM 阵列,如果断掉电源,会发生什么事情呢?首先所有的电磁铁都将因为没有电流而失去磁性,随着 “梆” 的一声,金属片将弹回原位,所有继电器将还原到未触发状态。RAM 中存储的数据也将丢失。正因为如此,随机访问存储器也被称为易失性(volatile)存储器。为了保证存储的数据不丢失,易失性存储器需要恒定的电流。
3 小结
编码:存储器篇以前文介绍的触发器为基础,对 D 型触发器进行改进从而获得了能够随机存取多位比特的存储设备,并结合存储器介绍了字节的概念。为了精简内容删减了部分较为详细的书写,仅作为整理总结。
网友评论