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