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