Add source-built bare-metal tests for memory copy and fill transfers,
completion status and interrupt acknowledgement.

Exercise UART0 and UART1 transmit and receive pacing through their DMA
request lines. Each UART test waits for DMA IRQ completion and validates
looped-back input before reporting success.

Signed-off-by: gilles grimaud <[email protected]>
---
 tests/tcg/arm/system/meson.build           |  25 ++
 tests/tcg/arm/system/rp2040-dma-memory.S   | 198 +++++++++++++++
 tests/tcg/arm/system/rp2040-dma-memory.ref |   4 +
 tests/tcg/arm/system/rp2040-dma-uart.S     | 267 +++++++++++++++++++++
 tests/tcg/arm/system/rp2040-dma-uart0.ref  |   3 +
 tests/tcg/arm/system/rp2040-dma-uart1.ref  |   3 +
 6 files changed, 500 insertions(+)
 create mode 100644 tests/tcg/arm/system/rp2040-dma-memory.S
 create mode 100644 tests/tcg/arm/system/rp2040-dma-memory.ref
 create mode 100644 tests/tcg/arm/system/rp2040-dma-uart.S
 create mode 100644 tests/tcg/arm/system/rp2040-dma-uart0.ref
 create mode 100644 tests/tcg/arm/system/rp2040-dma-uart1.ref

