[PATCH v7 8/8] tests/tcg/riscv64: Add test for Zicclsm

[email protected]
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <[email protected]>
From: Frank Chang <[email protected]>

Cover scalar, floating-point, vector, and segmented misaligned accesses
with Zicclsm enabled and disabled. Clean up both generated test
binaries.

To build and run the tests:

    make -C build/tests/tcg/riscv64-softmmu \
        CC=riscv64-unknown-elf-gcc LD=riscv64-unknown-elf-ld \
        test-zicclsm test-zicclsm-off

    make -C build/tests/tcg/riscv64-softmmu \
        run-test-zicclsm run-test-zicclsm-off

To clean the generated binaries and objects:

    make -C build/tests/tcg/riscv64-softmmu clean

Signed-off-by: Frank Chang <[email protected]>
---
 tests/tcg/riscv64/Makefile.softmmu-target |  22 ++
 tests/tcg/riscv64/test-zicclsm.S          | 368 ++++++++++++++++++++++
 2 files changed, 390 insertions(+)
 create mode 100644 tests/tcg/riscv64/test-zicclsm.S

diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
index 82be8a2c915..908fd008e4c 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -41,5 +41,27 @@ comma:= ,
 run-test-crc32: test-crc32
 	$(call run-test, $<, $(QEMU) -cpu rv64$(comma)xlrbr=true $(QEMU_OPTS)$<)
 
+# Zicclsm: misaligned load/store support. Assemble one source twice: the
+# default build expects every misaligned access to succeed (zicclsm=true),
+# the -DZICCLSM_DISABLED build expects every one to trap (zicclsm=false).
+ZICCLSM_MARCH = -march=rv64gcv_zfh
+CLEANFILES += test-zicclsm test-zicclsm-off
+
+test-zicclsm: test-zicclsm.S $(LINK_SCRIPT)
+	$(CC) $(CFLAGS) $(ZICCLSM_MARCH) $< -Wa,--noexecstack -c -o test-zicclsm.o
+	$(LD) $(LDFLAGS) test-zicclsm.o -o $@
+
+test-zicclsm-off: test-zicclsm.S $(LINK_SCRIPT)
+	$(CC) $(CFLAGS) $(ZICCLSM_MARCH) -DZICCLSM_DISABLED $< -Wa,--noexecstack -c -o test-zicclsm-off.o
+	$(LD) $(LDFLAGS) test-zicclsm-off.o -o $@
+
+EXTRA_RUNS += run-test-zicclsm
+run-test-zicclsm: test-zicclsm
+	$(call run-test, $<, $(QEMU) -cpu rv64$(comma)v=true$(comma)zfh=true$(comma)zicclsm=true $(QEMU_OPTS)$<)
+
+EXTRA_RUNS += run-test-zicclsm-off
+run-test-zicclsm-off: test-zicclsm-off
+	$(call run-test, $<, $(QEMU) -cpu rv64$(comma)v=true$(comma)zfh=true$(comma)zicclsm=false $(QEMU_OPTS)$<)
+
 # We don't currently support the multiarch system tests
 undefine MULTIARCH_TESTS
