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