跳转到主要内容

K.2 桌面、服务器及嵌入式计算机的 RISC 体系结构概览

引言

本节介绍两组精简指令集计算机(RISC)体系结构。第一组面向桌面、服务器和个人移动设备(PMD):

  • Advanced RISC Machines 的 ARMv8,即 64 位 ISA AArch64。
  • MIPS64 第 6 版,即原书讨论的最新 64 位 ISA。
  • Power 3.0,合并了早期 IBM Power 和 PowerPC 体系结构。
  • RISC-V,具体采用 64 位扩展 RV64G。
  • SPARCv9,即 64 位 ISA。

如图 K.1 所示,这些体系结构相当相似。

项目ARMv8MIPS64 R6Power v3.0RV64GSPARCv9
基础 ISA 最初年代19861986199020161987
本版 ISA 年代20112014201320162008
指令长度(位)3232323232
地址空间:大小、模型64 位,平坦64 位,平坦64 位,平坦64 位,平坦64 位,平坦
数据对齐优先对齐优先对齐可不对齐优先对齐对齐
数据寻址方式数8,含比例变址及前/后递增1,另有 1 种仅用于浮点412
整数寄存器:数量、模型、宽度31 个 64 位 GPR,加栈指针31 个 64 位 GPR31 个 64 位 GPR31 个 64 位 GPR31 个 64 位 GPR
独立浮点寄存器32 × 32 位或 32 × 64 位32 × 32 位或 32 × 64 位32 × 32 位或 32 × 64 位32 × 32 位或 32 × 64 位32 × 32 位或 32 × 64 位
浮点格式IEEE 754 单/双精度IEEE 754 单/双精度IEEE 754 单/双精度IEEE 754 单/双精度IEEE 754 单/双精度
图 K.1 五种用于桌面、服务器和 PMD 的体系结构在原书所述时期的最新版本,均有更早版本。除数据寻址方式数量和一些细节外,其整数指令集十分相似,可与图 K.29 对比。ARMv8 的寄存器 31 表示零,类似其他体系结构的寄存器 0;原文指出,用于加载或存储时,它表示专用的当前栈指针。SP 基址寻址既可看作单独的方式,如汇编助记符的处理,也可看作普通寄存器加偏移量,如实际指令编码的处理。

历史上还有两款重要 RISC 处理器,与上述体系结构近乎相同。Digital Equipment Corporation 在 1992–2004 年制造的 DEC Alpha,与 MIPS64 几乎一致。HP 约从 1986 年到 2005 年生产 PA-RISC,之后由 Itanium 取代。PA-RISC 与 Power ISA 最接近;后者来自 IBM Power,而 IBM Power 又继承自 IBM 801。

第二组是面向较低端应用的嵌入式 RISC:

  • Advanced RISC Machines 的 Thumb-2:包含 16 位和 32 位指令的 32 位指令集,兼有 ARMv7、ARMv8 的特性。
  • microMIPS64:包含 16 位指令的 MIPS64 版本。
  • RISC-V 压缩扩展 RV64GC:在 RV64G 上增加一组 16 位指令。

RV64GC 和 microMIPS64 都有对应的 32 位版本,即 RV32GC、microMIPS32。

由于基础 32 位或 64 位桌面、服务器体系结构的比较会讨论各 ISA 的差异,这里对嵌入式体系结构主要关注 16 位指令。

项目microMIPS64RV64GCThumb-2
发布年份200920162003
指令长度(位)16/3216/3216/32
地址空间:大小、模型32/64 位,平坦32/64 位,平坦32 位,平坦
数据对齐对齐优先对齐对齐
数据寻址方式数216
整数寄存器:数量、模型、宽度31 个 64 位 GPR31 个 64 位 GPR15 个 32 位 GPR
大多数 16 位指令可访问的整数寄存器8 个 GPR + SP + GP + RA;GPR 为 0、2–7、17,或 2–7、16、178 个 GPR + SP;GPR 为 8–158 个 GPR + SP,宽 32 位
图 K.2 三种较新的嵌入式体系结构。它们都为基础指令集增加 16 位扩展;除寻址方式数和一些细节外,整数指令集相似,可与图 K.29 对比。早期 MIPS 的 16 位版本 MIPS16 于 1995 年创建,后来由 microMIPS32、microMIPS64 替代。最初 Thumb 只有 16 位指令,创建于 1996 年。Thumb-2 主要基于 32 位 ARMv7,提供 16 个寄存器。RISC-V 还定义 RV32E,只有 16 个寄存器;原书称它包含 16 位指令且不能使用浮点。原书观察到,多数嵌入式实现选择 RV32C 或 RV64GC。

图 K.2 表明,这些嵌入式体系结构也很相似。三者的 16 位指令都是 32 位指令的简化版本,通常只允许使用有限的寄存器。基本思想是用 16 位版本替换常见的 32 位指令,从而缩小代码。RV32GC 或 Thumb-2 加入 16 位指令后,代码大小约为仅使用对应 32 位 ISA——RV32G 或 ARMv7——时的 0.73 倍。

三者的重要区别在基础 32 位 ISA 的结构。RV64GC 的 32 位指令与 RV64G 完全相同,因为 RISC-V 从一开始就考虑了 16 位选项,分支和跳转目标按 16 位边界指定。microMIPS64 基于 MIPS64,只作一项改变:分支和跳转偏移量按 16 位而不是 32 位对齐解释。它还使用了 MIPS64 为用户自定义指令扩展保留的编码空间;这些扩展不属于基础 ISA。

Thumb-2 稍有不同。其 32 位指令大多是 ARMv7 的子集,但不包含一些在 ARMv8 中被删除的特性,例如大多数指令的条件执行,以及把 PC 当作 GPR 写入。Thumb-2 还包含数十条在 ARMv8 引入的指令,具体为位字段操作、额外系统指令和同步支持。因此,Thumb-2 的 32 位指令构成一个独特的 ISA。

较早的 MIPS16 和 Thumb 采用独立模式:通过过程调用,转入只使用 16 位指令的代码段。其 16 位指令集并不完整,只面向对代码大小敏感的用户程序。

这些说明还受到一个复杂因素影响:较早的 RISC 经多年不断扩展。因此,本节选择描述原书所述时期的最新版本:桌面、服务器和 PMD 使用 ARMv8/AArch64、MIPS64 R6、Power v3.0、RV64G、SPARC v9;嵌入式部分描述 microMIPS64、RV64GC 和 Thumb-2 的 16 位子集。

讨论寻址方式和指令格式后,按五步概览指令:

  1. 附录 A 描述的 RV64G 核心中已有的指令。
  2. RV64G 或 RV64GC 没有、但至少另外两种体系结构具有的指令,按功能组织,例如扩展整数算术。
  3. ARM、MIPS、Power 或 SPARC 独有的指令组,按功能组织。
  4. 桌面、服务器、PMD RISC 的多媒体扩展。
  5. 嵌入式 RISC 的数字信号处理扩展。

本节覆盖这些体系结构的大多数指令,但并非每一条;Power 和 ARM 尤其如此,因为其指令很多。

寻址方式与指令格式

图 K.3 给出桌面、服务器、PMD 体系结构的数据寻址方式。除 ARM 外,它们都有一个寄存器,在参与地址计算时始终取零;因此,位移寻址以寄存器 0 为基址,就能合成范围有限的绝对寻址。PowerPC 的该寄存器可以被 ALU 操作修改,但用于地址计算时仍按零处理。同样,将位移设为零,就能合成寄存器间接寻址。简化的寻址方式是 RISC 的特征之一。

