Getting Started
Quick start
StudyRISC-V runs entirely in your browser. No installation, no account required. Open the simulator and start typing.
Write or load assembly in the editor.
Click Assemble to compile your program.
Click Step to execute one instruction at a time.
Your first program
# Your first RISC-V program
addi x1, x0, 10 # x1 = 10
addi x2, x0, 20 # x2 = 20
add x3, x1, x2 # x3 = x1 + x2 (should be 30)
After assembling and stepping three times, x3 in the register file will
show 0x0000001E (30 in decimal).
Controls reference
| Assemble | Compile the assembly source and load into simulator |
| Step | Execute one instruction, advance PC |
| Step Back | Undo the last instruction |
| Run | Execute continuously until halt or trap |
| Reset | Clear all state and return to assembled state |
| Keyboard | Action |
|---|---|
| Enter | Assemble when the editor is not focused |
| ↓ | Step |
| Shift+↓ | Step Back |
| R | Run / Stop |
| Escape | Reset |
Simulator Panels
Assembly editor
Syntax highlighting, line numbers, and tab support make it easy to write class-style assembly quickly.
Watch for: label coloring, inline comments, and the sample selector for fast starting points.
Disassembly view
Shows instruction address, hex encoding, mnemonic, and operands. The highlighted row is the current PC.
Watch for: the highlighted row moving as you step and branch targets snapping into focus.
Pseudo-C explainer
Translates the current instruction into a C-like expression. x1 = x2 + 10
is clearer than addi x1, x2, 10 for building intuition.
Watch for: the destination, operator, and source coloring as you step.
Call stack visualizer
Shows live stack frames as functions are called and returned from. Load the Function call sample to see it.
Watch for: saved ra, saved registers, local slots, and the current sp row moving.
Effect log
Every register change, memory write, and PC update from each step. Use the REG, MEM, and PC filters to focus.
Watch for: branch redirections, stores to memory, and which register changed most recently.
Memory panel
Shows a window of memory around a chosen address. Use the follow dropdown to track sp or another register.
Watch for: stack writes landing near 0x7FFFFFFC and data segment writes near 0x10000000.
Register file
All 32 RISC-V registers with ABI names and current values. Changed registers flash when updated.
Watch for: calling convention groupings, ABI aliases, and hex values stabilizing across steps.
RISC-V Reference
Register table
| Register | ABI Name | Role |
|---|---|---|
| x0 | zero | Constant value 0 |
| x1 | ra | Return address |
| x2 | sp | Stack pointer |
| x3 | gp | Global pointer |
| x4 | tp | Thread pointer |
| x5-x7 | t0-t2 | Temporaries |
| x8 | s0/fp | Saved register / frame pointer |
| x9 | s1 | Saved register |
| x10-x11 | a0-a1 | Function args / return values |
| x12-x17 | a2-a7 | Function arguments |
| x18-x27 | s2-s11 | Saved registers |
| x28-x31 | t3-t6 | Temporaries |
Instruction set
| Arithmetic | Format | Operation | Example |
|---|---|---|---|
| add | rd, rs1, rs2 | rd = rs1 + rs2 | add x3, x1, x2 |
| addi | rd, rs1, imm | rd = rs1 + imm | addi x1, x0, 10 |
| sub | rd, rs1, rs2 | rd = rs1 - rs2 | sub x3, x1, x2 |
| lui | rd, imm | rd = imm << 12 | lui x1, 0x10000 |
| auipc | rd, imm | rd = PC + (imm << 12) | auipc x1, 0 |
| Comparison | Format | Operation | Example |
|---|---|---|---|
| slt | rd, rs1, rs2 | rd = (rs1 < rs2) ? 1 : 0 | slt x3, x1, x2 |
| slti | rd, rs1, imm | rd = (rs1 < imm) ? 1 : 0 | slti x1, x2, 5 |
| sltu | rd, rs1, rs2 | unsigned compare | sltu x3, x1, x2 |
| sltiu | rd, rs1, imm | unsigned compare with imm | sltiu x1, x2, 5 |
| Bitwise | Format | Operation | Example |
|---|---|---|---|
| and | rd, rs1, rs2 | rd = rs1 & rs2 | and x3, x1, x2 |
| or | rd, rs1, rs2 | rd = rs1 | rs2 | or x3, x1, x2 |
| xor | rd, rs1, rs2 | rd = rs1 ^ rs2 | xor x3, x1, x2 |
| andi | rd, rs1, imm | rd = rs1 & imm | andi x1, x2, 15 |
| ori | rd, rs1, imm | rd = rs1 | imm | ori x1, x2, 1 |
| xori | rd, rs1, imm | rd = rs1 ^ imm | xori x1, x2, 1 |
| Shifts | Format | Operation | Example |
|---|---|---|---|
| sll | rd, rs1, rs2 | rd = rs1 << rs2 | sll x3, x1, x2 |
| srl | rd, rs1, rs2 | rd = rs1 >> rs2 (logical) | srl x3, x1, x2 |
| sra | rd, rs1, rs2 | rd = rs1 >> rs2 (arithmetic) | sra x3, x1, x2 |
| slli | rd, rs1, imm | shift left immediate | slli x1, x2, 2 |
| srli | rd, rs1, imm | shift right logical immediate | srli x1, x2, 1 |
| srai | rd, rs1, imm | shift right arithmetic immediate | srai x1, x2, 1 |
| M Extension | Format | Operation | Example |
|---|---|---|---|
| mul | rd, rs1, rs2 | rd = rs1 * rs2 (lower 32 bits) | mul x3, x1, x2 |
| mulh | rd, rs1, rs2 | rd = (rs1 * rs2) >> 32 signed | mulh x3, x1, x2 |
| div | rd, rs1, rs2 | rd = rs1 / rs2 signed | div x3, x1, x2 |
| divu | rd, rs1, rs2 | rd = rs1 / rs2 unsigned | divu x3, x1, x2 |
| rem | rd, rs1, rs2 | rd = rs1 % rs2 signed | rem x3, x1, x2 |
| remu | rd, rs1, rs2 | rd = rs1 % rs2 unsigned | remu x3, x1, x2 |
| Control flow | Format | Operation | Example |
|---|---|---|---|
| jal | rd, label | rd = PC+4; PC = label | jal ra, func |
| jalr | rd, rs1, imm | rd = PC+4; PC = rs1+imm | jalr x0, ra, 0 |
| beq | rs1, rs2, label | if rs1==rs2 branch | beq x1, x2, done |
| bne | rs1, rs2, label | if rs1!=rs2 branch | bne x1, x2, loop |
| blt | rs1, rs2, label | if rs1<rs2 branch (signed) | blt x1, x2, less |
| bge | rs1, rs2, label | if rs1>=rs2 branch (signed) | bge x1, x2, ge |
| bltu | rs1, rs2, label | unsigned less than | bltu x1, x2, lessu |
| bgeu | rs1, rs2, label | unsigned greater or equal | bgeu x1, x2, geu |
| Memory | Format | Operation | Example |
|---|---|---|---|
| lw | rd, imm(rs1) | rd = mem[rs1+imm] (32-bit) | lw x3, 0(x1) |
| lh | rd, imm(rs1) | rd = mem[rs1+imm] (16-bit sign-ext) | lh x3, 0(x1) |
| lb | rd, imm(rs1) | rd = mem[rs1+imm] (8-bit sign-ext) | lb x3, 0(x1) |
| lhu | rd, imm(rs1) | 16-bit zero-extended | lhu x3, 0(x1) |
| lbu | rd, imm(rs1) | 8-bit zero-extended | lbu x3, 0(x1) |
| sw | rs2, imm(rs1) | mem[rs1+imm] = rs2 (32-bit) | sw x3, 0(x1) |
| sh | rs2, imm(rs1) | mem[rs1+imm] = rs2 (16-bit) | sh x3, 0(x1) |
| sb | rs2, imm(rs1) | mem[rs1+imm] = rs2 (8-bit) | sb x3, 0(x1) |
| System | Format | Operation | Example |
|---|---|---|---|
| ecall | Environment call (syscall) | ecall | |
| ebreak | Breakpoint | ebreak |
mul, div, rem, and their unsigned and
upper-word variants.
Pseudo-instructions
| Pseudo | Expands to | Meaning |
|---|---|---|
| li rd, imm | addi rd, x0, imm (small) or lui+addi (large imm) | Load immediate |
| mv rd, rs | addi rd, rs, 0 | Copy register |
| nop | addi x0, x0, 0 | No operation |
| j label | jal x0, label | Unconditional jump |
| ret | jalr x0, ra, 0 | Return from function |
| call label | auipc ra, hi20; jalr ra, lo12 | Call function |
| la rd, lbl | auipc+addi | Load address |
Memory map
Not to scale.
Calling Convention
The RISC-V calling convention is a set of rules that functions agree to follow so they can call each other correctly. StudyRISC-V's call stack panel visualizes these rules in real time.
ra, t0-t6, a0-a7) may be overwritten by any function you call. Save them yourself if you need them after the call.
s0-s11, sp) must be restored to their original values before a function returns. If you use them, save and restore them.
Stack frames
A typical function prologue moves sp downward to allocate space, saves
ra and any callee-saved registers it uses, then writes local variables into
that frame.
Example walkthrough
-
addi sp, sp, -16Allocates a new stack frame by moving the stack pointer down 16 bytes.
This is the start of the function prologue.
-
sw ra, 12(sp)andsw s0, 8(sp)Saves the return address and a callee-saved register into the new frame.
This follows the rule that anything you promise to preserve must be restored before return.
-
addi a0, x0, 21andjal ra, doublePlaces the argument in
a0and calls the callee, writing the return address intora.The call stack panel pushes a new frame when this happens.
-
add a0, a0, a0The callee computes its result in
a0, which is where return values belong.This is why argument registers double as return-value registers.
-
lw ra, 4(sp),addi sp, sp, 8,jalr x0, ra, 0Restores the saved return address, deallocates the callee frame, and jumps back to the caller.
The call stack panel collapses the frame and shows the symmetry of call and return.
# Watch the CALL STACK panel on the right.
# Step through to see the frame grow, save ra and s0, call double, and return.
main:
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi a0, x0, 21
jal ra, double
double:
addi sp, sp, -8
sw ra, 4(sp)
add a0, a0, a0
jalr x0, ra, 0
ECE 2035 at Georgia Tech
StudyRISC-V was built while taking ECE 2035 (Assembly and C language) at Georgia Tech. The simulator covers the full RV32IM subset used in that course.
| Topic | Feature |
|---|---|
| Assembly programming fundamentals | Editor with syntax highlighting, built-in samples |
| Register file and data types | Live register panel, ABI name labels, hex/decimal context |
| Memory addressing and load/store | Memory panel with address following, byte-level view |
| Control flow (branches and jumps) | Disassembly with PC highlighting, effect log |
| Function calls and calling convention | Call stack visualizer that shows frame building live |
| M extension (multiply/divide) | Full mul/div/rem support including edge cases |
If you are a Georgia Tech student, sign up with your @gatech.edu email
for a Pro account. Free forever.
Sample programs
Start with the calling convention demo or recursive factorial if you want to see stack growth clearly. For data-segment practice, use the built-in string copy or bubble sort examples.