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