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