CPU指令流和数据流

1 阅读8分钟

cpu的核心功能就是指令流控制和数据流控制,我们先介绍一下指令类型。

1、指令类型

1.1、运算指令

算数运算:

  • 加:ADD ADC ADDS ADCS(后缀S表示更新标志位,后文会有说明)
  • 减:SUB SBC SUBS SBCS
  • 乘:MUL
  • 除:
  • 比较:CMP

逻辑运算:

  • 与:AND ANDS
  • 或:ORR ORRS
  • 非:NOT
  • 异或:EOR EORS

移位操作:

  • 逻辑左移:SHL
  • 逻辑右移:SHR
  • 算术左移:SAL
  • 算术右移:SAR

1.2数据加载指令

ARM寄存器属于精简指令集(RISC),不能对内存中的地址直接进行运算,需要现将对应地址的数据读取到寄存器上在进行运算。ADR和LDR属于伪指令,ADR 实际上是一个基于 PC 的加/减法指令。它算出的地址是“当前 PC + 偏移量”。

将地址加载到寄存器:ADR

将地址中的数据加载到寄存器:LDR

1.3跳转指令

跳转指令是计算机实现逻辑流控制的核心指令。

流水线冒险 (Pipeline Hazard) :当跳转指令执行并修改 PC 时,已经进入取指/译码阶段的后续指令会失效,这被称为“跳转开销”。

无条件跳转:

  • B lable 直接跳过去,不返回
  • BL lable 跳过去并保存返回地址

有条件跳转:

该指令根据上一条指令的执行结果所设置的标志位来运行。标志位有四种:Z(为零)、N(为负)、C(进位)、V(溢出)。上一条指令一般是CMP 或SUBS。

A. 基础状态类(直接观察 Z 和 N)

这类指令最简单,只看结果是不是零,或者最高位是不是 1。

指令描述标志位条件
BEQ相等 / 结果为 0Z=1Z=1
BNE不相等 / 结果非 0Z=0Z=0
BMI负数 (Minus)N=1N=1
BPL非负数 (Plus)N=0N=0

B. 算术溢出类(检查 V 和 C)

V 针对有符号数溢出,C 针对无符号数进位/借位。

指令描述标志位条件
BVS有符号溢出 (V set)V=1V=1
BVC无符号无溢出 (V clear)V=0V=0
BCS / BHS进位置位 / 大于等于C=1C=1
BCC / BLO进位清零 / 小于C=0C=0

C. 无符号数比较(Unsigned)

主要依赖 CZ

指令描述标志位条件
BHI高于 (Higher)C=1C=1Z=0Z=0
BHS高于或等于 (Higher or Same)C=1C=1
BLO低于 (Lower)C=0C=0
BLS低于或等于 (Lower or Same)C=0C=0Z=1Z=1

D. 有符号数比较(Signed)

如果发生了溢出(V=1V=1),符号位(NN)其实是反的。所以只有当 N 和 V 状态一致时,才说明真正的结果是大于等于 0。

指令描述标志位条件
BGT大于 (Greater Than)Z=0Z=0N=VN=V
BGE大于等于 (Greater or Equal)N=VN=V
BLT小于 (Less Than)NVN \neq V
BLE小于等于 (Less or Equal)Z=1Z=1NVN \neq V

1.4 关机指令

  • HLT :让cpu停下来不再取下一条指令。

2、CPU单个指令的执行流程

首先介绍一下CPU的基本模块。CPU中主要的模块就是下图这些,实际的电路非常多无法全部展现,仅展示下文会遇到的一些核心逻辑。

image-20260303214633720.png 控制器(CU)* *:**记录更新当前的指令执行阶段,控制其他硬件的行为。

程序计数器(PC): 记录当前指令所在的地址,自动+4到下一指令地址。其存储的是代码段中的地址,一个程序开始执行的第一条指令地址是默认的值(0x00000000),之后默认+4到下一条指令。

MAR寄存器: 连接内存,决定了 CPU 的寻址能力。例如 32 位 MAR 决定了 4GB4GB 的物理空间

  • 取址周期:读取PC中的地址并传给内存(这个内存是指L1缓存),让内存读取具体的指令并写回MBR寄存器
  • 解码周期:接收IR寄存器中要读取的操作数地址并传给内存,让内存将数据写入MBR寄存器(只有在下文“数据加载指令”时才用到)

指令寄存器: 存放要执行的具体指令

