支持的指令集
| 扩展 | 内容 | 覆盖度 |
|---|---|---|
| RV32I | 基础整数:算术、逻辑、访存、跳转、屏障 | 完整 |
| RV64I | 64 位扩展:ld/sd、addiw、addw 等 | 完整 |
| M | 乘除法:mul / div / rem 及 32 位变体 | 完整 |
| A | 原子操作:lr / sc / amoadd / amoswap 等 | 完整 |
| F / D | 浮点:算术、比较、加载存储、寄存器搬运 | 核心子集 |
| Zicsr | CSR 读写:csrrw / csrrs / csrrc 及立即数形式 | 完整 |
| C | 压缩指令:c.nop / c.li / c.lw / c.j / c.beqz 等 | RV32C + RV64C 主要部分 |
32 位指令的六种格式
RISC-V 的指令编码非常规整,所有指令都能归入六种格式,靠 opcode 和 funct 字段区分:
- R 型:寄存器到寄存器运算,如 add x1, x2, x3
- I 型:带 12 位立即数,如 addi、lw、jalr
- S 型:存储指令,立即数被拆成两段存放
- B 型:条件分支,13 位偏移同样拆开存放
- U 型:20 位高位立即数,如 lui、auipc
- J 型:无条件跳转,21 位偏移分散在多个字段里
之所以把立即数拆得七零八落,是为了让所有格式里「rs1、rs2、rd」这些关键字段 始终位于相同的比特位置,硬件解码时可以并行提取,不用先判断格式。
常用编码对照
00000013→nop00008067→ret00000073→ecall00100073→ebreak0001→c.nop8082→c.jr ra(即 ret)
所有解码在浏览器本地完成,机器码不会上传。遇到不支持的扩展会显示为 .word, 不会猜测编码含义。
常见问题
支持哪些指令集?
覆盖 RV32I / RV64I 基础整数指令、M(乘除)、A(原子)、F 与 D(浮点核心)、Zicsr(CSR 读写)、以及 C(压缩指令)。V(向量)和大部分自定义扩展没有实现,遇到不认识的编码会按 .word 原样输出,不会瞎猜。
为什么有的指令显示成 addi 而不是 nop?
nop 在机器码层面就是 addi x0, x0, 0,汇编器提供的 nop 是伪指令。页面上两者都显示:助记符是真实的指令,下面标注「= nop」是等价的伪指令写法。常见伪指令还包括 li、mv、ret、j、jr。
「指令字」和「内存镜像」有什么区别?
指令字模式:你输入的 4 个字节就是指令本身的编码,如 00000013 表示 nop。内存镜像模式:你输入的是一段内存 dump,因为 RISC-V 是小端存放,13 00 00 00 才是 nop。搞混了会得到完全相反的指令。
为什么压缩指令会自动识别?
RISC-V 规定 32 位指令的低 2 位必须是 11,否则就是 16 位的压缩指令。所以解码器看低 2 位就能判断长度,不需要额外标记。一个 4 字节里如果低 2 位不是 11,就会被拆成两条 16 位指令。
跳转偏移是怎么算的?
B 型和 J 型指令的偏移都是相对当前 PC 的,且最低位固定为 0(指令至少 2 字节对齐),所以编码里省略了最低位。页面直接显示编码里的偏移值,实际目标地址 = 当前指令地址 + 偏移。