xref: /qemu/target/m68k/op_helper.c (revision d8276573da58e8ce78dab8c46dd660efd664bcb7)
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 "exec/semihost.h"
25 
26 #if defined(CONFIG_USER_ONLY)
27 
28 void m68k_cpu_do_interrupt(CPUState *cs)
29 {
30     cs->exception_index = -1;
31 }
32 
33 static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
34 {
35 }
36 
37 #else
38 
39 static 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 
53 static void m68k_rte(CPUM68KState *env)
54 {
55     uint32_t sp;
56     uint16_t fmt;
57     uint16_t sr;
58 
59     sp = env->aregs[7];
60 throwaway:
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 
92 static 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 
197 static void cf_interrupt_all(CPUM68KState *env, int is_hw)
198 {
199     CPUState *cs = CPU(m68k_env_get_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 
271 static 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 = CPU(m68k_env_get_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 
300 static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
301 {
302     CPUState *cs = CPU(m68k_env_get_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 
420 static 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 
429 void 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 
437 static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
438 {
439     do_interrupt_all(env, 1);
440 }
441 
442 void m68k_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
443                                 bool is_exec, int is_asi, unsigned size)
444 {
445     M68kCPU *cpu = M68K_CPU(cs);
446     CPUM68KState *env = &cpu->env;
447 #ifdef DEBUG_UNASSIGNED
448     qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
449              addr, is_write, is_exec);
450 #endif
451     if (env == NULL) {
452         /* when called from gdb, env is NULL */
453         return;
454     }
455 
456     if (m68k_feature(env, M68K_FEATURE_M68040)) {
457         env->mmu.mmusr = 0;
458         env->mmu.ssw |= M68K_ATC_040;
459         /* FIXME: manage MMU table access error */
460         env->mmu.ssw &= ~M68K_TM_040;
461         if (env->sr & SR_S) { /* SUPERVISOR */
462             env->mmu.ssw |= M68K_TM_040_SUPER;
463         }
464         if (is_exec) { /* instruction or data */
465             env->mmu.ssw |= M68K_TM_040_CODE;
466         } else {
467             env->mmu.ssw |= M68K_TM_040_DATA;
468         }
469         env->mmu.ssw &= ~M68K_BA_SIZE_MASK;
470         switch (size) {
471         case 1:
472             env->mmu.ssw |= M68K_BA_SIZE_BYTE;
473             break;
474         case 2:
475             env->mmu.ssw |= M68K_BA_SIZE_WORD;
476             break;
477         case 4:
478             env->mmu.ssw |= M68K_BA_SIZE_LONG;
479             break;
480         }
481 
482         if (!is_write) {
483             env->mmu.ssw |= M68K_RW_040;
484         }
485 
486         env->mmu.ar = addr;
487 
488         cs->exception_index = EXCP_ACCESS;
489         cpu_loop_exit(cs);
490     }
491 }
492 #endif
493 
494 bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
495 {
496     M68kCPU *cpu = M68K_CPU(cs);
497     CPUM68KState *env = &cpu->env;
498 
499     if (interrupt_request & CPU_INTERRUPT_HARD
500         && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) {
501         /* Real hardware gets the interrupt vector via an IACK cycle
502            at this point.  Current emulated hardware doesn't rely on
503            this, so we provide/save the vector when the interrupt is
504            first signalled.  */
505         cs->exception_index = env->pending_vector;
506         do_interrupt_m68k_hardirq(env);
507         return true;
508     }
509     return false;
510 }
511 
512 static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
513 {
514     CPUState *cs = CPU(m68k_env_get_cpu(env));
515 
516     cs->exception_index = tt;
517     cpu_loop_exit_restore(cs, raddr);
518 }
519 
520 static void raise_exception(CPUM68KState *env, int tt)
521 {
522     raise_exception_ra(env, tt, 0);
523 }
524 
525 void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt)
526 {
527     raise_exception(env, tt);
528 }
529 
530 void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den)
531 {
532     uint32_t num = env->dregs[destr];
533     uint32_t quot, rem;
534 
535     if (den == 0) {
536         raise_exception_ra(env, EXCP_DIV0, GETPC());
537     }
538     quot = num / den;
539     rem = num % den;
540 
541     env->cc_c = 0; /* always cleared, even if overflow */
542     if (quot > 0xffff) {
543         env->cc_v = -1;
544         /* real 68040 keeps N and unset Z on overflow,
545          * whereas documentation says "undefined"
546          */
547         env->cc_z = 1;
548         return;
549     }
550     env->dregs[destr] = deposit32(quot, 16, 16, rem);
551     env->cc_z = (int16_t)quot;
552     env->cc_n = (int16_t)quot;
553     env->cc_v = 0;
554 }
555 
556 void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den)
557 {
558     int32_t num = env->dregs[destr];
559     uint32_t quot, rem;
560 
561     if (den == 0) {
562         raise_exception_ra(env, EXCP_DIV0, GETPC());
563     }
564     quot = num / den;
565     rem = num % den;
566 
567     env->cc_c = 0; /* always cleared, even if overflow */
568     if (quot != (int16_t)quot) {
569         env->cc_v = -1;
570         /* nothing else is modified */
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 
583 void 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 
611 void 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 
639 void 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         /* real 68040 keeps N and unset Z on overflow,
655          * whereas documentation says "undefined"
656          */
657         env->cc_z = 1;
658         return;
659     }
660     env->cc_z = quot;
661     env->cc_n = quot;
662     env->cc_v = 0;
663 
664     /*
665      * If Dq and Dr are the same, the quotient is returned.
666      * therefore we set Dq last.
667      */
668 
669     env->dregs[regr] = rem;
670     env->dregs[numr] = quot;
671 }
672 
673 void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den)
674 {
675     int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
676     int64_t quot;
677     int32_t rem;
678 
679     if (den == 0) {
680         raise_exception_ra(env, EXCP_DIV0, GETPC());
681     }
682     quot = num / den;
683     rem = num % den;
684 
685     env->cc_c = 0; /* always cleared, even if overflow */
686     if (quot != (int32_t)quot) {
687         env->cc_v = -1;
688         /* real 68040 keeps N and unset Z on overflow,
689          * whereas documentation says "undefined"
690          */
691         env->cc_z = 1;
692         return;
693     }
694     env->cc_z = quot;
695     env->cc_n = quot;
696     env->cc_v = 0;
697 
698     /*
699      * If Dq and Dr are the same, the quotient is returned.
700      * therefore we set Dq last.
701      */
702 
703     env->dregs[regr] = rem;
704     env->dregs[numr] = quot;
705 }
706 
707 /* We're executing in a serial context -- no need to be atomic.  */
708 void HELPER(cas2w)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
709 {
710     uint32_t Dc1 = extract32(regs, 9, 3);
711     uint32_t Dc2 = extract32(regs, 6, 3);
712     uint32_t Du1 = extract32(regs, 3, 3);
713     uint32_t Du2 = extract32(regs, 0, 3);
714     int16_t c1 = env->dregs[Dc1];
715     int16_t c2 = env->dregs[Dc2];
716     int16_t u1 = env->dregs[Du1];
717     int16_t u2 = env->dregs[Du2];
718     int16_t l1, l2;
719     uintptr_t ra = GETPC();
720 
721     l1 = cpu_lduw_data_ra(env, a1, ra);
722     l2 = cpu_lduw_data_ra(env, a2, ra);
723     if (l1 == c1 && l2 == c2) {
724         cpu_stw_data_ra(env, a1, u1, ra);
725         cpu_stw_data_ra(env, a2, u2, ra);
726     }
727 
728     if (c1 != l1) {
729         env->cc_n = l1;
730         env->cc_v = c1;
731     } else {
732         env->cc_n = l2;
733         env->cc_v = c2;
734     }
735     env->cc_op = CC_OP_CMPW;
736     env->dregs[Dc1] = deposit32(env->dregs[Dc1], 0, 16, l1);
737     env->dregs[Dc2] = deposit32(env->dregs[Dc2], 0, 16, l2);
738 }
739 
740 static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2,
741                      bool parallel)
742 {
743     uint32_t Dc1 = extract32(regs, 9, 3);
744     uint32_t Dc2 = extract32(regs, 6, 3);
745     uint32_t Du1 = extract32(regs, 3, 3);
746     uint32_t Du2 = extract32(regs, 0, 3);
747     uint32_t c1 = env->dregs[Dc1];
748     uint32_t c2 = env->dregs[Dc2];
749     uint32_t u1 = env->dregs[Du1];
750     uint32_t u2 = env->dregs[Du2];
751     uint32_t l1, l2;
752     uintptr_t ra = GETPC();
753 #if defined(CONFIG_ATOMIC64) && !defined(CONFIG_USER_ONLY)
754     int mmu_idx = cpu_mmu_index(env, 0);
755     TCGMemOpIdx oi;
756 #endif
757 
758     if (parallel) {
759         /* We're executing in a parallel context -- must be atomic.  */
760 #ifdef CONFIG_ATOMIC64
761         uint64_t c, u, l;
762         if ((a1 & 7) == 0 && a2 == a1 + 4) {
763             c = deposit64(c2, 32, 32, c1);
764             u = deposit64(u2, 32, 32, u1);
765 #ifdef CONFIG_USER_ONLY
766             l = helper_atomic_cmpxchgq_be(env, a1, c, u);
767 #else
768             oi = make_memop_idx(MO_BEQ, mmu_idx);
769             l = helper_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra);
770 #endif
771             l1 = l >> 32;
772             l2 = l;
773         } else if ((a2 & 7) == 0 && a1 == a2 + 4) {
774             c = deposit64(c1, 32, 32, c2);
775             u = deposit64(u1, 32, 32, u2);
776 #ifdef CONFIG_USER_ONLY
777             l = helper_atomic_cmpxchgq_be(env, a2, c, u);
778 #else
779             oi = make_memop_idx(MO_BEQ, mmu_idx);
780             l = helper_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra);
781 #endif
782             l2 = l >> 32;
783             l1 = l;
784         } else
785 #endif
786         {
787             /* Tell the main loop we need to serialize this insn.  */
788             cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
789         }
790     } else {
791         /* We're executing in a serial context -- no need to be atomic.  */
792         l1 = cpu_ldl_data_ra(env, a1, ra);
793         l2 = cpu_ldl_data_ra(env, a2, ra);
794         if (l1 == c1 && l2 == c2) {
795             cpu_stl_data_ra(env, a1, u1, ra);
796             cpu_stl_data_ra(env, a2, u2, ra);
797         }
798     }
799 
800     if (c1 != l1) {
801         env->cc_n = l1;
802         env->cc_v = c1;
803     } else {
804         env->cc_n = l2;
805         env->cc_v = c2;
806     }
807     env->cc_op = CC_OP_CMPL;
808     env->dregs[Dc1] = l1;
809     env->dregs[Dc2] = l2;
810 }
811 
812 void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
813 {
814     do_cas2l(env, regs, a1, a2, false);
815 }
816 
817 void HELPER(cas2l_parallel)(CPUM68KState *env, uint32_t regs, uint32_t a1,
818                             uint32_t a2)
819 {
820     do_cas2l(env, regs, a1, a2, true);
821 }
822 
823 struct bf_data {
824     uint32_t addr;
825     uint32_t bofs;
826     uint32_t blen;
827     uint32_t len;
828 };
829 
830 static struct bf_data bf_prep(uint32_t addr, int32_t ofs, uint32_t len)
831 {
832     int bofs, blen;
833 
834     /* Bound length; map 0 to 32.  */
835     len = ((len - 1) & 31) + 1;
836 
837     /* Note that ofs is signed.  */
838     addr += ofs / 8;
839     bofs = ofs % 8;
840     if (bofs < 0) {
841         bofs += 8;
842         addr -= 1;
843     }
844 
845     /* Compute the number of bytes required (minus one) to
846        satisfy the bitfield.  */
847     blen = (bofs + len - 1) / 8;
848 
849     /* Canonicalize the bit offset for data loaded into a 64-bit big-endian
850        word.  For the cases where BLEN is not a power of 2, adjust ADDR so
851        that we can use the next power of two sized load without crossing a
852        page boundary, unless the field itself crosses the boundary.  */
853     switch (blen) {
854     case 0:
855         bofs += 56;
856         break;
857     case 1:
858         bofs += 48;
859         break;
860     case 2:
861         if (addr & 1) {
862             bofs += 8;
863             addr -= 1;
864         }
865         /* fallthru */
866     case 3:
867         bofs += 32;
868         break;
869     case 4:
870         if (addr & 3) {
871             bofs += 8 * (addr & 3);
872             addr &= -4;
873         }
874         break;
875     default:
876         g_assert_not_reached();
877     }
878 
879     return (struct bf_data){
880         .addr = addr,
881         .bofs = bofs,
882         .blen = blen,
883         .len = len,
884     };
885 }
886 
887 static uint64_t bf_load(CPUM68KState *env, uint32_t addr, int blen,
888                         uintptr_t ra)
889 {
890     switch (blen) {
891     case 0:
892         return cpu_ldub_data_ra(env, addr, ra);
893     case 1:
894         return cpu_lduw_data_ra(env, addr, ra);
895     case 2:
896     case 3:
897         return cpu_ldl_data_ra(env, addr, ra);
898     case 4:
899         return cpu_ldq_data_ra(env, addr, ra);
900     default:
901         g_assert_not_reached();
902     }
903 }
904 
905 static void bf_store(CPUM68KState *env, uint32_t addr, int blen,
906                      uint64_t data, uintptr_t ra)
907 {
908     switch (blen) {
909     case 0:
910         cpu_stb_data_ra(env, addr, data, ra);
911         break;
912     case 1:
913         cpu_stw_data_ra(env, addr, data, ra);
914         break;
915     case 2:
916     case 3:
917         cpu_stl_data_ra(env, addr, data, ra);
918         break;
919     case 4:
920         cpu_stq_data_ra(env, addr, data, ra);
921         break;
922     default:
923         g_assert_not_reached();
924     }
925 }
926 
927 uint32_t HELPER(bfexts_mem)(CPUM68KState *env, uint32_t addr,
928                             int32_t ofs, uint32_t len)
929 {
930     uintptr_t ra = GETPC();
931     struct bf_data d = bf_prep(addr, ofs, len);
932     uint64_t data = bf_load(env, d.addr, d.blen, ra);
933 
934     return (int64_t)(data << d.bofs) >> (64 - d.len);
935 }
936 
937 uint64_t HELPER(bfextu_mem)(CPUM68KState *env, uint32_t addr,
938                             int32_t ofs, uint32_t len)
939 {
940     uintptr_t ra = GETPC();
941     struct bf_data d = bf_prep(addr, ofs, len);
942     uint64_t data = bf_load(env, d.addr, d.blen, ra);
943 
944     /* Put CC_N at the top of the high word; put the zero-extended value
945        at the bottom of the low word.  */
946     data <<= d.bofs;
947     data >>= 64 - d.len;
948     data |= data << (64 - d.len);
949 
950     return data;
951 }
952 
953 uint32_t HELPER(bfins_mem)(CPUM68KState *env, uint32_t addr, uint32_t val,
954                            int32_t ofs, uint32_t len)
955 {
956     uintptr_t ra = GETPC();
957     struct bf_data d = bf_prep(addr, ofs, len);
958     uint64_t data = bf_load(env, d.addr, d.blen, ra);
959     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
960 
961     data = (data & ~mask) | (((uint64_t)val << (64 - d.len)) >> d.bofs);
962 
963     bf_store(env, d.addr, d.blen, data, ra);
964 
965     /* The field at the top of the word is also CC_N for CC_OP_LOGIC.  */
966     return val << (32 - d.len);
967 }
968 
969 uint32_t HELPER(bfchg_mem)(CPUM68KState *env, uint32_t addr,
970                            int32_t ofs, uint32_t len)
971 {
972     uintptr_t ra = GETPC();
973     struct bf_data d = bf_prep(addr, ofs, len);
974     uint64_t data = bf_load(env, d.addr, d.blen, ra);
975     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
976 
977     bf_store(env, d.addr, d.blen, data ^ mask, ra);
978 
979     return ((data & mask) << d.bofs) >> 32;
980 }
981 
982 uint32_t HELPER(bfclr_mem)(CPUM68KState *env, uint32_t addr,
983                            int32_t ofs, uint32_t len)
984 {
985     uintptr_t ra = GETPC();
986     struct bf_data d = bf_prep(addr, ofs, len);
987     uint64_t data = bf_load(env, d.addr, d.blen, ra);
988     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
989 
990     bf_store(env, d.addr, d.blen, data & ~mask, ra);
991 
992     return ((data & mask) << d.bofs) >> 32;
993 }
994 
995 uint32_t HELPER(bfset_mem)(CPUM68KState *env, uint32_t addr,
996                            int32_t ofs, uint32_t len)
997 {
998     uintptr_t ra = GETPC();
999     struct bf_data d = bf_prep(addr, ofs, len);
1000     uint64_t data = bf_load(env, d.addr, d.blen, ra);
1001     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1002 
1003     bf_store(env, d.addr, d.blen, data | mask, ra);
1004 
1005     return ((data & mask) << d.bofs) >> 32;
1006 }
1007 
1008 uint32_t HELPER(bfffo_reg)(uint32_t n, uint32_t ofs, uint32_t len)
1009 {
1010     return (n ? clz32(n) : len) + ofs;
1011 }
1012 
1013 uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr,
1014                            int32_t ofs, uint32_t len)
1015 {
1016     uintptr_t ra = GETPC();
1017     struct bf_data d = bf_prep(addr, ofs, len);
1018     uint64_t data = bf_load(env, d.addr, d.blen, ra);
1019     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1020     uint64_t n = (data & mask) << d.bofs;
1021     uint32_t ffo = helper_bfffo_reg(n >> 32, ofs, d.len);
1022 
1023     /* Return FFO in the low word and N in the high word.
1024        Note that because of MASK and the shift, the low word
1025        is already zero.  */
1026     return n | ffo;
1027 }
1028 
1029 void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub)
1030 {
1031     /* From the specs:
1032      *   X: Not affected, C,V,Z: Undefined,
1033      *   N: Set if val < 0; cleared if val > ub, undefined otherwise
1034      * We implement here values found from a real MC68040:
1035      *   X,V,Z: Not affected
1036      *   N: Set if val < 0; cleared if val >= 0
1037      *   C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise
1038      *      if 0 > ub: set if val > ub and val < 0, cleared otherwise
1039      */
1040     env->cc_n = val;
1041     env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0;
1042 
1043     if (val < 0 || val > ub) {
1044         CPUState *cs = CPU(m68k_env_get_cpu(env));
1045 
1046         /* Recover PC and CC_OP for the beginning of the insn.  */
1047         cpu_restore_state(cs, GETPC(), true);
1048 
1049         /* flags have been modified by gen_flush_flags() */
1050         env->cc_op = CC_OP_FLAGS;
1051         /* Adjust PC to end of the insn.  */
1052         env->pc += 2;
1053 
1054         cs->exception_index = EXCP_CHK;
1055         cpu_loop_exit(cs);
1056     }
1057 }
1058 
1059 void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub)
1060 {
1061     /* From the specs:
1062      *   X: Not affected, N,V: Undefined,
1063      *   Z: Set if val is equal to lb or ub
1064      *   C: Set if val < lb or val > ub, cleared otherwise
1065      * We implement here values found from a real MC68040:
1066      *   X,N,V: Not affected
1067      *   Z: Set if val is equal to lb or ub
1068      *   C: if lb <= ub: set if val < lb or val > ub, cleared otherwise
1069      *      if lb > ub: set if val > ub and val < lb, cleared otherwise
1070      */
1071     env->cc_z = val != lb && val != ub;
1072     env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb;
1073 
1074     if (env->cc_c) {
1075         CPUState *cs = CPU(m68k_env_get_cpu(env));
1076 
1077         /* Recover PC and CC_OP for the beginning of the insn.  */
1078         cpu_restore_state(cs, GETPC(), true);
1079 
1080         /* flags have been modified by gen_flush_flags() */
1081         env->cc_op = CC_OP_FLAGS;
1082         /* Adjust PC to end of the insn.  */
1083         env->pc += 4;
1084 
1085         cs->exception_index = EXCP_CHK;
1086         cpu_loop_exit(cs);
1087     }
1088 }
1089