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