寻址方式ARMv8MIPS64 R6Power v3.0RV64GSPARCv9
寄存器 + 偏移量:位移/基址B,H,W,DB,H,W,DB,H,W,DB,H,W,DB,H,W,D
寄存器 + 寄存器:变址B,H,W,DB,H,W,DB,H,W,D
寄存器 + 按比例缩放的寄存器:比例变址B,H,W,DW,D
寄存器 + 寄存器 + 偏移量B,H,W,D
寄存器 + 偏移量,并将寄存器更新为有效地址:带更新的基址寻址B,H,W,DB,H,W,D
使用寄存器原值寻址,再将寄存器更新为寄存器 + 偏移量:带更新的寄存器寻址B,H,W,D
寄存器 + 寄存器,并将寄存器更新为有效地址:带更新的变址寻址B,H,W,DB,H,W,D
PC 相对:PC + 位移W,DW,D
图 K.3 桌面体系结构支持的数据寻址方式。B、H、W、D 分别表示可使用该方式的字节、半字、字、双字类型。ARM 包含两类带更新的寻址方式,其中一类也出现在 Power 中。空白沿用原表,表示未列出支持。

如图 K.4 所示,嵌入式体系结构限制了 16 位指令可访问的寄存器;大多数指令通常只能访问八个寄存器,少数特殊指令能访问其他寄存器。图 K.5 给出其 16 位指令模式的数据寻址方式。这些加载和存储版本既限制了地址计算可用的寄存器,也大幅缩短了位移立即数字段。

寄存器指定方式microMIPS64RV64GCThumb-2
3 位编码2–7、16、178–150–7
栈指针寄存器2920(用于加载/存储时)
全局指针寄存器28
返回地址寄存器31114
使用特殊寄存器栈指针或全局指针;5 位偏移量栈指针;5 位偏移量栈指针;8 位偏移量
图 K.4 microMIPS64、RV64GC、Thumb-2 的 16 位子集所采用的寄存器编码,包括核心通用寄存器,以及部分指令可访问的专用寄存器。
寻址方式microMIPS64RV64GCThumb-2
寄存器 + 偏移量:位移/基址4 位偏移量,八个寄存器之一5 位偏移量,八个寄存器之一5 位偏移量,八个寄存器之一
PC 相对数据仅字;8 位偏移量
使用特殊寄存器栈指针或全局指针;5 位偏移量栈指针;5 位偏移量栈指针;8 位偏移量
图 K.5 嵌入式体系结构支持的数据寻址方式。这里只列 microMIPS64、RV64GC、Thumb-2 的 16 位指令格式。在 RV64GC、microMIPS64 中,栈指针是指定的 GPR;原文称 Thumb-2 的栈指针是 r31 的另一种形式。原图注还称 microMIPS64 的全局指针为寄存器 30,由链接约定用来指向全局变量数据区。通常只有八个寄存器能作基址,后面将看到,ALU 的源和目的寄存器也常有同样限制。

译注:图 K.4 的 microMIPS64 全局指针为 28,图 K.5 图注却写 30;Thumb-2 栈指针在图 K.4 写作 0,图 K.5 图注写作 r31,又与图 K.2 所述寄存器规模不协调。这些都是原页可见的源书差异。

代码引用通常采用 PC 相对方式,同时支持寄存器间接跳转,用于过程返回、case 语句和经指针调用函数。桌面 RISC 的 PC 相对分支地址经常先左移两位再与 PC 相加,以扩大分支范围;这是因为指令均为 32 位,且必须在存储器中按 32 位字对齐。嵌入式体系结构和带压缩扩展的 RISC-V 包含 16 位指令,出于类似原因,PC 相对地址通常左移一位。

图 K.6 展示桌面、服务器、PMD RISC 最重要的指令格式。每种 ISA 使用四种主要格式,通常覆盖 90%–98% 的指令。寄存器—寄存器格式用于相应 ALU 指令;ALU 立即数格式用于带立即数的 ALU 指令,也用于加载与存储;分支格式用于条件分支;跳转/调用格式用于无条件分支和过程调用。

五种桌面及服务器 RISC 的主要指令格式
图 K.6 桌面/服务器 RISC 的指令格式,五种体系结构都具有这四类格式。图中上标表示字段位宽。虽然寄存器字段的位置相似,目的与两个源字段的排列有时不同。Op 是主操作码,Opx 是扩展操作码,Rd 是目的寄存器,Rs1、Rs2 是两个源寄存器,Const 是用作立即数、地址、掩码或移位量的常数。各格式中的指令也有变体:例如 MIPS 的加载和存储都采用 ALU 立即数格式;RISC-V 的加载采用 ALU 立即数格式,存储采用图中的分支格式。

图内术语:Register-register=寄存器—寄存器;Register-immediate=寄存器—立即数;Branch=分支;Jump/call=跳转/调用;Opcode=操作码;Register=寄存器;Constant=常数。

译注:原图 RISC-V 跳转行的常数字段标为 21,加上 Rd 的 5 位和 Op 的 7 位会得出 33 位;原图保留这一标注。RISC-V 的分支、存储格式对立即数字段的解释也并非完全相同,下一图继续区分 SB 等变体。

图 K.6 省略了一些较少使用的格式,图 K.7 将其汇总。

体系结构额外格式数格式功能与用途
ARMv8至少 10 种,另有许多小变体;右列列出主要形式带 13 位立即数字段的逻辑立即数操作
ARMv8常量移位量的移位,16 位操作码
ARMv816 位立即数格式
ARMv8独占访问操作,三个寄存器字段
ARMv8寄存器分支,较长操作码
ARMv8带寻址方式位的加载/存储
MIPS641一组 PC 相对加载/存储,使用寄存器—立即数格式,但立即数为 18 位,因为另一源操作数是 PC
Power9,不含小变体和向量扩展DQ 模式:使用 ALU 立即数形式,将位移的四位用于其他功能
PowerDS 模式:使用 ALU 立即数形式,将位移的两位用于其他功能
PowerDX 格式:类似寄存器—立即数,以 PC 取代一个源寄存器
PowerMD、MDS 格式:类似寄存器—寄存器,用于移位和循环移位
PowerX、XS 及若干小变体:用于变址寻址、移位和多种扩展功能
PowerZ22、Z23 格式:操作浮点数
RV642SB 格式:分支格式的变体,对立即数作不同解释
RV64UJ 格式:跳转/调用格式的变体,对立即数作不同解释
SPARC3另一种条件分支格式,多三位位移,总共 22 位而不是 19 位,但没有预测提示
SPARC22 位立即数格式,用于加载寄存器高半部
SPARC基于寄存器与零比较的条件分支格式
图 K.7 图 K.6 四类主要格式之外的其他指令格式。有些与核心格式十分相似,只是把寄存器字段用于其他用途。Power 还包含多种向量操作格式。

与基础 32 位体系结构不同,microMIPS64、RV64GC、Thumb-2 的 16 位扩展着重最小化代码。因此,虽然指令少得多,格式反而更多:microMIPS64、RV64GC 分别有八种和七种主要格式,Thumb-2 有十五种。图 K.8 显示,它们具有不同数量的寄存器操作数(0–3 个)、不同大小的立即数字段,甚至不同宽度的寄存器指定符。大多数指令只访问少量寄存器,较少的指令才可访问全部 32 个寄存器。

