@samitouri / QOSamiQemu / commits / efb3db2688

tests/tcg/riscv64: Add test for Zicclsm

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 <frank.chang@sifive.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260810055618.1175500-8-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Frank Chang committed Aug 10, 2026 at 13:56 UTC efb3db26887d7c8c515048019bd71d405173a59d
2 files changed +390
tests/tcg/riscv64/Makefile.softmmu-target
+22
@@ -41,5 +41,27 @@ comma:= ,
41 run-test-crc32: test-crc32
42 $(call run-test, $<, $(QEMU) -cpu rv64$(comma)xlrbr=true $(QEMU_OPTS)$<)
43
44 +# Zicclsm: misaligned load/store support. Assemble one source twice: the
45 +# default build expects every misaligned access to succeed (zicclsm=true),
46 +# the -DZICCLSM_DISABLED build expects every one to trap (zicclsm=false).
47 +ZICCLSM_MARCH = -march=rv64gcv_zfh
48 +CLEANFILES += test-zicclsm test-zicclsm-off
49 +
50 +test-zicclsm: test-zicclsm.S $(LINK_SCRIPT)
51 + $(CC) $(CFLAGS) $(ZICCLSM_MARCH) $< -Wa,--noexecstack -c -o test-zicclsm.o
52 + $(LD) $(LDFLAGS) test-zicclsm.o -o $@
53 +
54 +test-zicclsm-off: test-zicclsm.S $(LINK_SCRIPT)
55 + $(CC) $(CFLAGS) $(ZICCLSM_MARCH) -DZICCLSM_DISABLED $< -Wa,--noexecstack -c -o test-zicclsm-off.o
56 + $(LD) $(LDFLAGS) test-zicclsm-off.o -o $@
57 +
58 +EXTRA_RUNS += run-test-zicclsm
59 +run-test-zicclsm: test-zicclsm
60 + $(call run-test, $<, $(QEMU) -cpu rv64$(comma)v=true$(comma)zfh=true$(comma)zicclsm=true $(QEMU_OPTS)$<)
61 +
62 +EXTRA_RUNS += run-test-zicclsm-off
63 +run-test-zicclsm-off: test-zicclsm-off
64 + $(call run-test, $<, $(QEMU) -cpu rv64$(comma)v=true$(comma)zfh=true$(comma)zicclsm=false $(QEMU_OPTS)$<)
65 +
66 # We don't currently support the multiarch system tests
67 undefine MULTIARCH_TESTS
tests/tcg/riscv64/test-zicclsm.S new
+368
@@ -0,0 +1,368 @@
1 +/*
2 + * Test the Zicclsm extension (misaligned load/store support).
3 + *
4 + * This single source is assembled twice:
5 + * - test-zicclsm : run on a CPU with zicclsm=true. Every misaligned
6 + * scalar integer, floating-point and vector
7 + * load/store must complete WITHOUT raising a trap.
8 + * - test-zicclsm-off : built with -DZICCLSM_DISABLED and run on a CPU with
9 + * zicclsm=false. Every misaligned access must raise a
10 + * misaligned load/store exception, with the correct
11 + * mcause and mtval.
12 + *
13 + * Zicclsm governs all regular scalar loads/stores (integer and F/D/Zfh
14 + * floating-point) as well as vector element loads/stores. Floating-point
15 + * loads/stores (flh/flw/fld, fsh/fsw/fsd) are therefore exercised here.
16 + *
17 + * Atomic (A/Zacas/...) accesses are intentionally excluded: they always
18 + * require natural alignment regardless of Zicclsm. Likewise cm.push/cm.pop
19 + * (Zcmp) are excluded, as they are not regular loads/stores.
20 + *
21 + * Register conventions (persist across the whole test; the trap handler only
22 + * clobbers t0-t4):
23 + * s1 = expected mcause for the pending misaligned access
24 + * s2 = expected mtval (the misaligned address)
25 + * s3 = trap counter (incremented by the handler)
26 + * s4 = base address of the aligned data buffer
27 + * s5 = snapshot of s3 taken before an access, used to check the delta
28 + *
29 + * SPDX-License-Identifier: GPL-2.0-or-later
30 + */
31 +
32 + .option norelax
33 + .option norvc
34 +
35 +/* RISC-V exception causes (see target/riscv/cpu_bits.h). */
36 +#define CAUSE_LOAD_MISALIGNED 0x4
37 +#define CAUSE_STORE_MISALIGNED 0x6
38 +
39 +/*
40 + * EXPECT sets up the expectation for the access that immediately follows and
41 + * snapshots the trap counter.
42 + * \cause = expected mcause if the access traps
43 + * \off = byte offset from the buffer base; also the expected mtval
44 + */
45 + .macro EXPECT cause, off
46 + li s1, \cause
47 + addi s2, s4, \off
48 + mv s5, s3
49 + .endm
50 +
51 +/*
52 + * CHECK validates the outcome of the preceding access.
53 + * - When Zicclsm is disabled, exactly one trap must have fired.
54 + * - When Zicclsm is enabled, no trap must have fired.
55 + */
56 + .macro CHECK
57 +#ifdef ZICCLSM_DISABLED
58 + addi s5, s5, 1
59 + bne s3, s5, fail
60 +#else
61 + bne s3, s5, fail
62 +#endif
63 + .endm
64 +
65 +/* In the enabled case, also verify the value returned by scalar loads. */
66 + .macro CHECK_VALUE value
67 +#ifndef ZICCLSM_DISABLED
68 + li t0, \value
69 + bne a2, t0, fail
70 +#endif
71 + .endm
72 +
73 +/* Verify bytes written by an enabled scalar store. */
74 + .macro CHECK_BYTE off, value
75 +#ifndef ZICCLSM_DISABLED
76 + lbu t0, \off(s4)
77 + li t1, \value
78 + bne t0, t1, fail
79 +#endif
80 + .endm
81 +
82 + .text
83 + .global _start
84 +_start:
85 + /* Install the trap handler. */
86 + lla t0, trap
87 + csrw mtvec, t0
88 +
89 + /* Enable the FP (FS) and Vector (VS) unit state so F/D/V instructions
90 + * do not trap as illegal. 0x6600 = FS[14:13]=11 | VS[10:9]=11. */
91 + li t0, 0x6600
92 + csrs mstatus, t0
93 +
94 + /* Initialise persistent state. */
95 + li s3, 0 /* trap counter */
96 + lla s4, buf /* aligned buffer base */
97 +
98 + /*
99 + * ---- Scalar integer loads ----
100 + * lh/lhu need 2-byte alignment; lw/lwu 4-byte; ld 8-byte.
101 + */
102 + EXPECT CAUSE_LOAD_MISALIGNED, 1
103 + lh a2, 1(s4)
104 + CHECK
105 + CHECK_VALUE 0x2211
106 + EXPECT CAUSE_LOAD_MISALIGNED, 1
107 + lhu a2, 1(s4)
108 + CHECK
109 + CHECK_VALUE 0x2211
110 +
111 + EXPECT CAUSE_LOAD_MISALIGNED, 1
112 + lw a2, 1(s4)
113 + CHECK
114 + CHECK_VALUE 0x44332211
115 + EXPECT CAUSE_LOAD_MISALIGNED, 3
116 + lw a2, 3(s4)
117 + CHECK
118 + CHECK_VALUE 0x66554433
119 + EXPECT CAUSE_LOAD_MISALIGNED, 1
120 + lwu a2, 1(s4)
121 + CHECK
122 + CHECK_VALUE 0x44332211
123 +
124 + EXPECT CAUSE_LOAD_MISALIGNED, 1
125 + ld a2, 1(s4)
126 + CHECK
127 + CHECK_VALUE 0x8877665544332211
128 + EXPECT CAUSE_LOAD_MISALIGNED, 3
129 + ld a2, 3(s4)
130 + CHECK
131 + CHECK_VALUE 0xaa99887766554433
132 + EXPECT CAUSE_LOAD_MISALIGNED, 7
133 + ld a2, 7(s4)
134 + CHECK
135 + CHECK_VALUE 0xeeddccbbaa998877
136 +
137 + /*
138 + * ---- Scalar integer stores ----
139 + */
140 + li t6, 0x1122334455667788
141 + EXPECT CAUSE_STORE_MISALIGNED, 1
142 + sh t6, 1(s4)
143 + CHECK
144 + CHECK_BYTE 1, 0x88
145 + CHECK_BYTE 2, 0x77
146 +
147 + EXPECT CAUSE_STORE_MISALIGNED, 1
148 + sw t6, 1(s4)
149 + CHECK
150 + CHECK_BYTE 1, 0x88
151 + CHECK_BYTE 2, 0x77
152 + CHECK_BYTE 3, 0x66
153 + CHECK_BYTE 4, 0x55
154 + EXPECT CAUSE_STORE_MISALIGNED, 3
155 + sw t6, 3(s4)
156 + CHECK
157 + CHECK_BYTE 3, 0x88
158 + CHECK_BYTE 4, 0x77
159 + CHECK_BYTE 5, 0x66
160 + CHECK_BYTE 6, 0x55
161 +
162 + EXPECT CAUSE_STORE_MISALIGNED, 1
163 + sd t6, 1(s4)
164 + CHECK
165 + CHECK_BYTE 1, 0x88
166 + CHECK_BYTE 2, 0x77
167 + CHECK_BYTE 3, 0x66
168 + CHECK_BYTE 4, 0x55
169 + CHECK_BYTE 5, 0x44
170 + CHECK_BYTE 6, 0x33
171 + CHECK_BYTE 7, 0x22
172 + CHECK_BYTE 8, 0x11
173 + EXPECT CAUSE_STORE_MISALIGNED, 7
174 + sd t6, 7(s4)
175 + CHECK
176 + CHECK_BYTE 7, 0x88
177 + CHECK_BYTE 8, 0x77
178 + CHECK_BYTE 9, 0x66
179 + CHECK_BYTE 10, 0x55
180 + CHECK_BYTE 11, 0x44
181 + CHECK_BYTE 12, 0x33
182 + CHECK_BYTE 13, 0x22
183 + CHECK_BYTE 14, 0x11
184 +
185 + /*
186 + * ---- Floating-point loads ----
187 + * flh needs 2-byte alignment; flw 4-byte; fld 8-byte. Their alignment
188 + * is governed by Zicclsm just like the scalar integer forms.
189 + */
190 + EXPECT CAUSE_LOAD_MISALIGNED, 1
191 + flh fa0, 1(s4)
192 + CHECK
193 +
194 + EXPECT CAUSE_LOAD_MISALIGNED, 1
195 + flw fa0, 1(s4)
196 + CHECK
197 + EXPECT CAUSE_LOAD_MISALIGNED, 3
198 + flw fa0, 3(s4)
199 + CHECK
200 +
201 + EXPECT CAUSE_LOAD_MISALIGNED, 1
202 + fld fa0, 1(s4)
203 + CHECK
204 + EXPECT CAUSE_LOAD_MISALIGNED, 7
205 + fld fa0, 7(s4)
206 + CHECK
207 +
208 + /*
209 + * ---- Floating-point stores ----
210 + */
211 + EXPECT CAUSE_STORE_MISALIGNED, 1
212 + fsh fa0, 1(s4)
213 + CHECK
214 +
215 + EXPECT CAUSE_STORE_MISALIGNED, 1
216 + fsw fa0, 1(s4)
217 + CHECK
218 + EXPECT CAUSE_STORE_MISALIGNED, 3
219 + fsw fa0, 3(s4)
220 + CHECK
221 +
222 + EXPECT CAUSE_STORE_MISALIGNED, 1
223 + fsd fa0, 1(s4)
224 + CHECK
225 + EXPECT CAUSE_STORE_MISALIGNED, 7
226 + fsd fa0, 7(s4)
227 + CHECK
228 +
229 + /*
230 + * ---- Vector unit-stride loads / stores ----
231 + * A base address that is not aligned to the element size (SEW) is
232 + * misaligned for the first element access.
233 + */
234 + vsetvli t1, x0, e16, m1, ta, ma
235 + EXPECT CAUSE_LOAD_MISALIGNED, 1
236 + addi a0, s4, 1
237 + vle16.v v0, (a0)
238 + CHECK
239 + EXPECT CAUSE_STORE_MISALIGNED, 1
240 + addi a0, s4, 1
241 + vse16.v v0, (a0)
242 + CHECK
243 +
244 + vsetvli t1, x0, e32, m1, ta, ma
245 + EXPECT CAUSE_LOAD_MISALIGNED, 1
246 + addi a0, s4, 1
247 + vle32.v v0, (a0)
248 + CHECK
249 + EXPECT CAUSE_STORE_MISALIGNED, 3
250 + addi a0, s4, 3
251 + vse32.v v0, (a0)
252 + CHECK
253 +
254 + vsetvli t1, x0, e64, m1, ta, ma
255 + EXPECT CAUSE_LOAD_MISALIGNED, 1
256 + addi a0, s4, 1
257 + vle64.v v0, (a0)
258 + CHECK
259 + EXPECT CAUSE_STORE_MISALIGNED, 7
260 + addi a0, s4, 7
261 + vse64.v v0, (a0)
262 + CHECK
263 +
264 + /*
265 + * ---- Vector strided loads / stores ----
266 + */
267 + vsetvli t1, x0, e32, m1, ta, ma
268 + li a1, 8 /* stride in bytes */
269 + EXPECT CAUSE_LOAD_MISALIGNED, 1
270 + addi a0, s4, 1
271 + vlse32.v v0, (a0), a1
272 + CHECK
273 + EXPECT CAUSE_STORE_MISALIGNED, 1
274 + addi a0, s4, 1
275 + vsse32.v v0, (a0), a1
276 + CHECK
277 +
278 + /* ---- Vector indexed loads / stores ---- */
279 + /*
280 + * Zero indices keep the first element at the deliberately misaligned base.
281 + */
282 + vmv.v.i v1, 0
283 + EXPECT CAUSE_LOAD_MISALIGNED, 1
284 + addi a0, s4, 1
285 + vluxei32.v v0, (a0), v1
286 + CHECK
287 + EXPECT CAUSE_STORE_MISALIGNED, 1
288 + addi a0, s4, 1
289 + vsuxei32.v v0, (a0), v1
290 + CHECK
291 +
292 + /* ---- Vector segmented loads / stores ---- */
293 + EXPECT CAUSE_LOAD_MISALIGNED, 1
294 + addi a0, s4, 1
295 + vlseg2e32.v v0, (a0)
296 + CHECK
297 + EXPECT CAUSE_STORE_MISALIGNED, 1
298 + addi a0, s4, 1
299 + vsseg2e32.v v0, (a0)
300 + CHECK
301 +
302 + /*
303 + * ---- Vector whole-register load ----
304 + * Only the whole-register *load* forms carry an element width
305 + * (vl1re32.v => EEW=32), so only they enforce alignment when Zicclsm is
306 + * off. The whole-register store form (vs1r.v) is defined as EEW=8
307 + * (byte granular) and therefore never faults on misalignment, so it is
308 + * not exercised here.
309 + */
310 + EXPECT CAUSE_LOAD_MISALIGNED, 1
311 + addi a0, s4, 1
312 + vl1re32.v v1, (a0)
313 + CHECK
314 +
315 + /* Success. */
316 + li a0, 0
317 + j _exit
318 +
319 + /*
320 + * Trap handler: validate mcause and mtval against the expectation, bump
321 + * the trap counter, then skip past the faulting instruction. The
322 + * instruction length is decoded from its low two bits (0b11 => 4 bytes,
323 + * otherwise a 2-byte compressed instruction).
324 + */
325 + .balign 4
326 +trap:
327 + csrr t0, mcause
328 + bne t0, s1, fail
329 + csrr t1, mtval
330 + bne t1, s2, fail
331 + addi s3, s3, 1
332 +
333 + csrr t0, mepc
334 + lhu t2, 0(t0)
335 + andi t3, t2, 3
336 + li t4, 3
337 + bne t3, t4, 1f
338 + addi t0, t0, 4 /* 32-bit instruction */
339 + j 2f
340 +1:
341 + addi t0, t0, 2 /* 16-bit compressed instruction */
342 +2:
343 + csrw mepc, t0
344 + mret
345 +
346 +fail:
347 + li a0, 1
348 +_exit:
349 + lla a1, semiargs
350 + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */
351 + sd t0, 0(a1)
352 + sd a0, 8(a1)
353 + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */
354 + .balign 16
355 + slli zero, zero, 0x1f
356 + ebreak
357 + srai zero, zero, 0x7
358 + j .
359 +
360 + .data
361 + .balign 16
362 +semiargs:
363 + .space 16
364 + .balign 64
365 +buf:
366 + .byte 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
367 + .byte 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
368 + .space 240