mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-05 00:50:50 +02:00
The pieces that make Magic actually buildable as a WASM library.
* magic/magicWasm.c — new headless entry point exporting four
functions used by the JS wrapper:
- magic_wasm_init() idempotent initialisation
- magic_wasm_run_command(s) dispatch one Magic command
- magic_wasm_source_file(p) execute a script from the VFS
- magic_wasm_update() drive a display-update cycle
Sets CAD_ROOT=/ if unset, so embedded technology files under
/magic/sys/ resolve correctly. Centers the command point inside
GrScreenRect so commands route to the layout window client
rather than the border/window-management client.
* utils/main.c, utils/main.h — split magicMain() into magicMainInit()
+ the dispatch loop. magicMainInit is idempotent (a static flag
guards against re-initialisation) so JS callers can call any of
the four wasm entry points first without sequencing.
* magic/Makefile — adds the WASM link target, gated by MAKE_WASM=1
set from toolchains/emscripten/defs.mak. Conditionally compiles
magicWasm.c into the main binary, links to magic.js and runs
post-build.sh on the result.
* toolchains/emscripten/defs.mak — Emscripten linker flags (WASM=1,
MODULARIZE, EXPORT_ES6, ALLOW_MEMORY_GROWTH, INITIAL_MEMORY=32M,
STACK_SIZE=5M), the four EXPORTED_FUNCTIONS, and the embed-file
bindings for the technology files under /magic/sys/.
* toolchains/emscripten/post-build.sh — patches Emscripten's ESM
output so it works in pure Node.js ESM: aliases require()
through createRequire, injects __filename / __dirname shims,
and resyncs the ___emscripten_embedded_file_data constant from
the wasm global section if Emscripten emitted a stale value.
Idempotent and pinned to emsdk 3.1.56 (see WARNING in the
header).
* toolchains/emscripten/README.md — full build documentation:
quick-start via npm/build.sh, manual build, list of embedded
files, exported C API, JavaScript usage example, and notes on
CAD_ROOT, DISPLAY_SUSPEND, and the signal-API stubs.
* .gitignore — adds the WASM artefacts (magic.js, magic.wasm,
magic.symbols), tightens the editor/OS cruft list, and keeps
toolchains/emscripten/defs.mak tracked despite the `defs.mak`
ignore rule.
101 lines
3.3 KiB
Markdown
101 lines
3.3 KiB
Markdown
# Magic VLSI — Headless WASM Build
|
|
|
|
This toolchain builds Magic as a headless WebAssembly module using Emscripten.
|
|
X11, Tk, OpenGL, and readline are all disabled. The resulting `magic.js` /
|
|
`magic.wasm` pair can be loaded in Node.js, a browser, or a Web Worker.
|
|
|
|
## Quick start (npm package)
|
|
|
|
The easiest way to build and use the WASM module is through the npm package:
|
|
|
|
```bash
|
|
# Build magic.js + magic.wasm and copy them into npm/
|
|
bash npm/build.sh
|
|
|
|
# Run the test suite (extract, GDS, DRC, CIF)
|
|
npm --prefix npm test
|
|
```
|
|
|
|
See [`npm/examples/`](../../npm/examples/) for usage examples.
|
|
|
|
## Manual build
|
|
|
|
Prerequisites: an activated [emsdk](https://emscripten.org/docs/getting_started/downloads.html)
|
|
checkout (`emcc`, `emar`, `emranlib` on `PATH`), plus standard `make` and `gcc`.
|
|
|
|
```bash
|
|
# 1. Configure for Emscripten
|
|
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" \
|
|
emconfigure ./configure \
|
|
--without-cairo --without-opengl --without-x --without-tk --without-tcl \
|
|
--disable-readline --disable-compression \
|
|
--host=asmjs-unknown-emscripten \
|
|
--target=asmjs-unknown-emscripten
|
|
|
|
# 2. Append the Emscripten-specific make settings
|
|
cat toolchains/emscripten/defs.mak >> defs.mak
|
|
|
|
# 3. Build
|
|
emmake make depend
|
|
emmake make -j$(nproc) modules libs
|
|
emmake make techs
|
|
emmake make mains
|
|
```
|
|
|
|
The outputs are `magic/magic.js` and `magic/magic.wasm`.
|
|
|
|
## Embedded files
|
|
|
|
The following runtime files are baked directly into the WASM binary via
|
|
Emscripten's `--embed-file` mechanism and are available at startup without
|
|
any host filesystem access:
|
|
|
|
| Host path | VFS path |
|
|
|-----------|----------|
|
|
| `scmos/` | `/magic/sys/current/` |
|
|
| `windows/windows7.glyphs` | `/magic/sys/windows7.glyphs` |
|
|
| `windows/windows7.glyphs` | `/magic/sys/bw.glyphs` |
|
|
|
|
To embed a custom technology file, add an `--embed-file` entry to
|
|
`TOP_EXTRA_LIBS` in [`defs.mak`](defs.mak).
|
|
|
|
## Exported C API
|
|
|
|
The WASM module exports four functions:
|
|
|
|
| Function | Description |
|
|
|----------|-------------|
|
|
| `magic_wasm_init()` | Initialize Magic (idempotent — safe to call multiple times). Returns 0 on success. |
|
|
| `magic_wasm_run_command(const char *cmd)` | Dispatch one Magic command. Calls `magic_wasm_init()` automatically if needed. Returns 0 on success. |
|
|
| `magic_wasm_source_file(const char *path)` | Read and execute a command file from the virtual filesystem. |
|
|
| `magic_wasm_update()` | Drive a display-update cycle. No-op in headless builds (null display suspends all redraws). |
|
|
|
|
### JavaScript usage
|
|
|
|
```js
|
|
import createMagic from 'magic-vlsi-wasm';
|
|
|
|
const { runCommand, FS } = await createMagic();
|
|
|
|
// Write a layout file into the virtual filesystem
|
|
FS.writeFile('/work/inv.mag', layoutBytes);
|
|
|
|
// Run Magic commands
|
|
runCommand('tech load sky130A');
|
|
runCommand('load /work/inv');
|
|
runCommand('gds write /work/inv');
|
|
|
|
// Read the result back out
|
|
const gdsBytes = FS.readFile('/work/inv.gds');
|
|
```
|
|
|
|
## Notes
|
|
|
|
- `CAD_ROOT` is automatically set to `/` so that embedded system files are
|
|
resolved under `/magic/sys/`.
|
|
- The null display driver (`-d null`) sets `GrDisplayStatus = DISPLAY_SUSPEND`,
|
|
which causes `WindUpdate` to return immediately without invoking any display
|
|
callbacks. This is what makes the WASM build safe to run without a screen.
|
|
- All POSIX signal/timer APIs (`setitimer`, `SIGALRM`, `fcntl`) are compiled
|
|
out under `__EMSCRIPTEN__`; the display progress timer becomes a no-op.
|