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