What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
To write RISC-V assembly, choose a target such as RV32I or RV64I, write instructions and assembler directives for that target, then assemble, link, and run the result in a matching environment. The key is to keep three layers straight: the ISA defines available instructions, the assembler interprets source syntax and pseudoinstructions, and the ABI defines conventions such as register use across function calls.
Choose a RISC-V target before writing code
RISC-V is an open-standard instruction set architecture (ISA): it defines the instructions a processor implements, not one fixed processor design. The architecture is modular. A program targets a base integer ISA and may require additional extensions for features such as floating point, compressed instructions, or vectors. RV32 and RV64 use different register widths and have differences in available instruction forms, so specify the intended target instead of assuming every RISC-V processor can run every program. RISC-V International describes the ISA as the fundamental guidelines for designing and implementing RISC-V processors.
As an Amazon Associate I earn from qualifying purchases.
For a first assembly program, use a base integer target such as RV32I or RV64I and avoid extension-specific instructions. The official specification library marks its 20240411 unprivileged architecture manual as ratified and points readers to specification version 20260120 as the latest stable library version; check the library for the current document and status before relying on a particular extension. RISC-V International’s specification library
Free tools Windows power users keep installed
One-click scans. No signup required.
The toolchain target, including the ISA and ABI, must match the environment where the program will run. An assembler that accepts a mnemonic does not make that instruction available on every processor: extension support depends on the target and how the assembler is configured.
#1 Best Overall
What are the RISC-V registers used for?
RV32I provides 32 integer registers, named architecturally as x0 through x31; the program counter (pc) is separate. x0 always reads as zero, and writes to it are ignored. Assembly source commonly uses ABI aliases, which convey each register’s conventional role. The aliases are names for the same architectural registers, not additional hardware registers.
| ABI name | Architectural register | Conventional role | Call preservation |
|---|---|---|---|
zero |
x0 |
Constant zero | Always zero |
ra |
x1 |
Return address | Caller-saved |
sp |
x2 |
Stack pointer | Preserved by convention |
gp |
x3 |
Global pointer | Unallocatable in standard ABI use |
tp |
x4 |
Thread pointer | Unallocatable in standard ABI use |
t0–t2 |
x5–x7 |
Temporary values | Caller-saved |
s0/fp |
x8 |
Saved register; may serve as frame pointer | Callee-saved |
s1 |
x9 |
Saved value | Callee-saved |
a0–a7 |
x10–x17 |
Function arguments; a0 and a1 also return values |
Caller-saved |
s2–s11 |
x18–x27 |
Saved values | Callee-saved |
t3–t6 |
x28–x31 |
Temporary values | Caller-saved |
These are ABI conventions for software interoperability, not rules that change what the registers physically do. In ordinary function calls, the caller must assume that values in a and t registers may be overwritten. A function that changes an s register must restore its incoming value before returning. The RISC-V calling-convention specification
How do I write a first RISC-V assembly program?
Instructions operate on registers. For example, addi adds an immediate value to a register, while add adds two register values. The following loop sums the integers from 1 through 5 and leaves the result, 15, in a0:
Rank #2
.text
.globl _start
_start:
addi t0, zero, 1 # current value
addi t1, zero, 6 # stop before 6
addi a0, zero, 0 # running total
loop:
add a0, a0, t0
addi t0, t0, 1
blt t0, t1, loop
blt branches to the label loop when its first register is less than its second. Labels name instruction addresses; they are not instructions themselves. In this example, _start is an entry-point label often used by a bare-metal or custom-linker setup. It does not by itself define how a hosted operating system starts a program or how the program exits.
Memory uses explicit loads and stores
RISC-V is a load/store architecture: arithmetic and branches use registers, while loads and stores move values between registers and memory. A memory operand is typically expressed as an offset from a base register, written as offset(base). For example, lw t0, 0(s1) loads a word from the address in s1, and sw t0, 4(s1) stores a word four bytes from that base address. The suitable load/store width depends on the target and the data being accessed.
To walk through an array of 32-bit words, increment the address by four bytes per element and use a load such as lw for each value. Keep the data layout, address calculation, and chosen instruction width consistent.
Rank #3
Data and assembler directives
Directives tell the assembler how to organize or interpret source; they are not processor instructions. Common examples include .text for code, .data for initialized writable data, .rodata for read-only data where supported by the assembler and object format, and .bss for uninitialized storage. Directives such as .word and .string emit data, while .globl exports a symbol and .equ defines a constant. Directive details can vary by assembler; the RISC-V Assembly Programmer’s Manual documents GNU/LLVM-oriented syntax and directives. RISC-V Assembly Programmer’s Manual
What is the difference between an instruction and a pseudoinstruction?
An ISA instruction corresponds to an architectural operation encoded for the target. A pseudoinstruction is assembler-provided convenience syntax that may translate into one or more real instructions. Common examples include li (load immediate), mv (move), la (load address), ret (return), and call (call a function). Some aliases are short forms of existing instructions; others may expand into sequences selected according to the value, relocation, position-independent-code mode, range, or enabled extensions.
For example, la loads a symbol address using an expansion chosen for the applicable position-independent-code mode. A call may need a longer sequence involving auipc and jalr. If a conditional branch is out of range, the assembler may rewrite it. Thus the number of assembly mnemonics in a source file need not equal the number of machine instructions in the object code. The manual recommends la for symbol addresses unless you need explicit control over PC-relative or GOT-indirect addressing. Assembler pseudoinstructions and relocation behavior
Rank #4
When exact expansion matters—for example, when debugging code size or relocations—inspect the assembled object with a disassembler instead of inferring machine code from the source spelling.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.How do RISC-V function calls and returns work?
The ABI convention assigns a0–a7 to arguments, with a0 and a1 available for return values. The call pseudoinstruction arranges a call, and ret returns to the address in ra. A function that calls another function must account for the fact that a new call overwrites ra; it must preserve the return address if it still needs it to return to its own caller.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteHere is a schematic function showing the preservation rules. It saves the caller’s s0 and its own return address on the stack, uses s0 as a saved register, then restores both before returning:
sum_with_saved_register:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
mv s0, a0
add a0, s0, a1
lw s0, 8(sp)
lw ra, 12(sp)
addi sp, sp, 16
ret
This example uses RV32 word loads and stores and illustrates register preservation; a complete program must also use the stack layout and alignment required by its selected ABI. RV64 code generally uses the corresponding doubleword operations for full-width register values.
How do I assemble and run a RISC-V program?
Assembly source is first assembled into an object file. Linking combines object code and resolves symbols; running then depends on an execution environment such as an operating system, a bare-metal board, or an educational simulator. Those environments do not share a universal memory map, startup sequence, or input/output service.
- Select target, ISA, and ABI. Choose the appropriate target triple and options for the processor and runtime you intend to use. For example, the ALE Manual demonstrates Clang with
--target=riscv32, plus-marchand-mabioptions. The exact values depend on the target and selected ABI. ALE Manual v0.5.1: Assembling Programs - Assemble to an object file. With Clang,
-cstops after compilation/assembly and produces an object rather than a linked executable. Do not assume plain hostastargets RISC-V; the ALE Manual notes that it normally targets the host architecture. - Link for the intended environment. Use a compatible linker, startup code, and libraries if required. A bare-metal image and an operating-system executable need different setup, so the assembler output alone may not be runnable.
- Disassemble to inspect the result. Use a RISC-V-aware disassembler to see emitted instructions and verify pseudoinstruction expansion, target attributes, and relocations where relevant.
- Run with a matching runtime or simulator. Confirm that its supported ISA, ABI, memory map, and startup expectations match the binary. Any console output or exit service supplied by a simulator or runtime is that environment’s convention, not an instruction in the RISC-V ISA.
What should I learn after the base integer instructions?
Once registers, arithmetic, branches, memory access, and calls are comfortable, study extensions and system-level topics separately. Floating-point and compressed instructions require the corresponding ISA extensions. Vector instructions have their own extension context. Control and Status Register (CSR) access and privileged instructions also require an understanding of privilege levels and the relevant execution environment. They are not interchangeable with ordinary RV32I or RV64I user-level examples.
Recommended Free Tools
For choosing an assembler, simulator, or IDE, compare the actual target compatibility, assembler dialect and relocation behavior, execution environment, debugging visibility, and how much code depends on simulator-specific services. The official manuals establish these distinctions, but they do not establish a current universal ranking of learning tools.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