体系结构操作码位数:主/扩展寄存器指定符:个数 × 位宽立即数字段位数典型指令
microMIPS646无10跳转
microMIPS6461 × 55寄存器—寄存器操作,32 个寄存器;以 SP 为基址的加载,目的寄存器不限
microMIPS6461 × 37等于/不等于零的分支;以 GP 为基址的加载
microMIPS646:42 × 3寄存器—寄存器,rd/rs1 与 rs2;八个寄存器
microMIPS646:12 × 33寄存器—寄存器立即数,rd/rs1 与 rs2;八个寄存器
microMIPS6462 × 34加载和存储;八个寄存器
microMIPS646:42 × 3寄存器—寄存器,rd 与 rs1;八个寄存器
microMIPS6462 × 5寄存器—寄存器;32 个寄存器
RV64GC2:311跳转
RV64GC2:31 × 37分支
RV64GC2:31 × 38立即数操作,一个源寄存器
RV64GC2:31 × 56以 SP 为基址的存储
RV64GC2:31 × 56ALU 立即数,以及以 SP 为基址的加载
RV64GC2:42 × 5寄存器—寄存器操作
RV64GC2:32 × 35使用八个寄存器的加载和存储
Thumb-23:22 × 35移位、传送、字/字节加载和存储
Thumb-23:21 × 38立即数加、减、传送、比较
Thumb-24:11 × 38以 SP 为基址的加载/存储,对 SP 或 PC 做加法,多寄存器加载/存储
Thumb-24:33 × 3寄存器变址加载
Thumb-24:48条件分支、系统指令
Thumb-24:12杂项:22 条指令、12 种格式,包括比较零并分支、寄存器压栈/出栈、调整栈指针、字节反转、IF-THEN
Thumb-251 × 38PC 相对加载
Thumb-2511无条件分支
Thumb-26:13 × 3加/减
Thumb-26:31 × 4、1 × 3特殊数据处理
Thumb-26:42 × 3逻辑数据处理
Thumb-26:61 × 4分支并切换指令集:ARM 与 Thumb
图 K.8 microMIPS64、RV64GC、Thumb-2 的 16 位指令格式。如果有一个目的、两个源操作数,但只有两个寄存器字段,就将其中一个寄存器同时作为源和目的。扩展操作码或功能字段有时与立即数字段重叠,甚至相同。RV64GC 和 microMIPS64 的格式全部列出;Thumb-2 的杂项包括 22 条指令、12 种稍有差异的格式,这里用扩展操作码表示,但其中少数指令具有立即数或寄存器字段。

指令

各体系结构的相似性,让我们能够同时介绍它们,先从与 RISC-V 64 位 ISA 等价的操作开始。

RV64G 核心指令

RV64G 几乎每条指令,都能在其他体系结构中找到对应操作,如图 K.9–K.19 所示;RISC-V 指令定义见 A.9 节。分为四类:数据传送(图 K.9)、算术和逻辑(图 K.10)、控制(图 K.11、K.12)、浮点(图 K.13)。

若一条 RV64G 核心指令在其他体系结构中需要短指令序列合成,图 K.9–K.13 用分号分隔该序列。为避免混淆,本附录总将目的寄存器写在最左边,不受各体系结构通常记法的影响。

数据传送指令ARMv8(R-I)MIPS64(R-I)Power(R-I、R-R)RV64G(R-I)SPARC(R-I、R-R)
有/无符号字节加载LDR_BLB_LBZ; EXTSBLB_LD_B
有/无符号半字加载LDR_HLH_LHA/LHZLH_LD_H
字加载LDRSW/LDRLW_LW_LW_LD_W
双字加载LDRXLDLDLDLDD
单/双精度浮点寄存器加载LD_L_C1LF_FL_LD_F
字节存储STBSBSTBSBSTB
半字存储STWSHSTHSTHSTH
字存储STLSWSTWSWST
双字存储STXSDSDSDSTD
单/双精度浮点存储ST_S_C1STF_FS_ST_F
加载保留LDEXB, LDEXH, LDEXW, LDEXDLL, LLDlwarx, ldarxLR
条件存储STEXB, STEXH, STEXW, STEXDSC, SCDstwcx, stdcxSC
读/写特殊寄存器MF_, MT_MF, MT_M_SPRcsrr_, csrr_iRD__, WR__
整数寄存器传送到浮点寄存器ITOFSMFC1/DMFC1STW; LDFSSTW; FLDWXST; LDF
浮点寄存器传送到整数寄存器FTTOISMTC1/DMTC1STFS; LWFSTWX; LDWSTF; LD
数据/指令流同步DSB, ISBSYNC, SYNCISYNC, ISYNCFence, Fence.iMEMBAR, FLUSH
原子操作LDWAT, LDDAT, STWAT, STDATLLWP, LLDP, SCWP, SCDPAMOSWAP.W/D, AMOADD.W/D, AMOAND.W/D, AMOXOR.W/D, AMOOR.W/D, AMOMIN_.W/D, AMOMAX_.W/DCASA, SWAP, LDSTUB
图 K.9 与 RV64G 核心等价的桌面 RISC 数据传送指令。合成序列用分号分隔。MIPS 和 Power 的原子操作指令加载并有条件地存储一对寄存器,中间至多加入一条 ALU 指令,就能实现 RV64G 原子操作。SPARC 的 compare-and-swap、swap、LDSTUB 可以原子更新存储单元,用于构造 RV64G 操作。原图注称 Power3 依功能字段提供与 RV64G 相同的全部功能。

译注:图 K.9 的助记符按原表保留,包括 RV64G 栏的 STH、FLDWX、FSTWX、LDW,以及 MIPS 两行寄存器传送的名称与方向。这张跨体系结构概要表含版本混用和疑似笔误,不能将每个单元格直接作为可汇编代码。R-I、R-R 分别指寄存器—立即数和寄存器—寄存器格式。

比较与条件分支

每种体系结构都必须提供比较和条件分支。尽管它们有诸多相似之处,具体方法却各不相同。图 K.11 汇总控制指令,图 K.12 说明条件分支的处理。

SPARC 使用程序状态字中传统的四个条件码位:负、零、进位、溢出。任意算术或逻辑指令都可设置它们;与早期体系结构不同,每条指令是否设置条件码是可选的,显式选项可以减少流水线实现的问题。条件码既可作为操作的副作用设置,也可通过以 r0 为目的寄存器的减法来合成显式比较。条件分支检查条件码,判断各种无符号及有符号关系。浮点使用独立条件码编码 IEEE 754 条件,需要浮点比较指令。

SPARC 第 9 版从四方面扩展分支:为 64 位操作增加独立条件码;增加直接检查寄存器是否等于、不等于、小于、小于等于、大于等于或小于等于零的分支;增加三组浮点条件码;在分支指令中编码静态分支预测。1

Power 也采用四个条件码:小于、大于、等于和汇总溢出,但有八组副本。这使不同指令可使用不同条件码而不冲突,相当于多出八个 4 位寄存器。比较可以写入任意一组,条件分支也可读取任意一组。整数指令的选项位产生这样的效果:仿佛整数操作后面跟着一次与零比较,并设置第一组条件“寄存器”。

浮点指令也可选择设置第二组。PowerPC 允许对这八组条件码寄存器执行逻辑运算 CRAND、CROR、CRXOR、CRNAND、CRNOR、CREQV,让一个分支检测更复杂条件。Power 还包含分支计数寄存器,测试时自动递减,并可参与分支条件;另有专用指令用于读写条件寄存器。

RISC-V 与 MIPS 最相似。RISC-V 将完整的算术比较与分支结合;MIPS 也使用比较并分支,但比较限于相等以及与零比较。这种限制简化了分支判断,因为判断条件无需 ALU 操作,代价是有时必须先使用“小于则置位”指令 SLT、SLTI、SLTU、SLTIU:比较两个操作数,若前者小于后者,将目的寄存器置 1,否则置 0。更多细节见图 K.12。RISC-V 浮点比较将整数寄存器置为 0 或 1,再据此条件分支。MIPS 也使用独立浮点比较,把浮点寄存器置为 0 或 1,然后由浮点条件分支测试。

ARM 类似 SPARC,可选择设置传统四条件码。CMP 相减并据差设置条件码;CMN(compare negative)相加并据和设置条件码。TST 对两个操作数做 AND,设置除溢出以外的条件码;TEQ 用 XOR 设置前三个条件码。ARM 条件分支也根据条件码判断各类无符号及有符号关系。ARMv8 增加位测试指令,以及与零比较并分支。ARM 浮点比较设置整数条件码,由 B.cond 使用。

图 K.13 表明,五种体系结构的浮点支持也很相似。

