计算机组成原理17(数据通路)

CPU由指令加计算两部分组成,

指令:我们写的代码是怎么变成一条条机器能够理解的指令;

计算:也就是数据的二进制表现(定点数、浮点数),加法和乘法的实现,通过什么电路(半加器、全加器)。

只有把“指令”和“计算”这两部分功能连通起来,也就是建立数据通路,我们才能构成一个真正完整的 CPU。

指令周期(Instruction Cycle)

计算机每执行一条指令的过程,可以分解成这样几个步骤:


  1. Fetch(取得指令),也就是从 PC 寄存器里找到对应的指令地址,根据指令地址从内存里把具体的指令,加载到指令寄存器中,然后把 PC 寄存器自增,好在未来执行下一条指令。

  1. Decode(指令译码),也就是根据指令寄存器里面的指令,解析成要进行什么样的操作,是 R、I、J 中的哪一种指令,具体要操作哪些寄存器、数据或者内存地址。

  1. Execute(执行指令),也就是实际运行对应的 R、I、J 这些特定的指令,进行算术逻辑操作、数据传输或者直接的地址跳转。

  1. 重复进行 1~3 的步骤。

这样的步骤,就构成了永不停歇的“Fetch - Decode - Execute”的循环,我们把这个循环称之为指令周期(Instruction Cycle)。

image

1.指令存放于存储器中(PC寄存器、指令寄存器)

2.控制器从寄存器中取出指令,并对指令进行解码

3.运算器(算术逻辑单元ALU)负责指令的执行,如果是简单的无条件跳转,不需要计算的,则直接由运算器解决

image

除了指令周期(Instruction Cycle),CPU中还有其他周期:

  1. 机器周期(Machine Cycle)
  2. CPU周期(CPU Cycle):CPU 内部的操作速度很快,但是访问内存的速度却要慢很多。每一条指令都需要从内存里面加载而来,所以我们一般把从内存里面读取一条指令的最短时间,称为 CPU 周期。
  3. 时钟周期(Clock Cycle):就是CPU的主频如3.5GHZ,一个 CPU 周期,通常会由几个时钟周期累积起来。一个 CPU 周期的时间,就是这几个 Clock Cycle 的总和。
image

在一个指令周期中,取出指令,至少需要一个 CPU 周期,执行指令,也至少需要一个CPU周期,复杂的指令就需要更多的CPU周期(>=2),一个指令周期包含多个CPU周期,一个CPU周期包含多个时钟周期。

建立数据通路

数据通路就是我们的处理器单元。它通常由两类原件组成:

  1. 操作元件,也叫组合逻辑元件(Combinational Element),其实就是我们的 ALU。在前面讲 ALU 的过程中可以看到,它们的功能就是在特定的输入下,根据下面的组合电路的逻辑,生成特定的输出。
  2. 存储元件,也有叫状态元件(State Element)的。比如我们在计算过程中需要用到的寄存器,无论是通用寄存器还是状态寄存器,其实都是存储元件。

通过数据总线的方式,把它们连接起来,就可以完成数据的存储、处理和传输了,这就是所谓的建立数据通路了。

此时还需要控制器作为算术逻辑单元和寄存器的中间桥梁,它的逻辑就没那么复杂了。我们可以把它看成只是机械地重复“Fetch - Decode - Execute“循环中的前两个步骤,然后把最后一个步骤,通过控制器产生的控制信号,交给 ALU 去处理。

但实际上控制器的电路特别复杂:

一方面,所有 CPU 支持的指令,都会在控制器里面,被解析成不同的输出信号。我们之前说过,现在的 Intel CPU 支持 2000 个以上的指令。这意味着,控制器输出的控制信号,至少有 2000 种不同的组合。

运算器里的 ALU 和各种组合逻辑电路,可以认为是一个固定功能的电路。控制器“翻译”出来的,就是不同的控制信号。这些控制信号,告诉 ALU 去做不同的计算。可以说正是控制器的存在,让我们可以“编程”来实现功能,能让我们的“存储程序型计算机”名副其实。

image
指令译码器将输入的机器码,解析成不同的操作码和操作数,然后传输给 ALU 进行计算

CPU 所需要的硬件电路

  1. 自然是我们之前已经讲解过的 ALU 了,它实际就是一个没有状态的,根据输入计算输出结果的第一个电路。

  2. 我们需要有一个能够进行状态读写的电路元件,也就是我们的寄存器。我们需要有一个电路,能够存储到上一次的计算结果。这个计算结果并不一定要立刻拿到电路的下游去使用,但是可以在需要的时候拿出来用。常见的能够进行状态读写的电路,就有锁存器(Latch),以及我们后面要讲的 D 触发器(Data/Delay Flip-flop)的电路。

  3. 我们需要有一个“自动”的电路,按照固定的周期,不停地实现 PC 寄存器自增,自动地去执行“Fetch - Decode - Execute“的步骤。我们的程序执行,并不是靠人去拨动开关来执行指令的。我们希望有一个“自动”的电路,不停地去一条条执行指令。

    我们看似写了各种复杂的高级程序进行各种函数调用、条件跳转。其实只是修改 PC 寄存器里面的地址。PC 寄存器里面的地址一修改,计算机就可以加载一条指令新指令,往下运行。实际上,PC 寄存器还有一个名字,就叫作程序计数器。顾名思义,就是随着时间变化,不断去数数。数的数字变大了,就去执行一条新指令。所以,我们需要的就是一个自动数数的电路。

  4. 我们需要有一个“译码”的电路。无论是对于指令进行 decode,还是对于拿到的内存地址去获取对应的数据或者指令,我们都需要通过一个电路找到对应的数据。这个对应的自然就是“译码器”的电路了。

需要的 4 种基本电路,它们分别是,ALU 这样的组合逻辑电路、用来存储数据的锁存器和 D 触发器电路、用来实现 PC 寄存器的计数器电路,以及用来解码和寻址的译码器电路。

虽然 CPU 已经是由几十亿个晶体管组成的及其复杂的电路,但是它仍然是由这样一个个基本功能的电路组成的。只要搞清楚这些电路的运作原理,你自然也就弄明白了 CPU 的工作原理。

为什么 CPU 还会有满载运行和 Idle 闲置的状态呢?

CPU在空闲状态就会停止执行,具体来说就是切断时钟信号,CPU的主频就会瞬间降低为0,功耗也会瞬间降低为0。由于这个空闲状态是十分短暂的,所以在任务管理器里面也只会看到CPU频率下降,不会看到降低为0。当CPU从空闲状态中恢复时,就会接通时钟信号,这样CPU频率就会上升。所以会在任务管理器里面看到CPU的频率起伏变化。

同时,程序计数器一直在变化,意味着满载,如果持续不变就是idle。CPU密集型任务需要CPU大量计算的任务,这个时候CPU负载就很高,IO密集型任务,CPU一直在等待IO,就会有idle。