ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

MicroPython QEMU 移植(ports/qemu)完全指南:无硬件驱动的跨架构仿真、CI 与调试

2026/9/21 3:37:02 拓冰建站 浏览量
MicroPython QEMU 移植(ports/qemu)完全指南:无硬件驱动的跨架构仿真、CI 与调试 嵌入式语言运行时编程语言解释器编译器物联网系统编程【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址https://gitcode.com/gh_mirrors/mi/micropython点击查看免费下载本指南以 ports/qemu/README.md 为骨架结合 ports/qemu/Makefile、ports/qemu/main.c 等仓库源码系统讲解 MicroPython 官方 QEMU 移植的用途、工具链依赖、构建方式、REPL 与测试运行方法及全部可调 make 选项。读完你将掌握无需任何真实 MCU 与 JTAG即可在 QEMU 上为 ARM Cortex-M、RISC-V RV32/RV64、PowerPC 64 架构构建并运行 MicroPython 固件跑通官方测试套件与原生模块natmod测试并接入 gdb 进行无硬件调试。一、这个移植是做什么的ports/qemu是 MicroPython 仓库中一个实验性、由社区维护的移植其目标平台不是某块真实开发板而是 QEMUQuick Emulator模拟的虚拟机器。它覆盖三类处理器架构ARMCortex-M 系列如 Cortex-M3RISC-VRV32IMC / RV64IMCPowerPC 64little-endianREADME 明确给出了这一移植的三个核心用途这也是它与其它端口最本质的区别持续集成CI——在虚拟机上直接运行针对代码库中架构相关部分的测试。仓库的 tools/ci.sh 中可以看到完整的 CI 编排ci_qemu_build_arm_sabrelite、ci_qemu_build_rv32、ci_qemu_build_rv64等函数分别对SABRELITE、VIRT_RV32、VIRT_RV64板执行test_full、test与test_natmod覆盖了大小端MP_ENDIANNESS_BIG、硬浮点/软浮点armv6m/armv7m/armv7emsp/armv7emdp等多种组合。实验与原型验证——任何包含架构相关代码的部分都可以先仿真验证例如研究某条指令集特性对 MicroPython 或某个模块的优化影响。轻量化调试——不需要 JTAG不需要真实 MCU 芯片也不需要 OpenOCD省去了接线、按键等一切硬件调试的繁琐环节。二、构建前的工具链依赖不同架构的板卡需要对应的交叉编译工具链。ARMQEMU_ARCHarm需要裸机 ARM 工具链典型为arm-none-eabi-gcc。对应 Makefile 中CROSS_COMPILE ? arm-none-eabi-的设置。RISC-V 32QEMU_ARCHriscv32需要GCC 10 或更新版本的裸机 RISC-V 工具链要求支持 multilib或专门的 32 位工具链必须支持M、C、Zicsr扩展ABI 为ilp32newlib 与 picolibc 均可优先使用 picolibc存在时自动选择。一个容易踩坑的细节GCC 10 及更早版本不识别架构名中的Zicsr扩展因此 Makefile 中会根据GCC_VERSION自动切换RV32_ARCH ? rv32imac # GCC 10 RV32_ARCH ? rv32imac_zicsr # 新版本 GCC大多数发行版包管理器提供的预编译工具链或 xPack 等独立分发的riscv-none-elf-gcc开箱即用。RISC-V 64QEMU_ARCHriscv64要求与 RV32 类似但 ABI 为lp64、扩展为M、C、Zicsr。README 给出了一个自检技巧对交叉编译器执行gcc -v仅此一个参数如果输出中看不到-mcmodelmedany相关说明则该工具链很可能无法用于本移植。原因在于链接地址的约束QEMU 的VIRT_RV64板代码地址空间从0x80000000开始而一些工具链自带的libc、libm、libgcc无法被放置到超过0x7FFFF7FF的偏移处一旦构建过程引入这些库代码就会失败。README 直言“市面上很多现成的 RISC-V 工具链在这方面都是坏的”。针对这一痛点仓库提供了Docker 容器镜像内置与 MicroPython RV32/RV64 CI 任务相同、已知可用的编译器见 Dockerfile.riscv基于 Ubuntu 24.04安装gcc-riscv64-unknown-elf、picolibc-riscv64-unknown-elf、qemu-system及 Python 测试依赖。构建并运行测试cd $MICROPYTHON_SOURCE_ROOT/ports/qemu docker build -t micropython/mpy-qemu-riscv -f Dockerfile.riscv .cd $MICROPYTHON_SOURCE_ROOT docker container run -v .:/micropython --rm -it micropython/mpy-qemu-riscv make -C ports/qemu -- BOARDVIRT_RV64 test使用 Podman 时把docker换成podman即可。将VIRT_RV64换成VIRT_RV32即可运行 32 位测试。PowerPC 64QEMU_ARCHppc64需要面向 Linux PowerPC 64、小端little-endian输出的工具链典型为powerpc64le-linux-gnu-gcc对应 Makefile 中的CROSS_COMPILE ? powerpc64le-linux-gnu-。三、构建步骤在 ports/qemu 目录下执行。第一步先构建 MicroPython 交叉编译器 mpy-cross用于冻结模块与.mpy文件生成$ make -C ../../mpy-cross然后构建固件$ make默认板卡是mps2-an385Cortex-M3。选择其它板卡时通过BOARD参数指定$ make BOARDSABRELITE可用板卡一览README 给出的官方板卡对照表如下BOARD值对应 boards 目录下的子目录每个子目录含一个mpconfigboard.mk定义QEMU_ARCH、QEMU_MACHINE等关键参数BOARD名称架构对应的 QEMU 机器MICROBITarmmicrobitMPS2_AN385armmps2-an385MPS2_AN500armmps2-an500NETDUINO2armnetduino2POWERNV9ppc64powernv9SABRELITEarmsabreliteVIRT_RV32riscv32virtVIRT_RV64riscv64virt从源码结构看boards 目录下还额外包含MPS3_AN547armREADME 表格虽未列出但它同样可作为BOARDMPS3_AN547使用且 uart.c 中为其单独实现了 MPS3 外设寄存器映射UART 基址0x49303000。各板卡的关键差异源码佐证以默认板 boards/MPS2_AN385/mpconfigboard.mk 为例它定义了QEMU_ARCH arm、QEMU_MACHINE mps2-an385编译参数-mthumb -mcpucortex-m3 -mfloat-abisoft并声明QEMU_SOC_MPS2ROMFS 分区 0 起始地址0x21000000、大小0x00400000链接脚本mcu/arm/mps2.ld原生 GC helper 目标文件gchelper_native.o gchelper_thumb2.ompy-cross 架构参数-marcharmv7m。RISC-V 板如 boards/VIRT_RV64/mpconfigboard.mk则把 ROMFS 放在0x80620000并使用mcu/rv64/virt.ld与gchelper_rv64i.o。注意其注释提醒如果 ROMFS 分区大小不够需要同步修改 mcu/rv64/virt.ld 中的 ROMFS 段大小。四、运行与交互REPL、串口与测试固件启动后会在模拟硬件的 UART 上提供 MicroPython REPL。直接进入 REPLUART 重定向到 stdio$ make repl该命令会启动qemu-system-arm或对应的qemu-system-riscv32等并把 UART 重定向到终端标准输入输出。退出方式在 REPL 中执行import machine; machine.reset()或直接 Ctrl-C 终止命令。Makefile 中repl目标实现为-serial mon:stdio并提示 “Use machine.reset() to exit”。后台运行并连接外部串口终端$ make run该命令启动仿真并把 UART 重定向到一个pty 伪终端设备设备名会打印到 stdout。随后可用任何串口终端程序连接例如 MicroPython 官方工具 mpremote$ mpremote connect /dev/pts/1可以反复断开、重连该串口设备。结束时回到启动make run的终端按 Ctrl-C或在 REPL 中执行import machine; machine.reset()。运行官方测试套件一键运行全部测试$ make test或手动方式先make run启动仿真再在 tests 目录下用run-tests.py针对串口设备执行$ cd ../../tests $ ./run-tests.py -t /dev/pts/1make test的内部实现Makefile会把run-tests.py与-t execpty:$(QEMU_SYSTEM) $(QEMU_ARGS) ... -serial pty -kernel ../ports/qemu/$(BUILD)/firmware.elf组合起来自动拉起 QEMU 实例无需人工干预。测试示例原生模块natmod源码树自带的示例原生模块可用如下命令测试$ make test_natmod手动方式的注意事项与上面相同只是把run-tests.py换成run-natmodtests.py。默认会测试一组模块Makefile 中TEST_NATMODS ? btree deflate framebuf heapq random_basic re可用TEST_NATMODS选项限定子集见下一节。此外 Makefile 还提供了test_full目标依次执行三次测试普通运行、--via-mpy通过.mpy交叉编译字节码运行、--via-mpy --emit native原生机器码执行这正是 CI 中验证 mpy-cross 与各原生后端的关键路径。五、全部可调 make 选项以下是 README 列出的全部扩展选项可在make命令行追加选项作用CFLAGS_EXTRA向编译器传递额外编译标志RUN_TESTS_EXTRA在make test/make test_natmod时向run-tests.py/run-natmodtests.py传递额外参数如 CI 中使用的--arch armv6mQEMU_BASE指定 qemu 可执行文件的部分路径前缀例如/opt/custom-directory/qemu/bin/qemu-system-用法与交叉编译器名传给 MicroPython Makefile 的方式类似默认从系统PATH中查找对应 qemu 二进制QEMU_DEBUG1运行 qemurepl/run/test目标时阻塞等待调试器连接默认等待 gdb 连接 TCP 1234 端口QEMU_DEBUG_ARGS默认-s即 gdb 于 TCP 1234 端口可改为其它 qemu gdb 参数QEMU_DEBUG_EXTRA当QEMU_DEBUG1时额外传给 qemu 的选项QEMU_ROMFS_IMGn传入由 qemu 加载的 romfs 镜像若板卡启用TEST_NATMODS空格分隔的 natmod 名称列表限定test_natmod只测试指定子集例如make test_natmod TEST_NATMODSbtree heapq reMICROPY_HEAP_SIZE覆盖本移植的 GC 堆大小字节MICROPY_STACK_SIZE覆盖本移植的解释器栈大小字节选项背后的默认值源码级默认板卡BOARD ? MPS2_AN385构建目录按板卡命名BUILD ? build-$(BOARD)即build-MPS2_AN385等。堆与栈默认值arm 与 riscv32 为堆143360字节、栈10240字节riscv64 与 ppc64 为堆204800字节其中 ppc64 栈为20480字节。这些值通过-DMICROPY_HEAP_SIZE... -DMICROPY_STACK_SIZE...编译进固件且 main.c 在编译期强制校验二者必须为正整数。QEMU_DEBUG 实现当QEMU_DEBUG1时Makefile 会向 qemu 追加-S $(QEMU_DEBUG_ARGS) $(QEMU_DEBUG_EXTRA)。-S使 CPU 在启动时暂停等待调试器通过 gdb 协议接入后再继续执行。ROMFS 加载若配置了QEMU_ROMFS_IMGn会通过-device loader,file...,addr分区起始地址,force-rawon把镜像直接装入模拟内存测试时还会自动挂载 tests/assets/random_romfs.bin 作为 ROMFS 测试镜像见 Makefile 中ROMFS_TEST_IMAGE相关逻辑。picolibc 优先构建时若检测到编译器的picolibc.specs会自动追加--specs...显式选用 picolibc避免 Ubuntu 22.04 等发行版默认 nosys 导致的链接问题。六、源码视角这个移植的内部结构主循环与 REPL 分发main.c 是整个移植的入口其结构清晰地展示了“软复位”模型static uint32_t gc_heap[MICROPY_HEAP_SIZE / sizeof(uint32_t)]; int main(int argc, char **argv) { mp_cstack_init_with_sp_here(MICROPY_STACK_SIZE); gc_init(gc_heap, (char *)gc_heap MICROPY_HEAP_SIZE); ... for (;;) { mp_init(); for (;;) { if (pyexec_mode_kind PYEXEC_MODE_RAW_REPL) { if (pyexec_raw_repl() ! 0) break; } else { if (pyexec_friendly_repl() ! 0) break; } } mp_printf(mp_plat_print, MPY: soft reboot\n); ... gc_sweep_all(); mp_deinit(); } }要点堆是一个静态数组gc_init将其注册为 GC 堆因此MICROPY_HEAP_SIZE必须在编译期确定外层for(;;)实现无限软复位循环——这就是import machine; machine.reset()能“重启”而不退出仿真的原因内层循环根据pyexec_mode_kind分发到 RAW REPL测试与串口协议用或友好 REPL交互用。架构相关的配置开关mpconfigport.h 根据编译时的架构宏自动启用对应的原生代码生成器native emitterARMv7ThumbMICROPY_EMIT_THUMB、MICROPY_EMIT_INLINE_THUMBMPS2_AN385默认QEMU_SOC_NRF51即MICROBIT板除外RISC-V 32MICROPY_EMIT_RV32并启用ZBA、ZCMP扩展及内联汇编MICROPY_EMIT_INLINE_RV32RISC-V 64MICROPY_PERSISTENT_CODE_LOAD_NATIVE64 位可加载原生.mpyPowerPC 64通过MICROPY_MAKE_POINTER_CALLABLE处理函数指针。同时该文件还启用了MICROPY_VFS_ROM只读 ROM 文件系统配合 ROMFS 分区使用、MICROPY_PY_MACHINEmachine 模块等特性并将MICROPY_PY_SYS_PLATFORM设为qemu。UART 驱动一套接口、多种 SoCuart.c 是移植中最能体现“架构抽象”的文件对外只暴露uart_init()、uart_rx_chr()、uart_rx_any()、uart_tx_strn()四个函数内部则按QEMU_SOC_*宏为不同模拟 SoC 提供不同的寄存器级实现QEMU_SOC_STM32NETDUINO2STM32 风格 UART基址0x40011000QEMU_SOC_NRF51MICROBITnRF51 UART基址0x40002000通过事件寄存器RXDRDY轮询QEMU_SOC_MPS2/QEMU_SOC_MPS3MPS2_AN385 / MPS2_AN500 / MPS3_AN547Cortex-M 系统设计套件 UART基址0x40004000/0x49303000发送时轮询STATE.TXFULL位QEMU_SOC_IMX6SABRELITEi.MX6 UART基址0x02020000QEMU_SOC_VIRTVIRT_RV32 / VIRT_RV64与QEMU_SOC_POWERNVPOWERNV916550 兼容 UART基址0x10000000/ PowerNV 特有地址。网络支持可选通过 lan9118.c、network_lan.c 与 mpnetworkport.c 实现 LAN9118 以太网控制器的模拟驱动。当板卡启用MICROPY_HW_ETH_LAN9118时SABRELITE 等会自动拉起 lwIP 协议栈MICROPY_PY_LWIP提供network.LAN接口与 socket 模块默认主机名为mpy-qemu见 mpconfigport.h。七、冻结模块与原生测试样本构建时会通过FROZEN_MANIFEST冻结一组测试模块Makefile 按架构区分ARM除 MICROBITfrozen_asm_thumb.py、frozen_const.py、frozen_viper.py、native_frozen_align.pyMICROBIT / riscv32 / riscv64 / ppc64对应的frozen_asm_rv32.py或仅frozen_const.py。这些文件位于 test-frzmpy 目录分别用于验证 Thumb 内联汇编、RV32 内联汇编、viper 模式、原生冻结对齐等架构相关特性在仿真环境中的正确性是 CI 架构覆盖的重要一环。八、适用前提与限制实验性质README 明确标注本移植为 “experimental, community-supported”适合测试、实验与调试不代表对目标板卡硬件的完整支持工具链门槛RISC-V 64 工具链的-mcmodelmedany约束是构建失败的最常见原因建议直接使用仓库提供的 Docker 镜像规避外设覆盖有限UART、可选以太网与 ROMFS 是主要外设抽象真实芯片的中断、GPIO 等能力并不在仿真范围内无 JTAG/OpenOCD 需求这是本移植的卖点而非缺陷——调试通过QEMU_DEBUG1配合 gdb默认 TCP 1234即可完成。对希望验证 MicroPython 架构后端Thumb/RV32/RV64 原生代码生成、跑官方测试套件或在无硬件环境下做原型实验的开发者来说ports/qemu是目前仓库中成本最低、覆盖最广的入口。赞分享嵌入式语言运行时编程语言解释器编译器物联网系统编程【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址https://gitcode.com/gh_mirrors/mi/micropython点击查看免费下载相关推荐跨架构容器终极指南QEMU仿真与binfmt_misc完美解决方案跨架构容器终极指南QEMU仿真与binfmt_misc完美解决方案 在当今多架构计算环境中容器技术的跨平台运行已成为开发者和运维人员的迫切需求。multia开发工具虚拟化Zephyr 中的 ESP32-S3-DevKitC硬件特性、构建烧录、QEMU 仿真与 OpenOCD 调试实战Zephyr 中的 ESP32 S3 DevKitC硬件特性、构建烧录、QEMU 仿真与 OpenOCD 调试实战 ESP32 S3 DevKitC 是乐鑫操作系统嵌入式RTOS物联网Pwndbg 跨架构测试指南从 qemu-user 用户态调试到 qemu-system 全系统模拟Pwndbg 跨架构测试指南从 qemu user 用户态调试到 qemu system 全系统模拟 Pwndbg 的日常开发与测试大多运行在 x86_64逆向工程调试器应用安全开发工具上一篇终极SDAutoLayout布局约束复用指南5个实用技巧提升iOS开发效率下一篇Claude Code 终端代理编程工具快速上手与避坑指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考