算术/逻辑指令(各列均有 R-R、R-I 格式)ARMv8MIPS64Power v3RISC-VSPARC v9
字加法、立即数加法ADD, ADDIADDU, ADDUIADD, ADDIADDW, ADDWIADD
双字加法ADDXDADDU, DADDUIADD, ADDIADD, ADDIADD
减法SUB, SUBISUBU, SUBISUBFSUBW, SUBWISUB
双字减法SUBXDSUBU, DSUBUISUBFSUB, SUBISUB
乘法MUL, SMULMUL, MULU, DMUL, DMULUMULLW, MULLIMUL, MULU, MULW, MULWUMULX
除法MULX, SMULXDIV, DIVU, DDIV, DDIVUDIVWDIV, DIVU, DIVW, DIVWUDIVX
余数MOD, MODU, DMOD, DMODUMODSW, MODUWREM, REMU, REMW, REMWU
ANDAND, ANDIAND, ANDIAND, ANDIAND, ANDIAND
OROR, ORIOR, ORIOR, ORIOR, ORIOR
XORXOR, XORIXOR, XORIXOR, XORIXOR, XORIXOR
加载第 31–16 位MOVLUIADDISADDISSETHI (Bfmt.)
加载 PC 高位ADRADDIUPCADDPCISAUIPC
逻辑左移:字/双字,立即数/可变移位量LSLSLLV, SLLRLWINMSLL, SLLI, SLLW, SLLWISLL
逻辑右移:字/双字,立即数/可变移位量RSLSRLV, SRLRLWINM 32-iSRL, SRLI, SRLW, SRLWISRL
算术右移:字/双字,立即数/可变移位量RSASRAV, SRASRAWSRA, SRAI, SRAW, SRAWISRA
比较CMPSLT/U, SLTI/UCMP(I)CLRSLT/U, SLTI/USUBcc r0,...
图 K.10 与 RISC-V 整数 ISA 等价的桌面 RISC 算术/逻辑指令。MIPS 还提供算术溢出时触发陷阱的指令,其他体系结构需用多条指令合成。除 SPARC 外,各体系结构使用不同助记符标明立即数操作数;SPARC 提供立即数版本,但共用一个助记符,当然,操作码仍不同。

译注:图 K.10 原表存在多处助记符疑点,例如 ARM“除法”栏写 MULX, SMULX,RISC-V 栏写 ADDIS、SUBI、MULU 等,且部分 W/I 后缀顺序与附录 A 的写法不同。

控制指令ARMv8MIPS64PowerPCRISC-VSPARC v9
整数比较后分支B.cond, CBZ, CBNZBEQ, BNE, B_Z(<、>、≤、≥);或 S***; BEZBCBEQ, BNE, BLT, BGE, BLTU, BGEUBR_Z, BPcc(<、>、≤、≥、=、≠)
浮点比较后分支B.condBC1T, BC1FBCBEZ, BNZFBPfcc(<、>、≤、≥、= 等)
跳转、寄存器跳转B, BRJ, JRB, BCLR, BCCTRJAL, JALR,目的为 x0BA, JMPL r0,...
调用、寄存器调用BL, BLRJAL, JALRBL, BLA, BCLRL, BCCTRLJAL, JALRCALL, JMPL
陷阱SVC, HVC, SMCBREAKTW, TWIECALLTicc, SIR
中断返回ERETJR; ERETRFIEBREAKDONE, RETRY, RETURN
图 K.11 与 RV64G 等价的桌面 RISC 控制指令。

译注:原图把 EBREAK 放在 RISC-V“中断返回”行,存在明显功能分类疑点;保留原表,不应据此把断点指令用于中断返回。

条件分支特性ARMv8MIPS64PowerPCRISC-VSPARC v9
条件码位数:整数、浮点16,即 8 加其反值无两者均 8 × 4无整数 2 × 4,浮点 4 × 2
基本比较指令数:整数、浮点整数 1,浮点 1整数 1,浮点 1整数 4,浮点 2整数 2,浮点 3浮点 1
基本分支指令数:整数、浮点1整数 2,浮点 1两者共 1整数 4,也用于浮点结果整数 3,浮点 1
寄存器与寄存器/常数比较并分支—=、≠—=、≠、≥、<—
寄存器与零比较并分支—=、≠、<、≤、>、≥—=、≠、<、≤、>、≥=、≠、<、≤、>、≥
图 K.12 五种桌面 RISC 的条件分支方法。SPARC 的整数比较由设置条件码的算术指令合成,以 r0 为目的寄存器。

译注:图 K.12 的 ARMv8 条件码数量写作“16(8 加反值)”,与正文所述四个条件码位不一致;其“与零比较并分支”行也与图 K.11 的 CBZ、CBNZ 不一致。原表数字与空缺均保留。

浮点指令(均为 R-R 格式)ARMv8MIPS64PowerPCRISC-VSPARC v9
单/双精度加FADDADD.*FADD*FADD.*FADD*
单/双精度减FSUBSUB.*FSUB*FSUB.*FSUB*
单/双精度乘FMULMUL.*FMUL*FMUL.*FMUL*
单/双精度除FDIVDIV.*FDIV*FDIV.*FDIV*
单/双精度平方根FSQRTSQRT.*FSQRT*FSQRT.*FSQRT*
单/双精度乘加、负乘加FMADD, FNMADDMADD.*, NMAD.*FMADD*, FNMADD*FMADD.*, FNMADD.*
单/双精度乘减、负乘减FMSUB, FNMSUBMSUB.*, NMSUB.*FMSUB*, FNMSUB*FMSUB.*, FNMSUB.*
将单/双精度符号或反符号复制到另一浮点寄存器FMOV, FNEGFMOV.*, FNEG.*FMOV*, FNEG*FSGNJ.*, FSGNJN.*FMOV*, FNEG*
用符号位的 XOR 替换符号位,单/双精度FABSFABS.*FABS*FSGNJX.*FABS*
单/双精度最大/最小FMAX, FMINMAX.*, MIN.*FMAX.*, FMIN.*
单/双精度浮点值分类CLASS.*FCLASS.*
比较FCMPCMP.*FCMP*FCMP.*FCMP*
单/双精度浮点之间,或与有/无符号单字/双字整数之间的带舍入转换FCVTCVT, CEIL, FLOORFCVTF*TO*
图 K.13 与 RV64G ISA 等价的桌面 RISC 浮点指令;空白表示没有该指令。ARMv8 单、双精度共用助记符,由寄存器指定符表示精度;星号代指 S 或 D。浮点比较提供等于、不等于、小于、小于等于等条件。传送可以双向往返整数寄存器。分类指令根据值为正/负无穷、非规格化数、正/负零等来设置寄存器。符号注入指令接受两个操作数,主要用于构造浮点传送、取负和绝对值;其他 ISA 则用独立指令实现这些操作。

RV64GC 的核心 16 位指令

图 K.14–K.17 汇总 microMIPS64、RV64GC、Thumb-2 的数据传送、ALU 和控制指令。因为它们都基于完整体系结构的 32 位或 64 位版本,这里只关注 16 位指令实现的功能。浮点是可选项,因此不纳入这组比较。

数据传送指令microMIPS64:rs1;rs2/dst;偏移位数RV64GC:rs1;rs2/dst;偏移位数Thumb-2:rs1;rs2/dst;偏移位数
字加载8;8;48;8;58;8;5
双字加载8;8;5
以栈指针为基址的字加载1;32;51;32;61;3;8
以栈指针为基址的双字加载1;32;6
字存储8;8;48;8;58;8;5
双字存储8;8;5
以栈指针为基址的字存储1;32;51;32;61;3;8
以栈指针为基址的双字存储1;32;6
图 K.14 与 RV64GC 16 位 ISA 等价的嵌入式 RISC 数据传送指令;空白表示没有对应的 16 位指令。表中不列助记符,而依次列出地址计算可选基址寄存器数量、加载目的或存储源寄存器数量、地址立即数字段位数。例如加载的 8;8;5 表示八个基址、八个目的寄存器、5 位偏移量;存储则表示数据可来自八个寄存器之一。Thumb-2 还具有 32 位指令,但不是完整 ARMv8;RV64GC 和 microMIPS64 分别具有 RV64I、MIPS64 的完整 32 位指令。

