Esp32sim: открытый эмулятор ESP32 запускает прошивки в браузере

В разделе Show HN представлен esp32sim, эмулятор четырёх микроконтроллеров ESP32 с эмуляцией на уровне инструкций. Он охватывает обе архитектуры процессоров Espressif: Xtensa и RISC-V. Каждый чип загружает настоящее маскированное ПЗУ (mask ROM), настоящий загрузчик второго этапа и немодифицированный образ приложения, без патчей прошивки и без заглушек на пути. Достаточная часть чипа смоделирована, чтобы реальные проекты работали от начала до конца. Облако и учётные записи не нужны, лицензия MIT.
Состав: ESP32-S3 (Xtensa LX7, два ядра), ESP32-C3 и ESP32-C6 (RISC-V, одно ядро) и классический ESP32, который загружает своё ПЗУ версии ECO3 на двух ядрах LX6 с GPIO, UART и таймерами; плата ttgo-tdisplay добавляет дисплей ST7789 и кнопки LilyGO TTGO T-Display. Большая часть чипа общая: C3 использует модели UART, USB-Serial/JTAG, системного таймера, групп таймеров, GPIO, контроллера SPI-флеш, GDMA и ускорителей SHA/AES/RSA от S3 без изменений и добавляет свою карту памяти, контроллер кэша и матрицу прерываний; C6 снова переиспользует те же модели и добавляет свои карту памяти, front-end PLIC, кэш L1, PCR и блоки малого энергопотребления. По-настоящему раздельны только процессорные крейты (модули Rust). Проект построен как набор крейтов: общий emu-core, esp-soc с планировщиком, консолью и виртуальной сетью, esp-periph с общими периферийными блоками, отдельные крейты для каждого чипа и интерпретатором, а также JIT для AArch64 и интерпретатор базовых блоков на S3.
В браузере без установки можно попробовать Linux на S3, панель Touch-LCD-4B с SID-плеером, демо pocket-tank LLM aquarium, а также демо для C3 и C6 (https://mikroverk.github.io/esp32sim/). Для браузера есть крейт wasm, который оборачивает все три машины (S3, C3, C6) в один модуль, и веб-интерфейс с отрисовкой платы, консолью, звуком и камерой.
Модели плат интерпретируют события на уровне выводов (фронты GPIO, потоки символов RMT, отсчёты I2S). Для S3 есть платы atech14 (по умолчанию), waveshare-lcd4b (дисплей ST7701S 480×480, сенсор GT911), waveshare-amoled18-v2 (CO5300 368x448 по QSPI, сенсор CST820), waveshare-cam и режим none без платы. На waveshare-cam запускается прошивка waveshare-autopling (IDF 5.5, 16 МБ флеш, 8 МБ octal PSRAM): кадры камеры (из файла или из браузера, загрузка картинки или веб-камера) попадают в детектор пешеходов esp-dl на эмулированном SIMD-блоке PIE, после чего звучит сигнал на кодеке ES8311. Новую плату добавляют реализацией трейта.
Проверка на железе. На C3 эмулятор сверили построчно с физическим модулем: 205 из 208 строк консоли совпали за три цикла загрузки, расхождение, строка Saved PC из ПЗУ; в документации перечислены пять ошибок эмулятора, найденных сравнением с железом. На Waveshare ESP32-C6-LCD-1.47 совпали 203 из 204 строк за три цикла загрузки; единственное отличие, та же строка Saved PC при первой загрузке. Запуск hello_world на S3 идёт примерно в 30 раз быстрее реального времени (запуск из командной строки) и воспроизводит ПЗУ-баннер, логи загрузчика и приложения, обратный отсчёт и перезагрузку через RTC-сторожевой таймер, как на кремнии. Авторы оговаривают: эти числа относятся к ранним ручным прогонам, сравнение трасс с железом нормализует оконные исключения и пересинхронизирует циклы задержки, поэтому это не непрерывное побитовое совпадение такт в такт.
Сеть и радио. Флаг --wifi подключает виртуальную точку доступа, с которой связывается неизменённый бинарный Wi-Fi-блоб Espressif: сканирование, аутентификация, ассоциация и при наличии пароля четырёхстороннее рукопожатие WPA2-PSK. За ней работает виртуальная сеть (DHCP, ARP, ICMP, DNS, SNTP по часам хоста). Режим --net nat (по умолчанию) пробрасывает TCP и UDP гостя через обычные сокеты хоста, так что прошивка выходит в реальную сеть без изменений прошивки, root-прав и tun-устройства; --net none отключает выход. Пример, прошивка energy panel, которая подключается, получает адрес, синхронизирует часы, загружает цены на электричество по HTTPS и опрашивает реальный Home Assistant в локальной сети. На C3 станция работает с открытыми точками и WPA2, DHCP и NAT; плат нет, режим --boot app не поддерживается. На C6 Wi-Fi: одна станция, устаревшие скорости, без энергосбережения, и каждому радиозапуску нужен флаг --stub bb_init=0. MAC-уровень 802.15.4 на C6 отвечает на сканирование энергии и обменивается кадрами с тайминговой привязкой к эфиру; флаг --cooja делает C6 внешним узлом Cooja-NG в жёсткой синхронизации по NDJSON (образ Contiki-NG на IDF обменивался широковещательными кадрами с эмулированными узлами MSP430).
Для сборки нужен cargo build --release; образ маскированного ПЗУ берётся из ESP-IDF либо скачивается скриптом tools/fetch-demo-assets.sh. Прошивку Pocket Synth для демо atech14 (синтезатор SID и плеер cRSID) ведёт отдельный проект atech-firmware, а собранные образы лежат в репозитории.
Ключевые факты
- Esp32sim эмулирует на уровне инструкций четыре чипа ESP32 на обеих архитектурах Espressif (Xtensa и RISC-V); лицензия MIT, облако и аккаунты не нужны.
- Эмулятор загружает настоящее маскированное ПЗУ, настоящий загрузчик второго этапа и немодифицированный образ приложения, без патчей прошивки и заглушек.
- На ESP32-C3 совпали 205 из 208 строк консоли с физическим модулем за три загрузки, на ESP32-C6, 203 из 204; расхождение, строка Saved PC из ПЗУ.
- Демо запускается в браузере без установки: Linux на S3, панель Touch-LCD-4B с SID-плеером, pocket-tank LLM aquarium, демо для C3 и C6.
- Виртуальная точка доступа позволяет неизменённому Wi-Fi-блобу Espressif подключаться и выходить в реальную сеть через NAT без root и tun-устройства.
Почему это важно
Прошивки для ESP32 обычно проверяют на плате или в более упрощённых симуляторах. Esp32sim запускает настоящее ПЗУ, загрузчик и неизменённый образ приложения, и это сближает проверку с поведением кремния. Проект покрывает обе архитектуры Espressif и работает в браузере, а сравнение с физическими модулями дало 205 из 208 и 203 из 204 совпавших строк консоли.
Кому это важно
Разработчикам встраиваемых систем на ESP32 (S3, C3, C6 и классическом чипе), кто хочет отлаживать прошивку без платы или смотреть её работу в браузере. Также тем, кого интересует устройство эмуляторов: в репозитории описаны модели периферии, JIT для AArch64, виртуальная сеть и связка с Cooja-NG для сетей 802.15.4.
Как это применить
Проект открыт, лицензия MIT. Быстрее всего начать с браузерного демо по адресу mikroverk.github.io/esp32sim. Для локального запуска нужен cargo build --release и образ ПЗУ чипа: он берётся из ESP-IDF либо скачивается скриптом tools/fetch-demo-assets.sh. Далее запускается бинарник esp32sim (или esp32sim-c3, esp32sim-c6) с загрузчиком, таблицей разделов и образом приложения; в репозитории есть пример hello_world для S3, C3 и C6. Для сетевых прошивок используется флаг --wifi.
Можно ли доверять
Все сведения взяты из README репозитория, то есть это заявления самих авторов; независимых сравнений или отзывов в источнике нет. Авторы честно оговаривают пределы: числа сравнения с железом описывают ранние ручные прогоны, а не то, что проверяет CI; сравнение трасс с железом нормализует оконные исключения и пересинхронизирует циклы задержки, то есть это не непрерывное совпадение такт в такт. Заявления о точности по такту проект не делает. Текст README в нашем распоряжении обрывается на разделе про Wi-Fi.
Риски и подводные камни
На C3 нет плат и не поддерживается режим --boot app. Wi-Fi на C6 ограничен одной станцией, устаревшими скоростями и отсутствием энергосбережения, а каждому радиозапуску нужен флаг --stub bb_init=0. CI проверяет только записанные выборки декодера и эталонные выходы эмулятора, а полные внешние листинги исключает; тест Xtensa objdump не сравнивает операнды PIE. Из видимого текста не ясно, работает ли в браузере классический ESP32: крейт wasm упомянут для S3, C3 и C6. Скорость в браузере не приводится, число около 30× относится к запуску hello_world на S3 из командной строки. Для сборки нужно ПЗУ чипа, которое берётся из ESP-IDF или скачивается отдельным скриптом.