├── .github └── workflows │ └── build-rust.yml ├── clang-wasm ├── Dockerfile └── test.c ├── devicescript ├── Dockerfile └── compile.sh ├── esp-idf ├── Dockerfile ├── compile.sh └── project │ ├── CMakeLists.txt │ ├── main │ ├── CMakeLists.txt │ └── src │ │ └── main.c │ └── sdkconfig.defaults ├── golioth-esp-idf-sdk ├── Dockerfile └── project │ ├── CMakeLists.txt │ ├── main │ ├── CMakeLists.txt │ └── src │ │ └── app_main.c │ └── sdkconfig.defaults ├── pico-sdk ├── Dockerfile ├── compile.sh └── project │ ├── CMakeLists.txt │ ├── lwipopts.h │ ├── pico_sdk_import.cmake │ └── src │ └── main.c ├── platformio-stm32 ├── Dockerfile ├── compile.sh └── project │ ├── platformio.ini │ └── src │ └── main.c ├── rust-nostd-esp ├── Dockerfile └── compile.sh ├── rust-wasm ├── Dockerfile └── project │ ├── .cargo │ └── config.toml │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ └── lib.rs ├── verilog-cxxrtl ├── Dockerfile ├── LICENSE └── project │ ├── compile.sh │ ├── main.cpp │ └── src │ ├── wokwi-api.h │ └── wokwi.v ├── zephyr-esp32 ├── Dockerfile ├── esp32-wokwi.dts └── west.yml └── zig-wasm ├── .gitignore ├── Dockerfile └── project ├── build.zig ├── src └── lib.zig └── wokwi └── wokwi_chip_ll.zig /.github/workflows/build-rust.yml: -------------------------------------------------------------------------------- 1 | name: Build rust builders 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '37 13 * * *' 6 | 7 | jobs: 8 | build: 9 | name: Build containers 10 | runs-on: ubuntu-24.04 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | builder_name: 15 | - rust-nostd-esp 16 | 17 | env: 18 | BUILDER_NAME: ${{ matrix.builder_name }} 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Build container 23 | run: docker build -t "wokwi/builder-${BUILDER_NAME}" ${BUILDER_NAME} 24 | -------------------------------------------------------------------------------- /clang-wasm/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20 2 | RUN apk update 3 | RUN apk add clang lld git make llvm 4 | 5 | RUN git clone https://github.com/CraneStation/wasi-libc.git && \ 6 | cd /wasi-libc && \ 7 | make install INSTALL_DIR=/opt/wasi-libc && \ 8 | rm -rf /wasi-libc 9 | 10 | RUN mkdir -p /usr/lib/llvm17/lib/clang/17/lib/wasi/ && \ 11 | wget -O /usr/lib/llvm17/lib/clang/17/lib/wasi/libclang_rt.builtins-wasm32.a https://github.com/jedisct1/libclang_rt.builtins-wasm32.a/blob/master/precompiled/llvm-17/libclang_rt.builtins-wasm32.a?raw=true 12 | 13 | RUN mkdir /src && chown nobody /src 14 | USER nobody 15 | COPY --chown=nobody:nobody test.c /src/test.c 16 | WORKDIR /src 17 | RUN clang --target=wasm32-unknown-wasi --sysroot /opt/wasi-libc -nostartfiles -Wl,--no-entry -Wl,--export-all -o /tmp/app.wasm /src/test.c 18 | 19 | ENV HEXI_SRC_DIR="/src" 20 | ENV HEXI_BUILD_CMD="clang --target=wasm32-unknown-wasi --sysroot /opt/wasi-libc -nostartfiles -Wl,--export-table -Wl,--no-entry -Werror -o /tmp/app.wasm /src/app.c" 21 | ENV HEXI_OUT_HEX="/tmp/app.wasm" 22 | ENV HEXI_OUT_ELF="/tmp/app.elf" 23 | -------------------------------------------------------------------------------- /clang-wasm/test.c: -------------------------------------------------------------------------------- 1 | // copy.c 2 | #include 3 | 4 | int copy(char *input, char *output) 5 | { 6 | const int length = strlen(input); 7 | 8 | strncpy(output, input, length); 9 | 10 | return length; 11 | } 12 | -------------------------------------------------------------------------------- /devicescript/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | 3 | RUN adduser -h /app -D wokwi 4 | 5 | RUN npm i -g @devicescript/cli@2.14.14 6 | 7 | USER wokwi 8 | WORKDIR /app 9 | RUN devs init 10 | 11 | ADD compile.sh /app 12 | 13 | RUN devs bundle --board esp32_devkit_c src/main.ts 14 | RUN devs bundle --board esp32c3_bare src/main.ts 15 | RUN devs bundle --board pico src/main.ts 16 | 17 | # TODO: support other boards, e.g.: 18 | #RUN devs bundle --board esp32s2_bare src/main.ts 19 | #RUN devs bundle --board esp32c3_rust_devkit src/main.ts 20 | #RUN devs bundle --board esp32s3_devkit_m src/main.ts 21 | 22 | ENV HOME="/app" 23 | ENV HEXI_SRC_DIR="/app/build-in" 24 | ENV HEXI_SRC_FILES="*.ts" 25 | ENV HEXI_BUILD_CMD="./compile.sh" 26 | ENV HEXI_OUT_HEX="/app/.devicescript/bin/output.bin" 27 | ENV HEXI_OUT_ELF="dummy" 28 | -------------------------------------------------------------------------------- /devicescript/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case "$WOKWI_BOARD" in 4 | "esp32:esp32:esp32doit-devkit-v1") 5 | DEVICESCRIPT_BOARD="esp32_devkit_c" 6 | DEVICESCRIPT_BIN="bundle-devicescript-esp32-esp32_devkit_c-0x1000.bin" 7 | ;; 8 | "esp32:esp32:esp32c3") 9 | DEVICESCRIPT_BOARD="esp32c3_bare" 10 | DEVICESCRIPT_BIN="bundle-devicescript-esp32c3-esp32c3_bare-0x0.bin" 11 | ;; 12 | "pipico") 13 | DEVICESCRIPT_BOARD="pico" 14 | DEVICESCRIPT_BIN="bundle-devicescript-rp2040-pico.uf2" 15 | ;; 16 | *) 17 | >&2 echo "Unsupported wokwi board: $WOKWI_BOARD" 18 | exit 1 19 | ;; 20 | esac 21 | 22 | rm -rf /app/.devicescript/bin 23 | cp /app/build-in/*.ts src/ 24 | devs bundle --no-colors --board ${DEVICESCRIPT_BOARD} src/main.ts 25 | cp /app/.devicescript/bin/${DEVICESCRIPT_BIN} /app/.devicescript/bin/output.bin 26 | -------------------------------------------------------------------------------- /esp-idf/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM espressif/idf:v5.3.1 2 | 3 | RUN useradd -rm -d /home/wokwi wokwi 4 | USER wokwi 5 | WORKDIR /home/wokwi 6 | ENV USER=wokwi 7 | 8 | # Copy utility scripts and setup 9 | COPY compile.sh /home/wokwi/ 10 | ADD project /home/wokwi/esp-project-template 11 | RUN mkdir -p /home/wokwi/build-in /home/wokwi/build-out 12 | 13 | ENV HEXI_SRC_DIR="/home/wokwi/build-in" 14 | ENV HEXI_BUILD_CMD="bash /home/wokwi/compile.sh" 15 | ENV HEXI_OUT_HEX="/home/wokwi/build-out/project.bin" 16 | ENV HEXI_OUT_ELF="/home/wokwi/build-out/project.elf" 17 | RUN WOKWI_MCU=esp32 ./compile.sh 18 | RUN WOKWI_MCU=esp32-s2 ./compile.sh 19 | RUN WOKWI_MCU=esp32-s3 ./compile.sh 20 | RUN WOKWI_MCU=esp32-c3 ./compile.sh 21 | RUN WOKWI_MCU=esp32-c6 ./compile.sh 22 | RUN WOKWI_MCU=esp32-h2 ./compile.sh 23 | RUN WOKWI_MCU=esp32-p4 ./compile.sh 24 | -------------------------------------------------------------------------------- /esp-idf/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo $WOKWI_MCU 6 | 7 | source /opt/esp/idf/export.sh 8 | 9 | case ${WOKWI_MCU} in 10 | "esp32") 11 | MCU="esp32" 12 | ;; 13 | "esp32-c3") 14 | MCU="esp32c3" 15 | ;; 16 | "esp32-c6") 17 | MCU="esp32c6" 18 | ;; 19 | "esp32-h2") 20 | MCU="esp32h2" 21 | ;; 22 | "esp32-p4") 23 | MCU="esp32p4" 24 | ;; 25 | "esp32-s2") 26 | MCU="esp32s2" 27 | ;; 28 | "esp32-s3") 29 | MCU="esp32s3" 30 | ;; 31 | *) 32 | echo "Missing or invalid WOKWI_MCU environment variable" 33 | exit 1 34 | ;; 35 | esac 36 | 37 | PROJECT_NAME="esp-project-${MCU}" 38 | PROJECT_ROOT="${HOME}/${PROJECT_NAME}" 39 | 40 | if [ ! -e ${PROJECT_ROOT} ]; then 41 | cp -R ${HOME}/esp-project-template ${PROJECT_ROOT} 42 | cd $PROJECT_ROOT 43 | idf.py set-target ${MCU} 44 | fi 45 | 46 | cd $PROJECT_ROOT 47 | 48 | if [ "$(find ${HOME}/build-in -name '*.c')" ]; then 49 | cp ${HOME}/build-in/*.c main/src 50 | fi 51 | if [ "$(find ${HOME}/build-in -name '*.h')" ]; then 52 | cp ${HOME}/build-in/*.h main/src 53 | fi 54 | 55 | idf.py build 1>&2 56 | 57 | rm -f main/src/* 58 | 59 | cp ./build/wokwi-project.bin ${HOME}/build-out/project.bin 60 | cp ./build/wokwi-project.elf ${HOME}/build-out/project.elf 61 | -------------------------------------------------------------------------------- /esp-idf/project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about build system see 2 | # https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html 3 | # The following five lines of boilerplate have to be in your project's 4 | # CMakeLists in this exact order for cmake to work correctly 5 | cmake_minimum_required(VERSION 3.5) 6 | 7 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 8 | project(wokwi-project) 9 | -------------------------------------------------------------------------------- /esp-idf/project/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES "src/*.c") 2 | idf_component_register(SRCS ${SOURCES} 3 | INCLUDE_DIRS "src") 4 | -------------------------------------------------------------------------------- /esp-idf/project/main/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD 3 | * 4 | * SPDX-License-Identifier: CC0-1.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include "sdkconfig.h" 10 | #include "freertos/FreeRTOS.h" 11 | #include "freertos/task.h" 12 | #include "esp_chip_info.h" 13 | #include "esp_flash.h" 14 | #include "esp_system.h" 15 | 16 | void app_main(void) 17 | { 18 | printf("Hello world!\n"); 19 | 20 | /* Print chip information */ 21 | esp_chip_info_t chip_info; 22 | uint32_t flash_size; 23 | esp_chip_info(&chip_info); 24 | printf("This is %s chip with %d CPU core(s), %s%s%s%s, ", 25 | CONFIG_IDF_TARGET, 26 | chip_info.cores, 27 | (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "", 28 | (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "", 29 | (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "", 30 | (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : ""); 31 | 32 | unsigned major_rev = chip_info.revision / 100; 33 | unsigned minor_rev = chip_info.revision % 100; 34 | printf("silicon revision v%d.%d, ", major_rev, minor_rev); 35 | if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) { 36 | printf("Get flash size failed"); 37 | return; 38 | } 39 | 40 | printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024), 41 | (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); 42 | 43 | printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); 44 | 45 | for (int i = 10; i >= 0; i--) { 46 | printf("Restarting in %d seconds...\n", i); 47 | vTaskDelay(1000 / portTICK_PERIOD_MS); 48 | } 49 | printf("Restarting now.\n"); 50 | fflush(stdout); 51 | esp_restart(); 52 | } -------------------------------------------------------------------------------- /esp-idf/project/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_LOG_DEFAULT_LEVEL_ERROR=y 2 | CONFIG_LOG_DEFAULT_LEVEL=1 3 | -------------------------------------------------------------------------------- /golioth-esp-idf-sdk/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM espressif/idf:release-v4.4 2 | 3 | RUN useradd -ms /bin/bash wokwi 4 | 5 | USER wokwi 6 | WORKDIR /home/wokwi 7 | ENV IDF_PATH=/opt/esp/idf 8 | 9 | RUN git clone --recursive https://github.com/golioth/golioth-esp-idf-sdk.git && \ 10 | cd golioth-esp-idf-sdk && \ 11 | git submodule update --init --recursive 12 | 13 | COPY --chown=wokwi:wokwi project project/ 14 | WORKDIR /home/wokwi/project 15 | ENV GOLIOTH_SDK_PATH=/home/wokwi/golioth-esp-idf-sdk 16 | 17 | RUN . /opt/esp/entrypoint.sh && idf.py build 18 | -------------------------------------------------------------------------------- /golioth-esp-idf-sdk/project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | set(EXTRA_COMPONENT_DIRS $ENV{GOLIOTH_SDK_PATH}/components) 3 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 4 | project(wokwi_project) 5 | -------------------------------------------------------------------------------- /golioth-esp-idf-sdk/project/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | INCLUDE_DIRS 3 | "$ENV{GOLIOTH_SDK_PATH}/examples/common" 4 | SRCS 5 | "src/app_main.c" 6 | "$ENV{GOLIOTH_SDK_PATH}/examples/common/shell.c" 7 | "$ENV{GOLIOTH_SDK_PATH}/examples/common/wifi.c" 8 | "$ENV{GOLIOTH_SDK_PATH}/examples/common/nvs.c" 9 | PRIV_REQUIRES 10 | "golioth_sdk" 11 | "console" 12 | "spi_flash" 13 | "nvs_flash" 14 | "json" 15 | "driver" 16 | "esp_hw_support" 17 | ) 18 | list(APPEND EXTRA_C_FLAGS_LIST 19 | -Werror 20 | ) 21 | component_compile_options(${EXTRA_C_FLAGS_LIST}) 22 | -------------------------------------------------------------------------------- /golioth-esp-idf-sdk/project/main/src/app_main.c: -------------------------------------------------------------------------------- 1 | #include "freertos/FreeRTOS.h" 2 | #include "freertos/task.h" 3 | #include 4 | 5 | void app_main() { 6 | printf("I'm just a stub\n"); 7 | while (1) { 8 | vTaskDelay(portMAX_DELAY); 9 | } 10 | } -------------------------------------------------------------------------------- /golioth-esp-idf-sdk/project/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_MBEDTLS_SSL_PROTO_DTLS=y 2 | CONFIG_MBEDTLS_PSK_MODES=y 3 | CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y 4 | CONFIG_LWIP_NETBUF_RECVINFO=y 5 | CONFIG_FREERTOS_USE_TRACE_FACILITY=y 6 | CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y 7 | 8 | # Default sdkconfig parameters to use the OTA 9 | # partition table layout, with a 4MB flash size 10 | CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y 11 | CONFIG_PARTITION_TABLE_TWO_OTA=y 12 | 13 | # If the new app firmware does not cancel the rollback, 14 | # then this will ensure that rollback happens automatically 15 | # if/when the device is next rebooted. 16 | CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y 17 | -------------------------------------------------------------------------------- /pico-sdk/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.21 2 | 3 | # Install toolchain 4 | RUN apk update && \ 5 | apk upgrade && \ 6 | apk add git \ 7 | python3 \ 8 | py3-pip \ 9 | cmake \ 10 | build-base \ 11 | libusb-dev \ 12 | bsd-compat-headers \ 13 | newlib-arm-none-eabi \ 14 | gcc-arm-none-eabi \ 15 | g++-arm-none-eabi 16 | RUN adduser -D wokwi 17 | 18 | USER wokwi 19 | WORKDIR /home/wokwi 20 | ENV PICO_SDK_PATH=/home/wokwi/pico-sdk 21 | RUN git clone -b 2.1.1 --depth 1 https://github.com/raspberrypi/pico-sdk.git && cd pico-sdk && git submodule update --init --depth 1 22 | 23 | COPY --chown=wokwi:wokwi project project/ 24 | 25 | WORKDIR /home/wokwi/project/build_pico 26 | RUN cmake -DPICO_BOARD=pico .. && make -j4 27 | WORKDIR /home/wokwi/project/build_pico_w 28 | RUN cmake -DPICO_BOARD=pico_w .. && make -j4 29 | 30 | WORKDIR /home/wokwi/project 31 | ADD compile.sh . 32 | 33 | ENV HEXI_SRC_DIR="/home/wokwi/project/src" 34 | ENV HEXI_BUILD_CMD="./compile.sh" 35 | ENV HEXI_OUT_HEX="/home/wokwi/project/build/wokwi_project.hex" 36 | ENV HEXI_OUT_ELF="/home/wokwi/project/build/wokwi_project.elf" 37 | -------------------------------------------------------------------------------- /pico-sdk/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f build 4 | 5 | if [ "$WOKWI_BOARD" == "rp2040:rp2040:rpipicow" ]; then 6 | ln -s build_pico_w build 7 | cd build_pico_w 8 | else 9 | ln -s build_pico build 10 | cd build_pico 11 | fi 12 | 13 | cmake .. && make -j4 14 | -------------------------------------------------------------------------------- /pico-sdk/project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | include(pico_sdk_import.cmake) 3 | project(wokwi_project C CXX ASM) 4 | set(CMAKE_C_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(PICO_NO_UF2 1) 7 | pico_sdk_init() 8 | AUX_SOURCE_DIRECTORY(src SOURCE_FILES) 9 | add_executable(wokwi_project 10 | ${SOURCE_FILES} 11 | ) 12 | pico_add_extra_outputs(wokwi_project) 13 | target_link_libraries( 14 | wokwi_project 15 | pico_multicore 16 | pico_stdlib 17 | hardware_adc 18 | hardware_clocks 19 | hardware_dma 20 | hardware_flash 21 | hardware_i2c 22 | hardware_interp 23 | hardware_pio 24 | hardware_pwm 25 | hardware_rtc 26 | hardware_spi 27 | ) 28 | 29 | if (PICO_CYW43_SUPPORTED) # set by PICO_BOARD=pico_w 30 | target_include_directories(wokwi_project PRIVATE 31 | ${CMAKE_CURRENT_LIST_DIR} 32 | ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts 33 | ) 34 | 35 | target_link_libraries(wokwi_project 36 | pico_cyw43_arch_lwip_threadsafe_background 37 | pico_stdlib 38 | ) 39 | endif() 40 | -------------------------------------------------------------------------------- /pico-sdk/project/lwipopts.h: -------------------------------------------------------------------------------- 1 | #ifndef _LWIPOPTS_H 2 | #define _LWIPOPTS_H 3 | 4 | // Common settings used in most of the pico_w examples 5 | // (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) 6 | 7 | // allow override in some examples 8 | #ifndef NO_SYS 9 | #define NO_SYS 1 10 | #endif 11 | // allow override in some examples 12 | #ifndef LWIP_SOCKET 13 | #define LWIP_SOCKET 0 14 | #endif 15 | #if PICO_CYW43_ARCH_POLL 16 | #define MEM_LIBC_MALLOC 1 17 | #else 18 | // MEM_LIBC_MALLOC is incompatible with non polling versions 19 | #define MEM_LIBC_MALLOC 0 20 | #endif 21 | #define MEM_ALIGNMENT 4 22 | #define MEM_SIZE 4000 23 | #define MEMP_NUM_TCP_SEG 32 24 | #define MEMP_NUM_ARP_QUEUE 10 25 | #define PBUF_POOL_SIZE 24 26 | #define LWIP_ARP 1 27 | #define LWIP_ETHERNET 1 28 | #define LWIP_ICMP 1 29 | #define LWIP_RAW 1 30 | #define TCP_WND (8 * TCP_MSS) 31 | #define TCP_MSS 1460 32 | #define TCP_SND_BUF (8 * TCP_MSS) 33 | #define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) 34 | #define LWIP_NETIF_STATUS_CALLBACK 1 35 | #define LWIP_NETIF_LINK_CALLBACK 1 36 | #define LWIP_NETIF_HOSTNAME 1 37 | #define LWIP_NETCONN 0 38 | #define MEM_STATS 0 39 | #define SYS_STATS 0 40 | #define MEMP_STATS 0 41 | #define LINK_STATS 0 42 | // #define ETH_PAD_SIZE 2 43 | #define LWIP_CHKSUM_ALGORITHM 3 44 | #define LWIP_DHCP 1 45 | #define LWIP_IPV4 1 46 | #define LWIP_TCP 1 47 | #define LWIP_UDP 1 48 | #define LWIP_DNS 1 49 | #define LWIP_TCP_KEEPALIVE 1 50 | #define LWIP_NETIF_TX_SINGLE_PBUF 1 51 | #define DHCP_DOES_ARP_CHECK 0 52 | #define LWIP_DHCP_DOES_ACD_CHECK 0 53 | 54 | #ifndef NDEBUG 55 | #define LWIP_DEBUG 1 56 | #define LWIP_STATS 1 57 | #define LWIP_STATS_DISPLAY 1 58 | #endif 59 | 60 | #define ETHARP_DEBUG LWIP_DBG_OFF 61 | #define NETIF_DEBUG LWIP_DBG_OFF 62 | #define PBUF_DEBUG LWIP_DBG_OFF 63 | #define API_LIB_DEBUG LWIP_DBG_OFF 64 | #define API_MSG_DEBUG LWIP_DBG_OFF 65 | #define SOCKETS_DEBUG LWIP_DBG_OFF 66 | #define ICMP_DEBUG LWIP_DBG_OFF 67 | #define INET_DEBUG LWIP_DBG_OFF 68 | #define IP_DEBUG LWIP_DBG_OFF 69 | #define IP_REASS_DEBUG LWIP_DBG_OFF 70 | #define RAW_DEBUG LWIP_DBG_OFF 71 | #define MEM_DEBUG LWIP_DBG_OFF 72 | #define MEMP_DEBUG LWIP_DBG_OFF 73 | #define SYS_DEBUG LWIP_DBG_OFF 74 | #define TCP_DEBUG LWIP_DBG_OFF 75 | #define TCP_INPUT_DEBUG LWIP_DBG_OFF 76 | #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF 77 | #define TCP_RTO_DEBUG LWIP_DBG_OFF 78 | #define TCP_CWND_DEBUG LWIP_DBG_OFF 79 | #define TCP_WND_DEBUG LWIP_DBG_OFF 80 | #define TCP_FR_DEBUG LWIP_DBG_OFF 81 | #define TCP_QLEN_DEBUG LWIP_DBG_OFF 82 | #define TCP_RST_DEBUG LWIP_DBG_OFF 83 | #define UDP_DEBUG LWIP_DBG_OFF 84 | #define TCPIP_DEBUG LWIP_DBG_OFF 85 | #define PPP_DEBUG LWIP_DBG_OFF 86 | #define SLIP_DEBUG LWIP_DBG_OFF 87 | #define DHCP_DEBUG LWIP_DBG_OFF 88 | 89 | #endif /* __LWIPOPTS_H__ */ 90 | -------------------------------------------------------------------------------- /pico-sdk/project/pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | FetchContent_Declare( 33 | pico_sdk 34 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 35 | GIT_TAG master 36 | ) 37 | if (NOT pico_sdk) 38 | message("Downloading Raspberry Pi Pico SDK") 39 | FetchContent_Populate(pico_sdk) 40 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 41 | endif () 42 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 43 | else () 44 | message(FATAL_ERROR 45 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 46 | ) 47 | endif () 48 | endif () 49 | 50 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 51 | if (NOT EXISTS ${PICO_SDK_PATH}) 52 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 53 | endif () 54 | 55 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 56 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 57 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 58 | endif () 59 | 60 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 61 | 62 | include(${PICO_SDK_INIT_CMAKE_FILE}) -------------------------------------------------------------------------------- /pico-sdk/project/src/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | #include 8 | #include "pico/stdlib.h" 9 | 10 | int main() { 11 | stdio_init_all(); 12 | while (true) { 13 | printf("Hello, world!\n"); 14 | sleep_ms(1000); 15 | } 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /platformio-stm32/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | RUN apt-get update && apt-get install -y python3 python3-venv curl 4 | RUN adduser --disabled-password --gecos "" wokwi 5 | USER wokwi 6 | 7 | # Install PlatformIO Core (CLI) 8 | WORKDIR /home/wokwi 9 | RUN python3 -c "$(curl -fsSL https://raw.githubusercontent.com/platformio/platformio/master/scripts/get-platformio.py)" 10 | 11 | ADD --chown=wokwi project /home/wokwi/project 12 | ENV PATH=$PATH:/home/wokwi/.platformio/penv/bin 13 | WORKDIR /home/wokwi/project 14 | RUN pio run 15 | COPY compile.sh /home/wokwi/project 16 | -------------------------------------------------------------------------------- /platformio-stm32/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OUTPUT_DIR="/home/wokwi/project/output" 4 | 5 | # Extract the pnum from the board specification, convert it to lowercase 6 | REGEX='[:,]pnum=([a-zA-Z0-9_]+)' 7 | [[ "$WOKWI_BOARD" =~ $REGEX ]] 8 | ENV=${BASH_REMATCH[1],,} 9 | 10 | export PLATFORMIO_DEFAULT_ENVS="$ENV" 11 | rm -rf /home/wokwi/project/.pio/build/$ENV/firmware.* 12 | 13 | if [ "$WOKWI_DEBUG_BUILD" == "1" ]; then 14 | pio debug 15 | else 16 | pio run 17 | fi 18 | 19 | mkdir -p "$OUTPUT_DIR" 20 | cp /home/wokwi/project/.pio/build/$ENV/firmware.* $OUTPUT_DIR 2>>/dev/null 21 | -------------------------------------------------------------------------------- /platformio-stm32/project/platformio.ini: -------------------------------------------------------------------------------- 1 | [env] 2 | platform = ststm32 3 | framework = stm32cube 4 | 5 | [env:nucleo_l432kc] 6 | board = nucleo_l432kc 7 | build_flags = -DL4 8 | 9 | [env:bluepill_f103c8] 10 | board = bluepill_f103c8 11 | build_flags = -DF1 12 | -------------------------------------------------------------------------------- /platformio-stm32/project/src/main.c: -------------------------------------------------------------------------------- 1 | #if F0 2 | #include "stm32f0xx_hal.h" 3 | #elif F1 4 | #include "stm32f1xx_hal.h" 5 | #elif F2 6 | #include "stm32f2xx_hal.h" 7 | #elif F3 8 | #include "stm32f3xx_hal.h" 9 | #elif F4 10 | #include "stm32f4xx_hal.h" 11 | #elif F7 12 | #include "stm32f7xx_hal.h" 13 | #elif L0 14 | #include "stm32l0xx_hal.h" 15 | #elif L1 16 | #include "stm32l1xx_hal.h" 17 | #elif L4 18 | #include "stm32l4xx_hal.h" 19 | #else 20 | #error "Unsupported STM32 Family" 21 | #endif 22 | 23 | #define LED_PIN GPIO_PIN_5 24 | #define LED_GPIO_PORT GPIOA 25 | #define LED_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() 26 | 27 | int main(void) 28 | { 29 | HAL_Init(); 30 | 31 | LED_GPIO_CLK_ENABLE(); 32 | 33 | GPIO_InitTypeDef GPIO_InitStruct; 34 | 35 | GPIO_InitStruct.Pin = LED_PIN; 36 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 37 | GPIO_InitStruct.Pull = GPIO_PULLUP; 38 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; 39 | HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct); 40 | 41 | while (1) 42 | { 43 | HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_PIN); 44 | 45 | HAL_Delay(1000); 46 | } 47 | } 48 | 49 | void SysTick_Handler(void) 50 | { 51 | HAL_IncTick(); 52 | } 53 | 54 | void NMI_Handler(void) 55 | { 56 | } 57 | 58 | void HardFault_Handler(void) 59 | { 60 | while (1) {} 61 | } 62 | 63 | 64 | void MemManage_Handler(void) 65 | { 66 | while (1) {} 67 | } 68 | 69 | void BusFault_Handler(void) 70 | { 71 | while (1) {} 72 | } 73 | 74 | void UsageFault_Handler(void) 75 | { 76 | while (1) {} 77 | } 78 | 79 | void SVC_Handler(void) 80 | { 81 | } 82 | 83 | 84 | void DebugMon_Handler(void) 85 | { 86 | } 87 | 88 | void PendSV_Handler(void) 89 | { 90 | } 91 | -------------------------------------------------------------------------------- /rust-nostd-esp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM espressif/idf-rust:all_1.84.0.0 2 | 3 | USER esp 4 | ENV USER=esp 5 | 6 | # Install extra crates 7 | RUN cargo install cargo-audit && \ 8 | curl -L "https://github.com/esp-rs/esp-generate/releases/latest/download/esp-generate-x86_64-unknown-linux-gnu" -o "${HOME}/.cargo/bin/esp-generate" && \ 9 | chmod u+x "${HOME}/.cargo/bin/esp-generate" && \ 10 | curl -L "https://github.com/SergioGasquez/rnamer/releases/latest/download/rnamer-x86_64-unknown-linux-gnu" -o "${HOME}/.cargo/bin/rnamer" && \ 11 | chmod u+x "${HOME}/.cargo/bin/rnamer" 12 | 13 | # Generate project templates 14 | RUN esp-generate --headless --chip=esp32 -o log rust-project-esp32 15 | RUN esp-generate --headless --chip=esp32c3 -o log rust-project-esp32c3 16 | RUN esp-generate --headless --chip=esp32c6 -o log rust-project-esp32c6 17 | RUN esp-generate --headless --chip=esp32h2 -o log rust-project-esp32h2 18 | RUN esp-generate --headless --chip=esp32s2 -o log rust-project-esp32s2 19 | RUN esp-generate --headless --chip=esp32s3 -o log rust-project-esp32s3 20 | 21 | # Copy utility scripts and setup 22 | COPY compile.sh /home/esp/ 23 | 24 | RUN mkdir -p /home/esp/build-in /home/esp/build-out 25 | 26 | # Prebuild the template project for all targets, to test the container. 27 | # We remove the target directory to reduce the image size. 28 | RUN WOKWI_MCU=esp32 ./compile.sh && rm -rf rust-project-esp32/target 29 | RUN WOKWI_MCU=esp32-c3 ./compile.sh && rm -rf rust-project-esp32c3/target 30 | RUN WOKWI_MCU=esp32-c6 ./compile.sh && rm -rf rust-project-esp32c6/target 31 | RUN WOKWI_MCU=esp32-h2 ./compile.sh && rm -rf rust-project-esp32h2/target 32 | RUN WOKWI_MCU=esp32-s2 ./compile.sh && rm -rf rust-project-esp32s2/target 33 | RUN WOKWI_MCU=esp32-s3 ./compile.sh && rm -rf rust-project-esp32s3/target 34 | 35 | ENV HOME="/home/esp" 36 | ENV HEXI_SRC_DIR="/home/esp/build-in" 37 | ENV HEXI_SRC_FILES="*(*.rs|Cargo.toml)" 38 | ENV HEXI_BUILD_CMD="bash /home/esp/compile.sh" 39 | ENV HEXI_OUT_HEX="/home/esp/build-out/project.bin" 40 | ENV HEXI_OUT_ELF="/home/esp/build-out/project.elf" 41 | -------------------------------------------------------------------------------- /rust-nostd-esp/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | . /home/esp/export-esp.sh 5 | 6 | case ${WOKWI_MCU} in 7 | "esp32") 8 | PROJECT_NAME="rust-project-esp32" 9 | TARGET="xtensa-esp32-none-elf" 10 | ;; 11 | "esp32-c3") 12 | PROJECT_NAME="rust-project-esp32c3" 13 | TARGET="riscv32imc-unknown-none-elf" 14 | ;; 15 | "esp32-c6") 16 | PROJECT_NAME="rust-project-esp32c6" 17 | TARGET="riscv32imac-unknown-none-elf" 18 | ;; 19 | "esp32-h2") 20 | PROJECT_NAME="rust-project-esp32h2" 21 | TARGET="riscv32imac-unknown-none-elf" 22 | ;; 23 | "esp32-s2") 24 | PROJECT_NAME="rust-project-esp32s2" 25 | TARGET="xtensa-esp32s2-none-elf" 26 | ;; 27 | "esp32-s3") 28 | PROJECT_NAME="rust-project-esp32s3" 29 | TARGET="xtensa-esp32s3-none-elf" 30 | ;; 31 | *) 32 | echo "Missing or invalid WOKWI_MCU environment variable" 33 | exit 1 34 | ;; 35 | esac 36 | 37 | cd ${PROJECT_NAME} 38 | WOKWI_MCU_NO_DASH="${WOKWI_MCU//-/}" 39 | 40 | if [ "$(find ${HOME}/build-in -name '*.rs')" ]; then 41 | cp ${HOME}/build-in/*.rs src 42 | fi 43 | 44 | if [ -f ${HOME}/build-in/Cargo.toml ]; then 45 | cp ${HOME}/build-in/Cargo.toml Cargo.toml 46 | rnamer -n ${PROJECT_NAME} 47 | fi 48 | 49 | cargo audit 50 | cargo update 51 | cargo build --release 52 | espflash save-image --chip ${WOKWI_MCU_NO_DASH} --flash-size 4mb target/${TARGET}/release/${PROJECT_NAME} ${HOME}/build-out/project.bin 53 | cp target/${TARGET}/release/${PROJECT_NAME} ${HOME}/build-out/project.elf 54 | -------------------------------------------------------------------------------- /rust-wasm/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.16 2 | RUN apk update 3 | RUN apk add rust cargo rust-wasm 4 | RUN adduser -D wokwi 5 | COPY project /project 6 | 7 | RUN chown wokwi /project/src/lib.rs && chmod o+w /project 8 | 9 | WORKDIR /project 10 | USER wokwi 11 | RUN cargo build --target wasm32-unknown-unknown --release 12 | 13 | # Wokwi builder configuration: 14 | ENV HEXI_SRC_DIR="/project/src" 15 | ENV HEXI_BUILD_CMD="cargo build --target wasm32-unknown-unknown --release --offline" 16 | ENV HEXI_OUT_HEX="/project/target/wasm32-unknown-unknown/release/chip_rust.wasm" 17 | ENV HEXI_OUT_ELF="/project/target/wasm32-unknown-unknown/release/chip_rust.wasm" 18 | -------------------------------------------------------------------------------- /rust-wasm/project/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | 2 | [build] 3 | target = "wasm32-unknown-unknown" 4 | rustflags = ["-Clink-arg=--export-table"] 5 | -------------------------------------------------------------------------------- /rust-wasm/project/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "chip-rust" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "wokwi_chip_ll", 10 | ] 11 | 12 | [[package]] 13 | name = "wokwi_chip_ll" 14 | version = "0.1.1" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "9ce61b94e241449ad14dded340468f460db3bd5cff4be094affd6a4ab0b22338" 17 | -------------------------------------------------------------------------------- /rust-wasm/project/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chip-rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | wokwi_chip_ll = "0.1.1" 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | -------------------------------------------------------------------------------- /rust-wasm/project/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_void, CString}; 2 | 3 | use wokwi_chip_ll::{ 4 | debugPrint, pinInit, pinWatch, pinWrite, PinId, WatchConfig, BOTH, HIGH, INPUT, LOW, OUTPUT, 5 | }; 6 | 7 | struct Chip { 8 | pin_in: PinId, 9 | pin_out: PinId, 10 | } 11 | 12 | pub unsafe fn on_pin_change(user_data: *const c_void, _pin: PinId, value: u32) { 13 | let chip = &*(user_data as *const Chip); 14 | if value == HIGH { 15 | pinWrite(chip.pin_out, LOW); 16 | } else { 17 | pinWrite(chip.pin_out, HIGH); 18 | } 19 | } 20 | 21 | #[no_mangle] 22 | pub unsafe extern "C" fn chipInit() { 23 | debugPrint(CString::new("Hello rusty!").unwrap().into_raw()); 24 | 25 | let chip = Chip { 26 | pin_in: pinInit(CString::new("IN").unwrap().into_raw(), INPUT), 27 | pin_out: pinInit(CString::new("OUT").unwrap().into_raw(), OUTPUT), 28 | }; 29 | 30 | let watch_config = WatchConfig { 31 | user_data: &chip as *const _ as *const c_void, 32 | edge: BOTH, 33 | pin_change: on_pin_change as *const c_void, 34 | }; 35 | pinWatch(chip.pin_in, &watch_config); 36 | } 37 | -------------------------------------------------------------------------------- /verilog-cxxrtl/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y git curl python3 xz-utils bzip2 5 | WORKDIR /opt 6 | RUN curl -L https://github.com/YosysHQ/oss-cad-suite-build/releases/download/2023-07-31/oss-cad-suite-linux-x64-20230731.tgz | tar zxf - 7 | RUN git clone --depth 1 https://github.com/emscripten-core/emsdk.git 8 | WORKDIR /opt/emsdk 9 | RUN ./emsdk install latest && ./emsdk activate latest 10 | 11 | RUN adduser --disabled-password --gecos "" wokwi 12 | USER wokwi 13 | ENV PATH="/opt/oss-cad-suite/bin:${PATH}" 14 | ADD --chown=wokwi project /home/wokwi/project 15 | WORKDIR /home/wokwi/project 16 | RUN ./compile.sh 17 | 18 | # Wokwi builder configuration: 19 | ENV HEXI_SRC_DIR="/home/wokwi/project/src" 20 | ENV HEXI_BUILD_CMD="/home/wokwi/project/compile.sh" 21 | ENV HEXI_OUT_HEX="/home/wokwi/project/wokwi.wasm" 22 | ENV HEXI_OUT_ELF="/home/wokwi/project/wokwi.wasm" 23 | -------------------------------------------------------------------------------- /verilog-cxxrtl/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022-2023 Wokwi (by CodeMagic LTD) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /verilog-cxxrtl/project/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yosys -p "read_verilog src/wokwi.v; write_cxxrtl src/wokwi_cxxrtl.h" || exit 1 3 | source /opt/emsdk/emsdk_env.sh 4 | emcc -O3 -std=c++14 -I `yosys-config --datdir`/include -Isrc main.cpp --no-entry -sERROR_ON_UNDEFINED_SYMBOLS=0 -sINITIAL_MEMORY=128kb -sALLOW_MEMORY_GROWTH -sTOTAL_STACK=64kb -o wokwi.wasm 5 | -------------------------------------------------------------------------------- /verilog-cxxrtl/project/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "emscripten.h" 3 | #include "src/wokwi_cxxrtl.h" 4 | 5 | namespace wokwi { 6 | #include "src/wokwi-api.h" 7 | } 8 | 9 | typedef struct chip_pin_t { 10 | struct chip_state_t *chip; 11 | wokwi::pin_t wokwi_pin; 12 | cxxrtl::debug_item verilog_pin; 13 | uint8_t bit_index; 14 | struct chip_pin_t *next; 15 | } chip_pin_t; 16 | 17 | typedef struct chip_state_t { 18 | cxxrtl_design::p_wokwi *design; 19 | struct chip_pin_t *first_pin; 20 | } chip_state_t; 21 | 22 | static void update_input_pin(cxxrtl::debug_item verilog_pin, wokwi::pin_t wokwi_pin, uint8_t bit_index, uint32_t value) { 23 | if (verilog_pin.width == 1) { 24 | verilog_pin.next[0] = value; 25 | } else { 26 | uint32_t v = verilog_pin.curr[0]; 27 | if (value) { 28 | v |= (1 << bit_index); 29 | } else { 30 | v &= ~(1 << bit_index); 31 | } 32 | verilog_pin.next[0] = v; 33 | } 34 | } 35 | 36 | static void update_output_pin(cxxrtl::debug_item verilog_pin, wokwi::pin_t wokwi_pin) { 37 | if(verilog_pin.type == CXXRTL_OUTLINE) { 38 | verilog_pin.outline->eval(); 39 | } 40 | if (verilog_pin.width == 1) { 41 | wokwi::pin_write(wokwi_pin, verilog_pin.curr[0] ? wokwi::HIGH : wokwi::LOW); 42 | } else { 43 | for (uint32_t i = 0; i < verilog_pin.width; i++) { 44 | wokwi::pin_write(wokwi_pin, verilog_pin.curr[i]); 45 | } 46 | } 47 | } 48 | 49 | static void inline update_output_pins(chip_state_t *chip) { 50 | for (auto pin = chip->first_pin; pin; pin = pin->next) { 51 | auto verilog_pin = pin->verilog_pin; 52 | wokwi::pin_t wokwi_pin = pin->wokwi_pin; 53 | if ((verilog_pin.flags & cxxrtl::debug_item::OUTPUT) || verilog_pin.type == CXXRTL_ALIAS || verilog_pin.type == CXXRTL_OUTLINE) { 54 | update_output_pin(verilog_pin, wokwi_pin); 55 | } 56 | } 57 | } 58 | 59 | static void chip_input_pin_changed(void *state, wokwi::pin_t pin, uint32_t value) { 60 | chip_pin_t *ctx = (chip_pin_t *)state; 61 | 62 | update_input_pin(ctx->verilog_pin, pin, ctx->bit_index, value); 63 | 64 | auto design = ctx->chip->design; 65 | design->step(); 66 | 67 | update_output_pins(ctx->chip); 68 | } 69 | 70 | static chip_pin_t *create_pin(chip_state_t *chip) { 71 | chip_pin_t *result = (chip_pin_t *)malloc(sizeof(chip_pin_t)); 72 | result->next = chip->first_pin; 73 | result->chip = chip; 74 | chip->first_pin = result; 75 | return result; 76 | } 77 | 78 | extern "C" void chip_init(void) { 79 | chip_state_t *chip = (chip_state_t *)malloc(sizeof(chip_state_t)); 80 | chip->design = new cxxrtl_design::p_wokwi(); 81 | chip->first_pin = NULL; 82 | 83 | printf("Verilog chip started\n"); 84 | 85 | cxxrtl::debug_items items; 86 | chip->design->debug_info(items); 87 | 88 | for(auto &it : items.table) { 89 | for(auto &part : it.second) { 90 | const char *name = it.first.c_str(); 91 | if (part.flags & cxxrtl::debug_item::INPUT) { 92 | chip_pin_t *pin = create_pin(chip); 93 | pin->wokwi_pin = wokwi::pin_init(name, wokwi::INPUT); 94 | pin->verilog_pin = part; 95 | 96 | const wokwi::pin_watch_config_t config = { 97 | .user_data = pin, 98 | .edge = wokwi::BOTH, 99 | .pin_change = chip_input_pin_changed, 100 | }; 101 | uint32_t value = wokwi::pin_read(pin->wokwi_pin); 102 | update_input_pin(part, pin->wokwi_pin, 0, value); 103 | wokwi::pin_watch(pin->wokwi_pin, &config); 104 | } else if ((part.flags & cxxrtl::debug_item::OUTPUT) || part.type == CXXRTL_ALIAS || part.type == CXXRTL_OUTLINE) { 105 | chip_pin_t *pin = create_pin(chip); 106 | pin->wokwi_pin = wokwi::pin_init(name, wokwi::OUTPUT); 107 | pin->verilog_pin = part; 108 | } else if (part.flags & CXXRTL_DRIVEN_COMB && part.type == CXXRTL_VALUE ) { // Constant pin 109 | wokwi::pin_t pin = wokwi::pin_init(name, wokwi::OUTPUT); 110 | update_output_pin(part, pin); 111 | } 112 | } 113 | } 114 | 115 | chip->design->step(); 116 | update_output_pins(chip); 117 | } 118 | -------------------------------------------------------------------------------- /verilog-cxxrtl/project/src/wokwi-api.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef WOKWI_API_H 5 | #define WOKWI_API_H 6 | 7 | enum pin_value { 8 | LOW = 0, 9 | HIGH = 1 10 | }; 11 | 12 | enum pin_mode { 13 | INPUT = 0, 14 | OUTPUT = 1, 15 | INPUT_PULLUP = 2, 16 | INPUT_PULLDOWN = 3, 17 | ANALOG = 4, 18 | 19 | OUTPUT_LOW = 16, 20 | OUTPUT_HIGH = 17, 21 | }; 22 | 23 | enum edge { 24 | RISING = 1, 25 | FALLING = 2, 26 | BOTH = 3, 27 | }; 28 | 29 | void __attribute__((export_name("_wokwi:api.version=1"))) __wokwi_api_version(void) {} 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | typedef int32_t pin_t; 36 | #define NO_PIN ((pin_t)-1) 37 | 38 | typedef struct { 39 | void *user_data; 40 | uint32_t edge; 41 | void (*pin_change)(void *user_data, pin_t pin, uint32_t value); 42 | } pin_watch_config_t; 43 | 44 | extern __attribute__((export_name("chipInit"))) void chip_init(void); 45 | 46 | extern __attribute__((import_name("pinInit"))) pin_t pin_init(const char *name, uint32_t mode); 47 | 48 | extern __attribute__((import_name("pinRead"))) uint32_t pin_read(pin_t pin); 49 | extern __attribute__((import_name("pinWrite"))) void pin_write(pin_t pin, uint32_t value); 50 | extern __attribute__((import_name("pinWatch"))) bool pin_watch(pin_t pin, const pin_watch_config_t *config); 51 | extern __attribute__((import_name("pinWatchStop"))) void pin_watch_stop(pin_t pin); 52 | extern __attribute__((import_name("pinMode"))) void pin_mode(pin_t pin, uint32_t value); 53 | extern __attribute__((import_name("pinADCRead"))) float pin_adc_read(pin_t pin); 54 | extern __attribute__((import_name("pinDACWrite"))) float pin_dac_write(pin_t pin, float voltage); 55 | 56 | extern __attribute__((import_name("attrInit"))) uint32_t attr_init(const char *name, uint32_t default_value); 57 | extern __attribute__((import_name("attrInit"))) uint32_t attr_init_float(const char *name, float default_value); 58 | extern __attribute__((import_name("attrRead"))) uint32_t attr_read(uint32_t attr_id); 59 | extern __attribute__((import_name("attrReadFloat"))) float attr_read_float(uint32_t attr_id); 60 | 61 | typedef struct { 62 | void *user_data; 63 | uint32_t address; 64 | pin_t scl; 65 | pin_t sda; 66 | bool (*connect)(void *user_data, uint32_t address, bool connect); 67 | uint8_t (*read)(void *user_data); 68 | bool (*write)(void *user_data, uint8_t data); 69 | void (*disconnect)(void *user_data); 70 | uint32_t reserved[8]; 71 | } i2c_config_t; 72 | 73 | typedef uint32_t i2c_dev_t; 74 | 75 | extern __attribute__((import_name("i2cInit"))) i2c_dev_t i2c_init(const i2c_config_t *config); 76 | 77 | typedef struct { 78 | void *user_data; 79 | pin_t rx; 80 | pin_t tx; 81 | uint32_t baud_rate; 82 | void (*rx_data)(void *user_data, uint8_t byte); 83 | void (*write_done)(void *user_data); 84 | uint32_t reserved[8]; 85 | } uart_config_t; 86 | 87 | typedef uint32_t uart_dev_t; 88 | 89 | extern __attribute__((import_name("uartInit"))) uart_dev_t uart_init(const uart_config_t *config); 90 | extern __attribute__((import_name("uartWrite"))) bool uart_write(uart_dev_t uart, uint8_t *buffer, uint32_t count); 91 | 92 | typedef struct { 93 | void *user_data; 94 | pin_t sck; 95 | pin_t mosi; 96 | pin_t miso; 97 | uint32_t mode; 98 | void (*done)(void *user_data, uint8_t *buffer, uint32_t count); 99 | uint32_t reserved[8]; 100 | } spi_config_t; 101 | typedef uint32_t spi_dev_t; 102 | 103 | extern __attribute__((import_name("spiInit"))) spi_dev_t spi_init(const spi_config_t *spi_config); 104 | extern __attribute__((import_name("spiStart"))) void spi_start(const spi_dev_t spi, uint8_t *buffer, uint32_t count); 105 | extern __attribute__((import_name("spiStop"))) void spi_stop(const spi_dev_t spi); 106 | 107 | typedef struct { 108 | void *user_data; 109 | void (*callback)(void *user_data); 110 | uint32_t reserved[8]; 111 | } timer_config_t; 112 | 113 | typedef uint32_t timer_t; 114 | 115 | extern __attribute__((import_name("timerInit"))) timer_t timer_init(const timer_config_t *config); 116 | extern __attribute__((import_name("timerStart"))) void timer_start(const timer_t timer, uint32_t micros, bool repeat); 117 | extern __attribute__((import_name("timerStartNanos"))) void timer_start_ns_d(const timer_t timer, double nanos, bool repeat); 118 | static void timer_start_ns(const timer_t timer, uint64_t nanos, bool repeat) { 119 | timer_start_ns_d(timer, (double)nanos, repeat); 120 | } 121 | extern __attribute__((import_name("timerStop"))) void timer_stop(const timer_t timer); 122 | 123 | extern __attribute__((import_name("getSimNanos"))) double get_sim_nanos_d(void); 124 | 125 | static uint64_t get_sim_nanos(void) { 126 | return (uint64_t)get_sim_nanos_d(); 127 | } 128 | 129 | typedef uint32_t buffer_t; 130 | extern __attribute__((import_name("framebufferInit"))) buffer_t framebuffer_init(uint32_t *pixel_width, uint32_t *pixel_height); 131 | extern __attribute__((import_name("bufferRead"))) void buffer_read(buffer_t buffer, uint32_t offset, uint8_t *data, uint8_t data_len); 132 | extern __attribute__((import_name("bufferWrite"))) void buffer_write(buffer_t buffer, uint32_t offset, uint8_t *data, uint8_t data_len); 133 | 134 | #ifdef __cplusplus 135 | } 136 | #endif 137 | 138 | #endif /* WOKWI_API_H */ 139 | -------------------------------------------------------------------------------- /verilog-cxxrtl/project/src/wokwi.v: -------------------------------------------------------------------------------- 1 | module wokwi(input clk, output led); 2 | reg [11:0] counter = 12'h0; 3 | 4 | always @(posedge clk) begin 5 | counter <= counter + 1'b1; 6 | end 7 | 8 | assign led = counter[7]; 9 | 10 | endmodule 11 | -------------------------------------------------------------------------------- /zephyr-esp32/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/beriberikix/zephyr-xtensa-espressif_esp32:v3.3.0-0.16.0sdk 2 | 3 | RUN apt update \ 4 | && apt install -y --no-install-recommends python3-pip \ 5 | && pip3 install pyserial 6 | 7 | RUN adduser --disabled-password --gecos "" wokwi 8 | USER wokwi 9 | WORKDIR /home/wokwi/app 10 | 11 | COPY west.yml . 12 | RUN west init -l . 13 | RUN west update --narrow 14 | RUN west blobs fetch hal_espressif 15 | 16 | WORKDIR /home/wokwi/zephyr 17 | COPY esp32-wokwi.dts samples/basic/blinky/app.overlay 18 | RUN west build -b esp32 samples/basic/blinky -p 19 | 20 | # Wokwi builder configuration: 21 | ENV HEXI_SRC_DIR="/home/wokwi/zephyr/samples/basic/blinky/src" 22 | ENV HEXI_BUILD_CMD="west build -b esp32 samples/basic/blinky -p" 23 | ENV HEXI_OUT_HEX="/home/wokwi/zephyr/build/zephyr/zephyr.bin" 24 | ENV HEXI_OUT_ELF="/home/wokwi/zephyr/build/zephyr/zephyr.elf" -------------------------------------------------------------------------------- /zephyr-esp32/esp32-wokwi.dts: -------------------------------------------------------------------------------- 1 | / { 2 | aliases { 3 | led0 = &led0; 4 | }; 5 | 6 | leds { 7 | compatible = "gpio-leds"; 8 | led0: led_0 { 9 | gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; 10 | }; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /zephyr-esp32/west.yml: -------------------------------------------------------------------------------- 1 | manifest: 2 | projects: 3 | - name: zephyr 4 | revision: v3.3.0 5 | url: https://github.com/zephyrproject-rtos/zephyr 6 | import: 7 | name-allowlist: 8 | - hal_espressif -------------------------------------------------------------------------------- /zig-wasm/.gitignore: -------------------------------------------------------------------------------- 1 | project/zig-* 2 | -------------------------------------------------------------------------------- /zig-wasm/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.16 2 | RUN apk update 3 | RUN adduser -D wokwi 4 | COPY project /project 5 | 6 | RUN wget -q https://github.com/marler8997/zigup/releases/download/v2022_08_25/zigup.ubuntu-latest-x86_64.zip && \ 7 | unzip zigup.ubuntu-latest-x86_64.zip -d /usr/bin && \ 8 | chmod +x /usr/bin/zigup && \ 9 | zigup 0.10.0 10 | 11 | RUN chown wokwi /project/src/lib.zig && chmod o+w /project 12 | 13 | WORKDIR /project 14 | 15 | RUN zig build -Drelease-small 16 | 17 | # Wokwi builder configuration: 18 | ENV HEXI_SRC_DIR="/project/src" 19 | ENV HEXI_BUILD_CMD="zig build -Drelease-small" 20 | ENV HEXI_OUT_HEX="/project/zig-out/lib/chip_zig.wasm" 21 | ENV HEXI_OUT_ELF="/project/zig-out/lib/chip_zig.wasm" 22 | -------------------------------------------------------------------------------- /zig-wasm/project/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn build(b: *std.build.Builder) void { 4 | b.prominent_compile_errors = true; 5 | const mode = b.standardReleaseOptions(); 6 | const target: std.zig.CrossTarget = .{ .cpu_arch = .wasm32, .os_tag = .freestanding }; 7 | 8 | const lib = b.addSharedLibrary("chip_zig", "src/lib.zig", .unversioned); 9 | lib.setTarget(target); 10 | lib.setBuildMode(mode); 11 | lib.addPackagePath("wokwi", "wokwi/wokwi_chip_ll.zig"); 12 | lib.export_table = true; 13 | lib.install(); 14 | } 15 | -------------------------------------------------------------------------------- /zig-wasm/project/src/lib.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const wokwi = @import("wokwi"); 3 | 4 | const Chip = extern struct { 5 | pin_in: wokwi.PinId, 6 | pin_out: wokwi.PinId, 7 | }; 8 | 9 | fn on_pin_change(user_data: ?*anyopaque, _: wokwi.PinId, value: u32) void { 10 | var data = user_data.?; 11 | const chip = @ptrCast(*Chip, @alignCast(4, data)); 12 | 13 | if (value == wokwi.HIGH) { 14 | wokwi.pinWrite(chip.pin_out, wokwi.LOW); 15 | } else { 16 | wokwi.pinWrite(chip.pin_out, wokwi.HIGH); 17 | } 18 | } 19 | 20 | export fn chipInit() callconv(.C) void { 21 | wokwi.debugPrint("Hello Zig!\n"); 22 | var chip = Chip{ 23 | .pin_in = wokwi.pinInit("IN", wokwi.INPUT), 24 | .pin_out = wokwi.pinInit("OUT", wokwi.OUTPUT), 25 | }; 26 | 27 | comptime var pin_c = on_pin_change; 28 | var pin_change: ?*anyopaque = @ptrCast(*anyopaque, &pin_c); 29 | 30 | var watch_config = wokwi.WatchConfig{ 31 | .user_data = @as(?*anyopaque, &chip), 32 | .edge = wokwi.BOTH, 33 | .pin_change = pin_change, 34 | }; 35 | _ = wokwi.pinWatch(chip.pin_in, &watch_config); 36 | } 37 | -------------------------------------------------------------------------------- /zig-wasm/project/wokwi/wokwi_chip_ll.zig: -------------------------------------------------------------------------------- 1 | pub const LOW: u32 = 0; 2 | pub const HIGH: u32 = 1; 3 | pub const INPUT: u32 = 0; 4 | pub const OUTPUT: u32 = 1; 5 | pub const INPUT_PULLUP: u32 = 2; 6 | pub const INPUT_PULLDOWN: u32 = 3; 7 | pub const ANALOG: u32 = 4; 8 | pub const OUTPUT_LOW: u32 = 16; 9 | pub const OUTPUT_HIGH: u32 = 16; 10 | pub const RISING: u32 = 1; 11 | pub const FALLING: u32 = 2; 12 | pub const BOTH: u32 = 3; 13 | pub const PinId = i32; 14 | pub const WatchConfig = extern struct { 15 | user_data: ?*anyopaque, 16 | edge: u32, 17 | pin_change: ?*anyopaque, 18 | }; 19 | 20 | pub const TimerId = u32; 21 | pub const TimerConfig = extern struct { 22 | user_data: ?*anyopaque, 23 | callback: ?*anyopaque, 24 | }; 25 | 26 | pub const UARTDevId = u32; 27 | pub const UARTConfig = extern struct { 28 | user_data: ?*anyopaque, 29 | rx: PinId, 30 | tx: PinId, 31 | baud_rate: u32, 32 | rx_data: ?*anyopaque, 33 | write_done: ?*anyopaque, 34 | }; 35 | 36 | pub const I2CDevId = u32; 37 | pub const I2CConfig = extern struct { 38 | user_data: ?*anyopaque, 39 | address: u32, 40 | scl: PinId, 41 | sda: PinId, 42 | connect: ?*anyopaque, 43 | read: ?*anyopaque, 44 | write: ?*anyopaque, 45 | disconnect: ?*anyopaque, 46 | }; 47 | 48 | pub const SPIDevId = u32; 49 | pub const SPIConfig = extern struct { 50 | user_data: ?*anyopaque, 51 | sck: PinId, 52 | mosi: PinId, 53 | miso: PinId, 54 | mode: u32, 55 | done: ?*anyopaque, 56 | }; 57 | 58 | pub const AttrId = u32; 59 | pub const BufferId = u32; 60 | pub const NO_PIN: PinId = -1; 61 | 62 | /// # Safety 63 | /// 64 | /// Just a stub to specify the Chip API version. 65 | pub export fn __wokwi_api_version_1() u32 { 66 | return 1; 67 | } 68 | pub extern fn pinInit(name: [*:0]const u8, mode: u32) PinId; 69 | pub extern fn pinMode(pin: PinId, mode: u32) callconv(.C) void; 70 | pub extern fn pinRead(pin: PinId) u32; 71 | pub extern fn pinWrite(pin: PinId, value: u32) callconv(.C) void; 72 | pub extern fn pinWatch(pin: PinId, watch_config: ?*WatchConfig) bool; 73 | pub extern fn pinWatchStop(pin: PinId) callconv(.C) void; 74 | pub extern fn pinADCRead(pin: PinId) f32; 75 | pub extern fn pinDACWrite(pin: PinId, value: f32) callconv(.C) void; 76 | pub extern fn getSimNanos() f64; 77 | pub extern fn timerInit(timer_config: ?*TimerConfig) TimerId; 78 | pub extern fn timerStart(timer: TimerId, micros: u32, repeat: bool) callconv(.C) void; 79 | pub extern fn timerStartNanos(timer: TimerId, nanos: f64, repeat: bool) callconv(.C) void; 80 | pub extern fn timerStop(timer: TimerId) callconv(.C) void; 81 | pub extern fn uartInit(config: UARTConfig) UARTDevId; 82 | pub extern fn uartWrite(dev: UARTDevId, buffer: [*:0]const u8, count: u32) bool; 83 | pub extern fn i2cInit(config: ?*I2CConfig) I2CDevId; 84 | pub extern fn spiInit(config: ?*SPIConfig) SPIDevId; 85 | pub extern fn spiStart(dev: SPIDevId, buffer: [*:0]const u8, count: u32) callconv(.C) void; 86 | pub extern fn spiStop(dev: SPIDevId) callconv(.C) void; 87 | pub extern fn attrInit(name: [*:0]const u8, default_value: f64) AttrId; 88 | pub extern fn attrRead(attr: AttrId) u32; 89 | pub extern fn attrReadFloat(attr: AttrId) f64; 90 | pub extern fn framebufferInit(width: ?*u32, height: ?*u32) BufferId; 91 | pub extern fn bufferRead(buffer: BufferId, offset: u32, data: [*:0]const u8, data_len: u32) u32; 92 | pub extern fn bufferWrite(buffer: BufferId, offset: u32, data: [*:0]const u8, data_len: u32) u32; 93 | pub extern fn debugPrint(message: [*:0]const u8) callconv(.C) void; 94 | --------------------------------------------------------------------------------