译注:Thumb-2 两处 1;3;8 均为原表数字,未将 3 擅改为其他寄存器数量。

ALU 指令/功能microMIPS64RV64GCThumb-2
加载立即数8;732;68;8
加载高位立即数32;6
立即数加法32;432;68;8;3
32 位字立即数加法并符号扩展32;6
栈指针加立即数1;91;6,增加立即数的 16 倍1;7
栈指针加立即数,结果存入寄存器1;8;61;8;6,增加立即数的 4 倍
逻辑左/右移8;8;3,末项为移位量8;6,末项为移位量8;8;5,末项为移位量
算术右移8;6,末项为移位量8;8;5,末项为移位量
AND 立即数8;8;48;68;8
传送32;3232;3216;16
加法8;8;832;328;8;8 或 16;16
AND、OR、XOR8;88;88;8
减法8;8;88;88;8;8
32 位字加/减并符号扩展8;8
图 K.15 RV64GC 的 ALU 指令,以及 microMIPS64、Thumb-2 的 16 位指令中存在的对应功能。每项先给出可选源/目的寄存器数量,再给出立即数字段位数,如有。栈指针加缩放立即数用于调整栈指针,或创建指向栈中某位置的指针。Thumb 加法有两种形式:三个操作数均来自八寄存器子集 Lo,或仅有两个操作数但可用全部 16 个寄存器。
控制操作microMIPS64RV64GCThumb-2
无条件分支10 位偏移量11 位偏移量11 位偏移量
无条件分支并链接11 位偏移量11 位偏移量
无条件寄存器分支,带/不带链接任意 32 个寄存器之一任意 32 个寄存器之一
寄存器与零比较,等于/不等于时分支八个寄存器;7 位偏移量八个寄存器;8 位偏移量无,但见图注
图 K.16 三种嵌入式 RISC 的条件分支方法。空白表示不存在该指令。Thumb-2 使用四个条件码位,提供检查这四位的条件分支,分支偏移量为 8 位。

RV64G 之外的共同扩展

图 K.15–K.18 列出图 K.9–K.13 未包含的指令,仍按数据传送、ALU 和控制等类别组织。2 唯一显著的浮点扩展是倒数指令,MIPS64 和 Power 都支持。某条指令只有出现在不止一种标准体系结构中,才列入这些表。

回顾 K-6 页的图 K.3,各指令集支持的寻址方式比 RV64G 丰富。采用额外方式的加载和存储未列入图 K.17,但实际上也构成额外数据传送指令:ARM 有 64 条,Power3 有 12 条,MIPS64、SPARCv9 各有四条。

功能定义ARMv8MIPS64PowerPCSPARC v9
多寄存器加载/存储加载或存储至少两个寄存器加载寄存器对、存储寄存器对多寄存器加载/存储,至多 31 个寄存器
缓存操作与预取修改缓存行状态或预取PrefetchCACHE、PREFETCHPrefetchPrefetch
图 K.17 RISC-V 核心没有、但至少两种桌面体系结构具有的数据传送指令。SPARC 要求存储访问对齐;其他体系结构支持非对齐访问,但经常有很大性能代价,也可能用较慢机制处理。MIPS 提供非对齐访问指令:LDL、LDR,即左/右双字加载,成对加载非对齐的字;对应存储执行逆操作。Prefetch 发起缓存预取;CACHE 允许用户有限控制缓存状态。
名称定义ARMv8MIPS64PowerPCSPARC v9
延迟分支带/不带撤销的延迟分支BEQ, BNE, BGTZ, BLEZ, BCxEQZ, BCxNEZBPcc,A; FPBcc,A
条件陷阱条件为真时触发陷阱TEQ, TNE, TGE, TLT, TGEU, TLTUTW, TD, TWI, TDITcc
图 K.18 RV64G 核心没有、但至少两种其他体系结构具有的控制指令。MIPS64 Release 6 同时有非延迟与普通延迟分支;SPARC v9 则有根据静态预测进行撤销的延迟分支。

现代处理器使用动态分支预测来加速分支,见 3.3 节。许多体系结构早期支持延迟分支,后续版本将其删除或基本淘汰,通常提供非延迟版本作为首选条件分支。

SPARC 的“撤销”分支优化了延迟分支:只有分支跳转时才执行延迟槽指令,否则撤销它。因此,可以安全地把分支目标指令复制进延迟槽,因为它只在跳转时执行。限制是目标不能又是一条分支,且编译时必须知道目标。SPARC 还提供非延迟跳转,因为设置 annul 位的无条件分支不执行下一条指令。

与完整 ISA 之间的差异相比,三种嵌入式 ISA 的 16 位子集,除了前面图中列出的立即数字段、SP 和其他寄存器使用等区别外,基本没有显著差异。

共同点已经介绍完,下面转向独有特性。先讲桌面/服务器 RISC,按描述独特特性所需篇幅由短到长排列,再讲嵌入式 RISC。

MIPS64 R6 独有的指令

MIPS 指令集经历六代。第 1–4 代主要增加指令;Release 6 删除许多旧指令,同时增加非延迟分支和非对齐数据访问支持。图 K.19 汇总其独有指令。

指令类别指令名称功能
ALUByte align从一对寄存器提取由若干字节组成的字或双字,用于非对齐字节复制
ALUAlign Immediate to PC将 PC 的高 16 位与左移 16 位的立即数相加,结果放入寄存器,用于形成 PC 相对地址
ALUBit swap反转寄存器中每个字节内的位顺序
ALUNo-op and link将 PC+8 写入寄存器
ALULogical NOR对两个寄存器计算 NOR
控制转移Branch and Link conditional寄存器与零比较,条件为真则分支;将返回地址放入链接寄存器
控制转移Jump indexed、Jump and link indexed偏移量与寄存器相加形成新 PC,可带或不带链接地址
图 K.19 MIPS64 R6 提供的额外指令。另外还有若干支持虚拟机的指令,大多为特权指令。

SPARC v9 独有的指令

SPARC 有几项独特特性。下面先介绍其中的主要特性,再用一张表汇总这些特性及其他较小差异。

寄存器窗口

SPARC 最主要的独特特性是寄存器窗口(register windows),它通过优化过程调用来减少寄存器与存储器之间的数据传送。处理器有多组寄存器,每次过程调用分配一组新寄存器。这样做原本可能限制过程调用的深度,但把这些寄存器组作为循环缓冲区使用即可避免这一限制。成本与性能曲线的拐点似乎在 6–8 组;调用栈更深的程序需要把寄存器内容保存到存储器,并在需要时恢复。

SPARC 可以有 2–32 个窗口,全局变量、局部变量、传入参数和传出参数通常各用 8 个寄存器。

每个窗口有 16 个不与其他窗口共用的寄存器,因此 SPARC 实现的物理寄存器数最少可以是 40 个,最多可以是 520 个;迄今大多数实现有 128–136 个。SPARC 没有把窗口切换绑定到调用和返回指令,而是提供独立的 SAVE 与 RESTORE 指令。SAVE 通过指向下一组寄存器来“保存”调用者的窗口,同时执行一次加法。巧妙之处在于,加法的源寄存器来自调用者窗口,目的寄存器却属于被调用者窗口。SPARC 编译器通常用这条指令改变栈指针,为新栈帧中的局部变量分配空间。RESTORE 与 SAVE 相反:恢复调用者窗口,同时执行加法;源寄存器来自被调用者窗口,目的寄存器属于调用者窗口。这样便自动释放栈帧。编译器还可以用它生成被调用过程的最终返回值。

寄存器窗口的风险是,寄存器数量增加可能降低时钟频率。不过,早期实现并未出现这种情况。自 1987 年起,带寄存器窗口的 SPARC 体系结构和不带寄存器窗口的 MIPS R2000 体系结构,都采用过多种工艺实现。在若干代产品中,同等工艺的 SPARC 实现并未比 MIPS 的时钟频率低,这可能是因为这些实现中,缓存访问时间比寄存器访问时间更具决定性。多发射需要多得多的寄存器端口;加上寄存器重命名或重排序缓冲区之后,寄存器窗口的代价变得更大。寄存器窗口是最早的 Berkeley RISC 设计的特性,SPARC 正是受这些设计启发而采用它。在本书所述时期仍在使用的其他主要体系结构中,只有 Tensilica 也采用寄存器窗口;RISC-V ISA 没有纳入这一特性。

