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