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