English | 简体中文
esp-emulator browser API summary (wasm v0.51.0)
A reverse-engineered inventory of everything the closed-source
esp_emu_bg.wasm exposes to JS. Sources: the official www/pkg/esp_emu.js
(wasm-bindgen glue), official docs (esp-emulator README/BROWSER.md), and this
project's M0 measurements (tests/m0_probe.mjs, conclusions in
FEASIBILITY.md). Re-run the probe and re-check this document
after an upstream upgrade.
1. Loading & initialisation
2. Method inventory (all synchronous; no callbacks — polling only)
Lifecycle / loading
| method |
notes |
load_firmware(Uint8Array) |
must be a merged flash image (bootloader@0x0 + partition table@0x8000 + app@0x10000, from idf.py merge-bin); a bare app bin never boots |
load_rom_elf(Uint8Array) / load_default_rom() / has_default_rom() |
ROM; embedded version used by default |
load_efuse(Uint8Array) / load_app_elf(Uint8Array) |
eFuse / app ELF (for BLE symbol interception) |
set_boot_from_rom(bool) |
call before load_firmware |
restart() / needs_restart() |
soft reset (flash preserved) / firmware called esp_restart |
Execution (host-driven loop)
| method |
notes |
run_batch(n) → string |
executes ≤n instructions, returns the batch's UART0 output string (the only output channel) |
throttle_delay_ms(now) → number |
drift from wall clock; the host sleeps by this to pace to real time |
cycles() / cycles_per_us() |
cycle counter / clock (C3 = 160) |
CPU state
| method |
notes |
pc() / hart_pc(h) / num_harts() / is_xtensa() |
PC, per-hart PC, hart count, ISA |
registers() → Uint32Array / get_reg(i) |
RV32: x0..x31; Xtensa: a0..a15 + PS,SAR,WINDOWBASE,WINDOWSTART,EXCCAUSE,EXCVADDR,EPC1,LBEG,LEND,LCOUNT |
read_memory(addr, len) → Uint8Array |
bus read; MMIO is readable (LEDC/RMT/GPIO matrix etc.), unmapped returns 0, 4 KiB per call |
GPIO (this project's main interface)
| method |
notes |
gpio_set_input(pin, high) |
drives a pad input level; firmware reads it and GPIO interrupts fire (M0: 6/6); default level high |
gpio_state() → [out_lo, out_hi, enable_lo, enable_hi] |
mirror of the GPIO0-63 output and output-enable registers; only CPU-direct GPIO writes appear here — signals through the GPIO matrix (LEDC/RMT etc.) do not (M0 measurement) |
UART / network
| method |
notes |
uart_input(Uint8Array) |
inject bytes into UART0 RX |
set_wifi_config(ssid, pwd) / set_wifi_auth(ssid, pwd, auth, sae_pwe) |
simulated soft AP |
wifi_rx_push(Uint8Array) / wifi_tx_drain() → Uint8Array |
ethernet frames ↔ WiFi; TX is u32-length-prefixed concatenation, needs an external WebSocket TAP proxy (tools/ws-net-proxy.py) |
3. Register-level facts measured in M0 (ESP32-C3)
| fact |
value / notes |
| LEDC duty registers |
0x60019000 + 0x14*n + {0,4,8,C,10} (CONF0/HPOINT/DUTY/CONF1/DUTY_R); reg = duty×16 (bits[18:4]); precisely readable via read_memory (M0 Q2b 53/53) |
| RMT channel RAM |
0x60016400 + 0xC0*n, 48 words/channel; symbols remain after transmission and can be decoded afterwards (M0 Q3b); word format d0:15,l0:1,d1:15,l1:1 |
| GPIO matrix routing |
GPIO_FUNCn_OUT_SEL = 0x60004000+0x554+4n; LEDC0 signal = 0x2d, RMT ch0 = 0x33 → wiring can be auto-discovered |
| IO_MUX (C3) |
GPIO0..11 contiguous at 0x60009000+0x04+4n |
| Time fast-forward |
during vTaskDelay cycles() jumps ahead without spending full CPU cycles → pin waveforms inside CPU sleep windows cannot be captured (independent of sample rate) |
| Misc |
GPIO_COUNT: C3=22 / C5=29 / C6=31 / H2=28 / P4=55 / S3=49 (no 22-25) / S31=32 |
4. Official worker message protocol (www/worker.js; this project replicates and extends it)
- page→worker:
init{wasmUrl}, load{chip,firmware,ssid,password,rom?,efuse?},
start, stop, step, reset{chip}, uart_input{data},
gpio_input{pin,high}, read_mem{addr,len}, mem_watch{addr,len|null},
net_connect{url}, net_disconnect, set_batch_size{size}
- worker→page:
ready, loaded{chip,pc,isXtensa,numHarts,cyclesPerUs},
uart_output{data}, status{pc,cycles,mips,now},
snapshot{regs,pcs,gpio,cycles,mem?} (150ms throttle), mem{addr,bytes},
step{output,pc,cycles}, restarted, reset{reloaded,pc?},
net_status{connected}, error{message}
5. Beyond the wasm surface (browser build lacks these; CLI-only)
--uart1-tcp (external serial device), --i2c-dev (dumb-register I2C slave),
--rmt-loopback, --control-tcp (flash write/erase), --ble-hci,
--thread-sim, GDB stub, snapshot saving.
These are exactly the capabilities the M5 roadmap waits on
(see ROADMAP.md).