Signed-off-by: gilles grimaud <[email protected]>
---
hw/arm/rp2040.c | 290 +++++++++++++++++-
include/hw/arm/rp2040.h | 3 +
tests/tcg/arm/system/meson.build | 5 +
tests/tcg/arm/system/rp2040-bootrom-helpers.S | 235 ++++++++++++++
.../tcg/arm/system/rp2040-bootrom-helpers.ref | 5 +
5 files changed, 534 insertions(+), 4 deletions(-)
create mode 100644 tests/tcg/arm/system/rp2040-bootrom-helpers.S
create mode 100644 tests/tcg/arm/system/rp2040-bootrom-helpers.ref
diff --git a/hw/arm/rp2040.c b/hw/arm/rp2040.c
index 1b632be0b6..a3ad360462 100644
--- a/hw/arm/rp2040.c
+++ b/hw/arm/rp2040.c
@@ -44,6 +44,24 @@
#define RP2040_PROC1 1
+#define RP2040_BOOTROM_FUNC_TABLE_PTR_OFFSET 0x14
+#define RP2040_BOOTROM_DATA_TABLE_PTR_OFFSET 0x16
+#define RP2040_BOOTROM_TABLE_LOOKUP_PTR_OFFSET 0x18
+#define RP2040_BOOTROM_LOOKUP_OFFSET 0x0100
+#define RP2040_BOOTROM_STUBS_OFFSET 0x0120
+#define RP2040_BOOTROM_FUNC_TABLE_OFFSET 0x0300
+#define RP2040_BOOTROM_DATA_TABLE_OFFSET 0x0340
+#define RP2040_BOOTROM_FLOAT_NYI_STUB_OFFSET 0x0360
+#define RP2040_BOOTROM_DOUBLE_NYI_STUB_OFFSET 0x0380
+#define RP2040_BOOTROM_FLOAT_TABLE_OFFSET 0x03c0
+#define RP2040_BOOTROM_DOUBLE_TABLE_OFFSET 0x0460
+#define RP2040_BOOTROM_FUNC_TABLE_ENTRY_SIZE 4
+#define RP2040_BOOTROM_DATA_TABLE_ENTRY_SIZE 4
+#define RP2040_BOOTROM_NYI_CODE_LITERAL_OFFSET 20
+#define RP2040_BOOTROM_ROM_VERSION_OFFSET 0x13
+#define RP2040_BOOTROM_SYNTHETIC_ROM_VERSION 2
+#define RP2040_BOOTROM_FLOAT_TABLE_WORDS 32
+
/*
* Temporary boot ROM used until a faithful RP2040 boot ROM is requested. It
* uses SIO_CPUID to split core behavior: core 0 copies the 256-byte XIP
@@ -166,6 +184,222 @@ static const struct {
{ "rp2040.pio1", 0x50300000, 0x10000 },
};
+typedef struct RP2040BootromFunction {
+ uint16_t code;
+ const char *name;
+ const uint8_t *impl;
+ size_t impl_size;
+} RP2040BootromFunction;
+
+typedef struct RP2040BootromData {
+ uint16_t code;
+ uint16_t offset;
+} RP2040BootromData;
+
+#define RP2040_ROM_TABLE_CODE(c1, c2) ((uint16_t)(c1) | ((uint16_t)(c2) << 8))
+
+static const uint8_t rp2040_bootrom_clz32[] = {
+ 0x00, 0x21, 0x00, 0x28, 0x01, 0xd1, 0x20, 0x20,
+ 0x70, 0x47, 0x00, 0x28, 0x02, 0xd4, 0x40, 0x00,
+ 0x01, 0x31, 0xfa, 0xe7, 0x08, 0x46, 0x70, 0x47,
+};
+
+static const uint8_t rp2040_bootrom_ctz32[] = {
+ 0x00, 0x21, 0x00, 0x28, 0x01, 0xd1, 0x20, 0x20,
+ 0x70, 0x47, 0x01, 0x22, 0x10, 0x42, 0x02, 0xd1,
+ 0x40, 0x08, 0x01, 0x31, 0xf9, 0xe7, 0x08, 0x46,
+ 0x70, 0x47,
+};
+
+static const uint8_t rp2040_bootrom_popcount32[] = {
+ 0x00, 0x21, 0x00, 0x28, 0x04, 0xd0, 0x01, 0x22,
+ 0x02, 0x40, 0x89, 0x18, 0x40, 0x08, 0xf8, 0xe7,
+ 0x08, 0x46, 0x70, 0x47,
+};
+
+static const uint8_t rp2040_bootrom_reverse32[] = {
+ 0x00, 0x21, 0x20, 0x22, 0x49, 0x00, 0x01, 0x23,
+ 0x03, 0x40, 0x19, 0x43, 0x40, 0x08, 0x01, 0x3a,
+ 0xf8, 0xd1, 0x08, 0x46, 0x70, 0x47,
+};
+
+static const uint8_t rp2040_bootrom_memcpy[] = {
+ 0x10, 0xb4, 0x03, 0x46, 0x00, 0x2a, 0x05, 0xd0,
+ 0x0c, 0x78, 0x04, 0x70, 0x01, 0x31, 0x01, 0x30,
+ 0x01, 0x3a, 0xf7, 0xe7, 0x18, 0x46, 0x10, 0xbc,
+ 0x70, 0x47,
+};
+
+static const uint8_t rp2040_bootrom_memset[] = {
+ 0x03, 0x46, 0x00, 0x2a, 0x03, 0xd0, 0x01, 0x70,
+ 0x01, 0x30, 0x01, 0x3a, 0xf9, 0xe7, 0x18, 0x46,
+ 0x70, 0x47,
+};
+
+static const uint8_t rp2040_bootrom_memcpy44[] = {
+ 0x10, 0xb4, 0x03, 0x46, 0x00, 0x2a, 0x05, 0xd0,
+ 0x0c, 0x68, 0x04, 0x60, 0x04, 0x31, 0x04, 0x30,
+ 0x04, 0x3a, 0xf7, 0xe7, 0x18, 0x46, 0x10, 0xbc,
+ 0x70, 0x47,
+};
+
+static const uint8_t rp2040_bootrom_memset4[] = {
+ 0x10, 0xb4, 0x03, 0x46, 0xc9, 0xb2, 0x0c, 0x46,
+ 0x24, 0x02, 0x21, 0x43, 0x0c, 0x46, 0x24, 0x04,
+ 0x21, 0x43, 0x00, 0x2a, 0x03, 0xd0, 0x01, 0x60,
+ 0x04, 0x30, 0x04, 0x3a, 0xf9, 0xe7, 0x18, 0x46,
+ 0x10, 0xbc, 0x70, 0x47,
+};
+
+#define RP2040_BOOTROM_IMPL(_code, _name, _impl) \
+ { _code, _name, _impl, sizeof(_impl) }
+#define RP2040_BOOTROM_NYI(_code, _name) \
+ { _code, _name, NULL, 0 }
+
+static const RP2040BootromFunction rp2040_bootrom_functions[] = {
+ RP2040_BOOTROM_NYI(RP2040_ROM_TABLE_CODE('C', 'X'),
+ "flash_enter_cmd_xip"),
+ RP2040_BOOTROM_NYI(RP2040_ROM_TABLE_CODE('E', 'X'), "flash_exit_xip"),
+ RP2040_BOOTROM_NYI(RP2040_ROM_TABLE_CODE('F', 'C'),
+ "flash_flush_cache"),
+ RP2040_BOOTROM_NYI(RP2040_ROM_TABLE_CODE('I', 'F'),
+ "connect_internal_flash"),
+ RP2040_BOOTROM_NYI(RP2040_ROM_TABLE_CODE('R', 'E'),
+ "flash_range_erase"),
+ RP2040_BOOTROM_NYI(RP2040_ROM_TABLE_CODE('R', 'P'),
+ "flash_range_program"),
+ RP2040_BOOTROM_IMPL(RP2040_ROM_TABLE_CODE('C', '4'), "memcpy44",
+ rp2040_bootrom_memcpy44),
+ RP2040_BOOTROM_IMPL(RP2040_ROM_TABLE_CODE('L', '3'), "clz32",
+ rp2040_bootrom_clz32),
+ RP2040_BOOTROM_IMPL(RP2040_ROM_TABLE_CODE('M', 'C'), "memcpy",
+ rp2040_bootrom_memcpy),
+ RP2040_BOOTROM_IMPL(RP2040_ROM_TABLE_CODE('M', 'S'), "memset",
+ rp2040_bootrom_memset),
+ RP2040_BOOTROM_IMPL(RP2040_ROM_TABLE_CODE('P', '3'), "popcount32",
+ rp2040_bootrom_popcount32),
+ RP2040_BOOTROM_IMPL(RP2040_ROM_TABLE_CODE('R', '3'), "reverse32",
+ rp2040_bootrom_reverse32),
+ RP2040_BOOTROM_IMPL(RP2040_ROM_TABLE_CODE('S', '4'), "memset4",
+ rp2040_bootrom_memset4),
+ RP2040_BOOTROM_IMPL(RP2040_ROM_TABLE_CODE('T', '3'), "ctz32",
+ rp2040_bootrom_ctz32),
+ RP2040_BOOTROM_NYI(RP2040_ROM_TABLE_CODE('U', 'B'), "reset_usb_boot"),
+};
+
+static const RP2040BootromData rp2040_bootrom_data[] = {
+ { RP2040_ROM_TABLE_CODE('S', 'F'), RP2040_BOOTROM_FLOAT_TABLE_OFFSET + 2 },
+ { RP2040_ROM_TABLE_CODE('S', 'D'), RP2040_BOOTROM_DOUBLE_TABLE_OFFSET + 2
},
+};
+
+static const uint8_t rp2040_bootrom_lookup[] = {
+ 0x02, 0x88, 0x00, 0x2a, 0x05, 0xd0, 0x91, 0x42,
+ 0x01, 0xd0, 0x04, 0x30, 0xf8, 0xe7, 0x40, 0x88,
+ 0x70, 0x47, 0x5f, 0x22, 0x12, 0x06, 0xff, 0x23,
+ 0x1b, 0x04, 0x1a, 0x43, 0x11, 0x60, 0x00, 0xbe,
+ 0x00, 0x20, 0x70, 0x47,
+};
+
+static const uint8_t rp2040_bootrom_nyi_stub[] = {
+ 0x04, 0x49, 0x5f, 0x20, 0x00, 0x06, 0xff, 0x22,
+ 0x12, 0x04, 0x10, 0x43, 0x01, 0x60, 0x00, 0xbe,
+ 0xfe, 0xe7, 0xc0, 0x46, 0x00, 0x00, 0x00, 0x00,
+};
+
+static void rp2040_store_hword(uint8_t *rom, uint32_t offset, uint16_t value)
+{
+ rom[offset] = value;
+ rom[offset + 1] = value >> 8;
+}
+
+static void rp2040_store_word(uint8_t *rom, uint32_t offset, uint32_t value)
+{
+ rom[offset] = value;
+ rom[offset + 1] = value >> 8;
+ rom[offset + 2] = value >> 16;
+ rom[offset + 3] = value >> 24;
+}
+
+static void rp2040_install_synthetic_bootrom(void)
+{
+ g_autofree uint8_t *rom = g_malloc0(RP2040_ROM_SIZE);
+ uint32_t func_base = RP2040_BOOTROM_STUBS_OFFSET;
+ uint32_t func_table = RP2040_BOOTROM_FUNC_TABLE_OFFSET;
+ uint32_t data_table = RP2040_BOOTROM_DATA_TABLE_OFFSET;
+ uint32_t float_nyi = RP2040_BOOTROM_FLOAT_NYI_STUB_OFFSET | 1;
+ uint32_t double_nyi = RP2040_BOOTROM_DOUBLE_NYI_STUB_OFFSET | 1;
+ int i;
+
+ memcpy(rom, rp2040_bootrom, sizeof(rp2040_bootrom));
+ rom[RP2040_BOOTROM_ROM_VERSION_OFFSET] =
+ RP2040_BOOTROM_SYNTHETIC_ROM_VERSION;
+ memcpy(rom + RP2040_BOOTROM_LOOKUP_OFFSET, rp2040_bootrom_lookup,
+ sizeof(rp2040_bootrom_lookup));
+ rp2040_store_hword(rom, RP2040_BOOTROM_FUNC_TABLE_PTR_OFFSET,
+ RP2040_BOOTROM_FUNC_TABLE_OFFSET);
+ rp2040_store_hword(rom, RP2040_BOOTROM_DATA_TABLE_PTR_OFFSET,
+ RP2040_BOOTROM_DATA_TABLE_OFFSET);
+ rp2040_store_hword(rom, RP2040_BOOTROM_TABLE_LOOKUP_PTR_OFFSET,
+ RP2040_BOOTROM_LOOKUP_OFFSET | 1);
+
+ for (i = 0; i < ARRAY_SIZE(rp2040_bootrom_functions); i++) {
+ const RP2040BootromFunction *func = &rp2040_bootrom_functions[i];
+ uint32_t entry = func_base | 1;
+
+ if (func->impl) {
+ memcpy(rom + func_base, func->impl, func->impl_size);
+ func_base += ROUND_UP(func->impl_size, 4);
+ } else {
+ memcpy(rom + func_base, rp2040_bootrom_nyi_stub,
+ sizeof(rp2040_bootrom_nyi_stub));
+ rp2040_store_word(rom,
+ func_base +
+ RP2040_BOOTROM_NYI_CODE_LITERAL_OFFSET,
+ func->code);
+ func_base += ROUND_UP(sizeof(rp2040_bootrom_nyi_stub), 4);
+ }
+ rp2040_store_hword(rom, func_table +
+ i * RP2040_BOOTROM_FUNC_TABLE_ENTRY_SIZE,
+ func->code);
+ rp2040_store_hword(rom, func_table +
+ i * RP2040_BOOTROM_FUNC_TABLE_ENTRY_SIZE + 2,
+ entry);
+ }
+
+ memcpy(rom + RP2040_BOOTROM_FLOAT_NYI_STUB_OFFSET, rp2040_bootrom_nyi_stub,
+ sizeof(rp2040_bootrom_nyi_stub));
+ rp2040_store_word(rom, RP2040_BOOTROM_FLOAT_NYI_STUB_OFFSET +
+ RP2040_BOOTROM_NYI_CODE_LITERAL_OFFSET,
+ RP2040_ROM_TABLE_CODE('S', 'F'));
+ memcpy(rom + RP2040_BOOTROM_DOUBLE_NYI_STUB_OFFSET,
rp2040_bootrom_nyi_stub,
+ sizeof(rp2040_bootrom_nyi_stub));
+ rp2040_store_word(rom, RP2040_BOOTROM_DOUBLE_NYI_STUB_OFFSET +
+ RP2040_BOOTROM_NYI_CODE_LITERAL_OFFSET,
+ RP2040_ROM_TABLE_CODE('S', 'D'));
+ rom[RP2040_BOOTROM_FLOAT_TABLE_OFFSET] = RP2040_BOOTROM_FLOAT_TABLE_WORDS;
+ rom[RP2040_BOOTROM_DOUBLE_TABLE_OFFSET] = RP2040_BOOTROM_FLOAT_TABLE_WORDS;
+ for (i = 0; i < RP2040_BOOTROM_FLOAT_TABLE_WORDS; i++) {
+ rp2040_store_word(rom, RP2040_BOOTROM_FLOAT_TABLE_OFFSET + 2 +
+ i * sizeof(uint32_t), float_nyi);
+ rp2040_store_word(rom, RP2040_BOOTROM_DOUBLE_TABLE_OFFSET + 2 +
+ i * sizeof(uint32_t), double_nyi);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rp2040_bootrom_data); i++) {
+ const RP2040BootromData *data = &rp2040_bootrom_data[i];
+
+ rp2040_store_hword(rom, data_table +
+ i * RP2040_BOOTROM_DATA_TABLE_ENTRY_SIZE,
+ data->code);
+ rp2040_store_hword(rom, data_table +
+ i * RP2040_BOOTROM_DATA_TABLE_ENTRY_SIZE + 2,
+ data->offset);
+ }
+
+ rom_add_blob_fixed("rp2040.bootrom", rom, RP2040_ROM_SIZE,
+ RP2040_ROM_BASE);
+}
+
static uint64_t rp2040_usbctrl_regs_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -194,8 +428,8 @@ static uint64_t rp2040_usbctrl_regs_read(void *opaque,
hwaddr addr,
} else {
value = 0;
qemu_log_mask(LOG_UNIMP,
- "%s: unimplemented read at offset 0x%"
- HWADDR_PRIx "\n", __func__, addr & 0xfff);
+ "%s: unimplemented read at offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr & 0xfff);
}
break;
}
@@ -233,6 +467,48 @@ static const MemoryRegionOps rp2040_usbctrl_regs_ops = {
},
};
+static const char *rp2040_bootrom_function_name(uint16_t code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rp2040_bootrom_functions); i++) {
+ if (rp2040_bootrom_functions[i].code == code) {
+ return rp2040_bootrom_functions[i].name;
+ }
+ }
+ return NULL;
+}
+
+static void rp2040_synthetic_rom_dbg_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ uint16_t code = value;
+ const char *name = rp2040_bootrom_function_name(code);
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unimplemented boot ROM function '%c%c' (%s)\n",
+ __func__, code & 0xff, (code >> 8) & 0xff,
+ name ? name : "unknown lookup code");
+}
+
+static uint64_t rp2040_synthetic_rom_dbg_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ qemu_log_mask(LOG_UNIMP,
+ "%s: read from write-only synthetic register\n",
+ __func__);
+ return 0;
+}
+
+static const MemoryRegionOps rp2040_synthetic_rom_dbg_ops = {
+ .read = rp2040_synthetic_rom_dbg_read,
+ .write = rp2040_synthetic_rom_dbg_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
static void rp2040_update_nmi(RP2040State *s)
{
unsigned core;
@@ -498,6 +774,13 @@ static bool rp2040_init_memory(RP2040State *s, Error
**errp)
memory_region_add_subregion(s->board_memory, RP2040_USBCTRL_REGS_BASE,
&s->usbctrl_regs);
+ memory_region_init_io(&s->synthetic_rom_dbg, OBJECT(s),
+ &rp2040_synthetic_rom_dbg_ops, s,
+ "rp2040.synthetic-rom-dbg",
+ RP2040_SYNTHETIC_ROM_DBG_SIZE);
+ memory_region_add_subregion(s->board_memory,
+ RP2040_SYNTHETIC_ROM_DBG_BASE,
+ &s->synthetic_rom_dbg);
return true;
}
@@ -506,8 +789,7 @@ static bool rp2040_load_bootrom(RP2040State *s, Error
**errp)
g_autofree char *filename = NULL;
if (!s->bootrom_file) {
- rom_add_blob_fixed("rp2040.bootrom", rp2040_bootrom,
- sizeof(rp2040_bootrom), RP2040_ROM_BASE);
+ rp2040_install_synthetic_bootrom();
return true;
}
diff --git a/include/hw/arm/rp2040.h b/include/hw/arm/rp2040.h
index 0daa7d6ba1..17235827c4 100644
--- a/include/hw/arm/rp2040.h
+++ b/include/hw/arm/rp2040.h
@@ -52,6 +52,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(RP2040State, RP2040)
#define RP2040_USBCTRL_DPRAM_SIZE (4 * KiB)
#define RP2040_USBCTRL_REGS_BASE 0x50110000
#define RP2040_USBCTRL_REGS_SIZE 0x4000
+#define RP2040_SYNTHETIC_ROM_DBG_BASE 0x5fff0000
+#define RP2040_SYNTHETIC_ROM_DBG_SIZE 0x1000
#define RP2040_NUM_CORES 2
#define RP2040_NUM_IRQS 32
@@ -90,6 +92,7 @@ struct RP2040State {
MemoryRegion sram[6];
MemoryRegion usbctrl_dpram;
MemoryRegion usbctrl_regs;
+ MemoryRegion synthetic_rom_dbg;
uint32_t usbctrl_reg[0x100 / sizeof(uint32_t)];
char *bootrom_file;
diff --git a/tests/tcg/arm/system/meson.build b/tests/tcg/arm/system/meson.build
index a12aed74fa..9e1024cf11 100644
--- a/tests/tcg/arm/system/meson.build
+++ b/tests/tcg/arm/system/meson.build
@@ -157,6 +157,11 @@ tests += {
'qemu_args': rp2040_uart1_qemu_args,
'expected_output': 'rp2040-dma-uart1.ref',
},
+ 'rp2040-bootrom-helpers.S': {
+ 'cflags': rp2040_cflags,
+ 'qemu_args': rp2040_uart_qemu_args,
+ 'expected_output': 'rp2040-bootrom-helpers.ref',
+ },
'semiconsole.c': {
'cflags': cflags,
'qemu_args': ['-serial', 'none', '-chardev', 'stdio,mux=on,id=stdio0',
diff --git a/tests/tcg/arm/system/rp2040-bootrom-helpers.S
b/tests/tcg/arm/system/rp2040-bootrom-helpers.S
new file mode 100644
index 0000000000..e48230a875
--- /dev/null
+++ b/tests/tcg/arm/system/rp2040-bootrom-helpers.S
@@ -0,0 +1,235 @@
+/*
+ * Raspberry Pi Pico boot ROM integer and memory helper test.
+ *
+ * Copyright 2026 Gilles Grimaud
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+#define SRAM_END 0x20042000
+#define UART0_DR 0x40034000
+#define ROM_FUNC_TABLE_PTR 0x00000014
+#define ROM_TABLE_LOOKUP_PTR 0x00000018
+#define ROM_FUNC_POPCOUNT32 0x3350
+#define ROM_FUNC_CLZ32 0x334c
+#define ROM_FUNC_CTZ32 0x3354
+#define ROM_FUNC_REVERSE32 0x3352
+#define ROM_FUNC_MEMSET 0x534d
+#define ROM_FUNC_MEMCPY 0x434d
+#define ROM_FUNC_MEMSET4 0x3453
+#define ROM_FUNC_MEMCPY44 0x3443
+#define TEST_BUFFER 0x20000000
+#define SYS_EXIT 0x18
+#define ADP_STOPPED_APPLICATION_EXIT 0x20026
+#define ADP_STOPPED_RUNTIME_ERROR 0x20023
+
+.macro lookup code
+ ldr r0, =\code
+ bl rom_func_lookup
+ cmp r0, 0
+ bne 0f
+ b fail_lookup
+0:
+ mov r4, r0
+.endm
+
+.macro fail_if_ne reg, expected, target
+ ldr r2, =\expected
+ cmp \reg, r2
+ beq 0f
+ b \target
+0:
+.endm
+
+.section .vectors, "a", %progbits
+.global vector_table
+vector_table:
+ .word SRAM_END
+ .word reset_handler + 1
+ .word default_handler + 1
+ .word default_handler + 1
+
+.section .text, "ax", %progbits
+.thumb_func
+.global reset_handler
+reset_handler:
+ ldr r0, =start_message
+ bl puts
+
+ lookup ROM_FUNC_POPCOUNT32
+ ldr r0, =0xf0f00f0f
+ blx r4
+ fail_if_ne r0, 16, fail_bits
+
+ lookup ROM_FUNC_CLZ32
+ ldr r0, =0x00f00000
+ blx r4
+ fail_if_ne r0, 8, fail_bits
+
+ lookup ROM_FUNC_CTZ32
+ ldr r0, =0x00008000
+ blx r4
+ fail_if_ne r0, 15, fail_bits
+
+ lookup ROM_FUNC_REVERSE32
+ ldr r0, =0x80000001
+ blx r4
+ fail_if_ne r0, 0x80000001, fail_bits
+
+ ldr r0, =bits_ok_message
+ bl puts
+
+ lookup ROM_FUNC_MEMSET
+ ldr r0, =TEST_BUFFER
+ movs r1, 0x5a
+ movs r2, 4
+ blx r4
+ ldr r5, =TEST_BUFFER
+ ldrb r0, [r5]
+ fail_if_ne r0, 0x5a, fail_byte_memory
+ ldrb r0, [r5, 3]
+ fail_if_ne r0, 0x5a, fail_byte_memory
+
+ ldr r5, =TEST_BUFFER + 0x20
+ ldr r0, =0x11223344
+ str r0, [r5]
+ lookup ROM_FUNC_MEMCPY
+ ldr r0, =TEST_BUFFER + 0x10
+ ldr r1, =TEST_BUFFER + 0x20
+ movs r2, 4
+ blx r4
+ ldr r5, =TEST_BUFFER + 0x10
+ ldr r0, [r5]
+ fail_if_ne r0, 0x11223344, fail_byte_memory
+
+ ldr r0, =byte_memory_ok_message
+ bl puts
+
+ lookup ROM_FUNC_MEMSET4
+ ldr r5, =TEST_BUFFER + 0x30
+ ldr r0, =0xdeadbeef
+ str r0, [r5, 8]
+ ldr r0, =TEST_BUFFER + 0x30
+ movs r1, 0x5a
+ movs r2, 8
+ blx r4
+ ldr r5, =TEST_BUFFER + 0x30
+ ldr r0, [r5]
+ fail_if_ne r0, 0x5a5a5a5a, fail_word_memory
+ ldr r0, [r5, 4]
+ fail_if_ne r0, 0x5a5a5a5a, fail_word_memory
+ ldr r0, [r5, 8]
+ fail_if_ne r0, 0xdeadbeef, fail_word_memory
+
+ ldr r5, =TEST_BUFFER + 0x40
+ ldr r0, =0x55667788
+ str r0, [r5]
+ ldr r0, =0x99aabbcc
+ str r0, [r5, 4]
+ ldr r5, =TEST_BUFFER + 0x50
+ ldr r0, =0xdeadbeef
+ str r0, [r5, 8]
+ lookup ROM_FUNC_MEMCPY44
+ ldr r0, =TEST_BUFFER + 0x50
+ ldr r1, =TEST_BUFFER + 0x40
+ movs r2, 8
+ blx r4
+ ldr r5, =TEST_BUFFER + 0x50
+ ldr r0, [r5]
+ fail_if_ne r0, 0x55667788, fail_word_memory
+ ldr r0, [r5, 4]
+ fail_if_ne r0, 0x99aabbcc, fail_word_memory
+ ldr r0, [r5, 8]
+ fail_if_ne r0, 0xdeadbeef, fail_word_memory
+
+ ldr r0, =word_memory_ok_message
+ bl puts
+ ldr r0, =ok_message
+ bl puts
+ movs r0, SYS_EXIT
+ ldr r1, =ADP_STOPPED_APPLICATION_EXIT
+ bkpt 0xab
+
+1:
+ b 1b
+
+fail_lookup:
+ ldr r0, =fail_lookup_message
+ b test_failed
+
+fail_bits:
+ ldr r0, =fail_bits_message
+ b test_failed
+
+fail_byte_memory:
+ ldr r0, =fail_byte_memory_message
+ b test_failed
+
+fail_word_memory:
+ ldr r0, =fail_word_memory_message
+
+test_failed:
+ bl puts
+ movs r0, SYS_EXIT
+ ldr r1, =ADP_STOPPED_RUNTIME_ERROR
+ bkpt 0xab
+
+2:
+ b 2b
+
+.thumb_func
+rom_func_lookup:
+ push {r4, lr}
+ mov r1, r0
+ ldr r0, =ROM_FUNC_TABLE_PTR
+ ldrh r0, [r0]
+ ldr r4, =ROM_TABLE_LOOKUP_PTR
+ ldrh r4, [r4]
+ blx r4
+ pop {r4, pc}
+
+.thumb_func
+default_handler:
+ ldr r0, =fail_exception_message
+ b test_failed
+
+.thumb_func
+puts:
+ ldr r2, =UART0_DR
+
+3:
+ ldrb r1, [r0]
+ cmp r1, 0
+ beq 4f
+ str r1, [r2]
+ adds r0, 1
+ b 3b
+
+4:
+ bx lr
+
+.section .rodata, "a", %progbits
+start_message:
+ .asciz "PICO TCG BOOTROM HELPERS START\n"
+bits_ok_message:
+ .asciz "PICO TCG BOOTROM HELPERS BITS OK\n"
+byte_memory_ok_message:
+ .asciz "PICO TCG BOOTROM HELPERS BYTE MEMORY OK\n"
+word_memory_ok_message:
+ .asciz "PICO TCG BOOTROM HELPERS WORD MEMORY OK\n"
+ok_message:
+ .asciz "PICO TCG BOOTROM HELPERS OK\n"
+fail_lookup_message:
+ .asciz "PICO TCG BOOTROM HELPERS FAIL: LOOKUP\n"
+fail_bits_message:
+ .asciz "PICO TCG BOOTROM HELPERS FAIL: BITS\n"
+fail_byte_memory_message:
+ .asciz "PICO TCG BOOTROM HELPERS FAIL: BYTE MEMORY\n"
+fail_word_memory_message:
+ .asciz "PICO TCG BOOTROM HELPERS FAIL: WORD MEMORY\n"
+fail_exception_message:
+ .asciz "PICO TCG BOOTROM HELPERS FAIL: EXCEPTION\n"
diff --git a/tests/tcg/arm/system/rp2040-bootrom-helpers.ref
b/tests/tcg/arm/system/rp2040-bootrom-helpers.ref
new file mode 100644
index 0000000000..b1b4346bf4
--- /dev/null
+++ b/tests/tcg/arm/system/rp2040-bootrom-helpers.ref
@@ -0,0 +1,5 @@
+PICO TCG BOOTROM HELPERS START
+PICO TCG BOOTROM HELPERS BITS OK
+PICO TCG BOOTROM HELPERS BYTE MEMORY OK
+PICO TCG BOOTROM HELPERS WORD MEMORY OK
+PICO TCG BOOTROM HELPERS OK
--
2.55.0