RAVEN is a free RISC-V simulator and IDE for the terminal. Write assembly, assemble with one keystroke, and step through every instruction — watching registers, memory, and the cache update in real time. Nothing is a black box.
One terminal app. Write, assemble, run, debug, and profile your RISC-V programs without installing a toolchain.
Built-in editor with syntax highlighting for instructions, registers, directives, and labels. Press Ctrl+R to assemble instantly — no Makefile, no terminal juggling. Import .asm files from other simulators or export your work as binary.
Run free, pause, or advance one instruction at a time. See exactly which register changes, by how much, and why. Set breakpoints on any instruction.
Integer registers shown with ABI names (ra, sp, a0–a7, s0–s11…) plus hex and decimal side by side. Recently changed registers are highlighted automatically.
Each instruction is decoded into its fields: opcode, rd, rs1, rs2, funct3, funct7, sign-extended immediate. Understand encoding, not just mnemonics.
Base integer (RV32I), multiply/divide (M), and single-precision float (F). Every instruction your textbook covers, plus the pseudo-instructions used in real code.
A full I-cache + D-cache simulator tracks every fetch and memory access. Configure geometry and replacement policy, then watch hit rates, AMAT, and IPC update live. Compare configurations with a built-in baseline export.
RAVEN is built around one loop: write code, run it, and see exactly what happens inside the machine.
Type RISC-V assembly in the built-in editor. Syntax highlighting colours instructions, registers, labels, and directives. Ghost hints show operand syntax as you type. Press Ctrl+R to assemble instantly — errors show the exact line and reason.
Step instruction by instruction or run free. The instruction list shows the current PC, decoded type badge, and execution heat. Registers and memory update on every step.
Switch to the Cache tab to see hit rates, AMAT, IPC, and a visual matrix of every cache line. Change the replacement policy and run again to compare.
Most simulators hide the cache. RAVEN exposes everything — per-access tracking, live statistics, a visual matrix of every cache line, and configurable policies so you can experiment with what you learned in class.
Every example in RAVEN is ready to open, step through, and experiment with. Start with these, then write your own.
.data arr: .word 33,12,7,25,9,13,5,1,44,3,18,2,29,8,21,6,10,17,14,4 msg: .asciz "Quicksort (20 elements)" nl: .byte 10, 0 .text printStrLn msg la a0, arr ; base address li a1, 0 ; lo = 0 li a2, 19 ; hi = 19 call quicksort la t0, arr li t4, 20 li t1, 0 print_loop: slli t2, t1, 2 add t2, t0, t2 lw t3, 0(t2) print t3 printStr nl addi t1, t1, 1 blt t1, t4, print_loop li a0, 0 li a7, 93 ; syscall: exit ecall ; quicksort(a0=base, a1=lo, a2=hi) quicksort: bge a1, a2, qs_done push ra push s1 ; base push s2 ; lo push s3 ; hi push s4 ; pivot index mv s1, a0 mv s2, a1 mv s3, a2 call partition ; → a0 = pivot index mv s4, a0 mv a0, s1 mv a1, s2 addi a2, s4, -1 call quicksort ; recurse left mv a0, s1 addi a1, s4, 1 mv a2, s3 call quicksort ; recurse right pop s4 pop s3 pop s2 pop s1 pop ra qs_done: ret ; partition(a0=base, a1=lo, a2=hi) → a0 = pivot index partition: push ra push s0 ; pivot value push s1 ; base push s2 ; lo push s3 ; hi push s4 ; i push s5 ; j mv s1, a0 mv s2, a1 mv s3, a2 slli t0, s3, 2 add t0, s1, t0 lw s0, 0(t0) ; pivot = arr[hi] addi s4, s2, -1 ; i = lo - 1 mv s5, s2 ; j = lo part_loop: bge s5, s3, part_done slli t1, s5, 2 add t1, s1, t1 lw t2, 0(t1) ; arr[j] blt s0, t2, skip_swap addi s4, s4, 1 ; i++ beq s4, s5, skip_swap slli t3, s4, 2 add t3, s1, t3 lw t4, 0(t3) ; arr[i] sw t2, 0(t3) ; arr[i] = arr[j] sw t4, 0(t1) ; arr[j] = arr[i] skip_swap: addi s5, s5, 1 j part_loop part_done: addi t0, s4, 1 ; pivotIndex = i + 1 slli t1, t0, 2 add t1, s1, t1 lw t2, 0(t1) slli t3, s3, 2 add t3, s1, t3 lw t4, 0(t3) sw t4, 0(t1) ; swap pivot into place sw t2, 0(t3) mv a0, t0 pop s5 pop s4 pop s3 pop s2 pop s1 pop s0 pop ra ret
Full recursive quicksort on a 20-element integer array. Demonstrates proper RISC-V calling convention with push/pop to save callee-saved registers across recursive calls.
call + stack frame via push/pops0–s5)exit(93) via raw ecall.data arr: .word 20,1,19,2,18,3,17,4,16,5,15,6,14,7,13,8,12,9,11,10 msg: .asciz "Sorted values:" nl: .byte 10, 0 .text printStrLn msg la t0, arr ; base address li t4, 20 ; n = 20 li t1, 0 ; i = 0 outer: li t2, 0 sub s2, t4, t1 addi s2, s2, -1 ; limit = n - 1 - i inner: slli t3, t2, 2 ; offset = j * 4 add t3, t0, t3 ; &arr[j] addi t5, t3, 4 ; &arr[j+1] lw s0, 0(t3) lw s1, 0(t5) blt s0, s1, no_swap sw s1, 0(t3) sw s0, 0(t5) no_swap: addi t2, t2, 1 blt t2, s2, inner addi t1, t1, 1 blt t1, t4, outer li t2, 0 print_loop: slli t3, t2, 2 add t3, t0, t3 lw a0, 0(t3) print a0 printStr nl addi t2, t2, 1 blt t2, t4, print_loop li a0, 0 li a7, 93 ; syscall: exit ecall
Classic O(n²) sort over a 20-element array in .data. Great for watching D-cache access patterns in the Cache tab — the tight inner loop shows excellent spatial locality.
.word directiveslli + add)lw / swbltexit(93) via raw ecall.data buf: .space 64 .text ; Linux-style syscall ABI: ; a7 = syscall number ; a0..a5 = arguments ; a0 = return value li a0, 0 ; fd = stdin (0) la a1, buf li a2, 64 ; max bytes li a7, 63 ; read(fd, buf, count) ecall ; → a0 = bytes read mv t0, a0 ; save byte count li a0, 1 ; fd = stdout (1) la a1, buf mv a2, t0 ; exact bytes to echo li a7, 64 ; write(fd, buf, count) ecall li a0, 0 li a7, 93 ; exit(0) ecall
No pseudo-instructions. Pure Linux-style ecall: put the syscall number in a7, arguments in a0–a5, fire ecall. Return value lands in a0. Reads a line from stdin and writes it straight back to stdout.
read(63): stdin → bufferwrite(64): buffer → stdoutexit(93): clean exit.spaceread used as write length.data prompt: .asciz "Your name? " greet: .asciz "Hi, " buf: .space 64 .text ; --- write prompt to stdout --- li a0, 1 ; fd = stdout la a1, prompt li a2, 11 ; len("Your name? ") li a7, 64 ; write ecall ; --- read name from stdin --- li a0, 0 ; fd = stdin la a1, buf li a2, 64 ; max bytes li a7, 63 ; read ecall ; → a0 = bytes read mv t0, a0 ; save byte count ; --- write "Hi, " to stdout --- li a0, 1 la a1, greet li a2, 4 ; len("Hi, ") li a7, 64 ; write ecall ; --- write the name back --- li a0, 1 la a1, buf mv a2, t0 ; bytes_read from earlier li a7, 64 ; write ecall li a0, 0 li a7, 93 ; exit(0) ecall
Composes output from three separate write calls — a prompt string, a greeting prefix, and the user's input — all using raw Linux ABI. No pseudo-instructions, no helpers.
write(64) callsread reused as write lengthla (load address)exit(93) — Linux-compatible clean exitFrom basic arithmetic to floating-point. RAVEN supports the complete standard instruction set so you never hit a wall mid-course.
RAVEN is a single binary. No VM, no Docker, no toolchain setup.
Grab the binary for your OS from the Releases page and run it directly — RAVEN opens immediately.
Requires Rust (rustup.rs). Gives you the latest version and full access to the source.
If you're studying RISC-V — for a university course, self-study, or just curiosity — RAVEN is designed for you. Register naming, memory layout, and calling conventions follow the standard spec exactly. No surprises.