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]; 419 if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) { 420 sp &= ~1; 421 } 422 do_stack_frame(env, &sp, 1, oldsr, 0, retaddr); 423 } else { 424 do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); 425 } 426 427 env->aregs[7] = sp; 428 /* Jump to vector. */ 429 env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0); 430 } 431 432 static void do_interrupt_all(CPUM68KState *env, int is_hw) 433 { 434 if (m68k_feature(env, M68K_FEATURE_M68000)) { 435 m68k_interrupt_all(env, is_hw); 436 return; 437 } 438 cf_interrupt_all(env, is_hw); 439 } 440 441 void m68k_cpu_do_interrupt(CPUState *cs) 442 { 443 M68kCPU *cpu = M68K_CPU(cs); 444 CPUM68KState *env = &cpu->env; 445 446 do_interrupt_all(env, 0); 447 } 448 449 static inline void do_interrupt_m68k_hardirq(CPUM68KState *env) 450 { 451 do_interrupt_all(env, 1); 452 } 453 454 void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, 455 unsigned size, MMUAccessType access_type, 456 int mmu_idx, MemTxAttrs attrs, 457 MemTxResult response, uintptr_t retaddr) 458 { 459 M68kCPU *cpu = M68K_CPU(cs); 460 CPUM68KState *env = &cpu->env; 461 462 cpu_restore_state(cs, retaddr, true); 463 464 if (m68k_feature(env, M68K_FEATURE_M68040)) { 465 env->mmu.mmusr = 0; 466 467 /* 468 * According to the MC68040 users manual the ATC bit of the SSW is 469 * used to distinguish between ATC faults and physical bus errors. 470 * In the case of a bus error e.g. during nubus read from an empty 471 * slot this bit should not be set 472 */ 473 if (response != MEMTX_DECODE_ERROR) { 474 env->mmu.ssw |= M68K_ATC_040; 475 } 476 477 /* FIXME: manage MMU table access error */ 478 env->mmu.ssw &= ~M68K_TM_040; 479 if (env->sr & SR_S) { /* SUPERVISOR */ 480 env->mmu.ssw |= M68K_TM_040_SUPER; 481 } 482 if (access_type == MMU_INST_FETCH) { /* instruction or data */ 483 env->mmu.ssw |= M68K_TM_040_CODE; 484 } else { 485 env->mmu.ssw |= M68K_TM_040_DATA; 486 } 487 env->mmu.ssw &= ~M68K_BA_SIZE_MASK; 488 switch (size) { 489 case 1: 490 env->mmu.ssw |= M68K_BA_SIZE_BYTE; 491 break; 492 case 2: 493 env->mmu.ssw |= M68K_BA_SIZE_WORD; 494 break; 495 case 4: 496 env->mmu.ssw |= M68K_BA_SIZE_LONG; 497 break; 498 } 499 500 if (access_type != MMU_DATA_STORE) { 501 env->mmu.ssw |= M68K_RW_040; 502 } 503 504 env->mmu.ar = addr; 505 506 cs->exception_index = EXCP_ACCESS; 507 cpu_loop_exit(cs); 508 } 509 } 510 511 bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 512 { 513 M68kCPU *cpu = M68K_CPU(cs); 514 CPUM68KState *env = &cpu->env; 515 516 if (interrupt_request & CPU_INTERRUPT_HARD 517 && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) { 518 /* 519 * Real hardware gets the interrupt vector via an IACK cycle 520 * at this point. Current emulated hardware doesn't rely on 521 * this, so we provide/save the vector when the interrupt is 522 * first signalled. 523 */ 524 cs->exception_index = env->pending_vector; 525 do_interrupt_m68k_hardirq(env); 526 return true; 527 } 528 return false; 529 } 530 531 #endif /* !CONFIG_USER_ONLY */ 532 533 static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) 534 { 535 CPUState *cs = env_cpu(env); 536 537 cs->exception_index = tt; 538 cpu_loop_exit_restore(cs, raddr); 539 } 540 541 static void raise_exception(CPUM68KState *env, int tt) 542 { 543 raise_exception_ra(env, tt, 0); 544 } 545 546 void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) 547 { 548 raise_exception(env, tt); 549 } 550 551 void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) 552 { 553 uint32_t num = env->dregs[destr]; 554 uint32_t quot, rem; 555 556 if (den == 0) { 557 raise_exception_ra(env, EXCP_DIV0, GETPC()); 558 } 559 quot = num / den; 560 rem = num % den; 561 562 env->cc_c = 0; /* always cleared, even if overflow */ 563 if (quot > 0xffff) { 564 env->cc_v = -1; 565 /* 566 * real 68040 keeps N and unset Z on overflow, 567 * whereas documentation says "undefined" 568 */ 569 env->cc_z = 1; 570 return; 571 } 572 env->dregs[destr] = deposit32(quot, 16, 16, rem); 573 env->cc_z = (int16_t)quot; 574 env->cc_n = (int16_t)quot; 575 env->cc_v = 0; 576 } 577 578 void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den) 579 { 580 int32_t num = env->dregs[destr]; 581 uint32_t quot, rem; 582 583 if (den == 0) { 584 raise_exception_ra(env, EXCP_DIV0, GETPC()); 585 } 586 quot = num / den; 587 rem = num % den; 588 589 env->cc_c = 0; /* always cleared, even if overflow */ 590 if (quot != (int16_t)quot) { 591 env->cc_v = -1; 592 /* nothing else is modified */ 593 /* 594 * real 68040 keeps N and unset Z on overflow, 595 * whereas documentation says "undefined" 596 */ 597 env->cc_z = 1; 598 return; 599 } 600 env->dregs[destr] = deposit32(quot, 16, 16, rem); 601 env->cc_z = (int16_t)quot; 602 env->cc_n = (int16_t)quot; 603 env->cc_v = 0; 604 } 605 606 void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den) 607 { 608 uint32_t num = env->dregs[numr]; 609 uint32_t quot, rem; 610 611 if (den == 0) { 612 raise_exception_ra(env, EXCP_DIV0, GETPC()); 613 } 614 quot = num / den; 615 rem = num % den; 616 617 env->cc_c = 0; 618 env->cc_z = quot; 619 env->cc_n = quot; 620 env->cc_v = 0; 621 622 if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { 623 if (numr == regr) { 624 env->dregs[numr] = quot; 625 } else { 626 env->dregs[regr] = rem; 627 } 628 } else { 629 env->dregs[regr] = rem; 630 env->dregs[numr] = quot; 631 } 632 } 633 634 void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den) 635 { 636 int32_t num = env->dregs[numr]; 637 int32_t quot, rem; 638 639 if (den == 0) { 640 raise_exception_ra(env, EXCP_DIV0, GETPC()); 641 } 642 quot = num / den; 643 rem = num % den; 644 645 env->cc_c = 0; 646 env->cc_z = quot; 647 env->cc_n = quot; 648 env->cc_v = 0; 649 650 if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { 651 if (numr == regr) { 652 env->dregs[numr] = quot; 653 } else { 654 env->dregs[regr] = rem; 655 } 656 } else { 657 env->dregs[regr] = rem; 658 env->dregs[numr] = quot; 659 } 660 } 661 662 void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den) 663 { 664 uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); 665 uint64_t quot; 666 uint32_t rem; 667 668 if (den == 0) { 669 raise_exception_ra(env, EXCP_DIV0, GETPC()); 670 } 671 quot = num / den; 672 rem = num % den; 673 674 env->cc_c = 0; /* always cleared, even if overflow */ 675 if (quot > 0xffffffffULL) { 676 env->cc_v = -1; 677 /* 678 * real 68040 keeps N and unset Z on overflow, 679 * whereas documentation says "undefined" 680 */ 681 env->cc_z = 1; 682 return; 683 } 684 env->cc_z = quot; 685 env->cc_n = quot; 686 env->cc_v = 0; 687 688 /* 689 * If Dq and Dr are the same, the quotient is returned. 690 * therefore we set Dq last. 691 */ 692 693 env->dregs[regr] = rem; 694 env->dregs[numr] = quot; 695 } 696 697 void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den) 698 { 699 int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); 700 int64_t quot; 701 int32_t rem; 702 703 if (den == 0) { 704 raise_exception_ra(env, EXCP_DIV0, GETPC()); 705 } 706 quot = num / den; 707 rem = num % den; 708 709 env->cc_c = 0; /* always cleared, even if overflow */ 710 if (quot != (int32_t)quot) { 711 env->cc_v = -1; 712 /* 713 * real 68040 keeps N and unset Z on overflow, 714 * whereas documentation says "undefined" 715 */ 716 env->cc_z = 1; 717 return; 718 } 719 env->cc_z = quot; 720 env->cc_n = quot; 721 env->cc_v = 0; 722 723 /* 724 * If Dq and Dr are the same, the quotient is returned. 725 * therefore we set Dq last. 726 */ 727 728 env->dregs[regr] = rem; 729 env->dregs[numr] = quot; 730 } 731 732 /* We're executing in a serial context -- no need to be atomic. */ 733 void HELPER(cas2w)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2) 734 { 735 uint32_t Dc1 = extract32(regs, 9, 3); 736 uint32_t Dc2 = extract32(regs, 6, 3); 737 uint32_t Du1 = extract32(regs, 3, 3); 738 uint32_t Du2 = extract32(regs, 0, 3); 739 int16_t c1 = env->dregs[Dc1]; 740 int16_t c2 = env->dregs[Dc2]; 741 int16_t u1 = env->dregs[Du1]; 742 int16_t u2 = env->dregs[Du2]; 743 int16_t l1, l2; 744 uintptr_t ra = GETPC(); 745 746 l1 = cpu_lduw_data_ra(env, a1, ra); 747 l2 = cpu_lduw_data_ra(env, a2, ra); 748 if (l1 == c1 && l2 == c2) { 749 cpu_stw_data_ra(env, a1, u1, ra); 750 cpu_stw_data_ra(env, a2, u2, ra); 751 } 752 753 if (c1 != l1) { 754 env->cc_n = l1; 755 env->cc_v = c1; 756 } else { 757 env->cc_n = l2; 758 env->cc_v = c2; 759 } 760 env->cc_op = CC_OP_CMPW; 761 env->dregs[Dc1] = deposit32(env->dregs[Dc1], 0, 16, l1); 762 env->dregs[Dc2] = deposit32(env->dregs[Dc2], 0, 16, l2); 763 } 764 765 static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2, 766 bool parallel) 767 { 768 uint32_t Dc1 = extract32(regs, 9, 3); 769 uint32_t Dc2 = extract32(regs, 6, 3); 770 uint32_t Du1 = extract32(regs, 3, 3); 771 uint32_t Du2 = extract32(regs, 0, 3); 772 uint32_t c1 = env->dregs[Dc1]; 773 uint32_t c2 = env->dregs[Dc2]; 774 uint32_t u1 = env->dregs[Du1]; 775 uint32_t u2 = env->dregs[Du2]; 776 uint32_t l1, l2; 777 uintptr_t ra = GETPC(); 778 #if defined(CONFIG_ATOMIC64) 779 int mmu_idx = cpu_mmu_index(env, 0); 780 MemOpIdx oi = make_memop_idx(MO_BEUQ, mmu_idx); 781 #endif 782 783 if (parallel) { 784 /* We're executing in a parallel context -- must be atomic. */ 785 #ifdef CONFIG_ATOMIC64 786 uint64_t c, u, l; 787 if ((a1 & 7) == 0 && a2 == a1 + 4) { 788 c = deposit64(c2, 32, 32, c1); 789 u = deposit64(u2, 32, 32, u1); 790 l = cpu_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra); 791 l1 = l >> 32; 792 l2 = l; 793 } else if ((a2 & 7) == 0 && a1 == a2 + 4) { 794 c = deposit64(c1, 32, 32, c2); 795 u = deposit64(u1, 32, 32, u2); 796 l = cpu_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra); 797 l2 = l >> 32; 798 l1 = l; 799 } else 800 #endif 801 { 802 /* Tell the main loop we need to serialize this insn. */ 803 cpu_loop_exit_atomic(env_cpu(env), ra); 804 } 805 } else { 806 /* We're executing in a serial context -- no need to be atomic. */ 807 l1 = cpu_ldl_data_ra(env, a1, ra); 808 l2 = cpu_ldl_data_ra(env, a2, ra); 809 if (l1 == c1 && l2 == c2) { 810 cpu_stl_data_ra(env, a1, u1, ra); 811 cpu_stl_data_ra(env, a2, u2, ra); 812 } 813 } 814 815 if (c1 != l1) { 816 env->cc_n = l1; 817 env->cc_v = c1; 818 } else { 819 env->cc_n = l2; 820 env->cc_v = c2; 821 } 822 env->cc_op = CC_OP_CMPL; 823 env->dregs[Dc1] = l1; 824 env->dregs[Dc2] = l2; 825 } 826 827 void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2) 828 { 829 do_cas2l(env, regs, a1, a2, false); 830 } 831 832 void HELPER(cas2l_parallel)(CPUM68KState *env, uint32_t regs, uint32_t a1, 833 uint32_t a2) 834 { 835 do_cas2l(env, regs, a1, a2, true); 836 } 837 838 struct bf_data { 839 uint32_t addr; 840 uint32_t bofs; 841 uint32_t blen; 842 uint32_t len; 843 }; 844 845 static struct bf_data bf_prep(uint32_t addr, int32_t ofs, uint32_t len) 846 { 847 int bofs, blen; 848 849 /* Bound length; map 0 to 32. */ 850 len = ((len - 1) & 31) + 1; 851 852 /* Note that ofs is signed. */ 853 addr += ofs / 8; 854 bofs = ofs % 8; 855 if (bofs < 0) { 856 bofs += 8; 857 addr -= 1; 858 } 859 860 /* 861 * Compute the number of bytes required (minus one) to 862 * satisfy the bitfield. 863 */ 864 blen = (bofs + len - 1) / 8; 865 866 /* 867 * Canonicalize the bit offset for data loaded into a 64-bit big-endian 868 * word. For the cases where BLEN is not a power of 2, adjust ADDR so 869 * that we can use the next power of two sized load without crossing a 870 * page boundary, unless the field itself crosses the boundary. 871 */ 872 switch (blen) { 873 case 0: 874 bofs += 56; 875 break; 876 case 1: 877 bofs += 48; 878 break; 879 case 2: 880 if (addr & 1) { 881 bofs += 8; 882 addr -= 1; 883 } 884 /* fallthru */ 885 case 3: 886 bofs += 32; 887 break; 888 case 4: 889 if (addr & 3) { 890 bofs += 8 * (addr & 3); 891 addr &= -4; 892 } 893 break; 894 default: 895 g_assert_not_reached(); 896 } 897 898 return (struct bf_data){ 899 .addr = addr, 900 .bofs = bofs, 901 .blen = blen, 902 .len = len, 903 }; 904 } 905 906 static uint64_t bf_load(CPUM68KState *env, uint32_t addr, int blen, 907 uintptr_t ra) 908 { 909 switch (blen) { 910 case 0: 911 return cpu_ldub_data_ra(env, addr, ra); 912 case 1: 913 return cpu_lduw_data_ra(env, addr, ra); 914 case 2: 915 case 3: 916 return cpu_ldl_data_ra(env, addr, ra); 917 case 4: 918 return cpu_ldq_data_ra(env, addr, ra); 919 default: 920 g_assert_not_reached(); 921 } 922 } 923 924 static void bf_store(CPUM68KState *env, uint32_t addr, int blen, 925 uint64_t data, uintptr_t ra) 926 { 927 switch (blen) { 928 case 0: 929 cpu_stb_data_ra(env, addr, data, ra); 930 break; 931 case 1: 932 cpu_stw_data_ra(env, addr, data, ra); 933 break; 934 case 2: 935 case 3: 936 cpu_stl_data_ra(env, addr, data, ra); 937 break; 938 case 4: 939 cpu_stq_data_ra(env, addr, data, ra); 940 break; 941 default: 942 g_assert_not_reached(); 943 } 944 } 945 946 uint32_t HELPER(bfexts_mem)(CPUM68KState *env, uint32_t addr, 947 int32_t ofs, uint32_t len) 948 { 949 uintptr_t ra = GETPC(); 950 struct bf_data d = bf_prep(addr, ofs, len); 951 uint64_t data = bf_load(env, d.addr, d.blen, ra); 952 953 return (int64_t)(data << d.bofs) >> (64 - d.len); 954 } 955 956 uint64_t HELPER(bfextu_mem)(CPUM68KState *env, uint32_t addr, 957 int32_t ofs, uint32_t len) 958 { 959 uintptr_t ra = GETPC(); 960 struct bf_data d = bf_prep(addr, ofs, len); 961 uint64_t data = bf_load(env, d.addr, d.blen, ra); 962 963 /* 964 * Put CC_N at the top of the high word; put the zero-extended value 965 * at the bottom of the low word. 966 */ 967 data <<= d.bofs; 968 data >>= 64 - d.len; 969 data |= data << (64 - d.len); 970 971 return data; 972 } 973 974 uint32_t HELPER(bfins_mem)(CPUM68KState *env, uint32_t addr, uint32_t val, 975 int32_t ofs, uint32_t len) 976 { 977 uintptr_t ra = GETPC(); 978 struct bf_data d = bf_prep(addr, ofs, len); 979 uint64_t data = bf_load(env, d.addr, d.blen, ra); 980 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 981 982 data = (data & ~mask) | (((uint64_t)val << (64 - d.len)) >> d.bofs); 983 984 bf_store(env, d.addr, d.blen, data, ra); 985 986 /* The field at the top of the word is also CC_N for CC_OP_LOGIC. */ 987 return val << (32 - d.len); 988 } 989 990 uint32_t HELPER(bfchg_mem)(CPUM68KState *env, uint32_t addr, 991 int32_t ofs, uint32_t len) 992 { 993 uintptr_t ra = GETPC(); 994 struct bf_data d = bf_prep(addr, ofs, len); 995 uint64_t data = bf_load(env, d.addr, d.blen, ra); 996 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 997 998 bf_store(env, d.addr, d.blen, data ^ mask, ra); 999 1000 return ((data & mask) << d.bofs) >> 32; 1001 } 1002 1003 uint32_t HELPER(bfclr_mem)(CPUM68KState *env, uint32_t addr, 1004 int32_t ofs, uint32_t len) 1005 { 1006 uintptr_t ra = GETPC(); 1007 struct bf_data d = bf_prep(addr, ofs, len); 1008 uint64_t data = bf_load(env, d.addr, d.blen, ra); 1009 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 1010 1011 bf_store(env, d.addr, d.blen, data & ~mask, ra); 1012 1013 return ((data & mask) << d.bofs) >> 32; 1014 } 1015 1016 uint32_t HELPER(bfset_mem)(CPUM68KState *env, uint32_t addr, 1017 int32_t ofs, uint32_t len) 1018 { 1019 uintptr_t ra = GETPC(); 1020 struct bf_data d = bf_prep(addr, ofs, len); 1021 uint64_t data = bf_load(env, d.addr, d.blen, ra); 1022 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 1023 1024 bf_store(env, d.addr, d.blen, data | mask, ra); 1025 1026 return ((data & mask) << d.bofs) >> 32; 1027 } 1028 1029 uint32_t HELPER(bfffo_reg)(uint32_t n, uint32_t ofs, uint32_t len) 1030 { 1031 return (n ? clz32(n) : len) + ofs; 1032 } 1033 1034 uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr, 1035 int32_t ofs, uint32_t len) 1036 { 1037 uintptr_t ra = GETPC(); 1038 struct bf_data d = bf_prep(addr, ofs, len); 1039 uint64_t data = bf_load(env, d.addr, d.blen, ra); 1040 uint64_t mask = -1ull << (64 - d.len) >> d.bofs; 1041 uint64_t n = (data & mask) << d.bofs; 1042 uint32_t ffo = helper_bfffo_reg(n >> 32, ofs, d.len); 1043 1044 /* 1045 * Return FFO in the low word and N in the high word. 1046 * Note that because of MASK and the shift, the low word 1047 * is already zero. 1048 */ 1049 return n | ffo; 1050 } 1051 1052 void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub) 1053 { 1054 /* 1055 * From the specs: 1056 * X: Not affected, C,V,Z: Undefined, 1057 * N: Set if val < 0; cleared if val > ub, undefined otherwise 1058 * We implement here values found from a real MC68040: 1059 * X,V,Z: Not affected 1060 * N: Set if val < 0; cleared if val >= 0 1061 * C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise 1062 * if 0 > ub: set if val > ub and val < 0, cleared otherwise 1063 */ 1064 env->cc_n = val; 1065 env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0; 1066 1067 if (val < 0 || val > ub) { 1068 CPUState *cs = env_cpu(env); 1069 1070 /* Recover PC and CC_OP for the beginning of the insn. */ 1071 cpu_restore_state(cs, GETPC(), true); 1072 1073 /* flags have been modified by gen_flush_flags() */ 1074 env->cc_op = CC_OP_FLAGS; 1075 /* Adjust PC to end of the insn. */ 1076 env->pc += 2; 1077 1078 cs->exception_index = EXCP_CHK; 1079 cpu_loop_exit(cs); 1080 } 1081 } 1082 1083 void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub) 1084 { 1085 /* 1086 * From the specs: 1087 * X: Not affected, N,V: Undefined, 1088 * Z: Set if val is equal to lb or ub 1089 * C: Set if val < lb or val > ub, cleared otherwise 1090 * We implement here values found from a real MC68040: 1091 * X,N,V: Not affected 1092 * Z: Set if val is equal to lb or ub 1093 * C: if lb <= ub: set if val < lb or val > ub, cleared otherwise 1094 * if lb > ub: set if val > ub and val < lb, cleared otherwise 1095 */ 1096 env->cc_z = val != lb && val != ub; 1097 env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb; 1098 1099 if (env->cc_c) { 1100 CPUState *cs = env_cpu(env); 1101 1102 /* Recover PC and CC_OP for the beginning of the insn. */ 1103 cpu_restore_state(cs, GETPC(), true); 1104 1105 /* flags have been modified by gen_flush_flags() */ 1106 env->cc_op = CC_OP_FLAGS; 1107 /* Adjust PC to end of the insn. */ 1108 env->pc += 4; 1109 1110 cs->exception_index = EXCP_CHK; 1111 cpu_loop_exit(cs); 1112 } 1113 } 1114