1 /* 2 * ARM helper routines 3 * 4 * Copyright (c) 2005-2007 CodeSourcery, LLC 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 #include "cpu.h" 20 #include "tcg.h" 21 #include "helper.h" 22 23 #define SIGNBIT (uint32_t)0x80000000 24 #define SIGNBIT64 ((uint64_t)1 << 63) 25 26 #if !defined(CONFIG_USER_ONLY) 27 static void raise_exception(CPUARMState *env, int tt) 28 { 29 env->exception_index = tt; 30 cpu_loop_exit(env); 31 } 32 #endif 33 34 uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def, 35 uint32_t rn, uint32_t maxindex) 36 { 37 uint32_t val; 38 uint32_t tmp; 39 int index; 40 int shift; 41 uint64_t *table; 42 table = (uint64_t *)&env->vfp.regs[rn]; 43 val = 0; 44 for (shift = 0; shift < 32; shift += 8) { 45 index = (ireg >> shift) & 0xff; 46 if (index < maxindex) { 47 tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff; 48 val |= tmp << shift; 49 } else { 50 val |= def & (0xff << shift); 51 } 52 } 53 return val; 54 } 55 56 #undef env 57 58 #if !defined(CONFIG_USER_ONLY) 59 60 61 #define MMUSUFFIX _mmu 62 63 #define SHIFT 0 64 #include "exec/softmmu_template.h" 65 66 #define SHIFT 1 67 #include "exec/softmmu_template.h" 68 69 #define SHIFT 2 70 #include "exec/softmmu_template.h" 71 72 #define SHIFT 3 73 #include "exec/softmmu_template.h" 74 75 /* try to fill the TLB and return an exception if error. If retaddr is 76 NULL, it means that the function was called in C code (i.e. not 77 from generated code or from helper.c) */ 78 void tlb_fill(CPUARMState *env, target_ulong addr, int is_write, int mmu_idx, 79 uintptr_t retaddr) 80 { 81 int ret; 82 83 ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx); 84 if (unlikely(ret)) { 85 if (retaddr) { 86 /* now we have a real cpu fault */ 87 cpu_restore_state(env, retaddr); 88 } 89 raise_exception(env, env->exception_index); 90 } 91 } 92 93 void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val) 94 { 95 int cp_num = (insn >> 8) & 0xf; 96 int cp_info = (insn >> 5) & 7; 97 int src = (insn >> 16) & 0xf; 98 int operand = insn & 0xf; 99 100 if (env->cp[cp_num].cp_write) 101 env->cp[cp_num].cp_write(env->cp[cp_num].opaque, 102 cp_info, src, operand, val, (void*)GETPC()); 103 } 104 105 uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn) 106 { 107 int cp_num = (insn >> 8) & 0xf; 108 int cp_info = (insn >> 5) & 7; 109 int dest = (insn >> 16) & 0xf; 110 int operand = insn & 0xf; 111 112 if (env->cp[cp_num].cp_read) 113 return env->cp[cp_num].cp_read(env->cp[cp_num].opaque, 114 cp_info, dest, operand, (void*)GETPC()); 115 return 0; 116 } 117 118 #else 119 120 void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val) 121 { 122 int op1 = (insn >> 8) & 0xf; 123 cpu_abort(env, "cp%i insn %08x\n", op1, insn); 124 return; 125 } 126 127 uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn) 128 { 129 int op1 = (insn >> 8) & 0xf; 130 cpu_abort(env, "cp%i insn %08x\n", op1, insn); 131 return 0; 132 } 133 134 #endif 135 136 uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) 137 { 138 uint32_t res = a + b; 139 if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) 140 env->QF = 1; 141 return res; 142 } 143 144 uint32_t HELPER(add_saturate)(CPUARMState *env, uint32_t a, uint32_t b) 145 { 146 uint32_t res = a + b; 147 if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) { 148 env->QF = 1; 149 res = ~(((int32_t)a >> 31) ^ SIGNBIT); 150 } 151 return res; 152 } 153 154 uint32_t HELPER(sub_saturate)(CPUARMState *env, uint32_t a, uint32_t b) 155 { 156 uint32_t res = a - b; 157 if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) { 158 env->QF = 1; 159 res = ~(((int32_t)a >> 31) ^ SIGNBIT); 160 } 161 return res; 162 } 163 164 uint32_t HELPER(double_saturate)(CPUARMState *env, int32_t val) 165 { 166 uint32_t res; 167 if (val >= 0x40000000) { 168 res = ~SIGNBIT; 169 env->QF = 1; 170 } else if (val <= (int32_t)0xc0000000) { 171 res = SIGNBIT; 172 env->QF = 1; 173 } else { 174 res = val << 1; 175 } 176 return res; 177 } 178 179 uint32_t HELPER(add_usaturate)(CPUARMState *env, uint32_t a, uint32_t b) 180 { 181 uint32_t res = a + b; 182 if (res < a) { 183 env->QF = 1; 184 res = ~0; 185 } 186 return res; 187 } 188 189 uint32_t HELPER(sub_usaturate)(CPUARMState *env, uint32_t a, uint32_t b) 190 { 191 uint32_t res = a - b; 192 if (res > a) { 193 env->QF = 1; 194 res = 0; 195 } 196 return res; 197 } 198 199 /* Signed saturation. */ 200 static inline uint32_t do_ssat(CPUARMState *env, int32_t val, int shift) 201 { 202 int32_t top; 203 uint32_t mask; 204 205 top = val >> shift; 206 mask = (1u << shift) - 1; 207 if (top > 0) { 208 env->QF = 1; 209 return mask; 210 } else if (top < -1) { 211 env->QF = 1; 212 return ~mask; 213 } 214 return val; 215 } 216 217 /* Unsigned saturation. */ 218 static inline uint32_t do_usat(CPUARMState *env, int32_t val, int shift) 219 { 220 uint32_t max; 221 222 max = (1u << shift) - 1; 223 if (val < 0) { 224 env->QF = 1; 225 return 0; 226 } else if (val > max) { 227 env->QF = 1; 228 return max; 229 } 230 return val; 231 } 232 233 /* Signed saturate. */ 234 uint32_t HELPER(ssat)(CPUARMState *env, uint32_t x, uint32_t shift) 235 { 236 return do_ssat(env, x, shift); 237 } 238 239 /* Dual halfword signed saturate. */ 240 uint32_t HELPER(ssat16)(CPUARMState *env, uint32_t x, uint32_t shift) 241 { 242 uint32_t res; 243 244 res = (uint16_t)do_ssat(env, (int16_t)x, shift); 245 res |= do_ssat(env, ((int32_t)x) >> 16, shift) << 16; 246 return res; 247 } 248 249 /* Unsigned saturate. */ 250 uint32_t HELPER(usat)(CPUARMState *env, uint32_t x, uint32_t shift) 251 { 252 return do_usat(env, x, shift); 253 } 254 255 /* Dual halfword unsigned saturate. */ 256 uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift) 257 { 258 uint32_t res; 259 260 res = (uint16_t)do_usat(env, (int16_t)x, shift); 261 res |= do_usat(env, ((int32_t)x) >> 16, shift) << 16; 262 return res; 263 } 264 265 void HELPER(wfi)(CPUARMState *env) 266 { 267 env->exception_index = EXCP_HLT; 268 ENV_GET_CPU(env)->halted = 1; 269 cpu_loop_exit(env); 270 } 271 272 void HELPER(exception)(CPUARMState *env, uint32_t excp) 273 { 274 env->exception_index = excp; 275 cpu_loop_exit(env); 276 } 277 278 uint32_t HELPER(cpsr_read)(CPUARMState *env) 279 { 280 return cpsr_read(env) & ~CPSR_EXEC; 281 } 282 283 void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask) 284 { 285 cpsr_write(env, val, mask); 286 } 287 288 /* Access to user mode registers from privileged modes. */ 289 uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno) 290 { 291 uint32_t val; 292 293 if (regno == 13) { 294 val = env->banked_r13[0]; 295 } else if (regno == 14) { 296 val = env->banked_r14[0]; 297 } else if (regno >= 8 298 && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { 299 val = env->usr_regs[regno - 8]; 300 } else { 301 val = env->regs[regno]; 302 } 303 return val; 304 } 305 306 void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val) 307 { 308 if (regno == 13) { 309 env->banked_r13[0] = val; 310 } else if (regno == 14) { 311 env->banked_r14[0] = val; 312 } else if (regno >= 8 313 && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { 314 env->usr_regs[regno - 8] = val; 315 } else { 316 env->regs[regno] = val; 317 } 318 } 319 320 /* ??? Flag setting arithmetic is awkward because we need to do comparisons. 321 The only way to do that in TCG is a conditional branch, which clobbers 322 all our temporaries. For now implement these as helper functions. */ 323 324 uint32_t HELPER (add_cc)(CPUARMState *env, uint32_t a, uint32_t b) 325 { 326 uint32_t result; 327 result = a + b; 328 env->NF = env->ZF = result; 329 env->CF = result < a; 330 env->VF = (a ^ b ^ -1) & (a ^ result); 331 return result; 332 } 333 334 uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b) 335 { 336 uint32_t result; 337 if (!env->CF) { 338 result = a + b; 339 env->CF = result < a; 340 } else { 341 result = a + b + 1; 342 env->CF = result <= a; 343 } 344 env->VF = (a ^ b ^ -1) & (a ^ result); 345 env->NF = env->ZF = result; 346 return result; 347 } 348 349 uint32_t HELPER(sub_cc)(CPUARMState *env, uint32_t a, uint32_t b) 350 { 351 uint32_t result; 352 result = a - b; 353 env->NF = env->ZF = result; 354 env->CF = a >= b; 355 env->VF = (a ^ b) & (a ^ result); 356 return result; 357 } 358 359 uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b) 360 { 361 uint32_t result; 362 if (!env->CF) { 363 result = a - b - 1; 364 env->CF = a > b; 365 } else { 366 result = a - b; 367 env->CF = a >= b; 368 } 369 env->VF = (a ^ b) & (a ^ result); 370 env->NF = env->ZF = result; 371 return result; 372 } 373 374 /* Similarly for variable shift instructions. */ 375 376 uint32_t HELPER(shl)(uint32_t x, uint32_t i) 377 { 378 int shift = i & 0xff; 379 if (shift >= 32) 380 return 0; 381 return x << shift; 382 } 383 384 uint32_t HELPER(shr)(uint32_t x, uint32_t i) 385 { 386 int shift = i & 0xff; 387 if (shift >= 32) 388 return 0; 389 return (uint32_t)x >> shift; 390 } 391 392 uint32_t HELPER(sar)(uint32_t x, uint32_t i) 393 { 394 int shift = i & 0xff; 395 if (shift >= 32) 396 shift = 31; 397 return (int32_t)x >> shift; 398 } 399 400 uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i) 401 { 402 int shift = i & 0xff; 403 if (shift >= 32) { 404 if (shift == 32) 405 env->CF = x & 1; 406 else 407 env->CF = 0; 408 return 0; 409 } else if (shift != 0) { 410 env->CF = (x >> (32 - shift)) & 1; 411 return x << shift; 412 } 413 return x; 414 } 415 416 uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i) 417 { 418 int shift = i & 0xff; 419 if (shift >= 32) { 420 if (shift == 32) 421 env->CF = (x >> 31) & 1; 422 else 423 env->CF = 0; 424 return 0; 425 } else if (shift != 0) { 426 env->CF = (x >> (shift - 1)) & 1; 427 return x >> shift; 428 } 429 return x; 430 } 431 432 uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i) 433 { 434 int shift = i & 0xff; 435 if (shift >= 32) { 436 env->CF = (x >> 31) & 1; 437 return (int32_t)x >> 31; 438 } else if (shift != 0) { 439 env->CF = (x >> (shift - 1)) & 1; 440 return (int32_t)x >> shift; 441 } 442 return x; 443 } 444 445 uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i) 446 { 447 int shift1, shift; 448 shift1 = i & 0xff; 449 shift = shift1 & 0x1f; 450 if (shift == 0) { 451 if (shift1 != 0) 452 env->CF = (x >> 31) & 1; 453 return x; 454 } else { 455 env->CF = (x >> (shift - 1)) & 1; 456 return ((uint32_t)x >> shift) | (x << (32 - shift)); 457 } 458 } 459 460 void HELPER(neon_vldst_all)(CPUARMState *env, uint32_t insn) 461 { 462 #if defined(CONFIG_USER_ONLY) 463 #define LDB(addr) ldub(addr) 464 #define LDW(addr) lduw(addr) 465 #define LDL(addr) ldl(addr) 466 #define LDQ(addr) ldq(addr) 467 #define STB(addr, val) stb(addr, val) 468 #define STW(addr, val) stw(addr, val) 469 #define STL(addr, val) stl(addr, val) 470 #define STQ(addr, val) stq(addr, val) 471 #else 472 int user = cpu_mmu_index(env); 473 #define LDB(addr) helper_ldb_mmu(env, addr, user) 474 #define LDW(addr) helper_le_lduw_mmu(env, addr, user, GETPC()) 475 #define LDL(addr) helper_le_ldul_mmu(env, addr, user, GETPC()) 476 #define LDQ(addr) helper_le_ldq_mmu(env, addr, user, GETPC()) 477 #define STB(addr, val) helper_stb_mmu(env, addr, val, user) 478 #define STW(addr, val) helper_le_stw_mmu(env, addr, val, user, GETPC()) 479 #define STL(addr, val) helper_le_stl_mmu(env, addr, val, user, GETPC()) 480 #define STQ(addr, val) helper_le_stq_mmu(env, addr, val, user, GETPC()) 481 #endif 482 static const struct { 483 int nregs; 484 int interleave; 485 int spacing; 486 } neon_ls_element_type[11] = { 487 {4, 4, 1}, 488 {4, 4, 2}, 489 {4, 1, 1}, 490 {4, 2, 1}, 491 {3, 3, 1}, 492 {3, 3, 2}, 493 {3, 1, 1}, 494 {1, 1, 1}, 495 {2, 2, 1}, 496 {2, 2, 2}, 497 {2, 1, 1} 498 }; 499 500 const int op = (insn >> 8) & 0xf; 501 const int size = (insn >> 6) & 3; 502 int rd = ((insn >> 12) & 0x0f) | ((insn >> 18) & 0x10); 503 const int rn = (insn >> 16) & 0xf; 504 const int load = (insn & (1 << 21)) != 0; 505 const int nregs = neon_ls_element_type[op].nregs; 506 const int interleave = neon_ls_element_type[op].interleave; 507 const int spacing = neon_ls_element_type[op].spacing; 508 uint32_t addr = env->regs[rn]; 509 const int stride = (1 << size) * interleave; 510 int i, reg; 511 uint64_t tmp64; 512 513 for (reg = 0; reg < nregs; reg++) { 514 if (interleave > 2 || (interleave == 2 && nregs == 2)) { 515 addr = env->regs[rn] + (1 << size) * reg; 516 } else if (interleave == 2 && nregs == 4 && reg == 2) { 517 addr = env->regs[rn] + (1 << size); 518 } 519 switch (size) { 520 case 3: 521 if (load) { 522 env->vfp.regs[rd] = make_float64(LDQ(addr)); 523 } else { 524 STQ(addr, float64_val(env->vfp.regs[rd])); 525 } 526 addr += stride; 527 break; 528 case 2: 529 if (load) { 530 tmp64 = (uint32_t)LDL(addr); 531 addr += stride; 532 tmp64 |= (uint64_t)LDL(addr) << 32; 533 addr += stride; 534 env->vfp.regs[rd] = make_float64(tmp64); 535 } else { 536 tmp64 = float64_val(env->vfp.regs[rd]); 537 STL(addr, tmp64); 538 addr += stride; 539 STL(addr, tmp64 >> 32); 540 addr += stride; 541 } 542 break; 543 case 1: 544 if (load) { 545 tmp64 = 0ull; 546 for (i = 0; i < 4; i++, addr += stride) { 547 tmp64 |= (uint64_t)LDW(addr) << (i * 16); 548 } 549 env->vfp.regs[rd] = make_float64(tmp64); 550 } else { 551 tmp64 = float64_val(env->vfp.regs[rd]); 552 for (i = 0; i < 4; i++, addr += stride, tmp64 >>= 16) { 553 STW(addr, tmp64); 554 } 555 } 556 break; 557 case 0: 558 if (load) { 559 tmp64 = 0ull; 560 for (i = 0; i < 8; i++, addr += stride) { 561 tmp64 |= (uint64_t)LDB(addr) << (i * 8); 562 } 563 env->vfp.regs[rd] = make_float64(tmp64); 564 } else { 565 tmp64 = float64_val(env->vfp.regs[rd]); 566 for (i = 0; i < 8; i++, addr += stride, tmp64 >>= 8) { 567 STB(addr, tmp64); 568 } 569 } 570 break; 571 } 572 rd += spacing; 573 } 574 #undef LDB 575 #undef LDW 576 #undef LDL 577 #undef LDQ 578 #undef STB 579 #undef STW 580 #undef STL 581 #undef STQ 582 } 583