1 /* 2 * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 /* 19 * Test load unpack instructions 20 * 21 * Example 22 * r0 = memubh(r1+#0) 23 * loads a half word from memory and zero-extends the 2 bytes to form a word 24 * 25 * For each addressing mode, there are 4 tests 26 * bzw2 unsigned 2 elements 27 * bsw2 signed 2 elements 28 * bzw4 unsigned 4 elements 29 * bsw4 signed 4 elements 30 * There are 8 addressing modes, for a total of 32 instructions to test 31 */ 32 33 #include <stdio.h> 34 #include <string.h> 35 36 int err; 37 38 char buf[16] __attribute__((aligned(1 << 16))); 39 40 void init_buf(void) 41 { 42 int i; 43 for (i = 0; i < 16; i++) { 44 int sign = i % 2 == 0 ? 0x80 : 0; 45 buf[i] = sign | (i + 1); 46 } 47 } 48 49 void __check(int line, long long result, long long expect) 50 { 51 if (result != expect) { 52 printf("ERROR at line %d: 0x%08llx != 0x%08llx\n", 53 line, result, expect); 54 err++; 55 } 56 } 57 58 #define check(RES, EXP) __check(__LINE__, RES, EXP) 59 60 void __checkp(int line, void *p, void *expect) 61 { 62 if (p != expect) { 63 printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect); 64 err++; 65 } 66 } 67 68 #define checkp(RES, EXP) __checkp(__LINE__, RES, EXP) 69 70 /* 71 **************************************************************************** 72 * _io addressing mode (addr + offset) 73 */ 74 #define BxW_LOAD_io(SZ, RES, ADDR, OFF) \ 75 __asm__( \ 76 "%0 = mem" #SZ "(%1+#" #OFF ")\n\t" \ 77 : "=r"(RES) \ 78 : "r"(ADDR)) 79 #define BxW_LOAD_io_Z(RES, ADDR, OFF) \ 80 BxW_LOAD_io(ubh, RES, ADDR, OFF) 81 #define BxW_LOAD_io_S(RES, ADDR, OFF) \ 82 BxW_LOAD_io(bh, RES, ADDR, OFF) 83 84 #define TEST_io(NAME, TYPE, SIGN, SIZE, EXT, EXP1, EXP2, EXP3, EXP4) \ 85 void test_##NAME(void) \ 86 { \ 87 TYPE result; \ 88 init_buf(); \ 89 BxW_LOAD_io_##SIGN(result, buf, 0 * (SIZE)); \ 90 check(result, (EXP1) | (EXT)); \ 91 BxW_LOAD_io_##SIGN(result, buf, 1 * (SIZE)); \ 92 check(result, (EXP2) | (EXT)); \ 93 BxW_LOAD_io_##SIGN(result, buf, 2 * (SIZE)); \ 94 check(result, (EXP3) | (EXT)); \ 95 BxW_LOAD_io_##SIGN(result, buf, 3 * (SIZE)); \ 96 check(result, (EXP4) | (EXT)); \ 97 } 98 99 100 TEST_io(loadbzw2_io, int, Z, 2, 0x00000000, 101 0x00020081, 0x00040083, 0x00060085, 0x00080087) 102 TEST_io(loadbsw2_io, int, S, 2, 0x0000ff00, 103 0x00020081, 0x00040083, 0x00060085, 0x00080087) 104 TEST_io(loadbzw4_io, long long, Z, 4, 0x0000000000000000LL, 105 0x0004008300020081LL, 0x0008008700060085LL, 106 0x000c008b000a0089LL, 0x0010008f000e008dLL) 107 TEST_io(loadbsw4_io, long long, S, 4, 0x0000ff000000ff00LL, 108 0x0004008300020081LL, 0x0008008700060085LL, 109 0x000c008b000a0089LL, 0x0010008f000e008dLL) 110 111 /* 112 **************************************************************************** 113 * _ur addressing mode (index << offset + base) 114 */ 115 #define BxW_LOAD_ur(SZ, RES, SHIFT, IDX) \ 116 __asm__( \ 117 "%0 = mem" #SZ "(%1<<#" #SHIFT " + ##buf)\n\t" \ 118 : "=r"(RES) \ 119 : "r"(IDX)) 120 #define BxW_LOAD_ur_Z(RES, SHIFT, IDX) \ 121 BxW_LOAD_ur(ubh, RES, SHIFT, IDX) 122 #define BxW_LOAD_ur_S(RES, SHIFT, IDX) \ 123 BxW_LOAD_ur(bh, RES, SHIFT, IDX) 124 125 #define TEST_ur(NAME, TYPE, SIGN, SHIFT, EXT, RES1, RES2, RES3, RES4) \ 126 void test_##NAME(void) \ 127 { \ 128 TYPE result; \ 129 init_buf(); \ 130 BxW_LOAD_ur_##SIGN(result, (SHIFT), 0); \ 131 check(result, (RES1) | (EXT)); \ 132 BxW_LOAD_ur_##SIGN(result, (SHIFT), 1); \ 133 check(result, (RES2) | (EXT)); \ 134 BxW_LOAD_ur_##SIGN(result, (SHIFT), 2); \ 135 check(result, (RES3) | (EXT)); \ 136 BxW_LOAD_ur_##SIGN(result, (SHIFT), 3); \ 137 check(result, (RES4) | (EXT)); \ 138 } \ 139 140 TEST_ur(loadbzw2_ur, int, Z, 1, 0x00000000, 141 0x00020081, 0x00040083, 0x00060085, 0x00080087) 142 TEST_ur(loadbsw2_ur, int, S, 1, 0x0000ff00, 143 0x00020081, 0x00040083, 0x00060085, 0x00080087) 144 TEST_ur(loadbzw4_ur, long long, Z, 2, 0x0000000000000000LL, 145 0x0004008300020081LL, 0x0008008700060085LL, 146 0x000c008b000a0089LL, 0x0010008f000e008dLL) 147 TEST_ur(loadbsw4_ur, long long, S, 2, 0x0000ff000000ff00LL, 148 0x0004008300020081LL, 0x0008008700060085LL, 149 0x000c008b000a0089LL, 0x0010008f000e008dLL) 150 151 /* 152 **************************************************************************** 153 * _ap addressing mode (addr = base) 154 */ 155 #define BxW_LOAD_ap(SZ, RES, PTR, ADDR) \ 156 __asm__( \ 157 "%0 = mem" #SZ "(%1 = ##" #ADDR ")\n\t" \ 158 : "=r"(RES), "=r"(PTR)) 159 #define BxW_LOAD_ap_Z(RES, PTR, ADDR) \ 160 BxW_LOAD_ap(ubh, RES, PTR, ADDR) 161 #define BxW_LOAD_ap_S(RES, PTR, ADDR) \ 162 BxW_LOAD_ap(bh, RES, PTR, ADDR) 163 164 #define TEST_ap(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \ 165 void test_##NAME(void) \ 166 { \ 167 TYPE result; \ 168 void *ptr; \ 169 init_buf(); \ 170 BxW_LOAD_ap_##SIGN(result, ptr, (buf + 0 * (SIZE))); \ 171 check(result, (RES1) | (EXT)); \ 172 checkp(ptr, &buf[0 * (SIZE)]); \ 173 BxW_LOAD_ap_##SIGN(result, ptr, (buf + 1 * (SIZE))); \ 174 check(result, (RES2) | (EXT)); \ 175 checkp(ptr, &buf[1 * (SIZE)]); \ 176 BxW_LOAD_ap_##SIGN(result, ptr, (buf + 2 * (SIZE))); \ 177 check(result, (RES3) | (EXT)); \ 178 checkp(ptr, &buf[2 * (SIZE)]); \ 179 BxW_LOAD_ap_##SIGN(result, ptr, (buf + 3 * (SIZE))); \ 180 check(result, (RES4) | (EXT)); \ 181 checkp(ptr, &buf[3 * (SIZE)]); \ 182 } 183 184 TEST_ap(loadbzw2_ap, int, Z, 2, 0x00000000, 185 0x00020081, 0x00040083, 0x00060085, 0x00080087) 186 TEST_ap(loadbsw2_ap, int, S, 2, 0x0000ff00, 187 0x00020081, 0x00040083, 0x00060085, 0x00080087) 188 TEST_ap(loadbzw4_ap, long long, Z, 4, 0x0000000000000000LL, 189 0x0004008300020081LL, 0x0008008700060085LL, 190 0x000c008b000a0089LL, 0x0010008f000e008dLL) 191 TEST_ap(loadbsw4_ap, long long, S, 4, 0x0000ff000000ff00LL, 192 0x0004008300020081LL, 0x0008008700060085LL, 193 0x000c008b000a0089LL, 0x0010008f000e008dLL) 194 195 /* 196 **************************************************************************** 197 * _rp addressing mode (addr ++ modifer-reg) 198 */ 199 #define BxW_LOAD_pr(SZ, RES, PTR, INC) \ 200 __asm__( \ 201 "m0 = %2\n\t" \ 202 "%0 = mem" #SZ "(%1++m0)\n\t" \ 203 : "=r"(RES), "+r"(PTR) \ 204 : "r"(INC) \ 205 : "m0") 206 #define BxW_LOAD_pr_Z(RES, PTR, INC) \ 207 BxW_LOAD_pr(ubh, RES, PTR, INC) 208 #define BxW_LOAD_pr_S(RES, PTR, INC) \ 209 BxW_LOAD_pr(bh, RES, PTR, INC) 210 211 #define TEST_pr(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \ 212 void test_##NAME(void) \ 213 { \ 214 TYPE result; \ 215 void *ptr = buf; \ 216 init_buf(); \ 217 BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ 218 check(result, (RES1) | (EXT)); \ 219 checkp(ptr, &buf[1 * (SIZE)]); \ 220 BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ 221 check(result, (RES2) | (EXT)); \ 222 checkp(ptr, &buf[2 * (SIZE)]); \ 223 BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ 224 check(result, (RES3) | (EXT)); \ 225 checkp(ptr, &buf[3 * (SIZE)]); \ 226 BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ 227 check(result, (RES4) | (EXT)); \ 228 checkp(ptr, &buf[4 * (SIZE)]); \ 229 } 230 231 TEST_pr(loadbzw2_pr, int, Z, 2, 0x00000000, 232 0x00020081, 0x0040083, 0x00060085, 0x00080087) 233 TEST_pr(loadbsw2_pr, int, S, 2, 0x0000ff00, 234 0x00020081, 0x0040083, 0x00060085, 0x00080087) 235 TEST_pr(loadbzw4_pr, long long, Z, 4, 0x0000000000000000LL, 236 0x0004008300020081LL, 0x0008008700060085LL, 237 0x000c008b000a0089LL, 0x0010008f000e008dLL) 238 TEST_pr(loadbsw4_pr, long long, S, 4, 0x0000ff000000ff00LL, 239 0x0004008300020081LL, 0x0008008700060085LL, 240 0x000c008b000a0089LL, 0x0010008f000e008dLL) 241 242 /* 243 **************************************************************************** 244 * _pbr addressing mode (addr ++ modifer-reg:brev) 245 */ 246 #define BxW_LOAD_pbr(SZ, RES, PTR) \ 247 __asm__( \ 248 "r4 = #(1 << (16 - 3))\n\t" \ 249 "m0 = r4\n\t" \ 250 "%0 = mem" #SZ "(%1++m0:brev)\n\t" \ 251 : "=r"(RES), "+r"(PTR) \ 252 : \ 253 : "r4", "m0") 254 #define BxW_LOAD_pbr_Z(RES, PTR) \ 255 BxW_LOAD_pbr(ubh, RES, PTR) 256 #define BxW_LOAD_pbr_S(RES, PTR) \ 257 BxW_LOAD_pbr(bh, RES, PTR) 258 259 #define TEST_pbr(NAME, TYPE, SIGN, EXT, RES1, RES2, RES3, RES4) \ 260 void test_##NAME(void) \ 261 { \ 262 TYPE result; \ 263 void *ptr = buf; \ 264 init_buf(); \ 265 BxW_LOAD_pbr_##SIGN(result, ptr); \ 266 check(result, (RES1) | (EXT)); \ 267 BxW_LOAD_pbr_##SIGN(result, ptr); \ 268 check(result, (RES2) | (EXT)); \ 269 BxW_LOAD_pbr_##SIGN(result, ptr); \ 270 check(result, (RES3) | (EXT)); \ 271 BxW_LOAD_pbr_##SIGN(result, ptr); \ 272 check(result, (RES4) | (EXT)); \ 273 } 274 275 TEST_pbr(loadbzw2_pbr, int, Z, 0x00000000, 276 0x00020081, 0x00060085, 0x00040083, 0x00080087) 277 TEST_pbr(loadbsw2_pbr, int, S, 0x0000ff00, 278 0x00020081, 0x00060085, 0x00040083, 0x00080087) 279 TEST_pbr(loadbzw4_pbr, long long, Z, 0x0000000000000000LL, 280 0x0004008300020081LL, 0x0008008700060085LL, 281 0x0006008500040083LL, 0x000a008900080087LL) 282 TEST_pbr(loadbsw4_pbr, long long, S, 0x0000ff000000ff00LL, 283 0x0004008300020081LL, 0x0008008700060085LL, 284 0x0006008500040083LL, 0x000a008900080087LL) 285 286 /* 287 **************************************************************************** 288 * _pi addressing mode (addr ++ inc) 289 */ 290 #define BxW_LOAD_pi(SZ, RES, PTR, INC) \ 291 __asm__( \ 292 "%0 = mem" #SZ "(%1++#" #INC ")\n\t" \ 293 : "=r"(RES), "+r"(PTR)) 294 #define BxW_LOAD_pi_Z(RES, PTR, INC) \ 295 BxW_LOAD_pi(ubh, RES, PTR, INC) 296 #define BxW_LOAD_pi_S(RES, PTR, INC) \ 297 BxW_LOAD_pi(bh, RES, PTR, INC) 298 299 #define TEST_pi(NAME, TYPE, SIGN, INC, EXT, RES1, RES2, RES3, RES4) \ 300 void test_##NAME(void) \ 301 { \ 302 TYPE result; \ 303 void *ptr = buf; \ 304 init_buf(); \ 305 BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ 306 check(result, (RES1) | (EXT)); \ 307 checkp(ptr, &buf[1 * (INC)]); \ 308 BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ 309 check(result, (RES2) | (EXT)); \ 310 checkp(ptr, &buf[2 * (INC)]); \ 311 BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ 312 check(result, (RES3) | (EXT)); \ 313 checkp(ptr, &buf[3 * (INC)]); \ 314 BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ 315 check(result, (RES4) | (EXT)); \ 316 checkp(ptr, &buf[4 * (INC)]); \ 317 } 318 319 TEST_pi(loadbzw2_pi, int, Z, 2, 0x00000000, 320 0x00020081, 0x00040083, 0x00060085, 0x00080087) 321 TEST_pi(loadbsw2_pi, int, S, 2, 0x0000ff00, 322 0x00020081, 0x00040083, 0x00060085, 0x00080087) 323 TEST_pi(loadbzw4_pi, long long, Z, 4, 0x0000000000000000LL, 324 0x0004008300020081LL, 0x0008008700060085LL, 325 0x000c008b000a0089LL, 0x0010008f000e008dLL) 326 TEST_pi(loadbsw4_pi, long long, S, 4, 0x0000ff000000ff00LL, 327 0x0004008300020081LL, 0x0008008700060085LL, 328 0x000c008b000a0089LL, 0x0010008f000e008dLL) 329 330 /* 331 **************************************************************************** 332 * _pci addressing mode (addr ++ inc:circ) 333 */ 334 #define BxW_LOAD_pci(SZ, RES, PTR, START, LEN, INC) \ 335 __asm__( \ 336 "r4 = %3\n\t" \ 337 "m0 = r4\n\t" \ 338 "cs0 = %2\n\t" \ 339 "%0 = mem" #SZ "(%1++#" #INC ":circ(m0))\n\t" \ 340 : "=r"(RES), "+r"(PTR) \ 341 : "r"(START), "r"(LEN) \ 342 : "r4", "m0", "cs0") 343 #define BxW_LOAD_pci_Z(RES, PTR, START, LEN, INC) \ 344 BxW_LOAD_pci(ubh, RES, PTR, START, LEN, INC) 345 #define BxW_LOAD_pci_S(RES, PTR, START, LEN, INC) \ 346 BxW_LOAD_pci(bh, RES, PTR, START, LEN, INC) 347 348 #define TEST_pci(NAME, TYPE, SIGN, LEN, INC, EXT, RES1, RES2, RES3, RES4) \ 349 void test_##NAME(void) \ 350 { \ 351 TYPE result; \ 352 void *ptr = buf; \ 353 init_buf(); \ 354 BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ 355 check(result, (RES1) | (EXT)); \ 356 checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \ 357 BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ 358 check(result, (RES2) | (EXT)); \ 359 checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \ 360 BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ 361 check(result, (RES3) | (EXT)); \ 362 checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \ 363 BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ 364 check(result, (RES4) | (EXT)); \ 365 checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \ 366 } 367 368 TEST_pci(loadbzw2_pci, int, Z, 6, 2, 0x00000000, 369 0x00020081, 0x00040083, 0x00060085, 0x00020081) 370 TEST_pci(loadbsw2_pci, int, S, 6, 2, 0x0000ff00, 371 0x00020081, 0x00040083, 0x00060085, 0x00020081) 372 TEST_pci(loadbzw4_pci, long long, Z, 8, 4, 0x0000000000000000LL, 373 0x0004008300020081LL, 0x0008008700060085LL, 374 0x0004008300020081LL, 0x0008008700060085LL) 375 TEST_pci(loadbsw4_pci, long long, S, 8, 4, 0x0000ff000000ff00LL, 376 0x0004008300020081LL, 0x0008008700060085LL, 377 0x0004008300020081LL, 0x0008008700060085LL) 378 379 /* 380 **************************************************************************** 381 * _pcr addressing mode (addr ++ I:circ(modifier-reg)) 382 */ 383 #define BxW_LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \ 384 __asm__( \ 385 "r4 = %2\n\t" \ 386 "m1 = r4\n\t" \ 387 "cs1 = %3\n\t" \ 388 "%0 = mem" #SZ "(%1++I:circ(m1))\n\t" \ 389 : "=r"(RES), "+r"(PTR) \ 390 : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \ 391 "r"(START) \ 392 : "r4", "m1", "cs1") 393 #define BxW_LOAD_pcr_Z(RES, PTR, START, LEN, INC) \ 394 BxW_LOAD_pcr(ubh, RES, PTR, START, LEN, INC) 395 #define BxW_LOAD_pcr_S(RES, PTR, START, LEN, INC) \ 396 BxW_LOAD_pcr(bh, RES, PTR, START, LEN, INC) 397 398 #define TEST_pcr(NAME, TYPE, SIGN, SIZE, LEN, INC, \ 399 EXT, RES1, RES2, RES3, RES4) \ 400 void test_##NAME(void) \ 401 { \ 402 TYPE result; \ 403 void *ptr = buf; \ 404 init_buf(); \ 405 BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ 406 check(result, (RES1) | (EXT)); \ 407 checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \ 408 BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ 409 check(result, (RES2) | (EXT)); \ 410 checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \ 411 BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ 412 check(result, (RES3) | (EXT)); \ 413 checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \ 414 BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ 415 check(result, (RES4) | (EXT)); \ 416 checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \ 417 } 418 419 TEST_pcr(loadbzw2_pcr, int, Z, 2, 8, 2, 0x00000000, 420 0x00020081, 0x00060085, 0x00020081, 0x00060085) 421 TEST_pcr(loadbsw2_pcr, int, S, 2, 8, 2, 0x0000ff00, 422 0x00020081, 0x00060085, 0x00020081, 0x00060085) 423 TEST_pcr(loadbzw4_pcr, long long, Z, 4, 8, 1, 0x0000000000000000LL, 424 0x0004008300020081LL, 0x0008008700060085LL, 425 0x0004008300020081LL, 0x0008008700060085LL) 426 TEST_pcr(loadbsw4_pcr, long long, S, 4, 8, 1, 0x0000ff000000ff00LL, 427 0x0004008300020081LL, 0x0008008700060085LL, 428 0x0004008300020081LL, 0x0008008700060085LL) 429 430 int main() 431 { 432 test_loadbzw2_io(); 433 test_loadbsw2_io(); 434 test_loadbzw4_io(); 435 test_loadbsw4_io(); 436 437 test_loadbzw2_ur(); 438 test_loadbsw2_ur(); 439 test_loadbzw4_ur(); 440 test_loadbsw4_ur(); 441 442 test_loadbzw2_ap(); 443 test_loadbsw2_ap(); 444 test_loadbzw4_ap(); 445 test_loadbsw4_ap(); 446 447 test_loadbzw2_pr(); 448 test_loadbsw2_pr(); 449 test_loadbzw4_pr(); 450 test_loadbsw4_pr(); 451 452 test_loadbzw2_pbr(); 453 test_loadbsw2_pbr(); 454 test_loadbzw4_pbr(); 455 test_loadbsw4_pbr(); 456 457 test_loadbzw2_pi(); 458 test_loadbsw2_pi(); 459 test_loadbzw4_pi(); 460 test_loadbsw4_pi(); 461 462 test_loadbzw2_pci(); 463 test_loadbsw2_pci(); 464 test_loadbzw4_pci(); 465 test_loadbsw4_pci(); 466 467 test_loadbzw2_pcr(); 468 test_loadbsw2_pcr(); 469 test_loadbzw4_pcr(); 470 test_loadbsw4_pcr(); 471 472 puts(err ? "FAIL" : "PASS"); 473 return err ? 1 : 0; 474 } 475