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