free little xtensa emulator. boots real esp-idf firmware, models esp32 hardware, and tests production roms end to end.
$ cmake -S . -B build && cmake --build build -j # c17, cmake, openssl, zlib, and pthreads. $ ./build/xtensa-emu -q -s hello_world.elf -c 5000000 hello_world.bin I (0) cpu_start: Starting scheduler on PRO CPU. Hello world! $ FLEXE_ROMS=./roms MAX_UNMAPPED=0 REPS=5 ./scripts/bench-firmware.sh # release + lto; both engines must pass and produce the same uart digest: meshtastic 25.03× real-time nerdminer 12.84× real-time openhasp 8.31× real-time tasmota 8.29× real-time wled 2.32× real-time
traces hot basic blocks through conditional branches, chains them into long native runs (arm64 + x86-64), and constant-folds flash literal loads. cold code stays interpreted. no correctness cliff — unhandled instructions just run in the interpreter.
unmodified bruce, esp32 marauder, meshtastic, nerdminer, openhasp, tasmota, and wled images pass scripted hardware and service scenarios on both engines. pinned output digests catch a jit that produces the wrong result rather than no result.
alu, shifts, branches, zero-overhead loops, mac16, fpu, guest-managed window overflow/underflow vectors, exceptions and interrupts (levels 1–7, ccompare timers, waiti).
pro cpu + app cpu, synchronized cycle counts, freertos preemption on both. the benchmark counts instructions executed on both cores — no funny accounting.
rom functions (ets_printf, memcpy, sha/aes), freertos tasks/queues/semaphores, esp_timer callbacks, nvs, vfs/spiffs with host file backing, even lwip sockets bridged to the host network.
elf symbols, breakpoints, verbose + windowed traces, function-call trees, hierarchical traces for billion-cycle runs, checkpoints you can save and resume later.
plain c17, a switch-based interpreter, and hand-rolled jit backends. the implementation stays inspectable even as production firmware expands the hardware model.
production benchmarks measured on apple silicon with a release, lto, host-native build. jit is on by default. real-time factor is measured against a 240 mhz esp32.