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.