计算机组成知识点整理(2):指令系统

Last updated on April 1, 2025 pm

这是SJTU-ICE2603《计算机组成》课程的知识点整理系列。本文整理部分为“第2章:指令系统”。

2.1 RISC-V 指令集

  • 典型 RISC 架构:定长指令、精简指令集、32个通用寄存器

RISC-V操作数

  • 下面两张表是重点

RISC-V汇编语言1

RISC-V汇编语言2

2.2 操作数

2.2.1 寄存器操作数

  • RISC-V 体系中有 32 个 64 位寄存器(字表示 32 位
  • RISC-V 按单字节寻址连续双字的地址相差 8
    • 如下标 8 对应的偏移量是 64
  • RISC-V 无对齐限制,即双字的起始地址不一定是 8 的倍数

  • 访问寄存器比访问存储器快
  • 对存储器数据进行操作需要取数和存数

2.2.2 大端与小端存储

  • RISC-V 采用小端模式,即低位字节位于字中的低地址
  • 大端模式:高位字节位于低地址

  • 例:存放二进制数 0001-0010-0011-0100-0101-0110-0111-1000
  • 小端模式:
地址 0 1 2 3
数值 0111-1000 0101-0110 0011-0100 0001-0010
  • 大端模式:
地址 0 1 2 3
数值 0001-0010 0011-0100 0101-0110 0111-1000

2.3 数字的表示

  • nn 位有符号整数
    • x=xn12n1+xn22n2++x121+x020x = -x_{n-1} 2^{n-1} + x_{n-2} 2^{n-2} + \cdots + x_1 2^1 + x_0 2^0
    • 表示范围:2n12n11-2^{n-1} \sim 2^{n - 1} - 1
  • 有符号数取负:按位取反再加 1
  • 符号扩展(用更多的位表示一个数):把符号位复制到左边

2.4 指令格式

RISC-V指令格式

  • opcode:操作码

  • funct:功能码(扩展操作码)

  • rs:源操作数寄存器

  • rd:目的操作数寄存器

  • S 型指令中,rs1 是基地址寄存器,rs2 是源操作数寄存器

2.5 条件操作

2.5.1 if 语句

  • 例:假设 f\mathtt{f}j\mathtt{j} 保存在 x19\mathtt{x19}x23\mathtt{x23}
1
2
if (i == j) f = g + h;
else f = g - h;
1
2
3
4
5
      bne x22, x23, Else
add x19, x20, x21
beq x0, x0, Exit // 无条件跳转
Else: sub x19, x20, x21
Exit:

2.5.2 循环语句

  • 例:假设 i\mathtt{i}x22\mathtt{x22} 中,k\mathtt{k}x24\mathtt{x24} 中,save\mathtt{save} 的地址在 x25\mathtt{x25}
1
while (save[i] == k) i += 1;
1
2
3
4
5
6
7
Loop: slli x10, x22, 3
add x10, x10, x25
ld x9, 0(x10)
bne x9, x24, Exit
addi x22, x22, 1
beq x0, x0, Loop
Exit:
  • 基本块:只有一个入口(第一个语句)和一个出口(最后一个语句)的指令序列
    • 没有分支(除非在末尾)
    • 没有分支目标(除非在开头)

2.6 过程调用

2.6.1 步骤及寄存器约定

  • 六个步骤:将参数放在过程可以访问到的位置 \rightarrow 获取过程所需的存储空间 \rightarrow 执行过程中的操作 \rightarrow 将结果值放在调用程序可以访问到的位置 \rightarrow 将控制返回到初始点

  • 寄存器约定:

    • x10x17\mathtt{x10} \sim \mathtt{x17}:参数寄存器,用于传递参数或返回值
    • x1\mathtt{x1}:返回地址寄存器,用于返回到起始点
    • x5x7\mathtt{x5} \sim \mathtt{x7}x28x31\mathtt{x28} \sim \mathtt{x31}: 临时寄存器,被调用者不需要保留其中的值
    • x8x9\mathtt{x8} \sim \mathtt{x9}x18x27\mathtt{x18} \sim \mathtt{x27}: 保存寄存器,如用到这些寄存器,被调用者需先保存原值,用完再恢复原值

RISC-V寄存器约定

2.6.2 过程指令

  1. 过程调用:跳转-链接(jal\mathtt{jal}
1
jal x1, ProcedureLabel
  • 将下一条指令的地址(PC + 4)保存在 x1\mathtt{x1}
  • 跳转到目标地址
  1. 过程返回:寄存器跳转-链接(jalr\mathtt{jalr}
1
jalr x0, 0(x1)
  • 跳转到 0 + x1\mathtt{x1} 中保存的地址
  • x0\mathtt{x0} 用作目的寄存器(实际 x0\mathtt{x0} 不会被改变)
  • 可用于 case / switch 语句

2.6.3 叶过程的汇编代码

  • 例:假设 f\mathtt{f} 保存在 x20\mathtt{x20} 中,x5\mathtt{x5}x6\mathtt{x6} 保存临时变量
1
2
3
4
5
long long int leaf_example (long long int g, long long int h,  long long int i, long long int j) {
long long int f;
f = (g + h) - (i + j);
return f;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
leaf_example:
addi sp,sp,-24 // 把x5, x6, x20的值存到栈中
sd x5,16(sp)
sd x6,8(sp)
sd x20,0(sp)
add x5,x10,x11 // x5 = g + h
add x6,x12,x13 // x6 = i + j
sub x20,x5,x6 // f = x5 – x6
addi x10,x20,0 // 将f复制到返值寄存器
ld x20,0(sp) // 从栈中恢复x5, x6, x20的值
ld x6,8(sp)
ld x5,16(sp)
addi sp,sp,24
jalr x0,0(x1) // 返回到调用者

过程调用之前、之中和之后栈的分配情况

  • 栈指针sp\mathtt{sp})指向栈顶
  • 帧指针fp\mathtt{fp}x8\mathtt{x8})指向帧的第一个双字(通常是保存的参数寄存器)
  • 注意,栈向低地址方向扩展

2.6.3 非叶过程的汇编代码

  • 调用者需要在栈中保存:返回地址、调用后还需要的参数和临时变量

  • 例:

1
2
3
4
long long int fact (long long int n) { 
if (n < 1) return f;
else return n * fact(n - 1);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fact:
addi sp,sp,-16 // 将返回地址和n保存到栈中
sd x1,8(sp)
sd x10,0(sp)
addi x5,x10,-1 // x5 = n - 1
bge x5,x0,L1 // 若n >= 1,则跳转到L1
addi x10,x0,1 // 否则,将返值置1
addi sp,sp,16 // 出栈,此处不需要恢复原值
jalr x0,0(x1) // 返回
L1: addi x10,x10,-1 // n = n - 1
jal x1,fact // 调用fact(n-1)
addi x6,x10,0 // 将fact(n - 1)的结果存到x6
ld x10,0(sp) // 恢复调用者的n
ld x1,8(sp) // 恢复调用者的返回地址
addi sp,sp,16 // 出栈
mul x10,x10,x6 // 返回n * fact(n-1)
jalr x0,0(x1) // 返回

过程调用中的保存和不保存对象

2.6.4 内存布局

程序和数据的RISC-V内存分配

  • 一个可执行的程序要包括:指令段、数据段、堆栈段
  • 全局指针 gp\mathtt{gp} 指向静态数据区

2.7 寻址模式

RISC-V指令格式

2.7.1 大立即数(32位常量)

1
lui rd, constant
  • U 型指令
  • 加载 20 位常量到 rd[31:12],符号扩展 rd[63:32]
  • 将 rd[11:0] 清零

2.7.2 分支寻址

  • SB 型指令
  • PC 相对寻址:目标地址 = PC + 立即数 × 2
    • 立即数表示偏移的半字数,即只能跳转到偶数地址
    • 跳转范围:40964094-4096 \sim 4094

2.7.3 跳转寻址

  • UJ 型指令
  • jal:PC 相对寻址;jalr:绝对地址
  • 对于长跳转(32 位地址),lui 将 address[31:12] 写入临时寄存器, jalr 将 address[11:1] 加到临时寄存器并跳转到目标位置

RISC-V寻址模式总结

2.8 同步

  • 两个处理器共享存储器中的某一位置,若不同步,则发生数据竞争

2.8.1 保留加载 / 条件存储机制

预留取数

1
lr.d rd,(rs1)
  • 从地址 rs1 处取数,保存到 rd
  • 对内存地址设置预留

条件存数

1
sc.d rd,rs2,(rs1)
  • 将 rs2 的内容保存到地址 rs1
  • 如果从 lr.d 之后该位置没有被更改则执行成功,在 rd 中返回 0
  • 如果该位置被更改则执行失败,在 rd 中返回非 0 值

2.8.2 原子交换

1
2
3
4
again: lr.d x10,(x20)
sc.d x11,x23,(x20) // x11 = 执行状态
bne x11,x0,again // 如果存数失败则跳转
addi x23,x10,0 // x23 = 从(x20)读到的数值

2.8.3 加锁

1
2
3
4
5
6
       addi x12,x0,1        // x12 = 1,用于表示关锁
again: lr.d x10,(x20) // 读(x20)的锁值
bne x10,x0,again // 如果锁不为0则跳转
sc.d x11,x12,(x20) // 尝试向(x20)写1以关锁
bne x11,x0,again // 如果存数失败则跳转解锁
sd x0,0(x20) // 向(x20)写0以开锁

2.9 翻译与启动程序

C语言的转换层次结构

  • 目标模块(.o)的组成

    • 头:描述目标模块的内容
    • 代码段:翻译后的指令
    • 静态数据段:分配的数据,作用于程序生命周期
    • 重定位信息:依赖于程序加载的绝对地址的内容(用于加载程序)
    • 符号表:匹配标签名和指令所在地址及外部引用(用于链接模块)
    • 调试信息:用于关联到源代码
  • 动态链接:仅在调用时链接 / 加载库过程

    • 避免了静态链接导致的映像膨胀
    • 自动调用新版本的库
  • 可移植性:虚拟机 与 即时编译器

Java的转换层次结构

2.10 RISC 与 CISC 对比

RISC 与 CISC 对比(图源:王道考研)

历年真题

  1. 二进制补码 10101100 代表的十进制是
  • A:-172
  • B:+172
  • C:-84
  • D:+83
  1. 小端方式32位计算机中数值 -6 的存储方式的描述正确的是
  • A:内存位置从低到高存储的十六进制数分别是0xFA、0xFF、0xFF和0xFF
  • B:因为其值为负,所以一般采用反码方式存储
  • C:内存位置从低到高存储的十六进制数分别是0xFF、0xFF、0xFF和0xFA
  • D:内存位置从低到高存储的十六进制数分别是0xFF、0xFF、0xFF和0xFB

Reference

https://blog.csdn.net/weixin_45633061/article/details/117421452

https://gist.github.com/smallaccount101/6324d7c82d103783f21b7cc6da7d0f7c


计算机组成知识点整理(2):指令系统
https://cny123222.github.io/2025/04/01/计算机组成知识点整理-2-:指令系统/
Author
Nuoyan Chen
Posted on
April 1, 2025
Licensed under