快速陷阱

SPARC v9 提供了加快陷阱处理的支持。它把单级陷阱扩展到至少四级,使寄存器窗口上溢和下溢的陷阱处理程序也能被中断。增加这些级别后,处理程序就不必在代码中显式检查缺页或栈指针未对齐的情况,因此可以执行得更快。体系结构增加两条指令来从这种多级处理程序返回:RETRY 会重新执行被中断的指令,DONE 则不会。为支持用户级陷阱,RETURN 指令可以在非特权模式下从陷阱返回。

对 LISP 和 Smalltalk 的支持

剩下最主要的算术特性是带标记的加法和减法。SPARC 的设计者花了相当多时间研究 LISP、Smalltalk 等语言,这影响了前面已经讨论的若干 SPARC 特性:寄存器窗口、条件陷阱指令、使用 32 位指令地址的调用,以及多字算术运算,参见 Taylor 等人 [1986] 和 Ungar 等人 [1984]。体系结构为带标记的数据类型提供少量支持,可以进行加法、减法,进而进行比较。最低两位用于标识操作数是否为整数,整数编码为 00。因此,只要任一操作数没有标为整数,或者结果过大,TADDcc 和 TSUBcc 就会设置溢出位。随后的条件分支或陷阱指令决定下一步怎么处理。如果操作数不是整数,软件就恢复操作数、检查其类型,并根据类型调用正确的运算。未对齐存储器访问陷阱也可以用于带标记数据,因为用标记错误的指针进行加载可能属于非法访问。图 K.20 展示这两种标记支持。

SPARC 带标记算术与指针访问
图 K.20 SPARC 用最低两位为带标记算术指令编码不同数据类型。(a)整数的加法、减法或比较:只要操作数和结果都是整数,运算就只需一个周期。(b)通过有效指针加载:未对齐陷阱可捕获非法存储器访问,例如误把整数用作指针。对于 LISP 这类具有成对数据的语言,偏移量 −3 可访问一对数据中的偶数字(CAR),偏移量 +1 可访问奇数字(CDR)。

图中整数标记为 00,有效指针标记为 11;Word address 表示字地址。示例指令分别为 TADDcc r7, r5, r6 和 LD rD, r4, −3。

图 K.21 汇总上面介绍的额外指令及其他若干指令。

指令类别指令名称功能
数据传送SAVE, RESTORE保存或恢复寄存器窗口
数据传送Nonfaulting load加载指令的一种变体,地址异常不会引发故障,允许对加载进行推测执行
ALUTagged add、Tagged subtract,带陷阱和不带陷阱两种形式执行带标记加/减法,设置条件码,并可选择触发陷阱
控制转移Retry, Return, Done支持陷阱处理
浮点FMOVcc根据整数或浮点条件码,在浮点寄存器之间进行条件传送
图 K.21 SPARC v9 提供的额外指令。寄存器窗口虽是其中最显著的区别,却不需要很多指令!

ARM 独有的指令

较早的 ARM 体系结构版本 ARM v6 和 v7 具有许多不同寻常的特性,包括所有指令都能条件执行,以及把 PC 当作通用寄存器。这些特性在 ARMv8 中被移除,32 位和 64 位 ISA 都是如此。不过,至少从指令集规模来看,它仍保留了相当大的复杂性。如第 K-6 页的图 K.3 所示,ARM 的寻址方式最多,包含表中列出的全部方式。要记住,这些寻址方式使它比 RVG 多出数十条加载/存储指令,即使后面的表格没有逐一列出。第 K-8 页的图 K.6 还表明,ARMv8 的指令格式数量远远最多,既反映了指令种类的多样性,也反映了寻址方式的差异,其中某些寻址方式适用于一些加载/存储指令,却不适用于另一些。

大多数 ARMv8 ALU 指令允许在完成运算之前先对第二个操作数移位。这扩大了立即数的取值范围,但可移位的操作数不限于立即数。可选操作包括逻辑左移、逻辑右移、算术右移和循环右移。此外,与 Power3 一样,大多数 ALU 指令可以选择是否设置条件标志。图 K.22 列出了额外的指令,但没有枚举所有变体,例如选择设置条件标志的形式;详见图注。

尽管所有指令都能条件执行这一特性已被取消,ARMv8 除前面提到的条件传送和条件置位之外,仍提供多种条件指令。

指令类别指令名称功能
数据传送Load/Store Non-temporal pair加载/存储一对寄存器,并指示不要缓存这些数据;只支持基址加按比例缩放偏移量寻址
ALUAdd Extended word/double word对第二个寄存器操作数左移并扩展后,把两个寄存器相加
ALUAdd with shift;add immediate with shift先对第二个操作数移位,再相加
ALUAddress of page根据 PC 计算页地址,类似 ADDUIPC;原书称其与 ARMv8 的 ADR 相同
ALUAND、OR、XOR、XOR NOT shifted register对一个寄存器和一个经过移位的寄存器进行逻辑运算
ALUBit field clear shifted对操作数移位、取反,再与另一个操作数相与
ALUConditional compare、immediate、negative、negative immediate条件为真时,把条件标志设置为比较结果;否则保持条件标志不变
ALUConditional increment、invert、negate根据条件,将目的寄存器设为源寄存器加一、按位取反或取负的结果
ALUCRC计算 CRC 校验和,支持字节、字、半字和双字
ALUMultiply add、subtract整数乘加或乘减
ALUMultiply negate将两个整数的乘积取负,支持字和双字
ALUMove immediate or inverse用立即数替换寄存器中的 16 位,立即数可能先经过移位
ALUReverse bit order反转寄存器中的位顺序
ALUSigned bit field move传送有符号位字段,向左作符号扩展,向右补零
ALUUnsigned divide、multiply、multiply negate、multiply-add、multiply-sub基本指令的无符号版本
控制转移CBNZ, CBZ与零比较并按不等/相等条件分支,同时指示这不是调用或返回
控制转移TBNZ, TBZ测试寄存器中的某一位不等于/等于零,并据此分支
图 K.22 ARMv8 的 AArch64 指令集提供的额外指令。除非另有说明,凡字和双字有区别的指令都提供这两种格式。大多数 ALU 指令可以选择是否设置条件码,这些变体没有作为单独指令列在本表或前面的表中。

译注: Address of page 一行把页地址计算与 ADR 混为一谈;条件比较一行“否则保持条件标志不变”的描述也不宜直接当作指令手册的精确定义。

Power3 独有的指令

Power3 源于 IBM 多代商用 RISC 计算机——IBM RT/PC、IBM Power1 和 IBM Power2——以及主要由 IBM、Motorola 开展的 PowerPC 开发工作。下面先介绍分支寄存器和循环分支支持,随后图 K.23 列出只有 Power3 提供的其他指令。

分支寄存器:链接寄存器与计数寄存器

Power3 不占用 32 个通用寄存器之一来保存过程调用的返回地址,而是把地址放入专用的链接寄存器。许多过程在返回前不会调用其他过程,因此并非总要把链接寄存器的值另存起来。把返回地址放在专用寄存器中还能加快返回跳转,因为硬件处理这种跳转时不必经过寄存器读取流水级。

类似地,Power3 还有一个计数寄存器,用于执行固定次数迭代的 for 循环。使用专用寄存器后,分支硬件可以快速判断基于计数寄存器的分支是否可能跳转,因为在执行周期的早期就能知道该寄存器的值。分支指令测试计数寄存器的值时,会自动将它减一。

