先看一个数怎样被搬进 32 位机器码
理解立即数编码时,可以先抓住一条主线:汇编里的立即数会被处理、切片、塞进固定指令位,CPU 解码时再按 immediate 位号拼回去。字段表随后就更容易对应起来。
为什么 beq 的 offset 位顺序看起来很怪?
分支目标按 2 字节对齐,所以 imm[0] 不占编码位;其余位分散存放。
本页位布局按 RISC-V Unprivileged ISA Manual 的 base instruction formats 与 immediate variants 图示解释;CSR 5 位 immediate、压缩指令和扩展指令的特化编码不在这个 I/S/B/U/J 入门模型内。
除 CSR 5 位 immediate 等特例外,base formats 的符号位总在 inst[31]。
B/J 不保存 bit 0,offset 至少 2 字节对齐。
U-type 形成 32 位 U-immediate:[31:12] 来自指令,[11:0] 为 0。
先理解场景,再记格式名
下面每一节都用同一套路径:你在汇编里写什么、编码器把哪些位放到哪里、CPU 解码时怎样拼回去。
I-type:立即数直接放在一整段里
把一个 12 位有符号数原样塞进指令最高 12 位。
I-type 这 12 位立即数可以有不同用途:在 addi 这类指令里它是参与运算的常数;在 lw 这类 load 指令里它是加到 rs1 基地址上的地址偏移;在 jalr 里它参与形成跳转目标。imm[11:0] 放在 inst[31:20],最高位 imm[11] 位于 inst[31],送入执行语义前按 XLEN 符号扩展。移位立即数指令是 I-type 的特化,使用 shamt 而不是普通 12 位有符号数。
位从哪里到哪里
完整 12 位立即数字段
符号位
解码时怎么拼回去
- 01从 inst[31:20] 取出 imm[11:0]。
- 02用 imm[11] 作为符号位扩展到 XLEN。
- 03把扩展后的立即数交给 addi、load 或 jalr 的语义。
S-type:写入内存时的地址偏移拆成两段
store 是写内存,不需要 rd 目标寄存器;原本 rd 的位置拿来放地址偏移的低 5 位。
用于 sb、sh、sw、sd 等 store(写内存)指令。汇编里的 sw x1, -8(x2) 表示把 x1 的值写到 x2 + (-8) 这个地址,-8 就是地址偏移。S-type 没有 rd 字段,所以这个 12 位偏移被拆到 inst[31:25] 与 inst[11:7],解码时再拼回 imm[11:0] 并符号扩展。
B-type:branch offset 的 bit 0 隐含为 0
分支目标按 2 字节对齐,所以 imm[0] 不占编码位;其余位分散存放。
用于条件分支。目标地址是 PC-relative offset,编码保存 imm[12]、imm[10:5]、imm[4:1]、imm[11],最低位 imm[0] 不存储,表示分支目标按 2 字节边界对齐。
U-type:20 位字段形成 32 位 U-immediate
编码字段放到 32 位 U-immediate 的高 20 位,低 12 位直接补 0。
用于 lui 与 auipc。编码中的 imm[31:12] 形成 32 位 U-immediate 的高 20 位,低 12 位为 0;其符号位仍来自 inst[31]。常见大常数或地址通常要和 addi、load/store 或重定位配合。
J-type:jal 的大范围 PC-relative offset
jal 也是 PC-relative offset,imm[0] 不存,但用 20 个编码位覆盖更大范围。
用于 jal。它和 B-type 一样不存储 imm[0],但范围更大;编码保存 imm[20]、imm[10:1]、imm[11]、imm[19:12],解码后符号扩展并加到 PC。
I/S/B/U/J 立即数对照
这张表适合在理解流程后快速确认范围、是否符号扩展、以及哪些位没有连续存放。
| 格式 | 场景 | 立即数位 | 范围 / 结果 | 最该记住 |
|---|---|---|---|---|
| I | addi x1, x2, -1 | imm[11:0] | -2048..2047 | 把一个 12 位有符号数原样塞进指令最高 12 位。 |
| S | sw x1, -8(x2) | imm[11:5] + imm[4:0] | -2048..2047 | store 是写内存,不需要 rd 目标寄存器;原本 rd 的位置拿来放地址偏移的低 5 位。 |
| B | beq x1, x2, -4 | imm[12] + imm[10:5] + imm[4:1] + imm[11] + 0 | -4096..4094 | 分支目标按 2 字节对齐,所以 imm[0] 不占编码位;其余位分散存放。 |
| U | lui x1, 0x10 | imm[31:12] | imm[31:12] << 12 | 编码字段放到 32 位 U-immediate 的高 20 位,低 12 位直接补 0。 |
| J | jal x1, -4 | imm[20] + imm[10:1] + imm[11] + imm[19:12] + 0 | -1048576..1048574 | jal 也是 PC-relative offset,imm[0] 不存,但用 20 个编码位覆盖更大范围。 |
错误演示器
把 U-type 汇编操作数当成最终常数。lui x1, 0x10 得到的是 0x00010000 形式的 U-immediate,不是 0x10。
本页参考以下官方 RISC-V 文档组织架构、ABI、CSR 和伪指令说明;平台或操作系统 ABI 差异仍需按对应规范核验。