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