指令译码器: 解析IR中的指令,控制ALU要进行的运算类型、打开通用寄存器组到ALU的通路

ALU运算单元: 进行算数和逻辑运算,更新状态寄存器

状态寄存器: 作为跳转指令执行的判断依据

PC多路选择器: 控制PC寄存器的值,从默认的+4(下一条指令)和跳转指令指定的跳转地址选择其一

通用寄存器组: r0-r13 共14个通用寄存器,用来存储数据

一个指令的执行一般需要4个时钟周期,对应执行过程中的取值、译码、执行和写回第一节中提到的四种指令类型不同的类型在CPU内的执行流是不同的,接下来我们也会按照指令类型介绍各自的指令流。

2.1运算指令

运算指令:

image-20260303215056782.png

①取址:将当前要读取的指令地址发给MAR寄存器自加4,MAR寄存器通知内存,内存收到后读取改地址的数据并写入MBR寄存器,MBR寄存器再写入IR。

②译码:IR拿到指令后,指令译码器开始工作分析出要执行的指令和数据所在的寄存器。将指令告诉ALU,并通知存储数据的寄存器将其和ALU之间的通路打开。

③执行:ALU拿到数据和指令并开始计算

④写回:计算完成后将数据写入目标寄存器,根据指令类型(S位)决定是否更新标志位。状态寄存器的更新直接影响了 跳转指令的“执行”判断

数据加载指令:

image-20260303215132923.png

①取址:同上

②译码:IR拿到指令后,指令译码器开始工作分析出当前指令需要将内存中的数据读到某个寄存器。

③执行:指令译码器将指令中的偏移量传给ALU(指令中的地址是偏移量而非真实地址),ALU计算出完整地址再传给MAR寄存器,MAR寄存器再通知内存,内存则将数据写入MBR寄存器。 如果是写数据(寄存器->内存),就是MAR寄存器告诉内存要将数据写到哪个地方,内存去MBR寄存器读取这个数据并写入内存。

④写回:MBR寄存器拿到数据后写入目标寄存器。

跳转指令:

image-20260303215555852.png

①取址:同上

②译码:IR拿到指令后,指令译码器开始工作分析出当前指令需要根据标志位来判断是否进行跳转(更改PC程序计数器的地址值)。

③执行:状态寄存器根据指令读取的标志位判断是否需要跳转,如果不跳转就结束。反之则将信息传递给ALU,ALU计算出PC寄存器需要怎么修改地址(加多少或者减多少)并发给PC多路选择器,PC多路选择器修改PC程序计数器的值。

④写回:不做具体事项

停机/关机/系统控制指令:

image-20260303215909682.png

①取址:同上

②译码:IR拿到指令后,指令译码器开始工作分析出当前指令是关机指令。

③执行:通知PC程序计数器不再取下一条指令。

④写回:不做具体事项

3.1指令

image-20260304211333862.png

ADDS r1 r2 r3

①其中的ADDS再指令中对应27-26和24-21和20位这些位;这样细分是为了减少译码器的负担。

  • 27-26 表示指令大类

    • 00 :数据运算指令
    • 01:数据传送指令
    • 10:跳转指令、协处理器指令
    • 11:额外扩展指令
  • 24-21表示大类下的具体指令 ADD SUB等

  • 20 S位:是否更新标志位,ADDS就置为1,ADD置为0

②r1是目标寄存器,对应图中的r目的

③r2是操作数1,对应图中r源1

④r3是操作数2,他的含义受#号位(25位的控制)

  • #=1 表示立即数

  • #=0 表示寄存器地址(0-3位)和移位类型(5-6位),其又根据第4位决定其移位长度从哪读取:

    • 第四位=1:8-11位表示一个立即数,该立即数就是要移位的长度
    • 第四位=0:8-11位表示一个移位寄存器地址,其值即为要移位的长度

⑤:还有一个条形码(28-31位),其决定该指令是否要执行,主要是为了避免指令跳转,指令跳转后其已经执行的流水线会立即作废,因此我们可以通过这个控制某个指令是否执行:比如if(a=b)后面有五条指令要执行,if这个指令之前写一个CMP a b并更新标志位,那我们在后面的这几条指令的条形码中就可以写入0000(代表相等才执行)。

到这就结束了,上面的内容是根据《计算机组成原理》和与AI的咨询整理的,各位大佬如果又发现什么问题,请指出来,我核对一下进行修改。