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