Skip to content

UnsignedChad/nvc-wasm

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nvc-wasm

A WebAssembly build of the nvc VHDL analyser/elaborator/simulator. Runs in Node.js today and in any modern browser with SharedArrayBuffer + cross-origin isolation.

Status

Working. nvc.wasm analyses, elaborates, and simulates real VHDL designs using the IEEE 1993 and 2008 standard libraries:

=== Counter using IEEE numeric_bit (VHDL 2008) ===
** Note: 10ns+0: count = 1
** Note: 20ns+0: count = 2
** Note: 30ns+0: count = 3
...

What works:

  • VHDL 1993 standard library (std, ieee including std_logic_1164, numeric_bit, numeric_std, math_real, the vital_* packages)
  • VHDL 2008 standard library, minus IEEE.FIXED_PKG (known crash; see Limitations)
  • The bytecode interpreter path (--disable-llvm), which is the only viable execution model on wasm
  • Threading via Emscripten pthreads (SharedArrayBuffer)
  • File I/O via NODERAWFS=1 (the wasm module sees the host filesystem directly when run via Node)

What doesn't:

  • VHDL 2019 STD.REFLECTION crashes the wasm interpreter mid-elaboration (memory access out of bounds — an interpreter bug, not a fundamental blocker)
  • IEEE.FIXED_PKG / IEEE.FLOAT_PKG (both std-2008 and std-2019) hit a similar crash during the generic-package instantiation
  • Foreign C subprograms (VHPI, GHDL-style --foreign) are disabled — there's no dlopen on wasm. The C ABI required to call them would need to be replaced with statically-linked symbols at wasm link time.
  • LLVM JIT and x86 JIT backends are both disabled; wasm cannot generate executable code at runtime.

Why the previous attempt concluded this was impossible

The previous README said: "impossible to build nvc for [wasm] without massive changes because NVC uses dynamic linking and wasm does not support so."

That's correct in substance — nvc has four uses of dynamic linking:

  1. Per-design .so generation at elaboration time (cgen.c, make.c). Each VHDL unit becomes a native shared library. Elaboration calls fork() to invoke the system C compiler, then dlopens the result.
  2. LLVM JIT (jit-llvm.c) and x86 JIT (jit-x86.c) — runtime native code generation; needs mmap(PROT_EXEC).
  3. dlopen(NULL, ...) in jit-ffi.c to expose nvc's own internal symbols (the INTERNAL foreign-function convention).
  4. dlopen(user.so) in jit-ffi.c for VHPI / GHDL-style foreign C.

Wasm can do exactly none of these. But nvc also has a complete bytecode interpreter (jit-interp.c) that needs none of them. The previous attempt tried to build the whole machine with cmake glob *.c and didn't reach the point of discovering that ./configure --disable-llvm --without-system-cc sidesteps blockers (1) and (2) entirely. (3) and (4) are addressed by the patches in patches/nvc-wasm.patch.

Building

You need:

  • emsdklatest is fine
  • autoconf, automake, flex, bison, pkg-config
  • git, curl
git submodule update --init 3rdparty/nvc
source /path/to/emsdk/emsdk_env.sh
./build.sh

Produces build/wasm/bin/nvc.{js,wasm} plus the compiled standard libraries in build/wasm/lib/.

Running

node build/wasm/bin/nvc -L build/wasm/lib -a your.vhd -e top -r

For VHDL-2008:

node build/wasm/bin/nvc --std=08 -L build/wasm/lib -a your.vhd -e top -r

How it works

build.sh does five things, in order:

  1. Applies patches/nvc-wasm.patch to the pinned nvc submodule. The patch is small (~40 lines net) and guards wasm-incompatible code with #ifdef __EMSCRIPTEN__. Source files touched:

    • src/jit/jit-ffi.c — stub dlopen/dlsym/dlclose for wasm
    • src/jit/jit-code.c — skip __builtin___clear_cache on wasm
    • src/thread.c — disable signal-based stop-the-world on wasm
    • src/util.c — route nvc_memalign/munmap through posix_memalign/free (mmap's partial-munmap trick doesn't work on Emscripten)
    • thirdparty/cpustate.c — no-op stub for register capture on wasm
    • src/vhpi/vhpi_user.h — include <stdint.h> on Emscripten
    • src/rt/{assert,simpkg,standard,stdenv}.c — fix UB in foreign symbol signatures (some declared 1-arg but called as 2-arg; works on x86, trapped by wasm's strict indirect-call type checking)
    • src/jit/Makemodule.am — include the generated wasm_symtab.c
  2. Generates src/jit/wasm_symtab.c from src/symbols.txt. This is a static (name → function pointer) lookup table that replaces dlsym(NULL, name) for nvc's INTERNAL foreign symbols.

  3. Builds wasm dependencies in build/wasm-deps/:

    • Real libzstd.a (used by nvc's compressed work-library format)
    • Stub libffi.a (the wasm32 backend in upstream libffi 3.4.6 references Emscripten JS helpers that were renamed; the stub satisfies the linker and any actual call traps at runtime, which is fine because FFI is disabled)
  4. Configures nvc with emconfigure ./configure --disable-llvm --without-system-cc --host=wasm32-unknown-emscripten, passing --disable-llvm (no LLVM JIT) and --without-system-cc (no AOT-via- external-CC). Also pre-seeds a few ac_cv_func_*=no cache vars because autoconf's function probes give false positives under cross-compile.

  5. Runs emmake make -k. The -k lets the build continue past the two known stdlib crash points (STD.REFLECTION, IEEE.FIXED_PKG) so we still get all the working stdlib units.

Repository layout

.
├── 3rdparty/nvc/         # nvc submodule (pinned upstream commit)
├── patches/
│   └── nvc-wasm.patch    # applied to nvc at build time
├── scripts/
│   ├── build_deps.sh     # builds wasm libzstd + stub libffi
│   ├── gen_wasm_symtab.sh # generates wasm symbol lookup table
│   └── libffi_stub.c     # stub libffi source
├── build.sh              # top-level entry point
└── README.md

Credit

This builds on top of:

  • Zhukov Georgiy's nvc_wasm, which mapped out the dependency space and concluded it would need "massive changes." It does — but they're tractable when you start from --disable-llvm and don't try to recreate nvc's own autotools in CMake.
  • The nvc compiler by Nick Gasson, GPLv3.

About

NVC (free VHDL compiler) build for WASM in purpose to use in SVHDL project

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Shell 86.1%
  • C 13.9%