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