xref: /qemu/target/m68k/op_helper.c (revision a1aedd6cbdec67c1d47d961144285f4b95af5fc0)
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_TRAPCC:
403         /* FIXME: addr is not only env->pc */
404         do_stack_frame(env, &sp, 2, oldsr, env->pc, env->pc);
405         break;
406 
407     case EXCP_CHK:
408     case EXCP_DIV0:
409     case EXCP_TRACE:
410         do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc);
411         break;
412 
413     case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7:
414         if (is_hw && (oldsr & SR_M)) {
415             do_stack_frame(env, &sp, 0, oldsr, 0, env->pc);
416             oldsr = sr;
417             env->aregs[7] = sp;
418             cpu_m68k_set_sr(env, sr & ~SR_M);
419             sp = env->aregs[7];
420             if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) {
421                 sp &= ~1;
422             }
423             do_stack_frame(env, &sp, 1, oldsr, 0, env->pc);
424             break;
425         }
426         /* fall through */
427 
428     default:
429         do_stack_frame(env, &sp, 0, oldsr, 0, env->pc);
430         break;
431     }
432 
433     env->aregs[7] = sp;
434     /* Jump to vector.  */
435     env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0);
436 }
437 
438 static void do_interrupt_all(CPUM68KState *env, int is_hw)
439 {
440     if (m68k_feature(env, M68K_FEATURE_M68000)) {
441         m68k_interrupt_all(env, is_hw);
442         return;
443     }
444     cf_interrupt_all(env, is_hw);
445 }
446 
447 void m68k_cpu_do_interrupt(CPUState *cs)
448 {
449     M68kCPU *cpu = M68K_CPU(cs);
450     CPUM68KState *env = &cpu->env;
451 
452     do_interrupt_all(env, 0);
453 }
454 
455 static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
456 {
457     do_interrupt_all(env, 1);
458 }
459 
460 void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
461                                  unsigned size, MMUAccessType access_type,
462                                  int mmu_idx, MemTxAttrs attrs,
463                                  MemTxResult response, uintptr_t retaddr)
464 {
465     M68kCPU *cpu = M68K_CPU(cs);
466     CPUM68KState *env = &cpu->env;
467 
468     cpu_restore_state(cs, retaddr, true);
469 
470     if (m68k_feature(env, M68K_FEATURE_M68040)) {
471         env->mmu.mmusr = 0;
472 
473         /*
474          * According to the MC68040 users manual the ATC bit of the SSW is
475          * used to distinguish between ATC faults and physical bus errors.
476          * In the case of a bus error e.g. during nubus read from an empty
477          * slot this bit should not be set
478          */
479         if (response != MEMTX_DECODE_ERROR) {
480             env->mmu.ssw |= M68K_ATC_040;
481         }
482 
483         /* FIXME: manage MMU table access error */
484         env->mmu.ssw &= ~M68K_TM_040;
485         if (env->sr & SR_S) { /* SUPERVISOR */
486             env->mmu.ssw |= M68K_TM_040_SUPER;
487         }
488         if (access_type == MMU_INST_FETCH) { /* instruction or data */
489             env->mmu.ssw |= M68K_TM_040_CODE;
490         } else {
491             env->mmu.ssw |= M68K_TM_040_DATA;
492         }
493         env->mmu.ssw &= ~M68K_BA_SIZE_MASK;
494         switch (size) {
495         case 1:
496             env->mmu.ssw |= M68K_BA_SIZE_BYTE;
497             break;
498         case 2:
499             env->mmu.ssw |= M68K_BA_SIZE_WORD;
500             break;
501         case 4:
502             env->mmu.ssw |= M68K_BA_SIZE_LONG;
503             break;
504         }
505 
506         if (access_type != MMU_DATA_STORE) {
507             env->mmu.ssw |= M68K_RW_040;
508         }
509 
510         env->mmu.ar = addr;
511 
512         cs->exception_index = EXCP_ACCESS;
513         cpu_loop_exit(cs);
514     }
515 }
516 
517 bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
518 {
519     M68kCPU *cpu = M68K_CPU(cs);
520     CPUM68KState *env = &cpu->env;
521 
522     if (interrupt_request & CPU_INTERRUPT_HARD
523         && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) {
524         /*
525          * Real hardware gets the interrupt vector via an IACK cycle
526          * at this point.  Current emulated hardware doesn't rely on
527          * this, so we provide/save the vector when the interrupt is
528          * first signalled.
529          */
530         cs->exception_index = env->pending_vector;
531         do_interrupt_m68k_hardirq(env);
532         return true;
533     }
534     return false;
535 }
536 
537 #endif /* !CONFIG_USER_ONLY */
538 
539 static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
540 {
541     CPUState *cs = env_cpu(env);
542 
543     cs->exception_index = tt;
544     cpu_loop_exit_restore(cs, raddr);
545 }
546 
547 static void raise_exception(CPUM68KState *env, int tt)
548 {
549     raise_exception_ra(env, tt, 0);
550 }
551 
552 void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt)
553 {
554     raise_exception(env, tt);
555 }
556 
557 G_NORETURN static void
558 raise_exception_format2(CPUM68KState *env, int tt, int ilen, uintptr_t raddr)
559 {
560     CPUState *cs = env_cpu(env);
561 
562     cs->exception_index = tt;
563 
564     /* Recover PC and CC_OP for the beginning of the insn.  */
565     cpu_restore_state(cs, raddr, true);
566 
567     /* Flags are current in env->cc_*, or are undefined. */
568     env->cc_op = CC_OP_FLAGS;
569 
570     /*
571      * Remember original pc in mmu.ar, for the Format 2 stack frame.
572      * Adjust PC to end of the insn.
573      */
574     env->mmu.ar = env->pc;
575     env->pc += ilen;
576 
577     cpu_loop_exit(cs);
578 }
579 
580 void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den, int ilen)
581 {
582     uint32_t num = env->dregs[destr];
583     uint32_t quot, rem;
584 
585     env->cc_c = 0; /* always cleared, even if div0 */
586 
587     if (den == 0) {
588         raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
589     }
590     quot = num / den;
591     rem = num % den;
592 
593     if (quot > 0xffff) {
594         env->cc_v = -1;
595         /*
596          * real 68040 keeps N and unset Z on overflow,
597          * whereas documentation says "undefined"
598          */
599         env->cc_z = 1;
600         return;
601     }
602     env->dregs[destr] = deposit32(quot, 16, 16, rem);
603     env->cc_z = (int16_t)quot;
604     env->cc_n = (int16_t)quot;
605     env->cc_v = 0;
606 }
607 
608 void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den, int ilen)
609 {
610     int32_t num = env->dregs[destr];
611     uint32_t quot, rem;
612 
613     env->cc_c = 0; /* always cleared, even if overflow/div0 */
614 
615     if (den == 0) {
616         raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
617     }
618     quot = num / den;
619     rem = num % den;
620 
621     if (quot != (int16_t)quot) {
622         env->cc_v = -1;
623         /* nothing else is modified */
624         /*
625          * real 68040 keeps N and unset Z on overflow,
626          * whereas documentation says "undefined"
627          */
628         env->cc_z = 1;
629         return;
630     }
631     env->dregs[destr] = deposit32(quot, 16, 16, rem);
632     env->cc_z = (int16_t)quot;
633     env->cc_n = (int16_t)quot;
634     env->cc_v = 0;
635 }
636 
637 void HELPER(divul)(CPUM68KState *env, int numr, int regr,
638                    uint32_t den, int ilen)
639 {
640     uint32_t num = env->dregs[numr];
641     uint32_t quot, rem;
642 
643     env->cc_c = 0; /* always cleared, even if div0 */
644 
645     if (den == 0) {
646         raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
647     }
648     quot = num / den;
649     rem = num % den;
650 
651     env->cc_z = quot;
652     env->cc_n = quot;
653     env->cc_v = 0;
654 
655     if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) {
656         if (numr == regr) {
657             env->dregs[numr] = quot;
658         } else {
659             env->dregs[regr] = rem;
660         }
661     } else {
662         env->dregs[regr] = rem;
663         env->dregs[numr] = quot;
664     }
665 }
666 
667 void HELPER(divsl)(CPUM68KState *env, int numr, int regr,
668                    int32_t den, int ilen)
669 {
670     int32_t num = env->dregs[numr];
671     int32_t quot, rem;
672 
673     env->cc_c = 0; /* always cleared, even if overflow/div0 */
674 
675     if (den == 0) {
676         raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
677     }
678     quot = num / den;
679     rem = num % den;
680 
681     env->cc_z = quot;
682     env->cc_n = quot;
683     env->cc_v = 0;
684 
685     if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) {
686         if (numr == regr) {
687             env->dregs[numr] = quot;
688         } else {
689             env->dregs[regr] = rem;
690         }
691     } else {
692         env->dregs[regr] = rem;
693         env->dregs[numr] = quot;
694     }
695 }
696 
697 void HELPER(divull)(CPUM68KState *env, int numr, int regr,
698                     uint32_t den, int ilen)
699 {
700     uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
701     uint64_t quot;
702     uint32_t rem;
703 
704     env->cc_c = 0; /* always cleared, even if overflow/div0 */
705 
706     if (den == 0) {
707         raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
708     }
709     quot = num / den;
710     rem = num % den;
711 
712     if (quot > 0xffffffffULL) {
713         env->cc_v = -1;
714         /*
715          * real 68040 keeps N and unset Z on overflow,
716          * whereas documentation says "undefined"
717          */
718         env->cc_z = 1;
719         return;
720     }
721     env->cc_z = quot;
722     env->cc_n = quot;
723     env->cc_v = 0;
724 
725     /*
726      * If Dq and Dr are the same, the quotient is returned.
727      * therefore we set Dq last.
728      */
729 
730     env->dregs[regr] = rem;
731     env->dregs[numr] = quot;
732 }
733 
734 void HELPER(divsll)(CPUM68KState *env, int numr, int regr,
735                     int32_t den, int ilen)
736 {
737     int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
738     int64_t quot;
739     int32_t rem;
740 
741     env->cc_c = 0; /* always cleared, even if overflow/div0 */
742 
743     if (den == 0) {
744         raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
745     }
746     quot = num / den;
747     rem = num % den;
748 
749     if (quot != (int32_t)quot) {
750         env->cc_v = -1;
751         /*
752          * real 68040 keeps N and unset Z on overflow,
753          * whereas documentation says "undefined"
754          */
755         env->cc_z = 1;
756         return;
757     }
758     env->cc_z = quot;
759     env->cc_n = quot;
760     env->cc_v = 0;
761 
762     /*
763      * If Dq and Dr are the same, the quotient is returned.
764      * therefore we set Dq last.
765      */
766 
767     env->dregs[regr] = rem;
768     env->dregs[numr] = quot;
769 }
770 
771 /* We're executing in a serial context -- no need to be atomic.  */
772 void HELPER(cas2w)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
773 {
774     uint32_t Dc1 = extract32(regs, 9, 3);
775     uint32_t Dc2 = extract32(regs, 6, 3);
776     uint32_t Du1 = extract32(regs, 3, 3);
777     uint32_t Du2 = extract32(regs, 0, 3);
778     int16_t c1 = env->dregs[Dc1];
779     int16_t c2 = env->dregs[Dc2];
780     int16_t u1 = env->dregs[Du1];
781     int16_t u2 = env->dregs[Du2];
782     int16_t l1, l2;
783     uintptr_t ra = GETPC();
784 
785     l1 = cpu_lduw_data_ra(env, a1, ra);
786     l2 = cpu_lduw_data_ra(env, a2, ra);
787     if (l1 == c1 && l2 == c2) {
788         cpu_stw_data_ra(env, a1, u1, ra);
789         cpu_stw_data_ra(env, a2, u2, ra);
790     }
791 
792     if (c1 != l1) {
793         env->cc_n = l1;
794         env->cc_v = c1;
795     } else {
796         env->cc_n = l2;
797         env->cc_v = c2;
798     }
799     env->cc_op = CC_OP_CMPW;
800     env->dregs[Dc1] = deposit32(env->dregs[Dc1], 0, 16, l1);
801     env->dregs[Dc2] = deposit32(env->dregs[Dc2], 0, 16, l2);
802 }
803 
804 static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2,
805                      bool parallel)
806 {
807     uint32_t Dc1 = extract32(regs, 9, 3);
808     uint32_t Dc2 = extract32(regs, 6, 3);
809     uint32_t Du1 = extract32(regs, 3, 3);
810     uint32_t Du2 = extract32(regs, 0, 3);
811     uint32_t c1 = env->dregs[Dc1];
812     uint32_t c2 = env->dregs[Dc2];
813     uint32_t u1 = env->dregs[Du1];
814     uint32_t u2 = env->dregs[Du2];
815     uint32_t l1, l2;
816     uintptr_t ra = GETPC();
817 #if defined(CONFIG_ATOMIC64)
818     int mmu_idx = cpu_mmu_index(env, 0);
819     MemOpIdx oi = make_memop_idx(MO_BEUQ, mmu_idx);
820 #endif
821 
822     if (parallel) {
823         /* We're executing in a parallel context -- must be atomic.  */
824 #ifdef CONFIG_ATOMIC64
825         uint64_t c, u, l;
826         if ((a1 & 7) == 0 && a2 == a1 + 4) {
827             c = deposit64(c2, 32, 32, c1);
828             u = deposit64(u2, 32, 32, u1);
829             l = cpu_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra);
830             l1 = l >> 32;
831             l2 = l;
832         } else if ((a2 & 7) == 0 && a1 == a2 + 4) {
833             c = deposit64(c1, 32, 32, c2);
834             u = deposit64(u1, 32, 32, u2);
835             l = cpu_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra);
836             l2 = l >> 32;
837             l1 = l;
838         } else
839 #endif
840         {
841             /* Tell the main loop we need to serialize this insn.  */
842             cpu_loop_exit_atomic(env_cpu(env), ra);
843         }
844     } else {
845         /* We're executing in a serial context -- no need to be atomic.  */
846         l1 = cpu_ldl_data_ra(env, a1, ra);
847         l2 = cpu_ldl_data_ra(env, a2, ra);
848         if (l1 == c1 && l2 == c2) {
849             cpu_stl_data_ra(env, a1, u1, ra);
850             cpu_stl_data_ra(env, a2, u2, ra);
851         }
852     }
853 
854     if (c1 != l1) {
855         env->cc_n = l1;
856         env->cc_v = c1;
857     } else {
858         env->cc_n = l2;
859         env->cc_v = c2;
860     }
861     env->cc_op = CC_OP_CMPL;
862     env->dregs[Dc1] = l1;
863     env->dregs[Dc2] = l2;
864 }
865 
866 void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
867 {
868     do_cas2l(env, regs, a1, a2, false);
869 }
870 
871 void HELPER(cas2l_parallel)(CPUM68KState *env, uint32_t regs, uint32_t a1,
872                             uint32_t a2)
873 {
874     do_cas2l(env, regs, a1, a2, true);
875 }
876 
877 struct bf_data {
878     uint32_t addr;
879     uint32_t bofs;
880     uint32_t blen;
881     uint32_t len;
882 };
883 
884 static struct bf_data bf_prep(uint32_t addr, int32_t ofs, uint32_t len)
885 {
886     int bofs, blen;
887 
888     /* Bound length; map 0 to 32.  */
889     len = ((len - 1) & 31) + 1;
890 
891     /* Note that ofs is signed.  */
892     addr += ofs / 8;
893     bofs = ofs % 8;
894     if (bofs < 0) {
895         bofs += 8;
896         addr -= 1;
897     }
898 
899     /*
900      * Compute the number of bytes required (minus one) to
901      * satisfy the bitfield.
902      */
903     blen = (bofs + len - 1) / 8;
904 
905     /*
906      * Canonicalize the bit offset for data loaded into a 64-bit big-endian
907      * word.  For the cases where BLEN is not a power of 2, adjust ADDR so
908      * that we can use the next power of two sized load without crossing a
909      * page boundary, unless the field itself crosses the boundary.
910      */
911     switch (blen) {
912     case 0:
913         bofs += 56;
914         break;
915     case 1:
916         bofs += 48;
917         break;
918     case 2:
919         if (addr & 1) {
920             bofs += 8;
921             addr -= 1;
922         }
923         /* fallthru */
924     case 3:
925         bofs += 32;
926         break;
927     case 4:
928         if (addr & 3) {
929             bofs += 8 * (addr & 3);
930             addr &= -4;
931         }
932         break;
933     default:
934         g_assert_not_reached();
935     }
936 
937     return (struct bf_data){
938         .addr = addr,
939         .bofs = bofs,
940         .blen = blen,
941         .len = len,
942     };
943 }
944 
945 static uint64_t bf_load(CPUM68KState *env, uint32_t addr, int blen,
946                         uintptr_t ra)
947 {
948     switch (blen) {
949     case 0:
950         return cpu_ldub_data_ra(env, addr, ra);
951     case 1:
952         return cpu_lduw_data_ra(env, addr, ra);
953     case 2:
954     case 3:
955         return cpu_ldl_data_ra(env, addr, ra);
956     case 4:
957         return cpu_ldq_data_ra(env, addr, ra);
958     default:
959         g_assert_not_reached();
960     }
961 }
962 
963 static void bf_store(CPUM68KState *env, uint32_t addr, int blen,
964                      uint64_t data, uintptr_t ra)
965 {
966     switch (blen) {
967     case 0:
968         cpu_stb_data_ra(env, addr, data, ra);
969         break;
970     case 1:
971         cpu_stw_data_ra(env, addr, data, ra);
972         break;
973     case 2:
974     case 3:
975         cpu_stl_data_ra(env, addr, data, ra);
976         break;
977     case 4:
978         cpu_stq_data_ra(env, addr, data, ra);
979         break;
980     default:
981         g_assert_not_reached();
982     }
983 }
984 
985 uint32_t HELPER(bfexts_mem)(CPUM68KState *env, uint32_t addr,
986                             int32_t ofs, uint32_t len)
987 {
988     uintptr_t ra = GETPC();
989     struct bf_data d = bf_prep(addr, ofs, len);
990     uint64_t data = bf_load(env, d.addr, d.blen, ra);
991 
992     return (int64_t)(data << d.bofs) >> (64 - d.len);
993 }
994 
995 uint64_t HELPER(bfextu_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 
1002     /*
1003      * Put CC_N at the top of the high word; put the zero-extended value
1004      * at the bottom of the low word.
1005      */
1006     data <<= d.bofs;
1007     data >>= 64 - d.len;
1008     data |= data << (64 - d.len);
1009 
1010     return data;
1011 }
1012 
1013 uint32_t HELPER(bfins_mem)(CPUM68KState *env, uint32_t addr, uint32_t val,
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 
1021     data = (data & ~mask) | (((uint64_t)val << (64 - d.len)) >> d.bofs);
1022 
1023     bf_store(env, d.addr, d.blen, data, ra);
1024 
1025     /* The field at the top of the word is also CC_N for CC_OP_LOGIC.  */
1026     return val << (32 - d.len);
1027 }
1028 
1029 uint32_t HELPER(bfchg_mem)(CPUM68KState *env, uint32_t addr,
1030                            int32_t ofs, uint32_t len)
1031 {
1032     uintptr_t ra = GETPC();
1033     struct bf_data d = bf_prep(addr, ofs, len);
1034     uint64_t data = bf_load(env, d.addr, d.blen, ra);
1035     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1036 
1037     bf_store(env, d.addr, d.blen, data ^ mask, ra);
1038 
1039     return ((data & mask) << d.bofs) >> 32;
1040 }
1041 
1042 uint32_t HELPER(bfclr_mem)(CPUM68KState *env, uint32_t addr,
1043                            int32_t ofs, uint32_t len)
1044 {
1045     uintptr_t ra = GETPC();
1046     struct bf_data d = bf_prep(addr, ofs, len);
1047     uint64_t data = bf_load(env, d.addr, d.blen, ra);
1048     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1049 
1050     bf_store(env, d.addr, d.blen, data & ~mask, ra);
1051 
1052     return ((data & mask) << d.bofs) >> 32;
1053 }
1054 
1055 uint32_t HELPER(bfset_mem)(CPUM68KState *env, uint32_t addr,
1056                            int32_t ofs, uint32_t len)
1057 {
1058     uintptr_t ra = GETPC();
1059     struct bf_data d = bf_prep(addr, ofs, len);
1060     uint64_t data = bf_load(env, d.addr, d.blen, ra);
1061     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1062 
1063     bf_store(env, d.addr, d.blen, data | mask, ra);
1064 
1065     return ((data & mask) << d.bofs) >> 32;
1066 }
1067 
1068 uint32_t HELPER(bfffo_reg)(uint32_t n, uint32_t ofs, uint32_t len)
1069 {
1070     return (n ? clz32(n) : len) + ofs;
1071 }
1072 
1073 uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr,
1074                            int32_t ofs, uint32_t len)
1075 {
1076     uintptr_t ra = GETPC();
1077     struct bf_data d = bf_prep(addr, ofs, len);
1078     uint64_t data = bf_load(env, d.addr, d.blen, ra);
1079     uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1080     uint64_t n = (data & mask) << d.bofs;
1081     uint32_t ffo = helper_bfffo_reg(n >> 32, ofs, d.len);
1082 
1083     /*
1084      * Return FFO in the low word and N in the high word.
1085      * Note that because of MASK and the shift, the low word
1086      * is already zero.
1087      */
1088     return n | ffo;
1089 }
1090 
1091 void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub)
1092 {
1093     /*
1094      * From the specs:
1095      *   X: Not affected, C,V,Z: Undefined,
1096      *   N: Set if val < 0; cleared if val > ub, undefined otherwise
1097      * We implement here values found from a real MC68040:
1098      *   X,V,Z: Not affected
1099      *   N: Set if val < 0; cleared if val >= 0
1100      *   C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise
1101      *      if 0 > ub: set if val > ub and val < 0, cleared otherwise
1102      */
1103     env->cc_n = val;
1104     env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0;
1105 
1106     if (val < 0 || val > ub) {
1107         raise_exception_format2(env, EXCP_CHK, 2, GETPC());
1108     }
1109 }
1110 
1111 void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub)
1112 {
1113     /*
1114      * From the specs:
1115      *   X: Not affected, N,V: Undefined,
1116      *   Z: Set if val is equal to lb or ub
1117      *   C: Set if val < lb or val > ub, cleared otherwise
1118      * We implement here values found from a real MC68040:
1119      *   X,N,V: Not affected
1120      *   Z: Set if val is equal to lb or ub
1121      *   C: if lb <= ub: set if val < lb or val > ub, cleared otherwise
1122      *      if lb > ub: set if val > ub and val < lb, cleared otherwise
1123      */
1124     env->cc_z = val != lb && val != ub;
1125     env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb;
1126 
1127     if (env->cc_c) {
1128         raise_exception_format2(env, EXCP_CHK, 4, GETPC());
1129     }
1130 }
1131