CHAPTER 03 从代码到执行

指令与汇编.

从一行 C 代码出发,理解指令格式、寄存器、数据寻址与程序跳转。

6 个学习小节基于 54 页课件更新于 2026-10-23
已完成 0 / 6 节进度保存在当前浏览器

这一章沿着一个问题展开:x = a + b 到了 CPU 里,究竟会发生什么? 先认识指令,再理解编码和地址,最后读懂一段有条件分支的程序。处理器型号年表略去,发展史只保留能解释设计选择的部分。

01
THE CONTRACT

指令、汇编与 CPU

指令集规定软件可以要求什么;CPU 用电路实现这些约定。

机器指令用二进制表示加法、读写数据、比较和跳转等操作。汇编语言用助记符和寄存器名称表达这些操作,汇编器再把真实指令编码成机器码。汇编还可以提供伪指令,一条伪指令可能展开成多条机器指令。

C 等高级语言描述要完成的任务汇编指令操作与操作数机器指令规定的二进制编码CPU 执行电路实现操作

这是便于理解的典型主线,实际工具链还包括链接、装载等步骤,编译器也可以直接生成目标代码。

ISA 与 CPU 实现

ISA(指令集架构)规定指令的可见行为,还包括寄存器、数据类型、编码、寻址和异常等规则。流水线、执行单元和缓存如何组织,属于实现层面。同一套 ISA 可以有不同的 CPU 实现。

寄存器 REGISTER

CPU 内部的小型快速存储

保存正在使用的数据、中间结果,也可以保存地址。$t0、$s1 是寄存器的名称。

内存 MEMORY

通过地址访问的存储空间

存放程序与数据。本课 MIPS 按字节编址,一个 32 位字占 4 个连续字节。

从一个加法开始

add $t0, $t1, $t2    # $t0 ← $t1 + $t2

MIPS 的这种写法是目的在前、来源在后。计算时读取两个来源,结果覆盖目的寄存器。一个 C 变量在某段代码中使用哪个寄存器,由编译器安排。

MIPS 采用 load/store 结构:普通整数加法使用寄存器数据;内存数据通过专门的加载、存储指令读取和写入。这里说的是数据访问,CPU 还需要读取指令本身。

动手推演 / 01

看数据一步步流动

