这篇文章是计算机组成元素的第三章的总结,是接着前一篇写的。没看过前一篇的,可以去看下。这是链接:
我们在之前介绍过的各种逻辑门,比如 Mux, DMux 等等,都是各种操作组合起来。所以由这些门构成的 chip 都叫组合 chip。像 CPU 里面的 ALU,这种提供了一些处理数据功能的芯片就是组合芯片的一种。很明显光这种芯片肯定是不够构成一个简单的冯诺伊曼体系的计算机系统,我们还需要一种芯片,即时序芯片,一种可以维持我们数据状态的芯片。
这里举个例子来理解下时序芯片的作用,其实很简单,任何一个高级语言,例如 C++,Java 都会声明变量,然后让变量来保存一个值
int a = 10;
就像这样的,a 的值就永远是 10,而且你想用 a 的时候就直接用就行了。你应该会好奇在底层这种方式是如何实现的,这些功能就是要靠时序芯片来实现了。
我们先来介绍下背景知识。像我们前面举的例子,a = 10 的意思就是对计算机说,计算机,你要记住 a 是 10,也就是说这是一种记忆行为。
记忆行为很明显是跟时间有关的,只有你在某一时间点告诉我了 a = 10,我才能在之后的时间内知道 a 就是 10。这就引发出了一个问题,计算机是如何表示时间这个概念。我们的时间观念是年月日时分秒,那计算机的时间又是怎么回事?应该有很多人都听说过 CPU 主频这个东西吧,CPU的主频表示在CPU内数字脉冲信号震荡的速度,脉冲信号就是这个东西:
计算机有一个主时钟,在不停的发出连续的交流信号串。低相位用0代表,高相位用1代表,0-1,0-1,0-1就表示时间的流逝了。一个0-1就表示一个时钟周期,主频就是表示了一秒内出现了多少个时钟周期。
计算机中的时间概念介绍完,就该介绍 时序芯片。首先,我们来介绍一个最基本的时序元件,Flip-Flops,所有的高级的时序芯片,比如 Memory, registers,都是基于此构造成的。Flip-Flop 我们这边都翻译成触发器。触发器有好几种种类,RS 触发器,D 触发器,T 触发器和 JK 触发器等等,具体的可以去维基百科上看详细介绍。这里我们主要介绍 D 触发器,简称 DFF。DFF 没什么特别的,它跟我们之前所写的那些逻辑门都是一样的,有输入位也有输出位。但是跟那些组合芯片唯一的不同是,它还有一个 clock bit 输入位,正如我们之前的介绍,时序逻辑是基于时间的,既然组合芯片是一个基于输入输出的函数,那时序逻辑很明显就是基于时间的一个函数。DFF 实现的时间函数就是 :
out(t) = in(t - 1),即当前时钟周期的输出是上个时钟周期的输入
DFF 有两个特点是需要非常注意的,也可以说是时序芯片的两个特点:
1. 有一个时间的延迟(这里的时间的延迟,我们先暂且认为这是 DFF 硬件内置的一个属性)
2. out 值只在一个周期结束,另一个周期开始的转换点变换
Register
介绍完基础的时序元件,D 触发器,我们就来看一些基于 D 触发器的一些时序芯片。首先是 Registers,我们称寄存器。寄存器跟 D 触发器非常类似,只是寄存器实现的时间函数是 :
out(t) = out(t - 1),即当前时钟周期的输出是上个时钟周期的输出
这个是书上的两幅图,第二幅图描述的是如何基于 DFF 去构造 一位的寄存器,第一幅图是错误的实现。因为我们需要去控制加载新值的时间,有可能我们不想在下个周期去加载新值,想在下下个周期去加载新值,所以我们需要一个 load 位去控制何时加在新值。(注意:这里 DFF 中间有个小的三角形缺口,表示的是我们之前介绍的 clock-bit 输入位)。
这里说下这个一位寄存器的实现的一些提示:
1. 首先是决定是否加在新值,这个用 Mux 门很容易实现
2. 为赋值的变量默认是 0
3. DFF 可以输出上个周期的值
4. 类似循环
这里实现的是一位的寄存器,当然要实现能存储多位的寄存器就非常简单了,一个寄存器如果拥有 n 个这样一位的寄存器,我们称该寄存器的宽度是 n。然后寄存器一次能处理的 in 的位数又可以构成一个新的计量单位,叫 Word (字),大多数寄存器一个字长就是表示它的宽度,然而有些寄存器比如说是 32 位宽的,但是一次只能处理16位的数,那该寄存器的一个字长就是16。 就是然后内存 什么的基本都是以字为计量单位。
RAM
有了以上这些知识就可以去构造一个我们经常所说的 RAM,更准确的说应该是 RAM 的一个 unit。
RAM (Random Access Memory)指的是任何一个存储在存储空间的字,不管它的物理位置在哪里,我们都能以相同的速度获取到,
要满足这样的条件,RAM是这样设计的:
1. 我们要给 RAM 中的每一个寄存器的每一个 word 赋一个地址
2. 我们要实现一个逻辑门,可以输入一个地址,就输出一个位于该地址的寄存器
这里就可以看出一个 RAM 的基本参数:
1. 一个是数据宽度:一个字长是多少位的
2. size:总共是多少个字
Counters
计数器也是一个时序芯片。至于为什么介绍这个芯片,因为我们所写的那些程序跟这个关系蛮大的。举个例子,一个典型的 CPU 会有程序计数器,它的作用是表明下条应该被执行的指令的地址是什么。它的时间函数是:
out(t) = out(t - 1) + C,C 经常为 1
典型的计数器还会有额外的功能。比如说,重置为 0,加载一个新的 Constant等等
总结
总之,所有的时序芯片都可以用一幅图来表示,这幅图是书上的:
问题
我们已经知道了两种类型的芯片,一种是组合芯片,一种是时序芯片。那平常计算机工作的时候,肯定是两种芯片协同起来一起工作,当两种芯片协同起来工作的时候,就会有一些问题生成。
先来举一个具体的例子,用我们之前的 ALU 来计算 X + Y,并把结果储存到 Register A。首先我们要去存储 X 的寄存器的地方去获得 X 的值,之后再去获得 Y 的值,因为物理条件的约束(比如说有些寄存器离 ALU 比较远,传输过程中受到干扰),ALU 有可能会在不同的时间点获得正确的 X 和 Y 的值。所以想要 ALU 得出正确的结果是需要一段时间的,在这段时间内,ALU 产出的结果都是我们不想要的,称为 垃圾。那我们怎么保证寄存器最后存到的值是正确的?
我们在介绍寄存器曾经说过,寄存器的输出值的改变发生在每个周期开始的时候,并且依赖于上个周期的值,所以解决方法就是,一个时钟周期的时间设为刚好大于我去最远的一个寄存器去取值所需要花的时间。这样在每个时钟周期的结束和下一个时钟周期开始的转换点,寄存器就能获取到正确的值。
结尾
书里,没有详细介绍触发器的具体实现,把触发器作为基础元素,如果你有兴趣可以自己去探寻一下是怎么实现的(可能需要懂更多的硬件知识),我也在研究,欢迎在评论区一起去讨论。最后,书中也提到了,现代的内存芯片都是经过仔细优化的,会去利用硬件的一些物理属性来实现存储技术。所以很多时候技术的实现,都是一个性价比的问题。
这里放我自己写的那些逻辑门的 Code:
有问题欢迎提 PR,文章有任何问题也欢迎指出,还有最重要的一点,所有的详细资料都在: