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.1 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 "qemu/log.h" 21 #include "cpu.h" 22 #include "exec/helper-proto.h" 23 #include "accel/tcg/cpu-ldst.h" 24 #include "semihosting/semihost.h" 25 26 #if !defined(CONFIG_USER_ONLY) 27 28 static void cf_rte(CPUM68KState *env) 29 { 30 uint32_t sp; 31 uint32_t fmt; 32 33 sp = env->aregs[7]; 34 fmt = cpu_ldl_mmuidx_ra(env, sp, MMU_KERNEL_IDX, 0); 35 env->pc = cpu_ldl_mmuidx_ra(env, sp + 4, MMU_KERNEL_IDX, 0); 36 sp |= (fmt >> 28) & 3; 37 env->aregs[7] = sp + 8; 38 39 cpu_m68k_set_sr(env, fmt); 40 } 41 42 static void m68k_rte(CPUM68KState *env) 43 { 44 uint32_t sp; 45 uint16_t fmt; 46 uint16_t sr; 47 48 sp = env->aregs[7]; 49 throwaway: 50 sr = cpu_lduw_mmuidx_ra(env, sp, MMU_KERNEL_IDX, 0); 51 sp += 2; 52 env->pc = cpu_ldl_mmuidx_ra(env, sp, MMU_KERNEL_IDX, 0); 53 sp += 4; 54 if (m68k_feature(env, M68K_FEATURE_EXCEPTION_FORMAT_VEC)) { 55 /* all except 68000 */ 56 fmt = cpu_lduw_mmuidx_ra(env, sp, MMU_KERNEL_IDX, 0); 57 sp += 2; 58 switch (fmt >> 12) { 59 case 0: 60 break; 61 case 1: 62 env->aregs[7] = sp; 63 cpu_m68k_set_sr(env, sr); 64 goto throwaway; 65 case 2: 66 case 3: 67 sp += 4; 68 break; 69 case 4: 70 sp += 8; 71 break; 72 case 7: 73 sp += 52; 74 break; 75 } 76 } 77 env->aregs[7] = sp; 78 cpu_m68k_set_sr(env, sr); 79 } 80 81 static const char *m68k_exception_name(int index) 82 { 83 switch (index) { 84 case EXCP_ACCESS: 85 return "Access Fault"; 86 case EXCP_ADDRESS: 87 return "Address Error"; 88 case EXCP_ILLEGAL: 89 return "Illegal Instruction"; 90 case EXCP_DIV0: 91 return "Divide by Zero"; 92 case EXCP_CHK: 93 return "CHK/CHK2"; 94 case EXCP_TRAPCC: 95 return "FTRAPcc, TRAPcc, TRAPV"; 96 case EXCP_PRIVILEGE: 97 return "Privilege Violation"; 98 case EXCP_TRACE: 99 return "Trace"; 100 case EXCP_LINEA: 101 return "A-Line"; 102 case EXCP_LINEF: 103 return "F-Line"; 104 case EXCP_DEBEGBP: /* 68020/030 only */ 105 return "Copro Protocol Violation"; 106 case EXCP_FORMAT: 107 return "Format Error"; 108 case EXCP_UNINITIALIZED: 109 return "Uninitialized Interrupt"; 110 case EXCP_SPURIOUS: 111 return "Spurious Interrupt"; 112 case EXCP_INT_LEVEL_1: 113 return "Level 1 Interrupt"; 114 case EXCP_INT_LEVEL_1 + 1: 115 return "Level 2 Interrupt"; 116 case EXCP_INT_LEVEL_1 + 2: 117 return "Level 3 Interrupt"; 118 case EXCP_INT_LEVEL_1 + 3: 119 return "Level 4 Interrupt"; 120 case EXCP_INT_LEVEL_1 + 4: 121 return "Level 5 Interrupt"; 122 case EXCP_INT_LEVEL_1 + 5: 123 return "Level 6 Interrupt"; 124 case EXCP_INT_LEVEL_1 + 6: 125 return "Level 7 Interrupt"; 126 case EXCP_TRAP0: 127 return "TRAP #0"; 128 case EXCP_TRAP0 + 1: 129 return "TRAP #1"; 130 case EXCP_TRAP0 + 2: 131 return "TRAP #2"; 132 case EXCP_TRAP0 + 3: 133 return "TRAP #3"; 134 case EXCP_TRAP0 + 4: 135 return "TRAP #4"; 136 case EXCP_TRAP0 + 5: 137 return "TRAP #5"; 138 case EXCP_TRAP0 + 6: 139 return "TRAP #6"; 140 case EXCP_TRAP0 + 7: 141 return "TRAP #7"; 142 case EXCP_TRAP0 + 8: 143 return "TRAP #8"; 144 case EXCP_TRAP0 + 9: 145 return "TRAP #9"; 146 case EXCP_TRAP0 + 10: 147 return "TRAP #10"; 148 case EXCP_TRAP0 + 11: 149 return "TRAP #11"; 150 case EXCP_TRAP0 + 12: 151 return "TRAP #12"; 152 case EXCP_TRAP0 + 13: 153 return "TRAP #13"; 154 case EXCP_TRAP0 + 14: 155 return "TRAP #14"; 156 case EXCP_TRAP0 + 15: 157 return "TRAP #15"; 158 case EXCP_FP_BSUN: 159 return "FP Branch/Set on unordered condition"; 160 case EXCP_FP_INEX: 161 return "FP Inexact Result"; 162 case EXCP_FP_DZ: 163 return "FP Divide by Zero"; 164 case EXCP_FP_UNFL: 165 return "FP Underflow"; 166 case EXCP_FP_OPERR: 167 return "FP Operand Error"; 168 case EXCP_FP_OVFL: 169 return "FP Overflow"; 170 case EXCP_FP_SNAN: 171 return "FP Signaling NAN"; 172 case EXCP_FP_UNIMP: 173 return "FP Unimplemented Data Type"; 174 case EXCP_MMU_CONF: /* 68030/68851 only */ 175 return "MMU Configuration Error"; 176 case EXCP_MMU_ILLEGAL: /* 68851 only */ 177 return "MMU Illegal Operation"; 178 case EXCP_MMU_ACCESS: /* 68851 only */ 179 return "MMU Access Level Violation"; 180 case 64 ... 255: 181 return "User Defined Vector"; 182 } 183 return "Unassigned"; 184 } 185 186 static void cf_interrupt_all(CPUM68KState *env, int is_hw) 187 { 188 CPUState *cs = env_cpu(env); 189 uint32_t sp; 190 uint32_t sr; 191 uint32_t fmt; 192 uint32_t retaddr; 193 uint32_t vector; 194 195 fmt = 0; 196 retaddr = env->pc; 197 198 if (!is_hw) { 199 switch (cs->exception_index) { 200 case EXCP_RTE: 201 /* Return from an exception. */ 202 cf_rte(env); 203 return; 204 case EXCP_SEMIHOSTING: 205 do_m68k_semihosting(env, env->dregs[0]); 206 return; 207 } 208 } 209 210 vector = cs->exception_index << 2; 211 212 sr = env->sr | cpu_m68k_get_ccr(env); 213 if (qemu_loglevel_mask(CPU_LOG_INT)) { 214 static int count; 215 qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n", 216 ++count, m68k_exception_name(cs->exception_index), 217 vector, env->pc, env->aregs[7], sr); 218 } 219 220 fmt |= 0x40000000; 221 fmt |= vector << 16; 222 fmt |= sr; 223 224 env->sr |= SR_S; 225 if (is_hw) { 226 env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); 227 env->sr &= ~SR_M; 228 } 229 m68k_switch_sp(env); 230 sp = env->aregs[7]; 231 fmt |= (sp & 3) << 28; 232 233 /* ??? This could cause MMU faults. */ 234 sp &= ~3; 235 sp -= 4; 236 cpu_stl_mmuidx_ra(env, sp, retaddr, MMU_KERNEL_IDX, 0); 237 sp -= 4; 238 cpu_stl_mmuidx_ra(env, sp, fmt, MMU_KERNEL_IDX, 0); 239 env->aregs[7] = sp; 240 /* Jump to vector. */ 241 env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0); 242 } 243 244 static inline void do_stack_frame(CPUM68KState *env, uint32_t *sp, 245 uint16_t format, uint16_t sr, 246 uint32_t addr, uint32_t retaddr) 247 { 248 if (m68k_feature(env, M68K_FEATURE_EXCEPTION_FORMAT_VEC)) { 249 /* all except 68000 */ 250 CPUState *cs = env_cpu(env); 251 switch (format) { 252 case 4: 253 *sp -= 4; 254 cpu_stl_mmuidx_ra(env, *sp, env->pc, MMU_KERNEL_IDX, 0); 255 *sp -= 4; 256 cpu_stl_mmuidx_ra(env, *sp, addr, MMU_KERNEL_IDX, 0); 257 break; 258 case 3: 259 case 2: 260 *sp -= 4; 261 cpu_stl_mmuidx_ra(env, *sp, addr, MMU_KERNEL_IDX, 0); 262 break; 263 } 264 *sp -= 2; 265 cpu_stw_mmuidx_ra(env, *sp, (format << 12) + (cs->exception_index << 2), 266 MMU_KERNEL_IDX, 0); 267 } 268 *sp -= 4; 269 cpu_stl_mmuidx_ra(env, *sp, retaddr, MMU_KERNEL_IDX, 0); 270 *sp -= 2; 271 cpu_stw_mmuidx_ra(env, *sp, sr, MMU_KERNEL_IDX, 0); 272 } 273 274 static void m68k_interrupt_all(CPUM68KState *env, int is_hw) 275 { 276 CPUState *cs = env_cpu(env); 277 uint32_t sp; 278 uint32_t vector; 279 uint16_t sr, oldsr; 280 281 if (!is_hw) { 282 switch (cs->exception_index) { 283 case EXCP_RTE: 284 /* Return from an exception. */ 285 m68k_rte(env); 286 return; 287 } 288 } 289 290 vector = cs->exception_index << 2; 291 292 sr = env->sr | cpu_m68k_get_ccr(env); 293 if (qemu_loglevel_mask(CPU_LOG_INT)) { 294 static int count; 295 qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n", 296 ++count, m68k_exception_name(cs->exception_index), 297 vector, env->pc, env->aregs[7], sr); 298 } 299 300 /* 301 * MC68040UM/AD, chapter 9.3.10 302 */ 303 304 /* "the processor first make an internal copy" */ 305 oldsr = sr; 306 /* "set the mode to supervisor" */ 307 sr |= SR_S; 308 /* "suppress tracing" */ 309 sr &= ~SR_T; 310 /* "sets the processor interrupt mask" */ 311 if (is_hw) { 312 sr |= (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); 313 } 314 cpu_m68k_set_sr(env, sr); 315 sp = env->aregs[7]; 316 317 if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { 318 sp &= ~1; 319 } 320 321 switch (cs->exception_index) { 322 case EXCP_ACCESS: 323 if (env->mmu.fault) { 324 cpu_abort(cs, "DOUBLE MMU FAULT\n"); 325 } 326 env->mmu.fault = true; 327 /* push data 3 */ 328 sp -= 4; 329 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 330 /* push data 2 */ 331 sp -= 4; 332 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 333 /* push data 1 */ 334 sp -= 4; 335 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 336 /* write back 1 / push data 0 */ 337 sp -= 4; 338 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 339 /* write back 1 address */ 340 sp -= 4; 341 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 342 /* write back 2 data */ 343 sp -= 4; 344 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 345 /* write back 2 address */ 346 sp -= 4; 347 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 348 /* write back 3 data */ 349 sp -= 4; 350 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 351 /* write back 3 address */ 352 sp -= 4; 353 cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0); 354 /* fault address */ 355 sp -= 4; 356 cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0); 357 /* write back 1 status */ 358 sp -= 2; 359 cpu_stw_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 360 /* write back 2 status */ 361 sp -= 2; 362 cpu_stw_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 363 /* write back 3 status */ 364 sp -= 2; 365 cpu_stw_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0); 366 /* special status word */ 367 sp -= 2; 368 cpu_stw_mmuidx_ra(env, sp, env->mmu.ssw, MMU_KERNEL_IDX, 0); 369 /* effective address */ 370 sp -= 4; 371 cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0); 372 373 do_stack_frame(env, &sp, 7, oldsr, 0, env->pc); 374 env->mmu.fault = false; 375 if (qemu_loglevel_mask(CPU_LOG_INT)) { 376 qemu_log(" " 377 "ssw: %08x ea: %08x sfc: %d dfc: %d\n", 378 env->mmu.ssw, env->mmu.ar, env->sfc, env->dfc); 379 } 380 break; 381 382 case EXCP_ILLEGAL: 383 do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); 384 break; 385 386 case EXCP_ADDRESS: 387 do_stack_frame(env, &sp, 2, oldsr, 0, env->pc); 388 break; 389 390 case EXCP_CHK: 391 case EXCP_DIV0: 392 case EXCP_TRACE: 393 case EXCP_TRAPCC: 394 do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc); 395 break; 396 397 case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7: 398 if (is_hw && (oldsr & SR_M)) { 399 do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); 400 oldsr = sr; 401 env->aregs[7] = sp; 402 cpu_m68k_set_sr(env, sr & ~SR_M); 403 sp = env->aregs[7]; 404 if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { 405 sp &= ~1; 406 } 407 do_stack_frame(env, &sp, 1, oldsr, 0, env->pc); 408 break; 409 } 410 /* fall through */ 411 412 default: 413 do_stack_frame(env, &sp, 0, oldsr, 0, env->pc); 414 break; 415 } 416 417 env->aregs[7] = sp; 418 /* Jump to vector. */ 419 env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0); 420 } 421 422 static void do_interrupt_all(CPUM68KState *env, int is_hw) 423 { 424 if (m68k_feature(env, M68K_FEATURE_M68K)) { 425 m68k_interrupt_all(env, is_hw); 426 return; 427 } 428 cf_interrupt_all(env, is_hw); 429 } 430 431 void m68k_cpu_do_interrupt(CPUState *cs) 432 { 433 do_interrupt_all(cpu_env(cs), 0); 434 } 435 436 static inline void do_interrupt_m68k_hardirq(CPUM68KState *env) 437 { 438 do_interrupt_all(env, 1); 439 } 440 441 void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, 442 unsigned size, MMUAccessType access_type, 443 int mmu_idx, MemTxAttrs attrs, 444 MemTxResult response, uintptr_t retaddr) 445 { 446 CPUM68KState *env = cpu_env(cs); 447 448 cpu_restore_state(cs, retaddr); 449 450 if (m68k_feature(env, M68K_FEATURE_M68040)) { 451 env->mmu.mmusr = 0; 452 453 /* 454 * According to the MC68040 users manual the ATC bit of the SSW is 455 * used to distinguish between ATC faults and physical bus errors. 456 * In the case of a bus error e.g. during nubus read from an empty 457 * slot this bit should not be set 458 */ 459 if (response != MEMTX_DECODE_ERROR) { 460 env->mmu.ssw |= M68K_ATC_040; 461 } 462 463 /* FIXME: manage MMU table access error */ 464 env->mmu.ssw &= ~M68K_TM_040; 465 if (env->sr & SR_S) { /* SUPERVISOR */ 466 env->mmu.ssw |= M68K_TM_040_SUPER; 467 } 468 if (access_type == MMU_INST_FETCH) { /* instruction or data */ 469 env->mmu.ssw |= M68K_TM_040_CODE; 470 } else { 471 env->mmu.ssw |= M68K_TM_040_DATA; 472 } 473 env->mmu.ssw &= ~M68K_BA_SIZE_MASK; 474 switch (size) { 475 case 1: 476 env->mmu.ssw |= M68K_BA_SIZE_BYTE; 477 break; 478 case 2: 479 env->mmu.ssw |= M68K_BA_SIZE_WORD; 480 break; 481 case 4: 482 env->mmu.ssw |= M68K_BA_SIZE_LONG; 483 break; 484 } 485 486 if (access_type != MMU_DATA_STORE) { 487 env->mmu.ssw |= M68K_RW_040; 488 } 489 490 env->mmu.ar = addr; 491 492 cs->exception_index = EXCP_ACCESS; 493 cpu_loop_exit(cs); 494 } 495 } 496 497 bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 498 { 499 CPUM68KState *env = cpu_env(cs); 500 501 if (interrupt_request & CPU_INTERRUPT_HARD 502 && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) { 503 /* 504 * Real hardware gets the interrupt vector via an IACK cycle 505 * at this point. Current emulated hardware doesn't rely on 506 * this, so we provide/save the vector when the interrupt is 507 * first signalled. 508 */ 509 cs->exception_index = env->pending_vector; 510 do_interrupt_m68k_hardirq(env); 511 return true; 512 } 513 return false; 514 } 515 516 #endif /* !CONFIG_USER_ONLY */ 517 518 G_NORETURN static void 519 raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) 520 { 521 CPUState *cs = env_cpu(env); 522 523 cs->exception_index = tt; 524 cpu_loop_exit_restore(cs, raddr); 525 } 526 527 G_NORETURN static void raise_exception(CPUM68KState *env, int tt) 528 { 529 raise_exception_ra(env, tt, 0); 530 } 531 532 void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) 533 { 534 raise_exception(env, tt); 535 } 536 537 G_NORETURN static void 538 raise_exception_format2(CPUM68KState *env, int tt, int ilen, uintptr_t raddr) 539 { 540 CPUState *cs = env_cpu(env); 541 542 cs->exception_index = tt; 543 544 /* Recover PC and CC_OP for the beginning of the insn. */ 545 cpu_restore_state(cs, raddr); 546 547 /* Flags are current in env->cc_*, or are undefined. */ 548 env->cc_op = CC_OP_FLAGS; 549 550 /* 551 * Remember original pc in mmu.ar, for the Format 2 stack frame. 552 * Adjust PC to end of the insn. 553 */ 554 env->mmu.ar = env->pc; 555 env->pc += ilen; 556 557 cpu_loop_exit(cs); 558 } 559 560 void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den, int ilen) 561 { 562 uint32_t num = env->dregs[destr]; 563 uint32_t quot, rem; 564 565 env->cc_c = 0; /* always cleared, even if div0 */ 566 567 if (den == 0) { 568 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); 569 } 570 quot = num / den; 571 rem = num % den; 572 573 if (quot > 0xffff) { 574 env->cc_v = -1; 575 /* 576 * real 68040 keeps N and unset Z on overflow, 577 * whereas documentation says "undefined" 578 */ 579 env->cc_z = 1; 580 return; 581 } 582 env->dregs[destr] = deposit32(quot, 16, 16, rem); 583 env->cc_z = (int16_t)quot; 584 env->cc_n = (int16_t)quot; 585 env->cc_v = 0; 586 } 587 588 void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den, int ilen) 589 { 590 int32_t num = env->dregs[destr]; 591 uint32_t quot, rem; 592 593 env->cc_c = 0; /* always cleared, even if overflow/div0 */ 594 595 if (den == 0) { 596 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); 597 } 598 quot = num / den; 599 rem = num % den; 600 601 if (quot != (int16_t)quot) { 602 env->cc_v = -1; 603 /* nothing else is modified */ 604 /* 605 * real 68040 keeps N and unset Z on overflow, 606 * whereas documentation says "undefined" 607 */ 608 env->cc_z = 1; 609 return; 610 } 611 env->dregs[destr] = deposit32(quot, 16, 16, rem); 612 env->cc_z = (int16_t)quot; 613 env->cc_n = (int16_t)quot; 614 env->cc_v = 0; 615 } 616 617 void HELPER(divul)(CPUM68KState *env, int numr, int regr, 618 uint32_t den, int ilen) 619 { 620 uint32_t num = env->dregs[numr]; 621 uint32_t quot, rem; 622 623 env->cc_c = 0; /* always cleared, even if div0 */ 624 625 if (den == 0) { 626 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); 627 } 628 quot = num / den; 629 rem = num % den; 630 631 env->cc_z = quot; 632 env->cc_n = quot; 633 env->cc_v = 0; 634 635 if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { 636 if (numr == regr) { 637 env->dregs[numr] = quot; 638 } else { 639 env->dregs[regr] = rem; 640 } 641 } else { 642 env->dregs[regr] = rem; 643 env->dregs[numr] = quot; 644 } 645 } 646 647 void HELPER(divsl)(CPUM68KState *env, int numr, int regr, 648 int32_t den, int ilen) 649 { 650 int32_t num = env->dregs[numr]; 651 int32_t quot, rem; 652 653 env->cc_c = 0; /* always cleared, even if overflow/div0 */ 654 655 if (den == 0) { 656 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); 657 } 658 quot = num / den; 659 rem = num % den; 660 661 env->cc_z = quot; 662 env->cc_n = quot; 663 env->cc_v = 0; 664 665 if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { 666 if (numr == regr) { 667 env->dregs[numr] = quot; 668 } else { 669 env->dregs[regr] = rem; 670 } 671 } else { 672 env->dregs[regr] = rem; 673 env->dregs[numr] = quot; 674 } 675 } 676 677 void HELPER(divull)(CPUM68KState *env, int numr, int regr, 678 uint32_t den, int ilen) 679 { 680 uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); 681 uint64_t quot; 682 uint32_t rem; 683 684 env->cc_c = 0; /* always cleared, even if overflow/div0 */ 685 686 if (den == 0) { 687 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); 688 } 689 quot = num / den; 690 rem = num % den; 691 692 if (quot > 0xffffffffULL) { 693 env->cc_v = -1; 694 /* 695 * real 68040 keeps N and unset Z on overflow, 696 * whereas documentation says "undefined" 697 */ 698 env->cc_z = 1; 699 return; 700 } 701 env->cc_z = quot; 702 env->cc_n = quot; 703 env->cc_v = 0; 704 705 /* 706 * If Dq and Dr are the same, the quotient is returned. 707 * therefore we set Dq last. 708 */ 709 710 env->dregs[regr] = rem; 711 env->dregs[numr] = quot; 712 } 713 714 void HELPER(divsll)(CPUM68KState *env, int numr, int regr, 715 int32_t den, int ilen) 716 { 717 int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); 718 int64_t quot; 719 int32_t rem; 720 721 env->cc_c = 0; /* always cleared, even if overflow/div0 */ 722 723 if (den == 0) { 724 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC()); 725 } 726 quot = num / den; 727 rem = num % den; 728 729 if (quot != (int32_t)quot) { 730 env->cc_v = -1; 731 /* 732 * real 68040 keeps N and unset Z on overflow, 733 * whereas documentation says "undefined" 734 */ 735 env->cc_z = 1; 736 return; 737 } 738 env->cc_z = quot; 739 env->cc_n = quot; 740 env->cc_v = 0; 741 742 /* 743 * If Dq and Dr are the same, the quotient is returned. 744 * therefore we set Dq last. 745 */ 746 747 env->dregs[regr] = rem; 748 env->dregs[numr] = quot; 749 } 750 751 /* We're executing in a serial context -- no need to be atomic. */ 752 void HELPER(cas2w)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2) 753 { 754 uint32_t Dc1 = extract32(regs, 9, 3); 755 uint32_t Dc2 = extract32(regs, 6, 3); 756 uint32_t Du1 = extract32(regs, 3, 3); 757 uint32_t Du2 = extract32(regs, 0, 3); 758 int16_t c1 = env->dregs[Dc1]; 759 int16_t c2 = env->dregs[Dc2]; 760 int16_t u1 = env->dregs[Du1]; 761 int16_t u2 = env->dregs[Du2]; 762 int16_t l1, l2; 763 uintptr_t ra = GETPC(); 764 765 l1 = cpu_lduw_data_ra(env, a1, ra); 766 l2 = cpu_lduw_data_ra(env, a2, ra); 767 if (l1 == c1 && l2 == c2) { 768 cpu_stw_data_ra(env, a1, u1, ra); 769 cpu_stw_data_ra(env, a2, u2, ra); 770 } 771 772 if (c1 != l1) { 773 env->cc_n = l1; 774 env->cc_v = c1; 775 } else { 776 env->cc_n = l2; 777 env->cc_v = c2; 778 } 779 env->cc_op = CC_OP_CMPW; 780 env->dregs[Dc1] = deposit32(env->dregs[Dc1], 0, 16, l1); 781 env->dregs[Dc2] = deposit32(env->dregs[Dc2], 0, 16, l2); 782 } 783 784 static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2, 785 bool parallel) 786 { 787 uint32_t Dc1 = extract32(regs, 9, 3); 788 uint32_t Dc2 = extract32(regs, 6, 3); 789 uint32_t Du1 = extract32(regs, 3, 3); 790 uint32_t Du2 = extract32(regs, 0, 3); 791 uint32_t c1 = env->dregs[Dc1]; 792 uint32_t c2 = env->dregs[Dc2]; 793 uint32_t u1 = env->dregs[Du1]; 794 uint32_t u2 = env->dregs[Du2]; 795 uint32_t l1, l2; 796 uintptr_t ra = GETPC(); 797 #if defined(CONFIG_ATOMIC64) 798 int mmu_idx = cpu_mmu_index(env_cpu(env), 0); 799 MemOpIdx oi = make_memop_idx(MO_BEUQ, mmu_idx); 800 #endif 801 802 if (parallel) { 803 /* We're executing in a parallel context -- must be atomic. */ 804 #ifdef CONFIG_ATOMIC64 805 uint64_t c, u, l; 806 if ((a1 & 7) == 0 && a2 == a1 + 4) { 807 c = deposit64(c2, 32, 32, c1); 808 u = deposit64(u2, 32, 32, u1); 809 l = cpu_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra); 810 l1 = l >> 32; 811 l2 = l; 812 } else if ((a2 & 7) == 0 && a1 == a2 + 4) { 813 c = deposit64(c1, 32, 32, c2); 814 u = deposit64(u1, 32, 32, u2); 815 l = cpu_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra); 816 l2 = l >> 32; 817 l1 = l; 818 } else 819 #endif 820 { 821 /* Tell the main loop we need to serialize this insn. */ 822 cpu_loop_exit_atomic(env_cpu(env), ra); 823 } 824 } else { 825 /* We're executing in a serial context -- no need to be atomic. */ 826 l1 = cpu_ldl_data_ra(env, a1, ra); 827 l2 = cpu_ldl_data_ra(env, a2, ra); 828 if (l1 == c1 && l2 == c2) { 829 cpu_stl_data_ra(env, a1, u1, ra); 830 cpu_stl_data_ra(env, a2, u2, ra); 831 } 832 } 833 834 if (c1 != l1) { 835 env->cc_n = l1; 836 env->cc_v = c1; 837 } else { 838 env->cc_n = l2; 839 env->cc_v = c2; 840 } 841 env->cc_op = CC_OP_CMPL; 842 env->dregs[Dc1] = l1; 843 env->dregs[Dc2] = l2; 844 } 845 846 void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2) 847 { 848 do_cas2l(env, regs, a1, a2, false); 849 } 850 851 void HELPER(cas2l_parallel)(CPUM68KState *env, uint32_t regs, uint32_t a1, 852 uint32_t a2) 853 { 854 do_cas2l(env, regs, a1, a2, true); 855 } 856 857 struct bf_data { 858 uint32_t addr; 859 uint32_t bofs; 860 uint32_t blen; 861 uint32_t len; 862 }; 863 864 static struct bf_data bf_prep(uint32_t addr, int32_t ofs, uint32_t len) 865 { 866 int bofs, blen; 867 868 /* Bound length; map 0 to 32. */ 869 len = ((len - 1) & 31) + 1; 870 871 /* Note that ofs is signed. */ 872 addr += ofs / 8; 873 bofs = ofs % 8; 874 if (bofs < 0) { 875 bofs += 8; 876 addr -= 1; 877 } 878 879 /* 880 * Compute the number of bytes required (minus one) to 881 * satisfy the bitfield. 882 */ 883 blen = (bofs + len - 1) / 8; 884 885 /* 886 * Canonicalize the bit offset for data loaded into a 64-bit big-endian 887 * word. For the cases where BLEN is not a power of 2, adjust ADDR so 888 * that we can use the next power of two sized load without crossing a 889 * page boundary, unless the field itself crosses the boundary. 890 */ 891 switch (blen) { 892 case 0: 893 bofs += 56; 894 break; 895 case 1: 896 bofs += 48; 897 break; 898 case 2: 899 if (addr & 1) { 900 bofs += 8; 901 addr -= 1; 902 } 903 /* fallthru */ 904 case 3: 905 bofs += 32; 906 break; 907 case 4: 908 if (addr & 3) { 909 bofs += 8 * (addr & 3); 910 addr &= -4; 911 } 912 break; 913 default: 914 g_assert_not_reached(); 915 } 916 917 return (struct bf_data){ 918 .addr = addr, 919 .bofs = bofs, 920 .blen = blen, 921 .len = len, 922 }; 923 } 924 925 static uint64_t bf_load(CPUM68KState *env, uint32_t addr, int blen, 926 uintptr_t ra) 927 { 928 switch (blen) { 929 case 0: 930 return cpu_ldub_data_ra(env, addr, ra); 931 case 1: 932 return cpu_lduw_data_ra(env, addr, ra); 933 case 2: 934 case 3: 935 return cpu_ldl_data_ra(env, addr, ra); 936 case 4: 937 return cpu_ldq_data_ra(env, addr, ra); 938 default: 939 g_assert_not_reached(); 940 } 941 } 942 943 static void bf_store(CPUM68KState *env, uint32_t addr, int blen, 944 uint64_t data, uintptr_t ra) 945 { 946 switch (blen) { 947 case 0: 948 cpu_stb_data_ra(env, addr, data, ra); 949 break; 950 case 1: 951 cpu_stw_data_ra(env, addr, data, ra); 952 break; 953 case 2: 954 case 3: 955 cpu_stl_data_ra(env, addr, data, ra); 956 break; 957 case 4: 958 cpu_stq_data_ra(env, addr, data, ra); 959 break; 960 default: 961 g_assert_not_reached(); 962 } 963 } 964 965 uint32_t HELPER(bfexts_mem)(CPUM68KState *env, uint32_t addr, 966 int32_t ofs, uint32_t len) 967 { 968 uintptr_t ra = GETPC(); 969 struct bf_data d = bf_prep(addr, ofs, len); 970 uint64_t data = bf_load(env, d.addr, d.blen, ra); 971 972 return (int64_t)(data << d.bofs) >> (64 - d.len); 973 } 974 975 uint64_t HELPER(bfextu_mem)(CPUM68KState *env, uint32_t addr, 976 int32_t ofs, uint32_t len) 977 { 978 uintptr_t ra = GETPC(); 979 struct bf_data d = bf_prep(addr, ofs, len); 980 uint64_t data = bf_load(env, d.addr, d.blen, ra); 981 982 /* 983 * Put CC_N at the top of the high word; put the zero-extended value 984 * at the bottom of the low word. 985 */ 986 data <<= d.bofs; 987 data >>= 64 - d.len; 988 data |= data << (64 - d.len); 989 990 return data; 991 } 992 993 uint32_t HELPER(bfins_mem)(CPUM68KState *env, uint32_t addr, uint32_t val, 994 int32_t ofs, uint32_t len) 995 { 996 uintptr_t ra = GETPC(); 997 struct bf_data d = bf_prep(addr, ofs, len); 998 uint64_t data = bf_load(env, d.addr, d.blen, ra); 999 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 1000 1001 data = (data & ~mask) | (((uint64_t)val << (64 - d.len)) >> d.bofs); 1002 1003 bf_store(env, d.addr, d.blen, data, ra); 1004 1005 /* The field at the top of the word is also CC_N for CC_OP_LOGIC. */ 1006 return val << (32 - d.len); 1007 } 1008 1009 uint32_t HELPER(bfchg_mem)(CPUM68KState *env, uint32_t addr, 1010 int32_t ofs, uint32_t len) 1011 { 1012 uintptr_t ra = GETPC(); 1013 struct bf_data d = bf_prep(addr, ofs, len); 1014 uint64_t data = bf_load(env, d.addr, d.blen, ra); 1015 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 1016 1017 bf_store(env, d.addr, d.blen, data ^ mask, ra); 1018 1019 return ((data & mask) << d.bofs) >> 32; 1020 } 1021 1022 uint32_t HELPER(bfclr_mem)(CPUM68KState *env, uint32_t addr, 1023 int32_t ofs, uint32_t len) 1024 { 1025 uintptr_t ra = GETPC(); 1026 struct bf_data d = bf_prep(addr, ofs, len); 1027 uint64_t data = bf_load(env, d.addr, d.blen, ra); 1028 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 1029 1030 bf_store(env, d.addr, d.blen, data & ~mask, ra); 1031 1032 return ((data & mask) << d.bofs) >> 32; 1033 } 1034 1035 uint32_t HELPER(bfset_mem)(CPUM68KState *env, uint32_t addr, 1036 int32_t ofs, uint32_t len) 1037 { 1038 uintptr_t ra = GETPC(); 1039 struct bf_data d = bf_prep(addr, ofs, len); 1040 uint64_t data = bf_load(env, d.addr, d.blen, ra); 1041 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 1042 1043 bf_store(env, d.addr, d.blen, data | mask, ra); 1044 1045 return ((data & mask) << d.bofs) >> 32; 1046 } 1047 1048 uint32_t HELPER(bfffo_reg)(uint32_t n, uint32_t ofs, uint32_t len) 1049 { 1050 return (n ? clz32(n) : len) + ofs; 1051 } 1052 1053 uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr, 1054 int32_t ofs, uint32_t len) 1055 { 1056 uintptr_t ra = GETPC(); 1057 struct bf_data d = bf_prep(addr, ofs, len); 1058 uint64_t data = bf_load(env, d.addr, d.blen, ra); 1059 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 1060 uint64_t n = (data & mask) << d.bofs; 1061 uint32_t ffo = helper_bfffo_reg(n >> 32, ofs, d.len); 1062 1063 /* 1064 * Return FFO in the low word and N in the high word. 1065 * Note that because of MASK and the shift, the low word 1066 * is already zero. 1067 */ 1068 return n | ffo; 1069 } 1070 1071 void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub) 1072 { 1073 /* 1074 * From the specs: 1075 * X: Not affected, C,V,Z: Undefined, 1076 * N: Set if val < 0; cleared if val > ub, undefined otherwise 1077 * We implement here values found from a real MC68040: 1078 * X,V,Z: Not affected 1079 * N: Set if val < 0; cleared if val >= 0 1080 * C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise 1081 * if 0 > ub: set if val > ub and val < 0, cleared otherwise 1082 */ 1083 env->cc_n = val; 1084 env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0; 1085 1086 if (val < 0 || val > ub) { 1087 raise_exception_format2(env, EXCP_CHK, 2, GETPC()); 1088 } 1089 } 1090 1091 void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub) 1092 { 1093 /* 1094 * From the specs: 1095 * X: Not affected, N,V: Undefined, 1096 * Z: Set if val is equal to lb or ub 1097 * C: Set if val < lb or val > ub, cleared otherwise 1098 * We implement here values found from a real MC68040: 1099 * X,N,V: Not affected 1100 * Z: Set if val is equal to lb or ub 1101 * C: if lb <= ub: set if val < lb or val > ub, cleared otherwise 1102 * if lb > ub: set if val > ub and val < lb, cleared otherwise 1103 */ 1104 env->cc_z = val != lb && val != ub; 1105 env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb; 1106 1107 if (env->cc_c) { 1108 raise_exception_format2(env, EXCP_CHK, 4, GETPC()); 1109 } 1110 } 1111