计数寄存器和链接寄存器本来就位于控制分支的硬件附近;而分支预测的问题之一,是在流水线中尽早得到目标地址,见附录 C。因此,Power 的设计者决定让这两个寄存器再承担一种用途:任意一个都可保存条件分支的目标地址。于是,PowerPC 在基本条件分支之外增加了从这两个寄存器取目标地址的指令 BCLR 和 BCCTR。图 K.23 列出所增加的数十条指令;此外还应注意,它为十进制浮点数提供了丰富的功能。

指令类别指令名称功能
数据传送LHBRX, LWBRX, LDBRX加载半字/字/双字,同时反转字节顺序
数据传送SHBRX, SWBRX, SDBRX存储半字/字/双字,同时反转字节顺序
数据传送LDQ, STQ在存储器与一对寄存器之间加载/存储四字
ALUDRAN在寄存器中生成随机数
ALUCMPB比较寄存器中的各个字节,并逐字节设置另一个寄存器
ALUCMPRB将字节 xx 与另外两个字节 yy、zz 比较,并设置条件,指示是否满足 y≤x≤zy\leq x\leq z
ALUCRAND, CRNAND, CROR, CRNOR, CRXOR, CREQV, CORC, CRANDC对条件寄存器进行逻辑运算
ALUZCMPEQB将字节 xx 与另一个寄存器中的 8 个字节比较,并设置条件,指示 xx 是否等于其中任意一个
ALUEXTSWSL对字作符号扩展并左移
ALUPOPCNTB, POPCNTW, POPCNTD分别统计每个字节、每个字或一个双字中 1 的个数;字节/字的统计结果放入对应的另一字节/字
ALUPRTYD, PRTYW计算字或双字中各字节的奇偶校验
ALUBPERMD置换双字中的位,生成一个经置换的字节
ALUCDTBCD, CDCBCD, ADDGCS转换为/转换自二进制编码十进制数(BCD),或对两个 BCD 值进行运算
控制转移BA, BCA无条件或有条件地分支到绝对地址
控制转移BCCTR, BCCTRL有条件地分支到计数寄存器中的地址,不带/带链接
控制转移BCTSAR, BCTARL有条件地分支到分支目标地址寄存器中的地址,不带/带链接
控制转移CLRBHRB, MFBHRBE操作分支历史滚动缓冲区
浮点FRSQRTE估算平方根的倒数
浮点FTDIV, FTSQRT检查除零或对负数求平方根的情况
浮点FSEL将寄存器与零比较,从两个操作数中选择一个传送
浮点Decimal floating point operations一组共 48 条指令,支持十进制浮点运算
图 K.23 Power3 提供的额外指令。循环移位指令有设置条件寄存器和不设置条件寄存器两种形式。另有一组字符串指令,可以从任意地址向一组寄存器加载最多 32 字节;这些指令将在未来实现中逐步淘汰,因此这里仅作提及。

译注: 本表助记符依原页保留,包括 DRAN、CORC、ZCMPEQB、BCTSAR 等可疑拼写。原表 FTSQRT 功能写作 “square of negative number”,结合该行的平方根指令名译为“对负数求平方根”;并未把这些源书拼写视为已校正的汇编语法。

桌面/服务器 RISC 的多媒体扩展指令

对多媒体和图形操作的支持经历了若干阶段,起点是 1996 年出现的 Intel MMX、MIPS MDMX 和 SPARC VIS。正如 4.3 节所述——这里假定读者已读过该节——这些扩展把一个寄存器视为多个相互独立的短整数,每个为 8 位或 16 位,并对寄存器内的全部元素并行执行算术和逻辑运算。这些最初的 SIMD 扩展有时称为打包 SIMD(packed SIMD)。2000 年以后,它们通过加宽寄存器、将这些寄存器部分或全部与通用寄存器或浮点寄存器分离,以及增加并行浮点运算支持,得到进一步发展。RISC-V 为这类打包 SIMD 指令预留了扩展,但设计者目前选择把重点放在真正的向量扩展上。向量扩展 RV64V 是一种向量体系结构;正如 4.3 节指出的,真正的向量指令集通用得多,通常能够用向量运算完成 SIMD 扩展所处理的操作。

图 K.24 展示 ARM、MIPS、Power 和 SPARC 的 SIMD 扩展的基本结构。注意这些 SIMD“向量寄存器”的组织方式不同:复用浮点寄存器、扩展浮点寄存器,或增加额外寄存器。其他重要区别还包括:是否同时支持浮点数和整数,是否支持 128 位整数,以及整数和逻辑运算是否允许把立即数字段用作操作数。SIMD 寄存器与存储器之间的数据传送使用标准加载和存储指令,同时增加特殊扩展来处理不足一个完整 SIMD 寄存器的数据。SPARC VIS 是最早用于图形的 ISA 扩展之一,能力要有限得多:算术运算只包含加、减、乘,没有浮点支持,针对位元素操作的指令也很有限。图 K.24 包含它,但后面不再详述。

项目ARMv8MIPS64 R6Power v3.0SPARC v9
ISA 扩展名称Advanced SIMDMIPS64 SIMD ArchitectureVector FacilityVIS
当前版本年份2011201220151995
向量寄存器:数量 × 位数32 × 12832 × 12832 × 12832 × 64
复用 GP/FP 寄存器还是独立寄存器组扩展 FP 寄存器,宽度加倍扩展 FP 寄存器,宽度加倍独立与 FP 寄存器相同
整数位数8、16、32、648、16、32、648、16、32、64、1288、16、32
浮点位数32、6432、6432
整数与逻辑运算的立即数算术 5 位;逻辑 8 位
图 K.24 面向多媒体的 SIMD 扩展结构。最后一行指出 SIMD 指令集是否支持立即数,例如向量加立即数或向量与立即数;支持者列出立即数位数。是否带立即数编码在操作码空间内,也可以将这些形式作为额外指令列入下一张表。Power 3 除向量功能外,还有可选的 Vector-Scalar Extension;该扩展定义一组与浮点寄存器及普通向量寄存器重叠的向量寄存器,省去了向向量寄存器来回传送数据的需要,并支持双精度浮点运算。

图 K.25 展示这些 SIMD 扩展中的算术指令,只列出至少两种扩展都具有的指令。MIPS SIMD 还有许多其他指令,Power 3 的 Vector-Scalar Extension 也是如此,这里不作介绍。其中一种常见、但通用微处理器通常不具备的功能是饱和运算。饱和意味着,计算溢出时把结果设为最大正数或最小负数,而不像补码算术那样进行模运算。这类饱和运算常见于数字信号处理器,见下一小节,对于滤波程序很有用。另一种常见扩展是在单个寄存器内部累积数值的指令,点积以及最大值/最小值指令就是典型例子。

指令类别ARM Advanced SIMDMIPS SIMDPower Vector Facility
加/减16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
饱和加/减16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
差的绝对值16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
相邻元素加/减,成对操作16B、8H、4W16B、8H、4W16B、8H、4W、2D
平均值16B、8H、4W、2D16B、8H、4W、2D、Q
点积加、点积减16B、8H、4W16B、8H、4W16B、8H、4W、2D
有符号/无符号除法16B、8H、4W16B、8H、4W、2D16B、8H、4W、2D、Q
有符号/无符号乘法16B、8H、4W16B、8H、4W16B、8H、4W、2D
乘加、乘减16B、8H、4W16B、8H、4W16B、8H、4W、2D
有符号/无符号最大值16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
有符号/无符号最小值16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
有符号/无符号取模16B、8H、4W、2D16B、8H、4W、2D、Q
相等比较16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
小于/小于等于比较,有符号/无符号16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
图 K.25 SIMD 算术指令汇总。B 为字节(8 位),H 为半字(16 位),W 为字(32 位),D 为双字(64 位),Q 为四字(128 位)。因此,8B 表示一条指令对 8 个字节进行运算。某些指令,如相邻加/减或乘法,结果宽度是输入的两倍,例如对 16 个字节作乘法,得到 8 个半字结果。点积是乘法与累加。SPARC VIS 主要面向图形,其指令也按这一目标组织。

