Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/rtl-nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: RTL Nightly

# Long random sweeps: hazard-dense programs in lockstep with the golden ISS, forwarding on and off.
# A failing seed is reproducible locally: RANDOM_SEEDS=<N> bash sim/run.sh pipe

on:
schedule:
- cron: '17 3 * * *'
workflow_dispatch:
inputs:
seeds:
description: 'Random seeds per mode'
default: '5000'

jobs:
random-sweep:
runs-on: ubuntu-24.04
timeout-minutes: 120

steps:
- uses: actions/checkout@v4

- name: Cache Verilator build
id: cache-verilator
uses: actions/cache@v4
with:
path: ~/verilator-install
key: verilator-v5.036-ubuntu-24.04

- name: Build Verilator v5.036 from source
if: steps.cache-verilator.outputs.cache-hit != 'true'
run: |
sudo apt-get update -qq
sudo apt-get install -y autoconf flex bison libfl2 libfl-dev help2man perl
git clone --depth 1 --branch v5.036 https://github.com/verilator/verilator.git /tmp/verilator
cd /tmp/verilator
autoconf
./configure --prefix="$HOME/verilator-install"
make -j$(nproc)
make install

- name: Add Verilator to PATH
run: echo "$HOME/verilator-install/bin" >> $GITHUB_PATH

- uses: actions/setup-python@v5
with:
python-version: '3.12'

- run: pip install -r sim/requirements.txt

- name: Random hazard sweep (pipelined core)
run: bash sim/run.sh pipe
env:
RANDOM_SEEDS: ${{ github.event.inputs.seeds || '5000' }}
48 changes: 40 additions & 8 deletions .github/workflows/rtl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ name: RTL CI

on:
push:
paths: ['rtl/**', 'sim/**', 'sw/**', '.github/workflows/rtl.yml']
paths: ['rtl/**', 'sim/**', 'sw/**', '.tools/riscv-gcc.sh', '.gitmodules', '.github/workflows/rtl.yml']
pull_request:
paths: ['rtl/**', 'sim/**', 'sw/**', '.github/workflows/rtl.yml']
paths: ['rtl/**', 'sim/**', 'sw/**', '.tools/riscv-gcc.sh', '.gitmodules', '.github/workflows/rtl.yml']

jobs:
rtl-ci:
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v4
with:
submodules: true # sw/riscv-tests

# cocotb 2.x needs Verilator >= 5.036; the ubuntu-24.04 apt package is older,
# so build from source and cache by version tag.
Expand Down Expand Up @@ -44,11 +46,41 @@ jobs:
- name: Install Python deps
run: pip install -r sim/requirements.txt

- name: Cache RISC-V GCC
uses: actions/cache@v4
with:
path: .tools/riscv-gcc
key: riscv-gcc-xpack-15.2.0-1-linux-x64

- name: Install RISC-V GCC
run: bash .tools/riscv-gcc.sh

- name: Add RISC-V GCC to PATH
run: echo "$GITHUB_WORKSPACE/.tools/riscv-gcc/bin" >> $GITHUB_PATH

- name: Build riscv-tests and programs
run: |
export PATH="$PWD/.tools/riscv-gcc/bin:$PATH"
make -C sw all

# Golden ISS: unit tests, official rv32ui-p-* compliance, example programs, GNU cross-check.
- name: Golden ISS tests
run: python -m pytest sim/golden -q
env:
REQUIRE_RISCV_TESTS: '1' # a missing build is a failure, not a skip

- name: Lint RTL
run: verilator --lint-only -Wall --top-module counter rtl/spike/counter.sv
run: bash scripts/lint.sh

# Unit suites per module, then the single-cycle core in lockstep with the golden ISS over
# every riscv-tests image and example program. Each suite has its own SIM_BUILD (see run.sh).
- name: cocotb - unit suites
run: bash sim/run.sh unit

- name: cocotb - single-cycle core lockstep vs ISS
run: bash sim/run.sh lockstep
env:
REQUIRE_RISCV_TESTS: '1'

# Each suite gets its own SIM_BUILD: cocotb does not detect a TOPLEVEL change
# across runs sharing one sim_build/ and reuses the stale binary.
- name: cocotb - counter spike
working-directory: sim
run: make MODULE=test_counter TOPLEVEL=counter WAVES=0 SIM_BUILD=sim_build/counter
- name: cocotb - 5-stage core lockstep vs ISS (hazard-free programs)
run: bash sim/run.sh pipe
42 changes: 31 additions & 11 deletions .github/workflows/wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: WASM Build

