Skip to content

Releases: Gaok1/Raven-RiscV

v1.27.0

15 Apr 00:57

Choose a tag to compare

v1.26.1

14 Apr 20:49

Choose a tag to compare

Full Changelog: v1.26.0...v1.26.1

v1.26.0

04 Apr 12:38

Choose a tag to compare

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 tracking
  • AMO variants: AMOSWAP, AMOADD, AMOXOR, AMOAND, AMOOR, AMOMAX, AMOMIN, AMOMAXU, AMOMINU
  • FENCE — 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:

  1. 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.
  2. 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.
  3. sync_to_ram writeback order fixed — L2 (outer levels) is now flushed before D-cache to prevent stale L2 data from overwriting correct values in RAM.
  4. flush_all writeback 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
  • .pcfg format updated: per-bypass-path flags replace the single forwarding boolean; fu.* count fields added

rust-to-raven

  • raven_api restructured: hart.rs moved to hardware_thread/
  • New atomic/ module: Arc, AtomicBool, AtomicU32, and friends backed by LR.W/SC.W — atomics actually work on the simulator now
  • main.rs updated to use the new HartTask closure-based API

v1.25.1

31 Mar 01:49

Choose a tag to compare

Full Changelog: v1.25.0...v1.25.1

v1.25.0

28 Mar 03:08

Choose a tag to compare

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

FREERUNEXIT / 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:

  1. Open a program in the Editor tab and assemble (Ctrl+R)
  2. Switch to the Pipeline tab
  3. Press Space to run — watch the Gantt fill up in real time
  4. Slow down with the speed control to step cycle by cycle
  5. 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

22 Mar 19:43

Choose a tag to compare

Full Changelog: v1.22.0...v1.23.0

v1.22.0

19 Mar 01:01

Choose a tag to compare

Full Changelog: v1.21.0...v1.22.0

v1.21.0

13 Mar 18:06

Choose a tag to compare

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 up
  • print!, println!, eprint!, eprintln! — backed by write (syscall 64)
  • read_line!(buf) — reads a line from stdin via read (syscall 63)
  • Linux-compatible syscalls: read(63), write(64), exit(93), getrandom(278), brk(214)
  • Vec, BTreeMap, String and 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-ravenrust-to-raven — clearer name
  • sys_read (syscall 63) — raw read wrapper added to syscall.rs
  • read_line! macro — reads a line from stdin into &mut [u8]
  • Makefilemake / make release copies the ELF to the project root; no digging through target/

CLI — --mem flag

  • --mem <size> — set the simulator RAM at launch; accepts kb, mb and gb
    • 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)

Run tab — speed and controls

  • RunSpeed::X8 — new speed level; cycle is now 1x → 2x → 4x → 8x → GO
  • Pause in GO modep (keyboard) and the [State] button (mouse) now pause execution at any speed, including GO

v1.20.0

10 Mar 14:12

Choose a tag to compare

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+O

A 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 — just core::arch::asm!. The example in docs/RustCompatibleABI.rs wraps 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

09 Mar 21:01

Choose a tag to compare

Full Changelog: v1.18.0...v1.18.1