From e446f54e154b536e6307399adfd8d3f54245163d Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 7 Sep 2026 09:36:29 -0700 Subject: [PATCH 1/5] py: add CIRCUITPY_LOAD_NATIVE to load native .mpy without the emitter Expose MICROPY_PERSISTENT_CODE_LOAD_NATIVE as a CIRCUITPY_ make flag, the same way CIRCUITPY_ENABLE_MPY_NATIVE exposes MICROPY_EMIT_THUMB. A board that sets CIRCUITPY_LOAD_NATIVE = 1 loads and runs native and viper .mpy files that mpy-cross compiled on the host, without carrying the on-board emitter: @micropython.native and @micropython.viper from source still raise SyntaxError, a .mpy for another architecture still raises ValueError. Boards that already enable the emitter keep loading native .mpy, since the macro is also true when CIRCUITPY_ENABLE_MPY_NATIVE is set. Default is off; no board changes in this commit. Co-Authored-By: Claude Fable 5.1 --- py/circuitpy_mpconfig.h | 1 + py/circuitpy_mpconfig.mk | 3 +++ 2 files changed, 4 insertions(+) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 9dd5abc8a3a..89eeee606f5 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -105,6 +105,7 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_OPT_MPZ_BITWISE (0) #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) #define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_PERSISTENT_CODE_LOAD_NATIVE (CIRCUITPY_LOAD_NATIVE || CIRCUITPY_ENABLE_MPY_NATIVE) #define MICROPY_PY_ARRAY (CIRCUITPY_ARRAY) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index e7303c1d3b1..178f424d5c0 100755 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -419,6 +419,9 @@ CFLAGS += -DCIRCUITPY_KEYPAD_SHIFTREGISTERKEYS=$(CIRCUITPY_KEYPAD_SHIFTREGISTERK CIRCUITPY_KEYPAD_DEMUX ?= $(CIRCUITPY_KEYPAD) CFLAGS += -DCIRCUITPY_KEYPAD_DEMUX=$(CIRCUITPY_KEYPAD_DEMUX) +CIRCUITPY_LOAD_NATIVE ?= 0 +CFLAGS += -DCIRCUITPY_LOAD_NATIVE=$(CIRCUITPY_LOAD_NATIVE) + CIRCUITPY_LOCALE ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_LOCALE=$(CIRCUITPY_LOCALE) From cee7c17c08494ef4ff5157247e8aa9b1d873d2c8 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 7 Sep 2026 09:40:53 -0700 Subject: [PATCH 2/5] boards: load native .mpy on five ARM boards Turn on CIRCUITPY_LOAD_NATIVE for the Metro M4 AirLift Lite, Metro RP2040, Metro RP2350, Feather nRF52840 Express and Feather STM32F405 Express. Flash cost over the same build without the flag, and the time for a host-compiled viper mandelbrot (160x120, 64 iterations) against the float bytecode a user would write: Metro M4 AirLift Lite +1,904 B 431 ms (11,221 ms bytecode) Metro RP2040 +3,036 B 384 ms (13,942 ms bytecode) Metro RP2350 +2,876 B 261 ms (6,371 ms bytecode) Feather nRF52840 Express +2,432 B 781 ms (20,788 ms bytecode) Feather STM32F405 Express +2,444 B 416 ms (8,121 ms bytecode) The SAMD51 board is the reason for the flag: the on-board emitter overflows its flash by 12,804 B, the loader alone fits with 6,876 B free. Co-Authored-By: Claude Fable 5.1 --- ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk | 2 ++ ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk | 2 ++ ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk | 2 ++ ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk | 2 ++ ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk | 2 ++ 5 files changed, 10 insertions(+) diff --git a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk index cb7e690c6c0..a8e64606f4a 100644 --- a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk @@ -28,3 +28,5 @@ ifneq (,$(filter $(TRANSLATION),ja ko ru)) CIRCUITPY_TERMINALIO = 0 RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO) endif + +CIRCUITPY_LOAD_NATIVE = 1 diff --git a/ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk b/ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk index f77feb32250..70fad4656a5 100644 --- a/ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk +++ b/ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk @@ -7,3 +7,5 @@ MCU_CHIP = nrf52840 QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "GD25Q16C, W25Q16JVxQ" + +CIRCUITPY_LOAD_NATIVE = 1 diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk index 8b3ce22c1bc..976173b50d7 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk @@ -9,3 +9,5 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ,W25Q128JV" CIRCUITPY_SDIOIO = 1 + +CIRCUITPY_LOAD_NATIVE = 1 diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk index 6d499c367d7..bb0e5af811a 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk @@ -10,3 +10,5 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" CIRCUITPY_SDIOIO = 1 + +CIRCUITPY_LOAD_NATIVE = 1 diff --git a/ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk b/ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk index 75065000807..8177a4dd48e 100644 --- a/ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk +++ b/ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk @@ -17,3 +17,5 @@ LD_BOOT = boards/STM32F405_boot.ld UF2_OFFSET = 0x8010000 CIRCUITPY_RGBMATRIX ?= 1 + +CIRCUITPY_LOAD_NATIVE = 1 From 0da55e8c9e5ee65dfceb3c952d30ce4908957fa3 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 10 Sep 2026 14:36:07 -0700 Subject: [PATCH 3/5] raspberrypi: load native .mpy on all RP2 boards Move CIRCUITPY_LOAD_NATIVE from five board files to the raspberrypi port default, so every RP2040 and RP2350 board gets it. Other ports stay off and can be turned on one chip family at a time. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013jNwbykarVuwvQYHaPZS3Y --- ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk | 2 -- ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk | 2 -- ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk | 2 -- ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk | 2 -- ports/raspberrypi/mpconfigport.mk | 1 + ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk | 2 -- 6 files changed, 1 insertion(+), 10 deletions(-) diff --git a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk index a8e64606f4a..cb7e690c6c0 100644 --- a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk @@ -28,5 +28,3 @@ ifneq (,$(filter $(TRANSLATION),ja ko ru)) CIRCUITPY_TERMINALIO = 0 RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO) endif - -CIRCUITPY_LOAD_NATIVE = 1 diff --git a/ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk b/ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk index 70fad4656a5..f77feb32250 100644 --- a/ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk +++ b/ports/nordic/boards/feather_nrf52840_express/mpconfigboard.mk @@ -7,5 +7,3 @@ MCU_CHIP = nrf52840 QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "GD25Q16C, W25Q16JVxQ" - -CIRCUITPY_LOAD_NATIVE = 1 diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk index 976173b50d7..8b3ce22c1bc 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk @@ -9,5 +9,3 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ,W25Q128JV" CIRCUITPY_SDIOIO = 1 - -CIRCUITPY_LOAD_NATIVE = 1 diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk index bb0e5af811a..6d499c367d7 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk @@ -10,5 +10,3 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" CIRCUITPY_SDIOIO = 1 - -CIRCUITPY_LOAD_NATIVE = 1 diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 02fd6365b68..551ab00ab47 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -18,6 +18,7 @@ CIRCUITPY_BITOPS ?= 1 CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 CIRCUITPY_IMAGECAPTURE ?= 1 +CIRCUITPY_LOAD_NATIVE ?= 1 CIRCUITPY_MAX3421E ?= 0 CIRCUITPY_MCP4822 ?= 0 CIRCUITPY_MEMORYMAP ?= 1 diff --git a/ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk b/ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk index 8177a4dd48e..75065000807 100644 --- a/ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk +++ b/ports/stm/boards/feather_stm32f405_express/mpconfigboard.mk @@ -17,5 +17,3 @@ LD_BOOT = boards/STM32F405_boot.ld UF2_OFFSET = 0x8010000 CIRCUITPY_RGBMATRIX ?= 1 - -CIRCUITPY_LOAD_NATIVE = 1 From 8b859253c9933949ddfbfcb538e476ceb392b229 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 10 Sep 2026 15:04:51 -0700 Subject: [PATCH 4/5] raspberrypi: leave the loader off on four Pimoroni WiFi boards pimoroni_badger2040w, pimoroni_inky_frame_5_7, pimoroni_inky_frame_7_3 and pimoroni_plasma2040w run out of flash with it on. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013jNwbykarVuwvQYHaPZS3Y --- ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk | 3 +++ .../boards/pimoroni_inky_frame_5_7/mpconfigboard.mk | 3 +++ .../boards/pimoroni_inky_frame_7_3/mpconfigboard.mk | 3 +++ ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk | 3 +++ 4 files changed, 12 insertions(+) diff --git a/ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk index dc70c551959..9c4954f6d77 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk @@ -38,3 +38,6 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register + +# Not enough flash for the native .mpy loader +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk index 0a56b55a0c1..731bfae93cd 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk @@ -36,3 +36,6 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register + +# Not enough flash for the native .mpy loader +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.mk index ee04517499e..719746e8028 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.mk @@ -36,3 +36,6 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register + +# Not enough flash for the native .mpy loader +CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk index 442991fa126..5b192e4d9bb 100644 --- a/ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk @@ -35,3 +35,6 @@ CFLAGS += \ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel + +# Not enough flash for the native .mpy loader +CIRCUITPY_LOAD_NATIVE = 0 From 0518c5be6fed569914d68f5ecd82a6a9cde33573 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 10 Sep 2026 16:17:57 -0700 Subject: [PATCH 5/5] raspberrypi: re-enable the loader on four Pimoroni WiFi boards This reverts commit 8b859253c9. The overflow only happened with GCC 14.2.1. With the GCC 15.2.1 that CI uses, all four fit with the loader on in every language; the tightest, ja, leaves about 2.5 KB free. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013jNwbykarVuwvQYHaPZS3Y --- ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk | 3 --- .../boards/pimoroni_inky_frame_5_7/mpconfigboard.mk | 3 --- .../boards/pimoroni_inky_frame_7_3/mpconfigboard.mk | 3 --- ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk | 3 --- 4 files changed, 12 deletions(-) diff --git a/ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk index 9c4954f6d77..dc70c551959 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_badger2040w/mpconfigboard.mk @@ -38,6 +38,3 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register - -# Not enough flash for the native .mpy loader -CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk index 731bfae93cd..0a56b55a0c1 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk @@ -36,6 +36,3 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register - -# Not enough flash for the native .mpy loader -CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.mk index 719746e8028..ee04517499e 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.mk @@ -36,6 +36,3 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register - -# Not enough flash for the native .mpy loader -CIRCUITPY_LOAD_NATIVE = 0 diff --git a/ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk index 5b192e4d9bb..442991fa126 100644 --- a/ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_plasma2040w/mpconfigboard.mk @@ -35,6 +35,3 @@ CFLAGS += \ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel - -# Not enough flash for the native .mpy loader -CIRCUITPY_LOAD_NATIVE = 0