RV1 Verilator to WASM Build Notes

This document captures the full working path and all workarounds used to run the copied RV1 RTL in the browser as WebAssembly.

Quick Start

From rv1_copy/wasm:

make rv1-install
cd ../../
npm run build

Expected copied runtime assets in content/rv1:

Expected generated site assets in build/rv1:

Goal

End-to-end flow:

  1. Build a bare-metal RV32IM program from C.
  2. Verilate RV1 RTL to C++.
  3. Compile the Verilated model plus harness to standalone WASM.
  4. Load program/data binaries into IMEM/DMEM in-browser.
  5. Run cycles and blit framebuffer to canvas.

Workspace Paths

Prerequisites

On macOS/Homebrew, the RISC-V toolchain needed additional runtime libs:

  1. Install isl:
brew install isl
  1. Install libmpc:
brew install libmpc

If Homebrew tap trust blocks package install, trust only required formulas from the tap and retry.

Required Source Workarounds

1. Make IMEM/DMEM writable from Verilated C++

File: rv1_copy/rtl/riscv_top.v

This enables direct memory pointer access from the C++ harness and avoids runtime file I/O assumptions in WASM.

2. Add browser-safe RV32 linker and startup

These provide bare-metal entry and IMEM/DMEM placement suitable for the browser simulation memory map.

3. Extend RV32 compile script outputs

File: rv1_copy/scripts/compile_c.sh

Important details:

4. Add Verilated WASM harness

File: rv1_copy/wasm/rv1_verilated_harness.cpp

Exports C ABI functions for JS:

File: rv1_copy/wasm/rv1_wasm_posix_shims.c

Provided stubs:

This resolves unresolved symbols from Verilator runtime threading code when targeting browser WASM.

6. Verilator/Emscripten portability flags

File: rv1_copy/wasm/Makefile

Key flags/workarounds:

Build Commands

From rv1_copy/wasm:

  1. Build full RTL-to-WASM pipeline and copy artifacts into content:
make rv1-install

This runs:

  1. verilate

  2. rv1-wasm

  3. rv32-content

  4. copy rv1_verilated.wasm into content

  5. Build codeng site:

cd ../../
npm run build

Runtime Integration

Browser loader: content/rv1/rv1_verilated.js

Runtime behavior:

  1. Fetch rv1_verilated.wasm.
  2. Instantiate and call rv1_init + rv1_clear_memories.
  3. Fetch program.bin and data.bin.
  4. Copy bytes into IMEM/DMEM via exported pointers.
  5. Reset core, run fixed number of cycles.
  6. Read framebuffer bytes from DMEM and convert BGRA memory layout to RGBA for canvas.

Demo page: content/rv1/verilated.md

Expected Artifacts

After make rv1-install:

After npm run build:

Known Failure Modes and Fixes

  1. dyld: libisl missing when invoking riscv64-unknown-elf-gcc Fix: brew install isl

  2. dyld: libmpc.3.dylib missing when invoking riscv64-unknown-elf-gcc Fix: brew install libmpc

  3. Verilator runtime unresolved affinity symbols under wasm Fix: include rv1_copy/wasm/rv1_wasm_posix_shims.c in em++ link

  4. Verilator arch portability errors in wasm toolchain Fix: compile with -DVL_IGNORE_UNKNOWN_ARCH and include stdint.h

  5. Browser cannot rely on HDL $readmemh files Fix: compile RTL with RV1_NO_MEM_INIT and load binaries from JS into exported memory pointers