assembly-riscv
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRISC-V Assembly
RISC-V汇编
Purpose
用途
Guide agents through RISC-V assembly programming: RV32/RV64 instruction sets, register naming and calling conventions (psABI), ISA extension naming, inline assembly with GCC/Clang, compressed (RVC) instructions, and QEMU-based simulation with GDB remote debugging.
为Agent提供RISC-V汇编编程指导:包括RV32/RV64指令集、寄存器命名与调用约定(psABI)、ISA扩展命名、GCC/Clang内联汇编、压缩(RVC)指令,以及基于QEMU的模拟和GDB远程调试。
Triggers
触发场景
- "How do I write RISC-V assembly?"
- "What are the RISC-V calling convention registers?"
- "How do I use inline asm for RISC-V in C?"
- "What do RISC-V extension letters mean (IMAFD)?"
- "How do I simulate RISC-V with QEMU?"
- "How do I debug RISC-V code with GDB?"
- "如何编写RISC-V汇编代码?"
- "RISC-V调用约定对应的寄存器有哪些?"
- "如何在C语言中使用RISC-V内联汇编?"
- "RISC-V扩展字母(IMAFD)代表什么含义?"
- "如何使用QEMU模拟RISC-V?"
- "如何使用GDB调试RISC-V代码?"
Workflow
工作流程
1. Register file and calling convention
1. 寄存器文件与调用约定
RISC-V has 32 integer registers (x0–x31) with ABI names:
| Register | ABI name | Role | Saved by |
|---|---|---|---|
| x0 | zero | Hard-wired zero | — |
| x1 | ra | Return address | Caller |
| x2 | sp | Stack pointer | Callee |
| x3 | gp | Global pointer | — |
| x4 | tp | Thread pointer | — |
| x5–x7 | t0–t2 | Temporaries | Caller |
| x8 | s0/fp | Frame pointer | Callee |
| x9 | s1 | Saved register | Callee |
| x10–x11 | a0–a1 | Arguments / return values | Caller |
| x12–x17 | a2–a7 | Arguments | Caller |
| x18–x27 | s2–s11 | Saved registers | Callee |
| x28–x31 | t3–t6 | Temporaries | Caller |
Floating-point registers (F extension): f0–f31 (fa0–fa7 for arguments).
RISC-V拥有32个整数寄存器(x0–x31),对应以下ABI名称:
| 寄存器 | ABI名称 | 作用 | 保存方 |
|---|---|---|---|
| x0 | zero | 硬连线为0 | — |
| x1 | ra | 返回地址 | 调用者 |
| x2 | sp | 栈指针 | 被调用者 |
| x3 | gp | 全局指针 | — |
| x4 | tp | 线程指针 | — |
| x5–x7 | t0–t2 | 临时寄存器 | 调用者 |
| x8 | s0/fp | 帧指针 | 被调用者 |
| x9 | s1 | 保存寄存器 | 被调用者 |
| x10–x11 | a0–a1 | 参数/返回值 | 调用者 |
| x12–x17 | a2–a7 | 参数 | 调用者 |
| x18–x27 | s2–s11 | 保存寄存器 | 被调用者 |
| x28–x31 | t3–t6 | 临时寄存器 | 调用者 |
浮点寄存器(F扩展):f0–f31(其中fa0–fa7用于传递参数)。
2. Basic instructions
2. 基础指令
asm
undefinedasm
undefinedArithmetic (R and I type)
Arithmetic (R and I type)
add a0, a1, a2 # a0 = a1 + a2
sub a0, a1, a2 # a0 = a1 - a2
addi a0, a1, 42 # a0 = a1 + 42 (immediate)
mul a0, a1, a2 # a0 = a1 * a2 (M extension)
div a0, a1, a2 # signed divide (M extension)
rem a0, a1, a2 # remainder (M extension)
add a0, a1, a2 # a0 = a1 + a2
sub a0, a1, a2 # a0 = a1 - a2
addi a0, a1, 42 # a0 = a1 + 42 (immediate)
mul a0, a1, a2 # a0 = a1 * a2 (M extension)
div a0, a1, a2 # signed divide (M extension)
rem a0, a1, a2 # remainder (M extension)
Logical
Logical
and a0, a1, a2 # bitwise AND
or a0, a1, a2 # bitwise OR
xor a0, a1, a2 # bitwise XOR
sll a0, a1, a2 # shift left logical
srl a0, a1, a2 # shift right logical (unsigned)
sra a0, a1, a2 # shift right arithmetic (signed)
and a0, a1, a2 # bitwise AND
or a0, a1, a2 # bitwise OR
xor a0, a1, a2 # bitwise XOR
sll a0, a1, a2 # shift left logical
srl a0, a1, a2 # shift right logical (unsigned)
sra a0, a1, a2 # shift right arithmetic (signed)
Load / store
Load / store
lw a0, 0(sp) # load word (32-bit)
ld a0, 0(sp) # load doubleword (64-bit, RV64)
lh a0, 4(sp) # load halfword (sign-extended)
lbu a0, 8(sp) # load byte (zero-extended)
sw a0, 0(sp) # store word
sd a0, 0(sp) # store doubleword (RV64)
lw a0, 0(sp) # load word (32-bit)
ld a0, 0(sp) # load doubleword (64-bit, RV64)
lh a0, 4(sp) # load halfword (sign-extended)
lbu a0, 8(sp) # load byte (zero-extended)
sw a0, 0(sp) # store word
sd a0, 0(sp) # store doubleword (RV64)
Branches (compare and branch)
Branches (compare and branch)
beq a0, a1, label # branch if equal
bne a0, a1, label # branch if not equal
blt a0, a1, label # branch if less than (signed)
bltu a0, a1, label # branch if less than (unsigned)
bge a0, a1, label # branch if ≥ (signed)
beq a0, a1, label # branch if equal
bne a0, a1, label # branch if not equal
blt a0, a1, label # branch if less than (signed)
bltu a0, a1, label # branch if less than (unsigned)
bge a0, a1, label # branch if ≥ (signed)
Jumps
Jumps
j label # unconditional jump (pseudoinstruction: jal x0, label)
jal ra, func # jump and link (call)
jalr zero, ra, 0 # jump to ra (return: pseudoinstruction: ret)
undefinedj label # unconditional jump (pseudoinstruction: jal x0, label)
jal ra, func # jump and link (call)
jalr zero, ra, 0 # jump to ra (return: pseudoinstruction: ret)
undefined3. Minimal function (psABI calling convention)
3. 最小函数示例(psABI调用约定)
asm
.section .text
.global add_numbersasm
.section .text
.global add_numbersint add_numbers(int a, int b); — a in a0, b in a1, return in a0
int add_numbers(int a, int b); — a in a0, b in a1, return in a0
add_numbers:
add a0, a0, a1 # result = a + b
ret # return (jalr zero, ra, 0)
.global factorial
add_numbers:
add a0, a0, a1 # result = a + b
ret # return (jalr zero, ra, 0)
.global factorial
long factorial(int n); — n in a0
long factorial(int n); — n in a0
factorial:
addi sp, sp, -16 # allocate stack frame
sd ra, 8(sp) # save return address (RV64)
sd s0, 0(sp) # save s0 (callee-saved)
mv s0, a0 # s0 = n
li a0, 1 # default return 1
blez s0, .done # if n <= 0, return 1
addi a0, s0, -1 # a0 = n - 1
call factorial # recursive call: factorial(n-1)
mul a0, a0, s0 # a0 = result * n.done:
ld ra, 8(sp) # restore ra
ld s0, 0(sp) # restore s0
addi sp, sp, 16 # deallocate
ret
undefinedfactorial:
addi sp, sp, -16 # allocate stack frame
sd ra, 8(sp) # save return address (RV64)
sd s0, 0(sp) # save s0 (callee-saved)
mv s0, a0 # s0 = n
li a0, 1 # default return 1
blez s0, .done # if n <= 0, return 1
addi a0, s0, -1 # a0 = n - 1
call factorial # recursive call: factorial(n-1)
mul a0, a0, s0 # a0 = result * n.done:
ld ra, 8(sp) # restore ra
ld s0, 0(sp) # restore s0
addi sp, sp, 16 # deallocate
ret
undefined4. ISA extension naming
4. ISA扩展命名
RISC-V extensions are combined as a string after the base ISA:
| Letter | Extension | Description |
|---|---|---|
| I | Integer | Base 32/64-bit integer (RV32I, RV64I) |
| M | Multiply | Integer multiply and divide |
| A | Atomic | Atomic memory operations (lr/sc, AMOs) |
| F | Float | Single-precision float |
| D | Double | Double-precision float |
| C | Compressed | 16-bit compressed instructions |
| G | General | = IMAFD (shorthand) |
| V | Vector | Vector instructions (SIMD) |
| Zicsr | CSR | Control/status register access |
| Zifencei | Fence.i | Instruction-fetch fence |
| Zba/Zbb/Zbc/Zbs | Bit manipulation | Bit ops (B extension set) |
| Ztso | TSO | Total Store Ordering memory model |
Common targets:
- Embedded: — no floating point, with atomics and compressed
rv32imac - Linux app: — full general + compressed
rv64gc - High performance: — + vector
rv64gcv
RISC-V扩展以字符串形式附加在基础ISA之后:
| 字母 | 扩展 | 描述 |
|---|---|---|
| I | 整数 | 基础32/64位整数指令集(RV32I、RV64I) |
| M | 乘法 | 整数乘法与除法指令 |
| A | 原子操作 | 原子内存操作(lr/sc、AMOs) |
| F | 浮点 | 单精度浮点指令 |
| D | 双精度浮点 | 双精度浮点指令 |
| C | 压缩指令 | 16位压缩指令 |
| G | 通用 | = IMAFD(简写形式) |
| V | 向量 | 向量指令(SIMD) |
| Zicsr | CSR | 控制/状态寄存器访问 |
| Zifencei | Fence.i | 指令取指屏障 |
| Zba/Zbb/Zbc/Zbs | 位操作 | 位操作指令(B扩展集) |
| Ztso | TSO | 全存储排序内存模型 |
常见目标平台:
- 嵌入式:— 无浮点支持,包含原子操作与压缩指令
rv32imac - Linux应用:— 完整通用指令集 + 压缩指令
rv64gc - 高性能场景:— 通用指令集 + 向量指令
rv64gcv
5. Inline assembly (GCC/Clang)
5. GCC/Clang内联汇编
c
// Read a CSR register (e.g., cycle counter)
static inline uint64_t read_cycle(void) {
uint64_t val;
asm volatile ("rdcycle %0" : "=r"(val));
return val;
}
// Atomic swap
static inline int atomic_swap(int *ptr, int new_val) {
int old;
asm volatile (
"amoswap.w.aqrl %0, %2, (%1)"
: "=r"(old)
: "r"(ptr), "r"(new_val)
: "memory"
);
return old;
}
// Memory fence
static inline void memory_fence(void) {
asm volatile ("fence rw, rw" ::: "memory");
}
// CSR read/write
#define csr_read(csr) ({ \
uint64_t _v; \
asm volatile ("csrr %0, " #csr : "=r"(_v)); \
_v; \
})
uint64_t mstatus = csr_read(mstatus);c
// Read a CSR register (e.g., cycle counter)
static inline uint64_t read_cycle(void) {
uint64_t val;
asm volatile ("rdcycle %0" : "=r"(val));
return val;
}
// Atomic swap
static inline int atomic_swap(int *ptr, int new_val) {
int old;
asm volatile (
"amoswap.w.aqrl %0, %2, (%1)"
: "=r"(old)
: "r"(ptr), "r"(new_val)
: "memory"
);
return old;
}
// Memory fence
static inline void memory_fence(void) {
asm volatile ("fence rw, rw" ::: "memory");
}
// CSR read/write
#define csr_read(csr) ({ \
uint64_t _v; \
asm volatile ("csrr %0, " #csr : "=r"(_v)); \
_v; \
})
uint64_t mstatus = csr_read(mstatus);6. Compressed instructions (RVC)
6. 压缩指令(RVC)
RVC replaces common 32-bit instructions with 16-bit versions when:
- Register is in x8–x15 (for versions)
c. - Immediate fits in smaller field
- Specific instruction patterns match
bash
undefinedRVC会在以下场景将常见的32位指令替换为16位版本:
- 寄存器为x8–x15(对应前缀版本)
c. - 立即数能适配更小的字段
- 指令模式匹配特定规则
bash
undefinedEnable C extension in GCC
Enable C extension in GCC
riscv64-linux-gnu-gcc -march=rv64gc prog.c -o prog
riscv64-linux-gnu-gcc -march=rv64gc prog.c -o prog
Check if compressed instructions were generated
Check if compressed instructions were generated
riscv64-linux-gnu-objdump -d prog | grep "c."
riscv64-linux-gnu-objdump -d prog | grep "c."
c.addi, c.ld, c.sw, c.j, etc.
c.addi, c.ld, c.sw, c.j, etc.
Disable compressed (for debugging or targets without C)
Disable compressed (for debugging or targets without C)
riscv64-linux-gnu-gcc -march=rv64g prog.c -o prog
undefinedriscv64-linux-gnu-gcc -march=rv64g prog.c -o prog
undefined7. QEMU simulation and GDB
7. QEMU模拟与GDB调试
bash
undefinedbash
undefinedInstall QEMU RISC-V
Install QEMU RISC-V
apt-get install qemu-user qemu-system-riscv64
apt-get install qemu-user qemu-system-riscv64
User-mode emulation (run RV64 binary on x86 host)
User-mode emulation (run RV64 binary on x86 host)
qemu-riscv64 ./prog
qemu-riscv64 ./prog
System emulation (full bare-metal VM)
System emulation (full bare-metal VM)
qemu-system-riscv64
-machine virt
-nographic
-kernel firmware.elf
-gdb tcp::1234
-S # start paused
-machine virt
-nographic
-kernel firmware.elf
-gdb tcp::1234
-S # start paused
qemu-system-riscv64
-machine virt
-nographic
-kernel firmware.elf
-gdb tcp::1234
-S # start paused
-machine virt
-nographic
-kernel firmware.elf
-gdb tcp::1234
-S # start paused
GDB remote session
GDB remote session
riscv64-linux-gnu-gdb prog
(gdb) target remote :1234
(gdb) load
(gdb) break main
(gdb) continue
For the RISC-V psABI calling convention details, see [references/riscv-abi.md](references/riscv-abi.md).riscv64-linux-gnu-gdb prog
(gdb) target remote :1234
(gdb) load
(gdb) break main
(gdb) continue
关于RISC-V psABI调用约定的详细内容,请参考 [references/riscv-abi.md](references/riscv-abi.md)。Related skills
相关技能
- Use for AArch64 comparison
skills/low-level-programming/assembly-arm - Use for x86-64 assembly
skills/low-level-programming/assembly-x86 - Use for real hardware RISC-V debugging
skills/embedded/openocd-jtag - Use for RISC-V cross-compilation setup
skills/compilers/cross-gcc
- 如需AArch64汇编对比,请使用
skills/low-level-programming/assembly-arm - 如需x86-64汇编内容,请使用
skills/low-level-programming/assembly-x86 - 如需真实硬件RISC-V调试,请使用
skills/embedded/openocd-jtag - 如需RISC-V交叉编译环境搭建,请使用
skills/compilers/cross-gcc