assembly-riscv

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

RISC-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:
RegisterABI nameRoleSaved by
x0zeroHard-wired zero
x1raReturn addressCaller
x2spStack pointerCallee
x3gpGlobal pointer
x4tpThread pointer
x5–x7t0–t2TemporariesCaller
x8s0/fpFrame pointerCallee
x9s1Saved registerCallee
x10–x11a0–a1Arguments / return valuesCaller
x12–x17a2–a7ArgumentsCaller
x18–x27s2–s11Saved registersCallee
x28–x31t3–t6TemporariesCaller
Floating-point registers (F extension): f0–f31 (fa0–fa7 for arguments).
RISC-V拥有32个整数寄存器(x0–x31),对应以下ABI名称:
寄存器ABI名称作用保存方
x0zero硬连线为0
x1ra返回地址调用者
x2sp栈指针被调用者
x3gp全局指针
x4tp线程指针
x5–x7t0–t2临时寄存器调用者
x8s0/fp帧指针被调用者
x9s1保存寄存器被调用者
x10–x11a0–a1参数/返回值调用者
x12–x17a2–a7参数调用者
x18–x27s2–s11保存寄存器被调用者
x28–x31t3–t6临时寄存器调用者
浮点寄存器(F扩展):f0–f31(其中fa0–fa7用于传递参数)。

2. Basic instructions

2. 基础指令

asm
undefined
asm
undefined

Arithmetic (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)
undefined
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)
undefined

3. Minimal function (psABI calling convention)

3. 最小函数示例(psABI调用约定)

asm
.section .text
.global add_numbers
asm
.section .text
.global add_numbers

int 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
undefined
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
undefined

4. ISA extension naming

4. ISA扩展命名

RISC-V extensions are combined as a string after the base ISA:
LetterExtensionDescription
IIntegerBase 32/64-bit integer (RV32I, RV64I)
MMultiplyInteger multiply and divide
AAtomicAtomic memory operations (lr/sc, AMOs)
FFloatSingle-precision float
DDoubleDouble-precision float
CCompressed16-bit compressed instructions
GGeneral= IMAFD (shorthand)
VVectorVector instructions (SIMD)
ZicsrCSRControl/status register access
ZifenceiFence.iInstruction-fetch fence
Zba/Zbb/Zbc/ZbsBit manipulationBit ops (B extension set)
ZtsoTSOTotal Store Ordering memory model
Common targets:
  • Embedded:
    rv32imac
    — no floating point, with atomics and compressed
  • Linux app:
    rv64gc
    — full general + compressed
  • High performance:
    rv64gcv
    — + vector
RISC-V扩展以字符串形式附加在基础ISA之后:
字母扩展描述
I整数基础32/64位整数指令集(RV32I、RV64I)
M乘法整数乘法与除法指令
A原子操作原子内存操作(lr/sc、AMOs)
F浮点单精度浮点指令
D双精度浮点双精度浮点指令
C压缩指令16位压缩指令
G通用= IMAFD(简写形式)
V向量向量指令(SIMD)
ZicsrCSR控制/状态寄存器访问
ZifenceiFence.i指令取指屏障
Zba/Zbb/Zbc/Zbs位操作位操作指令(B扩展集)
ZtsoTSO全存储排序内存模型
常见目标平台:
  • 嵌入式:
    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
    c.
    versions)
  • Immediate fits in smaller field
  • Specific instruction patterns match
bash
undefined
RVC会在以下场景将常见的32位指令替换为16位版本:
  • 寄存器为x8–x15(对应
    c.
    前缀版本)
  • 立即数能适配更小的字段
  • 指令模式匹配特定规则
bash
undefined

Enable 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
undefined
riscv64-linux-gnu-gcc -march=rv64g prog.c -o prog
undefined

7. QEMU simulation and GDB

7. QEMU模拟与GDB调试

bash
undefined
bash
undefined

Install 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
qemu-system-riscv64
-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
    skills/low-level-programming/assembly-arm
    for AArch64 comparison
  • Use
    skills/low-level-programming/assembly-x86
    for x86-64 assembly
  • Use
    skills/embedded/openocd-jtag
    for real hardware RISC-V debugging
  • Use
    skills/compilers/cross-gcc
    for RISC-V cross-compilation setup
  • 如需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