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