1 /* 2 * M68K helper routines 3 * 4 * Copyright (c) 2007 CodeSourcery 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 "qemu/osdep.h" 20 #include "cpu.h" 21 #include "exec/helper-proto.h" 22 #include "exec/exec-all.h" 23 #include "exec/cpu_ldst.h" 24 #include "exec/semihost.h" 25 26 #if defined(CONFIG_USER_ONLY) 27 28 void m68k_cpu_do_interrupt(CPUState *cs) 29 { 30 cs->exception_index = -1; 31 } 32 33 static inline void do_interrupt_m68k_hardirq(CPUM68KState *env) 34 { 35 } 36 37 #else 38 39 /* Try to fill the TLB and return an exception if error. If retaddr is 40 NULL, it means that the function was called in C code (i.e. not 41 from generated code or from helper.c) */ 42 void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, 43 int mmu_idx, uintptr_t retaddr) 44 { 45 int ret; 46 47 ret = m68k_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); 48 if (unlikely(ret)) { 49 /* now we have a real cpu fault */ 50 cpu_loop_exit_restore(cs, retaddr); 51 } 52 } 53 54 static void do_rte(CPUM68KState *env) 55 { 56 uint32_t sp; 57 uint32_t fmt; 58 59 sp = env->aregs[7]; 60 fmt = cpu_ldl_kernel(env, sp); 61 env->pc = cpu_ldl_kernel(env, sp + 4); 62 sp |= (fmt >> 28) & 3; 63 env->aregs[7] = sp + 8; 64 65 helper_set_sr(env, fmt); 66 } 67 68 static void do_interrupt_all(CPUM68KState *env, int is_hw) 69 { 70 CPUState *cs = CPU(m68k_env_get_cpu(env)); 71 uint32_t sp; 72 uint32_t fmt; 73 uint32_t retaddr; 74 uint32_t vector; 75 76 fmt = 0; 77 retaddr = env->pc; 78 79 if (!is_hw) { 80 switch (cs->exception_index) { 81 case EXCP_RTE: 82 /* Return from an exception. */ 83 do_rte(env); 84 return; 85 case EXCP_HALT_INSN: 86 if (semihosting_enabled() 87 && (env->sr & SR_S) != 0 88 && (env->pc & 3) == 0 89 && cpu_lduw_code(env, env->pc - 4) == 0x4e71 90 && cpu_ldl_code(env, env->pc) == 0x4e7bf000) { 91 env->pc += 4; 92 do_m68k_semihosting(env, env->dregs[0]); 93 return; 94 } 95 cs->halted = 1; 96 cs->exception_index = EXCP_HLT; 97 cpu_loop_exit(cs); 98 return; 99 } 100 if (cs->exception_index >= EXCP_TRAP0 101 && cs->exception_index <= EXCP_TRAP15) { 102 /* Move the PC after the trap instruction. */ 103 retaddr += 2; 104 } 105 } 106 107 vector = cs->exception_index << 2; 108 109 fmt |= 0x40000000; 110 fmt |= vector << 16; 111 fmt |= env->sr; 112 fmt |= cpu_m68k_get_ccr(env); 113 114 env->sr |= SR_S; 115 if (is_hw) { 116 env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); 117 env->sr &= ~SR_M; 118 } 119 m68k_switch_sp(env); 120 sp = env->aregs[7]; 121 fmt |= (sp & 3) << 28; 122 123 /* ??? This could cause MMU faults. */ 124 sp &= ~3; 125 sp -= 4; 126 cpu_stl_kernel(env, sp, retaddr); 127 sp -= 4; 128 cpu_stl_kernel(env, sp, fmt); 129 env->aregs[7] = sp; 130 /* Jump to vector. */ 131 env->pc = cpu_ldl_kernel(env, env->vbr + vector); 132 } 133 134 void m68k_cpu_do_interrupt(CPUState *cs) 135 { 136 M68kCPU *cpu = M68K_CPU(cs); 137 CPUM68KState *env = &cpu->env; 138 139 do_interrupt_all(env, 0); 140 } 141 142 static inline void do_interrupt_m68k_hardirq(CPUM68KState *env) 143 { 144 do_interrupt_all(env, 1); 145 } 146 #endif 147 148 bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 149 { 150 M68kCPU *cpu = M68K_CPU(cs); 151 CPUM68KState *env = &cpu->env; 152 153 if (interrupt_request & CPU_INTERRUPT_HARD 154 && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) { 155 /* Real hardware gets the interrupt vector via an IACK cycle 156 at this point. Current emulated hardware doesn't rely on 157 this, so we provide/save the vector when the interrupt is 158 first signalled. */ 159 cs->exception_index = env->pending_vector; 160 do_interrupt_m68k_hardirq(env); 161 return true; 162 } 163 return false; 164 } 165 166 static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) 167 { 168 CPUState *cs = CPU(m68k_env_get_cpu(env)); 169 170 cs->exception_index = tt; 171 cpu_loop_exit_restore(cs, raddr); 172 } 173 174 static void raise_exception(CPUM68KState *env, int tt) 175 { 176 raise_exception_ra(env, tt, 0); 177 } 178 179 void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) 180 { 181 raise_exception(env, tt); 182 } 183 184 void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) 185 { 186 uint32_t num = env->dregs[destr]; 187 uint32_t quot, rem; 188 189 if (den == 0) { 190 raise_exception_ra(env, EXCP_DIV0, GETPC()); 191 } 192 quot = num / den; 193 rem = num % den; 194 195 env->cc_c = 0; /* always cleared, even if overflow */ 196 if (quot > 0xffff) { 197 env->cc_v = -1; 198 /* real 68040 keeps N and unset Z on overflow, 199 * whereas documentation says "undefined" 200 */ 201 env->cc_z = 1; 202 return; 203 } 204 env->dregs[destr] = deposit32(quot, 16, 16, rem); 205 env->cc_z = (int16_t)quot; 206 env->cc_n = (int16_t)quot; 207 env->cc_v = 0; 208 } 209 210 void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den) 211 { 212 int32_t num = env->dregs[destr]; 213 uint32_t quot, rem; 214 215 if (den == 0) { 216 raise_exception_ra(env, EXCP_DIV0, GETPC()); 217 } 218 quot = num / den; 219 rem = num % den; 220 221 env->cc_c = 0; /* always cleared, even if overflow */ 222 if (quot != (int16_t)quot) { 223 env->cc_v = -1; 224 /* nothing else is modified */ 225 /* real 68040 keeps N and unset Z on overflow, 226 * whereas documentation says "undefined" 227 */ 228 env->cc_z = 1; 229 return; 230 } 231 env->dregs[destr] = deposit32(quot, 16, 16, rem); 232 env->cc_z = (int16_t)quot; 233 env->cc_n = (int16_t)quot; 234 env->cc_v = 0; 235 } 236 237 void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den) 238 { 239 uint32_t num = env->dregs[numr]; 240 uint32_t quot, rem; 241 242 if (den == 0) { 243 raise_exception_ra(env, EXCP_DIV0, GETPC()); 244 } 245 quot = num / den; 246 rem = num % den; 247 248 env->cc_c = 0; 249 env->cc_z = quot; 250 env->cc_n = quot; 251 env->cc_v = 0; 252 253 if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { 254 if (numr == regr) { 255 env->dregs[numr] = quot; 256 } else { 257 env->dregs[regr] = rem; 258 } 259 } else { 260 env->dregs[regr] = rem; 261 env->dregs[numr] = quot; 262 } 263 } 264 265 void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den) 266 { 267 int32_t num = env->dregs[numr]; 268 int32_t quot, rem; 269 270 if (den == 0) { 271 raise_exception_ra(env, EXCP_DIV0, GETPC()); 272 } 273 quot = num / den; 274 rem = num % den; 275 276 env->cc_c = 0; 277 env->cc_z = quot; 278 env->cc_n = quot; 279 env->cc_v = 0; 280 281 if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { 282 if (numr == regr) { 283 env->dregs[numr] = quot; 284 } else { 285 env->dregs[regr] = rem; 286 } 287 } else { 288 env->dregs[regr] = rem; 289 env->dregs[numr] = quot; 290 } 291 } 292 293 void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den) 294 { 295 uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); 296 uint64_t quot; 297 uint32_t rem; 298 299 if (den == 0) { 300 raise_exception_ra(env, EXCP_DIV0, GETPC()); 301 } 302 quot = num / den; 303 rem = num % den; 304 305 env->cc_c = 0; /* always cleared, even if overflow */ 306 if (quot > 0xffffffffULL) { 307 env->cc_v = -1; 308 /* real 68040 keeps N and unset Z on overflow, 309 * whereas documentation says "undefined" 310 */ 311 env->cc_z = 1; 312 return; 313 } 314 env->cc_z = quot; 315 env->cc_n = quot; 316 env->cc_v = 0; 317 318 /* 319 * If Dq and Dr are the same, the quotient is returned. 320 * therefore we set Dq last. 321 */ 322 323 env->dregs[regr] = rem; 324 env->dregs[numr] = quot; 325 } 326 327 void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den) 328 { 329 int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); 330 int64_t quot; 331 int32_t rem; 332 333 if (den == 0) { 334 raise_exception_ra(env, EXCP_DIV0, GETPC()); 335 } 336 quot = num / den; 337 rem = num % den; 338 339 env->cc_c = 0; /* always cleared, even if overflow */ 340 if (quot != (int32_t)quot) { 341 env->cc_v = -1; 342 /* real 68040 keeps N and unset Z on overflow, 343 * whereas documentation says "undefined" 344 */ 345 env->cc_z = 1; 346 return; 347 } 348 env->cc_z = quot; 349 env->cc_n = quot; 350 env->cc_v = 0; 351 352 /* 353 * If Dq and Dr are the same, the quotient is returned. 354 * therefore we set Dq last. 355 */ 356 357 env->dregs[regr] = rem; 358 env->dregs[numr] = quot; 359 } 360 361 /* We're executing in a serial context -- no need to be atomic. */ 362 void HELPER(cas2w)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2) 363 { 364 uint32_t Dc1 = extract32(regs, 9, 3); 365 uint32_t Dc2 = extract32(regs, 6, 3); 366 uint32_t Du1 = extract32(regs, 3, 3); 367 uint32_t Du2 = extract32(regs, 0, 3); 368 int16_t c1 = env->dregs[Dc1]; 369 int16_t c2 = env->dregs[Dc2]; 370 int16_t u1 = env->dregs[Du1]; 371 int16_t u2 = env->dregs[Du2]; 372 int16_t l1, l2; 373 uintptr_t ra = GETPC(); 374 375 l1 = cpu_lduw_data_ra(env, a1, ra); 376 l2 = cpu_lduw_data_ra(env, a2, ra); 377 if (l1 == c1 && l2 == c2) { 378 cpu_stw_data_ra(env, a1, u1, ra); 379 cpu_stw_data_ra(env, a2, u2, ra); 380 } 381 382 if (c1 != l1) { 383 env->cc_n = l1; 384 env->cc_v = c1; 385 } else { 386 env->cc_n = l2; 387 env->cc_v = c2; 388 } 389 env->cc_op = CC_OP_CMPW; 390 env->dregs[Dc1] = deposit32(env->dregs[Dc1], 0, 16, l1); 391 env->dregs[Dc2] = deposit32(env->dregs[Dc2], 0, 16, l2); 392 } 393 394 static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2, 395 bool parallel) 396 { 397 uint32_t Dc1 = extract32(regs, 9, 3); 398 uint32_t Dc2 = extract32(regs, 6, 3); 399 uint32_t Du1 = extract32(regs, 3, 3); 400 uint32_t Du2 = extract32(regs, 0, 3); 401 uint32_t c1 = env->dregs[Dc1]; 402 uint32_t c2 = env->dregs[Dc2]; 403 uint32_t u1 = env->dregs[Du1]; 404 uint32_t u2 = env->dregs[Du2]; 405 uint32_t l1, l2; 406 uintptr_t ra = GETPC(); 407 #if defined(CONFIG_ATOMIC64) && !defined(CONFIG_USER_ONLY) 408 int mmu_idx = cpu_mmu_index(env, 0); 409 TCGMemOpIdx oi; 410 #endif 411 412 if (parallel) { 413 /* We're executing in a parallel context -- must be atomic. */ 414 #ifdef CONFIG_ATOMIC64 415 uint64_t c, u, l; 416 if ((a1 & 7) == 0 && a2 == a1 + 4) { 417 c = deposit64(c2, 32, 32, c1); 418 u = deposit64(u2, 32, 32, u1); 419 #ifdef CONFIG_USER_ONLY 420 l = helper_atomic_cmpxchgq_be(env, a1, c, u); 421 #else 422 oi = make_memop_idx(MO_BEQ, mmu_idx); 423 l = helper_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra); 424 #endif 425 l1 = l >> 32; 426 l2 = l; 427 } else if ((a2 & 7) == 0 && a1 == a2 + 4) { 428 c = deposit64(c1, 32, 32, c2); 429 u = deposit64(u1, 32, 32, u2); 430 #ifdef CONFIG_USER_ONLY 431 l = helper_atomic_cmpxchgq_be(env, a2, c, u); 432 #else 433 oi = make_memop_idx(MO_BEQ, mmu_idx); 434 l = helper_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra); 435 #endif 436 l2 = l >> 32; 437 l1 = l; 438 } else 439 #endif 440 { 441 /* Tell the main loop we need to serialize this insn. */ 442 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra); 443 } 444 } else { 445 /* We're executing in a serial context -- no need to be atomic. */ 446 l1 = cpu_ldl_data_ra(env, a1, ra); 447 l2 = cpu_ldl_data_ra(env, a2, ra); 448 if (l1 == c1 && l2 == c2) { 449 cpu_stl_data_ra(env, a1, u1, ra); 450 cpu_stl_data_ra(env, a2, u2, ra); 451 } 452 } 453 454 if (c1 != l1) { 455 env->cc_n = l1; 456 env->cc_v = c1; 457 } else { 458 env->cc_n = l2; 459 env->cc_v = c2; 460 } 461 env->cc_op = CC_OP_CMPL; 462 env->dregs[Dc1] = l1; 463 env->dregs[Dc2] = l2; 464 } 465 466 void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2) 467 { 468 do_cas2l(env, regs, a1, a2, false); 469 } 470 471 void HELPER(cas2l_parallel)(CPUM68KState *env, uint32_t regs, uint32_t a1, 472 uint32_t a2) 473 { 474 do_cas2l(env, regs, a1, a2, true); 475 } 476 477 struct bf_data { 478 uint32_t addr; 479 uint32_t bofs; 480 uint32_t blen; 481 uint32_t len; 482 }; 483 484 static struct bf_data bf_prep(uint32_t addr, int32_t ofs, uint32_t len) 485 { 486 int bofs, blen; 487 488 /* Bound length; map 0 to 32. */ 489 len = ((len - 1) & 31) + 1; 490 491 /* Note that ofs is signed. */ 492 addr += ofs / 8; 493 bofs = ofs % 8; 494 if (bofs < 0) { 495 bofs += 8; 496 addr -= 1; 497 } 498 499 /* Compute the number of bytes required (minus one) to 500 satisfy the bitfield. */ 501 blen = (bofs + len - 1) / 8; 502 503 /* Canonicalize the bit offset for data loaded into a 64-bit big-endian 504 word. For the cases where BLEN is not a power of 2, adjust ADDR so 505 that we can use the next power of two sized load without crossing a 506 page boundary, unless the field itself crosses the boundary. */ 507 switch (blen) { 508 case 0: 509 bofs += 56; 510 break; 511 case 1: 512 bofs += 48; 513 break; 514 case 2: 515 if (addr & 1) { 516 bofs += 8; 517 addr -= 1; 518 } 519 /* fallthru */ 520 case 3: 521 bofs += 32; 522 break; 523 case 4: 524 if (addr & 3) { 525 bofs += 8 * (addr & 3); 526 addr &= -4; 527 } 528 break; 529 default: 530 g_assert_not_reached(); 531 } 532 533 return (struct bf_data){ 534 .addr = addr, 535 .bofs = bofs, 536 .blen = blen, 537 .len = len, 538 }; 539 } 540 541 static uint64_t bf_load(CPUM68KState *env, uint32_t addr, int blen, 542 uintptr_t ra) 543 { 544 switch (blen) { 545 case 0: 546 return cpu_ldub_data_ra(env, addr, ra); 547 case 1: 548 return cpu_lduw_data_ra(env, addr, ra); 549 case 2: 550 case 3: 551 return cpu_ldl_data_ra(env, addr, ra); 552 case 4: 553 return cpu_ldq_data_ra(env, addr, ra); 554 default: 555 g_assert_not_reached(); 556 } 557 } 558 559 static void bf_store(CPUM68KState *env, uint32_t addr, int blen, 560 uint64_t data, uintptr_t ra) 561 { 562 switch (blen) { 563 case 0: 564 cpu_stb_data_ra(env, addr, data, ra); 565 break; 566 case 1: 567 cpu_stw_data_ra(env, addr, data, ra); 568 break; 569 case 2: 570 case 3: 571 cpu_stl_data_ra(env, addr, data, ra); 572 break; 573 case 4: 574 cpu_stq_data_ra(env, addr, data, ra); 575 break; 576 default: 577 g_assert_not_reached(); 578 } 579 } 580 581 uint32_t HELPER(bfexts_mem)(CPUM68KState *env, uint32_t addr, 582 int32_t ofs, uint32_t len) 583 { 584 uintptr_t ra = GETPC(); 585 struct bf_data d = bf_prep(addr, ofs, len); 586 uint64_t data = bf_load(env, d.addr, d.blen, ra); 587 588 return (int64_t)(data << d.bofs) >> (64 - d.len); 589 } 590 591 uint64_t HELPER(bfextu_mem)(CPUM68KState *env, uint32_t addr, 592 int32_t ofs, uint32_t len) 593 { 594 uintptr_t ra = GETPC(); 595 struct bf_data d = bf_prep(addr, ofs, len); 596 uint64_t data = bf_load(env, d.addr, d.blen, ra); 597 598 /* Put CC_N at the top of the high word; put the zero-extended value 599 at the bottom of the low word. */ 600 data <<= d.bofs; 601 data >>= 64 - d.len; 602 data |= data << (64 - d.len); 603 604 return data; 605 } 606 607 uint32_t HELPER(bfins_mem)(CPUM68KState *env, uint32_t addr, uint32_t val, 608 int32_t ofs, uint32_t len) 609 { 610 uintptr_t ra = GETPC(); 611 struct bf_data d = bf_prep(addr, ofs, len); 612 uint64_t data = bf_load(env, d.addr, d.blen, ra); 613 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 614 615 data = (data & ~mask) | (((uint64_t)val << (64 - d.len)) >> d.bofs); 616 617 bf_store(env, d.addr, d.blen, data, ra); 618 619 /* The field at the top of the word is also CC_N for CC_OP_LOGIC. */ 620 return val << (32 - d.len); 621 } 622 623 uint32_t HELPER(bfchg_mem)(CPUM68KState *env, uint32_t addr, 624 int32_t ofs, uint32_t len) 625 { 626 uintptr_t ra = GETPC(); 627 struct bf_data d = bf_prep(addr, ofs, len); 628 uint64_t data = bf_load(env, d.addr, d.blen, ra); 629 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 630 631 bf_store(env, d.addr, d.blen, data ^ mask, ra); 632 633 return ((data & mask) << d.bofs) >> 32; 634 } 635 636 uint32_t HELPER(bfclr_mem)(CPUM68KState *env, uint32_t addr, 637 int32_t ofs, uint32_t len) 638 { 639 uintptr_t ra = GETPC(); 640 struct bf_data d = bf_prep(addr, ofs, len); 641 uint64_t data = bf_load(env, d.addr, d.blen, ra); 642 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 643 644 bf_store(env, d.addr, d.blen, data & ~mask, ra); 645 646 return ((data & mask) << d.bofs) >> 32; 647 } 648 649 uint32_t HELPER(bfset_mem)(CPUM68KState *env, uint32_t addr, 650 int32_t ofs, uint32_t len) 651 { 652 uintptr_t ra = GETPC(); 653 struct bf_data d = bf_prep(addr, ofs, len); 654 uint64_t data = bf_load(env, d.addr, d.blen, ra); 655 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 656 657 bf_store(env, d.addr, d.blen, data | mask, ra); 658 659 return ((data & mask) << d.bofs) >> 32; 660 } 661 662 uint32_t HELPER(bfffo_reg)(uint32_t n, uint32_t ofs, uint32_t len) 663 { 664 return (n ? clz32(n) : len) + ofs; 665 } 666 667 uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr, 668 int32_t ofs, uint32_t len) 669 { 670 uintptr_t ra = GETPC(); 671 struct bf_data d = bf_prep(addr, ofs, len); 672 uint64_t data = bf_load(env, d.addr, d.blen, ra); 673 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 674 uint64_t n = (data & mask) << d.bofs; 675 uint32_t ffo = helper_bfffo_reg(n >> 32, ofs, d.len); 676 677 /* Return FFO in the low word and N in the high word. 678 Note that because of MASK and the shift, the low word 679 is already zero. */ 680 return n | ffo; 681 } 682