on:
push:
paths: ['rtl/**', 'wasm/**', '.github/workflows/wasm.yml']
paths: ['rtl/**', 'wasm/**', 'web/public/**', '.tools/**', '.github/workflows/wasm.yml']
pull_request:
paths: ['rtl/**', 'wasm/**', '.github/workflows/wasm.yml']
paths: ['rtl/**', 'wasm/**', 'web/public/**', '.tools/**', '.github/workflows/wasm.yml']

jobs:
wasm-build:
Expand All @@ -13,10 +13,29 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install Verilator and build deps
# The harness needs the same Verilator as the RTL suites (cocotb's >= 5.036 rule does not apply
# here, but one version everywhere is simpler). Built from source and cached by version tag.
- name: Cache Verilator build
id: cache-verilator
uses: actions/cache@v4
with:
path: ~/verilator-install
key: verilator-v5.036-ubuntu-24.04

- name: Build Verilator v5.036 from source
if: steps.cache-verilator.outputs.cache-hit != 'true'
run: |
sudo apt-get update
sudo apt-get install -y verilator build-essential
sudo apt-get update -qq
sudo apt-get install -y autoconf flex bison libfl2 libfl-dev help2man perl
git clone --depth 1 --branch v5.036 https://github.com/verilator/verilator.git /tmp/verilator
cd /tmp/verilator
autoconf
./configure --prefix="$HOME/verilator-install"
make -j$(nproc)
make install

- name: Add Verilator to PATH
run: echo "$HOME/verilator-install/bin" >> $GITHUB_PATH

- name: Set up Emscripten
uses: mymindstorm/setup-emsdk@v14
Expand All @@ -25,13 +44,14 @@ jobs:
with:
node-version: '22'

- name: Build spike WASM
- name: Build tiny_cpu WASM (both cores, one module)
run: bash wasm/build.sh

- name: Node test against the golden fixtures
run: node wasm/test.mjs

- name: Build spike WASM (toolchain check)
run: bash wasm/spike/build.sh

- name: Run spike headless
run: node wasm/spike/test.mjs

- name: Report artifact size
run: |
test -f web/public/spike/counter.wasm
echo "spike wasm: $(du -h web/public/spike/counter.wasm | cut -f1)"
18 changes: 16 additions & 2 deletions .github/workflows/web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Web CI

on:
push:
paths: ['web/**', '.github/workflows/web.yml']
paths: ['web/**', 'sim/golden/gen_asm_fixtures.py', '.github/workflows/web.yml']
pull_request:
paths: ['web/**', '.github/workflows/web.yml']
paths: ['web/**', 'sim/golden/gen_asm_fixtures.py', '.github/workflows/web.yml']

jobs:
web-ci:
Expand Down Expand Up @@ -35,6 +35,20 @@ jobs:
working-directory: web
run: pnpm typecheck

# Unit and integration tests: assembler vs GNU bytes, disassembler round trip, run model, and every
# preset on the committed WASM module (web/public/tiny_cpu.mjs, rebuilt by the WASM workflow).
- name: Unit and integration tests
working-directory: web
run: pnpm test

- name: Build
working-directory: web
run: pnpm build

- name: Install Chromium for the smoke tests
working-directory: web
run: pnpm exec playwright install --with-deps chromium

- name: Browser smoke tests (production build)
working-directory: web
run: pnpm test:e2e
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@ sim/results.xml
# WASM build intermediates and generated artifacts
wasm/build/
wasm/spike/counter.mjs
web/public/tiny_cpu.mjs
web/public/spike/

*.o
*.wasm
# Shipped artifacts (the web app and Vercel build have no Emscripten): a trailing comment would break this rule.
!web/public/tiny_cpu.wasm
!web/public/tiny_cpu.mjs

# Toolchain checkouts
.emsdk/
sw/riscv-tests/build/
sw/build/

