指令周期(Instruction Cycle)
计算机每执行一条指令的过程,可以分解成这样几个步骤。
1.Fetch(取得指令),也就是从 PC 寄存器里找到对应的指令地址,根据指令地址从内存里把具体的指令,加载到指令寄存器中,然后把 PC 寄存器自增,好在未来执行下一条指令。
2.Decode(指令译码),也就是根据指令寄存器里面的指令,解析成要进行什么样的操作,是 R、I、J 中的哪一种指令,具体要操作哪些寄存器、数据或者内存地址。
3.Execute(执行指令),也就是实际运行对应的 R、I、J 这些特定的指令,进行算术逻辑操作、数据传输或者直接的地址跳转。
4. 重复进行 1~3 的步骤。
在取指令的阶段,我们的指令是放在存储器里的,通过 PC 寄存器和指令寄存器取出指令的过程,是由控制器(Control Unit)操作的。指令的解码过程,也是由控制器进行的。一旦到了执行指令阶段,无论是进行算术操作、逻辑操作的 R 型指令,还是进行数据传输、条件分支的 I 型指令,都是由算术逻辑单元(ALU)操作的,也就是由运算器处理的。不过,如果是一个简单的无条件地址跳转,那么我们可以直接在控制器里面完成,不需要用到运算器。
除此之外,CPU 内部还有零位两个常见的 Cycle :
一个叫 Machine Cycle,机器周期或者 CPU 周期。CPU 内部的操作速度很快,但是访问内存的速度却要慢很多。每一条指令都需要从内存里面加载而来,所以一般把从内存里面读取一条指令的最短时间,称为 CPU 周期。
另外一个是 Clock Cycle,也就是时钟周期以及我们机器的主频。一个 CPU 周期,通常会由几个时钟周期累积起来。一个 CPU 周期的时间,就是这几个 Clock Cycle 的总和。
一个指令周期,包含多个 CPU 周期,一个 CPU 周期包含多个时钟周期。
建立数据通路
“数据通路”是指数据在CPU中所经过的路径,连同路径上的部件,包括:通用寄存器、多路选择器、符号扩展器、零扩展器、ALU、移位寄存器等。这些部件的宽度和数据传送的路径宽度都是一致的,这个一致的宽度就是数据通路的宽度。CPU中有定点运算器和浮点运算器,因而,相对应的就有定点运算器的数据通路和浮点运算器数据通路。两者的宽度不同,浮点运算器的数据通路要宽的多。
宽度
机器字长,字宽
“机器字长”是计算机的一个非常重要的指标。通常称32位机器或64位机器,就是指机器的字长是32位或64位。一般情况下,机器字长定义为CPU中在同一时间内一次能够处理的二进制数的位数,实际上就是CPU中数据通路的位数。因为机器字长与内存单元的地址位数有关,而地址计算是在定点运算器中进行的。所以,一般把定点运算器的数据通路宽度定为机器字长。
在计算机中,“字”的概念经常出现。一个“字”的宽度并不等于机器字长。“字”作为机器中所有信息宽度的计量单位,对于某个系列机来说,其字宽总是固定的。例如,在80x86系列中,一个字的宽度为16位,因此,32位是双字,64位是四字。在IBM303X系列中,一个字的宽度为32位,所以16位为半字,32位为单字、64位为双字。
指令字长
“指令字长”指指令的位数。有定长指令字机器和不定长指令字机器。定长指令字机器中所有指令的位数是相同的,目前定长指令字大多是32位指令字。不定长指令字机器的指令有长有短,但每条指令的长度一般都是8的倍数。所以,一个指令字在存储器中存放时,可能占用多个存储单元;从存储器读出并通过总线传输时,可能分多次进行,也可能一次读多条指令。
处理单元元件组成
第一类叫操作元件,也叫组合逻辑元件(Combinational Element),也就是 ALU 它们的功能就是在特定的输入下,根据下面的组合电路的逻辑,生成特定的输出。
第二类叫存储元件,也有叫状态元件(State Element)的。比如我们在计算过程中需要用到的寄存器,无论是通用寄存器还是状态寄存器,其实都是存储元件。
通过数据总线的方式,把它们连接起来,就可以完成数据的存储、处理和传输了,这就是所谓的建立数据通路了。
CPU 所需硬件电路
首先是 ALU 了,它实际就是一个没有状态的,根据输入计算输出结果的第一个电路。
第二,一个能够进行状态读写的电路元件,即寄存器。我们需要有一个电路,能够存储到上一次的计算结果。这个计算结果并不一定要立刻拿到电路的下游去使用,但是可以在需要的时候拿出来用。常见的能够进行状态读写的电路,就是有锁存器(Latch), D 触发器(Data/Delay Flip-flop)的电路。
第三,一个“自动”的电路,按照固定的周期,不停地实现 PC 寄存器自增,自动地去执行“Fetch - Decode - Execute“的步骤。各种复杂的高级程序进行各种函数调用、条件跳转。其实只是修改 PC 寄存器(程序计数器)里面的地址。PC 寄存器里面的地址一修改,计算机就可以加载一条指令新指令,往下运行。所以,我们需要的就是一个自动数数的电路。
第四,一个“译码”的电路。无论是对于指令进行 decode,还是对于拿到的内存地址去获取对应的数据或者指令,都需要通过一个电路找到对应的数据。这个对应的自然就是“译码器”的电路了。
简而言之:ALU 这样的组合逻辑电路、用来存储数据的锁存器和 D 触发器电路、用来实现 PC 寄存器的计数器电路,以及用来解码和寻址的译码器电路。
时序逻辑电路
组合逻辑电路:给定输入即可得到相应的输出,但达不到自动和随需要简易的改变计算。时序逻辑电路刚好解决这些问题:
第一个就是自动运行的问题。时序电路接通之后可以不停地开启和关闭开关,进入一个自动运行的状态。使得控制器不停地让 PC 寄存器自增读取下一条指令成为可能。
第二个是存储的问题。通过时序电路实现的触发器(RS,JK,D 触发器等),能把计算结果存储在特定的电路里面,而不是像组合逻辑电路那样,一旦输入有任何改变,对应的输出也会改变。
第三个本质上解决了各个功能按照时序协调的问题。无论是程序实现的软件指令,还是到硬件层面,各种指令的操作都有先后的顺序要求。时序电路使得不同的事件按照时间顺序发生。
时钟信号的硬件实现
实现时序逻辑电路首先需要的就是时钟,CPU 的主频是由一个晶体振荡器来实现的,而这个晶体振荡器生成的电路信号,就是我们的时钟信号。
首先实现一个具有记忆功能的电路:
然后给这个电路加上时钟信号,靠时钟信号的高低电平决定电路是否变化,R,S 两个输入端决定如何变化:
R,S 通过相反器连接起来,即通过一个开关控制 R,S,这就构成了 D 触发器:
一个 D 型触发器,只能控制 1 个比特的读写,但是如果同时拿出多个 D 型触发器并列在一起,并且把用同一个 CLK 信号控制作为所有 D 型触发器的开关,这就变成了一个 N 位的 D 型触发器,也就可以同时控制 N 位的读写。
CPU 里面的寄存器可以直接通过 D 型触发器来构造。我们可以在 D 型触发器的基础上,加上更多的开关,来实现清 0 或者全部置为 1 这样的快捷操作。
CPU 主频和外频
主频
主频也叫时钟频率,单位是 MHz,用来表示 CPU 的运算速度。
CPU 的主频=外频×倍频系数。很多人认为主频就决定着 CPU 的运行速度,这不仅是个片面的,而且对于服务器来讲,这个认识也出现了偏差。至今,没有一条确定的公式能够实现主频和实际的运算速度两者之间的数值关系,即使是两大处理器厂家 Intel 和 AMD,在这点上也存在着很大的争议,我们从 Intel 的产品的发展趋势,可以看出 Intel 很注重加强自身主频的发展。像其他的处理器厂家,有人曾经拿过一快 1G 的全美达来做比较,它的运行效率相当于 2G 的 Intel 处理器。所以,CPU 的主频与 CPU 实际的运算能力是没有直接关系的,主频表示在 CPU 内数字脉冲信号震荡的速度。在 Intel 的处理器产品中,我们也可以看到这样的例子:1 GHz Itanium 芯片能够表现得差不多跟 2.66 GHz Xeon/Opteron 一样快,或是 1.5 GHz Itanium 2 大约跟 4 GHz Xeon/Opteron 一样快。CPU 的运算速度还要看CPU 的流水线的各方面的性能指标。
当然,主频和实际的运算速度是有关的,只能说主频仅仅是 CPU 性能表现的一个方面,而不代表 CPU 的整体性能。
外频
外频是 CPU 的基准频率,单位也是 MHz。CPU 的外频决定着整块主板的运行速度。说白了,在台式机中,我们所说的超频,都是超 CPU 的外频(当然一般情况下,CPU 的倍频都是被锁住的)相信这点是很好理解的。但对于服务器 CPU 来讲,超频是绝对不允许的。前面说到 CPU 决定着主板的运行速度,两者是同步运行的,如果把服务器 CPU 超频了,改变了外频,会产生异步运行,(台式机很多主板都支持异步运行)这样会造成整个服务器系统的不稳定。
目前的绝大部分电脑系统中外频也是内存与主板之间的同步运行的速度,在这种方式下,可以理解为 CPU 的外频直接与内存相连通,实现两者间的同步运行状态。
网上一篇 2013 年发布的关于 CPU 部分内容的博客,内容略有过时,可以作为大致了解。
程序计数器
有了时钟信号,我们可以提供定时的输入;有了 D 型触发器,我们可以在时钟信号控制的时间点写入数据。我们把这两个功能组合起来,就可以实现一个自动的计数器了。
每次自增之后,去对应的 D 型触发器里面取值,这也是下一条需要运行指令的地址。已知同一个程序的指令应该顺序地存放在内存里面。这里就和前面对应上了,顺序存放指令,通过程序计数器就能定时地不断执行新指令。
译码器
参考 3 - 8 译码器,现代的计算机,如果 CPU 是 64 位的,就意味着寻址空间也是 ,那么我们就需要一个有 64 个开关的译码器。译码器的本质,就是从输入的多个位的信号中,根据一定的开关和电路组合,选择出自己想要的信号。
搭建 CPU
首先要有一个自动计数器,其随着时钟主频不断自增,作为 PC 寄存器。自动计数器的后面连上一个译码器。译码器还要同时连着由大量的 D 触发器组成的内存。
自动计数器会随着时钟主频不断自增,从译码器当中,找到对应的计数器所表示的内存地址,然后读取出里面的 CPU 指令。
读取出来的 CPU 指令通过 CPU 时钟的控制,写入到一个由 D 触发器组成的寄存器,也就是指令寄存器当中。
在指令寄存器后面,再跟一个译码器。这个译码器不再是用来寻址的了,而是把拿到的指令,解析成 opcode 和对应的操作数。
当拿到对应的 opcode 和操作数后,对应的输出线路连接 ALU,进行各种算术和逻辑运算。对应的计算结果,则会再写回到 D 触发器组成的寄存器或者内存当中。
总结延伸
通过自动计数器的电路,实现 PC 寄存器,不断生成下一条要执行的计算机指令的内存地址。通过译码器,从内存里面读出对应的指令,写入到 D 触发器实现的指令寄存器中。再通过另外一个译码器,把它解析成我们需要执行的指令和操作数的地址。这些电路,组成了计算机五大组成部分里面的控制器。
把 opcode 和对应的操作数,发送给 ALU 进行计算,得到计算结果,再写回到寄存器以及内存里面来,这个就是计算机五大组成部分里面的运算器。