Add functional Raspberry Pi Pico tests covering synthetic ROM startup, UART output, flash persistence, UF2 loading, DMA/UART paths, dual-core startup, flash helper shortcuts, random source configuration and selected Pico SDK-style workloads.
Signed-off-by: Gilles Grimaud <[email protected]> --- tests/functional/arm/meson.build | 2 + tests/functional/arm/test_raspi_pico.py | 1289 +++++++++++++++++++++++ 2 files changed, 1291 insertions(+) create mode 100644 tests/functional/arm/test_raspi_pico.py diff --git a/tests/functional/arm/meson.build b/tests/functional/arm/meson.build index 61b00932db..0e3bebd5dc 100644 --- a/tests/functional/arm/meson.build +++ b/tests/functional/arm/meson.build @@ -22,6 +22,7 @@ test_arm_timeouts = { 'cubieboard' : 360, 'orangepi' : 540, 'quanta_gsj' : 240, + 'raspi_pico' : 30, 'raspi2' : 120, 'replay' : 240, 'tuxrun' : 240, @@ -30,6 +31,7 @@ test_arm_timeouts = { tests_arm_system_quick = [ 'migration', + 'raspi_pico', ] tests_arm_system_thorough = [ diff --git a/tests/functional/arm/test_raspi_pico.py b/tests/functional/arm/test_raspi_pico.py new file mode 100644 index 0000000000..c0ddc018b8 --- /dev/null +++ b/tests/functional/arm/test_raspi_pico.py @@ -0,0 +1,1289 @@ +#!/usr/bin/env python3 +# +# Functional test that checks the Raspberry Pi Pico machine. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os +import socket +import struct +import subprocess +import time + +from qemu_test import QemuSystemTest, wait_for_console_pattern + + +class RaspiPicoMachine(QemuSystemTest): + + UF2_MAGIC_START0 = 0x0A324655 + UF2_MAGIC_START1 = 0x9E5D5157 + UF2_MAGIC_END = 0x0AB16F30 + UF2_FLAG_FAMILY_ID_PRESENT = 0x00002000 + RP2040_FAMILY_ID = 0xE48BFF56 + + def set_direct_uart_machine(self): + self.set_machine('raspi-pico') + self.vm.set_machine('raspi-pico,strict-uart-pins=off') + + def pipico_rom(self): + rom = os.getenv('QEMU_TEST_PIPICO_ROM') + if rom: + if os.path.exists(rom): + return rom + self.skipTest(f'QEMU_TEST_PIPICO_ROM does not exist: {rom}') + + rom = os.path.join(os.getcwd(), 'pc-bios', 'pipico.rom') + if os.path.exists(rom): + return rom + + self.skipTest('pipico.rom not available; set QEMU_TEST_PIPICO_ROM') + + # Minimal Cortex-M0+ raw image linked for XIP at 0x10000000. It contains a + # vector table and writes "PICO UART OK\n" to UART0 at 0x40034000. + UART_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x09, 0x00, 0x00, 0x10, + 0x07, 0x48, 0x08, 0x4a, 0x11, 0x78, 0x00, 0x29, + 0x02, 0xd0, 0x01, 0x60, 0x01, 0x32, 0xf9, 0xe7, + 0xfe, 0xe7, 0x50, 0x49, 0x43, 0x4f, 0x20, 0x55, + 0x41, 0x52, 0x54, 0x20, 0x4f, 0x4b, 0x0a, 0x00, + 0x00, 0x40, 0x03, 0x40, 0x1a, 0x00, 0x00, 0x10, + ]) + + # Arms TIMER alarm 0, waits for the NVIC IRQ0 handler to run, then writes + # "TIMER OK\n" to UART0. + TIMER_ALARM_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x45, 0x00, 0x00, 0x10, + 0x6d, 0x00, 0x00, 0x10, 0x6d, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x00, 0x00, 0x10, + 0x14, 0x48, 0x00, 0x21, 0x01, 0x60, 0x14, 0x48, + 0x01, 0x21, 0x01, 0x60, 0x13, 0x4c, 0x61, 0x63, + 0xa1, 0x63, 0xa2, 0x6a, 0x64, 0x23, 0xd2, 0x18, + 0x22, 0x61, 0x0e, 0x48, 0x01, 0x68, 0x00, 0x29, + 0xfb, 0xd0, 0x0f, 0x48, 0x00, 0xf0, 0x07, 0xf8, + 0xfe, 0xe7, 0x0c, 0x48, 0x01, 0x21, 0x41, 0x63, + 0x08, 0x48, 0x01, 0x60, 0x70, 0x47, 0x0b, 0x4a, + 0x01, 0x78, 0x00, 0x29, 0x02, 0xd0, 0x11, 0x60, + 0x01, 0x30, 0xf9, 0xe7, 0x70, 0x47, 0xc0, 0x46, + 0x54, 0x49, 0x4d, 0x45, 0x52, 0x20, 0x4f, 0x4b, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0xe1, + 0x00, 0xe0, 0x00, 0x40, 0x05, 0x40, 0x8c, 0x00, + 0x00, 0x10, 0x00, 0x40, 0x03, 0x40, + ]) + + # Verifies the RP2040 SIO view seen from core 0: CPUID, FIFO ready bit, + # read-on-empty sticky flag and write-one-to-clear behavior. + SIO_FIFO_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x3b, 0x00, 0x00, 0x10, 0x3b, 0x00, 0x00, 0x10, + 0x18, 0x4c, 0x20, 0x68, 0x00, 0x28, 0x10, 0xd1, + 0x20, 0x6d, 0x02, 0x21, 0x08, 0x42, 0x0c, 0xd0, + 0xa0, 0x6d, 0x20, 0x6d, 0x08, 0x21, 0x08, 0x42, + 0x07, 0xd0, 0x21, 0x65, 0x20, 0x6d, 0x08, 0x42, + 0x03, 0xd1, 0x11, 0x48, 0x00, 0xf0, 0x05, 0xf8, + 0xfe, 0xe7, 0x10, 0x48, 0x00, 0xf0, 0x01, 0xf8, + 0xfe, 0xe7, 0x0f, 0x4a, 0x01, 0x78, 0x00, 0x29, + 0x02, 0xd0, 0x11, 0x60, 0x01, 0x30, 0xf9, 0xe7, + 0x70, 0x47, 0xc0, 0x46, 0x53, 0x49, 0x4f, 0x20, + 0x43, 0x4f, 0x52, 0x45, 0x30, 0x20, 0x4f, 0x4b, + 0x0a, 0x00, 0x53, 0x49, 0x4f, 0x20, 0x43, 0x4f, + 0x52, 0x45, 0x30, 0x20, 0x46, 0x41, 0x49, 0x4c, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, + 0x54, 0x00, 0x00, 0x10, 0x62, 0x00, 0x00, 0x10, + 0x00, 0x40, 0x03, 0x40, + ]) + + # Verifies the RP2040 SIO hardware divider: unsigned and signed division, + # division by zero, result save/restore writes, and CSR READY/DIRTY. + SIO_DIVIDER_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x09, 0x00, 0x00, 0x10, + 0x37, 0x4c, 0x64, 0x20, 0x20, 0x66, 0x07, 0x20, + 0x60, 0x66, 0xa0, 0x6f, 0x35, 0x4a, 0x90, 0x42, + 0x00, 0xd0, 0x4b, 0xe0, 0x60, 0x6f, 0x34, 0x4a, + 0x90, 0x42, 0x00, 0xd0, 0x46, 0xe0, 0xa0, 0x6f, + 0x30, 0x4a, 0x90, 0x42, 0x00, 0xd0, 0x41, 0xe0, + 0x20, 0x6f, 0x30, 0x4a, 0x90, 0x42, 0x00, 0xd0, + 0x3c, 0xe0, 0xa0, 0x6f, 0x2e, 0x4a, 0x90, 0x42, + 0x00, 0xd0, 0x37, 0xe0, 0x2d, 0x48, 0xa0, 0x66, + 0x07, 0x20, 0xe0, 0x66, 0x60, 0x6f, 0x2c, 0x4a, + 0x90, 0x42, 0x00, 0xd0, 0x2e, 0xe0, 0x20, 0x6f, + 0x2a, 0x4a, 0x90, 0x42, 0x00, 0xd0, 0x29, 0xe0, + 0x29, 0x48, 0x20, 0x66, 0x00, 0x20, 0x60, 0x66, + 0x60, 0x6f, 0x27, 0x4a, 0x90, 0x42, 0x00, 0xd0, + 0x20, 0xe0, 0x20, 0x6f, 0x25, 0x4a, 0x90, 0x42, + 0x00, 0xd0, 0x1b, 0xe0, 0x24, 0x48, 0x60, 0x67, + 0x24, 0x48, 0x20, 0x67, 0xa0, 0x6f, 0x19, 0x4a, + 0x90, 0x42, 0x00, 0xd0, 0x12, 0xe0, 0x60, 0x6f, + 0x1f, 0x4a, 0x90, 0x42, 0x00, 0xd0, 0x0d, 0xe0, + 0x20, 0x6f, 0x1e, 0x4a, 0x90, 0x42, 0x00, 0xd0, + 0x08, 0xe0, 0xa0, 0x6f, 0x14, 0x4a, 0x90, 0x42, + 0x00, 0xd0, 0x03, 0xe0, 0x1a, 0x48, 0x00, 0xf0, + 0x05, 0xf8, 0xfe, 0xe7, 0x19, 0x48, 0x00, 0xf0, + 0x01, 0xf8, 0xfe, 0xe7, 0x18, 0x4a, 0x01, 0x78, + 0x00, 0x29, 0x02, 0xd0, 0x11, 0x60, 0x01, 0x30, + 0xf9, 0xe7, 0x70, 0x47, 0x53, 0x49, 0x4f, 0x20, + 0x44, 0x49, 0x56, 0x20, 0x4f, 0x4b, 0x0a, 0x00, + 0x53, 0x49, 0x4f, 0x20, 0x44, 0x49, 0x56, 0x20, + 0x46, 0x41, 0x49, 0x4c, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x9c, 0xff, 0xff, 0xff, + 0xfe, 0xff, 0xff, 0xff, 0xf2, 0xff, 0xff, 0xff, + 0x34, 0x12, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xdd, 0xcc, 0xbb, 0xaa, 0x44, 0x33, 0x22, 0x11, + 0xcc, 0x00, 0x00, 0x10, 0xd8, 0x00, 0x00, 0x10, + 0x00, 0x40, 0x03, 0x40, + ]) + + # Verifies the initial PSM PROC1 force-off state, the derived DONE bit, + # and the RP2040 atomic SET/CLR aliases used by the Pico SDK. + PSM_PROC1_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x4b, 0x00, 0x00, 0x10, 0x4b, 0x00, 0x00, 0x10, + 0x19, 0x4c, 0x1a, 0x4d, 0x1a, 0x4e, 0x20, 0x68, + 0x28, 0x42, 0x16, 0xd1, 0x30, 0x68, 0x28, 0x42, + 0x13, 0xd0, 0x18, 0x49, 0x0d, 0x60, 0x20, 0x68, + 0x28, 0x42, 0x0e, 0xd0, 0x30, 0x68, 0x28, 0x42, + 0x0b, 0xd1, 0x15, 0x49, 0x0d, 0x60, 0x20, 0x68, + 0x28, 0x42, 0x06, 0xd1, 0x30, 0x68, 0x28, 0x42, + 0x03, 0xd0, 0x12, 0x48, 0x00, 0xf0, 0x05, 0xf8, + 0xfe, 0xe7, 0x11, 0x48, 0x00, 0xf0, 0x01, 0xf8, + 0xfe, 0xe7, 0x10, 0x4a, 0x01, 0x78, 0x00, 0x29, + 0x02, 0xd0, 0x11, 0x60, 0x01, 0x30, 0xf9, 0xe7, + 0x70, 0x47, 0xc0, 0x46, 0x50, 0x53, 0x4d, 0x20, + 0x4f, 0x4b, 0x0a, 0x00, 0x50, 0x53, 0x4d, 0x20, + 0x46, 0x41, 0x49, 0x4c, 0x0a, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x00, + 0x0c, 0x00, 0x01, 0x40, 0x04, 0x20, 0x01, 0x40, + 0x04, 0x30, 0x01, 0x40, 0x64, 0x00, 0x00, 0x10, + 0x6c, 0x00, 0x00, 0x10, 0x00, 0x40, 0x03, 0x40, + ]) + + # Core 0 sends the Pico SDK multicore_launch_core1_raw() FIFO sequence to + # synthetic ROM on core 1. Core 1 echoes the sequence, jumps to the + # supplied entry point, calls send_ack() using the supplied stack, and + # sends 0xd01e back through FIFO. + CORE1_WORKING_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x55, 0x00, 0x00, 0x10, 0x55, 0x00, 0x00, 0x10, + 0x2f, 0x4c, 0x00, 0x27, 0x06, 0x2f, 0x0b, 0xd0, + 0xb8, 0x00, 0x2e, 0x4e, 0x36, 0x58, 0x30, 0x46, + 0x00, 0xf0, 0x22, 0xf8, 0x00, 0xf0, 0x1a, 0xf8, + 0xb0, 0x42, 0x13, 0xd1, 0x01, 0x37, 0xf1, 0xe7, + 0x00, 0xf0, 0x14, 0xf8, 0x28, 0x49, 0x88, 0x42, + 0x0c, 0xd1, 0x28, 0x48, 0x00, 0xf0, 0x1a, 0xf8, + 0xfe, 0xe7, 0x00, 0xf0, 0x01, 0xf8, 0xfe, 0xe7, + 0x00, 0xb5, 0x21, 0x4c, 0x22, 0x48, 0x00, 0xf0, + 0x0b, 0xf8, 0x00, 0xbd, 0x22, 0x48, 0x00, 0xf0, + 0x0d, 0xf8, 0xfe, 0xe7, 0x20, 0x6d, 0x01, 0x21, + 0x08, 0x42, 0xfb, 0xd0, 0xa0, 0x6d, 0x70, 0x47, + 0x21, 0x6d, 0x02, 0x22, 0x11, 0x42, 0xfb, 0xd0, + 0x60, 0x65, 0x70, 0x47, 0x1b, 0x4a, 0x01, 0x78, + 0x00, 0x29, 0x02, 0xd0, 0x11, 0x60, 0x01, 0x30, + 0xf9, 0xe7, 0x70, 0x47, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x10, 0x04, 0x20, 0x43, 0x00, 0x00, 0x10, + 0x63, 0x6f, 0x72, 0x65, 0x20, 0x30, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, + 0x31, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, + 0x67, 0x20, 0x21, 0x0a, 0x00, 0x43, 0x4f, 0x52, + 0x45, 0x31, 0x20, 0x57, 0x4f, 0x52, 0x4b, 0x49, + 0x4e, 0x47, 0x20, 0x46, 0x41, 0x49, 0x4c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, + 0x84, 0x00, 0x00, 0x10, 0x1e, 0xd0, 0x00, 0x00, + 0x9c, 0x00, 0x00, 0x10, 0xb9, 0x00, 0x00, 0x10, + 0x00, 0x40, 0x03, 0x40, + ]) + + # No-SDK regression derived from the Pico SDK flash_safe_execute smoke + # test. Core 0 launches core 1 through the synthetic ROM FIFO protocol, + # core 1 installs a FIFO IRQ lockout handler, core 0 takes a SIO spinlock, + # locks out core 1, calls the synthetic flash_range_erase/program helpers, + # verifies XIP contents and helper counters, then releases core 1. + FLASH_SAFE_MULTICORE_TEST_BIN = bytes.fromhex( + '00200420010100108b0200108b02001000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '4701001000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '00f03cf800f050f8704800f095f840bf6f4800f0aaf800f050f86e4800f08cf8' + '40bf6d4800f0a1f800f043f86b4800f0a3f8fee76a486b4901606b486b490160' + '62b620bffde71fb4744600f07df85f49884210d15e4800f06ff820bf6448016d' + '01200142f9d000f06ff85a49884202d1594800f061f80fbc01b0204730b55d4c' + '06252068002803d100f066f840bf206800f052f840bf00f057f82168884274d1' + '0434013dedd130bd5348016800296cd07047514800210160704770b54f480021' + '002201231b028154013101329a42fad14b4c4c48606001200003a0600020e060' + '202020614848206048480021002201231b02855cff26b54247d101329a42f8d1' + '404860603d48a06001200002e060404820603e480021002201231b02855c8d42' + '33d1013101329a42f8d1206d01282cd1606d012829d170bd0eb52d490a6d0223' + '1a42fbd048650ebd0eb529490a6d01231a42fbd0886d0ebd0fb525490a6d0123' + '1a4201d0886df9e70fbd10b50446fff7ebffa04209d110bd06b526490278002a' + '02d00a600130f9e706bd2348fff7f4fffee7c046000000000000000001000000' + '000000100010042035010010464c4153482053414645204f4b0a00464c415348' + '2053414645204641494c0a00edfecefa0100cefaefbecefa0200cefaac020010' + '08ed00e00000001000e100e000000100000000d094020010000100d000000020' + '0000ff5f0010100052450000001010105250000000400340bb020010' + ) + + # Similar to FLASH_SAFE_MULTICORE_TEST_BIN, but after locking out core 1 + # in SRAM it starts a page program through the low-level SSI path and + # verifies that an XIP read while the flash is busy raises HardFault. + FLASH_BUSY_LOCKOUT_TEST_BIN = bytes.fromhex( + '0020042001010010e5010010e501001000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + 'e501001000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '664800f066f800f027f800f00ff800f02ef8634800f03df840bf624800f052f8' + '614800f056f800f027f85be030b55f4c06252068002803d100f03bf840bf2068' + '00f027f840bf00f02cf82168884249d10434013dedd130bd55485649564a9042' + '04d203680b6004300431f8e7704753480168002936d0704751485249524a9042' + '04d203680b6004300431f8e74d48013000470eb54d490a6d02231a42fbd04865' + '0ebd0eb549490a6d01231a42fbd0886d0ebd0fb545490a6d01231a4201d0886d' + 'f9e70fbd10b50446fff7ebffa04209d110bd06b53e490278002a02d00a600130' + 'f9e706bd3b48fff7f4fffee73a483b490160002141603a49314a891a314a8918' + 'c16038483449016037485a210160374c0120a060206106202066002020610120' + '2061022020661020206610202066002020665a202066002020612d4800782d48' + '1f49401a1f49401800f009f8fee72a481b49401a1b49401800f001f8fee71c49' + '0278002a02d00a600130f9e77047c046464c4153482042555359204c4f434b4f' + '5554204f4b0a00464c4153482042555359204e4f204641554c540a00c1040010' + 'edfecefa0100cefad304001064040010fc0200100010002064040010000100d0' + 'ec01001000010020fc020010000000d000400340930400100000002000200420' + '4f02001008ed00e0000200200000001800101010870200107002001000100420' + '0111002000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000013110020' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000012481349' + '016013481349016062b620bffde71fb4744600f012f81049884204d10f4800f0' + '05f820bffde70fbc01b020470c490a6d02231a42fbd04865704709490a6d0123' + '1a42fbd0886d704708ed00e00010002000e100e000000100edfecefa0100cefa' + '000000d0000000000000000001000000001000200010042001110020464c4153' + '482042555359204c4f434b4f5554204f4b0a00464c4153482042555359204c4f' + '434b4f5554204641494c0a00464c4153482042555359204e4f204641554c540a' + '00464c41534820425553592053544152540a00464c4153482042555359204c4f' + '434b45440a00c046' + ) + + # Calls synthetic boot ROM helpers through the RP2040 rom_table_lookup() + # ABI and verifies bit, byte-memory, and word-memory helper results. + BOOTROM_HELPERS_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x09, 0x00, 0x00, 0x10, + 0x00, 0xf0, 0x11, 0xf8, 0x00, 0x28, 0x03, 0xd1, + 0x48, 0x48, 0x00, 0xf0, 0x70, 0xf8, 0xfe, 0xe7, + 0x47, 0x48, 0x00, 0xf0, 0x6c, 0xf8, 0xfe, 0xe7, + 0x10, 0xb5, 0x46, 0x48, 0x00, 0x88, 0x46, 0x4b, + 0x1b, 0x88, 0x98, 0x47, 0x10, 0xbd, 0x30, 0xb5, + 0x44, 0x49, 0xff, 0xf7, 0xf5, 0xff, 0x04, 0x46, + 0x43, 0x48, 0xa0, 0x47, 0x10, 0x28, 0x58, 0xd1, + 0x42, 0x49, 0xff, 0xf7, 0xed, 0xff, 0x04, 0x46, + 0x41, 0x48, 0xa0, 0x47, 0x08, 0x28, 0x50, 0xd1, + 0x40, 0x49, 0xff, 0xf7, 0xe5, 0xff, 0x04, 0x46, + 0x3f, 0x48, 0xa0, 0x47, 0x0f, 0x28, 0x48, 0xd1, + 0x3e, 0x49, 0xff, 0xf7, 0xdd, 0xff, 0x04, 0x46, + 0x3d, 0x48, 0xa0, 0x47, 0x3c, 0x49, 0x88, 0x42, + 0x3f, 0xd1, 0x3c, 0x49, 0xff, 0xf7, 0xd4, 0xff, + 0x04, 0x46, 0x3b, 0x48, 0x5a, 0x21, 0x04, 0x22, + 0xa0, 0x47, 0x39, 0x4d, 0x28, 0x78, 0x5a, 0x28, + 0x33, 0xd1, 0xe8, 0x78, 0x5a, 0x28, 0x30, 0xd1, + 0x36, 0x49, 0xff, 0xf7, 0xc5, 0xff, 0x04, 0x46, + 0x35, 0x4d, 0x36, 0x48, 0x28, 0x60, 0x36, 0x48, + 0x29, 0x46, 0x04, 0x22, 0xa0, 0x47, 0x33, 0x49, + 0x00, 0x68, 0x88, 0x42, 0x21, 0xd1, 0x33, 0x49, + 0xff, 0xf7, 0xb6, 0xff, 0x04, 0x46, 0x32, 0x48, + 0x32, 0x49, 0x02, 0x22, 0xa0, 0x47, 0x30, 0x4d, + 0x28, 0x68, 0x88, 0x42, 0x15, 0xd1, 0x68, 0x68, + 0x88, 0x42, 0x12, 0xd1, 0x2e, 0x49, 0xff, 0xf7, + 0xa7, 0xff, 0x04, 0x46, 0x2d, 0x4d, 0x2e, 0x48, + 0x28, 0x60, 0x2e, 0x48, 0x68, 0x60, 0x2e, 0x48, + 0x29, 0x46, 0x02, 0x22, 0xa0, 0x47, 0x2a, 0x49, + 0x00, 0x68, 0x88, 0x42, 0x01, 0xd1, 0x00, 0x20, + 0x30, 0xbd, 0x01, 0x20, 0x30, 0xbd, 0x29, 0x4a, + 0x01, 0x78, 0x00, 0x29, 0x02, 0xd0, 0x11, 0x60, + 0x01, 0x30, 0xf9, 0xe7, 0x70, 0x47, 0xc0, 0x46, + 0x42, 0x4f, 0x4f, 0x54, 0x52, 0x4f, 0x4d, 0x20, + 0x48, 0x45, 0x4c, 0x50, 0x45, 0x52, 0x53, 0x20, + 0x4f, 0x4b, 0x0a, 0x00, 0x42, 0x4f, 0x4f, 0x54, + 0x52, 0x4f, 0x4d, 0x20, 0x48, 0x45, 0x4c, 0x50, + 0x45, 0x52, 0x53, 0x20, 0x46, 0x41, 0x49, 0x4c, + 0x0a, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x10, + 0x1c, 0x01, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x50, 0x33, 0x00, 0x00, + 0x0f, 0xf0, 0xf0, 0xf0, 0x4c, 0x33, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x00, 0x54, 0x33, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x52, 0x33, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x4d, 0x53, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x4d, 0x43, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x20, 0x44, 0x33, 0x22, 0x11, + 0x20, 0x00, 0x00, 0x20, 0x53, 0x34, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x20, 0x5a, 0x5a, 0xa5, 0xa5, + 0x43, 0x34, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, + 0x88, 0x77, 0x66, 0x55, 0xcc, 0xbb, 0xaa, 0x99, + 0x50, 0x00, 0x00, 0x20, 0x00, 0x40, 0x03, 0x40, + ]) + + # Calls synthetic RP2040 boot ROM SF/SD table helpers directly and checks + # representative single/double arithmetic and conversion results. + BOOTROM_FLOAT_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x09, 0x00, 0x00, 0x10, + 0x4a, 0x4c, 0x23, 0x78, 0x65, 0x78, 0x2d, 0x02, + 0x2b, 0x43, 0xa5, 0x78, 0x2d, 0x04, 0x2b, 0x43, + 0xe5, 0x78, 0x2d, 0x06, 0x2b, 0x43, 0x1c, 0x46, + 0x45, 0x48, 0x46, 0x49, 0xa0, 0x47, 0x46, 0x4a, + 0x90, 0x42, 0x62, 0xd1, 0x45, 0x4c, 0x23, 0x78, + 0x65, 0x78, 0x2d, 0x02, 0x2b, 0x43, 0xa5, 0x78, + 0x2d, 0x04, 0x2b, 0x43, 0xe5, 0x78, 0x2d, 0x06, + 0x2b, 0x43, 0x1c, 0x46, 0x3e, 0x48, 0x40, 0x49, + 0xa0, 0x47, 0x40, 0x4a, 0x90, 0x42, 0x50, 0xd1, + 0x3f, 0x4c, 0x23, 0x78, 0x65, 0x78, 0x2d, 0x02, + 0x2b, 0x43, 0xa5, 0x78, 0x2d, 0x04, 0x2b, 0x43, + 0xe5, 0x78, 0x2d, 0x06, 0x2b, 0x43, 0x1c, 0x46, + 0x38, 0x48, 0x3a, 0x49, 0xa0, 0x47, 0x33, 0x4a, + 0x90, 0x42, 0x3e, 0xd1, 0x38, 0x4c, 0x23, 0x78, + 0x65, 0x78, 0x2d, 0x02, 0x2b, 0x43, 0xa5, 0x78, + 0x2d, 0x04, 0x2b, 0x43, 0xe5, 0x78, 0x2d, 0x06, + 0x2b, 0x43, 0x1c, 0x46, 0x2a, 0x48, 0xa0, 0x47, + 0x00, 0x28, 0x2e, 0xd1, 0x31, 0x4a, 0x91, 0x42, + 0x2b, 0xd1, 0x31, 0x4c, 0x23, 0x78, 0x65, 0x78, + 0x2d, 0x02, 0x2b, 0x43, 0xa5, 0x78, 0x2d, 0x04, + 0x2b, 0x43, 0xe5, 0x78, 0x2d, 0x06, 0x2b, 0x43, + 0x1c, 0x46, 0x00, 0x20, 0x2b, 0x49, 0x00, 0x22, + 0x2b, 0x4b, 0xa0, 0x47, 0x00, 0x28, 0x18, 0xd1, + 0x2a, 0x4a, 0x91, 0x42, 0x15, 0xd1, 0x2a, 0x4c, + 0x23, 0x78, 0x65, 0x78, 0x2d, 0x02, 0x2b, 0x43, + 0xa5, 0x78, 0x2d, 0x04, 0x2b, 0x43, 0xe5, 0x78, + 0x2d, 0x06, 0x2b, 0x43, 0x1c, 0x46, 0x00, 0x20, + 0x20, 0x49, 0xa0, 0x47, 0x23, 0x4a, 0x90, 0x42, + 0x03, 0xd1, 0x23, 0x48, 0x00, 0xf0, 0x05, 0xf8, + 0xfe, 0xe7, 0x22, 0x48, 0x00, 0xf0, 0x01, 0xf8, + 0xfe, 0xe7, 0x21, 0x4a, 0x01, 0x78, 0x00, 0x29, + 0x02, 0xd0, 0x11, 0x60, 0x01, 0x30, 0xf9, 0xe7, + 0x70, 0x47, 0xc0, 0x46, 0x42, 0x4f, 0x4f, 0x54, + 0x52, 0x4f, 0x4d, 0x20, 0x46, 0x4c, 0x4f, 0x41, + 0x54, 0x20, 0x4f, 0x4b, 0x0a, 0x00, 0x42, 0x4f, + 0x4f, 0x54, 0x52, 0x4f, 0x4d, 0x20, 0x46, 0x4c, + 0x4f, 0x41, 0x54, 0x20, 0x46, 0x41, 0x49, 0x4c, + 0x0a, 0x00, 0x00, 0x00, 0xc2, 0x03, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x3f, 0x00, 0x00, 0x20, 0x40, + 0x00, 0x00, 0x70, 0x40, 0xca, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xf0, 0x40, + 0xce, 0x03, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, + 0x3e, 0x04, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x3f, + 0x62, 0x04, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, + 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x16, 0x40, + 0xde, 0x04, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, + 0x0c, 0x01, 0x00, 0x10, 0x1e, 0x01, 0x00, 0x10, + 0x00, 0x40, 0x03, 0x40, + ]) + + # Exercises DMA channel 0 as a synchronous memory copy engine, then as a + # fill engine by keeping READ_ADDR fixed and incrementing WRITE_ADDR. + DMA_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x95, 0x00, 0x00, 0x10, 0x95, 0x00, 0x00, 0x10, + 0x2e, 0x4c, 0x2f, 0x4d, 0x01, 0x23, 0x9b, 0x02, + 0x1b, 0x19, 0x2e, 0x48, 0x28, 0x60, 0x2e, 0x48, + 0x68, 0x60, 0x01, 0x20, 0x00, 0x03, 0x18, 0x60, + 0x25, 0x60, 0x10, 0x20, 0x40, 0x19, 0x60, 0x60, + 0x02, 0x20, 0xa0, 0x60, 0x29, 0x48, 0xe0, 0x60, + 0x28, 0x69, 0x26, 0x49, 0x88, 0x42, 0x25, 0xd1, + 0x68, 0x69, 0x25, 0x49, 0x88, 0x42, 0x21, 0xd1, + 0x18, 0x68, 0x01, 0x21, 0x08, 0x42, 0x1d, 0xd0, + 0x19, 0x60, 0x18, 0x68, 0x08, 0x42, 0x19, 0xd1, + 0x21, 0x48, 0x28, 0x62, 0x20, 0x20, 0x40, 0x19, + 0x20, 0x60, 0x30, 0x20, 0x40, 0x19, 0x60, 0x60, + 0x03, 0x20, 0xa0, 0x60, 0x1d, 0x48, 0xe0, 0x60, + 0x1b, 0x49, 0x28, 0x6b, 0x88, 0x42, 0x09, 0xd1, + 0x68, 0x6b, 0x88, 0x42, 0x06, 0xd1, 0xa8, 0x6b, + 0x88, 0x42, 0x03, 0xd1, 0x18, 0x48, 0x00, 0xf0, + 0x09, 0xf8, 0xfe, 0xe7, 0x17, 0x48, 0x00, 0xf0, + 0x05, 0xf8, 0xfa, 0xe7, 0x16, 0x48, 0x00, 0xf0, + 0x01, 0xf8, 0xf6, 0xe7, 0x15, 0x4a, 0x01, 0x78, + 0x00, 0x29, 0x02, 0xd0, 0x11, 0x60, 0x01, 0x30, + 0xf9, 0xe7, 0x70, 0x47, 0x44, 0x4d, 0x41, 0x20, + 0x4f, 0x4b, 0x0a, 0x00, 0x44, 0x4d, 0x41, 0x20, + 0x46, 0x41, 0x49, 0x4c, 0x0a, 0x00, 0x44, 0x4d, + 0x41, 0x20, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x20, 0x44, 0x33, 0x22, 0x11, + 0xdd, 0xcc, 0xbb, 0xaa, 0x39, 0x80, 0x1f, 0x00, + 0xaa, 0x55, 0xaa, 0x55, 0x29, 0x80, 0x1f, 0x00, + 0xac, 0x00, 0x00, 0x10, 0xb4, 0x00, 0x00, 0x10, + 0xbe, 0x00, 0x00, 0x10, 0x00, 0x40, 0x03, 0x40, + ]) + + # Exercises UART0 paced DMA. Channel 0 first sends a trace string through + # UART0 TX DREQ and waits for DMA IRQ0. It then receives "HELLO" through + # UART0 RX DREQ, waits for DMA IRQ0 again, verifies the bytes in SRAM, and + # sends the success string through UART0 TX DREQ. + DMA_UART_TEST_BIN = bytes.fromhex( + '0020042071000010350100103501001000000000000000000000000000000000' + '0000000000000000000000003501001000000000000000003501001035010010' + '3501001035010010350100103501001035010010350100103501001035010010' + '3501001035010010350100102901001072b63d481021c1623c49016303218164' + '3b493c480022d24302603b4802603b48016062b63a480f2100f019f839480521' + '00f023f837483849052203780c78a34208d101300131013af7d134480c2100f0' + '06f837e032480e2100f001f832e010b50c4600f018f82f4a1060234b53609460' + '2d4bd36000f018f810bd10b50c4600f00af8284a1c4b136050609460274bd360' + '00f00af810bd264a00231360254a01231360254a13607047214a136801242342' + '01d130bff9d070471e48016801601c480160704730bffde7444d412055415254' + '2054524143450a48454c4c4f444d412055415254204f4b0a444d412055415254' + '204641494c0a000000400340010300000008000080e100e080e200e000e100e0' + '3801001010000020470100104c010010580100100000005011000a0021800a00' + '000000200004005004040050' + ) + + # Same UART paced DMA test as DMA_UART_TEST_BIN, but using UART1 at + # 0x40038000 and DREQ_UART1_TX/RX. + DMA_UART1_TEST_BIN = bytes.fromhex( + '0020042071000010350100103501001000000000000000000000000000000000' + '0000000000000000000000003501001000000000000000003501001035010010' + '3501001035010010350100103501001035010010350100103501001035010010' + '3501001035010010350100102901001072b63e481021c1623d49016303218164' + '3c493d480022d24302603c4802603c48016062b63b48102100f019f83a480521' + '00f023f838483949052203780c78a34208d101300131013af7d135480d2100f0' + '06f837e033480f2100f001f832e010b50c4600f018f8304a1060244b53609460' + '2e4bd36000f018f810bd10b50c4600f00af8294a1d4b136050609460284bd360' + '00f00af810bd274a00231360264a01231360264a13607047224a136801242342' + '01d130bff9d070471f48016801601d480160704730bffde7444d412055415254' + '312054524143450a48454c4c4f444d41205541525431204f4b0a444d41205541' + '525431204641494c0a00000000800340010300000008000080e100e080e200e0' + '00e100e03801001010000020480100104d0100105a0100100000005011000b00' + '21800b00000000200004005004040050' + ) + + BOOT2_W25Q080_BIN = bytes.fromhex( + '00b5324b212058609868022188439860' + 'd860186158612e4b0021996002215961' + '0121f02299502b491960012199603520' + '00f044f80222904214d00621196600f0' + '34f8196e01211966002018661a6600f0' + '2cf8196e196e196e052000f02ff80121' + '0842f9d1002199601b49196000215960' + '1a491b48016001219960eb211966a021' + '196600f012f800219960164914480160' + '0121996001bc002800d0004712481349' + '086003c880f30888084703b5996a0420' + '0142fbd001200142f8d103bd02b51866' + '1866fff7f2ff186e186e02bd00000240' + '000000180000070000035f0021220000' + 'f4000018222000a00001001008ed00e0' + '00000000000000000000000074b24e7a' + ) + + @staticmethod + def make_xip_elf(payload): + return RaspiPicoMachine.make_xip_elf_with_phdrs(payload, ()) + + @staticmethod + def make_xip_elf_with_phdrs(payload, extra_phdrs): + load_addr = 0x10000000 + payload_off = 0x100 + phnum = 1 + len(extra_phdrs) + + elf_header = struct.pack( + '<16sHHIIIIIHHHHHH', + b'\x7fELF\x01\x01\x01' + b'\x00' * 9, + 2, # ET_EXEC + 40, # EM_ARM + 1, # EV_CURRENT + load_addr, + 52, # e_phoff + 0, # e_shoff + 0x05000200, # EABI version 5, soft-float + 52, # e_ehsize + 32, # e_phentsize + phnum, + 0, + 0, + 0, + ) + phdr = struct.pack( + '<IIIIIIII', + 1, # PT_LOAD + payload_off, + load_addr, + load_addr, + len(payload), + len(payload), + 5, # PF_R | PF_X + 4, + ) + + phdrs = phdr + b''.join(extra_phdrs) + padding = bytes(payload_off - 52 - len(phdrs)) + return elf_header + phdrs + padding + payload + + @classmethod + def make_xip_elf_with_empty_sram_load(cls, payload): + sram_phdr = struct.pack( + '<IIIIIIII', + 1, # PT_LOAD + 0, # p_offset is ignored when p_filesz is zero + 0x20000000, + 0x20000000, + 0, + 0x1000, + 6, # PF_R | PF_W + 4, + ) + return cls.make_xip_elf_with_phdrs(payload, (sram_phdr,)) + + @classmethod + def make_uf2(cls, payload, target=0x10000000): + payload_size = len(payload) + block = bytearray(512) + + if payload_size > 476: + raise ValueError('single-block test UF2 payload is too large') + + struct.pack_into( + '<IIIIIIII', + block, + 0, + cls.UF2_MAGIC_START0, + cls.UF2_MAGIC_START1, + cls.UF2_FLAG_FAMILY_ID_PRESENT, + target, + payload_size, + 0, + 1, + cls.RP2040_FAMILY_ID, + ) + block[32:32 + payload_size] = payload + struct.pack_into('<I', block, 512 - 4, cls.UF2_MAGIC_END) + + return bytes(block) + + @classmethod + def make_bootable_uart_uf2(cls): + return cls.make_uf2(cls.make_bootable_image(cls.UART_TEST_BIN)) + + @classmethod + def make_bootable_uart_elf(cls): + return cls.make_xip_elf(cls.make_bootable_image(cls.UART_TEST_BIN)) + + @staticmethod + def relocate_xip_payload(payload): + relocated = bytearray(payload) + payload_end = 0x10000000 + len(payload) + + for off in range(0, len(relocated) - 3, 4): + value = struct.unpack_from('<I', relocated, off)[0] + if 0x10000000 <= value <= payload_end: + struct.pack_into('<I', relocated, off, value + 0x100) + + return bytes(relocated) + + @classmethod + def make_bootable_image(cls, payload): + return cls.BOOT2_W25Q080_BIN + cls.relocate_xip_payload(payload) + + # Copies a small routine to SRAM, erases/programs flash through the SSI + # registers, polls status once, then verifies the programmed bytes via XIP. + FLASH_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x10, + 0x3c, 0x48, 0x3d, 0x49, 0x3d, 0x4a, 0x91, 0x42, + 0x04, 0xd2, 0x0b, 0x68, 0x03, 0x60, 0x04, 0x31, + 0x04, 0x30, 0xf8, 0xe7, 0x3a, 0x48, 0x00, 0x47, + 0xfe, 0xe7, 0xc0, 0x46, 0x00, 0xf0, 0x44, 0xf8, + 0x38, 0x4c, 0x39, 0x4d, 0x01, 0x20, 0x20, 0x60, + 0x20, 0x20, 0x28, 0x60, 0x00, 0x20, 0x28, 0x60, + 0x10, 0x20, 0x28, 0x60, 0x00, 0x20, 0x28, 0x60, + 0x00, 0x20, 0x20, 0x60, 0x00, 0xf0, 0x3d, 0xf8, + 0x00, 0xf0, 0x32, 0xf8, 0x2f, 0x4c, 0x30, 0x4d, + 0x01, 0x20, 0x20, 0x60, 0x02, 0x20, 0x28, 0x60, + 0x00, 0x20, 0x28, 0x60, 0x10, 0x20, 0x28, 0x60, + 0x00, 0x20, 0x28, 0x60, 0x46, 0x20, 0x28, 0x60, + 0x4c, 0x20, 0x28, 0x60, 0x41, 0x20, 0x28, 0x60, + 0x53, 0x20, 0x28, 0x60, 0x48, 0x20, 0x28, 0x60, + 0x00, 0x20, 0x20, 0x60, 0x00, 0xf0, 0x21, 0xf8, + 0x24, 0x49, 0x08, 0x78, 0x46, 0x28, 0x0f, 0xd1, + 0x48, 0x78, 0x4c, 0x28, 0x0c, 0xd1, 0x88, 0x78, + 0x41, 0x28, 0x09, 0xd1, 0xc8, 0x78, 0x53, 0x28, + 0x06, 0xd1, 0x08, 0x79, 0x48, 0x28, 0x03, 0xd1, + 0x1d, 0x48, 0x00, 0xf0, 0x18, 0xf8, 0xfe, 0xe7, + 0x1c, 0x48, 0x00, 0xf0, 0x14, 0xf8, 0xfe, 0xe7, + 0x16, 0x4c, 0x17, 0x4d, 0x01, 0x20, 0x20, 0x60, + 0x06, 0x20, 0x28, 0x60, 0x00, 0x20, 0x20, 0x60, + 0x70, 0x47, 0x12, 0x4c, 0x12, 0x4d, 0x01, 0x20, + 0x20, 0x60, 0x05, 0x20, 0x28, 0x60, 0x28, 0x68, + 0x00, 0x20, 0x20, 0x60, 0x70, 0x47, 0x12, 0x4a, + 0x01, 0x78, 0x00, 0x29, 0x02, 0xd0, 0x11, 0x60, + 0x01, 0x30, 0xf9, 0xe7, 0x70, 0x47, 0x46, 0x4c, + 0x41, 0x53, 0x48, 0x20, 0x4f, 0x4b, 0x0a, 0x00, + 0x46, 0x4c, 0x41, 0x53, 0x48, 0x20, 0x46, 0x41, + 0x49, 0x4c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x2c, 0x00, 0x00, 0x10, 0x2c, 0x01, 0x00, 0x10, + 0x01, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x18, + 0x60, 0x00, 0x00, 0x18, 0x00, 0x10, 0x00, 0x10, + 0xee, 0x00, 0x00, 0x10, 0xf8, 0x00, 0x00, 0x10, + 0x00, 0x40, 0x03, 0x40, + ]) + + # Copies a small routine to SRAM, then exercises the ROM-style flash + # command path: QSPI chip select is forced through IO_QSPI, bytes are + # exchanged through the XIP SSI data register, and the result is verified + # through the XIP flash window. + FLASH_IOQSPI_CS_TEST_BIN = bytes.fromhex( + '00200420090000104f485049504a914204d20b68036004310430f8e74a480130' + '0047c0464b4c002020604b4c4b4820604b4c01202060474c206000f047f800f0' + '5ff8202000f054f8002000f051f8102000f04ef8002000f04bf800f056f800f0' + '3ef800f033f800f04bf8022000f040f8002000f03df8102000f03af8002000f0' + '37f8512000f034f8532000f031f8502000f02ef8492000f02bf800f036f800f0' + '1ef83049087851280cd14878532809d18878502806d1c878492803d12a4800f0' + '29f8fee7294800f025f8fee700b500f017f8062000f00cf800f017f800bd00b5' + '00f00ef8052000f003f800f00ef800bd1f4a10601f4b18680028fcd010687047' + '1d4902200002086070471b490320000208607047194a0178002902d011600130' + 'f9e77047494f5153504920464c415348204f4b0a00494f5153504920464c4153' + '48204641494c0a00000000202400001080010010080000180000001800000700' + '1000001800100010240100103501001060000018240000180c80014000400340' + ) + + # Attempts a page program without write enable, then verifies the target + # byte is still in the erased state. + FLASH_NO_WEL_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, + 0x1e, 0x48, 0x1f, 0x49, 0x1f, 0x4a, 0x91, 0x42, + 0x04, 0xd2, 0x0b, 0x68, 0x03, 0x60, 0x04, 0x31, + 0x04, 0x30, 0xf8, 0xe7, 0x19, 0x48, 0x01, 0x30, + 0x00, 0x47, 0xc0, 0x46, 0x1a, 0x4c, 0x1b, 0x4d, + 0x01, 0x20, 0x20, 0x61, 0x02, 0x20, 0x28, 0x60, + 0x00, 0x20, 0x28, 0x60, 0x10, 0x20, 0x28, 0x60, + 0x00, 0x20, 0x28, 0x60, 0xa5, 0x20, 0x28, 0x60, + 0x00, 0x20, 0x20, 0x61, 0x14, 0x49, 0x08, 0x78, + 0xff, 0x28, 0x03, 0xd1, 0x13, 0x48, 0x00, 0xf0, + 0x05, 0xf8, 0xfe, 0xe7, 0x12, 0x48, 0x00, 0xf0, + 0x01, 0xf8, 0xfe, 0xe7, 0x11, 0x4a, 0x01, 0x78, + 0x00, 0x29, 0x02, 0xd0, 0x11, 0x60, 0x01, 0x30, + 0xf9, 0xe7, 0x70, 0x47, 0x4e, 0x4f, 0x20, 0x57, + 0x45, 0x4c, 0x20, 0x4f, 0x4b, 0x0a, 0x00, 0x4e, + 0x4f, 0x20, 0x57, 0x45, 0x4c, 0x20, 0x46, 0x41, + 0x49, 0x4c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x2c, 0x00, 0x00, 0x10, 0xb0, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x18, 0x60, 0x00, 0x00, 0x18, + 0x00, 0x10, 0x00, 0x10, 0x74, 0x00, 0x00, 0x10, + 0x7f, 0x00, 0x00, 0x10, 0x00, 0x40, 0x03, 0x40, + ]) + + # Programs 0x00, then attempts to program 0xff without erase and verifies + # that NOR semantics preserve the old & new result. + FLASH_OLD_AND_NEW_TEST_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, + 0x30, 0x48, 0x31, 0x49, 0x31, 0x4a, 0x91, 0x42, + 0x04, 0xd2, 0x0b, 0x68, 0x03, 0x60, 0x04, 0x31, + 0x04, 0x30, 0xf8, 0xe7, 0x2b, 0x48, 0x01, 0x30, + 0x00, 0x47, 0xc0, 0x46, 0x00, 0xf0, 0x18, 0xf8, + 0x00, 0x20, 0x00, 0xf0, 0x24, 0xf8, 0x00, 0xf0, + 0x1a, 0xf8, 0x00, 0xf0, 0x11, 0xf8, 0xff, 0x20, + 0x00, 0xf0, 0x1d, 0xf8, 0x00, 0xf0, 0x13, 0xf8, + 0x25, 0x49, 0x08, 0x78, 0x00, 0x28, 0x03, 0xd1, + 0x24, 0x48, 0x00, 0xf0, 0x25, 0xf8, 0xfe, 0xe7, + 0x23, 0x48, 0x00, 0xf0, 0x21, 0xf8, 0xfe, 0xe7, + 0x22, 0x4c, 0x23, 0x4d, 0x01, 0x20, 0x20, 0x61, + 0x06, 0x20, 0x28, 0x60, 0x70, 0x47, 0x1f, 0x4c, + 0x1f, 0x4d, 0x01, 0x20, 0x20, 0x61, 0x05, 0x20, + 0x28, 0x60, 0x28, 0x68, 0x70, 0x47, 0x1b, 0x4c, + 0x1b, 0x4d, 0x06, 0x46, 0x01, 0x20, 0x20, 0x61, + 0x02, 0x20, 0x28, 0x60, 0x00, 0x20, 0x28, 0x60, + 0x10, 0x20, 0x28, 0x60, 0x00, 0x20, 0x28, 0x60, + 0x2e, 0x60, 0x00, 0x20, 0x20, 0x61, 0x70, 0x47, + 0x14, 0x4a, 0x01, 0x78, 0x00, 0x29, 0x02, 0xd0, + 0x11, 0x60, 0x01, 0x30, 0xf9, 0xe7, 0x70, 0x47, + 0x4f, 0x4c, 0x44, 0x20, 0x41, 0x4e, 0x44, 0x20, + 0x4e, 0x45, 0x57, 0x20, 0x4f, 0x4b, 0x0a, 0x00, + 0x4f, 0x4c, 0x44, 0x20, 0x41, 0x4e, 0x44, 0x20, + 0x4e, 0x45, 0x57, 0x20, 0x46, 0x41, 0x49, 0x4c, + 0x0a, 0x00, 0xc0, 0x46, 0x00, 0x00, 0x00, 0x20, + 0x2c, 0x00, 0x00, 0x10, 0xf8, 0x00, 0x00, 0x10, + 0x00, 0x10, 0x00, 0x10, 0xb0, 0x00, 0x00, 0x10, + 0xc0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, + 0x60, 0x00, 0x00, 0x18, 0x00, 0x40, 0x03, 0x40, + ]) + + FLASH_PERSIST_READER_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, + 0x16, 0x49, 0x08, 0x78, 0x46, 0x28, 0x0f, 0xd1, + 0x48, 0x78, 0x4c, 0x28, 0x0c, 0xd1, 0x88, 0x78, + 0x41, 0x28, 0x09, 0xd1, 0xc8, 0x78, 0x53, 0x28, + 0x06, 0xd1, 0x08, 0x79, 0x48, 0x28, 0x03, 0xd1, + 0x0f, 0x48, 0x00, 0xf0, 0x05, 0xf8, 0xfe, 0xe7, + 0x0e, 0x48, 0x00, 0xf0, 0x01, 0xf8, 0xfe, 0xe7, + 0x0d, 0x4a, 0x01, 0x78, 0x00, 0x29, 0x02, 0xd0, + 0x11, 0x60, 0x01, 0x30, 0xf9, 0xe7, 0x70, 0x47, + 0x50, 0x45, 0x52, 0x53, 0x49, 0x53, 0x54, 0x20, + 0x4f, 0x4b, 0x0a, 0x00, 0x50, 0x45, 0x52, 0x53, + 0x49, 0x53, 0x54, 0x20, 0x46, 0x41, 0x49, 0x4c, + 0x0a, 0x00, 0xc0, 0x46, 0x00, 0x10, 0x00, 0x10, + 0x50, 0x00, 0x00, 0x10, 0x5c, 0x00, 0x00, 0x10, + 0x00, 0x40, 0x03, 0x40, + ]) + + # Installs a vector table in SRAM, starts a page program, then performs + # an XIP read while the emulated flash is busy. The HardFault handler + # runs from SRAM and prints the expected message. + FLASH_BUSY_HARDFAULT_BIN = bytes([ + 0x00, 0x20, 0x04, 0x20, 0x11, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x10, + 0x2a, 0x48, 0x2b, 0x49, 0x2b, 0x4a, 0x91, 0x42, + 0x04, 0xd2, 0x0b, 0x68, 0x03, 0x60, 0x04, 0x31, + 0x04, 0x30, 0xf8, 0xe7, 0x28, 0x48, 0x00, 0x47, + 0xfe, 0xe7, 0xc0, 0x46, 0x27, 0x48, 0x28, 0x49, + 0x01, 0x60, 0x25, 0x49, 0x41, 0x60, 0x00, 0x21, + 0x81, 0x60, 0x13, 0xa1, 0x01, 0x31, 0xc1, 0x60, + 0x24, 0x4a, 0x10, 0x60, 0x00, 0xf0, 0x16, 0xf8, + 0x23, 0x4c, 0x24, 0x4d, 0x01, 0x20, 0x20, 0x60, + 0x02, 0x20, 0x28, 0x60, 0x00, 0x20, 0x28, 0x60, + 0x10, 0x20, 0x28, 0x60, 0x00, 0x20, 0x28, 0x60, + 0x58, 0x20, 0x28, 0x60, 0x00, 0x20, 0x20, 0x60, + 0x1d, 0x49, 0x08, 0x78, 0x10, 0xa0, 0x00, 0xf0, + 0x0f, 0xf8, 0xfe, 0xe7, 0x18, 0x4c, 0x19, 0x4d, + 0x01, 0x20, 0x20, 0x60, 0x06, 0x20, 0x28, 0x60, + 0x00, 0x20, 0x20, 0x60, 0x70, 0x47, 0xc0, 0x46, + 0x05, 0xa0, 0x00, 0xf0, 0x01, 0xf8, 0xfe, 0xe7, + 0x14, 0x4a, 0x01, 0x78, 0x00, 0x29, 0x02, 0xd0, + 0x11, 0x60, 0x01, 0x30, 0xf9, 0xe7, 0x70, 0x47, + 0x48, 0x41, 0x52, 0x44, 0x46, 0x41, 0x55, 0x4c, + 0x54, 0x20, 0x4f, 0x4b, 0x0a, 0x00, 0xc0, 0x46, + 0x4e, 0x4f, 0x20, 0x46, 0x41, 0x55, 0x4c, 0x54, + 0x0a, 0x00, 0xc0, 0x46, 0x00, 0x00, 0x00, 0x20, + 0x2c, 0x00, 0x00, 0x10, 0xe8, 0x00, 0x00, 0x10, + 0x01, 0x00, 0x00, 0x20, 0x00, 0x01, 0x00, 0x20, + 0x00, 0x20, 0x04, 0x20, 0x08, 0xed, 0x00, 0xe0, + 0x10, 0x00, 0x00, 0x18, 0x60, 0x00, 0x00, 0x18, + 0x00, 0x10, 0x00, 0x10, 0x00, 0x40, 0x03, 0x40, + ]) + + # Starts a page program from SRAM, leaves the flash busy, then branches + # back to XIP on core 0. The expected result is a core 0 HardFault handled + # by the SRAM vector table. + FLASH_BUSY_CORE0_XIP_FAULT_BIN = bytes.fromhex( + '002004200900001038483949394a914204d20b68036004310430f8e733480130' + '0047354800f044f8fee7c0462f483349016005a101314160002181601aa10131' + 'c1602f4a1060c0462e4c002020602e4c2e4820602e4c012020602a4c206000f0' + '15f8022000f017f8002000f014f8202000f011f8002000f00ef85a2000f00bf8' + '234c0020206023480130004700b5062000f001f800bd204a1060204b18680028' + 'fcd010687047c04605a000f001f8fee71b4a0178002902d011600130f9e77047' + '434f5245302058495020484152444641554c54204f4b0a00434f524530205849' + '50204e4f204641554c540a00000000202c00001024010010d800001000200420' + '08ed00e008000018000000180000070010000018220000106000001824000018' + '00400340' + ) + + # Launches core 1 into a small XIP loop through the synthetic ROM FIFO + # protocol. Core 0 then starts a page program from SRAM. The expected + # result is a core 1 HardFault handled by the shared SRAM vector table. + FLASH_BUSY_CORE1_XIP_FAULT_BIN = bytes.fromhex( + '002004200900001056485749574a914204d20b68036004310430f8e751480130' + '0047534800f001f8fee752490a6802231a42fbd0504908607047c04649484f49' + '016004a1013141600021816030a10131c160c046002000f017f8002000f014f8' + '012000f011f83f4800f00ef8444800f00bf8444800f008f800f017f83c498842' + '4ad100f01af8fee710b5044600f005f800f00bf8a0423fd110bd36490a680223' + '1a42fbd034490860704732490a6801231a42fbd034490868704700b5334c0020' + '2060334c33482060334c012020602f4c2060062000f013f8022000f010f80020' + '00f00df8302000f00af8002000f007f8a52000f004f8284c0020206000bd274a' + '1060274b18680028fcd010687047c04607a000f005f8fee70ba000f001f8fee7' + '204a0178002902d011600130f9e77047434f5245312058495020484152444641' + '554c54204f4b0a00434f5245312058495020484152444641554c54204641494c' + '0a00c046000000203c000010a801001001101ec0500000d0540000d000200420' + '0010042023000010580000d00800001800000018000007001000001860000018' + '2400001800400340' + ) + + def test_uart0(self): + self.set_direct_uart_machine() + + image = self.scratch_file('uart-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image(self.UART_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'PICO UART OK') + + def test_uart0_elf(self): + self.set_direct_uart_machine() + + image = self.scratch_file('uart-test.elf') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_uart_elf()) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'PICO UART OK') + + def test_uart0_elf_with_empty_sram_load_segment(self): + self.set_direct_uart_machine() + + image = self.scratch_file('uart-test-empty-sram.elf') + with open(image, 'wb') as image_file: + image_file.write(self.make_xip_elf_with_empty_sram_load( + self.make_bootable_image(self.UART_TEST_BIN))) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'PICO UART OK') + + def test_timer_alarm_irq(self): + self.set_direct_uart_machine() + + image = self.scratch_file('timer-alarm-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.TIMER_ALARM_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'TIMER OK') + + def test_sio_fifo_core0_status(self): + self.set_direct_uart_machine() + + image = self.scratch_file('sio-fifo-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.SIO_FIFO_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'SIO CORE0 OK') + + def test_sio_divider(self): + self.set_direct_uart_machine() + + image = self.scratch_file('sio-divider-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.SIO_DIVIDER_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'SIO DIV OK') + + def test_psm_proc1_force_off(self): + self.set_direct_uart_machine() + + image = self.scratch_file('psm-proc1-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.PSM_PROC1_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'PSM OK') + + def test_core1_rom_launch_ack(self): + self.set_direct_uart_machine() + + image = self.scratch_file('core1-working-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.CORE1_WORKING_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'core 0 and core 1 working !') + + def test_flash_safe_multicore_lockout(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-safe-multicore-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_SAFE_MULTICORE_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'FLASH SAFE OK') + + def test_flash_busy_multicore_lockout_hardfault(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-busy-lockout-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_BUSY_LOCKOUT_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'FLASH BUSY LOCKOUT OK') + + def test_synthetic_bootrom_helpers(self): + self.set_direct_uart_machine() + + image = self.scratch_file('bootrom-helpers-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.BOOTROM_HELPERS_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'BOOTROM HELPERS OK') + + def test_synthetic_bootrom_float_helpers(self): + self.set_direct_uart_machine() + + image = self.scratch_file('bootrom-float-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.BOOTROM_FLOAT_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'BOOTROM FLOAT OK') + + def test_dma_copy_and_fill(self): + self.set_direct_uart_machine() + + image = self.scratch_file('dma-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image(self.DMA_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'DMA OK') + + def test_dma_uart_tx_rx(self): + image = self.scratch_file('dma-uart-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image(self.DMA_UART_TEST_BIN)) + + guest_sock, qemu_sock = socket.socketpair() + os.set_inheritable(qemu_sock.fileno(), True) + qemu = subprocess.Popen([ + self.qemu_bin, + '-machine', 'raspi-pico,strict-uart-pins=off', + '-kernel', image, + '-chardev', f'socket,id=console,fd={qemu_sock.fileno()}', + '-serial', 'chardev:console', + '-display', 'none', + ], cwd=os.path.dirname(os.getenv('MESON_BUILD_ROOT')), + pass_fds=(qemu_sock.fileno(),)) + qemu_sock.close() + guest_sock.settimeout(10) + data = b'' + try: + while b'DMA UART TRACE' not in data: + data += guest_sock.recv(1) + time.sleep(5.0) + guest_sock.sendall(b'HELLO\r') + while b'DMA UART OK' not in data: + data += guest_sock.recv(1) + finally: + qemu.terminate() + qemu.wait(timeout=2) + guest_sock.close() + self.assertIn(b'DMA UART OK', data) + + def test_dma_uart1_tx_rx(self): + image = self.scratch_file('dma-uart1-test.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image(self.DMA_UART1_TEST_BIN)) + + guest_sock, qemu_sock = socket.socketpair() + os.set_inheritable(qemu_sock.fileno(), True) + qemu = subprocess.Popen([ + self.qemu_bin, + '-machine', 'raspi-pico,strict-uart-pins=off', + '-kernel', image, + '-serial', 'null', + '-chardev', f'socket,id=uart1,fd={qemu_sock.fileno()}', + '-serial', 'chardev:uart1', + '-display', 'none', + ], cwd=os.path.dirname(os.getenv('MESON_BUILD_ROOT')), + pass_fds=(qemu_sock.fileno(),)) + qemu_sock.close() + guest_sock.settimeout(10) + data = b'' + try: + while b'DMA UART1 TRACE' not in data: + data += guest_sock.recv(1) + time.sleep(5.0) + guest_sock.sendall(b'HELLO\r') + while b'DMA UART1 OK' not in data: + data += guest_sock.recv(1) + finally: + qemu.terminate() + qemu.wait(timeout=2) + guest_sock.close() + self.assertIn(b'DMA UART1 OK', data) + + def test_flash_file_uart0(self): + flash = self.scratch_file('flash.bin') + with open(flash, 'wb') as flash_file: + flash_file.write(self.make_bootable_image(self.UART_TEST_BIN)) + + self.set_direct_uart_machine() + self.vm.set_machine( + f'raspi-pico,strict-uart-pins=off,flash-file={flash}') + self.vm.set_console() + self.vm.launch() + + wait_for_console_pattern(self, 'PICO UART OK') + + def test_uart0_uf2(self): + uf2 = self.scratch_file('uart-test.uf2') + + with open(uf2, 'wb') as uf2_file: + uf2_file.write(self.make_bootable_uart_uf2()) + + self.set_direct_uart_machine() + self.vm.set_console() + self.vm.add_args('-kernel', uf2) + self.vm.launch() + + wait_for_console_pattern(self, 'PICO UART OK') + + def test_flash_file_uart0_overlayed_by_uf2_kernel(self): + uf2 = self.scratch_file('uart-test.uf2') + flash = self.scratch_file('flash.bin') + + with open(uf2, 'wb') as uf2_file: + uf2_file.write(self.make_bootable_uart_uf2()) + with open(flash, 'wb') as flash_file: + flash_file.write(bytes([0xff]) * 512) + + self.set_direct_uart_machine() + self.vm.set_machine( + f'raspi-pico,strict-uart-pins=off,flash-file={flash}') + self.vm.set_console() + self.vm.add_args('-kernel', uf2) + self.vm.launch() + + wait_for_console_pattern(self, 'PICO UART OK') + + def test_flash_program(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-program.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image(self.FLASH_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'FLASH OK') + + def test_flash_program_with_ioqspi_cs(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-ioqspi-cs.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_IOQSPI_CS_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'IOQSPI FLASH OK') + + def launch_flash_file(self, name, flash, pattern, kernel=None, + extra_args=()): + vm = self.get_vm(name=name) + + vm.set_machine(f'raspi-pico,strict-uart-pins=off,flash-file={flash}') + vm.set_console() + vm.add_args(*extra_args) + if kernel: + vm.add_args('-kernel', kernel) + vm.launch() + wait_for_console_pattern(self, pattern, vm=vm) + vm.shutdown() + + def test_flash_file_kernel_overlay_persists(self): + uf2 = self.scratch_file('uart-test.uf2') + flash = self.scratch_file('flash.bin') + + with open(uf2, 'wb') as uf2_file: + uf2_file.write(self.make_bootable_uart_uf2()) + with open(flash, 'wb') as flash_file: + flash_file.write(bytes([0xff]) * 512) + + self.set_direct_uart_machine() + self.launch_flash_file('overlay-write', flash, 'PICO UART OK', uf2) + self.launch_flash_file('overlay-read', flash, 'PICO UART OK') + + def test_bootrom_uf2_kernel_without_flash_file(self): + uf2 = self.scratch_file('bootrom-uart-test.uf2') + rom = self.pipico_rom() + + with open(uf2, 'wb') as uf2_file: + uf2_file.write(self.make_bootable_uart_uf2()) + + self.set_direct_uart_machine() + self.vm.set_console() + self.vm.add_args('-bios', rom, '-kernel', uf2) + self.vm.launch() + + wait_for_console_pattern(self, 'PICO UART OK') + + def test_bootrom_elf_kernel_without_flash_file(self): + elf = self.scratch_file('bootrom-uart-test.elf') + rom = self.pipico_rom() + + with open(elf, 'wb') as elf_file: + elf_file.write(self.make_bootable_uart_elf()) + + self.set_direct_uart_machine() + self.vm.set_console() + self.vm.add_args('-bios', rom, '-kernel', elf) + self.vm.launch() + + wait_for_console_pattern(self, 'PICO UART OK') + + def test_bootrom_flash_file_uf2_kernel_persists(self): + uf2 = self.scratch_file('bootrom-uart-test.uf2') + flash = self.scratch_file('flash.bin') + rom = self.pipico_rom() + + with open(uf2, 'wb') as uf2_file: + uf2_file.write(self.make_bootable_uart_uf2()) + with open(flash, 'wb') as flash_file: + flash_file.write(bytes([0xff]) * 512) + + self.set_direct_uart_machine() + self.launch_flash_file('bootrom-overlay-write', flash, + 'PICO UART OK', uf2, + extra_args=('-bios', rom)) + self.launch_flash_file('bootrom-overlay-read', flash, + 'PICO UART OK', + extra_args=('-bios', rom)) + + def test_flash_file_guest_writes_persist(self): + flash = self.scratch_file('flash.bin') + program = self.scratch_file('flash-program.bin') + reader = self.scratch_file('flash-reader.bin') + + with open(flash, 'wb') as flash_file: + flash_file.write(bytes([0xff]) * 512) + with open(program, 'wb') as image_file: + image_file.write(self.make_bootable_image(self.FLASH_TEST_BIN)) + with open(reader, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_PERSIST_READER_BIN)) + + self.set_direct_uart_machine() + self.launch_flash_file('guest-write', flash, 'FLASH OK', program) + self.launch_flash_file('guest-read', flash, 'PERSIST OK', reader) + + def test_flash_program_without_write_enable(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-no-wel.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_NO_WEL_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'NO WEL OK') + + def test_flash_program_old_and_new(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-old-and-new.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_OLD_AND_NEW_TEST_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'OLD AND NEW OK') + + def test_flash_busy_xip_hardfault(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-hardfault.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_BUSY_HARDFAULT_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'HARDFAULT OK') + + def test_flash_busy_core0_xip_fetch_hardfault(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-busy-core0-xip-fault.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_BUSY_CORE0_XIP_FAULT_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'CORE0 XIP HARDFAULT OK') + + def test_flash_busy_core1_xip_fetch_hardfault(self): + self.set_direct_uart_machine() + + image = self.scratch_file('flash-busy-core1-xip-fault.bin') + with open(image, 'wb') as image_file: + image_file.write(self.make_bootable_image( + self.FLASH_BUSY_CORE1_XIP_FAULT_BIN)) + + self.vm.set_console() + self.vm.add_args('-kernel', image) + self.vm.launch() + + wait_for_console_pattern(self, 'CORE1 XIP HARDFAULT OK') + + +if __name__ == '__main__': + QemuSystemTest.main() -- 2.53.0
