/assembly-riscv
RISC-V assembly skill for RV32/RV64 programming. Use when working with the RISC-V ISA, calling conventions (psABI), inline assembly with GCC/Clang, understanding extension naming (IMAFD), compressed instructions, or simulating RISC-V with QEMU and GDB remote debugging. Activates
$ npx -y skills add mohitmishra786/low-level-dev-skills --skill assembly-riscv --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/assembly-riscv
Context preview
The summary Claude sees to decide when to auto-load this skill.
RISC-V assembly skill for RV32/RV64 programming. Use when working with the RISC-V ISA, calling conventions (psABI), inline assembly with GCC/Clang, understanding extension naming (IMAFD), compressed instructions, or simulating RISC-V with QEMU and GDB remote debugging. Activates
SKILL.md
assembly-riscv.SKILL.mdname: assembly-riscv
description: RISC-V assembly skill for RV32/RV64 programming. Use when working with the RISC-V ISA, calling conventions (psABI), inline assembly with GCC/Clang, understanding extension naming (IMAFD), compressed instructions, or simulating RISC-V with QEMU and GDB remote debugging. Activates on queries about RISC-V assembly, RV32, RV64, RISC-V calling convention, RISC-V inline asm, RISC-V extensions, QEMU RISC-V, or RISC-V GDB.
RISC-V Assembly
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.
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?"
Workflow
1. Register file and calling convention
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).
2. Basic instructions
# 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)
# 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)
# 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)
# 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)
# 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)
3. Minimal function (psABI calling convention)
.section .text
.global add_numbers
# 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
# 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
ret4. ISA extension naming
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: `rv32imac` — no floating point, with atomics and compressed
- Linux app: `rv64gc` — full general + compressed
- High performance: `rv64gcv` — + vector
5. Inline assembly (GCC/Clang)
// 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)
RVC replaces common 32-bit instructions with 16-bit versions when:
- Register is in x8–x15 (for `c.` versions)
- Immediate fits
Read more
name: assembly-riscv description: RISC-V assembly skill for RV32/RV64 programming. Use when working with the RISC-V ISA, calling conventions (psABI), inline assembly with GCC/Clang, understanding extension naming (IMAFD), compressed instructions, or simulating RISC-V with QEMU and GDB remote debugging. Activates on queries about RISC-V assembly, RV32, RV64, RISC-V calling convention, RISC-V inline asm, RISC-V extensions, QEMU RISC-V, or RISC-V GDB.
RISC-V Assembly
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.
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?"
Workflow
1. Register file and calling convention
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).
2. Basic instructions
# 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) # 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) # 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) # 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) # 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)
3. Minimal function (psABI calling convention)
.section .text
.global add_numbers
# 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
# 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
ret4. ISA extension naming
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: `rv32imac` — no floating point, with atomics and compressed
- Linux app: `rv64gc` — full general + compressed
- High performance: `rv64gcv` — + vector
5. Inline assembly (GCC/Clang)
// 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)
RVC replaces common 32-bit instructions with 16-bit versions when:
- Register is in x8–x15 (for `c.` versions)
- Immediate fits
A curated suite of AI agent skills for systems and low-level programming — C/C++, Rust, Zig, GPU, bare-metal firmware, Linux kernel/driver development, computer architecture, compiler internals, HPC, and more.
Repo: mohitmishra786/low-level-dev-skills
Other skills on low-level-dev-skills.
- /custom-allocators
Custom allocator skill for memory allocation strategies. Use when implementing pool/slab/arena allocators, tuning jemalloc/mimalloc, writing Rust GlobalAlloc, or benchmarking allocator performance. Activates on queries about jemalloc, mimalloc, tcmalloc, arena allocator,
Open skill - /numa-programming
NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology, binding processes with numactl, using libnuma API, building NUMA-aware data structures, or measuring remote access penalties. Activates on queries about numactl, libnuma, NUMA topology,
Open skill - /af-xdp
AF_XDP skill for high-performance XDP sockets. Use when creating AF_XDP sockets, configuring UMEM and XSK rings, XDP_REDIRECT programs, copy vs zero-copy mode, or comparing with DPDK. Activates on queries about AF_XDP, xsk_umem, XDP_REDIRECT, libbpf xsk, or zero-copy XDP.
Open skill - /dpdk
DPDK skill for userspace packet I/O. Use when initializing EAL, configuring PMD drivers, using mbuf pools and rte_ring, setting up huge pages, RSS, or testpmd validation. Activates on queries about DPDK, EAL, rte_eth_rx_burst, hugepages, PMD, or testpmd.
Open skill - /io-uring
io_uring skill for Linux async I/O. Use when building high-performance servers with liburing, multi-shot operations, provided buffers, fixed files, zero-copy send, or tokio-uring. Activates on queries about io_uring, SQE/CQE, liburing, IORING_OP_PROVIDE_BUFFERS, or io_uring vs
Open skill - /adc-dac-baremetal
Bare-metal ADC and DAC skill. Use when configuring analog sampling, DMA-driven ADC, calibration, or DAC output on MCUs. Activates on queries about ADC bare-metal, sampling time, DMA ADC, or DAC channel setup.
Open skill

