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