Releases: Gaok1/Raven-RiscV
v1.27.0
Full Changelog: v1.26.1...v1.27.0
v1.26.1
Full Changelog: v1.26.0...v1.26.1
v1.26.0
Raven v1.26.0
New Instructions — RV32A Extension
Full RV32A atomic instruction support:
LR.W/SC.W— load-reserved / store-conditional with per-hart reservation trackingAMOvariants:AMOSWAP,AMOADD,AMOXOR,AMOAND,AMOOR,AMOMAX,AMOMIN,AMOMAXU,AMOMINUFENCE— now forwarded to the bus layer (was a no-op)FENCE.I— invalidates the I-cache, enabling self-modifying code to work correctly
Instruction panel type badges extended: [A] for atomic, [F] for float.
Cache Coherence Bug Fixes
Four bugs that caused silent data corruption in multi-level cache (L1 D + L2) configurations, which could manifest as a program crash at PC=0x00000000:
- Blanket L2 invalidation after write-back stores removed — on a write-allocate miss, L2 was being invalidated right after the dirty eviction wrote back to it, losing data in both cache levels.
- Write-through stores now correctly invalidate L2 — stale L2 copies are now dropped after write-through stores so future misses re-read the updated value from RAM.
sync_to_ramwriteback order fixed — L2 (outer levels) is now flushed before D-cache to prevent stale L2 data from overwriting correct values in RAM.flush_allwriteback order fixed — same root cause as #3; applied when the user toggles the cache off.
Pipeline Improvements
- Per-FU stall counters — stall counts broken down by functional unit (ALU, MUL, DIV, FPU, LSU, SYS)
- Configurable FU counts — set the number of each functional unit in
.pcfg - Branch predictor expanded — not-taken (default), always-taken, BTFNT, and 2-bit dynamic strategies
- Per-hazard stall breakdown in the pipeline footer
- Speculative Gantt — in-flight speculative instructions shown with distinct styling; flushed instructions marked
.pcfgformat updated: per-bypass-path flags replace the singleforwardingboolean;fu.*count fields added
rust-to-raven
raven_apirestructured:hart.rsmoved tohardware_thread/- New
atomic/module:Arc,AtomicBool,AtomicU32, and friends backed byLR.W/SC.W— atomics actually work on the simulator now main.rsupdated to use the newHartTaskclosure-based API
v1.25.1
Full Changelog: v1.25.0...v1.25.1
v1.25.0
Raven — Pipeline & Hardware Threads - 1.25.0
This release adds two interconnected features that make the inner mechanics of a RISC-V processor visible in a way that no static textbook diagram can match: a cycle-by-cycle pipeline simulator and multi-hart (hardware thread) execution.
Both features work with every program that already runs in Raven. No changes to your assembly are required to observe the pipeline. Hart spawning is opt-in via the hart_start syscall.
Pipeline simulation
What it is
A classic 5-stage in-order pipeline running alongside every execution in Raven. When the Pipeline tab is open, you watch the machine tick one clock cycle at a time.
IF → ID → EX → MEM → WB
Each stage does exactly what a real core does:
| Stage | Work |
|---|---|
IF |
Fetch from I-cache. Stall here when the cache misses. |
ID |
Decode, read registers, apply forwarding, attach prediction. |
EX |
ALU, branch evaluation, address generation, FU latency. |
MEM |
Load/store through D-cache. Stall here on cache miss. |
WB |
Write result, retire instruction, handle syscalls. |
Hazards — made visible
Every hazard that would stall or flush your program is labeled and shown in the Hazard / Forwarding Map below the pipeline:
| Hazard | Color | What it means |
|---|---|---|
RAW |
amber | Read-after-write: consumer needs a value not yet written |
LOAD |
amber | Load-use: load result is only available after MEM |
CTRL |
red | Branch/jump: wrong-path instructions were flushed |
FWD |
blue | Forwarding bypassed the hazard — no stall needed |
FU |
purple | Functional unit busy (multi-cycle mode) |
MEM |
steel blue | Cache latency converted to pipeline stall cycles |
WAW/WAR |
— | Informational: name dependency, no stall required |
Gantt history
The Gantt chart to the right of the stage view shows the last 12 instructions as a timeline. Each row is one instruction; each column is one clock cycle. You can see at a glance where an instruction stalled, which cycle it committed, and how many bubbles a branch flush introduced.
Cell types: IF ID EX MEM WB ── (stall) · (bubble) ✕ (flush)
Forwarding
With forwarding enabled, Raven bypasses results from older to younger stages along three paths:
EX/MEM/WB → ID
MEM/WB → EX
WB → MEM (store data)
The map distinguishes a forwarding-covered RAW (no stall, shown as FWD) from a true load-use stall.
Branch prediction
Static prediction is configurable: not-taken (default) or taken. The pipeline attaches a prediction badge when the branch reaches ID. If the prediction is wrong, younger speculative instructions are flushed and the fetch redirects.
You can also choose where branches resolve: ID (1 bubble), EX (2 bubbles, default), or MEM (3 bubbles).
Functional-unit mode
Switch from Single-cycle to Functional Units in the pipeline config. Each instruction class then has its own configurable latency — MUL holds EX for 3 cycles, DIV for 20, FP for 5, and so on. The pipe stalls visibly while the unit is occupied.
Cache integration
The pipeline and cache share one clock model. A cache miss in IF stalls the IF stage for exactly as many cycles as the miss penalty. A cache miss in MEM does the same. The cache stats tab and the pipeline Gantt stay in sync — you can see the same access from both sides.
Configuration file
Pipeline settings persist in a .pcfg file (Ctrl+Shift+P to save/load):
# Raven Pipeline Config v1
enabled=true
forwarding=true
mode=SingleCycle
branch_resolve=Ex
predict=NotTaken
speed=Normal
Hardware threads (harts)
What a hart is
A hart is an independent RISC-V execution context — its own PC, register file, and stack — running concurrently with other harts. All harts share the same flat address space and cache hierarchy. There is no memory protection between harts.
In Raven, each hart maps to one simulated core slot. The maximum number of simultaneous harts is set in Settings (max_cores).
Spawning a hart
# Assembly: syscall 1100
la a0, worker # entry PC
la a1, stack_top # stack pointer (top/high address, 16-byte aligned)
li a2, 42 # argument passed to the new hart in a0
li a7, 1100
ecall # returns hart id in a0 (< 0 = error)// C: c-to-raven
static char stack[4096];
SPAWN_HART(worker, stack, /*arg=*/42);// Rust: rust-to-raven
static mut STACK: [u8; 4096] = [0; 4096];
spawn_hart_fn(worker, unsafe { &mut STACK }, 42);
// or with a closure:
spawn_hart(move || { /* ... */ hart_exit() }, unsafe { &mut STACK });Terminating a hart
| Syscall | Number | Effect |
|---|---|---|
hart_exit |
1101 |
This hart only. Others keep running. |
exit |
93 |
All harts. Global program exit. |
exit_group |
94 |
All harts. Identical to exit in Raven. |
Hart lifecycle states
FREE → RUN → EXIT / BRK / FAULT
A fault in any hart stops the entire simulation. A breakpoint pauses only that hart; the rest continue if the run scope is ALL.
Pipeline per hart
Every spawned hart has its own pipeline state. When you switch cores in the Pipeline tab, you see that hart's in-flight stages, Gantt history, hazard map, and statistics — independent of every other hart.
Execution model
Harts advance in round-robin lockstep: each global step advances all running harts by one cycle (or one instruction in non-pipeline mode). The shared memory means cache effects from one hart are immediately visible to all others.
New example programs
Five programs in Program Examples/ are designed specifically for these features:
| Program | What to observe |
|---|---|
pipeline_forwarding_demo.fas |
Chained RAW hazards, forwarding bypass paths |
pipeline_load_use_demo.fas |
Load-use stalls on every access |
pipeline_branch_flush_demo.fas |
Wrong-path squashes on every loop iteration |
pipeline_cache_stall_demo.fas |
Streaming access pattern, MEM and IF stalls |
hart_spawn_visual_demo.fas |
Three concurrent harts, core selector in action |
Suggested workflow for the pipeline demos:
- Open a program in the Editor tab and assemble (
Ctrl+R) - Switch to the Pipeline tab
- Press
Spaceto run — watch the Gantt fill up in real time - Slow down with the speed control to step cycle by cycle
- Toggle forwarding off in the Config subtab and compare CPI
Interactive tutorial
The pipeline tutorial (click [?] in the Pipeline tab) walks through every part of the interface: the stage view, the hazard map, the Gantt chart, and the config panel. It points to the exact UI element it is describing at each step.
Stats
The pipeline tab footer shows live metrics:
Cycle 342 Instr 211 CPI 1.62 Stalls 89 Flushes 12
Per-class instruction counts are visible in the Gantt color legend.
Summary of new keys and controls
| Control | Action |
|---|---|
| Pipeline tab → Config subtab | Toggle forwarding, mode, prediction |
| Speed button in Pipeline toolbar | Slow / Normal / Fast / Instant |
| Core button in Pipeline/Run toolbar | Switch between hart core slots |
Settings → max_cores |
Set number of concurrent hart slots |
Settings → Run scope ALL/FOCUS |
Step all harts or only the focused one |
Ctrl+Shift+P |
Save / load pipeline config (.pcfg) |
v1.23.0
Full Changelog: v1.22.0...v1.23.0
v1.22.0
Full Changelog: v1.21.0...v1.22.0
v1.21.0
Changelog
v1.21.0
Rust on RAVEN — native ELF compatibility
The highlight of this release is first-class support for running Rust programs inside the simulator.
RAVEN has been able to load ELF binaries for a while, but the repo now ships
rust-to-raven/ — a ready-to-use bare-metal Rust project that closes the full loop:
write Rust, compile to riscv32im-unknown-none-elf, drop the ELF into RAVEN, and step through
every instruction with registers, memory and cache stats live.
What rust-to-raven/ gives you:
#![no_std]+#![no_main]with_start, panic handler and global allocator already wired upprint!,println!,eprint!,eprintln!— backed bywrite(syscall 64)read_line!(buf)— reads a line from stdin viaread(syscall 63)- Linux-compatible syscalls:
read(63),write(64),exit(93),getrandom(278),brk(214) Vec,BTreeMap,Stringand heap allocations work out of the box
Quick start — full tutorial in rust-to-raven/README.md:
# 1. add the target once
rustup target add riscv32im-unknown-none-elf
# 2. build (ELF lands in the project root)
cd rust-to-raven && make release # → rust-to-raven.elf
# 3. open RAVEN → Editor tab → [BIN] → select rust-to-raven.elf- Renamed
hello-raven→rust-to-raven— clearer name sys_read(syscall 63) — raw read wrapper added tosyscall.rsread_line!macro — reads a line from stdin into&mut [u8]Makefile—make/make releasecopies the ELF to the project root; no digging throughtarget/
CLI — --mem flag
--mem <size>— set the simulator RAM at launch; acceptskb,mbandgb- Examples:
./raven --mem 256kb,./raven --mem 16mb,./raven --mem 2gb - Minimum:
64kb— Maximum:4gb(full 32-bit address space) - Without the flag: original defaults are preserved (128 KB for assembly, 16 MB for ELF)
- Examples:
Run tab — speed and controls
RunSpeed::X8— new speed level; cycle is now1x → 2x → 4x → 8x → GO- Pause in GO mode —
p(keyboard) and the[State]button (mouse) now pause execution at any speed, including GO
v1.20.0
Raven v1.20.0
riscv32im-unknown-none-elf Compatibility
Raven runs ELF binaries compiled for the riscv32im-unknown-none-elf target — the standard bare-metal Rust target for 32-bit RISC-V without an operating system.
To compile a project for Raven:
# .cargo/config.toml
[build]
target = "riscv32im-unknown-none-elf"cargo build --release
# load the generated .elf in Raven via Ctrl+OA working, commented example is available at docs/RustCompatibleABI.rs, showing the minimal structure of a #![no_std] program with _start, a panic handler, and communication with the emulator.
Note: communication with the emulator uses the Linux RISC-V syscall ABI (
ecall). No external crates are needed — justcore::arch::asm!. The example indocs/RustCompatibleABI.rswraps this into simple helper functions to keep application code clean.
Supported Extensions
| Extension | Support |
|---|---|
| RV32I — base integer | ✅ |
| RV32M — multiply/divide | ✅ |
| RV32A — atomics | ✅ |
| RV32F — single-precision float | ✅ |
fence |
✅ (no-op on single-core) |
Available Syscalls
Raven implements a subset of the Linux RISC-V syscall ABI. You don't need to call ecall directly — the example in docs/RustCompatibleABI.rs provides ready-to-use wrappers.
| Syscall | Purpose |
|---|---|
write (64) |
Write text to the Raven console |
read (63) |
Read a line typed by the user |
exit (93) |
Terminate execution |
getrandom (278) |
Fill a buffer with random bytes |
What's new in v1.20.0 — Visible exit code
When a program calls exit, Raven now prints the exit code in red in the console:
Exit 0
Makes it easy to tell at a glance whether the program finished successfully or with an error, without having to inspect registers manually.
Download
| Platform | File |
|---|---|
| Windows x64 | raven-x86_64-pc-windows-msvc.zip |
| Linux x64 | raven-x86_64-unknown-linux-gnu.tar.gz |
| macOS x64 | raven-x86_64-apple-darwin.tar.gz |
| macOS ARM64 (Apple Silicon) | raven-aarch64-apple-darwin.tar.gz |
SHA256 checksums for all files in SHA256SUMS.txt.
v1.18.1
Full Changelog: v1.18.0...v1.18.1