除算术指令外,最常见的增加内容是逻辑和按位操作,以及对 SIMD 寄存器内元素进行各种置换与打包的指令。图 K.26 汇总了这些扩展。最后,三种扩展都支持 SIMD 浮点操作,如图 K.27 所示。

指令类别ARM Advanced SIMDMIPS SIMDPower Vector Facility
右移/左移,逻辑/算术16B、8H、4W、2D16B、8H、4W、2D、Q16B、8H、4W、2D、Q
统计前导零或尾随零16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
AND/OR/XORQQQ
位插入与提取16B、8H、4W、2D16B、8H、4W、2D16B、8H、4W、2D、Q
统计 1 的个数16B、8H、4W、2D16B、8H、4W、2D、Q
交织偶数/奇数、左侧/右侧元素16B、8H、4W、2D6B、8H、4W、2D
打包偶数/奇数元素16B、8H、4W、2D6B、8H、4W、2D
Shuffle16B、8H、4W、2D16B、8H、4W、2D
SPLAT16B、8H、4W、2D16B、8H、4W、2D
图 K.26 逻辑、按位、置换以及打包/解包指令汇总,格式与上一图相同。只有单个操作对象时,指令作用于整个寄存器;对于逻辑运算,这种区分没有影响。Interleave 将两个寄存器的元素组合成一个值,所取元素可为全部偶数、奇数、最左侧或最右侧元素,可用于解包。Pack 把两个寄存器的偶数或奇数元素分别移入结果的左半部分和右半部分。Shuffle 根据掩码为每个元素选择来源,从两个寄存器构造结果。SPLAT 把一个值复制到寄存器中的每个元素。

译注: Power 列中两处 6B 与同列其他行的 16B 不一致。

指令类别ARM Advanced SIMDMIPS SIMDPower Vector Facility
浮点加、减、乘、除4W、2D4W、2D4W、2D
浮点乘加/乘减4W、2D4W、2D4W、2D
浮点最大值/最小值4W、2D4W、2D4W、2D
浮点平方根与平方根的倒数4W、2D4W、2D4W、2D
浮点比较4W、2D4W、2D4W、2D
浮点数与整数相互转换4W、2D4W、2D4W、2D
图 K.27 浮点操作汇总,格式与上一图相同。

译注: 图 K.24 对 Power Vector Facility 只列 32 位浮点数,而本表又列出 2D。图 K.25–K.27 是原书的概括性比较,不宜当作完整的 ISA 支持清单。

嵌入式 RISC 的数字信号处理扩展指令

Thumb2 和 microMIPS32 都提供 DSP(数字信号处理)及多媒体操作指令。在 Thumb2 中,这些属于核心指令集;在 microMIPS32 中,它们属于 DSP 扩展。这些扩展编码为 32 位指令,其功能范围小于 MIPS64 或 ARMv8(AArch64)的 SIMD/向量扩展所提供的多媒体和图形支持。与后者那些更全面的扩展一样,Thumb2 和 microMIPS32 也采用打包 SIMD,但使用现有整数寄存器,仅作少量扩充来支持宽累加器,而且只操作整数数据。RISC-V 已规定,P 扩展将使用浮点寄存器支持打包整数 SIMD。

不过在本书出版时,该规范尚未完成。

DSP 操作经常包括线性代数函数和卷积等运算,其中间结果需要比输入更大的表示范围。Thumb2 用一组基于成对整数寄存器、产生 64 位结果的操作来处理这一问题。microMIPS32 DSP 有 4 个 64 位累加器寄存器,其中包括原本用于整数乘除的 Hi-Lo 寄存器。两种体系结构都对字节、半字和字提供并行算术,类似于 ARMv8 和 MIPS64 的多媒体扩展。此外,MIPS DSP 扩展还处理 DSP 运算大量使用的定点小数数据。这类数据有一个符号位,其余位表示小数部分。

其取值范围用十进制近似表示为 −1.0 到 0.9999。MIPS DSP 支持 Q15 和 Q31 两种定点小数格式,分别包含 1 个符号位以及 15 位或 31 位小数。

图 K.28 使用图 K.25 相同的记法列出共同操作。应记住,基本的 32 位指令集还提供其他功能,包括基本算术、逻辑和位操作。

功能Thumb-2microMIPS32 DSP
加/减4B、2H4B、2Q15
饱和加/减4B、2H4B、2Q15、Q31
交换后加/减:交换 rt 中两个半字,对第一个半字作加法、第二个作减法;可选择饱和2H
加法规约,即对各值求和4B
绝对值2Q15、Q31
降低/提高数值精度2B、Q15、2Q15、Q31
左/右移,逻辑/算术,可选择饱和4B、2H
乘法2H2B、2H、2Q15
乘加/乘减,在 MIPS 中写入 GPR 或累加器2H2Q15
复数乘法步骤:两次乘法加一次加/减法2H2Q15
乘法并累加,通过加法或减法累积2HQ15、Q31
位复制B、H
比较 =、<、<=,设置条件字段4B、2H
Pick:根据条件位,从两个操作数中选择字节或半字4B、2H
Pack:从每个操作数中选择一个半字进行打包H
Extract:提取Q63
与累加器之间传送DW
图 K.28 两种嵌入式 RISC 的 DSP 操作汇总,列出每种操作的数据类型。空白表示不能用一条指令完成该操作。字节量通常是无符号的。“复数乘法步骤”实现复数乘法,每个分量都是 Q15 值。ARM 使用标准条件寄存器,MIPS 则在 DSP 扩展的状态中增加一组条件位。

结束语

本节概述了 8 种 RISC 体系结构的寻址方式、指令格式和几乎全部指令。虽然后半部分着重讨论差异,但如果它们没有如此多的相似之处,就不可能在这么少的篇幅内介绍 8 种体系结构。事实上,我们估计,无论哪一种体系结构,所执行指令中超过 90% 都能在图 K.9–K.13 中找到。为了与这种一致性对照,图 K.29 用类似图 K.1 的格式,汇总了 20 世纪 70 年代的四种体系结构。

这些体系结构无法用同样的方式在一节中统一介绍,因此后面三节分别讨论 80x86、VAX 和 IBM 360/370。在计算史上,从来没有出现过像 20 世纪 80 年代 RISC 思想兴起后这样,对计算机体系结构达成如此广泛共识的时期。

项目IBM 360/370Intel 8086Motorola 68000DEC VAX
发布年份1964/1970197819801977
指令长度,位16、32、488、16、24、32、40、4816、32、48、64、808、16、24、32、…、432
寻址:位数与模型24 位,平坦/31 位,平坦4+16 位,分段24 位,平坦32 位,平坦
数据须对齐?360 是,370 否否按 16 位边界对齐否
数据寻址方式数2/359=14
保护页无可选页
页大小2 KB、4 KB—0.25–32 KB0.5 KB
I/O专用操作码专用操作码存储器映射存储器映射
整数寄存器:数量、模型、位数16 个 GPR × 32 位8 个专用数据寄存器 × 16 位8 个数据寄存器及 8 个地址寄存器 × 32 位15 个 GPR × 32 位
独立浮点寄存器4 × 64 位可选:8 × 80 位可选:8 × 80 位0
浮点格式IBM,十六进制浮点IEEE 754 单精度、双精度、扩展精度IEEE 754 单精度、双精度、扩展精度DEC
图 K.29 四种 20 世纪 70 年代体系结构的汇总。与图 K.1 中的体系结构不同,这些体系结构在任何类别上都很少一致。80x86 的更多细节见 K.3 节,VAX 的说明见 K.4 节。

  1. 原文的 SPARC 比较关系列表重复列出“小于等于”,与图 K.12 所列六种关系不完全一致。 ↩︎

  2. 原文称图 K.15–K.18 为共同扩展,但 K.15、K.16 属于前面介绍的压缩指令核心,K.17、K.18 才列出共同扩展;同时原文说“四类”却只列出数据传送、ALU、控制三类。 ↩︎

表格阅读