diff --git a/tests/tcg/arm/system/meson.build b/tests/tcg/arm/system/meson.build
index c57bf5f0d0..a12aed74fa 100644
--- a/tests/tcg/arm/system/meson.build
+++ b/tests/tcg/arm/system/meson.build
@@ -24,6 +24,9 @@ rp2040_qemu_args = ['-M', 'raspi-pico', '-monitor', 'none',
 rp2040_uart_qemu_args = ['-M', 'raspi-pico,strict-uart-pins=off',
                          '-monitor', 'none', '-serial', 'stdio',
                          qemu_base_args]
+rp2040_uart1_qemu_args = ['-M', 'raspi-pico,strict-uart-pins=off',
+                          '-monitor', 'none', '-serial', 'null',
+                          '-serial', 'stdio', qemu_base_args]
 rp2040_flash_persist = find_program('rp2040-flash-persist.sh')
 
 # Multi arch tests
@@ -132,6 +135,28 @@ tests += {
     'qemu_args': rp2040_uart_qemu_args,
     'expected_output': 'rp2040-core1-xip-fault.ref',
   },
+  'rp2040-dma-memory.S': {
+    'cflags': rp2040_cflags,
+    'qemu_args': rp2040_uart_qemu_args,
+    'expected_output': 'rp2040-dma-memory.ref',
+  },
+  'rp2040-dma-uart.S': {
+    'exe_name': 'rp2040-dma-uart0',
+    'test_name': 'rp2040-dma-uart0',
+    'cflags': rp2040_cflags + ['-DUART_INDEX=0'],
+    'qemu_args': rp2040_uart_qemu_args,
+    'expected_output': 'rp2040-dma-uart0.ref',
+  },
+}
+
+tests += {
+  'rp2040-dma-uart.S': {
+    'exe_name': 'rp2040-dma-uart1',
+    'test_name': 'rp2040-dma-uart1',
+    'cflags': rp2040_cflags + ['-DUART_INDEX=1'],
+    'qemu_args': rp2040_uart1_qemu_args,
+    'expected_output': 'rp2040-dma-uart1.ref',
+  },
   'semiconsole.c': {
     'cflags': cflags,
     'qemu_args': ['-serial', 'none', '-chardev', 'stdio,mux=on,id=stdio0',
diff --git a/tests/tcg/arm/system/rp2040-dma-memory.S 
b/tests/tcg/arm/system/rp2040-dma-memory.S
new file mode 100644
index 0000000000..015c7241dc
--- /dev/null
+++ b/tests/tcg/arm/system/rp2040-dma-memory.S
@@ -0,0 +1,198 @@
+/*
+ * Raspberry Pi Pico DMA memory transfer test.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+#define SRAM_END               0x20042000
+#define UART0_DR               0x40034000
+#define DMA_BASE               0x50000000
+#define DMA_READ_ADDR          0x000
+#define DMA_WRITE_ADDR         0x004
+#define DMA_TRANS_COUNT        0x008
+#define DMA_CTRL_TRIG          0x00c
+#define DMA_INTR               0x400
+#define DMA_CTRL_WORD_COPY     0x001f8039
+#define DMA_CTRL_WORD_FILL     0x001f8029
+#define SYS_EXIT               0x18
+#define ADP_STOPPED_APPLICATION_EXIT 0x20026
+#define ADP_STOPPED_RUNTIME_ERROR    0x20023
+
+.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
+
+    ldr r5, =copy_source
+    ldr r0, =0x11223344
+    str r0, [r5, #0]
+    ldr r0, =0xaabbccdd
+    str r0, [r5, #4]
+    ldr r0, =0x01020304
+    str r0, [r5, #8]
+    ldr r0, =0xfeedc0de
+    str r0, [r5, #12]
+    ldr r5, =fill_source
+    ldr r0, =0x55aa55aa
+    str r0, [r5]
+
+    ldr r4, =DMA_BASE
+
+    ldr r0, =copy_source
+    str r0, [r4, DMA_READ_ADDR]
+    ldr r0, =copy_destination
+    str r0, [r4, DMA_WRITE_ADDR]
+    movs r0, 4
+    str r0, [r4, DMA_TRANS_COUNT]
+    ldr r0, =DMA_CTRL_WORD_COPY
+    str r0, [r4, DMA_CTRL_TRIG]
+
+    ldr r5, =copy_source
+    ldr r6, =copy_destination
+    movs r3, 4
+
+copy_check_loop:
+    ldr r0, [r5]
+    ldr r1, [r6]
+    cmp r0, r1
+    bne fail_copy
+    adds r5, 4
+    adds r6, 4
+    subs r3, 1
+    bne copy_check_loop
+
+    ldr r6, =DMA_BASE + DMA_INTR
+    ldr r0, [r6]
+    movs r1, 1
+    tst r0, r1
+    beq fail_irq
+    str r1, [r6]
+    ldr r0, [r6]
+    tst r0, r1
+    bne fail_irq
+
+    ldr r0, =copy_ok_message
+    bl puts
+
+    ldr r0, =fill_source
+    str r0, [r4, DMA_READ_ADDR]
+    ldr r0, =fill_destination
+    str r0, [r4, DMA_WRITE_ADDR]
+    movs r0, 4
+    str r0, [r4, DMA_TRANS_COUNT]
+    ldr r0, =DMA_CTRL_WORD_FILL
+    str r0, [r4, DMA_CTRL_TRIG]
+
+    ldr r5, =fill_destination
+    ldr r1, =0x55aa55aa
+    movs r3, 4
+
+fill_check_loop:
+    ldr r0, [r5]
+    cmp r0, r1
+    bne fail_fill
+    adds r5, 4
+    subs r3, 1
+    bne fill_check_loop
+
+    ldr r0, =fill_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_copy:
+    ldr r0, =fail_copy_message
+    b test_failed
+
+fail_fill:
+    ldr r0, =fail_fill_message
+    b test_failed
+
+fail_irq:
+    ldr r0, =fail_irq_message
+
+test_failed:
+    bl puts
+    movs r0, SYS_EXIT
+    ldr r1, =ADP_STOPPED_RUNTIME_ERROR
+    bkpt 0xab
+
+2:
+    b 2b
+
+.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 .bss, "aw", %nobits
+.align 2
+copy_source:
+    .space 16
+copy_destination:
+    .space 16
+fill_source:
+    .space 4
+fill_destination:
+    .space 16
+
+.section .rodata, "a", %progbits
+start_message:
+    .asciz "PICO TCG DMA MEMORY START\n"
+copy_ok_message:
+    .asciz "PICO TCG DMA MEMORY COPY OK\n"
+fill_ok_message:
+    .asciz "PICO TCG DMA MEMORY FILL OK\n"
+ok_message:
+    .asciz "PICO TCG DMA MEMORY OK\n"
+fail_copy_message:
+    .asciz "PICO TCG DMA MEMORY FAIL: COPY\n"
+fail_fill_message:
+    .asciz "PICO TCG DMA MEMORY FAIL: FILL\n"
+fail_irq_message:
+    .asciz "PICO TCG DMA MEMORY FAIL: IRQ\n"
+fail_exception_message:
+    .asciz "PICO TCG DMA MEMORY FAIL: EXCEPTION\n"
diff --git a/tests/tcg/arm/system/rp2040-dma-memory.ref 
b/tests/tcg/arm/system/rp2040-dma-memory.ref
new file mode 100644
index 0000000000..5960220ead
--- /dev/null
+++ b/tests/tcg/arm/system/rp2040-dma-memory.ref
@@ -0,0 +1,4 @@
+PICO TCG DMA MEMORY START
+PICO TCG DMA MEMORY COPY OK
+PICO TCG DMA MEMORY FILL OK
+PICO TCG DMA MEMORY OK
diff --git a/tests/tcg/arm/system/rp2040-dma-uart.S 
b/tests/tcg/arm/system/rp2040-dma-uart.S
new file mode 100644
index 0000000000..36972bbc98
--- /dev/null
+++ b/tests/tcg/arm/system/rp2040-dma-uart.S
@@ -0,0 +1,267 @@
+/*
+ * Raspberry Pi Pico UART-paced DMA transfer test.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+#ifndef UART_INDEX
+#error UART_INDEX must select UART0 or UART1
+#elif UART_INDEX == 0
+#define UART_BASE              0x40034000
+#define DREQ_UART_TX           20
+#define DREQ_UART_RX           21
+#define UART_NAME              "UART0"
+#elif UART_INDEX == 1
+#define UART_BASE              0x40038000
+#define DREQ_UART_TX           22
+#define DREQ_UART_RX           23
+#define UART_NAME              "UART1"
+#else
+#error Unsupported UART_INDEX
+#endif
+
+#define SRAM_END               0x20042000
+#define UART_LCR_H             0x2c
+#define UART_CR                0x30
+#define UART_DMACR             0x48
+#define UART_CR_ENABLED        0x301
+#define UART_CR_LOOPBACK       0x381
+#define DMA_BASE               0x50000000
+#define DMA_READ_ADDR          0x000
+#define DMA_WRITE_ADDR         0x004
+#define DMA_TRANS_COUNT        0x008
+#define DMA_CTRL_TRIG          0x00c
+#define DMA_INTR               0x400
+#define DMA_INTE0              0x404
+#define DMA_CTRL_EN            0x00000001
+#define DMA_CTRL_INCR_R        0x00000010
+#define DMA_CTRL_INCR_W        0x00000020
+#define DMA_CTRL_TX            (DMA_CTRL_EN | DMA_CTRL_INCR_R | \
+                                (DREQ_UART_TX << 15))
+#define DMA_CTRL_RX            (DMA_CTRL_EN | DMA_CTRL_INCR_W | \
+                                (DREQ_UART_RX << 15))
+#define DMA_IRQ_0              11
+#define NVIC_ISER              0xe000e100
+#define NVIC_ICER              0xe000e180
+#define NVIC_ICPR              0xe000e280
+#define SYS_EXIT               0x18
+#define ADP_STOPPED_APPLICATION_EXIT 0x20026
+#define ADP_STOPPED_RUNTIME_ERROR    0x20023
+
+.section .vectors, "a", %progbits
+.global vector_table
+vector_table:
+    .word SRAM_END
+    .word reset_handler + 1
+    .word default_handler + 1
+    .word default_handler + 1
+    .rept 12
+    .word default_handler + 1
+    .endr
+    .rept DMA_IRQ_0
+    .word default_handler + 1
+    .endr
+    .word dma_irq_handler + 1
+
+.section .text, "ax", %progbits
+.thumb_func
+.global reset_handler
+reset_handler:
+    cpsid i
+    ldr r0, =UART_BASE
+    movs r1, 0x10
+    str r1, [r0, UART_LCR_H]
+    ldr r1, =UART_CR_ENABLED
+    str r1, [r0, UART_CR]
+    movs r1, 3
+    str r1, [r0, UART_DMACR]
+
+    ldr r0, =NVIC_ICER
+    movs r2, 0
+    mvns r2, r2
+    str r2, [r0]
+    ldr r0, =NVIC_ICPR
+    str r2, [r0]
+    ldr r0, =NVIC_ISER
+    ldr r1, =(1 << DMA_IRQ_0)
+    str r1, [r0]
+    cpsie i
+
+    ldr r0, =start_message
+    movs r1, START_MESSAGE_LEN
+    bl dma_tx
+
+    ldr r0, =UART_BASE
+    ldr r1, =UART_CR_LOOPBACK
+    str r1, [r0, UART_CR]
+    ldr r0, =hello_message
+    movs r1, 5
+    bl dma_tx
+    ldr r0, =UART_BASE
+    ldr r1, =UART_CR_ENABLED
+    str r1, [r0, UART_CR]
+    ldr r0, =newline_message
+    bl puts
+
+    ldr r0, =rx_buffer
+    movs r1, 5
+    bl dma_rx
+
+    ldr r0, =rx_buffer
+    ldr r1, =hello_message
+    movs r2, 5
+
+check_loop:
+    ldrb r3, [r0]
+    ldrb r4, [r1]
+    cmp r3, r4
+    bne fail_data
+    adds r0, 1
+    adds r1, 1
+    subs r2, 1
+    bne check_loop
+
+    ldr r0, =ok_message
+    movs r1, OK_MESSAGE_LEN
+    bl dma_tx
+    movs r0, SYS_EXIT
+    ldr r1, =ADP_STOPPED_APPLICATION_EXIT
+    bkpt 0xab
+
+1:
+    b 1b
+
+fail_data:
+    ldr r0, =fail_data_message
+    b test_failed
+
+fail_irq:
+    ldr r0, =fail_irq_message
+    b test_failed
+
+.thumb_func
+default_handler:
+    ldr r0, =fail_exception_message
+
+test_failed:
+    bl puts
+    movs r0, SYS_EXIT
+    ldr r1, =ADP_STOPPED_RUNTIME_ERROR
+    bkpt 0xab
+
+2:
+    b 2b
+
+.thumb_func
+dma_tx:
+    push {r4, lr}
+    mov r4, r1
+    bl clear_dma_irq
+    ldr r2, =DMA_BASE
+    str r0, [r2, DMA_READ_ADDR]
+    ldr r3, =UART_BASE
+    str r3, [r2, DMA_WRITE_ADDR]
+    str r4, [r2, DMA_TRANS_COUNT]
+    ldr r3, =DMA_CTRL_TX
+    str r3, [r2, DMA_CTRL_TRIG]
+    bl wait_dma_irq
+    pop {r4, pc}
+
+.thumb_func
+dma_rx:
+    push {r4, lr}
+    mov r4, r1
+    bl clear_dma_irq
+    ldr r2, =DMA_BASE
+    ldr r3, =UART_BASE
+    str r3, [r2, DMA_READ_ADDR]
+    str r0, [r2, DMA_WRITE_ADDR]
+    str r4, [r2, DMA_TRANS_COUNT]
+    ldr r3, =DMA_CTRL_RX
+    str r3, [r2, DMA_CTRL_TRIG]
+    bl wait_dma_irq
+    pop {r4, pc}
+
+.thumb_func
+clear_dma_irq:
+    ldr r2, =irq_flag
+    movs r3, 0
+    str r3, [r2]
+    ldr r2, =DMA_BASE + DMA_INTR
+    movs r3, 1
+    str r3, [r2]
+    ldr r2, =DMA_BASE + DMA_INTE0
+    str r3, [r2]
+    bx lr
+
+.thumb_func
+wait_dma_irq:
+    ldr r2, =irq_flag
+
+3:
+    ldr r3, [r2]
+    movs r4, 1
+    tst r3, r4
+    bne 4f
+    b 3b
+
+4:
+    bx lr
+
+.thumb_func
+dma_irq_handler:
+    ldr r0, =DMA_BASE + DMA_INTR
+    ldr r1, [r0]
+    movs r2, 1
+    tst r1, r2
+    beq fail_irq
+    str r1, [r0]
+    ldr r0, =irq_flag
+    str r1, [r0]
+    bx lr
+
+.thumb_func
+puts:
+    ldr r2, =UART_BASE
+
+5:
+    ldrb r1, [r0]
+    cmp r1, 0
+    beq 6f
+    str r1, [r2]
+    adds r0, 1
+    b 5b
+
+6:
+    bx lr
+
+.section .bss, "aw", %nobits
+.align 2
+irq_flag:
+    .word 0
+rx_buffer:
+    .space 8
+
+.section .rodata, "a", %progbits
+start_message:
+    .ascii "PICO TCG DMA " UART_NAME " START\n"
+start_message_end:
+hello_message:
+    .ascii "HELLO"
+newline_message:
+    .asciz "\n"
+ok_message:
+    .ascii "PICO TCG DMA " UART_NAME " TX/RX OK\n"
+ok_message_end:
+.equ START_MESSAGE_LEN, start_message_end - start_message
+.equ OK_MESSAGE_LEN, ok_message_end - ok_message
+fail_data_message:
+    .asciz "PICO TCG DMA " UART_NAME " FAIL: DATA\n"
+fail_irq_message:
+    .asciz "PICO TCG DMA " UART_NAME " FAIL: IRQ\n"
+fail_exception_message:
+    .asciz "PICO TCG DMA " UART_NAME " FAIL: EXCEPTION\n"
diff --git a/tests/tcg/arm/system/rp2040-dma-uart0.ref 
b/tests/tcg/arm/system/rp2040-dma-uart0.ref
new file mode 100644
index 0000000000..5cb57c56cc
--- /dev/null
+++ b/tests/tcg/arm/system/rp2040-dma-uart0.ref
@@ -0,0 +1,3 @@
+PICO TCG DMA UART0 START
+HELLO
+PICO TCG DMA UART0 TX/RX OK
diff --git a/tests/tcg/arm/system/rp2040-dma-uart1.ref 
b/tests/tcg/arm/system/rp2040-dma-uart1.ref
new file mode 100644
index 0000000000..1509dc034a
--- /dev/null
+++ b/tests/tcg/arm/system/rp2040-dma-uart1.ref
@@ -0,0 +1,3 @@
+PICO TCG DMA UART1 START
+HELLO
+PICO TCG DMA UART1 TX/RX OK
-- 
2.55.0


Reply via email to