跳转到主要内容

A.7 指令集编码

前面各项选择显然会影响指令如何编码为处理器执行的二进制表示。表示方式不仅影响编译后的程序大小,也影响处理器实现:处理器必须对其译码,迅速找出操作及操作数。操作通常由一个称为操作码的字段指定。下面将看到,关键决定是如何将寻址方式与操作一起编码。

这一决定取决于寻址方式的种类,以及操作码与寻址方式之间的独立程度。某些较早的计算机有一至五个操作数,每个操作数又有十种寻址方式(见图 A.6)。面对如此多的组合,通常需要为每个操作数设置独立的地址说明符,说明如何访问它。另一个极端是加载—存储计算机,它们只有一个存储器操作数,而且只有一两种寻址方式;此时显然可将寻址方式直接编码在操作码中。

寄存器数量与寻址方式数量都会显著影响指令大小,因为寄存器字段和寻址方式字段可能在同一条指令中出现多次。实际上,对大多数指令而言,寻址方式与寄存器字段消耗的位数,远多于操作码。编码指令集时,设计者必须权衡几种互相竞争的要求:

  1. 希望拥有尽可能多的寄存器和寻址方式。
  2. 寄存器与寻址方式字段的大小,会影响平均指令大小,继而影响平均程序大小。
  3. 希望指令长度便于流水线实现处理。易于译码的指令有何价值,将在附录 C 与第 3 章讨论。至少,指令应为整数字节长度,而非任意位数。许多桌面与服务器设计者选择定长指令,以牺牲平均代码大小为代价,获得实现上的好处。

图 A.18 展示三种常见编码方案。第一种称为可变编码,因为几乎所有操作都可以使用全部寻址方式;当寻址方式和操作都很多时,它最合适。第二种称为固定编码,将操作与寻址方式合并到操作码中;它通常只有一种指令长度,适合操作和寻址方式都较少的情形。二者的权衡是程序大小与处理器译码难易程度。可变编码力求用尽可能少的位表示程序,但不同指令的长度与所完成工作量可能差异很大。

可变长度、固定长度与混合指令编码格式
图 A.18 指令编码的三种基本形式:变长、定长和混合。变长格式可支持任意数量的操作数,由每个地址说明符确定相应操作数的寻址方式及说明符长度;通常代码最小,因为无需包含未使用的字段。定长格式始终具有相同操作数数量,寻址方式若有选择,则作为操作码的一部分;它通常产生最大的代码。字段位置往往固定,但不同指令可以将其用于不同目的。混合方法用操作码指定多种格式,增加一或两个字段指定寻址方式,再用一或两个字段指定操作数地址。

图内术语:Operation and no. of operands=操作及操作数数量;Operation=操作;Address specifier=地址说明符;Address field=地址字段。(A) 变长:Intel 80x86、VAX;(B) 定长:RISC-V、ARM、MIPS、PowerPC、SPARC;(C) 混合:RISC-V Compressed(RV32IC)、IBM 360/370、microMIPS、Arm Thumb2。

看一条 80x86 指令,就能说明可变编码:

add EAX,1000(EBX)

add 表示两个操作数的 32 位整数加法,操作码占 1 字节。80x86 的地址说明符占 1 或 2 字节,指定源/目的寄存器 EAX,以及第二个操作数的寻址方式(此处为位移)和基址寄存器 EBX;这一组合用 1 字节即可指定。处于 32 位模式时(见附录 K),地址字段为 1 或 4 字节。由于 1000 大于 282^8,该指令总长为:

1+1+4=6 字节 1+1+4=6\ \text{字节}

80x86 指令长度在 1–17 字节之间。80x86 程序通常比采用固定格式的 RISC 程序更小(见附录 K)。

在可变与固定这两个极端之间,很自然会想到第三种方案:减小可变体系结构中指令大小与工作量的差异,同时提供多种指令长度以减少代码大小。这就是混合方法,下面将给出实例。

减小 RISC 的代码大小

RISC 开始用于嵌入式应用后,32 位固定格式成为负担,因为这类应用重视成本,也就重视更小的代码。为此,几家厂商提供了新混合版本的 RISC 指令集,同时包含 16 位和 32 位指令。较窄指令支持更少的操作、较小的地址和立即数字段、较少的寄存器,并采用两地址格式,而非经典 RISC 的三地址格式。RISC-V 提供名为 RV32IC 的扩展,C 表示 compressed(压缩)。常见情形,例如较小的立即数,以及源、目的寄存器相同的常用 ALU 操作,都可以编码为 16 位格式。1 附录 K 还给出 ARM Thumb 和 microMIPS 两个实例,它们均声称代码大小最多可缩减 40%。

与这些指令集扩展不同,IBM 直接压缩标准指令集,并加入硬件,在指令缓存未命中、从存储器取指时解压。因此,指令缓存中仍保存完整的 32 位指令,主存、ROM 和磁盘上则保存压缩代码。RV32IC、microMIPS、Thumb2 等压缩格式的优点,是让指令缓存的有效容量仿佛增加约 25%;IBM CodePack 的优点则是编译器不必为不同指令集作修改,而且指令译码仍可保持简单。

CodePack 首先对任意 PowerPC 程序进行行程长度编码压缩,然后将得到的压缩表装入片上一个 2 KB 表中,因此每个程序都有自己的独特编码。压缩后,分支目标不再位于对齐的字边界;为处理这种情况,PowerPC 在存储器中建立哈希表,将压缩地址与未压缩地址相互映射。类似 TLB(见第 2 章),它缓存最近使用的映射,以减少访存次数。IBM 声称,整体性能代价为 10%,换来 35%–40% 的代码缩减。

小结:指令集编码

前几节关于指令集各组成部分的选择,决定设计者是否有条件在可变编码与固定编码之间作选择。若能够选择,重视代码大小甚于性能的设计者会选可变编码,重视性能甚于代码大小的设计者会选固定编码。RISC-V、MIPS 和 ARM 都有同时使用 16 位、32 位指令的扩展;代码大小受严格限制的应用,可以选择 16 位变体。附录 E 给出 13 个体现设计者选择结果的实例。2 附录 C 与第 3 章还将进一步讨论,指令的可变性如何影响处理器性能。

为 A.9 节介绍 RISC-V 指令集体系结构所需的铺垫已经接近完成。不过在此之前,简要考察编译技术及其对程序性质的影响,会很有帮助。


  1. 译注:原文此处写作“intermediates with small values”;结合上下文的压缩指令字段,这里按小立即数理解。 ↩︎

  2. 译注:原文此处指向附录 E;本文件中附录 E 为嵌入式系统,指令集体系结构调查位于附录 K。 ↩︎