qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

op_helper.c (31110B)


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