* [RFC PATCH 1/3] hw/riscv: add K230 SRAM device model
[not found] <20260720074545.8987-1-lingqian_gi@163.com>
@ 2026-07-20 7:45 ` Jian Cai
2026-07-20 9:42 ` Chao Liu
2026-07-21 6:04 ` [PATCH v2] hw/riscv/k230: add k230_sram_create() helper function Jian Cai
2026-07-20 7:45 ` [RFC PATCH 2/3] hw/riscv/k230: integrate SRAM device into SoC Jian Cai
2026-07-20 7:45 ` [RFC PATCH 3/3] tests/qtest: add K230 SRAM qtest Jian Cai
2 siblings, 2 replies; 5+ messages in thread
From: Jian Cai @ 2026-07-20 7:45 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: chao.liu, palmer, alistair.francis, liwei1518, daniel.barboza,
zhiwei_liu
The K230 shared SRAM (2 MB at 0x80200000) has no software-visible
controller registers: it is a pure on-chip RAM block accessed via
the AXI bus. This patch wraps it as a SysBusDevice so that it appears
in the QOM tree, supports VMState migration, and can be introspected
by management tools.
Clock gating (CMU at 0x91100000, offset 0x5c) and reset control
(RMU at 0x91101000, offsets 0x60/0x64) are handled by separate
system-controller peripherals and are not modelled here.
Reference:
K230 TRM V0.3.1 (2024-11-18), Section 5.2 Sram
Signed-off-by: Jian Cai <lingqian_gi@163.com>
---
MAINTAINERS | 5 +++
hw/riscv/k230_sram.c | 81 ++++++++++++++++++++++++++++++++++++
include/hw/riscv/k230_sram.h | 35 ++++++++++++++++
3 files changed, 121 insertions(+)
create mode 100644 hw/riscv/k230_sram.c
create mode 100644 include/hw/riscv/k230_sram.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 6171cc7494..3567563ba6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1825,6 +1825,11 @@ L: qemu-riscv@nongnu.org
S: Maintained
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: hw/riscv/k230_sram.c
+F: include/hw/riscv/k230_sram.h
+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/hw/riscv/k230_sram.c b/hw/riscv/k230_sram.c
new file mode 100644
index 0000000000..1d960e733e
--- /dev/null
+++ b/hw/riscv/k230_sram.c
@@ -0,0 +1,81 @@
+/*
+ * K230 SRAM Controller
+ *
+ * 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 (2 MB at 0x80200000) has no software-visible
+ * controller registers. This device wraps the SRAM as a SysBusDevice
+ * so that it appears in the QOM tree, supports migration (VMState),
+ * and can be introspected by management tools.
+ *
+ * Clock gating is controlled by the CMU at 0x91100000 (shrm_CLK_CFG,
+ * offset 0x5c, bit 10: sram_aclk_enable). Reset is controlled by the
+ * RMU at 0x91101000 (SRAM_RST_TIM/SRAM_RST_CTL, offsets 0x60/0x64).
+ * Those peripherals are not modelled yet, so SRAM is always enabled
+ * in the current QEMU implementation.
+ *
+ * Copyright (c) 2026 Jian Cai <lingqian_gi@163.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "hw/core/sysbus.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "hw/riscv/k230_sram.h"
+
+static void k230_sram_realize(DeviceState *dev, Error **errp)
+{
+ K230SramState *s = K230_SRAM(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_ram(&s->sram, OBJECT(dev), "k230.sram",
+ 2 * MiB, &error_fatal);
+ sysbus_init_mmio(sbd, &s->sram);
+}
+
+static void k230_sram_reset_hold(Object *obj, ResetType type)
+{
+ /*
+ * No software-visible registers to reset. SRAM content is preserved
+ * across warm reset on real hardware; a cold reset would clear it,
+ * but QEMU memory_region_init_ram already zeroes the region on init.
+ */
+}
+
+static const VMStateDescription vmstate_k230_sram = {
+ .name = "k230.sram",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void k230_sram_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = k230_sram_realize;
+ rc->phases.hold = k230_sram_reset_hold;
+ dc->vmsd = &vmstate_k230_sram;
+ dc->desc = "K230 SRAM";
+}
+
+static const TypeInfo k230_sram_info = {
+ .name = TYPE_K230_SRAM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(K230SramState),
+ .class_init = k230_sram_class_init,
+};
+
+static void k230_sram_register_type(void)
+{
+ type_register_static(&k230_sram_info);
+}
+
+type_init(k230_sram_register_type)
diff --git a/include/hw/riscv/k230_sram.h b/include/hw/riscv/k230_sram.h
new file mode 100644
index 0000000000..6d15970ab9
--- /dev/null
+++ b/include/hw/riscv/k230_sram.h
@@ -0,0 +1,35 @@
+/*
+ * K230 SRAM Controller
+ *
+ * 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 (2 MB at 0x80200000) has no software-visible
+ * controller registers: it is a pure on-chip RAM block accessed directly
+ * via the AXI bus. Clock gating (CMU at 0x91100000, offset 0x5c) and
+ * reset control (RMU at 0x91101000, offsets 0x60/0x64) are handled by
+ * separate system-controller peripherals and are not modelled here yet.
+ *
+ * Copyright (c) 2026 Jian Cai <lingqian_gi@163.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef K230_SRAM_H
+#define K230_SRAM_H
+
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_K230_SRAM "riscv.k230.sram"
+OBJECT_DECLARE_SIMPLE_TYPE(K230SramState, K230_SRAM)
+
+struct K230SramState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion sram; /* 2 MB SRAM storage */
+};
+
+#endif /* K230_SRAM_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [RFC PATCH 1/3] hw/riscv: add K230 SRAM device model
2026-07-20 7:45 ` [RFC PATCH 1/3] hw/riscv: add K230 SRAM device model Jian Cai
@ 2026-07-20 9:42 ` Chao Liu
2026-07-21 6:04 ` [PATCH v2] hw/riscv/k230: add k230_sram_create() helper function Jian Cai
1 sibling, 0 replies; 5+ messages in thread
From: Chao Liu @ 2026-07-20 9:42 UTC (permalink / raw)
To: Jian Cai
Cc: qemu-devel, qemu-riscv, palmer, alistair.francis, liwei1518,
daniel.barboza, zhiwei_liu
Hi Jian,
On Mon, Jul 20, 2026 at 03:45:43PM +0800, Jian Cai wrote:
> The K230 shared SRAM (2 MB at 0x80200000) has no software-visible
> controller registers: it is a pure on-chip RAM block accessed via
> the AXI bus. This patch wraps it as a SysBusDevice so that it appears
> in the QOM tree, supports VMState migration, and can be introspected
> by management tools.
>
> Clock gating (CMU at 0x91100000, offset 0x5c) and reset control
> (RMU at 0x91101000, offsets 0x60/0x64) are handled by separate
> system-controller peripherals and are not modelled here.
>
> Reference:
> K230 TRM V0.3.1 (2024-11-18), Section 5.2 Sram
Thanks for the contribution!
But I didn't receive the cover letter for this patch set. Please check if you
prepared one, or if it might have been lost during transmission.
Could you please include a cover letter when you send the next revision
of this series? It should briefly explain what the series does as a
whole and what problem it is intended to solve.
Here are two ways to generate one:
1. Store the cover letter in the branch description:
git branch --edit-description
git format-patch --cover-letter --cover-from-description=subject \
-o outgoing
2. Generate a cover letter template and edit it manually:
git format-patch --cover-letter -o k230-patches
$EDITOR k230-patches/0000-cover-letter.patch
In general, a single-patch submission does not need a separate cover
letter. For a multi-patch series like this one, however, we prefer a
cover letter that provides an overview of the whole series.
>
> Signed-off-by: Jian Cai <lingqian_gi@163.com>
> ---
> MAINTAINERS | 5 +++
> hw/riscv/k230_sram.c | 81 ++++++++++++++++++++++++++++++++++++
> include/hw/riscv/k230_sram.h | 35 ++++++++++++++++
> 3 files changed, 121 insertions(+)
> create mode 100644 hw/riscv/k230_sram.c
> create mode 100644 include/hw/riscv/k230_sram.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6171cc7494..3567563ba6 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1825,6 +1825,11 @@ L: qemu-riscv@nongnu.org
> S: Maintained
> 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: hw/riscv/k230_sram.c
> +F: include/hw/riscv/k230_sram.h
> +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/hw/riscv/k230_sram.c b/hw/riscv/k230_sram.c
> new file mode 100644
> index 0000000000..1d960e733e
> --- /dev/null
> +++ b/hw/riscv/k230_sram.c
> @@ -0,0 +1,81 @@
> +/*
> + * K230 SRAM Controller
> + *
> + * 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 (2 MB at 0x80200000) has no software-visible
> + * controller registers. This device wraps the SRAM as a SysBusDevice
> + * so that it appears in the QOM tree, supports migration (VMState),
> + * and can be introspected by management tools.
> + *
> + * Clock gating is controlled by the CMU at 0x91100000 (shrm_CLK_CFG,
> + * offset 0x5c, bit 10: sram_aclk_enable). Reset is controlled by the
> + * RMU at 0x91101000 (SRAM_RST_TIM/SRAM_RST_CTL, offsets 0x60/0x64).
> + * Those peripherals are not modelled yet, so SRAM is always enabled
> + * in the current QEMU implementation.
> + *
> + * Copyright (c) 2026 Jian Cai <lingqian_gi@163.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
We probably don't need to create a dedicated device model for SRAM.
It can actually be replaced directly by using a QEMU memory region RAM.
A simpler approach would be to keep this code in k230.c, perhaps in a
helper function such as k230_sram_create().
Thanks,
Chao
> +
> +#include "qemu/osdep.h"
> +#include "qemu/units.h"
> +#include "hw/core/sysbus.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +#include "hw/riscv/k230_sram.h"
> +
> +static void k230_sram_realize(DeviceState *dev, Error **errp)
> +{
> + K230SramState *s = K230_SRAM(dev);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +
> + memory_region_init_ram(&s->sram, OBJECT(dev), "k230.sram",
> + 2 * MiB, &error_fatal);
> + sysbus_init_mmio(sbd, &s->sram);
> +}
> +
> +static void k230_sram_reset_hold(Object *obj, ResetType type)
> +{
> + /*
> + * No software-visible registers to reset. SRAM content is preserved
> + * across warm reset on real hardware; a cold reset would clear it,
> + * but QEMU memory_region_init_ram already zeroes the region on init.
> + */
> +}
> +
> +static const VMStateDescription vmstate_k230_sram = {
> + .name = "k230.sram",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (const VMStateField[]) {
> + VMSTATE_END_OF_LIST()
> + },
> +};
> +
> +static void k230_sram_class_init(ObjectClass *klass, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + ResettableClass *rc = RESETTABLE_CLASS(klass);
> +
> + dc->realize = k230_sram_realize;
> + rc->phases.hold = k230_sram_reset_hold;
> + dc->vmsd = &vmstate_k230_sram;
> + dc->desc = "K230 SRAM";
> +}
> +
> +static const TypeInfo k230_sram_info = {
> + .name = TYPE_K230_SRAM,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(K230SramState),
> + .class_init = k230_sram_class_init,
> +};
> +
> +static void k230_sram_register_type(void)
> +{
> + type_register_static(&k230_sram_info);
> +}
> +
> +type_init(k230_sram_register_type)
> diff --git a/include/hw/riscv/k230_sram.h b/include/hw/riscv/k230_sram.h
> new file mode 100644
> index 0000000000..6d15970ab9
> --- /dev/null
> +++ b/include/hw/riscv/k230_sram.h
> @@ -0,0 +1,35 @@
> +/*
> + * K230 SRAM Controller
> + *
> + * 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 (2 MB at 0x80200000) has no software-visible
> + * controller registers: it is a pure on-chip RAM block accessed directly
> + * via the AXI bus. Clock gating (CMU at 0x91100000, offset 0x5c) and
> + * reset control (RMU at 0x91101000, offsets 0x60/0x64) are handled by
> + * separate system-controller peripherals and are not modelled here yet.
> + *
> + * Copyright (c) 2026 Jian Cai <lingqian_gi@163.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef K230_SRAM_H
> +#define K230_SRAM_H
> +
> +#include "hw/core/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_K230_SRAM "riscv.k230.sram"
> +OBJECT_DECLARE_SIMPLE_TYPE(K230SramState, K230_SRAM)
> +
> +struct K230SramState {
> + /*< private >*/
> + SysBusDevice parent_obj;
> +
> + /*< public >*/
> + MemoryRegion sram; /* 2 MB SRAM storage */
> +};
> +
> +#endif /* K230_SRAM_H */
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v2] hw/riscv/k230: add k230_sram_create() helper function
2026-07-20 7:45 ` [RFC PATCH 1/3] hw/riscv: add K230 SRAM device model Jian Cai
2026-07-20 9:42 ` Chao Liu
@ 2026-07-21 6:04 ` Jian Cai
1 sibling, 0 replies; 5+ messages in thread
From: Jian Cai @ 2026-07-21 6:04 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: chao.liu, palmer, alistair.francis, liwei1518, daniel.barboza,
zhiwei_liu, Jian Cai
The K230 shared SRAM (2 MB at 0x80200000) has no software-visible
controller registers: it is a pure on-chip RAM block accessed via
the AXI bus. Replace the inline memory_region_init_ram calls in
k230_soc_realize() with a static k230_sram_create() helper, which
follows the same pattern as the existing k230_create_plic() and
k230_create_uart() helpers.
Also fix two non-ASCII characters (registered sign and em-dash)
in k230.rst that would cause git send-email to reject the patch
as 8-bit.
Reference:
K230 TRM V0.3.1 (2024-11-18), Section 5.2 Sram
https://github.com/revyos/external-docs/blob/master/K230/en-us/
K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
Signed-off-by: Jian Cai <lingqian_gi@163.com>
---
Changes in v2:
- Dropped SysBusDevice model per Chao Liu's review; use a static helper
function k230_sram_create() in k230.c instead.
- Removed k230_sram.c, k230_sram.h, and k230-sram-test.c.
- Fixed two non-ASCII characters (registered sign, em-dash) in k230.rst.
- Removed SRAM entries from MAINTAINERS (no new files added).
- v1: [RFC PATCH 0/3] hw/riscv: add K230 SRAM device model
https://lore.kernel.org/qemu-devel/
docs/system/riscv/k230.rst | 3 ++-
hw/riscv/k230.c | 14 ++++++++++----
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
index cea8202e55..18eb6806f6 100644
--- a/docs/system/riscv/k230.rst
+++ b/docs/system/riscv/k230.rst
@@ -2,7 +2,7 @@ Kendryte K230 virt reference platform (``k230``)
==========================================================================
The ``k230`` machine is compatible with the Kendryte K230 SDK.
-The K230 is a chip from the AIoT SoC series made by Kendryte ® — a part of
+The K230 is a chip from the AIoT SoC series made by Kendryte (R) -- a part of
Canaan Inc. It uses a brand-new multi-heterogeneous unit accelerated computing
structure.
@@ -111,3 +111,4 @@ this machine does not emulate those controllers yet. Replace ``${INITRD_END}``
with the host-calculated value above when typing the command. ``cma=0`` avoids
the SDK kernel reserving too much of the little-core memory window for initramfs
boot.
+
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
index 656f28190c..96add64c2a 100644
--- a/hw/riscv/k230.c
+++ b/hw/riscv/k230.c
@@ -14,6 +14,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "cpu-qom.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
@@ -151,6 +152,14 @@ static void k230_create_uart(MemoryRegion *sys_mem, DeviceState *plic,
399193, serial_hd(index), DEVICE_LITTLE_ENDIAN);
}
+static void k230_sram_create(K230SoCState *s)
+{
+ memory_region_init_ram(&s->sram, OBJECT(s), "k230.sram",
+ memmap[K230_DEV_SRAM].size, &error_fatal);
+ memory_region_add_subregion(get_system_memory(),
+ memmap[K230_DEV_SRAM].base, &s->sram);
+}
+
static void k230_soc_realize(DeviceState *dev, Error **errp)
{
K230SoCState *s = RISCV_K230_SOC(dev);
@@ -162,10 +171,7 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
c908_cpus = s->c908_cpu.num_harts;
/* SRAM */
- memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
- memmap[K230_DEV_SRAM].size, &error_fatal);
- memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
- &s->sram);
+ k230_sram_create(s);
/* BootROM */
memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH 2/3] hw/riscv/k230: integrate SRAM device into SoC
[not found] <20260720074545.8987-1-lingqian_gi@163.com>
2026-07-20 7:45 ` [RFC PATCH 1/3] hw/riscv: add K230 SRAM device model Jian Cai
@ 2026-07-20 7:45 ` Jian Cai
2026-07-20 7:45 ` [RFC PATCH 3/3] tests/qtest: add K230 SRAM qtest Jian Cai
2 siblings, 0 replies; 5+ messages in thread
From: Jian Cai @ 2026-07-20 7:45 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: chao.liu, palmer, alistair.francis, liwei1518, daniel.barboza,
zhiwei_liu
Replace the bare memory_region_init_ram() in k230_soc_realize()
with a proper SysBusDevice. Wire up object_initialize_child()
in k230_soc_init(), call sysbus_realize() and sysbus_mmio_map()
in k230_soc_realize(), and add the Kconfig + meson.build entries.
Update docs/system/riscv/k230.rst.
Signed-off-by: Jian Cai <lingqian_gi@163.com>
---
docs/system/riscv/k230.rst | 8 ++++++++
hw/riscv/Kconfig | 4 ++++
hw/riscv/k230.c | 9 +++++----
hw/riscv/meson.build | 1 +
include/hw/riscv/k230.h | 3 ++-
5 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
index cea8202e55..a7668fa065 100644
--- a/docs/system/riscv/k230.rst
+++ b/docs/system/riscv/k230.rst
@@ -111,3 +111,11 @@ this machine does not emulate those controllers yet. Replace ``${INITRD_END}``
with the host-calculated value above when typing the command. ``cma=0`` avoids
the SDK kernel reserving too much of the little-core memory window for initramfs
boot.
+
+SRAM
+~~~~
+
+The K230 shared SRAM is a 2 MB on-chip RAM block at ``0x80200000``. It has no
+software-visible controller registers -- the region is accessed directly via the
+AXI bus. Clock gating and reset control are handled by separate
+system-controller peripherals (CMU and RMU).
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index de37c08cae..ee48ea530d 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -142,6 +142,9 @@ config XIANGSHAN_KUNMINGHU
select RISCV_IMSIC
select SERIAL_MM
+config K230_SRAM
+ bool
+
config MIPS_BOSTON_AIA
bool
default y
@@ -161,4 +164,5 @@ config K230
select RISCV_IMSIC
select SERIAL_MM
select UNIMP
+ select K230_SRAM
select K230_WDT
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
index 656f28190c..3469a9d43b 100644
--- a/hw/riscv/k230.c
+++ b/hw/riscv/k230.c
@@ -110,6 +110,7 @@ static void k230_soc_init(Object *obj)
object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
+ object_initialize_child(obj, "k230-sram", &s->sram, TYPE_K230_SRAM);
qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
@@ -162,10 +163,10 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
c908_cpus = s->c908_cpu.num_harts;
/* SRAM */
- memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
- memmap[K230_DEV_SRAM].size, &error_fatal);
- memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
- &s->sram);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sram), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sram), 0, memmap[K230_DEV_SRAM].base);
/* BootROM */
memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 0d82ceacc4..80b7455141 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -20,5 +20,6 @@ riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c
riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c'))
riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c'))
riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
+riscv_ss.add(when: 'CONFIG_K230_SRAM', if_true: files('k230_sram.c'))
hw_arch += {'riscv': riscv_ss}
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
index 592e1c26bf..9f7baa513c 100644
--- a/include/hw/riscv/k230.h
+++ b/include/hw/riscv/k230.h
@@ -18,6 +18,7 @@
#include "hw/core/boards.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/watchdog/k230_wdt.h"
+#include "hw/riscv/k230_sram.h"
#define C908_CPU_HARTID (0)
@@ -33,7 +34,7 @@ typedef struct K230SoCState {
RISCVHartArrayState c908_cpu; /* Small core */
K230WdtState wdt[2];
- MemoryRegion sram;
+ K230SramState sram;
MemoryRegion bootrom;
DeviceState *c908_plic;
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [RFC PATCH 3/3] tests/qtest: add K230 SRAM qtest
[not found] <20260720074545.8987-1-lingqian_gi@163.com>
2026-07-20 7:45 ` [RFC PATCH 1/3] hw/riscv: add K230 SRAM device model Jian Cai
2026-07-20 7:45 ` [RFC PATCH 2/3] hw/riscv/k230: integrate SRAM device into SoC Jian Cai
@ 2026-07-20 7:45 ` Jian Cai
2 siblings, 0 replies; 5+ messages in thread
From: Jian Cai @ 2026-07-20 7:45 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: chao.liu, palmer, alistair.francis, liwei1518, daniel.barboza,
zhiwei_liu
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 <lingqian_gi@163.com>
---
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 <lingqian_gi@163.com>
+ *
+ * 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
^ permalink raw reply related [flat|nested] 5+ messages in thread