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