Browser-based Verilog simulation IDE. Write RTL, compile, simulate, and inspect waveforms — entirely in the browser, no backend required.
Vera chains three WASM compilers in the browser:
- Verilator (WASM) transpiles Verilog to C++
- Clang/LLVM (WASM, via Emception) compiles C++ to a simulation WASM module
- V8 hot-loads and runs the simulation at 20-67 MHz
.v file → [Verilator.wasm] → C++ → [Clang.wasm] → sim.wasm → [WebAssembly.instantiate] → running simulation
| Design | Compile time | Simulation speed |
|---|---|---|
| 8-bit counter | 3s | ~22 MHz |
| 32-bit ALU (7 ops) | 3s | ~67 MHz |
| UART TX | 3s | ~20 MHz |
Compile times are for incremental recompilation (cached runtime). First compile after page load takes ~7s. Parallel compilation across 4 Web Workers.
- Node.js 20+
- Emscripten SDK (for building Verilator WASM)
- Docker (for building Emception artifacts)
# Install emsdk if needed
./scripts/setup-emsdk.sh
# Build verilator_bin.wasm
./scripts/build-verilator-wasm.shEmception provides Clang/LLVM compiled to WASM. Build on a machine with Docker:
git clone https://github.com/jprendes/emception.git /tmp/emception
cd /tmp/emception
./build-with-docker.shCopy artifacts to public/emception/.
The default Emscripten sysroot uses JS-based exception handling which causes slow WASM-JS boundary crossings. Rebuild with native WASM exceptions:
docker run -i --rm -v ./public/wasm/sysroot-lib:/output emscripten/emsdk:3.1.61 bash -c '
export EMCC_CFLAGS="-fwasm-exceptions"
embuilder build libc libc++ libc++abi libcompiler_rt libdlmalloc --force
cp /emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/lib*.a /output/
'npm install
npm run devOpen http://localhost:5173 in Chrome.
./scripts/deploy.shThe deploy script:
- Concatenates the sysroot
.alibs intopublic/wasm/sysroot-libs.bin+ a JSON offset manifest (scripts/bundle-sysroot-libs.mjs) - Content-hashes runtime assets, brotli-compresses
.wasm/.packfiles, and splits anything >25 MB into parts (scripts/hash-assets.mjs). The resulting URL/size/parts manifest is written tosrc/wasm-bundle/asset-urls.jsonand statically imported by the workers. - Runs
vite build - Assembles
deploy/with only the hashed (compressed/split) artifacts - Deploys to Cloudflare via
wrangler deploy
There is no R2 binding — every asset, including the brotli-compressed emscripten sysroot pack, is served from Workers Assets.
src/wasm-bundle/is generated by the build scripts and gitignored.
src/
├── workers/
│ ├── verilator.worker.ts # Verilator WASM (Verilog → C++)
│ ├── compiler.worker.ts # Emception/Clang (C++ → WASM)
│ ├── clang-worker.ts # Parallel clang sub-workers
│ └── simulation.worker.ts # Hot-loaded simulation runner
├── pipeline/
│ ├── pipeline.ts # Orchestrates compile → link → simulate
│ ├── verilator-api.ts # Verilator worker API
│ ├── emception-api.ts # Compiler worker API
│ └── simulation-api.ts # Simulation worker API
├── lib/
│ ├── harness-template.ts # C++ harness generator (wraps Verilator model)
│ ├── verilated-light.ts # Minimal Verilator runtime (~200 lines vs 3900)
│ ├── signal-extractor.ts # Parses Verilator headers for signal metadata
│ ├── asset-fetch.ts # OPFS-cached fetch + brotli decode for runtime assets
│ ├── asset-urls.ts # Build-time hashed asset manifest (generated)
│ ├── opfs-store.ts # OPFS read/write helpers
│ ├── preloader.ts # Pre-startup byte-progress preloader
│ └── sysroot-libs.ts # Loads concatenated sysroot bundle from OPFS
├── components/ # Vue 3 IDE components
├── composables/
│ └── usePipeline.ts # Vue composable bridging pipeline to UI
├── stores/
│ └── project.ts # Pinia store
└── bridge/
├── signal-protocol.ts # SharedArrayBuffer layout for ArduPilot bridge
└── shpak-bridge.ts # Connection to Shpak flight simulator
- Minimal verilated runtime — 200 lines replacing 3900, eliminates C++ exception overhead
-fwasm-exceptions— native WASM exception handling, no JS invoke_* boundary crossings- Parallel compilation — 4 clang sub-workers compile .cpp files concurrently
- Incremental compilation — object file cache, only recompile changed files
-O3 -msimd128— aggressive optimization + WASM SIMD for all builds- Dead code elimination —
--gc-sections+-ffunction-sectionsremoves unused code - Prewarm — compiles a tiny module on startup to warm V8 JIT and cache runtime objects
- Brotli + OPFS asset pipeline —
.wasm/.packassets are content-hashed and brotli-compressed at build time, decoded on the client viabrotli-wasm, and cached (decompressed) in OPFS so subsequent loads are network-free - Split assets — anything over the 25 MB Workers Assets limit (e.g. the 74 MB emscripten sysroot) is sliced into ≤25 MB parts at build time and fetched in parallel
- Sysroot bundle —
libc.a,libc++.a, etc. are concatenated into a singlesysroot-libs.bin+ JSON offset manifest, eliminating per-file requests
| Layer | Technology |
|---|---|
| UI | Vue 3 + Composition API |
| Editor | Monaco Editor |
| Waveforms | Surfer (Rust/WASM) |
| State | Pinia |
| Build | Vite |
| Verilator | v5.046 compiled to WASM via Emscripten |
| Compiler | Emception (LLVM 15 + Clang + LLD + Binaryen) |
| Sysroot | emsdk 3.1.61 libc/libc++/libc++abi with -fwasm-exceptions |
MIT