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