| 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 |