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 #include <stdio.h> 19 #include <string.h> 20 21 typedef unsigned char uint8_t; 22 typedef unsigned short uint16_t; 23 typedef unsigned int uint32_t; 24 25 26 static inline void S4_storerhnew_rr(void *p, int index, uint16_t v) 27 { 28 asm volatile("{\n\t" 29 " r0 = %0\n\n" 30 " memh(%1+%2<<#2) = r0.new\n\t" 31 "}\n" 32 :: "r"(v), "r"(p), "r"(index) 33 : "r0", "memory"); 34 } 35 36 static uint32_t data; 37 static inline void *S4_storerbnew_ap(uint8_t v) 38 { 39 void *ret; 40 asm volatile("{\n\t" 41 " r0 = %1\n\n" 42 " memb(%0 = ##data) = r0.new\n\t" 43 "}\n" 44 : "=r"(ret) 45 : "r"(v) 46 : "r0", "memory"); 47 return ret; 48 } 49 50 static inline void *S4_storerhnew_ap(uint16_t v) 51 { 52 void *ret; 53 asm volatile("{\n\t" 54 " r0 = %1\n\n" 55 " memh(%0 = ##data) = r0.new\n\t" 56 "}\n" 57 : "=r"(ret) 58 : "r"(v) 59 : "r0", "memory"); 60 return ret; 61 } 62 63 static inline void *S4_storerinew_ap(uint32_t v) 64 { 65 void *ret; 66 asm volatile("{\n\t" 67 " r0 = %1\n\n" 68 " memw(%0 = ##data) = r0.new\n\t" 69 "}\n" 70 : "=r"(ret) 71 : "r"(v) 72 : "r0", "memory"); 73 return ret; 74 } 75 76 static inline void S4_storeirbt_io(void *p, int pred) 77 { 78 asm volatile("p0 = cmp.eq(%0, #1)\n\t" 79 "if (p0) memb(%1+#4)=#27\n\t" 80 :: "r"(pred), "r"(p) 81 : "p0", "memory"); 82 } 83 84 static inline void S4_storeirbf_io(void *p, int pred) 85 { 86 asm volatile("p0 = cmp.eq(%0, #1)\n\t" 87 "if (!p0) memb(%1+#4)=#27\n\t" 88 :: "r"(pred), "r"(p) 89 : "p0", "memory"); 90 } 91 92 static inline void S4_storeirbtnew_io(void *p, int pred) 93 { 94 asm volatile("{\n\t" 95 " p0 = cmp.eq(%0, #1)\n\t" 96 " if (p0.new) memb(%1+#4)=#27\n\t" 97 "}\n\t" 98 :: "r"(pred), "r"(p) 99 : "p0", "memory"); 100 } 101 102 static inline void S4_storeirbfnew_io(void *p, int pred) 103 { 104 asm volatile("{\n\t" 105 " p0 = cmp.eq(%0, #1)\n\t" 106 " if (!p0.new) memb(%1+#4)=#27\n\t" 107 "}\n\t" 108 :: "r"(pred), "r"(p) 109 : "p0", "memory"); 110 } 111 112 static inline void S4_storeirht_io(void *p, int pred) 113 { 114 asm volatile("p0 = cmp.eq(%0, #1)\n\t" 115 "if (p0) memh(%1+#4)=#27\n\t" 116 :: "r"(pred), "r"(p) 117 : "p0", "memory"); 118 } 119 120 static inline void S4_storeirhf_io(void *p, int pred) 121 { 122 asm volatile("p0 = cmp.eq(%0, #1)\n\t" 123 "if (!p0) memh(%1+#4)=#27\n\t" 124 :: "r"(pred), "r"(p) 125 : "p0", "memory"); 126 } 127 128 static inline void S4_storeirhtnew_io(void *p, int pred) 129 { 130 asm volatile("{\n\t" 131 " p0 = cmp.eq(%0, #1)\n\t" 132 " if (p0.new) memh(%1+#4)=#27\n\t" 133 "}\n\t" 134 :: "r"(pred), "r"(p) 135 : "p0", "memory"); 136 } 137 138 static inline void S4_storeirhfnew_io(void *p, int pred) 139 { 140 asm volatile("{\n\t" 141 " p0 = cmp.eq(%0, #1)\n\t" 142 " if (!p0.new) memh(%1+#4)=#27\n\t" 143 "}\n\t" 144 :: "r"(pred), "r"(p) 145 : "p0", "memory"); 146 } 147 148 static inline void S4_storeirit_io(void *p, int pred) 149 { 150 asm volatile("p0 = cmp.eq(%0, #1)\n\t" 151 "if (p0) memw(%1+#4)=#27\n\t" 152 :: "r"(pred), "r"(p) 153 : "p0", "memory"); 154 } 155 156 static inline void S4_storeirif_io(void *p, int pred) 157 { 158 asm volatile("p0 = cmp.eq(%0, #1)\n\t" 159 "if (!p0) memw(%1+#4)=#27\n\t" 160 :: "r"(pred), "r"(p) 161 : "p0", "memory"); 162 } 163 164 static inline void S4_storeiritnew_io(void *p, int pred) 165 { 166 asm volatile("{\n\t" 167 " p0 = cmp.eq(%0, #1)\n\t" 168 " if (p0.new) memw(%1+#4)=#27\n\t" 169 "}\n\t" 170 :: "r"(pred), "r"(p) 171 : "p0", "memory"); 172 } 173 174 static inline void S4_storeirifnew_io(void *p, int pred) 175 { 176 asm volatile("{\n\t" 177 " p0 = cmp.eq(%0, #1)\n\t" 178 " if (!p0.new) memw(%1+#4)=#27\n\t" 179 "}\n\t" 180 :: "r"(pred), "r"(p) 181 : "p0", "memory"); 182 } 183 184 static int L2_ploadrifnew_pi(void *p, int pred) 185 { 186 int result; 187 asm volatile("%0 = #31\n\t" 188 "{\n\t" 189 " p0 = cmp.eq(%1, #1)\n\t" 190 " if (!p0.new) %0 = memw(%2++#4)\n\t" 191 "}\n\t" 192 : "=r"(result) : "r"(pred), "r"(p) 193 : "p0"); 194 return result; 195 } 196 197 /* 198 * Test that compound-compare-jump is executed in 2 parts 199 * First we have to do all the compares in the packet and 200 * account for auto-anding. Then, we can do the predicated 201 * jump. 202 */ 203 static inline int cmpnd_cmp_jump(void) 204 { 205 int retval; 206 asm ("r5 = #7\n\t" 207 "r6 = #9\n\t" 208 "{\n\t" 209 " p0 = cmp.eq(r5, #7)\n\t" 210 " if (p0.new) jump:nt 1f\n\t" 211 " p0 = cmp.eq(r6, #7)\n\t" 212 "}\n\t" 213 "%0 = #12\n\t" 214 "jump 2f\n\t" 215 "1:\n\t" 216 "%0 = #13\n\t" 217 "2:\n\t" 218 : "=r"(retval) :: "r5", "r6", "p0"); 219 return retval; 220 } 221 222 static inline int test_clrtnew(int arg1, int old_val) 223 { 224 int ret; 225 asm volatile("r5 = %2\n\t" 226 "{\n\t" 227 "p0 = cmp.eq(%1, #1)\n\t" 228 "if (p0.new) r5=#0\n\t" 229 "}\n\t" 230 "%0 = r5\n\t" 231 : "=r"(ret) 232 : "r"(arg1), "r"(old_val) 233 : "p0", "r5"); 234 return ret; 235 } 236 237 int err; 238 239 static void check(int val, int expect) 240 { 241 if (val != expect) { 242 printf("ERROR: 0x%04x != 0x%04x\n", val, expect); 243 err++; 244 } 245 } 246 247 static void check64(long long val, long long expect) 248 { 249 if (val != expect) { 250 printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect); 251 err++; 252 } 253 } 254 255 uint32_t init[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 256 uint32_t array[10]; 257 258 uint32_t early_exit; 259 260 /* 261 * Write this as a function because we can't guarantee the compiler will 262 * allocate a frame with just the SL2_return_tnew packet. 263 */ 264 static void SL2_return_tnew(int x); 265 asm ("SL2_return_tnew:\n\t" 266 " allocframe(#0)\n\t" 267 " r1 = #1\n\t" 268 " memw(##early_exit) = r1\n\t" 269 " {\n\t" 270 " p0 = cmp.eq(r0, #1)\n\t" 271 " if (p0.new) dealloc_return:nt\n\t" /* SL2_return_tnew */ 272 " }\n\t" 273 " r1 = #0\n\t" 274 " memw(##early_exit) = r1\n\t" 275 " dealloc_return\n\t" 276 ); 277 278 static long long creg_pair(int x, int y) 279 { 280 long long retval; 281 asm ("m0 = %1\n\t" 282 "m1 = %2\n\t" 283 "%0 = c7:6\n\t" 284 : "=r"(retval) : "r"(x), "r"(y) : "m0", "m1"); 285 return retval; 286 } 287 288 static long long decbin(long long x, long long y, int *pred) 289 { 290 long long retval; 291 asm ("%0 = decbin(%2, %3)\n\t" 292 "%1 = p0\n\t" 293 : "=r"(retval), "=r"(*pred) 294 : "r"(x), "r"(y)); 295 return retval; 296 } 297 298 /* Check that predicates are auto-and'ed in a packet */ 299 static int auto_and(void) 300 { 301 int retval; 302 asm ("r5 = #1\n\t" 303 "{\n\t" 304 " p0 = cmp.eq(r1, #1)\n\t" 305 " p0 = cmp.eq(r1, #2)\n\t" 306 "}\n\t" 307 "%0 = p0\n\t" 308 : "=r"(retval) 309 : 310 : "r5", "p0"); 311 return retval; 312 } 313 314 void test_lsbnew(void) 315 { 316 int result; 317 318 asm("r0 = #2\n\t" 319 "r1 = #5\n\t" 320 "{\n\t" 321 " p0 = r0\n\t" 322 " if (p0.new) r1 = #3\n\t" 323 "}\n\t" 324 "%0 = r1\n\t" 325 : "=r"(result) :: "r0", "r1", "p0"); 326 check(result, 5); 327 } 328 329 void test_l2fetch(void) 330 { 331 /* These don't do anything in qemu, just make sure they don't assert */ 332 asm volatile ("l2fetch(r0, r1)\n\t" 333 "l2fetch(r0, r3:2)\n\t"); 334 } 335 336 int main() 337 { 338 int res; 339 long long res64; 340 int pred; 341 342 memcpy(array, init, sizeof(array)); 343 S4_storerhnew_rr(array, 4, 0xffff); 344 check(array[4], 0xffff); 345 346 data = ~0; 347 check((uint32_t)S4_storerbnew_ap(0x12), (uint32_t)&data); 348 check(data, 0xffffff12); 349 350 data = ~0; 351 check((uint32_t)S4_storerhnew_ap(0x1234), (uint32_t)&data); 352 check(data, 0xffff1234); 353 354 data = ~0; 355 check((uint32_t)S4_storerinew_ap(0x12345678), (uint32_t)&data); 356 check(data, 0x12345678); 357 358 /* Byte */ 359 memcpy(array, init, sizeof(array)); 360 S4_storeirbt_io(&array[1], 1); 361 check(array[2], 27); 362 S4_storeirbt_io(&array[2], 0); 363 check(array[3], 3); 364 365 memcpy(array, init, sizeof(array)); 366 S4_storeirbf_io(&array[3], 0); 367 check(array[4], 27); 368 S4_storeirbf_io(&array[4], 1); 369 check(array[5], 5); 370 371 memcpy(array, init, sizeof(array)); 372 S4_storeirbtnew_io(&array[5], 1); 373 check(array[6], 27); 374 S4_storeirbtnew_io(&array[6], 0); 375 check(array[7], 7); 376 377 memcpy(array, init, sizeof(array)); 378 S4_storeirbfnew_io(&array[7], 0); 379 check(array[8], 27); 380 S4_storeirbfnew_io(&array[8], 1); 381 check(array[9], 9); 382 383 /* Half word */ 384 memcpy(array, init, sizeof(array)); 385 S4_storeirht_io(&array[1], 1); 386 check(array[2], 27); 387 S4_storeirht_io(&array[2], 0); 388 check(array[3], 3); 389 390 memcpy(array, init, sizeof(array)); 391 S4_storeirhf_io(&array[3], 0); 392 check(array[4], 27); 393 S4_storeirhf_io(&array[4], 1); 394 check(array[5], 5); 395 396 memcpy(array, init, sizeof(array)); 397 S4_storeirhtnew_io(&array[5], 1); 398 check(array[6], 27); 399 S4_storeirhtnew_io(&array[6], 0); 400 check(array[7], 7); 401 402 memcpy(array, init, sizeof(array)); 403 S4_storeirhfnew_io(&array[7], 0); 404 check(array[8], 27); 405 S4_storeirhfnew_io(&array[8], 1); 406 check(array[9], 9); 407 408 /* Word */ 409 memcpy(array, init, sizeof(array)); 410 S4_storeirit_io(&array[1], 1); 411 check(array[2], 27); 412 S4_storeirit_io(&array[2], 0); 413 check(array[3], 3); 414 415 memcpy(array, init, sizeof(array)); 416 S4_storeirif_io(&array[3], 0); 417 check(array[4], 27); 418 S4_storeirif_io(&array[4], 1); 419 check(array[5], 5); 420 421 memcpy(array, init, sizeof(array)); 422 S4_storeiritnew_io(&array[5], 1); 423 check(array[6], 27); 424 S4_storeiritnew_io(&array[6], 0); 425 check(array[7], 7); 426 427 memcpy(array, init, sizeof(array)); 428 S4_storeirifnew_io(&array[7], 0); 429 check(array[8], 27); 430 S4_storeirifnew_io(&array[8], 1); 431 check(array[9], 9); 432 433 memcpy(array, init, sizeof(array)); 434 res = L2_ploadrifnew_pi(&array[6], 0); 435 check(res, 6); 436 res = L2_ploadrifnew_pi(&array[7], 1); 437 check(res, 31); 438 439 int x = cmpnd_cmp_jump(); 440 check(x, 12); 441 442 SL2_return_tnew(0); 443 check(early_exit, 0); 444 SL2_return_tnew(1); 445 check(early_exit, 1); 446 447 long long pair = creg_pair(5, 7); 448 check((int)pair, 5); 449 check((int)(pair >> 32), 7); 450 451 res = test_clrtnew(1, 7); 452 check(res, 0); 453 res = test_clrtnew(2, 7); 454 check(res, 7); 455 456 res64 = decbin(0xf0f1f2f3f4f5f6f7LL, 0x7f6f5f4f3f2f1f0fLL, &pred); 457 check64(res64, 0x357980003700010cLL); 458 check(pred, 0); 459 460 res64 = decbin(0xfLL, 0x1bLL, &pred); 461 check64(res64, 0x78000100LL); 462 check(pred, 1); 463 464 res = auto_and(); 465 check(res, 0); 466 467 test_lsbnew(); 468 469 test_l2fetch(); 470 471 puts(err ? "FAIL" : "PASS"); 472 return err; 473 } 474