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