xref: /openbmc/qemu/target/m68k/op_helper.c (revision 5da72194df36535d773c8bdc951529ecd5e31707)
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