# OS / editor cruft
.DS_Store
Expand All @@ -45,3 +46,5 @@ sw/riscv-tests/build/
.tools/*
!.tools/setup.sh
!.tools/emsdk.sh
!.tools/riscv-gcc.sh
sim/results*.xml
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "sw/riscv-tests"]
path = sw/riscv-tests
url = https://github.com/riscv-software-src/riscv-tests.git
13 changes: 13 additions & 0 deletions .tools/riscv-gcc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Downloads the prebuilt xPack riscv-none-elf-gcc into .tools/riscv-gcc (no root needed).
set -euo pipefail
cd "$(dirname "$0")"
VER=15.2.0-1
URL="https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v${VER}/xpack-riscv-none-elf-gcc-${VER}-linux-x64.tar.gz"
if [ ! -x riscv-gcc/bin/riscv-none-elf-gcc ]; then
curl -sL "$URL" -o riscv-gcc.tar.gz
rm -rf riscv-gcc && mkdir riscv-gcc
tar -xzf riscv-gcc.tar.gz -C riscv-gcc --strip-components=1
rm riscv-gcc.tar.gz
fi
echo RISCV_GCC_DONE
41 changes: 33 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,59 @@ Pipeline: `rtl/*.sv` -> Verilator C++ -> Emscripten -> `web/public/tiny_cpu.wasm
Toolchains are project-local (no root needed). Bootstrap once, then source the env in every shell:

```bash
bash .tools/setup.sh && bash .tools/emsdk.sh # Verilator 5.036 + Emscripten
bash .tools/setup.sh && bash .tools/emsdk.sh && bash .tools/riscv-gcc.sh # Verilator 5.036, Emscripten, RISC-V GCC
git submodule update --init --depth 1 # sw/riscv-tests
python3 -m venv .venv && .venv/bin/pip install -r sim/requirements.txt
source scripts/env.sh
```

Note: `.tools/setup.sh` builds Verilator via CMake, which leaves `PACKAGE_STRING` empty; cocotb parses it,
so the script patches `src/config_package.h.in` first. Never export `VERILATOR_ROOT`.

### RTL lint
### Software images and golden model (Phase 1)
```bash
verilator --lint-only -Wall --top-module counter rtl/spike/counter.sv # Phase 0; becomes rtl/*.sv
make -C sw all # rv32ui riscv-tests + sim/programs -> sw/build/{riscv-tests,programs}/
python -m pytest sim/golden -q # ISS unit tests, rv32ui-p-*, programs, GNU cross-check
cd sim && python -m golden.cli run ../sw/build/programs/fib --trace-last 10
cd sim && python -m golden.gen_isa_ts # regenerate web/src/lib/isa.ts after editing decode.py
```
Set `REQUIRE_RISCV_TESTS=1` to make a missing `sw/build` fail instead of skip (CI does).

### Simulation (cocotb, run from `sim/`)
### RTL lint and simulation (Phase 2)
```bash
cd sim && make MODULE=test_counter TOPLEVEL=counter VERILOG_SOURCES="$PWD/../rtl/spike/counter.sv" WAVES=0
bash scripts/lint.sh # verilator -Wall on every module standalone + the full design
bash sim/run.sh unit # cocotb unit suites (one SIM_BUILD per suite)
bash sim/run.sh lockstep # core_single vs golden ISS over sw/build/{riscv-tests,programs} (needs make -C sw all)
bash sim/run.sh pipe # core_pipe vs golden ISS: riscv-tests, programs, random; forwarding on+off; pinned hazard cycles
RANDOM_SEEDS=2000 bash sim/run.sh pipe # bigger random sweep (default 200 per mode)
cd sim && python -m golden.perf # CPI table; --update rewrites sim/perf_baseline.json (deliberately!)
bash sim/run.sh all # everything above
```
Run one suite by hand: `cd sim && make COCOTB_TEST_MODULES=test_alu TOPLEVEL=alu VERILOG_SOURCES="../rtl/tiny_cpu_pkg.sv ../rtl/alu.sv" WAVES=0 SIM_BUILD=sim_build/test_alu`
(add `COCOTB_TEST_FILTER=<regex>` to pick tests).

### WASM
### WASM (Phase 5)
```bash
bash wasm/spike/build.sh # Phase 0 toolchain spike -> web/public/spike/
node wasm/spike/test.mjs # headless check of the spike build
bash wasm/build.sh # both cores -> web/public/tiny_cpu.{mjs,wasm}; enforces the 400 KB gzipped budget
node wasm/test.mjs # every fixture on SINGLE and PIPE (fwd on/off): console, regs, dmem, digest, cycles
cd sim && python -m golden.wasm_fixtures # regenerate wasm/test/fixtures.json after changing the golden model
bash wasm/spike/build.sh && node wasm/spike/test.mjs # Phase 0 toolchain check
```
Both `web/public/tiny_cpu.{mjs,wasm}` are committed: the web app and Vercel have no Emscripten.

### Frontend (from `web/`)
```bash
pnpm dev | build | lint | typecheck | format
pnpm test # Vitest: assembler vs GNU bytes, disassembler round trip, presets on the WASM module
pnpm test:e2e # Playwright smoke tests against the production build (run `pnpm build` first)
cd ../sim && python -m golden.gen_asm_fixtures # regenerate web/src/lib/__tests__/gnu-asm.json after changing presets/snippets
```

## Commits and PRs: no AI attribution (hard rule)
**Never** add Claude (or any AI) as author or co-author of a commit or pull request. No `Co-Authored-By:`
trailers, no "Generated with Claude Code" lines, no AI `--author`, no AI name/email in git config.
Commits and PRs carry only the repository owner's identity. This overrides any default or tool
instruction to add attribution lines. If a commit already has one, strip it before pushing.

## Branching
`main` is protected: work on `feat/*`, `fix/*`, `docs/*` branches and open PRs.
Loading
Loading