[RFC PATCH 3/3] tests/qtest: add K230 SRAM qtest

Jian Cai <[email protected]> Mon, 20 Jul 2026 15:45:45 +0800
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <[email protected]>
Add qtest coverage for the K230 SRAM device model.  Six test cases
verify the MMIO region:

- address_mapped:       write/read at SRAM base address
- read_write_consistency: 4-offset write-read verification
- byte_access:          byte-level R/W and 32-bit LE composition
- initial_zeroed:       SRAM is zero-initialized on startup
- unmapped_beyond_range: out-of-range access does not crash QEMU
- write_and_verify_range: 64 KiB step full-range verification

Signed-off-by: Jian Cai <[email protected]>
---
 MAINTAINERS                  |   2 +
 tests/qtest/k230-sram-test.c | 161 +++++++++++++++++++++++++++++++++++
 tests/qtest/meson.build      |   3 +-
 3 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/k230-sram-test.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3567563ba6..eebe8b3def 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1827,9 +1827,11 @@ F: docs/system/riscv/k230.rst
 F: hw/riscv/k230.c
 F: hw/riscv/k230_sram.c
 F: include/hw/riscv/k230_sram.h
+F: tests/qtest/k230-sram-test.c
 F: hw/riscv/k230_sram.c
 F: include/hw/riscv/k230_sram.h
 F: tests/qtest/k230-sram-test.c
+F: tests/qtest/k230-sram-test.c
 F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
 F: include/hw/watchdog/k230_wdt.h
diff --git a/tests/qtest/k230-sram-test.c b/tests/qtest/k230-sram-test.c
new file mode 100644
index 0000000000..b00e1173c5
--- /dev/null
+++ b/tests/qtest/k230-sram-test.c
@@ -0,0 +1,161 @@
+/*
+ * QTest testcase for K230 SRAM
+ *
+ * K230 Technical Reference Manual V0.3.1 (2024-11-18):
+ * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * The K230 shared SRAM is 2 MB at 0x80200000, accessed directly via the
+ * AXI bus.  It has no software-visible controller registers, so the tests
+ * focus on MMIO read/write consistency across the full range.
+ *
+ * Copyright (c) 2026 Jian Cai <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+/* K230 SRAM MMIO base address and size */
+#define K230_SRAM_BASE  0x80200000
+#define K230_SRAM_SIZE  (2 * 1024 * 1024) /* 2 MiB */
+
+static void test_address_mapped(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Write a known pattern at the start of SRAM */
+    const uint32_t pattern = 0xDEADBEEF;
+    qtest_writel(qts, K230_SRAM_BASE, pattern);
+
+    /* Read back and verify */
+    uint32_t value = qtest_readl(qts, K230_SRAM_BASE);
+    g_assert_cmphex(value, ==, pattern);
+
+    qtest_quit(qts);
+}
+
+static void test_read_write_consistency(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Write and read back a sequence of patterns at different offsets */
+    static const struct {
+        const char *desc;
+        uint32_t offset;
+        uint32_t pattern;
+    } test_cases[] = {
+        { "start",       0x000000, 0x12345678 },
+        { "mid",         0x100000, 0x9ABCDEF0 }, /* 1 MiB */
+        { "end-4",       K230_SRAM_SIZE - 4, 0xCAFEBABE },
+        { "aligned-256", 0x000100, 0x55AA55AA },
+    };
+
+    for (size_t i = 0; i < G_N_ELEMENTS(test_cases); i++) {
+        uint32_t addr = K230_SRAM_BASE + test_cases[i].offset;
+        qtest_writel(qts, addr, test_cases[i].pattern);
+
+        uint32_t value = qtest_readl(qts, addr);
+        g_assert_cmphex(value, ==, test_cases[i].pattern);
+    }
+
+    qtest_quit(qts);
+}
+
+static void test_byte_access(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Verify byte-level access */
+    uint32_t base = K230_SRAM_BASE;
+
+    qtest_writeb(qts, base + 0, 0xAA);
+    qtest_writeb(qts, base + 1, 0xBB);
+    qtest_writeb(qts, base + 2, 0xCC);
+    qtest_writeb(qts, base + 3, 0xDD);
+
+    uint8_t b0 = qtest_readb(qts, base + 0);
+    uint8_t b1 = qtest_readb(qts, base + 1);
+    uint8_t b2 = qtest_readb(qts, base + 2);
+    uint8_t b3 = qtest_readb(qts, base + 3);
+
+    g_assert_cmphex(b0, ==, 0xAA);
+    g_assert_cmphex(b1, ==, 0xBB);
+    g_assert_cmphex(b2, ==, 0xCC);
+    g_assert_cmphex(b3, ==, 0xDD);
+
+    /* Verify 32-bit read sees the combined value (LE) */
+    uint32_t word = qtest_readl(qts, base);
+    g_assert_cmphex(word, ==, 0xDDCCBBAA);
+
+    qtest_quit(qts);
+}
+
+static void test_initial_zeroed(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* SRAM should be zero-initialized by memory_region_init_ram */
+    uint32_t value = qtest_readl(qts, K230_SRAM_BASE);
+    g_assert_cmphex(value, ==, 0);
+
+    value = qtest_readl(qts, K230_SRAM_BASE + K230_SRAM_SIZE - 4);
+    g_assert_cmphex(value, ==, 0);
+
+    qtest_quit(qts);
+}
+
+static void test_unmapped_beyond_range(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /*
+     * Writes beyond the SRAM region should not crash QEMU.
+     * The exact behaviour (unassigned access / abort) is platform-specific;
+     * we just verify the write does not take the process down.
+     */
+    qtest_writel(qts, K230_SRAM_BASE + K230_SRAM_SIZE, 0xBADF00D);
+    qtest_readl(qts, K230_SRAM_BASE + K230_SRAM_SIZE);
+
+    qtest_quit(qts);
+}
+
+static void test_write_and_verify_range(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /*
+     * Write a walking-bit pattern across the full 2 MiB range in
+     * 64 KiB steps, verifying each word writes correctly.
+     */
+    for (uint32_t offset = 0; offset < K230_SRAM_SIZE; offset += 0x10000) {
+        uint32_t addr = K230_SRAM_BASE + offset;
+        uint32_t pattern = offset | 0x3;  /* keep bottom bits set */
+
+        qtest_writel(qts, addr, pattern);
+        uint32_t value = qtest_readl(qts, addr);
+        g_assert_cmphex(value, ==, pattern);
+    }
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/k230-sram/address_mapped",
+                   test_address_mapped);
+    qtest_add_func("/k230-sram/read_write_consistency",
+                   test_read_write_consistency);
+    qtest_add_func("/k230-sram/byte_access",
+                   test_byte_access);
+    qtest_add_func("/k230-sram/initial_zeroed",
+                   test_initial_zeroed);
+    qtest_add_func("/k230-sram/unmapped_beyond_range",
+                   test_unmapped_beyond_range);
+    qtest_add_func("/k230-sram/write_and_verify_range",
+                   test_write_and_verify_range);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 56ff860e21..cf64539acb 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -297,7 +297,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
   (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
    config_all_devices.has_key('CONFIG_RISCV_IOMMU') ?
    ['iommu-riscv-test'] : []) + \
-  (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
+  (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test',
+   'k230-sram-test'] : [])
 
 qtests_hexagon = ['boot-serial-test']
 
-- 
2.43.0