xref: /openbmc/qemu/target/m68k/helper.c (revision 6b8f9c6e)
1 /*
2  *  m68k op helpers
3  *
4  *  Copyright (c) 2006-2007 CodeSourcery
5  *  Written by Paul Brook
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/exec-all.h"
24 #include "exec/gdbstub.h"
25 #include "exec/helper-proto.h"
26 #include "fpu/softfloat.h"
27 #include "qemu/qemu-print.h"
28 
29 #define SIGNBIT (1u << 31)
30 
31 /* Sort alphabetically, except for "any". */
32 static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b)
33 {
34     ObjectClass *class_a = (ObjectClass *)a;
35     ObjectClass *class_b = (ObjectClass *)b;
36     const char *name_a, *name_b;
37 
38     name_a = object_class_get_name(class_a);
39     name_b = object_class_get_name(class_b);
40     if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) {
41         return 1;
42     } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
43         return -1;
44     } else {
45         return strcasecmp(name_a, name_b);
46     }
47 }
48 
49 static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
50 {
51     ObjectClass *c = data;
52     const char *typename;
53     char *name;
54 
55     typename = object_class_get_name(c);
56     name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
57     qemu_printf("%s\n", name);
58     g_free(name);
59 }
60 
61 void m68k_cpu_list(void)
62 {
63     GSList *list;
64 
65     list = object_class_get_list(TYPE_M68K_CPU, false);
66     list = g_slist_sort(list, m68k_cpu_list_compare);
67     g_slist_foreach(list, m68k_cpu_list_entry, NULL);
68     g_slist_free(list);
69 }
70 
71 static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
72 {
73     if (n < 8) {
74         float_status s;
75         stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
76         return 8;
77     }
78     switch (n) {
79     case 8: /* fpcontrol */
80         stl_be_p(mem_buf, env->fpcr);
81         return 4;
82     case 9: /* fpstatus */
83         stl_be_p(mem_buf, env->fpsr);
84         return 4;
85     case 10: /* fpiar, not implemented */
86         memset(mem_buf, 0, 4);
87         return 4;
88     }
89     return 0;
90 }
91 
92 static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
93 {
94     if (n < 8) {
95         float_status s;
96         env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
97         return 8;
98     }
99     switch (n) {
100     case 8: /* fpcontrol */
101         cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
102         return 4;
103     case 9: /* fpstatus */
104         env->fpsr = ldl_p(mem_buf);
105         return 4;
106     case 10: /* fpiar, not implemented */
107         return 4;
108     }
109     return 0;
110 }
111 
112 static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
113 {
114     if (n < 8) {
115         stw_be_p(mem_buf, env->fregs[n].l.upper);
116         memset(mem_buf + 2, 0, 2);
117         stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
118         return 12;
119     }
120     switch (n) {
121     case 8: /* fpcontrol */
122         stl_be_p(mem_buf, env->fpcr);
123         return 4;
124     case 9: /* fpstatus */
125         stl_be_p(mem_buf, env->fpsr);
126         return 4;
127     case 10: /* fpiar, not implemented */
128         memset(mem_buf, 0, 4);
129         return 4;
130     }
131     return 0;
132 }
133 
134 static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
135 {
136     if (n < 8) {
137         env->fregs[n].l.upper = lduw_be_p(mem_buf);
138         env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
139         return 12;
140     }
141     switch (n) {
142     case 8: /* fpcontrol */
143         cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
144         return 4;
145     case 9: /* fpstatus */
146         env->fpsr = ldl_p(mem_buf);
147         return 4;
148     case 10: /* fpiar, not implemented */
149         return 4;
150     }
151     return 0;
152 }
153 
154 void m68k_cpu_init_gdb(M68kCPU *cpu)
155 {
156     CPUState *cs = CPU(cpu);
157     CPUM68KState *env = &cpu->env;
158 
159     if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
160         gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
161                                  11, "cf-fp.xml", 18);
162     } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
163         gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
164                                  m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
165     }
166     /* TODO: Add [E]MAC registers.  */
167 }
168 
169 void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
170 {
171     M68kCPU *cpu = m68k_env_get_cpu(env);
172 
173     switch (reg) {
174     case M68K_CR_CACR:
175         env->cacr = val;
176         m68k_switch_sp(env);
177         break;
178     case M68K_CR_ACR0:
179     case M68K_CR_ACR1:
180     case M68K_CR_ACR2:
181     case M68K_CR_ACR3:
182         /* TODO: Implement Access Control Registers.  */
183         break;
184     case M68K_CR_VBR:
185         env->vbr = val;
186         break;
187     /* TODO: Implement control registers.  */
188     default:
189         cpu_abort(CPU(cpu),
190                   "Unimplemented control register write 0x%x = 0x%x\n",
191                   reg, val);
192     }
193 }
194 
195 void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
196 {
197     M68kCPU *cpu = m68k_env_get_cpu(env);
198 
199     switch (reg) {
200     /* MC680[1234]0 */
201     case M68K_CR_SFC:
202         env->sfc = val & 7;
203         return;
204     case M68K_CR_DFC:
205         env->dfc = val & 7;
206         return;
207     case M68K_CR_VBR:
208         env->vbr = val;
209         return;
210     /* MC680[234]0 */
211     case M68K_CR_CACR:
212         env->cacr = val;
213         m68k_switch_sp(env);
214         return;
215     /* MC680[34]0 */
216     case M68K_CR_TC:
217         env->mmu.tcr = val;
218         return;
219     case M68K_CR_MMUSR:
220         env->mmu.mmusr = val;
221         return;
222     case M68K_CR_SRP:
223         env->mmu.srp = val;
224         return;
225     case M68K_CR_URP:
226         env->mmu.urp = val;
227         return;
228     case M68K_CR_USP:
229         env->sp[M68K_USP] = val;
230         return;
231     case M68K_CR_MSP:
232         env->sp[M68K_SSP] = val;
233         return;
234     case M68K_CR_ISP:
235         env->sp[M68K_ISP] = val;
236         return;
237     /* MC68040/MC68LC040 */
238     case M68K_CR_ITT0:
239         env->mmu.ttr[M68K_ITTR0] = val;
240         return;
241     case M68K_CR_ITT1:
242          env->mmu.ttr[M68K_ITTR1] = val;
243         return;
244     case M68K_CR_DTT0:
245         env->mmu.ttr[M68K_DTTR0] = val;
246         return;
247     case M68K_CR_DTT1:
248         env->mmu.ttr[M68K_DTTR1] = val;
249         return;
250     }
251     cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
252               reg, val);
253 }
254 
255 uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
256 {
257     M68kCPU *cpu = m68k_env_get_cpu(env);
258 
259     switch (reg) {
260     /* MC680[1234]0 */
261     case M68K_CR_SFC:
262         return env->sfc;
263     case M68K_CR_DFC:
264         return env->dfc;
265     case M68K_CR_VBR:
266         return env->vbr;
267     /* MC680[234]0 */
268     case M68K_CR_CACR:
269         return env->cacr;
270     /* MC680[34]0 */
271     case M68K_CR_TC:
272         return env->mmu.tcr;
273     case M68K_CR_MMUSR:
274         return env->mmu.mmusr;
275     case M68K_CR_SRP:
276         return env->mmu.srp;
277     case M68K_CR_USP:
278         return env->sp[M68K_USP];
279     case M68K_CR_MSP:
280         return env->sp[M68K_SSP];
281     case M68K_CR_ISP:
282         return env->sp[M68K_ISP];
283     /* MC68040/MC68LC040 */
284     case M68K_CR_URP:
285         return env->mmu.urp;
286     case M68K_CR_ITT0:
287         return env->mmu.ttr[M68K_ITTR0];
288     case M68K_CR_ITT1:
289         return env->mmu.ttr[M68K_ITTR1];
290     case M68K_CR_DTT0:
291         return env->mmu.ttr[M68K_DTTR0];
292     case M68K_CR_DTT1:
293         return env->mmu.ttr[M68K_DTTR1];
294     }
295     cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n",
296               reg);
297 }
298 
299 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
300 {
301     uint32_t acc;
302     int8_t exthigh;
303     uint8_t extlow;
304     uint64_t regval;
305     int i;
306     if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
307         for (i = 0; i < 4; i++) {
308             regval = env->macc[i];
309             exthigh = regval >> 40;
310             if (env->macsr & MACSR_FI) {
311                 acc = regval >> 8;
312                 extlow = regval;
313             } else {
314                 acc = regval;
315                 extlow = regval >> 32;
316             }
317             if (env->macsr & MACSR_FI) {
318                 regval = (((uint64_t)acc) << 8) | extlow;
319                 regval |= ((int64_t)exthigh) << 40;
320             } else if (env->macsr & MACSR_SU) {
321                 regval = acc | (((int64_t)extlow) << 32);
322                 regval |= ((int64_t)exthigh) << 40;
323             } else {
324                 regval = acc | (((uint64_t)extlow) << 32);
325                 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
326             }
327             env->macc[i] = regval;
328         }
329     }
330     env->macsr = val;
331 }
332 
333 void m68k_switch_sp(CPUM68KState *env)
334 {
335     int new_sp;
336 
337     env->sp[env->current_sp] = env->aregs[7];
338     if (m68k_feature(env, M68K_FEATURE_M68000)) {
339         if (env->sr & SR_S) {
340             if (env->sr & SR_M) {
341                 new_sp = M68K_SSP;
342             } else {
343                 new_sp = M68K_ISP;
344             }
345         } else {
346             new_sp = M68K_USP;
347         }
348     } else {
349         new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
350                  ? M68K_SSP : M68K_USP;
351     }
352     env->aregs[7] = env->sp[new_sp];
353     env->current_sp = new_sp;
354 }
355 
356 #if !defined(CONFIG_USER_ONLY)
357 /* MMU: 68040 only */
358 
359 static void print_address_zone(uint32_t logical, uint32_t physical,
360                                uint32_t size, int attr)
361 {
362     qemu_printf("%08x - %08x -> %08x - %08x %c ",
363                 logical, logical + size - 1,
364                 physical, physical + size - 1,
365                 attr & 4 ? 'W' : '-');
366     size >>= 10;
367     if (size < 1024) {
368         qemu_printf("(%d KiB)\n", size);
369     } else {
370         size >>= 10;
371         if (size < 1024) {
372             qemu_printf("(%d MiB)\n", size);
373         } else {
374             size >>= 10;
375             qemu_printf("(%d GiB)\n", size);
376         }
377     }
378 }
379 
380 static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
381 {
382     int i, j, k;
383     int tic_size, tic_shift;
384     uint32_t tib_mask;
385     uint32_t tia, tib, tic;
386     uint32_t logical = 0xffffffff, physical = 0xffffffff;
387     uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
388     uint32_t last_logical, last_physical;
389     int32_t size;
390     int last_attr = -1, attr = -1;
391     M68kCPU *cpu = m68k_env_get_cpu(env);
392     CPUState *cs = CPU(cpu);
393     MemTxResult txres;
394 
395     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
396         /* 8k page */
397         tic_size = 32;
398         tic_shift = 13;
399         tib_mask = M68K_8K_PAGE_MASK;
400     } else {
401         /* 4k page */
402         tic_size = 64;
403         tic_shift = 12;
404         tib_mask = M68K_4K_PAGE_MASK;
405     }
406     for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
407         tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4,
408                                 MEMTXATTRS_UNSPECIFIED, &txres);
409         if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) {
410             continue;
411         }
412         for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
413             tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4,
414                                     MEMTXATTRS_UNSPECIFIED, &txres);
415             if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) {
416                 continue;
417             }
418             for (k = 0; k < tic_size; k++) {
419                 tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4,
420                                         MEMTXATTRS_UNSPECIFIED, &txres);
421                 if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) {
422                     continue;
423                 }
424                 if (M68K_PDT_INDIRECT(tic)) {
425                     tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic),
426                                             MEMTXATTRS_UNSPECIFIED, &txres);
427                     if (txres != MEMTX_OK) {
428                         continue;
429                     }
430                 }
431 
432                 last_logical = logical;
433                 logical = (i << M68K_TTS_ROOT_SHIFT) |
434                           (j << M68K_TTS_POINTER_SHIFT) |
435                           (k << tic_shift);
436 
437                 last_physical = physical;
438                 physical = tic & ~((1 << tic_shift) - 1);
439 
440                 last_attr = attr;
441                 attr = tic & ((1 << tic_shift) - 1);
442 
443                 if ((logical != (last_logical + (1 << tic_shift))) ||
444                     (physical != (last_physical + (1 << tic_shift))) ||
445                     (attr & 4) != (last_attr & 4)) {
446 
447                     if (first_logical != 0xffffffff) {
448                         size = last_logical + (1 << tic_shift) -
449                                first_logical;
450                         print_address_zone(first_logical,
451                                            first_physical, size, last_attr);
452                     }
453                     first_logical = logical;
454                     first_physical = physical;
455                 }
456             }
457         }
458     }
459     if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
460         size = logical + (1 << tic_shift) - first_logical;
461         print_address_zone(first_logical, first_physical, size, last_attr);
462     }
463 }
464 
465 #define DUMP_CACHEFLAGS(a) \
466     switch (a & M68K_DESC_CACHEMODE) { \
467     case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
468         qemu_printf("T"); \
469         break; \
470     case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
471         qemu_printf("C"); \
472         break; \
473     case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
474         qemu_printf("S"); \
475         break; \
476     case M68K_DESC_CM_NCACHE: /* noncachable */ \
477         qemu_printf("N"); \
478         break; \
479     }
480 
481 static void dump_ttr(uint32_t ttr)
482 {
483     if ((ttr & M68K_TTR_ENABLED) == 0) {
484         qemu_printf("disabled\n");
485         return;
486     }
487     qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ",
488                 ttr & M68K_TTR_ADDR_BASE,
489                 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
490     switch (ttr & M68K_TTR_SFIELD) {
491     case M68K_TTR_SFIELD_USER:
492         qemu_printf("U");
493         break;
494     case M68K_TTR_SFIELD_SUPER:
495         qemu_printf("S");
496         break;
497     default:
498         qemu_printf("*");
499         break;
500     }
501     DUMP_CACHEFLAGS(ttr);
502     if (ttr & M68K_DESC_WRITEPROT) {
503         qemu_printf("R");
504     } else {
505         qemu_printf("W");
506     }
507     qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >>
508                                M68K_DESC_USERATTR_SHIFT);
509 }
510 
511 void dump_mmu(CPUM68KState *env)
512 {
513     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
514         qemu_printf("Translation disabled\n");
515         return;
516     }
517     qemu_printf("Page Size: ");
518     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
519         qemu_printf("8kB\n");
520     } else {
521         qemu_printf("4kB\n");
522     }
523 
524     qemu_printf("MMUSR: ");
525     if (env->mmu.mmusr & M68K_MMU_B_040) {
526         qemu_printf("BUS ERROR\n");
527     } else {
528         qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
529         /* flags found on the page descriptor */
530         if (env->mmu.mmusr & M68K_MMU_G_040) {
531             qemu_printf("G"); /* Global */
532         } else {
533             qemu_printf(".");
534         }
535         if (env->mmu.mmusr & M68K_MMU_S_040) {
536             qemu_printf("S"); /* Supervisor */
537         } else {
538             qemu_printf(".");
539         }
540         if (env->mmu.mmusr & M68K_MMU_M_040) {
541             qemu_printf("M"); /* Modified */
542         } else {
543             qemu_printf(".");
544         }
545         if (env->mmu.mmusr & M68K_MMU_WP_040) {
546             qemu_printf("W"); /* Write protect */
547         } else {
548             qemu_printf(".");
549         }
550         if (env->mmu.mmusr & M68K_MMU_T_040) {
551             qemu_printf("T"); /* Transparent */
552         } else {
553             qemu_printf(".");
554         }
555         if (env->mmu.mmusr & M68K_MMU_R_040) {
556             qemu_printf("R"); /* Resident */
557         } else {
558             qemu_printf(".");
559         }
560         qemu_printf(" Cache: ");
561         DUMP_CACHEFLAGS(env->mmu.mmusr);
562         qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3);
563         qemu_printf("\n");
564     }
565 
566     qemu_printf("ITTR0: ");
567     dump_ttr(env->mmu.ttr[M68K_ITTR0]);
568     qemu_printf("ITTR1: ");
569     dump_ttr(env->mmu.ttr[M68K_ITTR1]);
570     qemu_printf("DTTR0: ");
571     dump_ttr(env->mmu.ttr[M68K_DTTR0]);
572     qemu_printf("DTTR1: ");
573     dump_ttr(env->mmu.ttr[M68K_DTTR1]);
574 
575     qemu_printf("SRP: 0x%08x\n", env->mmu.srp);
576     dump_address_map(env, env->mmu.srp);
577 
578     qemu_printf("URP: 0x%08x\n", env->mmu.urp);
579     dump_address_map(env, env->mmu.urp);
580 }
581 
582 static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
583                      int access_type)
584 {
585     uint32_t base, mask;
586 
587     /* check if transparent translation is enabled */
588     if ((ttr & M68K_TTR_ENABLED) == 0) {
589         return 0;
590     }
591 
592     /* check mode access */
593     switch (ttr & M68K_TTR_SFIELD) {
594     case M68K_TTR_SFIELD_USER:
595         /* match only if user */
596         if ((access_type & ACCESS_SUPER) != 0) {
597             return 0;
598         }
599         break;
600     case M68K_TTR_SFIELD_SUPER:
601         /* match only if supervisor */
602         if ((access_type & ACCESS_SUPER) == 0) {
603             return 0;
604         }
605         break;
606     default:
607         /* all other values disable mode matching (FC2) */
608         break;
609     }
610 
611     /* check address matching */
612 
613     base = ttr & M68K_TTR_ADDR_BASE;
614     mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
615     mask <<= M68K_TTR_ADDR_MASK_SHIFT;
616 
617     if ((addr & mask) != (base & mask)) {
618         return 0;
619     }
620 
621     *prot = PAGE_READ | PAGE_EXEC;
622     if ((ttr & M68K_DESC_WRITEPROT) == 0) {
623         *prot |= PAGE_WRITE;
624     }
625 
626     return 1;
627 }
628 
629 static int get_physical_address(CPUM68KState *env, hwaddr *physical,
630                                 int *prot, target_ulong address,
631                                 int access_type, target_ulong *page_size)
632 {
633     M68kCPU *cpu = m68k_env_get_cpu(env);
634     CPUState *cs = CPU(cpu);
635     uint32_t entry;
636     uint32_t next;
637     target_ulong page_mask;
638     bool debug = access_type & ACCESS_DEBUG;
639     int page_bits;
640     int i;
641     MemTxResult txres;
642 
643     /* Transparent Translation (physical = logical) */
644     for (i = 0; i < M68K_MAX_TTR; i++) {
645         if (check_TTR(env->mmu.TTR(access_type, i),
646                       prot, address, access_type)) {
647             if (access_type & ACCESS_PTEST) {
648                 /* Transparent Translation Register bit */
649                 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
650             }
651             *physical = address & TARGET_PAGE_MASK;
652             *page_size = TARGET_PAGE_SIZE;
653             return 0;
654         }
655     }
656 
657     /* Page Table Root Pointer */
658     *prot = PAGE_READ | PAGE_WRITE;
659     if (access_type & ACCESS_CODE) {
660         *prot |= PAGE_EXEC;
661     }
662     if (access_type & ACCESS_SUPER) {
663         next = env->mmu.srp;
664     } else {
665         next = env->mmu.urp;
666     }
667 
668     /* Root Index */
669     entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
670 
671     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
672     if (txres != MEMTX_OK) {
673         goto txfail;
674     }
675     if (!M68K_UDT_VALID(next)) {
676         return -1;
677     }
678     if (!(next & M68K_DESC_USED) && !debug) {
679         address_space_stl(cs->as, entry, next | M68K_DESC_USED,
680                           MEMTXATTRS_UNSPECIFIED, &txres);
681         if (txres != MEMTX_OK) {
682             goto txfail;
683         }
684     }
685     if (next & M68K_DESC_WRITEPROT) {
686         if (access_type & ACCESS_PTEST) {
687             env->mmu.mmusr |= M68K_MMU_WP_040;
688         }
689         *prot &= ~PAGE_WRITE;
690         if (access_type & ACCESS_STORE) {
691             return -1;
692         }
693     }
694 
695     /* Pointer Index */
696     entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
697 
698     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
699     if (txres != MEMTX_OK) {
700         goto txfail;
701     }
702     if (!M68K_UDT_VALID(next)) {
703         return -1;
704     }
705     if (!(next & M68K_DESC_USED) && !debug) {
706         address_space_stl(cs->as, entry, next | M68K_DESC_USED,
707                           MEMTXATTRS_UNSPECIFIED, &txres);
708         if (txres != MEMTX_OK) {
709             goto txfail;
710         }
711     }
712     if (next & M68K_DESC_WRITEPROT) {
713         if (access_type & ACCESS_PTEST) {
714             env->mmu.mmusr |= M68K_MMU_WP_040;
715         }
716         *prot &= ~PAGE_WRITE;
717         if (access_type & ACCESS_STORE) {
718             return -1;
719         }
720     }
721 
722     /* Page Index */
723     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
724         entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
725     } else {
726         entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
727     }
728 
729     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
730     if (txres != MEMTX_OK) {
731         goto txfail;
732     }
733 
734     if (!M68K_PDT_VALID(next)) {
735         return -1;
736     }
737     if (M68K_PDT_INDIRECT(next)) {
738         next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next),
739                                  MEMTXATTRS_UNSPECIFIED, &txres);
740         if (txres != MEMTX_OK) {
741             goto txfail;
742         }
743     }
744     if (access_type & ACCESS_STORE) {
745         if (next & M68K_DESC_WRITEPROT) {
746             if (!(next & M68K_DESC_USED) && !debug) {
747                 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
748                                   MEMTXATTRS_UNSPECIFIED, &txres);
749                 if (txres != MEMTX_OK) {
750                     goto txfail;
751                 }
752             }
753         } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
754                            (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
755             address_space_stl(cs->as, entry,
756                               next | (M68K_DESC_MODIFIED | M68K_DESC_USED),
757                               MEMTXATTRS_UNSPECIFIED, &txres);
758             if (txres != MEMTX_OK) {
759                 goto txfail;
760             }
761         }
762     } else {
763         if (!(next & M68K_DESC_USED) && !debug) {
764             address_space_stl(cs->as, entry, next | M68K_DESC_USED,
765                               MEMTXATTRS_UNSPECIFIED, &txres);
766             if (txres != MEMTX_OK) {
767                 goto txfail;
768             }
769         }
770     }
771 
772     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
773         page_bits = 13;
774     } else {
775         page_bits = 12;
776     }
777     *page_size = 1 << page_bits;
778     page_mask = ~(*page_size - 1);
779     *physical = next & page_mask;
780 
781     if (access_type & ACCESS_PTEST) {
782         env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
783         env->mmu.mmusr |= *physical & 0xfffff000;
784         env->mmu.mmusr |= M68K_MMU_R_040;
785     }
786 
787     if (next & M68K_DESC_WRITEPROT) {
788         *prot &= ~PAGE_WRITE;
789         if (access_type & ACCESS_STORE) {
790             return -1;
791         }
792     }
793     if (next & M68K_DESC_SUPERONLY) {
794         if ((access_type & ACCESS_SUPER) == 0) {
795             return -1;
796         }
797     }
798 
799     return 0;
800 
801 txfail:
802     /*
803      * A page table load/store failed. TODO: we should really raise a
804      * suitable guest fault here if this is not a debug access.
805      * For now just return that the translation failed.
806      */
807     return -1;
808 }
809 
810 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
811 {
812     M68kCPU *cpu = M68K_CPU(cs);
813     CPUM68KState *env = &cpu->env;
814     hwaddr phys_addr;
815     int prot;
816     int access_type;
817     target_ulong page_size;
818 
819     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
820         /* MMU disabled */
821         return addr;
822     }
823 
824     access_type = ACCESS_DATA | ACCESS_DEBUG;
825     if (env->sr & SR_S) {
826         access_type |= ACCESS_SUPER;
827     }
828     if (get_physical_address(env, &phys_addr, &prot,
829                              addr, access_type, &page_size) != 0) {
830         return -1;
831     }
832     return phys_addr;
833 }
834 
835 /*
836  * Notify CPU of a pending interrupt.  Prioritization and vectoring should
837  * be handled by the interrupt controller.  Real hardware only requests
838  * the vector when the interrupt is acknowledged by the CPU.  For
839  * simplicity we calculate it when the interrupt is signalled.
840  */
841 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
842 {
843     CPUState *cs = CPU(cpu);
844     CPUM68KState *env = &cpu->env;
845 
846     env->pending_level = level;
847     env->pending_vector = vector;
848     if (level) {
849         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
850     } else {
851         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
852     }
853 }
854 
855 #endif
856 
857 bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
858                        MMUAccessType qemu_access_type, int mmu_idx,
859                        bool probe, uintptr_t retaddr)
860 {
861     M68kCPU *cpu = M68K_CPU(cs);
862     CPUM68KState *env = &cpu->env;
863 
864 #ifndef CONFIG_USER_ONLY
865     hwaddr physical;
866     int prot;
867     int access_type;
868     int ret;
869     target_ulong page_size;
870 
871     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
872         /* MMU disabled */
873         tlb_set_page(cs, address & TARGET_PAGE_MASK,
874                      address & TARGET_PAGE_MASK,
875                      PAGE_READ | PAGE_WRITE | PAGE_EXEC,
876                      mmu_idx, TARGET_PAGE_SIZE);
877         return true;
878     }
879 
880     if (qemu_access_type == MMU_INST_FETCH) {
881         access_type = ACCESS_CODE;
882     } else {
883         access_type = ACCESS_DATA;
884         if (qemu_access_type == MMU_DATA_STORE) {
885             access_type |= ACCESS_STORE;
886         }
887     }
888     if (mmu_idx != MMU_USER_IDX) {
889         access_type |= ACCESS_SUPER;
890     }
891 
892     ret = get_physical_address(&cpu->env, &physical, &prot,
893                                address, access_type, &page_size);
894     if (likely(ret == 0)) {
895         address &= TARGET_PAGE_MASK;
896         physical += address & (page_size - 1);
897         tlb_set_page(cs, address, physical,
898                      prot, mmu_idx, TARGET_PAGE_SIZE);
899         return true;
900     }
901 
902     if (probe) {
903         return false;
904     }
905 
906     /* page fault */
907     env->mmu.ssw = M68K_ATC_040;
908     switch (size) {
909     case 1:
910         env->mmu.ssw |= M68K_BA_SIZE_BYTE;
911         break;
912     case 2:
913         env->mmu.ssw |= M68K_BA_SIZE_WORD;
914         break;
915     case 4:
916         env->mmu.ssw |= M68K_BA_SIZE_LONG;
917         break;
918     }
919     if (access_type & ACCESS_SUPER) {
920         env->mmu.ssw |= M68K_TM_040_SUPER;
921     }
922     if (access_type & ACCESS_CODE) {
923         env->mmu.ssw |= M68K_TM_040_CODE;
924     } else {
925         env->mmu.ssw |= M68K_TM_040_DATA;
926     }
927     if (!(access_type & ACCESS_STORE)) {
928         env->mmu.ssw |= M68K_RW_040;
929     }
930 #endif
931 
932     cs->exception_index = EXCP_ACCESS;
933     env->mmu.ar = address;
934     cpu_loop_exit_restore(cs, retaddr);
935 }
936 
937 uint32_t HELPER(bitrev)(uint32_t x)
938 {
939     x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
940     x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
941     x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
942     return bswap32(x);
943 }
944 
945 uint32_t HELPER(ff1)(uint32_t x)
946 {
947     int n;
948     for (n = 32; x; n--)
949         x >>= 1;
950     return n;
951 }
952 
953 uint32_t HELPER(sats)(uint32_t val, uint32_t v)
954 {
955     /* The result has the opposite sign to the original value.  */
956     if ((int32_t)v < 0) {
957         val = (((int32_t)val) >> 31) ^ SIGNBIT;
958     }
959     return val;
960 }
961 
962 void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
963 {
964     env->sr = sr & 0xffe0;
965     cpu_m68k_set_ccr(env, sr);
966     m68k_switch_sp(env);
967 }
968 
969 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
970 {
971     cpu_m68k_set_sr(env, val);
972 }
973 
974 /* MAC unit.  */
975 /* FIXME: The MAC unit implementation is a bit of a mess.  Some helpers
976    take values,  others take register numbers and manipulate the contents
977    in-place.  */
978 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
979 {
980     uint32_t mask;
981     env->macc[dest] = env->macc[src];
982     mask = MACSR_PAV0 << dest;
983     if (env->macsr & (MACSR_PAV0 << src))
984         env->macsr |= mask;
985     else
986         env->macsr &= ~mask;
987 }
988 
989 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
990 {
991     int64_t product;
992     int64_t res;
993 
994     product = (uint64_t)op1 * op2;
995     res = (product << 24) >> 24;
996     if (res != product) {
997         env->macsr |= MACSR_V;
998         if (env->macsr & MACSR_OMC) {
999             /* Make sure the accumulate operation overflows.  */
1000             if (product < 0)
1001                 res = ~(1ll << 50);
1002             else
1003                 res = 1ll << 50;
1004         }
1005     }
1006     return res;
1007 }
1008 
1009 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1010 {
1011     uint64_t product;
1012 
1013     product = (uint64_t)op1 * op2;
1014     if (product & (0xffffffull << 40)) {
1015         env->macsr |= MACSR_V;
1016         if (env->macsr & MACSR_OMC) {
1017             /* Make sure the accumulate operation overflows.  */
1018             product = 1ll << 50;
1019         } else {
1020             product &= ((1ull << 40) - 1);
1021         }
1022     }
1023     return product;
1024 }
1025 
1026 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1027 {
1028     uint64_t product;
1029     uint32_t remainder;
1030 
1031     product = (uint64_t)op1 * op2;
1032     if (env->macsr & MACSR_RT) {
1033         remainder = product & 0xffffff;
1034         product >>= 24;
1035         if (remainder > 0x800000)
1036             product++;
1037         else if (remainder == 0x800000)
1038             product += (product & 1);
1039     } else {
1040         product >>= 24;
1041     }
1042     return product;
1043 }
1044 
1045 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
1046 {
1047     int64_t tmp;
1048     int64_t result;
1049     tmp = env->macc[acc];
1050     result = ((tmp << 16) >> 16);
1051     if (result != tmp) {
1052         env->macsr |= MACSR_V;
1053     }
1054     if (env->macsr & MACSR_V) {
1055         env->macsr |= MACSR_PAV0 << acc;
1056         if (env->macsr & MACSR_OMC) {
1057             /* The result is saturated to 32 bits, despite overflow occurring
1058                at 48 bits.  Seems weird, but that's what the hardware docs
1059                say.  */
1060             result = (result >> 63) ^ 0x7fffffff;
1061         }
1062     }
1063     env->macc[acc] = result;
1064 }
1065 
1066 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1067 {
1068     uint64_t val;
1069 
1070     val = env->macc[acc];
1071     if (val & (0xffffull << 48)) {
1072         env->macsr |= MACSR_V;
1073     }
1074     if (env->macsr & MACSR_V) {
1075         env->macsr |= MACSR_PAV0 << acc;
1076         if (env->macsr & MACSR_OMC) {
1077             if (val > (1ull << 53))
1078                 val = 0;
1079             else
1080                 val = (1ull << 48) - 1;
1081         } else {
1082             val &= ((1ull << 48) - 1);
1083         }
1084     }
1085     env->macc[acc] = val;
1086 }
1087 
1088 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1089 {
1090     int64_t sum;
1091     int64_t result;
1092 
1093     sum = env->macc[acc];
1094     result = (sum << 16) >> 16;
1095     if (result != sum) {
1096         env->macsr |= MACSR_V;
1097     }
1098     if (env->macsr & MACSR_V) {
1099         env->macsr |= MACSR_PAV0 << acc;
1100         if (env->macsr & MACSR_OMC) {
1101             result = (result >> 63) ^ 0x7fffffffffffll;
1102         }
1103     }
1104     env->macc[acc] = result;
1105 }
1106 
1107 void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1108 {
1109     uint64_t val;
1110     val = env->macc[acc];
1111     if (val == 0) {
1112         env->macsr |= MACSR_Z;
1113     } else if (val & (1ull << 47)) {
1114         env->macsr |= MACSR_N;
1115     }
1116     if (env->macsr & (MACSR_PAV0 << acc)) {
1117         env->macsr |= MACSR_V;
1118     }
1119     if (env->macsr & MACSR_FI) {
1120         val = ((int64_t)val) >> 40;
1121         if (val != 0 && val != -1)
1122             env->macsr |= MACSR_EV;
1123     } else if (env->macsr & MACSR_SU) {
1124         val = ((int64_t)val) >> 32;
1125         if (val != 0 && val != -1)
1126             env->macsr |= MACSR_EV;
1127     } else {
1128         if ((val >> 32) != 0)
1129             env->macsr |= MACSR_EV;
1130     }
1131 }
1132 
1133 #define EXTSIGN(val, index) (     \
1134     (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1135 )
1136 
1137 #define COMPUTE_CCR(op, x, n, z, v, c) {                                   \
1138     switch (op) {                                                          \
1139     case CC_OP_FLAGS:                                                      \
1140         /* Everything in place.  */                                        \
1141         break;                                                             \
1142     case CC_OP_ADDB:                                                       \
1143     case CC_OP_ADDW:                                                       \
1144     case CC_OP_ADDL:                                                       \
1145         res = n;                                                           \
1146         src2 = v;                                                          \
1147         src1 = EXTSIGN(res - src2, op - CC_OP_ADDB);                       \
1148         c = x;                                                             \
1149         z = n;                                                             \
1150         v = (res ^ src1) & ~(src1 ^ src2);                                 \
1151         break;                                                             \
1152     case CC_OP_SUBB:                                                       \
1153     case CC_OP_SUBW:                                                       \
1154     case CC_OP_SUBL:                                                       \
1155         res = n;                                                           \
1156         src2 = v;                                                          \
1157         src1 = EXTSIGN(res + src2, op - CC_OP_SUBB);                       \
1158         c = x;                                                             \
1159         z = n;                                                             \
1160         v = (res ^ src1) & (src1 ^ src2);                                  \
1161         break;                                                             \
1162     case CC_OP_CMPB:                                                       \
1163     case CC_OP_CMPW:                                                       \
1164     case CC_OP_CMPL:                                                       \
1165         src1 = n;                                                          \
1166         src2 = v;                                                          \
1167         res = EXTSIGN(src1 - src2, op - CC_OP_CMPB);                       \
1168         n = res;                                                           \
1169         z = res;                                                           \
1170         c = src1 < src2;                                                   \
1171         v = (res ^ src1) & (src1 ^ src2);                                  \
1172         break;                                                             \
1173     case CC_OP_LOGIC:                                                      \
1174         c = v = 0;                                                         \
1175         z = n;                                                             \
1176         break;                                                             \
1177     default:                                                               \
1178         cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op);         \
1179     }                                                                      \
1180 } while (0)
1181 
1182 uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1183 {
1184     uint32_t x, c, n, z, v;
1185     uint32_t res, src1, src2;
1186 
1187     x = env->cc_x;
1188     n = env->cc_n;
1189     z = env->cc_z;
1190     v = env->cc_v;
1191     c = env->cc_c;
1192 
1193     COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1194 
1195     n = n >> 31;
1196     z = (z == 0);
1197     v = v >> 31;
1198 
1199     return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1200 }
1201 
1202 uint32_t HELPER(get_ccr)(CPUM68KState *env)
1203 {
1204     return cpu_m68k_get_ccr(env);
1205 }
1206 
1207 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1208 {
1209     env->cc_x = (ccr & CCF_X ? 1 : 0);
1210     env->cc_n = (ccr & CCF_N ? -1 : 0);
1211     env->cc_z = (ccr & CCF_Z ? 0 : 1);
1212     env->cc_v = (ccr & CCF_V ? -1 : 0);
1213     env->cc_c = (ccr & CCF_C ? 1 : 0);
1214     env->cc_op = CC_OP_FLAGS;
1215 }
1216 
1217 void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1218 {
1219     cpu_m68k_set_ccr(env, ccr);
1220 }
1221 
1222 void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1223 {
1224     uint32_t res, src1, src2;
1225 
1226     COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1227     env->cc_op = CC_OP_FLAGS;
1228 }
1229 
1230 uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1231 {
1232     int rem;
1233     uint32_t result;
1234 
1235     if (env->macsr & MACSR_SU) {
1236         /* 16-bit rounding.  */
1237         rem = val & 0xffffff;
1238         val = (val >> 24) & 0xffffu;
1239         if (rem > 0x800000)
1240             val++;
1241         else if (rem == 0x800000)
1242             val += (val & 1);
1243     } else if (env->macsr & MACSR_RT) {
1244         /* 32-bit rounding.  */
1245         rem = val & 0xff;
1246         val >>= 8;
1247         if (rem > 0x80)
1248             val++;
1249         else if (rem == 0x80)
1250             val += (val & 1);
1251     } else {
1252         /* No rounding.  */
1253         val >>= 8;
1254     }
1255     if (env->macsr & MACSR_OMC) {
1256         /* Saturate.  */
1257         if (env->macsr & MACSR_SU) {
1258             if (val != (uint16_t) val) {
1259                 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1260             } else {
1261                 result = val & 0xffff;
1262             }
1263         } else {
1264             if (val != (uint32_t)val) {
1265                 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1266             } else {
1267                 result = (uint32_t)val;
1268             }
1269         }
1270     } else {
1271         /* No saturation.  */
1272         if (env->macsr & MACSR_SU) {
1273             result = val & 0xffff;
1274         } else {
1275             result = (uint32_t)val;
1276         }
1277     }
1278     return result;
1279 }
1280 
1281 uint32_t HELPER(get_macs)(uint64_t val)
1282 {
1283     if (val == (int32_t)val) {
1284         return (int32_t)val;
1285     } else {
1286         return (val >> 61) ^ ~SIGNBIT;
1287     }
1288 }
1289 
1290 uint32_t HELPER(get_macu)(uint64_t val)
1291 {
1292     if ((val >> 32) == 0) {
1293         return (uint32_t)val;
1294     } else {
1295         return 0xffffffffu;
1296     }
1297 }
1298 
1299 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1300 {
1301     uint32_t val;
1302     val = env->macc[acc] & 0x00ff;
1303     val |= (env->macc[acc] >> 32) & 0xff00;
1304     val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1305     val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1306     return val;
1307 }
1308 
1309 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1310 {
1311     uint32_t val;
1312     val = (env->macc[acc] >> 32) & 0xffff;
1313     val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1314     return val;
1315 }
1316 
1317 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1318 {
1319     int64_t res;
1320     int32_t tmp;
1321     res = env->macc[acc] & 0xffffffff00ull;
1322     tmp = (int16_t)(val & 0xff00);
1323     res |= ((int64_t)tmp) << 32;
1324     res |= val & 0xff;
1325     env->macc[acc] = res;
1326     res = env->macc[acc + 1] & 0xffffffff00ull;
1327     tmp = (val & 0xff000000);
1328     res |= ((int64_t)tmp) << 16;
1329     res |= (val >> 16) & 0xff;
1330     env->macc[acc + 1] = res;
1331 }
1332 
1333 void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
1334 {
1335     int64_t res;
1336     int32_t tmp;
1337     res = (uint32_t)env->macc[acc];
1338     tmp = (int16_t)val;
1339     res |= ((int64_t)tmp) << 32;
1340     env->macc[acc] = res;
1341     res = (uint32_t)env->macc[acc + 1];
1342     tmp = val & 0xffff0000;
1343     res |= (int64_t)tmp << 16;
1344     env->macc[acc + 1] = res;
1345 }
1346 
1347 void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
1348 {
1349     uint64_t res;
1350     res = (uint32_t)env->macc[acc];
1351     res |= ((uint64_t)(val & 0xffff)) << 32;
1352     env->macc[acc] = res;
1353     res = (uint32_t)env->macc[acc + 1];
1354     res |= (uint64_t)(val & 0xffff0000) << 16;
1355     env->macc[acc + 1] = res;
1356 }
1357 
1358 #if defined(CONFIG_SOFTMMU)
1359 void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1360 {
1361     M68kCPU *cpu = m68k_env_get_cpu(env);
1362     CPUState *cs = CPU(cpu);
1363     hwaddr physical;
1364     int access_type;
1365     int prot;
1366     int ret;
1367     target_ulong page_size;
1368 
1369     access_type = ACCESS_PTEST;
1370     if (env->dfc & 4) {
1371         access_type |= ACCESS_SUPER;
1372     }
1373     if ((env->dfc & 3) == 2) {
1374         access_type |= ACCESS_CODE;
1375     }
1376     if (!is_read) {
1377         access_type |= ACCESS_STORE;
1378     }
1379 
1380     env->mmu.mmusr = 0;
1381     env->mmu.ssw = 0;
1382     ret = get_physical_address(env, &physical, &prot, addr,
1383                                access_type, &page_size);
1384     if (ret == 0) {
1385         addr &= TARGET_PAGE_MASK;
1386         physical += addr & (page_size - 1);
1387         tlb_set_page(cs, addr, physical,
1388                      prot, access_type & ACCESS_SUPER ?
1389                      MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1390     }
1391 }
1392 
1393 void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1394 {
1395     M68kCPU *cpu = m68k_env_get_cpu(env);
1396 
1397     switch (opmode) {
1398     case 0: /* Flush page entry if not global */
1399     case 1: /* Flush page entry */
1400         tlb_flush_page(CPU(cpu), addr);
1401         break;
1402     case 2: /* Flush all except global entries */
1403         tlb_flush(CPU(cpu));
1404         break;
1405     case 3: /* Flush all entries */
1406         tlb_flush(CPU(cpu));
1407         break;
1408     }
1409 }
1410 
1411 void HELPER(reset)(CPUM68KState *env)
1412 {
1413     /* FIXME: reset all except CPU */
1414 }
1415 #endif
1416