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