本文声明:内容来源于网络,进行整合/再创作;部分内容由AI辅助生成。
ARM微处理器主要包含3级指令流水线、5级指令流水线、7级指令流水线、8级指令流水线和13级指令流水线这5个流水线。本节着重讲述3级、5级指令流水线。
3级指令流水线
到ARM7为止的ARM处理器使用简单的3级流水线,它包括下列流水线级:
① 取指令(fetch):从寄存器装载一条指令。
② 译码(decode):识别被执行的指令,并为下一个周期准备数据通路的控制信号。在这一级,指令占有译码逻辑,不占用数据通路。
③ 执行(excute):处理指令并将结果写回寄存器。
![]()
3级指令流水线——指令执行过程

3级指令流水线——指令执行示意图
当处理器执行简单的数据处理指令时,流水线使得平均每个时钟周期能完成1条指令。但1条指令需要3个时钟周期来完成,因此,有3个时钟周期的延时(latency),但处理器吞吐率(throughput)是每个周期1条指令。
5级指令流水线
所有的处理器都要满足对高性能的要求,在ARM核中使用的3级流水线的性价比是很高的。但是,为了得到更高的性能,需要重新考虑处理器的组织结构。有两种方法来提高性能:
- 提高时钟频率。时钟频率的提高,必然引起指令执行周期的缩短,所以要求简化流水线每一级的逻辑,流水线的级数就要增加。
- 减少每条指令的平均指令周期CPI(Cycles Per Instruction),即通过优化手段降低处理器执行每条指令所需的时钟周期,从而提升程序运行效率。在3级流水线ARM中,有些复杂指令需要多个时钟周期才能完成,会导致指令流水线停顿,降拖慢整体执行速度。为此,可以改进多周期指令的实现方式,让它们占用更少的周期完成;或者减少因指令依赖、资源冲突等原因造成的流水线停顿;也可以同时采用这两种策略,从而更有效地提升效率。
3级指令流水线ARM核在每一个时钟周期都访问存储器,或取指令(拿代码),或传输数据(读写变量)。为了降低 CPI(即提升处理速度),存储系统必须跟上CPU的节奏,不能让CPU干等。这就要求存储器在一个时钟周期内,必须能够提供超过1个的数据项(即同时满足“取指令”和“传数据”的需求)。要实现这个“一周期双输出”的目标,主要有两种技术手段:
- 加大数据带宽(更宽的存储器总线):将存储器的数据位宽从32位增加到64/128位。这样,一次访存就能取出两条或更多条指令,或者一个更大的数据块。
- 采用哈佛架构或分离的存储器接口:为指令和数据分别提供独立的缓存、访问通路。这样,CPU可以一边从指令区读代码,一边在数据区读写变量,互不干扰,从而提升效率。
在ARM9TDMI中使用了典型的5级流水线,5级流水线包括下面的流水线级:
①取指令(fetch):从存储器中取出指令,并将其放入指令流水线。
②译码(decode):指令被译码,从寄存器堆中读取寄存器操作数。在寄存器堆中有3个操作数读端口,因此,大多数ARM指令能在1个周期内读取其操作数。
③执行(execute):将其中1个操作数移位,并在ALU中产生结果。如果指令是Load或Store指令,则在ALU中计算存储器的地址。
④(访存)数据/缓冲(data/buffer):如果需要则访问数据存储器,否则ALU只是简单地缓冲1个时钟周期。
⑤回写(write-back):将指令的结果回写到寄存器堆,包括任何从寄存器读出的数据。
![]()
5级指令流水线——执行过程

5级指令流水线——指令执行示意图
3级与5级指令流水线的比较
AArch32执行状态下,在程序执行过程中,程序计数寄存器(ProgramCounterRegister,PC)值是基于3级指令流水线操作特性的。在ARM处理器中,程序计数器PC的值并不是简单地指向当前正在执行的指令地址,而是受到流水线结构的影响。
早期的ARM处理器采用3级指令流水线(取指 → 译码 → 执行)。由于在取指阶段就提前读取下一条指令,所以当某条指令在执行时,PC实际上已经指向下下条指令了,即“当前指令地址 + 8(因为每条ARM指令占4字节,+8表示跳过了两条指令)。因此,在3级流水线中,软件看到的PC值总是“超前”当前执行指令8个字节(PC + 8)。
5级指令流水线(取指 → 译码 → 执行 → 访存 → 写回)本由于流水线更深,PC的“超前量”可能会不同(比如变成+12)。为了保持软件兼容性,ARM在设计5级流水线时特意做了处理:通过额外的硬件逻辑,在取指阶段计算出 PC+4(即下一条指令的地址),并把这个值直接传递到译码阶段,跳过中间的流水寄存器延迟。这样一来,当指令在译码或执行阶段读取R15时,看到的值仍然是“PC+ 8”,和3级流水线的行为完全一致。

3级与5级指令流水线的比较
然而,在 AArch64 状态下,ARM 架构师对程序计数器(PC)进行了彻底的重构,以剥离历史包袱并简化处理器架构模型。
PC 不再是一个通用寄存器,因此软件无法直接通过 MOV PC, R0 这样的指令修改执行流,而必须使用专用的分支指令(如 B、BR、RET)来实现跳转。这一改动简化了流水线的控制逻辑,并减少了分支预测错误的风险。
此外,彻底消除了历史遗留的偏移量——在 AArch64 中,当指令读取 PC 时(例如通过 ADR 指令获取当前地址),其值指向的是当前正在执行的指令的地址,而非像 AArch32 那样超前 8 个字节。这极大简化了位置无关代码(PIC)的编写,开发者可以直接通过 ADR X0, 标签 获取绝对地址,而无需手动计算令人困惑的 +8 或 +12 补偿。
注意,硬件自动更新机制依然存在,即执行完当前指令后,PC 会自动增加 4 字节以指向下一条指令,但关键在于 AArch64 的架构手册明确规定了读取 PC 的语义,将其从微架构的实现细节中彻底剥离,使得程序行为更加直观和可预测。

