从本篇起,我们将自己实现一个 Y86 处理器。
首先看一下为了实现 Y86 处理器,我们都需要哪些部件。
我们已经知道,CPU 会逐条地执行机器指令。那么 CPU 是如何判断正在执行的指令是否执行完毕,继而可以开始执行下一条指令的呢?
答案是:CPU 并不对此进行判断。
它采用固定的时长来执行每一条指令,CPU 能够保证各种指令均能在该时长内被执行完毕。
所以,每隔固定的时长 CPU 便开始执行下一条指令。
时钟
由于 CPU 采用了上述的机制执行指令,自然需要一个定时器,间隔固定时长周期性地通知 CPU 执行下一条指令。这个定时器被称为 时钟。
一般采用矩形波状的电位变化来实现时钟。每当时钟变成高电位时,PC(程序计数器) 应该更新指令地址,继而执行下一条指令。
组合逻辑电路
-
有的指令在执行时,需要对数据进行算数或逻辑运算。
如 IA32 中的
addl
、orl
等指令。 -
有的指令在执行时,需要将数据按照某种规则进行筛选。
如在下面这段指令的第一句指令,CPU 即要从
0x8048291
和0x8048296
中筛选出一个值。804828f: je 8048296 8048291: call 80482b4
以上两种需求均可以概括为:将输入数据按照某种规则处理后输出结果。
这两种需求,在 CPU 中均通过组合逻辑电路(简称组合电路)予以实现。
组合电路只是简单地根据输入信号和某种规则进行信号输出,不存储任何信息。
组合电路会在后文进一步介绍。
存储器
-
有的指令在执行时,需要根据地址从寄存器文件或存储器中获取数据。
这种操作和 组合逻辑电路 一节中所描述的需求很相近,即 将输入数据按照某种规则处理后输出结果。
即,从存储器中读取数据时,存储器的表现就像是一个组合电路。
-
有的指令在执行完毕时,需要将结果保存在寄存器或存储器中。
当时钟信号变为高电位时,当前指令已经执行完毕,此时即可将数据写入到存储器中。
即,时钟信号控制着存储器的写入。
下面来看我们在 Y86 处理器中使用的两类存储器:
时钟寄存器和随机访问存储器。
时钟寄存器(简称寄存器)
时钟寄存器只存储单个位或字。
-
大多数时候,寄存器都保持在稳定状态(用 x 表示),产生的输出等于它保存的值。
这是它的读状态,无论输入是什么,它都只会输出自身保存的值。
-
当时钟变成高电位时,输入值才被加载到寄存器中,并输出该值。
在 Y86 处理器中,会使用时钟寄存器来保存程序计数器(PC)、条件代码(CC)和程序状态(Stat)。
随机访问存储器(简称存储器)
随机访问存储器存储多个字,用地址来选择读或写哪个字。
比如虚拟存储器系统和寄存器文件。
下面来看一个典型的寄存器文件:
它有两个读端口(A 和 B),和一个写端口(W)。
为什么读端口有两个而写端口只有一个呢?
看一下之前的 IA32 指令可以发现:任何指令,最多只会读取两个寄存器中的值,最多只会向一个寄存器中写入。
Y86 将要制定的指令与 IA32 相类似。
下面来看另外一个存储程序数据的存储器:
这个存储器只有一个地址接口。
这意味着在一个时钟周期内,要么进行读操作,要么进行写操作。
在 Y86 处理器中,使用随机访问存储器包括寄存器文件、指令存储器、程序数据存储器等。
小结
考察一个时钟周期的实质:
当时钟电压上升——即一个新的时钟周期开始后,“源头时钟寄存器”的输出(可能)会发生改变;
这里所说的“源头时钟寄存器”可初步认为是 PC,后文将会看到还有其他“源头”寄存器。
由此,会引发一系列的改变:
组合电路的输出会随着输入的改变而改变,存储器会因为读取地址的改变而改变输出值。
由源头时钟寄存器输出改变而引发的变动在 CPU 中不断向前传递。最终,CPU 中各个部件的输入输出都会稳定下来。
这时,CPU 就纯粹是在等待下一个时钟周期的到来了。