CPU 执行程序的秘密,藏在了这 15 张图里( 五 )


不同的 CPU 有不同的指令集 , 也就是对应着不同的汇编语言和不同的机器码 , 接下来选用最简单的 MIPS 指集 , 来看看机器码是如何生成的 , 这样也能明白二进制的机器码的具体含义 。
MIPS 的指令是一个 32 位的整数 , 高 6 位代表着操作码 , 表示这条指令是一条什么样的指令 , 剩下的 26 位不同指令类型所表示的内容也就不相同 , 主要有三种类型R、I 和 J 。
CPU 执行程序的秘密,藏在了这 15 张图里文章插图
一起具体看看这三种类型的含义:

  • R 指令 , 用在算术和逻辑操作 , 里面由读取和写入数据的寄存器地址 。 如果是逻辑位移操作 , 后面还有位移操作的「位移量」 , 而最后的「功能码」则是再前面的操作码不够的时候 , 扩展操作码来表示对应的具体指令的;
  • I 指令 , 用在数据传输、条件分支等 。 这个类型的指令 , 就没有了位移量和操作码 , 也没有了第三个寄存器 , 而是把这三部分直接合并成了一个地址值或一个常数;
  • J 指令 , 用在跳转 , 高 6 位之外的 26 位都是一个跳转后的地址;
接下来 , 我们把前面例子的这条指令:「add 指令将寄存器 R0 和 R1 的数据相加 , 并把结果放入到 R3」 , 翻译成机器码 。
CPU 执行程序的秘密,藏在了这 15 张图里文章插图
加和运算 add 指令是属于 R 指令类型:
  • add 对应的 MIPS 指令里操作码是 000000 , 以及最末尾的功能码是 100000 , 这些数值都是固定的 , 查一下 MIPS 指令集的手册就能知道的;
  • rs 代表第一个寄存器 R0 的编号 , 即 00000;
  • rt 代表第二个寄存器 R1 的编号 , 即 00001;
  • rd 代表目标的临时寄存器 R2 的编号 , 即 00010;
  • 因为不是位移操作 , 所以位移量是 00000
把上面这些数字拼在一起就是一条 32 位的 MIPS 加法指令了 , 那么用 16 进制表示的机器码则是 0x00011020 。
编译器在编译程序的时候 , 会构造指令 , 这个过程叫做指令的编码 。 CPU 执行程序的时候 , 就会解析指令 , 这个过程叫作指令的解码 。
现代大多数 CPU 都使用来流水线的方式来执行指令 , 所谓的流水线就是把一个任务拆分成多个小任务 , 于是一条指令通常分为 4 个阶段 , 称为 4 级流水线 , 如下图:
CPU 执行程序的秘密,藏在了这 15 张图里文章插图
四个阶段的具体含义:
  1. CPU 通过程序计数器读取对应内存地址的指令 , 这个部分称为 Fetch(取得指令);
  2. CPU 对指令进行解码 , 这个部分称为 Decode(指令译码);
  3. CPU 执行指令 , 这个部分称为 Execution(执行指令);
  4. CPU 将计算结果存回寄存器或者将寄存器的值存入内存 , 这个部分称为 Store(数据回写);
上面这 4 个阶段 , 我们称为指令周期(Instrution Cycle) , CPU 的工作就是一个周期接着一个周期 , 周而复始 。
事实上 , 不同的阶段其实是由计算机中的不同组件完成的:
CPU 执行程序的秘密,藏在了这 15 张图里文章插图