diff --git a/tests/tcg/riscv64/test-zicclsm.S b/tests/tcg/riscv64/test-zicclsm.S
new file mode 100644
index 00000000000..a2f217c0d1e
--- /dev/null
+++ b/tests/tcg/riscv64/test-zicclsm.S
@@ -0,0 +1,368 @@
+/*
+ * Test the Zicclsm extension (misaligned load/store support).
+ *
+ * This single source is assembled twice:
+ *   - test-zicclsm      : run on a CPU with zicclsm=true. Every misaligned
+ *                         scalar integer, floating-point and vector
+ *                         load/store must complete WITHOUT raising a trap.
+ *   - test-zicclsm-off  : built with -DZICCLSM_DISABLED and run on a CPU with
+ *                         zicclsm=false. Every misaligned access must raise a
+ *                         misaligned load/store exception, with the correct
+ *                         mcause and mtval.
+ *
+ * Zicclsm governs all regular scalar loads/stores (integer and F/D/Zfh
+ * floating-point) as well as vector element loads/stores.  Floating-point
+ * loads/stores (flh/flw/fld, fsh/fsw/fsd) are therefore exercised here.
+ *
+ * Atomic (A/Zacas/...) accesses are intentionally excluded: they always
+ * require natural alignment regardless of Zicclsm.  Likewise cm.push/cm.pop
+ * (Zcmp) are excluded, as they are not regular loads/stores.
+ *
+ * Register conventions (persist across the whole test; the trap handler only
+ * clobbers t0-t4):
+ *   s1 = expected mcause for the pending misaligned access
+ *   s2 = expected mtval (the misaligned address)
+ *   s3 = trap counter (incremented by the handler)
+ *   s4 = base address of the aligned data buffer
+ *   s5 = snapshot of s3 taken before an access, used to check the delta
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+	.option	norelax
+	.option	norvc
+
+/* RISC-V exception causes (see target/riscv/cpu_bits.h). */
+#define CAUSE_LOAD_MISALIGNED	0x4
+#define CAUSE_STORE_MISALIGNED	0x6
+
+/*
+ * EXPECT sets up the expectation for the access that immediately follows and
+ * snapshots the trap counter.
+ *   \cause = expected mcause if the access traps
+ *   \off   = byte offset from the buffer base; also the expected mtval
+ */
+	.macro	EXPECT cause, off
+	li	s1, \cause
+	addi	s2, s4, \off
+	mv	s5, s3
+	.endm
+
+/*
+ * CHECK validates the outcome of the preceding access.
+ *   - When Zicclsm is disabled, exactly one trap must have fired.
+ *   - When Zicclsm is enabled, no trap must have fired.
+ */
+	.macro	CHECK
+#ifdef ZICCLSM_DISABLED
+	addi	s5, s5, 1
+	bne	s3, s5, fail
+#else
+	bne	s3, s5, fail
+#endif
+	.endm
+
+/* In the enabled case, also verify the value returned by scalar loads. */
+	.macro	CHECK_VALUE value
+#ifndef ZICCLSM_DISABLED
+	li	t0, \value
+	bne	a2, t0, fail
+#endif
+	.endm
+
+/* Verify bytes written by an enabled scalar store. */
+	.macro	CHECK_BYTE off, value
+#ifndef ZICCLSM_DISABLED
+	lbu	t0, \off(s4)
+	li	t1, \value
+	bne	t0, t1, fail
+#endif
+	.endm
+
+	.text
+	.global	_start
+_start:
+	/* Install the trap handler. */
+	lla	t0, trap
+	csrw	mtvec, t0
+
+	/* Enable the FP (FS) and Vector (VS) unit state so F/D/V instructions
+	 * do not trap as illegal. 0x6600 = FS[14:13]=11 | VS[10:9]=11. */
+	li	t0, 0x6600
+	csrs	mstatus, t0
+
+	/* Initialise persistent state. */
+	li	s3, 0			/* trap counter */
+	lla	s4, buf			/* aligned buffer base */
+
+	/*
+	 * ---- Scalar integer loads ----
+	 * lh/lhu need 2-byte alignment; lw/lwu 4-byte; ld 8-byte.
+	 */
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	lh	a2, 1(s4)
+	CHECK
+	CHECK_VALUE 0x2211
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	lhu	a2, 1(s4)
+	CHECK
+	CHECK_VALUE 0x2211
+
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	lw	a2, 1(s4)
+	CHECK
+	CHECK_VALUE 0x44332211
+	EXPECT	CAUSE_LOAD_MISALIGNED, 3
+	lw	a2, 3(s4)
+	CHECK
+	CHECK_VALUE 0x66554433
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	lwu	a2, 1(s4)
+	CHECK
+	CHECK_VALUE 0x44332211
+
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	ld	a2, 1(s4)
+	CHECK
+	CHECK_VALUE 0x8877665544332211
+	EXPECT	CAUSE_LOAD_MISALIGNED, 3
+	ld	a2, 3(s4)
+	CHECK
+	CHECK_VALUE 0xaa99887766554433
+	EXPECT	CAUSE_LOAD_MISALIGNED, 7
+	ld	a2, 7(s4)
+	CHECK
+	CHECK_VALUE 0xeeddccbbaa998877
+
+	/*
+	 * ---- Scalar integer stores ----
+	 */
+	li	t6, 0x1122334455667788
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	sh	t6, 1(s4)
+	CHECK
+	CHECK_BYTE 1, 0x88
+	CHECK_BYTE 2, 0x77
+
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	sw	t6, 1(s4)
+	CHECK
+	CHECK_BYTE 1, 0x88
+	CHECK_BYTE 2, 0x77
+	CHECK_BYTE 3, 0x66
+	CHECK_BYTE 4, 0x55
+	EXPECT	CAUSE_STORE_MISALIGNED, 3
+	sw	t6, 3(s4)
+	CHECK
+	CHECK_BYTE 3, 0x88
+	CHECK_BYTE 4, 0x77
+	CHECK_BYTE 5, 0x66
+	CHECK_BYTE 6, 0x55
+
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	sd	t6, 1(s4)
+	CHECK
+	CHECK_BYTE 1, 0x88
+	CHECK_BYTE 2, 0x77
+	CHECK_BYTE 3, 0x66
+	CHECK_BYTE 4, 0x55
+	CHECK_BYTE 5, 0x44
+	CHECK_BYTE 6, 0x33
+	CHECK_BYTE 7, 0x22
+	CHECK_BYTE 8, 0x11
+	EXPECT	CAUSE_STORE_MISALIGNED, 7
+	sd	t6, 7(s4)
+	CHECK
+	CHECK_BYTE 7, 0x88
+	CHECK_BYTE 8, 0x77
+	CHECK_BYTE 9, 0x66
+	CHECK_BYTE 10, 0x55
+	CHECK_BYTE 11, 0x44
+	CHECK_BYTE 12, 0x33
+	CHECK_BYTE 13, 0x22
+	CHECK_BYTE 14, 0x11
+
+	/*
+	 * ---- Floating-point loads ----
+	 * flh needs 2-byte alignment; flw 4-byte; fld 8-byte.  Their alignment
+	 * is governed by Zicclsm just like the scalar integer forms.
+	 */
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	flh	fa0, 1(s4)
+	CHECK
+
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	flw	fa0, 1(s4)
+	CHECK
+	EXPECT	CAUSE_LOAD_MISALIGNED, 3
+	flw	fa0, 3(s4)
+	CHECK
+
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	fld	fa0, 1(s4)
+	CHECK
+	EXPECT	CAUSE_LOAD_MISALIGNED, 7
+	fld	fa0, 7(s4)
+	CHECK
+
+	/*
+	 * ---- Floating-point stores ----
+	 */
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	fsh	fa0, 1(s4)
+	CHECK
+
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	fsw	fa0, 1(s4)
+	CHECK
+	EXPECT	CAUSE_STORE_MISALIGNED, 3
+	fsw	fa0, 3(s4)
+	CHECK
+
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	fsd	fa0, 1(s4)
+	CHECK
+	EXPECT	CAUSE_STORE_MISALIGNED, 7
+	fsd	fa0, 7(s4)
+	CHECK
+
+	/*
+	 * ---- Vector unit-stride loads / stores ----
+	 * A base address that is not aligned to the element size (SEW) is
+	 * misaligned for the first element access.
+	 */
+	vsetvli	t1, x0, e16, m1, ta, ma
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	addi	a0, s4, 1
+	vle16.v	v0, (a0)
+	CHECK
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	addi	a0, s4, 1
+	vse16.v	v0, (a0)
+	CHECK
+
+	vsetvli	t1, x0, e32, m1, ta, ma
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	addi	a0, s4, 1
+	vle32.v	v0, (a0)
+	CHECK
+	EXPECT	CAUSE_STORE_MISALIGNED, 3
+	addi	a0, s4, 3
+	vse32.v	v0, (a0)
+	CHECK
+
+	vsetvli	t1, x0, e64, m1, ta, ma
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	addi	a0, s4, 1
+	vle64.v	v0, (a0)
+	CHECK
+	EXPECT	CAUSE_STORE_MISALIGNED, 7
+	addi	a0, s4, 7
+	vse64.v	v0, (a0)
+	CHECK
+
+	/*
+	 * ---- Vector strided loads / stores ----
+	 */
+	vsetvli	t1, x0, e32, m1, ta, ma
+	li	a1, 8			/* stride in bytes */
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	addi	a0, s4, 1
+	vlse32.v	v0, (a0), a1
+	CHECK
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	addi	a0, s4, 1
+	vsse32.v	v0, (a0), a1
+	CHECK
+
+	/* ---- Vector indexed loads / stores ---- */
+	/*
+	 * Zero indices keep the first element at the deliberately misaligned base.
+	 */
+	vmv.v.i	v1, 0
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	addi	a0, s4, 1
+	vluxei32.v	v0, (a0), v1
+	CHECK
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	addi	a0, s4, 1
+	vsuxei32.v	v0, (a0), v1
+	CHECK
+
+	/* ---- Vector segmented loads / stores ---- */
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	addi	a0, s4, 1
+	vlseg2e32.v	v0, (a0)
+	CHECK
+	EXPECT	CAUSE_STORE_MISALIGNED, 1
+	addi	a0, s4, 1
+	vsseg2e32.v	v0, (a0)
+	CHECK
+
+	/*
+	 * ---- Vector whole-register load ----
+	 * Only the whole-register *load* forms carry an element width
+	 * (vl1re32.v => EEW=32), so only they enforce alignment when Zicclsm is
+	 * off.  The whole-register store form (vs1r.v) is defined as EEW=8
+	 * (byte granular) and therefore never faults on misalignment, so it is
+	 * not exercised here.
+	 */
+	EXPECT	CAUSE_LOAD_MISALIGNED, 1
+	addi	a0, s4, 1
+	vl1re32.v	v1, (a0)
+	CHECK
+
+	/* Success. */
+	li	a0, 0
+	j	_exit
+
+	/*
+	 * Trap handler: validate mcause and mtval against the expectation, bump
+	 * the trap counter, then skip past the faulting instruction.  The
+	 * instruction length is decoded from its low two bits (0b11 => 4 bytes,
+	 * otherwise a 2-byte compressed instruction).
+	 */
+	.balign	4
+trap:
+	csrr	t0, mcause
+	bne	t0, s1, fail
+	csrr	t1, mtval
+	bne	t1, s2, fail
+	addi	s3, s3, 1
+
+	csrr	t0, mepc
+	lhu	t2, 0(t0)
+	andi	t3, t2, 3
+	li	t4, 3
+	bne	t3, t4, 1f
+	addi	t0, t0, 4		/* 32-bit instruction */
+	j	2f
+1:
+	addi	t0, t0, 2		/* 16-bit compressed instruction */
+2:
+	csrw	mepc, t0
+	mret
+
+fail:
+	li	a0, 1
+_exit:
+	lla	a1, semiargs
+	li	t0, 0x20026		/* ADP_Stopped_ApplicationExit */
+	sd	t0, 0(a1)
+	sd	a0, 8(a1)
+	li	a0, 0x20		/* TARGET_SYS_EXIT_EXTENDED */
+	.balign	16
+	slli	zero, zero, 0x1f
+	ebreak
+	srai	zero, zero, 0x7
+	j	.
+
+	.data
+	.balign	16
+semiargs:
+	.space	16
+	.balign	64
+buf:
+	.byte	0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
+	.byte	0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+	.space	240
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.