feat(wasm): add browser QEMU build
This commit is contained in:
+28
-13
@@ -12,10 +12,11 @@ touching QEMU internals. Pairs with `ROADMAP.md` (the plan) — this is the
|
||||
- One `xteink` QEMU machine selects `variant=x3|x4` at launch. **Unmodified
|
||||
canonical firmware** detects X3 through I²C fingerprints and boots the home
|
||||
screen; X4 detects through all-NAK probes and reaches a blank SSD1677 stub.
|
||||
- All Phase-1 device models live in **one patch**:
|
||||
`qemu/patches/0001-xteink-machine.patch`, applied onto exact espressif/qemu
|
||||
commit `40edccac415693c5130f91c01d84176ae6008566`.
|
||||
- Next: compile to WASM (qemu-wasm) → static browser UI. Full X4 rendering waits.
|
||||
- Phase-1 device models live in `qemu/patches/0001-xteink-machine.patch`;
|
||||
`0002-qemu-wasm.patch` ports qemu-wasm's host backend onto the same pinned
|
||||
Espressif QEMU commit `40edccac415693c5130f91c01d84176ae6008566`.
|
||||
- `make qemu-wasm` produces a smoke-tested ES module, WASM binary, and pthread
|
||||
worker under `dist/wasm/`. Next: static browser UI. Full X4 rendering waits.
|
||||
|
||||
---
|
||||
|
||||
@@ -207,8 +208,8 @@ ADC ladders on GPIO1 & GPIO2; power button GPIO3; UC8253 @ 16 MHz.
|
||||
|
||||
## 8. Reproducibility model
|
||||
|
||||
- **Durable = the patch** (`qemu/patches/0001-xteink-machine.patch`), verified
|
||||
against exact QEMU commit `40edccac415693c5130f91c01d84176ae6008566` (tag
|
||||
- **Durable = the patches**: apply `0001-xteink-machine.patch`, then
|
||||
`0002-qemu-wasm.patch` for the browser build. Both target exact QEMU commit `40edccac415693c5130f91c01d84176ae6008566` (tag
|
||||
`esp-develop-9.2.2-20260417`). When editing `_scratch/qemu-src`, regenerate:
|
||||
```sh
|
||||
cd <qemu-src> && git add -N <new files> && git diff --binary > <repo>/qemu/patches/0001-xteink-machine.patch
|
||||
@@ -253,15 +254,27 @@ ADC ladders on GPIO1 & GPIO2; power button GPIO3; UC8253 @ 16 MHz.
|
||||
|
||||
---
|
||||
|
||||
## 10. Next steps (in priority order)
|
||||
## 10. WASM build and next steps
|
||||
|
||||
1. **Compile to WASM**: combine this pinned Espressif fork with
|
||||
`ktock/qemu-wasm`'s WASM TCG/TCI backend + Emscripten. De-risk by building an
|
||||
unpatched esp32c3 target under qemu-wasm first, then apply our patch.
|
||||
2. **Static browser front-end**: display surface → canvas; physical buttons →
|
||||
- `make qemu-wasm` uses Podman or Docker and the pinned Emscripten 3.1.50 image
|
||||
in `qemu/wasm/Dockerfile`. It builds only `riscv32-softmmu` with the xteink
|
||||
device graph; unrelated boards, networking, audio, virtfs, tools, and docs are
|
||||
disabled. Outputs go to `dist/wasm/`.
|
||||
- qemu-wasm commit `0ef7b4e2814b231705d8371dd7997f5b72e70baf` is based on
|
||||
QEMU 8.2; `0002-qemu-wasm.patch` is the resolved port to Espressif QEMU 9.2.
|
||||
`-sEMULATE_FUNCTION_POINTER_CASTS=1` is required for QEMU's QOM callbacks.
|
||||
- The WASM dependency image omits libgcrypt. AES/RSA/DS/XTS devices are therefore
|
||||
not instantiated; their MMIO falls through to the existing zero-return stub.
|
||||
Canonical firmware boot still needs browser-level validation; add cross-built
|
||||
libgcrypt only if firmware proves it uses those accelerators.
|
||||
- Emscripten pthreads require cross-origin isolation (COOP/COEP) in the browser.
|
||||
|
||||
Next:
|
||||
|
||||
1. **Static browser front-end**: display surface → canvas; physical buttons →
|
||||
ADC/GPIO controls; uploaded flash; SD block backend; `variant=x3|x4` chosen
|
||||
before boot. Must run fully from static assets (airgapped).
|
||||
3. **Full X4 rendering later**: SSD1677 is 800×480 controller / 480×800 portrait,
|
||||
2. **Full X4 rendering later**: SSD1677 is 800×480 controller / 480×800 portrait,
|
||||
BUSY active-high. Implement its RAM/window/update commands when needed.
|
||||
|
||||
---
|
||||
@@ -271,7 +284,9 @@ ADC ladders on GPIO1 & GPIO2; power button GPIO3; UC8253 @ 16 MHz.
|
||||
| What | Where |
|
||||
|------|-------|
|
||||
| Emulator repo | `/home/evanreichard/Development/git/personal/xteink-web-emulator` |
|
||||
| The patch | `qemu/patches/0001-xteink-machine.patch` |
|
||||
| Native/WASM patches | `qemu/patches/0001-xteink-machine.patch`, `0002-qemu-wasm.patch` |
|
||||
| WASM environment | `qemu/wasm/Dockerfile` |
|
||||
| WASM build | `scripts/build-qemu-wasm.sh` → `dist/wasm/` |
|
||||
| QEMU source (ephemeral) | `_scratch/qemu-src` (via `make qemu`) |
|
||||
| Canonical firmware | `https://github.com/crosspoint-reader/crosspoint-reader` |
|
||||
| Tested firmware checkout | `/tmp/crosspoint-reader-main` @ `556b8ae` (unmodified) |
|
||||
|
||||
@@ -5,9 +5,11 @@ FIRMWARE_DIR ?= $(FIRMWARE_REPO)/.pio/build/default
|
||||
SD_SRC ?= $(FIRMWARE_REPO)/sdcard
|
||||
QEMU_SRC ?= _scratch/qemu-src
|
||||
QEMU_BIN = $(QEMU_SRC)/build/qemu-system-riscv32
|
||||
QEMU_WASM_SRC ?= _scratch/qemu-wasm-src
|
||||
WASM_OUT ?= dist/wasm
|
||||
VARIANT ?= x3
|
||||
|
||||
.PHONY: firmware sdimage qemu run run-upstream chip clean
|
||||
.PHONY: firmware sdimage qemu qemu-wasm run run-upstream chip clean
|
||||
|
||||
firmware:
|
||||
esptool --chip esp32c3 merge-bin -o flash.bin \
|
||||
@@ -24,6 +26,9 @@ sdimage:
|
||||
qemu:
|
||||
QEMU_SRC=$(QEMU_SRC) scripts/build-qemu.sh
|
||||
|
||||
qemu-wasm:
|
||||
QEMU_WASM_SRC=$(QEMU_WASM_SRC) WASM_OUT=$(WASM_OUT) JOBS=2 scripts/build-qemu-wasm.sh
|
||||
|
||||
# Select X4 with `make run VARIANT=x4`. Add `-display none` for headless.
|
||||
run: qemu
|
||||
$(QEMU_BIN) -machine xteink,variant=$(VARIANT) -L $(QEMU_SRC)/pc-bios \
|
||||
|
||||
@@ -4,11 +4,12 @@ An offline, in-browser emulator for the xteink **X3/X4** (ESP32-C3 + e-ink):
|
||||
upload a firmware `.bin`, run the real machine code client-side, see the screen,
|
||||
press buttons, mount a virtual SD — no server, no proprietary engine.
|
||||
|
||||
**Status:** one native `xteink` machine selects X3 or X4 at launch. Unmodified
|
||||
**Status:** native and WebAssembly builds provide one `xteink` machine that
|
||||
selects X3 or X4 at launch. Unmodified
|
||||
[canonical firmware](https://github.com/crosspoint-reader/crosspoint-reader)
|
||||
auto-detects the selected variant: X3 boots with its UC8253 display and SD card;
|
||||
X4 reaches its SSD1677 driver through a blank protocol stub. The browser (WASM)
|
||||
port is next. See [ROADMAP.md](./ROADMAP.md) for architecture and plan.
|
||||
X4 reaches its SSD1677 driver through a blank protocol stub. The static browser
|
||||
frontend is next. See [ROADMAP.md](./ROADMAP.md) for architecture and plan.
|
||||
|
||||
## Quick start (native QEMU)
|
||||
|
||||
@@ -25,12 +26,30 @@ make run VARIANT=x4 # X4 detection + blank SSD1677 stub
|
||||
Point at a firmware build with `make firmware FIRMWARE_DIR=/path/to/.pio/build/gh_release`.
|
||||
`make qemu` is a long compile on modest hardware — set `JOBS` to taste.
|
||||
|
||||
## WebAssembly build
|
||||
|
||||
Podman or Docker is required. The build is limited to `riscv32-softmmu` and the
|
||||
X3/X4 device graph; networking, audio, virtfs, tools, docs, and unrelated boards
|
||||
are disabled.
|
||||
|
||||
```sh
|
||||
make qemu-wasm
|
||||
# dist/wasm/qemu-system-riscv32.{js,wasm,worker.js}
|
||||
```
|
||||
|
||||
The build runs a Node smoke check when Node is available. Browser execution
|
||||
requires cross-origin isolation for Emscripten pthreads; the frontend and its
|
||||
COOP/COEP serving setup are the next phase.
|
||||
|
||||
## Contents
|
||||
|
||||
- `qemu/patches/0001-xteink-machine.patch` — the `xteink,variant=x3|x4` machine
|
||||
and its device models (I²C fingerprints, ADC, GPIO, SPI2, X3 UC8253, X4 panel
|
||||
stub, SD-over-SPI fix), applied onto the pinned espressif/qemu commit by
|
||||
`scripts/build-qemu.sh`.
|
||||
- `qemu/patches/0002-qemu-wasm.patch` and `qemu/wasm/Dockerfile` — the pinned
|
||||
qemu-wasm host backend port and minimal Emscripten dependency environment,
|
||||
built by `scripts/build-qemu-wasm.sh`.
|
||||
- `flake.nix` — the espressif-qemu *release* binary as the fast generic baseline
|
||||
(`nix run .#run-upstream -- flash.bin`), plus a devShell with QEMU's full build
|
||||
environment. `Makefile` — `qemu`, `firmware`, `sdimage`, `run`, `chip`.
|
||||
|
||||
+8
-6
@@ -19,7 +19,7 @@ running in-browser from static files. The endgame merges those two.
|
||||
|
||||
## Status
|
||||
|
||||
**Phase 1 (native foundation) is done for X3 and X4 selection.** Unmodified
|
||||
**The native foundation and WASM compile phase are done.** Unmodified
|
||||
[canonical firmware](https://github.com/crosspoint-reader/crosspoint-reader)
|
||||
auto-detects `xteink,variant=x3` through its real I²C fingerprint and boots the
|
||||
X3 home screen with SD support. `variant=x4` omits those chips, so the same
|
||||
@@ -35,6 +35,8 @@ make run VARIANT=x4 # X4 detection + blank panel stub
|
||||
|
||||
QMP screenshots confirmed the X3 home screen and 528×792 orientation; captured
|
||||
X4 SPI traffic confirmed the firmware selected its SSD1677 driver.
|
||||
`make qemu-wasm` produces the Emscripten module, WASM binary, and pthread worker
|
||||
under `dist/wasm/`; a Node smoke check confirms `xteink` is registered.
|
||||
|
||||
### Device selection (X3 vs X4)
|
||||
|
||||
@@ -80,11 +82,9 @@ reuses unchanged — no bespoke abstraction layer:
|
||||
|
||||
## Remaining phases
|
||||
|
||||
1. **Compile the patched fork to WASM** — combine Espressif's SoC models with
|
||||
qemu-wasm's WASM TCG/TCI backend; build `qemu-system-riscv32` with Emscripten.
|
||||
2. **Browser front-end (static)** — uploaded flash, canvas, physical buttons,
|
||||
1. **Browser front-end (static)** — uploaded flash, canvas, physical buttons,
|
||||
SD block backend, and pre-boot X3/X4 picker. Fully airgapped.
|
||||
3. **Full X4 panel** — implement SSD1677 RAM/window/update commands when visible
|
||||
2. **Full X4 panel** — implement SSD1677 RAM/window/update commands when visible
|
||||
X4 rendering is needed; the selection, dimensions, wiring, and stub exist.
|
||||
|
||||
## Repo layout
|
||||
@@ -94,7 +94,9 @@ reuses unchanged — no bespoke abstraction layer:
|
||||
| `flake.nix` | espressif-qemu release pkg (`nix run .#run-upstream`) + full QEMU build devShell |
|
||||
| `Makefile` | `qemu` (source build), `firmware`, `sdimage`, `run`, `chip` |
|
||||
| `scripts/build-qemu.sh` | clone pinned espressif/qemu, apply patch, build riscv32-softmmu |
|
||||
| `qemu/patches/` | xteink machine + device models (applied onto the pinned QEMU commit) |
|
||||
| `qemu/patches/` | xteink devices plus the qemu-wasm host port, applied onto pinned Espressif QEMU |
|
||||
| `qemu/wasm/Dockerfile` | Minimal pinned Emscripten dependency environment |
|
||||
| `scripts/build-qemu-wasm.sh` | X3/X4-only WASM build → `dist/wasm/` |
|
||||
| `chip/eink-x3.chip.c` | legacy Wokwi model — the reverse-engineered X3 e-ink protocol reference |
|
||||
| `web/` | (phase 3) static front-end: upload + canvas + buttons |
|
||||
|
||||
|
||||
@@ -564,12 +564,13 @@ index 5f4022f..1477f15 100644
|
||||
switch (opcode) {
|
||||
case I2C_OPCODE_RSTART:
|
||||
i2c_end_transfer(s->bus);
|
||||
@@ -261,9 +272,16 @@ static void esp32_i2c_init(Object * obj)
|
||||
@@ -261,9 +272,17 @@ static void esp32_i2c_init(Object * obj)
|
||||
fifo8_create(&s->rx_fifo, ESP32_I2C_FIFO_LENGTH);
|
||||
}
|
||||
|
||||
+static const Property esp32_i2c_properties[] = {
|
||||
+ DEFINE_PROP_BOOL("c3", Esp32I2CState, c3, false),
|
||||
+ DEFINE_PROP_END_OF_LIST(),
|
||||
+};
|
||||
+
|
||||
static void esp32_i2c_class_init(ObjectClass * klass, void * data)
|
||||
@@ -708,11 +709,15 @@ diff --git i/hw/riscv/Kconfig w/hw/riscv/Kconfig
|
||||
index 192ab47..293808d 100644
|
||||
--- i/hw/riscv/Kconfig
|
||||
+++ w/hw/riscv/Kconfig
|
||||
@@ -119,4 +119,5 @@ config RISCV_ESP32C3
|
||||
@@ -119,4 +119,9 @@ config RISCV_ESP32C3
|
||||
select OPENCORES_ETH
|
||||
select UNIMP
|
||||
select ESP_RGB
|
||||
+ select I2C
|
||||
+ select SSI
|
||||
+ select SSI_SD
|
||||
+ select SSI_M25P80
|
||||
+ select CAN_SJA1000
|
||||
|
||||
diff --git i/hw/riscv/esp32c3.c w/hw/riscv/esp32c3.c
|
||||
index ed698fb..2f1ccbf 100644
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
ARG EMSDK_VERSION=3.1.50
|
||||
ARG ZLIB_VERSION=1.3.1
|
||||
ARG GLIB_SERIES=2.75
|
||||
ARG GLIB_VERSION=2.75.0
|
||||
ARG FFI_COMMIT=adbcf2b247696dde2667ab552cb93e0c79455c84
|
||||
|
||||
FROM emscripten/emsdk:${EMSDK_VERSION} AS base
|
||||
ENV TARGET=/build/target
|
||||
ENV CFLAGS="-O2 -matomics -mbulk-memory -DNDEBUG -sWASM_BIGINT -DWASM_BIGINT -pthread -sMALLOC=mimalloc -sASYNCIFY=1"
|
||||
ENV CXXFLAGS="$CFLAGS"
|
||||
ENV LDFLAGS="-L$TARGET/lib -O2"
|
||||
ENV CPATH="$TARGET/include"
|
||||
ENV PKG_CONFIG_PATH="$TARGET/lib/pkgconfig"
|
||||
ENV EM_PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
|
||||
ENV CHOST=wasm32-unknown-linux
|
||||
ENV MAKEFLAGS=-j2
|
||||
RUN apt-get update && apt-get install -y \
|
||||
autoconf build-essential libglib2.0-dev libtool ninja-build pkgconf python3-pip
|
||||
RUN pip3 install meson==1.5.0 tomli
|
||||
WORKDIR /build
|
||||
RUN mkdir -p "$TARGET"
|
||||
|
||||
FROM base AS zlib
|
||||
ARG ZLIB_VERSION
|
||||
RUN mkdir /zlib \
|
||||
&& curl -Ls "https://zlib.net/fossils/zlib-${ZLIB_VERSION}.tar.gz" \
|
||||
| tar xzC /zlib --strip-components=1
|
||||
WORKDIR /zlib
|
||||
RUN emconfigure ./configure --prefix="$TARGET" --static && make install
|
||||
|
||||
FROM base AS libffi
|
||||
ARG FFI_COMMIT
|
||||
RUN git clone https://github.com/libffi/libffi /libffi \
|
||||
&& git -C /libffi checkout "$FFI_COMMIT"
|
||||
WORKDIR /libffi
|
||||
RUN autoreconf -fiv \
|
||||
&& emconfigure ./configure --host="$CHOST" --prefix="$TARGET" \
|
||||
--enable-static --disable-shared --disable-dependency-tracking \
|
||||
--disable-builddir --disable-multi-os-directory --disable-raw-api \
|
||||
--disable-structs --disable-docs \
|
||||
&& emmake make install SUBDIRS=include
|
||||
|
||||
FROM base AS glib
|
||||
ARG GLIB_SERIES
|
||||
ARG GLIB_VERSION
|
||||
COPY --from=zlib /build/ /build/
|
||||
COPY --from=libffi /build/ /build/
|
||||
RUN mkdir /stub \
|
||||
&& printf '%s\n' '#include <netdb.h>' \
|
||||
'int res_query(const char *n, int c, int t, unsigned char *d, int l) { h_errno = HOST_NOT_FOUND; return -1; }' \
|
||||
>/stub/res_query.c \
|
||||
&& emcc $CFLAGS -c /stub/res_query.c -fPIC -o /stub/libresolv.o \
|
||||
&& ar rcs "$TARGET/lib/libresolv.a" /stub/libresolv.o
|
||||
RUN mkdir /glib \
|
||||
&& curl -Lks "https://download.gnome.org/sources/glib/${GLIB_SERIES}/glib-${GLIB_VERSION}.tar.xz" \
|
||||
| tar xJC /glib --strip-components=1
|
||||
WORKDIR /glib
|
||||
ENV CFLAGS="-Wno-error=incompatible-function-pointer-types -O2 -matomics -mbulk-memory -DNDEBUG -pthread -sWASM_BIGINT -sMALLOC=mimalloc -sASYNCIFY=1"
|
||||
ENV CXXFLAGS="$CFLAGS"
|
||||
RUN printf '%s\n' \
|
||||
'#!/bin/bash' \
|
||||
'set -euo pipefail' \
|
||||
'cmd="$1"; shift' \
|
||||
'args=()' \
|
||||
'for arg in "$@"; do args+=("${arg/-Werror=unused-command-line-argument/-Wno-error=unused-command-line-argument}"); done' \
|
||||
'"$cmd" "${args[@]}"' \
|
||||
>/emcc-meson-wrap.sh && chmod +x /emcc-meson-wrap.sh
|
||||
RUN printf '%s\n' \
|
||||
'[host_machine]' \
|
||||
"system = 'emscripten'" \
|
||||
"cpu_family = 'wasm32'" \
|
||||
"cpu = 'wasm32'" \
|
||||
"endian = 'little'" \
|
||||
'' \
|
||||
'[binaries]' \
|
||||
"c = ['bash', '/emcc-meson-wrap.sh', 'emcc']" \
|
||||
"cpp = ['bash', '/emcc-meson-wrap.sh', 'em++']" \
|
||||
"ar = 'emar'" \
|
||||
"ranlib = 'emranlib'" \
|
||||
"pkgconfig = ['pkg-config', '--static']" \
|
||||
>/cross.meson
|
||||
RUN meson setup _build --prefix="$TARGET" --cross-file=/cross.meson \
|
||||
--default-library=static --buildtype=release --force-fallback-for=pcre2,gvdb \
|
||||
-Dselinux=disabled -Dxattr=false -Dlibmount=disabled -Dnls=disabled \
|
||||
-Dtests=false -Dglib_assert=false -Dglib_checks=false \
|
||||
&& sed -i -E '/#define HAVE_(CLOSE_RANGE|EPOLL_CREATE|KQUEUE|POSIX_SPAWN|FALLOCATE) 1/d' _build/config.h \
|
||||
&& meson install -C _build
|
||||
|
||||
FROM base
|
||||
COPY --from=glib /build/ /build/
|
||||
WORKDIR /build
|
||||
CMD ["sleep", "infinity"]
|
||||
Executable
+79
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
SRC="${QEMU_WASM_SRC:-$ROOT/_scratch/qemu-wasm-src}"
|
||||
OUT="${WASM_OUT:-$ROOT/dist/wasm}"
|
||||
[[ "$SRC" = /* ]] || SRC="$ROOT/$SRC"
|
||||
[[ "$OUT" = /* ]] || OUT="$ROOT/$OUT"
|
||||
TAG="esp-develop-9.2.2-20260417"
|
||||
COMMIT="40edccac415693c5130f91c01d84176ae6008566"
|
||||
QEMU_WASM_COMMIT="0ef7b4e2814b231705d8371dd7997f5b72e70baf"
|
||||
IMAGE="xteink-qemu-wasm-build"
|
||||
JOBS="${JOBS:-2}"
|
||||
|
||||
if [ -n "${CONTAINER_ENGINE:-}" ]; then
|
||||
ENGINE="$CONTAINER_ENGINE"
|
||||
elif command -v podman >/dev/null; then
|
||||
ENGINE=podman
|
||||
else
|
||||
ENGINE=docker
|
||||
fi
|
||||
|
||||
if [ ! -d "$SRC/.git" ]; then
|
||||
git clone --depth 1 --branch "$TAG" https://github.com/espressif/qemu "$SRC"
|
||||
fi
|
||||
|
||||
cd "$SRC"
|
||||
if [ "$(git rev-parse HEAD)" != "$COMMIT" ]; then
|
||||
echo "QEMU source must be $COMMIT ($TAG)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f hw/display/xteink_x3_eink.c ] || [ ! -f tcg/wasm32.c ]; then
|
||||
if ! git diff --quiet || ! git diff --cached --quiet; then
|
||||
echo "QEMU source has changes that conflict with the WASM patches" >&2
|
||||
exit 1
|
||||
fi
|
||||
git apply "$ROOT/qemu/patches/0001-xteink-machine.patch"
|
||||
git apply --whitespace=nowarn "$ROOT/qemu/patches/0002-qemu-wasm.patch"
|
||||
fi
|
||||
|
||||
printf 'Building Emscripten environment (qemu-wasm %s)\n' "$QEMU_WASM_COMMIT"
|
||||
"$ENGINE" build -t "$IMAGE" -f "$ROOT/qemu/wasm/Dockerfile" "$ROOT/qemu/wasm"
|
||||
|
||||
FLAGS="-O3 -Wno-error=unused-command-line-argument -matomics -mbulk-memory -DNDEBUG -DG_DISABLE_ASSERT -D_GNU_SOURCE -sASYNCIFY=1 -pthread -sPROXY_TO_PTHREAD=1 -sFORCE_FILESYSTEM -sALLOW_TABLE_GROWTH -sEMULATE_FUNCTION_POINTER_CASTS=1 -sINITIAL_MEMORY=512MB -sWASM_BIGINT -sMALLOC=mimalloc -sEXPORT_ES6=1 -sASYNCIFY_IMPORTS=ffi_call_js"
|
||||
|
||||
if [ ! -f build/build.ninja ]; then
|
||||
"$ENGINE" run --rm -v "$SRC:/qemu" "$IMAGE" bash -lc "
|
||||
cd /qemu
|
||||
emconfigure ./configure \\
|
||||
--static \\
|
||||
--target-list=riscv32-softmmu \\
|
||||
--cpu=wasm32 \\
|
||||
--cross-prefix= \\
|
||||
--without-default-features \\
|
||||
--without-default-devices \\
|
||||
--with-devices-riscv32=xteink \\
|
||||
--enable-system \\
|
||||
--with-coroutine=fiber \\
|
||||
--disable-werror \\
|
||||
--disable-docs \\
|
||||
--disable-tools \\
|
||||
--extra-cflags='$FLAGS' \\
|
||||
--extra-cxxflags='$FLAGS' \\
|
||||
--extra-ldflags='-sEXPORTED_RUNTIME_METHODS=getTempRet0,setTempRet0,addFunction,removeFunction,TTY,FS'
|
||||
"
|
||||
fi
|
||||
|
||||
"$ENGINE" run --rm -v "$SRC:/qemu" "$IMAGE" \
|
||||
bash -lc "cd /qemu && emmake ninja -C build -j$JOBS qemu-system-riscv32.js"
|
||||
|
||||
mkdir -p "$OUT"
|
||||
install -m 0644 build/qemu-system-riscv32.js "$OUT/"
|
||||
install -m 0644 build/qemu-system-riscv32.wasm "$OUT/"
|
||||
install -m 0644 build/qemu-system-riscv32.worker.js "$OUT/"
|
||||
if command -v node >/dev/null; then
|
||||
"$ROOT/scripts/smoke-qemu-wasm.sh" "$OUT/qemu-system-riscv32.js"
|
||||
fi
|
||||
printf '%s\n' "$OUT"
|
||||
@@ -0,0 +1,9 @@
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
const modulePath = process.argv[2];
|
||||
if (!modulePath) {
|
||||
throw new Error('usage: node scripts/smoke-qemu-wasm.mjs <qemu-system-riscv32.js>');
|
||||
}
|
||||
|
||||
const { default: createQemu } = await import(pathToFileURL(modulePath));
|
||||
await createQemu({ arguments: ['-machine', 'help'] });
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
MODULE="${1:?usage: scripts/smoke-qemu-wasm.sh <qemu-system-riscv32.js>}"
|
||||
OUTPUT="$(mktemp)"
|
||||
trap 'rm -f "$OUTPUT"' EXIT
|
||||
|
||||
timeout 15 node "$(dirname "$0")/smoke-qemu-wasm.mjs" "$MODULE" >"$OUTPUT" 2>&1 || status=$?
|
||||
status="${status:-0}"
|
||||
if [ "$status" -ne 0 ] && [ "$status" -ne 1 ] && [ "$status" -ne 124 ]; then
|
||||
cat "$OUTPUT" >&2
|
||||
exit "$status"
|
||||
fi
|
||||
|
||||
grep -F 'xteink xteink X3/X4 (ESP32-C3); variant=x3|x4' "$OUTPUT" >/dev/null
|
||||
if grep -Eq 'RuntimeError|table index is out of bounds' "$OUTPUT"; then
|
||||
cat "$OUTPUT" >&2
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user