构建指令集

书中所示的 Y86-64 的指令集十分简单,其共有13个指令,其中的三个指令具有多个分支。

在指定完指令的功能后,要对指令集进行编码,使用4位二进制数,即1个16进制数来表示这13个指令,另用1个16进制数表示部分指令的分支,而对于没有分支的指令,第二个16进制数则填为0。 CESHI 再取两个16进制数分别表示源寄存器和目的寄存器,在使用一个寄存器的情况下,另一个寄存器的标识符用 F 表示(这里用 F 标记不使用的寄存器,和后面 取指 通知 译码 是否使用寄存器时所用的标识一致),最后,在需要使用跳转标识的指令和使用内存地址的指令加上常数字。

流水线

简述

流水线的本质是多个任务同时执行,而不是单一的执行一个任务,以充分利用处理器的组合逻辑单元。

在流水线化的系统中,待执行的任务被划分成了若干个独立的阶段。 流水线的重要特性是提高了系统的吞吐量。

未被流水线化的状态是,一个处理单元完整的处理完整个任务后,再执行下一项任务。

流水线化的状态是,多个处理单元执行单个任务的不同阶段,以使得每一个处理单元的每个部分得到充分的利用。

一个时钟周期,通常指每个单元完成其单个任务的平均耗时,在下一个上升沿到来时,将处理好的数据存放在每个处理单元后的寄存器中,随后,每个单元再从前一个寄存器中读取数据,以此往复循环的完成任务。

在本书所描述的分层系统中(即 Y86-64),这「若干个独立的阶段」所指分别为: 取指、译码、执行、访存、写回

在取指阶段会对下个一个指令的地址进行预测,对于普通的指令(即除跳转、返回之外的指令),其预测值由指令本身的长度所决定,而对于跳转指令,Y86-64 选用「预测选择了分支」,对于返回指令,要更特殊化的处理。

出现的问题

流水线冒险

依照这样的分层体系,完成一个任务需要经历5个阶段,注意写回在最后一个阶段才进行,若正在执行的任务需要前一个任务的「输出」,就需要等待前一个任务执行完写回操作后才能获得需要的数据,这时,当前正在执行的任务可能就会被暂停,这将会浪费几个时钟周期,这被称为流水线冒险

为了解决这个问题,引入了:

  1. 暂停,插入气泡 暂停会造成严重的周期浪费,所以除非迫不得已,一般不会考虑使用暂停。
  2. 用转发来避免数据冒险 为了解决暂停造成的浪费,引入了转发。需要在设计上引入转发回路,使部分数据不经过寄存器,或不经过完整的处理即向下转发给寄存器的输出(即执行单元的输入)。
  3. 加载/使用数据冒险 由于内存操作要滞后一个周期(从内存中读到寄存器,下一条指令准备在这个寄存器上写时),所以引入了这个方式,它先暂停一个周期,随后随后再进行转发。
  4. 避免控制冒险 返回指令和错误的分支预测会造成不得不暂停的情况,于是通过插入气泡来解决这两个问题。