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