逐条执行
指令 PC = 0x00001000
    寄存器
    名称值
    内存中的字 地址为十进制;每个字占 4 字节
    尚未执行

    加法结果先保存在寄存器中,执行 sw 后才写回内存。

    必要的发展史:CISC 与 RISC

    CISC 的一个方向是增加指令功能,让单条指令承担更多工作,并兼顾已有程序的兼容性。对实际程序的观察推动了 RISC 思路:优先处理常用操作,强调规整格式、寄存器计算和 load/store 分工,以便高效实现。

    它们是设计取向。现代实现相互吸收技术;实际性能还受 CPU 内部结构、内存访问和程序行为影响。本课采用的经典 MIPS 指令固定为 32 位,不能把这一条件推广到所有 RISC 架构与扩展。

    02
    INSTRUCTION & DATA

    指令格式与数据

    一条指令需要说明操作、输入、结果位置,以及怎样继续执行。

    操作码说明做什么,地址码描述操作对象。地址码可以指定寄存器、涉及内存地址,也可以直接携带常数。顺序执行时,下一条指令地址通常由 CPU 隐含推算;转移指令则提供改变执行位置的信息。

    地址个数:统计显式指定的操作数字段

    形式示意写法含义
    三地址add R0, R1, R2R0 ← R1 + R2
    二地址ADD R1, R2R1 ← R1 + R2,其中一个来源兼作目的
    一地址ADD AAC ← AC + 内存[A],累加器 AC 是约定的位置
    零地址ADD默认取栈顶两个数,再把和压回栈顶

    上表比较不同机器风格的教学语法;本课 MIPS 的普通寄存器加法采用三地址形式。零地址统计显式字段,参与运算的数据仍可以隐含存在。

    显式字段少可以节省编码空间;字段多能更灵活地指定来源和去向。程序的总指令数与执行时间还取决于具体操作和实现。

    字节、字与大小端

    1 字节 = 8 位本课 1 字 = 32 位 = 4 字节相邻地址相差 1 字节

    一个从地址 0x1000 开始存放的字占用 0x1000 至 0x1003。大端把最高有效字节放在低地址,小端把最低有效字节放在低地址;变化的是字节排列。

    动手推演 / 02

    一个数,四个字节

    内存视图

    按相同规则读回整个字,数值保持不变;这里没有反转单个字节内部的位。

    03
    THE 32-BIT LANGUAGE

    MIPS 指令编码

    32 位编码空间有限。不同格式,把空间分配给不同的信息。

    MIPS 有 32 个通用寄存器,指定一个需要 5 位,因为 2⁵ = 32。机器码存的是编号:$t0 = 8、$t3 = 11、$s1 = 17。

    R 型op 6 │ rs 5 │ rt 5 │ rd 5 │ shamt 5 │ funct 6以寄存器运算为例:两个来源、一个目的,以及具体操作。
    I 型op 6 │ rs 5 │ rt 5 │ immediate 16给立即数、数据地址偏移量或分支偏移量留出空间。
    J 型op 6 │ target 26把更多编码空间用于构造跳转目标。

    R 型:先认清角色,再放进字段

    add $t0, $t3, $s1
    # 汇编顺序:目的 rd、来源 rs、来源 rt
    # 字段顺序:op、rs、rt、rd、shamt、funct

    本例字段为 0 | 11 | 17 | 8 | 0 | 32。op 和 funct 共同确定运算:add 的 funct 是 32,sub 是 34,两者 op 都是 0。其他 R 型指令会按自己的语义使用这些字段。

    I 型:同一个字段,作用随指令变化

    指令rsrt16 位字段
    addi提供加数接收结果参与加法的常数
    lw提供基址接收读取的数据字节偏移量
    sw提供基址提供要写入的数据字节偏移量
    beq比较来源比较来源以 4 字节为单位的分支偏移量

    本课的 addi、lw、sw 使用有符号 16 位立即数,范围是 −32768~32767,使用前按符号扩展。I 型字段怎样解释由具体指令规定,例如逻辑立即数指令有不同规则。

    动手推演 / 03

    组装一条机器指令

    R 型
    32 位机器码

    04
    FIND THE DATA

    数据寻址与数组

    寄存器里的数与这个数所指向的内存内容,是两层不同的信息。

    假设 R1 = 1000,从内存地址 1000 开始的字为 42,从地址 1004 开始的字为 7。下面用 内存[地址] 表示读取该地址处的一个字。

    寻址方式怎样取得操作数本例的值
    立即数直接使用指令里的常数 10001000
    寄存器使用 R1 的值1000
    直接内存[1000]42
    寄存器间接内存[R1]42
    基址加偏移内存[R1 + 4]7

    存储器间接寻址多一层取地址:若内存[800] = 1000、内存[1000] = 42,就先访问 800 取得地址 1000,再到 1000 取出数据 42。这种计数指的是取数据过程中的内存访问,未计取指令与缓存实现细节。

    有效地址 EA:先算位置,再按指令读写

    EA = 基址寄存器的值 + 有符号字节偏移量
    addi $t0, $s1, 4    # 计算一个数:$s1 + 4
    lw   $t0, 4($s1)    # 计算地址后,读取该处的一个字
    sw   $t0, 4($s1)    # 计算地址后,把 $t0 写入该处

    加载和存储可以使用相同的地址算法,数据流向由操作码决定。lw 读取后保留内存原值,sw 写入后保留源寄存器的值。

    数组下标,要换成字节偏移

    A[i] 的地址 = 数组基地址 + i × 每个元素的字节数

    本课每个字占 4 字节,所以 A[12] 相对数组起点的偏移量为 12 × 4 = 48 字节。变址寻址常用于改变索引、遍历数组;复合寻址可以组合“基址 + 索引 × 比例 + 固定偏移”。哪些项能放进一条指令由 ISA 决定,MIPS 的 lw/sw 直接提供“寄存器基址 + 常数偏移”。

    动手推演 / 04

    从下标走到内存地址

    4 字节 / 元素

    把一行 C 代码拆开

    # $s0 保存 x;$s1 保存数组 A 的基地址
    # C:A[100] = x - A[12];
    lw  $t0, 48($s1)       # 取 A[12]
    sub $t0, $s0, $t0      # 计算差值
    sw  $t0, 400($s1)      # 写回 A[100]
    05
    FIND THE NEXT INSTRUCTION

    分支与跳转

    数据寻址决定去哪里取数;指令寻址决定程序到哪里继续。

    以下统一把 PC 定义为当前分支或跳转指令的地址。本课指令长 4 字节,顺序位置是 PC + 4。例如 0x1000 后面的指令依次位于 0x1004、0x1008、0x100C。

    beq:比较寄存器,按相对距离分支

    beq $t0, $t1, TARGET    # 相等时转移到 TARGET

    TARGET 是指令位置的标签,汇编器会计算它对应的偏移字段。beq 属于 I 型,两个寄存器都提供比较数据。

    目标地址 = PC + 4 + 有符号 offset × 4

    例如当前地址 0x1000、目标 0x1010,字段应为 (0x1010 − 0x1004) ÷ 4 = 3。偏移量为负时能回到前面的指令,这为循环提供了基础。16 位有符号字段对应相对 PC+4 约 ±128 KiB 的范围,精确字节位移为 −131072~131068。

    经典 MIPS 的延迟槽

    本讲的经典 beq 和 j 在完成转移前,先执行紧随其后的一条指令。初学示例把空操作 nop 放在这里。它影响执行顺序,目标地址计算公式保持不变。具体架构版本与教学模拟器设置需分别确认。

    j:拼接出跳转目标

    J 型的 26 位目标字段用于构造地址。指令地址按 4 字节对齐,因此最低 2 位为 00,再从 PC+4 取最高 4 位,拼成 32 位地址。

    PC+4 高 4 位4 位目标字段26 位002 位

    这种方式称为伪直接寻址,可以在 PC+4 所在的 256 MiB 对齐区域内选择目标。这里的运算是拼接;分支公式中的运算则是相加。

    动手推演 / 05

    亲手算一个跳转目标

    地址推演
    计算出的目标地址

    指令地址计算偏移量解释
    lw / sw基址寄存器值 + 偏移量字节,直接相加
    beqPC + 4 + 偏移量 × 4以 4 字节为单位
    j高 4 位 + 目标字段 + 00 的位拼接按拼接规则构造地址
    06
    PUT IT ALL TOGETHER

    用一段程序,检查理解

    先独立推演,再检查答案。做错的地方,就是最值得回看的那个步骤。

    综合例子中,$s1 = 1000(十进制数组基址),$s0 = 20(x 的值),A[2] = 7,A[5] = 99。每个元素占 4 字节,左侧指令地址为十六进制。

    0x1000:       lw  $t0, 8($s1)
    0x1004:       beq $s0, $t0, END
    0x1008:       nop
    0x100C:       sub $t1, $s0, $t0
    0x1010:       sw  $t1, 20($s1)
    0x1014: END:  nop

    也可以回到第一个演示,选择“带条件的数组写入”逐条核对。该演示支持延迟槽,并可修改 x 与 A[2] 的值。

    01 零地址加法怎样取得操作数?
    02 0x12345678 按小端存于 0x1000,地址 0x1001 的字节是什么?
    03 sub $s1, $t0, $t3 的 rs、rt、rd 依次是哪三个寄存器?
    04 综合例子的第一条 lw 访问哪个数据地址?
    05 按初始条件执行完整程序,A[5] 的最终值是多少?
    06 综合例子中 beq 的 16 位偏移字段应填多少?
    07 从初始状态重新执行,只把 $s0 改成 7,A[5] 最后是多少?
    08 beq 在 0x2000,偏移字段为 −3,条件成立时目标地址是多少?
    09 j 的字段左移 2 位后为 0x00002000,PC+4 的高 4 位为 0x8,目标地址是多少?

    共 9 题,答案只保存在当前浏览器。

    查看综合程序对应的 C 代码
    if (x != A[2]) {
        A[5] = x - A[2];
    }

    C 在“不相等”时进入代码块;这段汇编在“相等”时跳过代码块。读分支时,要同时看比较条件和目标位置。

    REFERENCES & NOTES

    来源与适用范围

    依据课件《3指令与汇编-1.pdf》整理,实际内容覆盖 3.1 指令系统的发展、3.2 指令格式、3.3 寻址方式。目录中的 3.4、3.5 尚未在该文件展开。讲解采用经典 32 位定长 MIPS;具体架构扩展和模拟器设置可能有不同约定。

    对课件中的简写作了补全:分支以当前指令地址加 4 为基准;J 型高 4 位来自 PC+4;立即数字段的解释由具体指令决定。RISC 的规整格式是设计取向,不代表所有 RISC 扩展都采用同一种指令长度。

    MIPS32 指令手册 · BEQ(印刷页 55) ↗MIPS32 指令手册 · J(印刷页 115) ↗
    本章结束 / KEEP EXPLORING返回课程目录 ↗