xref: /qemu/target/m68k/helper.c (revision 8df0e6aedad33c6746f4bc2a4d0cfdd432877084)
1e6e5906bSpbrook /*
2e6e5906bSpbrook  *  m68k op helpers
3e6e5906bSpbrook  *
40633879fSpbrook  *  Copyright (c) 2006-2007 CodeSourcery
5e6e5906bSpbrook  *  Written by Paul Brook
6e6e5906bSpbrook  *
7e6e5906bSpbrook  * This library is free software; you can redistribute it and/or
8e6e5906bSpbrook  * modify it under the terms of the GNU Lesser General Public
9e6e5906bSpbrook  * License as published by the Free Software Foundation; either
10d749fb85SThomas Huth  * version 2.1 of the License, or (at your option) any later version.
11e6e5906bSpbrook  *
12e6e5906bSpbrook  * This library is distributed in the hope that it will be useful,
13e6e5906bSpbrook  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14e6e5906bSpbrook  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15d749fb85SThomas Huth  * Lesser General Public License for more details.
16e6e5906bSpbrook  *
17e6e5906bSpbrook  * You should have received a copy of the GNU Lesser General Public
188167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19e6e5906bSpbrook  */
20e6e5906bSpbrook 
21d8416665SPeter Maydell #include "qemu/osdep.h"
22e6e5906bSpbrook #include "cpu.h"
2363c91552SPaolo Bonzini #include "exec/exec-all.h"
24022c62cbSPaolo Bonzini #include "exec/gdbstub.h"
252ef6175aSRichard Henderson #include "exec/helper-proto.h"
2624f91e81SAlex Bennée #include "fpu/softfloat.h"
270442428aSMarkus Armbruster #include "qemu/qemu-print.h"
28e1f3808eSpbrook 
29e1f3808eSpbrook #define SIGNBIT (1u << 31)
30e1f3808eSpbrook 
3111150915SAndreas Färber /* Sort alphabetically, except for "any". */
3211150915SAndreas Färber static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b)
3311150915SAndreas Färber {
3411150915SAndreas Färber     ObjectClass *class_a = (ObjectClass *)a;
3511150915SAndreas Färber     ObjectClass *class_b = (ObjectClass *)b;
3611150915SAndreas Färber     const char *name_a, *name_b;
37aaed909aSbellard 
3811150915SAndreas Färber     name_a = object_class_get_name(class_a);
3911150915SAndreas Färber     name_b = object_class_get_name(class_b);
407a9f812bSAndreas Färber     if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) {
4111150915SAndreas Färber         return 1;
427a9f812bSAndreas Färber     } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
4311150915SAndreas Färber         return -1;
4411150915SAndreas Färber     } else {
4511150915SAndreas Färber         return strcasecmp(name_a, name_b);
4611150915SAndreas Färber     }
4711150915SAndreas Färber }
480402f767Spbrook 
4911150915SAndreas Färber static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
5011150915SAndreas Färber {
5111150915SAndreas Färber     ObjectClass *c = data;
527a9f812bSAndreas Färber     const char *typename;
537a9f812bSAndreas Färber     char *name;
5411150915SAndreas Färber 
557a9f812bSAndreas Färber     typename = object_class_get_name(c);
567a9f812bSAndreas Färber     name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
570442428aSMarkus Armbruster     qemu_printf("%s\n", name);
587a9f812bSAndreas Färber     g_free(name);
5911150915SAndreas Färber }
600402f767Spbrook 
610442428aSMarkus Armbruster void m68k_cpu_list(void)
62009a4356SLaurent Vivier {
6311150915SAndreas Färber     GSList *list;
64009a4356SLaurent Vivier 
6511150915SAndreas Färber     list = object_class_get_list(TYPE_M68K_CPU, false);
6611150915SAndreas Färber     list = g_slist_sort(list, m68k_cpu_list_compare);
670442428aSMarkus Armbruster     g_slist_foreach(list, m68k_cpu_list_entry, NULL);
6811150915SAndreas Färber     g_slist_free(list);
69009a4356SLaurent Vivier }
70009a4356SLaurent Vivier 
71a010bdbeSAlex Bennée static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
7256aebc89Spbrook {
7356aebc89Spbrook     if (n < 8) {
74f83311e4SLaurent Vivier         float_status s;
7538c1c098SPhilippe Mathieu-Daudé         return gdb_get_float64(mem_buf,
7638c1c098SPhilippe Mathieu-Daudé                                floatx80_to_float64(env->fregs[n].d, &s));
7756aebc89Spbrook     }
78ba624944SLaurent Vivier     switch (n) {
79ba624944SLaurent Vivier     case 8: /* fpcontrol */
80462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, env->fpcr);
81ba624944SLaurent Vivier     case 9: /* fpstatus */
82462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, env->fpsr);
83ba624944SLaurent Vivier     case 10: /* fpiar, not implemented */
84462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, 0);
8556aebc89Spbrook     }
8656aebc89Spbrook     return 0;
8756aebc89Spbrook }
8856aebc89Spbrook 
89f83311e4SLaurent Vivier static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
9056aebc89Spbrook {
9156aebc89Spbrook     if (n < 8) {
92f83311e4SLaurent Vivier         float_status s;
93f83311e4SLaurent Vivier         env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
9456aebc89Spbrook         return 8;
9556aebc89Spbrook     }
96ba624944SLaurent Vivier     switch (n) {
97ba624944SLaurent Vivier     case 8: /* fpcontrol */
98ba624944SLaurent Vivier         cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
99ba624944SLaurent Vivier         return 4;
100ba624944SLaurent Vivier     case 9: /* fpstatus */
101ba624944SLaurent Vivier         env->fpsr = ldl_p(mem_buf);
102ba624944SLaurent Vivier         return 4;
103ba624944SLaurent Vivier     case 10: /* fpiar, not implemented */
10456aebc89Spbrook         return 4;
10556aebc89Spbrook     }
10656aebc89Spbrook     return 0;
10756aebc89Spbrook }
10856aebc89Spbrook 
109a010bdbeSAlex Bennée static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
1105a4526b2SLaurent Vivier {
1115a4526b2SLaurent Vivier     if (n < 8) {
112462474d7SAlex Bennée         int len = gdb_get_reg16(mem_buf, env->fregs[n].l.upper);
1134b27f9b0SPhilippe Mathieu-Daudé         len += gdb_get_reg16(mem_buf, 0);
1144b27f9b0SPhilippe Mathieu-Daudé         len += gdb_get_reg64(mem_buf, env->fregs[n].l.lower);
115462474d7SAlex Bennée         return len;
1165a4526b2SLaurent Vivier     }
1175a4526b2SLaurent Vivier     switch (n) {
1185a4526b2SLaurent Vivier     case 8: /* fpcontrol */
119462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, env->fpcr);
1205a4526b2SLaurent Vivier     case 9: /* fpstatus */
121462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, env->fpsr);
1225a4526b2SLaurent Vivier     case 10: /* fpiar, not implemented */
123462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, 0);
1245a4526b2SLaurent Vivier     }
1255a4526b2SLaurent Vivier     return 0;
1265a4526b2SLaurent Vivier }
1275a4526b2SLaurent Vivier 
1285a4526b2SLaurent Vivier static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
1295a4526b2SLaurent Vivier {
1305a4526b2SLaurent Vivier     if (n < 8) {
1315a4526b2SLaurent Vivier         env->fregs[n].l.upper = lduw_be_p(mem_buf);
1325a4526b2SLaurent Vivier         env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
1335a4526b2SLaurent Vivier         return 12;
1345a4526b2SLaurent Vivier     }
1355a4526b2SLaurent Vivier     switch (n) {
1365a4526b2SLaurent Vivier     case 8: /* fpcontrol */
137ba624944SLaurent Vivier         cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
1385a4526b2SLaurent Vivier         return 4;
1395a4526b2SLaurent Vivier     case 9: /* fpstatus */
1405a4526b2SLaurent Vivier         env->fpsr = ldl_p(mem_buf);
1415a4526b2SLaurent Vivier         return 4;
1425a4526b2SLaurent Vivier     case 10: /* fpiar, not implemented */
1435a4526b2SLaurent Vivier         return 4;
1445a4526b2SLaurent Vivier     }
1455a4526b2SLaurent Vivier     return 0;
1465a4526b2SLaurent Vivier }
1475a4526b2SLaurent Vivier 
1486d1bbc62SAndreas Färber void m68k_cpu_init_gdb(M68kCPU *cpu)
1496d1bbc62SAndreas Färber {
15022169d41SAndreas Färber     CPUState *cs = CPU(cpu);
1516d1bbc62SAndreas Färber     CPUM68KState *env = &cpu->env;
1526d1bbc62SAndreas Färber 
15311150915SAndreas Färber     if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
154f83311e4SLaurent Vivier         gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
15511150915SAndreas Färber                                  11, "cf-fp.xml", 18);
1565a4526b2SLaurent Vivier     } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
1575a4526b2SLaurent Vivier         gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
1585a4526b2SLaurent Vivier                                  m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
159aaed909aSbellard     }
16011150915SAndreas Färber     /* TODO: Add [E]MAC registers.  */
161aaed909aSbellard }
162aaed909aSbellard 
1636e22b28eSLaurent Vivier void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
1640633879fSpbrook {
1650633879fSpbrook     switch (reg) {
1666e22b28eSLaurent Vivier     case M68K_CR_CACR:
16720dcee94Spbrook         env->cacr = val;
16820dcee94Spbrook         m68k_switch_sp(env);
16920dcee94Spbrook         break;
1706e22b28eSLaurent Vivier     case M68K_CR_ACR0:
1716e22b28eSLaurent Vivier     case M68K_CR_ACR1:
1726e22b28eSLaurent Vivier     case M68K_CR_ACR2:
1736e22b28eSLaurent Vivier     case M68K_CR_ACR3:
17420dcee94Spbrook         /* TODO: Implement Access Control Registers.  */
1750633879fSpbrook         break;
1766e22b28eSLaurent Vivier     case M68K_CR_VBR:
1770633879fSpbrook         env->vbr = val;
1780633879fSpbrook         break;
1790633879fSpbrook     /* TODO: Implement control registers.  */
1800633879fSpbrook     default:
181a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env),
1826e22b28eSLaurent Vivier                   "Unimplemented control register write 0x%x = 0x%x\n",
1836e22b28eSLaurent Vivier                   reg, val);
1846e22b28eSLaurent Vivier     }
1856e22b28eSLaurent Vivier }
1866e22b28eSLaurent Vivier 
187*8df0e6aeSLucien Murray-Pitts static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
188*8df0e6aeSLucien Murray-Pitts {
189*8df0e6aeSLucien Murray-Pitts     CPUState *cs = env_cpu(env);
190*8df0e6aeSLucien Murray-Pitts 
191*8df0e6aeSLucien Murray-Pitts     cs->exception_index = tt;
192*8df0e6aeSLucien Murray-Pitts     cpu_loop_exit_restore(cs, raddr);
193*8df0e6aeSLucien Murray-Pitts }
194*8df0e6aeSLucien Murray-Pitts 
1956e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
1966e22b28eSLaurent Vivier {
1976e22b28eSLaurent Vivier     switch (reg) {
19860d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
1995fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
2005fa9f1f2SLaurent Vivier         env->sfc = val & 7;
2015fa9f1f2SLaurent Vivier         return;
20260d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
2035fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
2045fa9f1f2SLaurent Vivier         env->dfc = val & 7;
2055fa9f1f2SLaurent Vivier         return;
20660d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
2076e22b28eSLaurent Vivier     case M68K_CR_VBR:
2086e22b28eSLaurent Vivier         env->vbr = val;
2096e22b28eSLaurent Vivier         return;
21018b6102eSLaurent Vivier     /* MC680[2346]0 */
2116e22b28eSLaurent Vivier     case M68K_CR_CACR:
21218b6102eSLaurent Vivier         if (m68k_feature(env, M68K_FEATURE_M68020)) {
21318b6102eSLaurent Vivier             env->cacr = val & 0x0000000f;
21418b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68030)) {
21518b6102eSLaurent Vivier             env->cacr = val & 0x00003f1f;
21618b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68040)) {
21718b6102eSLaurent Vivier             env->cacr = val & 0x80008000;
21818b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68060)) {
21918b6102eSLaurent Vivier             env->cacr = val & 0xf8e0e000;
220*8df0e6aeSLucien Murray-Pitts         } else {
221*8df0e6aeSLucien Murray-Pitts             break;
22218b6102eSLaurent Vivier         }
2236e22b28eSLaurent Vivier         m68k_switch_sp(env);
2246e22b28eSLaurent Vivier         return;
22560d8e964SLucien Murray-Pitts     /* MC680[46]0 */
22688b2fef6SLaurent Vivier     case M68K_CR_TC:
227*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
228*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
22988b2fef6SLaurent Vivier             env->mmu.tcr = val;
23088b2fef6SLaurent Vivier             return;
231*8df0e6aeSLucien Murray-Pitts         }
232*8df0e6aeSLucien Murray-Pitts         break;
23360d8e964SLucien Murray-Pitts     /* MC68040 */
234e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
235*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
236e55886c3SLaurent Vivier             env->mmu.mmusr = val;
237e55886c3SLaurent Vivier             return;
238*8df0e6aeSLucien Murray-Pitts         }
239*8df0e6aeSLucien Murray-Pitts         break;
24060d8e964SLucien Murray-Pitts     /* MC680[46]0 */
24188b2fef6SLaurent Vivier     case M68K_CR_SRP:
242*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
243*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
24488b2fef6SLaurent Vivier             env->mmu.srp = val;
24588b2fef6SLaurent Vivier             return;
246*8df0e6aeSLucien Murray-Pitts         }
247*8df0e6aeSLucien Murray-Pitts         break;
248*8df0e6aeSLucien Murray-Pitts     /* MC680[46]0 */
24988b2fef6SLaurent Vivier     case M68K_CR_URP:
250*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
251*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
25288b2fef6SLaurent Vivier             env->mmu.urp = val;
25388b2fef6SLaurent Vivier             return;
254*8df0e6aeSLucien Murray-Pitts         }
255*8df0e6aeSLucien Murray-Pitts         break;
256*8df0e6aeSLucien Murray-Pitts     /* MC680[12346]0 */
2576e22b28eSLaurent Vivier     case M68K_CR_USP:
2586e22b28eSLaurent Vivier         env->sp[M68K_USP] = val;
2596e22b28eSLaurent Vivier         return;
26060d8e964SLucien Murray-Pitts     /* MC680[234]0 */
2616e22b28eSLaurent Vivier     case M68K_CR_MSP:
262*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
263*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
264*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)) {
2656e22b28eSLaurent Vivier             env->sp[M68K_SSP] = val;
2666e22b28eSLaurent Vivier             return;
267*8df0e6aeSLucien Murray-Pitts         }
268*8df0e6aeSLucien Murray-Pitts         break;
26960d8e964SLucien Murray-Pitts     /* MC680[234]0 */
2706e22b28eSLaurent Vivier     case M68K_CR_ISP:
271*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
272*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
273*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)) {
2746e22b28eSLaurent Vivier             env->sp[M68K_ISP] = val;
2756e22b28eSLaurent Vivier             return;
276*8df0e6aeSLucien Murray-Pitts         }
277*8df0e6aeSLucien Murray-Pitts         break;
278c05c73b0SLaurent Vivier     /* MC68040/MC68LC040 */
279*8df0e6aeSLucien Murray-Pitts     case M68K_CR_ITT0: /* MC68EC040 only: M68K_CR_IACR0 */
280*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
281c05c73b0SLaurent Vivier             env->mmu.ttr[M68K_ITTR0] = val;
282c05c73b0SLaurent Vivier             return;
283*8df0e6aeSLucien Murray-Pitts         }
284*8df0e6aeSLucien Murray-Pitts         break;
28560d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
286*8df0e6aeSLucien Murray-Pitts     case M68K_CR_ITT1: /* MC68EC040 only: M68K_CR_IACR1 */
287*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
288c05c73b0SLaurent Vivier             env->mmu.ttr[M68K_ITTR1] = val;
289c05c73b0SLaurent Vivier             return;
290*8df0e6aeSLucien Murray-Pitts         }
291*8df0e6aeSLucien Murray-Pitts         break;
29260d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
293*8df0e6aeSLucien Murray-Pitts     case M68K_CR_DTT0: /* MC68EC040 only: M68K_CR_DACR0 */
294*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
295c05c73b0SLaurent Vivier             env->mmu.ttr[M68K_DTTR0] = val;
296c05c73b0SLaurent Vivier             return;
297*8df0e6aeSLucien Murray-Pitts         }
298*8df0e6aeSLucien Murray-Pitts         break;
29960d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
300*8df0e6aeSLucien Murray-Pitts     case M68K_CR_DTT1: /* MC68EC040 only: M68K_CR_DACR1 */
301*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
302c05c73b0SLaurent Vivier             env->mmu.ttr[M68K_DTTR1] = val;
303c05c73b0SLaurent Vivier             return;
304*8df0e6aeSLucien Murray-Pitts         }
305*8df0e6aeSLucien Murray-Pitts         break;
3065736526cSLucien Murray-Pitts     /* Unimplemented Registers */
3075736526cSLucien Murray-Pitts     case M68K_CR_CAAR:
3085736526cSLucien Murray-Pitts     case M68K_CR_PCR:
3095736526cSLucien Murray-Pitts     case M68K_CR_BUSCR:
310a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env),
311a8d92fd8SRichard Henderson                   "Unimplemented control register write 0x%x = 0x%x\n",
3120633879fSpbrook                   reg, val);
3130633879fSpbrook     }
3146e22b28eSLaurent Vivier 
315*8df0e6aeSLucien Murray-Pitts     /* Invalid control registers will generate an exception. */
316*8df0e6aeSLucien Murray-Pitts     raise_exception_ra(env, EXCP_ILLEGAL, 0);
317*8df0e6aeSLucien Murray-Pitts     return;
318*8df0e6aeSLucien Murray-Pitts }
319*8df0e6aeSLucien Murray-Pitts 
3206e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
3216e22b28eSLaurent Vivier {
3226e22b28eSLaurent Vivier     switch (reg) {
32360d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
3245fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
3255fa9f1f2SLaurent Vivier         return env->sfc;
32660d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
3275fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
3285fa9f1f2SLaurent Vivier         return env->dfc;
32960d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
3306e22b28eSLaurent Vivier     case M68K_CR_VBR:
3316e22b28eSLaurent Vivier         return env->vbr;
33260d8e964SLucien Murray-Pitts     /* MC680[2346]0 */
3336e22b28eSLaurent Vivier     case M68K_CR_CACR:
334*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
335*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
336*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)
337*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
3386e22b28eSLaurent Vivier             return env->cacr;
339*8df0e6aeSLucien Murray-Pitts         }
340*8df0e6aeSLucien Murray-Pitts         break;
34160d8e964SLucien Murray-Pitts     /* MC680[46]0 */
34288b2fef6SLaurent Vivier     case M68K_CR_TC:
343*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
344*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
34588b2fef6SLaurent Vivier             return env->mmu.tcr;
346*8df0e6aeSLucien Murray-Pitts         }
347*8df0e6aeSLucien Murray-Pitts         break;
34860d8e964SLucien Murray-Pitts     /* MC68040 */
349e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
350*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
351e55886c3SLaurent Vivier             return env->mmu.mmusr;
352*8df0e6aeSLucien Murray-Pitts         }
353*8df0e6aeSLucien Murray-Pitts         break;
35460d8e964SLucien Murray-Pitts     /* MC680[46]0 */
35588b2fef6SLaurent Vivier     case M68K_CR_SRP:
356*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
357*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
35888b2fef6SLaurent Vivier             return env->mmu.srp;
359*8df0e6aeSLucien Murray-Pitts         }
360*8df0e6aeSLucien Murray-Pitts         break;
361*8df0e6aeSLucien Murray-Pitts     /* MC68040/MC68LC040 */
362*8df0e6aeSLucien Murray-Pitts     case M68K_CR_URP:
363*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
364*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
365*8df0e6aeSLucien Murray-Pitts             return env->mmu.urp;
366*8df0e6aeSLucien Murray-Pitts         }
367*8df0e6aeSLucien Murray-Pitts         break;
36860d8e964SLucien Murray-Pitts     /* MC680[46]0 */
3696e22b28eSLaurent Vivier     case M68K_CR_USP:
3706e22b28eSLaurent Vivier         return env->sp[M68K_USP];
37160d8e964SLucien Murray-Pitts     /* MC680[234]0 */
3726e22b28eSLaurent Vivier     case M68K_CR_MSP:
373*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
374*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
375*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)) {
3766e22b28eSLaurent Vivier             return env->sp[M68K_SSP];
377*8df0e6aeSLucien Murray-Pitts         }
378*8df0e6aeSLucien Murray-Pitts         break;
37960d8e964SLucien Murray-Pitts     /* MC680[234]0 */
3806e22b28eSLaurent Vivier     case M68K_CR_ISP:
381*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
382*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
383*8df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)) {
3846e22b28eSLaurent Vivier             return env->sp[M68K_ISP];
385*8df0e6aeSLucien Murray-Pitts         }
386*8df0e6aeSLucien Murray-Pitts         break;
38760d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
38860d8e964SLucien Murray-Pitts     case M68K_CR_ITT0: /* MC68EC040 only: M68K_CR_IACR0 */
389*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
390c05c73b0SLaurent Vivier             return env->mmu.ttr[M68K_ITTR0];
391*8df0e6aeSLucien Murray-Pitts         }
392*8df0e6aeSLucien Murray-Pitts         break;
39360d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
39460d8e964SLucien Murray-Pitts     case M68K_CR_ITT1: /* MC68EC040 only: M68K_CR_IACR1 */
395*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
396c05c73b0SLaurent Vivier             return env->mmu.ttr[M68K_ITTR1];
397*8df0e6aeSLucien Murray-Pitts         }
398*8df0e6aeSLucien Murray-Pitts         break;
39960d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
40060d8e964SLucien Murray-Pitts     case M68K_CR_DTT0: /* MC68EC040 only: M68K_CR_DACR0 */
401*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
402c05c73b0SLaurent Vivier             return env->mmu.ttr[M68K_DTTR0];
403*8df0e6aeSLucien Murray-Pitts         }
404*8df0e6aeSLucien Murray-Pitts         break;
40560d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
40660d8e964SLucien Murray-Pitts     case M68K_CR_DTT1: /* MC68EC040 only: M68K_CR_DACR1 */
407*8df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
408c05c73b0SLaurent Vivier             return env->mmu.ttr[M68K_DTTR1];
409*8df0e6aeSLucien Murray-Pitts         }
410*8df0e6aeSLucien Murray-Pitts         break;
4115736526cSLucien Murray-Pitts     /* Unimplemented Registers */
4125736526cSLucien Murray-Pitts     case M68K_CR_CAAR:
4135736526cSLucien Murray-Pitts     case M68K_CR_PCR:
4145736526cSLucien Murray-Pitts     case M68K_CR_BUSCR:
415a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n",
4166e22b28eSLaurent Vivier                   reg);
4170633879fSpbrook     }
4180633879fSpbrook 
419*8df0e6aeSLucien Murray-Pitts     /* Invalid control registers will generate an exception. */
420*8df0e6aeSLucien Murray-Pitts     raise_exception_ra(env, EXCP_ILLEGAL, 0);
421*8df0e6aeSLucien Murray-Pitts 
422*8df0e6aeSLucien Murray-Pitts     return 0;
423*8df0e6aeSLucien Murray-Pitts }
424*8df0e6aeSLucien Murray-Pitts 
425e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
426acf930aaSpbrook {
427acf930aaSpbrook     uint32_t acc;
428acf930aaSpbrook     int8_t exthigh;
429acf930aaSpbrook     uint8_t extlow;
430acf930aaSpbrook     uint64_t regval;
431acf930aaSpbrook     int i;
432acf930aaSpbrook     if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
433acf930aaSpbrook         for (i = 0; i < 4; i++) {
434acf930aaSpbrook             regval = env->macc[i];
435acf930aaSpbrook             exthigh = regval >> 40;
436acf930aaSpbrook             if (env->macsr & MACSR_FI) {
437acf930aaSpbrook                 acc = regval >> 8;
438acf930aaSpbrook                 extlow = regval;
439acf930aaSpbrook             } else {
440acf930aaSpbrook                 acc = regval;
441acf930aaSpbrook                 extlow = regval >> 32;
442acf930aaSpbrook             }
443acf930aaSpbrook             if (env->macsr & MACSR_FI) {
444acf930aaSpbrook                 regval = (((uint64_t)acc) << 8) | extlow;
445acf930aaSpbrook                 regval |= ((int64_t)exthigh) << 40;
446acf930aaSpbrook             } else if (env->macsr & MACSR_SU) {
447acf930aaSpbrook                 regval = acc | (((int64_t)extlow) << 32);
448acf930aaSpbrook                 regval |= ((int64_t)exthigh) << 40;
449acf930aaSpbrook             } else {
450acf930aaSpbrook                 regval = acc | (((uint64_t)extlow) << 32);
451acf930aaSpbrook                 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
452acf930aaSpbrook             }
453acf930aaSpbrook             env->macc[i] = regval;
454acf930aaSpbrook         }
455acf930aaSpbrook     }
456acf930aaSpbrook     env->macsr = val;
457acf930aaSpbrook }
458acf930aaSpbrook 
45920dcee94Spbrook void m68k_switch_sp(CPUM68KState *env)
46020dcee94Spbrook {
46120dcee94Spbrook     int new_sp;
46220dcee94Spbrook 
46320dcee94Spbrook     env->sp[env->current_sp] = env->aregs[7];
4646e22b28eSLaurent Vivier     if (m68k_feature(env, M68K_FEATURE_M68000)) {
4656e22b28eSLaurent Vivier         if (env->sr & SR_S) {
4666e22b28eSLaurent Vivier             if (env->sr & SR_M) {
4676e22b28eSLaurent Vivier                 new_sp = M68K_SSP;
4686e22b28eSLaurent Vivier             } else {
4696e22b28eSLaurent Vivier                 new_sp = M68K_ISP;
4706e22b28eSLaurent Vivier             }
4716e22b28eSLaurent Vivier         } else {
4726e22b28eSLaurent Vivier             new_sp = M68K_USP;
4736e22b28eSLaurent Vivier         }
4746e22b28eSLaurent Vivier     } else {
47520dcee94Spbrook         new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
47620dcee94Spbrook                  ? M68K_SSP : M68K_USP;
4776e22b28eSLaurent Vivier     }
47820dcee94Spbrook     env->aregs[7] = env->sp[new_sp];
47920dcee94Spbrook     env->current_sp = new_sp;
48020dcee94Spbrook }
48120dcee94Spbrook 
482fe5f7b1bSRichard Henderson #if !defined(CONFIG_USER_ONLY)
48388b2fef6SLaurent Vivier /* MMU: 68040 only */
4844fcc562bSPaul Brook 
485fad866daSMarkus Armbruster static void print_address_zone(uint32_t logical, uint32_t physical,
4862097dca6SLaurent Vivier                                uint32_t size, int attr)
4872097dca6SLaurent Vivier {
488fad866daSMarkus Armbruster     qemu_printf("%08x - %08x -> %08x - %08x %c ",
4892097dca6SLaurent Vivier                 logical, logical + size - 1,
4902097dca6SLaurent Vivier                 physical, physical + size - 1,
4912097dca6SLaurent Vivier                 attr & 4 ? 'W' : '-');
4922097dca6SLaurent Vivier     size >>= 10;
4932097dca6SLaurent Vivier     if (size < 1024) {
494fad866daSMarkus Armbruster         qemu_printf("(%d KiB)\n", size);
4952097dca6SLaurent Vivier     } else {
4962097dca6SLaurent Vivier         size >>= 10;
4972097dca6SLaurent Vivier         if (size < 1024) {
498fad866daSMarkus Armbruster             qemu_printf("(%d MiB)\n", size);
4992097dca6SLaurent Vivier         } else {
5002097dca6SLaurent Vivier             size >>= 10;
501fad866daSMarkus Armbruster             qemu_printf("(%d GiB)\n", size);
5022097dca6SLaurent Vivier         }
5032097dca6SLaurent Vivier     }
5042097dca6SLaurent Vivier }
5052097dca6SLaurent Vivier 
506fad866daSMarkus Armbruster static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
5072097dca6SLaurent Vivier {
5082097dca6SLaurent Vivier     int i, j, k;
5092097dca6SLaurent Vivier     int tic_size, tic_shift;
5102097dca6SLaurent Vivier     uint32_t tib_mask;
5112097dca6SLaurent Vivier     uint32_t tia, tib, tic;
5122097dca6SLaurent Vivier     uint32_t logical = 0xffffffff, physical = 0xffffffff;
5132097dca6SLaurent Vivier     uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
5142097dca6SLaurent Vivier     uint32_t last_logical, last_physical;
5152097dca6SLaurent Vivier     int32_t size;
5162097dca6SLaurent Vivier     int last_attr = -1, attr = -1;
517a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
518f80b551dSPeter Maydell     MemTxResult txres;
5192097dca6SLaurent Vivier 
5202097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
5212097dca6SLaurent Vivier         /* 8k page */
5222097dca6SLaurent Vivier         tic_size = 32;
5232097dca6SLaurent Vivier         tic_shift = 13;
5242097dca6SLaurent Vivier         tib_mask = M68K_8K_PAGE_MASK;
5252097dca6SLaurent Vivier     } else {
5262097dca6SLaurent Vivier         /* 4k page */
5272097dca6SLaurent Vivier         tic_size = 64;
5282097dca6SLaurent Vivier         tic_shift = 12;
5292097dca6SLaurent Vivier         tib_mask = M68K_4K_PAGE_MASK;
5302097dca6SLaurent Vivier     }
5312097dca6SLaurent Vivier     for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
532f80b551dSPeter Maydell         tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4,
533f80b551dSPeter Maydell                                 MEMTXATTRS_UNSPECIFIED, &txres);
534f80b551dSPeter Maydell         if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) {
5352097dca6SLaurent Vivier             continue;
5362097dca6SLaurent Vivier         }
5372097dca6SLaurent Vivier         for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
538f80b551dSPeter Maydell             tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4,
539f80b551dSPeter Maydell                                     MEMTXATTRS_UNSPECIFIED, &txres);
540f80b551dSPeter Maydell             if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) {
5412097dca6SLaurent Vivier                 continue;
5422097dca6SLaurent Vivier             }
5432097dca6SLaurent Vivier             for (k = 0; k < tic_size; k++) {
544f80b551dSPeter Maydell                 tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4,
545f80b551dSPeter Maydell                                         MEMTXATTRS_UNSPECIFIED, &txres);
546f80b551dSPeter Maydell                 if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) {
5472097dca6SLaurent Vivier                     continue;
5482097dca6SLaurent Vivier                 }
5492097dca6SLaurent Vivier                 if (M68K_PDT_INDIRECT(tic)) {
550f80b551dSPeter Maydell                     tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic),
551f80b551dSPeter Maydell                                             MEMTXATTRS_UNSPECIFIED, &txres);
552f80b551dSPeter Maydell                     if (txres != MEMTX_OK) {
553f80b551dSPeter Maydell                         continue;
554f80b551dSPeter Maydell                     }
5552097dca6SLaurent Vivier                 }
5562097dca6SLaurent Vivier 
5572097dca6SLaurent Vivier                 last_logical = logical;
5582097dca6SLaurent Vivier                 logical = (i << M68K_TTS_ROOT_SHIFT) |
5592097dca6SLaurent Vivier                           (j << M68K_TTS_POINTER_SHIFT) |
5602097dca6SLaurent Vivier                           (k << tic_shift);
5612097dca6SLaurent Vivier 
5622097dca6SLaurent Vivier                 last_physical = physical;
5632097dca6SLaurent Vivier                 physical = tic & ~((1 << tic_shift) - 1);
5642097dca6SLaurent Vivier 
5652097dca6SLaurent Vivier                 last_attr = attr;
5662097dca6SLaurent Vivier                 attr = tic & ((1 << tic_shift) - 1);
5672097dca6SLaurent Vivier 
5682097dca6SLaurent Vivier                 if ((logical != (last_logical + (1 << tic_shift))) ||
5692097dca6SLaurent Vivier                     (physical != (last_physical + (1 << tic_shift))) ||
5702097dca6SLaurent Vivier                     (attr & 4) != (last_attr & 4)) {
5712097dca6SLaurent Vivier 
5722097dca6SLaurent Vivier                     if (first_logical != 0xffffffff) {
5732097dca6SLaurent Vivier                         size = last_logical + (1 << tic_shift) -
5742097dca6SLaurent Vivier                                first_logical;
575fad866daSMarkus Armbruster                         print_address_zone(first_logical,
5762097dca6SLaurent Vivier                                            first_physical, size, last_attr);
5772097dca6SLaurent Vivier                     }
5782097dca6SLaurent Vivier                     first_logical = logical;
5792097dca6SLaurent Vivier                     first_physical = physical;
5802097dca6SLaurent Vivier                 }
5812097dca6SLaurent Vivier             }
5822097dca6SLaurent Vivier         }
5832097dca6SLaurent Vivier     }
5842097dca6SLaurent Vivier     if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
5852097dca6SLaurent Vivier         size = logical + (1 << tic_shift) - first_logical;
586fad866daSMarkus Armbruster         print_address_zone(first_logical, first_physical, size, last_attr);
5872097dca6SLaurent Vivier     }
5882097dca6SLaurent Vivier }
5892097dca6SLaurent Vivier 
5902097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \
5912097dca6SLaurent Vivier     switch (a & M68K_DESC_CACHEMODE) { \
5922097dca6SLaurent Vivier     case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
593fad866daSMarkus Armbruster         qemu_printf("T"); \
5942097dca6SLaurent Vivier         break; \
5952097dca6SLaurent Vivier     case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
596fad866daSMarkus Armbruster         qemu_printf("C"); \
5972097dca6SLaurent Vivier         break; \
5982097dca6SLaurent Vivier     case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
599fad866daSMarkus Armbruster         qemu_printf("S"); \
6002097dca6SLaurent Vivier         break; \
6012097dca6SLaurent Vivier     case M68K_DESC_CM_NCACHE: /* noncachable */ \
602fad866daSMarkus Armbruster         qemu_printf("N"); \
6032097dca6SLaurent Vivier         break; \
6042097dca6SLaurent Vivier     }
6052097dca6SLaurent Vivier 
606fad866daSMarkus Armbruster static void dump_ttr(uint32_t ttr)
6072097dca6SLaurent Vivier {
6082097dca6SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
609fad866daSMarkus Armbruster         qemu_printf("disabled\n");
6102097dca6SLaurent Vivier         return;
6112097dca6SLaurent Vivier     }
612fad866daSMarkus Armbruster     qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ",
6132097dca6SLaurent Vivier                 ttr & M68K_TTR_ADDR_BASE,
6142097dca6SLaurent Vivier                 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
6152097dca6SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
6162097dca6SLaurent Vivier     case M68K_TTR_SFIELD_USER:
617fad866daSMarkus Armbruster         qemu_printf("U");
6182097dca6SLaurent Vivier         break;
6192097dca6SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
620fad866daSMarkus Armbruster         qemu_printf("S");
6212097dca6SLaurent Vivier         break;
6222097dca6SLaurent Vivier     default:
623fad866daSMarkus Armbruster         qemu_printf("*");
6242097dca6SLaurent Vivier         break;
6252097dca6SLaurent Vivier     }
6262097dca6SLaurent Vivier     DUMP_CACHEFLAGS(ttr);
6272097dca6SLaurent Vivier     if (ttr & M68K_DESC_WRITEPROT) {
628fad866daSMarkus Armbruster         qemu_printf("R");
6292097dca6SLaurent Vivier     } else {
630fad866daSMarkus Armbruster         qemu_printf("W");
6312097dca6SLaurent Vivier     }
632fad866daSMarkus Armbruster     qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >>
6332097dca6SLaurent Vivier                                M68K_DESC_USERATTR_SHIFT);
6342097dca6SLaurent Vivier }
6352097dca6SLaurent Vivier 
636fad866daSMarkus Armbruster void dump_mmu(CPUM68KState *env)
6372097dca6SLaurent Vivier {
6382097dca6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
639fad866daSMarkus Armbruster         qemu_printf("Translation disabled\n");
6402097dca6SLaurent Vivier         return;
6412097dca6SLaurent Vivier     }
642fad866daSMarkus Armbruster     qemu_printf("Page Size: ");
6432097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
644fad866daSMarkus Armbruster         qemu_printf("8kB\n");
6452097dca6SLaurent Vivier     } else {
646fad866daSMarkus Armbruster         qemu_printf("4kB\n");
6472097dca6SLaurent Vivier     }
6482097dca6SLaurent Vivier 
649fad866daSMarkus Armbruster     qemu_printf("MMUSR: ");
6502097dca6SLaurent Vivier     if (env->mmu.mmusr & M68K_MMU_B_040) {
651fad866daSMarkus Armbruster         qemu_printf("BUS ERROR\n");
6522097dca6SLaurent Vivier     } else {
653fad866daSMarkus Armbruster         qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
6542097dca6SLaurent Vivier         /* flags found on the page descriptor */
6552097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_G_040) {
656fad866daSMarkus Armbruster             qemu_printf("G"); /* Global */
6572097dca6SLaurent Vivier         } else {
658fad866daSMarkus Armbruster             qemu_printf(".");
6592097dca6SLaurent Vivier         }
6602097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_S_040) {
661fad866daSMarkus Armbruster             qemu_printf("S"); /* Supervisor */
6622097dca6SLaurent Vivier         } else {
663fad866daSMarkus Armbruster             qemu_printf(".");
6642097dca6SLaurent Vivier         }
6652097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_M_040) {
666fad866daSMarkus Armbruster             qemu_printf("M"); /* Modified */
6672097dca6SLaurent Vivier         } else {
668fad866daSMarkus Armbruster             qemu_printf(".");
6692097dca6SLaurent Vivier         }
6702097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_WP_040) {
671fad866daSMarkus Armbruster             qemu_printf("W"); /* Write protect */
6722097dca6SLaurent Vivier         } else {
673fad866daSMarkus Armbruster             qemu_printf(".");
6742097dca6SLaurent Vivier         }
6752097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_T_040) {
676fad866daSMarkus Armbruster             qemu_printf("T"); /* Transparent */
6772097dca6SLaurent Vivier         } else {
678fad866daSMarkus Armbruster             qemu_printf(".");
6792097dca6SLaurent Vivier         }
6802097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_R_040) {
681fad866daSMarkus Armbruster             qemu_printf("R"); /* Resident */
6822097dca6SLaurent Vivier         } else {
683fad866daSMarkus Armbruster             qemu_printf(".");
6842097dca6SLaurent Vivier         }
685fad866daSMarkus Armbruster         qemu_printf(" Cache: ");
6862097dca6SLaurent Vivier         DUMP_CACHEFLAGS(env->mmu.mmusr);
687fad866daSMarkus Armbruster         qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3);
688fad866daSMarkus Armbruster         qemu_printf("\n");
6892097dca6SLaurent Vivier     }
6902097dca6SLaurent Vivier 
691fad866daSMarkus Armbruster     qemu_printf("ITTR0: ");
692fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_ITTR0]);
693fad866daSMarkus Armbruster     qemu_printf("ITTR1: ");
694fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_ITTR1]);
695fad866daSMarkus Armbruster     qemu_printf("DTTR0: ");
696fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_DTTR0]);
697fad866daSMarkus Armbruster     qemu_printf("DTTR1: ");
698fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_DTTR1]);
6992097dca6SLaurent Vivier 
700fad866daSMarkus Armbruster     qemu_printf("SRP: 0x%08x\n", env->mmu.srp);
701fad866daSMarkus Armbruster     dump_address_map(env, env->mmu.srp);
7022097dca6SLaurent Vivier 
703fad866daSMarkus Armbruster     qemu_printf("URP: 0x%08x\n", env->mmu.urp);
704fad866daSMarkus Armbruster     dump_address_map(env, env->mmu.urp);
7052097dca6SLaurent Vivier }
7062097dca6SLaurent Vivier 
707c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
708c05c73b0SLaurent Vivier                      int access_type)
709c05c73b0SLaurent Vivier {
710c05c73b0SLaurent Vivier     uint32_t base, mask;
711c05c73b0SLaurent Vivier 
712c05c73b0SLaurent Vivier     /* check if transparent translation is enabled */
713c05c73b0SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
714c05c73b0SLaurent Vivier         return 0;
715c05c73b0SLaurent Vivier     }
716c05c73b0SLaurent Vivier 
717c05c73b0SLaurent Vivier     /* check mode access */
718c05c73b0SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
719c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_USER:
720c05c73b0SLaurent Vivier         /* match only if user */
721c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) != 0) {
722c05c73b0SLaurent Vivier             return 0;
723c05c73b0SLaurent Vivier         }
724c05c73b0SLaurent Vivier         break;
725c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
726c05c73b0SLaurent Vivier         /* match only if supervisor */
727c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
728c05c73b0SLaurent Vivier             return 0;
729c05c73b0SLaurent Vivier         }
730c05c73b0SLaurent Vivier         break;
731c05c73b0SLaurent Vivier     default:
732c05c73b0SLaurent Vivier         /* all other values disable mode matching (FC2) */
733c05c73b0SLaurent Vivier         break;
734c05c73b0SLaurent Vivier     }
735c05c73b0SLaurent Vivier 
736c05c73b0SLaurent Vivier     /* check address matching */
737c05c73b0SLaurent Vivier 
738c05c73b0SLaurent Vivier     base = ttr & M68K_TTR_ADDR_BASE;
739c05c73b0SLaurent Vivier     mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
740c05c73b0SLaurent Vivier     mask <<= M68K_TTR_ADDR_MASK_SHIFT;
741c05c73b0SLaurent Vivier 
742c05c73b0SLaurent Vivier     if ((addr & mask) != (base & mask)) {
743c05c73b0SLaurent Vivier         return 0;
744c05c73b0SLaurent Vivier     }
745c05c73b0SLaurent Vivier 
746c05c73b0SLaurent Vivier     *prot = PAGE_READ | PAGE_EXEC;
747c05c73b0SLaurent Vivier     if ((ttr & M68K_DESC_WRITEPROT) == 0) {
748c05c73b0SLaurent Vivier         *prot |= PAGE_WRITE;
749c05c73b0SLaurent Vivier     }
750c05c73b0SLaurent Vivier 
751c05c73b0SLaurent Vivier     return 1;
752c05c73b0SLaurent Vivier }
753c05c73b0SLaurent Vivier 
75488b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical,
75588b2fef6SLaurent Vivier                                 int *prot, target_ulong address,
75688b2fef6SLaurent Vivier                                 int access_type, target_ulong *page_size)
75788b2fef6SLaurent Vivier {
758a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
75988b2fef6SLaurent Vivier     uint32_t entry;
76088b2fef6SLaurent Vivier     uint32_t next;
76188b2fef6SLaurent Vivier     target_ulong page_mask;
76288b2fef6SLaurent Vivier     bool debug = access_type & ACCESS_DEBUG;
76388b2fef6SLaurent Vivier     int page_bits;
764c05c73b0SLaurent Vivier     int i;
765adcf0bf0SPeter Maydell     MemTxResult txres;
766c05c73b0SLaurent Vivier 
767c05c73b0SLaurent Vivier     /* Transparent Translation (physical = logical) */
768c05c73b0SLaurent Vivier     for (i = 0; i < M68K_MAX_TTR; i++) {
769c05c73b0SLaurent Vivier         if (check_TTR(env->mmu.TTR(access_type, i),
770c05c73b0SLaurent Vivier                       prot, address, access_type)) {
771e55886c3SLaurent Vivier             if (access_type & ACCESS_PTEST) {
772e55886c3SLaurent Vivier                 /* Transparent Translation Register bit */
773e55886c3SLaurent Vivier                 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
774e55886c3SLaurent Vivier             }
775852002b5SMark Cave-Ayland             *physical = address;
776c05c73b0SLaurent Vivier             *page_size = TARGET_PAGE_SIZE;
777c05c73b0SLaurent Vivier             return 0;
778c05c73b0SLaurent Vivier         }
779c05c73b0SLaurent Vivier     }
78088b2fef6SLaurent Vivier 
78188b2fef6SLaurent Vivier     /* Page Table Root Pointer */
78288b2fef6SLaurent Vivier     *prot = PAGE_READ | PAGE_WRITE;
78388b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
78488b2fef6SLaurent Vivier         *prot |= PAGE_EXEC;
78588b2fef6SLaurent Vivier     }
78688b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
78788b2fef6SLaurent Vivier         next = env->mmu.srp;
78888b2fef6SLaurent Vivier     } else {
78988b2fef6SLaurent Vivier         next = env->mmu.urp;
79088b2fef6SLaurent Vivier     }
79188b2fef6SLaurent Vivier 
79288b2fef6SLaurent Vivier     /* Root Index */
79388b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
79488b2fef6SLaurent Vivier 
795adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
796adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
797adcf0bf0SPeter Maydell         goto txfail;
798adcf0bf0SPeter Maydell     }
79988b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
80088b2fef6SLaurent Vivier         return -1;
80188b2fef6SLaurent Vivier     }
80288b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
803adcf0bf0SPeter Maydell         address_space_stl(cs->as, entry, next | M68K_DESC_USED,
804adcf0bf0SPeter Maydell                           MEMTXATTRS_UNSPECIFIED, &txres);
805adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
806adcf0bf0SPeter Maydell             goto txfail;
807adcf0bf0SPeter Maydell         }
80888b2fef6SLaurent Vivier     }
80988b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
810e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
811e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
812e55886c3SLaurent Vivier         }
81388b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
81488b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
81588b2fef6SLaurent Vivier             return -1;
81688b2fef6SLaurent Vivier         }
81788b2fef6SLaurent Vivier     }
81888b2fef6SLaurent Vivier 
81988b2fef6SLaurent Vivier     /* Pointer Index */
82088b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
82188b2fef6SLaurent Vivier 
822adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
823adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
824adcf0bf0SPeter Maydell         goto txfail;
825adcf0bf0SPeter Maydell     }
82688b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
82788b2fef6SLaurent Vivier         return -1;
82888b2fef6SLaurent Vivier     }
82988b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
830adcf0bf0SPeter Maydell         address_space_stl(cs->as, entry, next | M68K_DESC_USED,
831adcf0bf0SPeter Maydell                           MEMTXATTRS_UNSPECIFIED, &txres);
832adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
833adcf0bf0SPeter Maydell             goto txfail;
834adcf0bf0SPeter Maydell         }
83588b2fef6SLaurent Vivier     }
83688b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
837e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
838e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
839e55886c3SLaurent Vivier         }
84088b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
84188b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
84288b2fef6SLaurent Vivier             return -1;
84388b2fef6SLaurent Vivier         }
84488b2fef6SLaurent Vivier     }
84588b2fef6SLaurent Vivier 
84688b2fef6SLaurent Vivier     /* Page Index */
84788b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
84888b2fef6SLaurent Vivier         entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
84988b2fef6SLaurent Vivier     } else {
85088b2fef6SLaurent Vivier         entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
85188b2fef6SLaurent Vivier     }
85288b2fef6SLaurent Vivier 
853adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
854adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
855adcf0bf0SPeter Maydell         goto txfail;
856adcf0bf0SPeter Maydell     }
85788b2fef6SLaurent Vivier 
85888b2fef6SLaurent Vivier     if (!M68K_PDT_VALID(next)) {
85988b2fef6SLaurent Vivier         return -1;
86088b2fef6SLaurent Vivier     }
86188b2fef6SLaurent Vivier     if (M68K_PDT_INDIRECT(next)) {
862adcf0bf0SPeter Maydell         next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next),
863adcf0bf0SPeter Maydell                                  MEMTXATTRS_UNSPECIFIED, &txres);
864adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
865adcf0bf0SPeter Maydell             goto txfail;
866adcf0bf0SPeter Maydell         }
86788b2fef6SLaurent Vivier     }
86888b2fef6SLaurent Vivier     if (access_type & ACCESS_STORE) {
86988b2fef6SLaurent Vivier         if (next & M68K_DESC_WRITEPROT) {
87088b2fef6SLaurent Vivier             if (!(next & M68K_DESC_USED) && !debug) {
871adcf0bf0SPeter Maydell                 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
872adcf0bf0SPeter Maydell                                   MEMTXATTRS_UNSPECIFIED, &txres);
873adcf0bf0SPeter Maydell                 if (txres != MEMTX_OK) {
874adcf0bf0SPeter Maydell                     goto txfail;
875adcf0bf0SPeter Maydell                 }
87688b2fef6SLaurent Vivier             }
87788b2fef6SLaurent Vivier         } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
87888b2fef6SLaurent Vivier                            (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
879adcf0bf0SPeter Maydell             address_space_stl(cs->as, entry,
880adcf0bf0SPeter Maydell                               next | (M68K_DESC_MODIFIED | M68K_DESC_USED),
881adcf0bf0SPeter Maydell                               MEMTXATTRS_UNSPECIFIED, &txres);
882adcf0bf0SPeter Maydell             if (txres != MEMTX_OK) {
883adcf0bf0SPeter Maydell                 goto txfail;
884adcf0bf0SPeter Maydell             }
88588b2fef6SLaurent Vivier         }
88688b2fef6SLaurent Vivier     } else {
88788b2fef6SLaurent Vivier         if (!(next & M68K_DESC_USED) && !debug) {
888adcf0bf0SPeter Maydell             address_space_stl(cs->as, entry, next | M68K_DESC_USED,
889adcf0bf0SPeter Maydell                               MEMTXATTRS_UNSPECIFIED, &txres);
890adcf0bf0SPeter Maydell             if (txres != MEMTX_OK) {
891adcf0bf0SPeter Maydell                 goto txfail;
892adcf0bf0SPeter Maydell             }
89388b2fef6SLaurent Vivier         }
89488b2fef6SLaurent Vivier     }
89588b2fef6SLaurent Vivier 
89688b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
89788b2fef6SLaurent Vivier         page_bits = 13;
89888b2fef6SLaurent Vivier     } else {
89988b2fef6SLaurent Vivier         page_bits = 12;
90088b2fef6SLaurent Vivier     }
90188b2fef6SLaurent Vivier     *page_size = 1 << page_bits;
90288b2fef6SLaurent Vivier     page_mask = ~(*page_size - 1);
903852002b5SMark Cave-Ayland     *physical = (next & page_mask) + (address & (*page_size - 1));
90488b2fef6SLaurent Vivier 
905e55886c3SLaurent Vivier     if (access_type & ACCESS_PTEST) {
906e55886c3SLaurent Vivier         env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
907e55886c3SLaurent Vivier         env->mmu.mmusr |= *physical & 0xfffff000;
908e55886c3SLaurent Vivier         env->mmu.mmusr |= M68K_MMU_R_040;
909e55886c3SLaurent Vivier     }
910e55886c3SLaurent Vivier 
91188b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
91288b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
91388b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
91488b2fef6SLaurent Vivier             return -1;
91588b2fef6SLaurent Vivier         }
91688b2fef6SLaurent Vivier     }
91788b2fef6SLaurent Vivier     if (next & M68K_DESC_SUPERONLY) {
91888b2fef6SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
91988b2fef6SLaurent Vivier             return -1;
92088b2fef6SLaurent Vivier         }
92188b2fef6SLaurent Vivier     }
92288b2fef6SLaurent Vivier 
92388b2fef6SLaurent Vivier     return 0;
924adcf0bf0SPeter Maydell 
925adcf0bf0SPeter Maydell txfail:
926adcf0bf0SPeter Maydell     /*
927adcf0bf0SPeter Maydell      * A page table load/store failed. TODO: we should really raise a
928adcf0bf0SPeter Maydell      * suitable guest fault here if this is not a debug access.
929adcf0bf0SPeter Maydell      * For now just return that the translation failed.
930adcf0bf0SPeter Maydell      */
931adcf0bf0SPeter Maydell     return -1;
93288b2fef6SLaurent Vivier }
93388b2fef6SLaurent Vivier 
93400b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
9354fcc562bSPaul Brook {
93688b2fef6SLaurent Vivier     M68kCPU *cpu = M68K_CPU(cs);
93788b2fef6SLaurent Vivier     CPUM68KState *env = &cpu->env;
93888b2fef6SLaurent Vivier     hwaddr phys_addr;
93988b2fef6SLaurent Vivier     int prot;
94088b2fef6SLaurent Vivier     int access_type;
94188b2fef6SLaurent Vivier     target_ulong page_size;
94288b2fef6SLaurent Vivier 
94388b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
94488b2fef6SLaurent Vivier         /* MMU disabled */
9454fcc562bSPaul Brook         return addr;
9464fcc562bSPaul Brook     }
9474fcc562bSPaul Brook 
94888b2fef6SLaurent Vivier     access_type = ACCESS_DATA | ACCESS_DEBUG;
94988b2fef6SLaurent Vivier     if (env->sr & SR_S) {
95088b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
95188b2fef6SLaurent Vivier     }
95278318119SMark Cave-Ayland 
95388b2fef6SLaurent Vivier     if (get_physical_address(env, &phys_addr, &prot,
95488b2fef6SLaurent Vivier                              addr, access_type, &page_size) != 0) {
95588b2fef6SLaurent Vivier         return -1;
95688b2fef6SLaurent Vivier     }
95778318119SMark Cave-Ayland 
95888b2fef6SLaurent Vivier     return phys_addr;
95988b2fef6SLaurent Vivier }
96088b2fef6SLaurent Vivier 
961fe5f7b1bSRichard Henderson /*
962fe5f7b1bSRichard Henderson  * Notify CPU of a pending interrupt.  Prioritization and vectoring should
963fe5f7b1bSRichard Henderson  * be handled by the interrupt controller.  Real hardware only requests
964fe5f7b1bSRichard Henderson  * the vector when the interrupt is acknowledged by the CPU.  For
965fe5f7b1bSRichard Henderson  * simplicity we calculate it when the interrupt is signalled.
966fe5f7b1bSRichard Henderson  */
967fe5f7b1bSRichard Henderson void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
968fe5f7b1bSRichard Henderson {
969fe5f7b1bSRichard Henderson     CPUState *cs = CPU(cpu);
970fe5f7b1bSRichard Henderson     CPUM68KState *env = &cpu->env;
971fe5f7b1bSRichard Henderson 
972fe5f7b1bSRichard Henderson     env->pending_level = level;
973fe5f7b1bSRichard Henderson     env->pending_vector = vector;
974fe5f7b1bSRichard Henderson     if (level) {
975fe5f7b1bSRichard Henderson         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
976fe5f7b1bSRichard Henderson     } else {
977fe5f7b1bSRichard Henderson         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
978fe5f7b1bSRichard Henderson     }
979fe5f7b1bSRichard Henderson }
980fe5f7b1bSRichard Henderson 
981fe5f7b1bSRichard Henderson #endif
982fe5f7b1bSRichard Henderson 
983fe5f7b1bSRichard Henderson bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
984fe5f7b1bSRichard Henderson                        MMUAccessType qemu_access_type, int mmu_idx,
985fe5f7b1bSRichard Henderson                        bool probe, uintptr_t retaddr)
9860633879fSpbrook {
98788b2fef6SLaurent Vivier     M68kCPU *cpu = M68K_CPU(cs);
98888b2fef6SLaurent Vivier     CPUM68KState *env = &cpu->env;
989fe5f7b1bSRichard Henderson 
990fe5f7b1bSRichard Henderson #ifndef CONFIG_USER_ONLY
99188b2fef6SLaurent Vivier     hwaddr physical;
9920633879fSpbrook     int prot;
99388b2fef6SLaurent Vivier     int access_type;
99488b2fef6SLaurent Vivier     int ret;
99588b2fef6SLaurent Vivier     target_ulong page_size;
9960633879fSpbrook 
99788b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
99888b2fef6SLaurent Vivier         /* MMU disabled */
99988b2fef6SLaurent Vivier         tlb_set_page(cs, address & TARGET_PAGE_MASK,
100088b2fef6SLaurent Vivier                      address & TARGET_PAGE_MASK,
100188b2fef6SLaurent Vivier                      PAGE_READ | PAGE_WRITE | PAGE_EXEC,
100288b2fef6SLaurent Vivier                      mmu_idx, TARGET_PAGE_SIZE);
1003fe5f7b1bSRichard Henderson         return true;
10040633879fSpbrook     }
10050633879fSpbrook 
1006fe5f7b1bSRichard Henderson     if (qemu_access_type == MMU_INST_FETCH) {
100788b2fef6SLaurent Vivier         access_type = ACCESS_CODE;
100888b2fef6SLaurent Vivier     } else {
100988b2fef6SLaurent Vivier         access_type = ACCESS_DATA;
1010fe5f7b1bSRichard Henderson         if (qemu_access_type == MMU_DATA_STORE) {
101188b2fef6SLaurent Vivier             access_type |= ACCESS_STORE;
101288b2fef6SLaurent Vivier         }
101388b2fef6SLaurent Vivier     }
101488b2fef6SLaurent Vivier     if (mmu_idx != MMU_USER_IDX) {
101588b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
101688b2fef6SLaurent Vivier     }
101788b2fef6SLaurent Vivier 
101888b2fef6SLaurent Vivier     ret = get_physical_address(&cpu->env, &physical, &prot,
101988b2fef6SLaurent Vivier                                address, access_type, &page_size);
1020fe5f7b1bSRichard Henderson     if (likely(ret == 0)) {
1021852002b5SMark Cave-Ayland         tlb_set_page(cs, address & TARGET_PAGE_MASK,
1022852002b5SMark Cave-Ayland                      physical & TARGET_PAGE_MASK, prot, mmu_idx, page_size);
1023fe5f7b1bSRichard Henderson         return true;
102488b2fef6SLaurent Vivier     }
1025fe5f7b1bSRichard Henderson 
1026fe5f7b1bSRichard Henderson     if (probe) {
1027fe5f7b1bSRichard Henderson         return false;
1028fe5f7b1bSRichard Henderson     }
1029fe5f7b1bSRichard Henderson 
103088b2fef6SLaurent Vivier     /* page fault */
103188b2fef6SLaurent Vivier     env->mmu.ssw = M68K_ATC_040;
103288b2fef6SLaurent Vivier     switch (size) {
103388b2fef6SLaurent Vivier     case 1:
103488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_BYTE;
103588b2fef6SLaurent Vivier         break;
103688b2fef6SLaurent Vivier     case 2:
103788b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_WORD;
103888b2fef6SLaurent Vivier         break;
103988b2fef6SLaurent Vivier     case 4:
104088b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_LONG;
104188b2fef6SLaurent Vivier         break;
104288b2fef6SLaurent Vivier     }
104388b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
104488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_SUPER;
104588b2fef6SLaurent Vivier     }
104688b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
104788b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_CODE;
104888b2fef6SLaurent Vivier     } else {
104988b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_DATA;
105088b2fef6SLaurent Vivier     }
105188b2fef6SLaurent Vivier     if (!(access_type & ACCESS_STORE)) {
105288b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_RW_040;
105388b2fef6SLaurent Vivier     }
1054fe5f7b1bSRichard Henderson #endif
1055fe5f7b1bSRichard Henderson 
105688b2fef6SLaurent Vivier     cs->exception_index = EXCP_ACCESS;
1057fe5f7b1bSRichard Henderson     env->mmu.ar = address;
1058fe5f7b1bSRichard Henderson     cpu_loop_exit_restore(cs, retaddr);
105988b2fef6SLaurent Vivier }
106088b2fef6SLaurent Vivier 
1061e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x)
1062e1f3808eSpbrook {
1063e1f3808eSpbrook     x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
1064e1f3808eSpbrook     x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
1065e1f3808eSpbrook     x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
1066e1f3808eSpbrook     return bswap32(x);
1067e1f3808eSpbrook }
1068e1f3808eSpbrook 
1069e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x)
1070e1f3808eSpbrook {
1071e1f3808eSpbrook     int n;
1072e1f3808eSpbrook     for (n = 32; x; n--)
1073e1f3808eSpbrook         x >>= 1;
1074e1f3808eSpbrook     return n;
1075e1f3808eSpbrook }
1076e1f3808eSpbrook 
1077620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v)
1078e1f3808eSpbrook {
1079e1f3808eSpbrook     /* The result has the opposite sign to the original value.  */
1080620c6cf6SRichard Henderson     if ((int32_t)v < 0) {
1081e1f3808eSpbrook         val = (((int32_t)val) >> 31) ^ SIGNBIT;
1082620c6cf6SRichard Henderson     }
1083e1f3808eSpbrook     return val;
1084e1f3808eSpbrook }
1085e1f3808eSpbrook 
1086d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
1087e1f3808eSpbrook {
1088d2f8fb8eSLaurent Vivier     env->sr = sr & 0xffe0;
1089d2f8fb8eSLaurent Vivier     cpu_m68k_set_ccr(env, sr);
1090e1f3808eSpbrook     m68k_switch_sp(env);
1091e1f3808eSpbrook }
1092e1f3808eSpbrook 
1093d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
1094d2f8fb8eSLaurent Vivier {
1095d2f8fb8eSLaurent Vivier     cpu_m68k_set_sr(env, val);
1096d2f8fb8eSLaurent Vivier }
1097e1f3808eSpbrook 
1098e1f3808eSpbrook /* MAC unit.  */
1099808d77bcSLucien Murray-Pitts /*
1100808d77bcSLucien Murray-Pitts  * FIXME: The MAC unit implementation is a bit of a mess.  Some helpers
1101808d77bcSLucien Murray-Pitts  * take values,  others take register numbers and manipulate the contents
1102808d77bcSLucien Murray-Pitts  * in-place.
1103808d77bcSLucien Murray-Pitts  */
11042b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
1105e1f3808eSpbrook {
1106e1f3808eSpbrook     uint32_t mask;
1107e1f3808eSpbrook     env->macc[dest] = env->macc[src];
1108e1f3808eSpbrook     mask = MACSR_PAV0 << dest;
1109e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << src))
1110e1f3808eSpbrook         env->macsr |= mask;
1111e1f3808eSpbrook     else
1112e1f3808eSpbrook         env->macsr &= ~mask;
1113e1f3808eSpbrook }
1114e1f3808eSpbrook 
11152b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1116e1f3808eSpbrook {
1117e1f3808eSpbrook     int64_t product;
1118e1f3808eSpbrook     int64_t res;
1119e1f3808eSpbrook 
1120e1f3808eSpbrook     product = (uint64_t)op1 * op2;
1121e1f3808eSpbrook     res = (product << 24) >> 24;
1122e1f3808eSpbrook     if (res != product) {
1123e1f3808eSpbrook         env->macsr |= MACSR_V;
1124e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1125e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
1126e1f3808eSpbrook             if (product < 0)
1127e1f3808eSpbrook                 res = ~(1ll << 50);
1128e1f3808eSpbrook             else
1129e1f3808eSpbrook                 res = 1ll << 50;
1130e1f3808eSpbrook         }
1131e1f3808eSpbrook     }
1132e1f3808eSpbrook     return res;
1133e1f3808eSpbrook }
1134e1f3808eSpbrook 
11352b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1136e1f3808eSpbrook {
1137e1f3808eSpbrook     uint64_t product;
1138e1f3808eSpbrook 
1139e1f3808eSpbrook     product = (uint64_t)op1 * op2;
1140e1f3808eSpbrook     if (product & (0xffffffull << 40)) {
1141e1f3808eSpbrook         env->macsr |= MACSR_V;
1142e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1143e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
1144e1f3808eSpbrook             product = 1ll << 50;
1145e1f3808eSpbrook         } else {
1146e1f3808eSpbrook             product &= ((1ull << 40) - 1);
1147e1f3808eSpbrook         }
1148e1f3808eSpbrook     }
1149e1f3808eSpbrook     return product;
1150e1f3808eSpbrook }
1151e1f3808eSpbrook 
11522b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1153e1f3808eSpbrook {
1154e1f3808eSpbrook     uint64_t product;
1155e1f3808eSpbrook     uint32_t remainder;
1156e1f3808eSpbrook 
1157e1f3808eSpbrook     product = (uint64_t)op1 * op2;
1158e1f3808eSpbrook     if (env->macsr & MACSR_RT) {
1159e1f3808eSpbrook         remainder = product & 0xffffff;
1160e1f3808eSpbrook         product >>= 24;
1161e1f3808eSpbrook         if (remainder > 0x800000)
1162e1f3808eSpbrook             product++;
1163e1f3808eSpbrook         else if (remainder == 0x800000)
1164e1f3808eSpbrook             product += (product & 1);
1165e1f3808eSpbrook     } else {
1166e1f3808eSpbrook         product >>= 24;
1167e1f3808eSpbrook     }
1168e1f3808eSpbrook     return product;
1169e1f3808eSpbrook }
1170e1f3808eSpbrook 
11712b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
1172e1f3808eSpbrook {
1173e1f3808eSpbrook     int64_t tmp;
1174e1f3808eSpbrook     int64_t result;
1175e1f3808eSpbrook     tmp = env->macc[acc];
1176e1f3808eSpbrook     result = ((tmp << 16) >> 16);
1177e1f3808eSpbrook     if (result != tmp) {
1178e1f3808eSpbrook         env->macsr |= MACSR_V;
1179e1f3808eSpbrook     }
1180e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1181e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1182e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1183808d77bcSLucien Murray-Pitts             /*
1184808d77bcSLucien Murray-Pitts              * The result is saturated to 32 bits, despite overflow occurring
1185808d77bcSLucien Murray-Pitts              * at 48 bits.  Seems weird, but that's what the hardware docs
1186808d77bcSLucien Murray-Pitts              * say.
1187808d77bcSLucien Murray-Pitts              */
1188e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffff;
1189e1f3808eSpbrook         }
1190e1f3808eSpbrook     }
1191e1f3808eSpbrook     env->macc[acc] = result;
1192e1f3808eSpbrook }
1193e1f3808eSpbrook 
11942b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1195e1f3808eSpbrook {
1196e1f3808eSpbrook     uint64_t val;
1197e1f3808eSpbrook 
1198e1f3808eSpbrook     val = env->macc[acc];
1199e1f3808eSpbrook     if (val & (0xffffull << 48)) {
1200e1f3808eSpbrook         env->macsr |= MACSR_V;
1201e1f3808eSpbrook     }
1202e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1203e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1204e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1205e1f3808eSpbrook             if (val > (1ull << 53))
1206e1f3808eSpbrook                 val = 0;
1207e1f3808eSpbrook             else
1208e1f3808eSpbrook                 val = (1ull << 48) - 1;
1209e1f3808eSpbrook         } else {
1210e1f3808eSpbrook             val &= ((1ull << 48) - 1);
1211e1f3808eSpbrook         }
1212e1f3808eSpbrook     }
1213e1f3808eSpbrook     env->macc[acc] = val;
1214e1f3808eSpbrook }
1215e1f3808eSpbrook 
12162b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1217e1f3808eSpbrook {
1218e1f3808eSpbrook     int64_t sum;
1219e1f3808eSpbrook     int64_t result;
1220e1f3808eSpbrook 
1221e1f3808eSpbrook     sum = env->macc[acc];
1222e1f3808eSpbrook     result = (sum << 16) >> 16;
1223e1f3808eSpbrook     if (result != sum) {
1224e1f3808eSpbrook         env->macsr |= MACSR_V;
1225e1f3808eSpbrook     }
1226e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1227e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1228e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1229e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffffffffll;
1230e1f3808eSpbrook         }
1231e1f3808eSpbrook     }
1232e1f3808eSpbrook     env->macc[acc] = result;
1233e1f3808eSpbrook }
1234e1f3808eSpbrook 
12352b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1236e1f3808eSpbrook {
1237e1f3808eSpbrook     uint64_t val;
1238e1f3808eSpbrook     val = env->macc[acc];
1239c4162574SBlue Swirl     if (val == 0) {
1240e1f3808eSpbrook         env->macsr |= MACSR_Z;
1241c4162574SBlue Swirl     } else if (val & (1ull << 47)) {
1242e1f3808eSpbrook         env->macsr |= MACSR_N;
1243c4162574SBlue Swirl     }
1244e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << acc)) {
1245e1f3808eSpbrook         env->macsr |= MACSR_V;
1246e1f3808eSpbrook     }
1247e1f3808eSpbrook     if (env->macsr & MACSR_FI) {
1248e1f3808eSpbrook         val = ((int64_t)val) >> 40;
1249e1f3808eSpbrook         if (val != 0 && val != -1)
1250e1f3808eSpbrook             env->macsr |= MACSR_EV;
1251e1f3808eSpbrook     } else if (env->macsr & MACSR_SU) {
1252e1f3808eSpbrook         val = ((int64_t)val) >> 32;
1253e1f3808eSpbrook         if (val != 0 && val != -1)
1254e1f3808eSpbrook             env->macsr |= MACSR_EV;
1255e1f3808eSpbrook     } else {
1256e1f3808eSpbrook         if ((val >> 32) != 0)
1257e1f3808eSpbrook             env->macsr |= MACSR_EV;
1258e1f3808eSpbrook     }
1259e1f3808eSpbrook }
1260e1f3808eSpbrook 
1261db3d7945SLaurent Vivier #define EXTSIGN(val, index) (     \
1262db3d7945SLaurent Vivier     (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1263db3d7945SLaurent Vivier )
1264620c6cf6SRichard Henderson 
1265620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) {                                   \
1266620c6cf6SRichard Henderson     switch (op) {                                                          \
1267620c6cf6SRichard Henderson     case CC_OP_FLAGS:                                                      \
1268620c6cf6SRichard Henderson         /* Everything in place.  */                                        \
1269620c6cf6SRichard Henderson         break;                                                             \
1270db3d7945SLaurent Vivier     case CC_OP_ADDB:                                                       \
1271db3d7945SLaurent Vivier     case CC_OP_ADDW:                                                       \
1272db3d7945SLaurent Vivier     case CC_OP_ADDL:                                                       \
1273620c6cf6SRichard Henderson         res = n;                                                           \
1274620c6cf6SRichard Henderson         src2 = v;                                                          \
1275db3d7945SLaurent Vivier         src1 = EXTSIGN(res - src2, op - CC_OP_ADDB);                       \
1276620c6cf6SRichard Henderson         c = x;                                                             \
1277620c6cf6SRichard Henderson         z = n;                                                             \
1278620c6cf6SRichard Henderson         v = (res ^ src1) & ~(src1 ^ src2);                                 \
1279620c6cf6SRichard Henderson         break;                                                             \
1280db3d7945SLaurent Vivier     case CC_OP_SUBB:                                                       \
1281db3d7945SLaurent Vivier     case CC_OP_SUBW:                                                       \
1282db3d7945SLaurent Vivier     case CC_OP_SUBL:                                                       \
1283620c6cf6SRichard Henderson         res = n;                                                           \
1284620c6cf6SRichard Henderson         src2 = v;                                                          \
1285db3d7945SLaurent Vivier         src1 = EXTSIGN(res + src2, op - CC_OP_SUBB);                       \
1286620c6cf6SRichard Henderson         c = x;                                                             \
1287620c6cf6SRichard Henderson         z = n;                                                             \
1288620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1289620c6cf6SRichard Henderson         break;                                                             \
1290db3d7945SLaurent Vivier     case CC_OP_CMPB:                                                       \
1291db3d7945SLaurent Vivier     case CC_OP_CMPW:                                                       \
1292db3d7945SLaurent Vivier     case CC_OP_CMPL:                                                       \
1293620c6cf6SRichard Henderson         src1 = n;                                                          \
1294620c6cf6SRichard Henderson         src2 = v;                                                          \
1295db3d7945SLaurent Vivier         res = EXTSIGN(src1 - src2, op - CC_OP_CMPB);                       \
1296620c6cf6SRichard Henderson         n = res;                                                           \
1297620c6cf6SRichard Henderson         z = res;                                                           \
1298620c6cf6SRichard Henderson         c = src1 < src2;                                                   \
1299620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1300620c6cf6SRichard Henderson         break;                                                             \
1301620c6cf6SRichard Henderson     case CC_OP_LOGIC:                                                      \
1302620c6cf6SRichard Henderson         c = v = 0;                                                         \
1303620c6cf6SRichard Henderson         z = n;                                                             \
1304620c6cf6SRichard Henderson         break;                                                             \
1305620c6cf6SRichard Henderson     default:                                                               \
1306a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env), "Bad CC_OP %d", op);                       \
1307620c6cf6SRichard Henderson     }                                                                      \
1308620c6cf6SRichard Henderson } while (0)
1309620c6cf6SRichard Henderson 
1310620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1311e1f3808eSpbrook {
1312620c6cf6SRichard Henderson     uint32_t x, c, n, z, v;
1313620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1314620c6cf6SRichard Henderson 
1315620c6cf6SRichard Henderson     x = env->cc_x;
1316620c6cf6SRichard Henderson     n = env->cc_n;
1317620c6cf6SRichard Henderson     z = env->cc_z;
1318620c6cf6SRichard Henderson     v = env->cc_v;
1319db3d7945SLaurent Vivier     c = env->cc_c;
1320620c6cf6SRichard Henderson 
1321620c6cf6SRichard Henderson     COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1322620c6cf6SRichard Henderson 
1323620c6cf6SRichard Henderson     n = n >> 31;
1324620c6cf6SRichard Henderson     z = (z == 0);
1325db3d7945SLaurent Vivier     v = v >> 31;
1326620c6cf6SRichard Henderson 
1327620c6cf6SRichard Henderson     return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1328620c6cf6SRichard Henderson }
1329620c6cf6SRichard Henderson 
1330620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env)
1331620c6cf6SRichard Henderson {
1332620c6cf6SRichard Henderson     return cpu_m68k_get_ccr(env);
1333620c6cf6SRichard Henderson }
1334620c6cf6SRichard Henderson 
1335620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1336620c6cf6SRichard Henderson {
1337620c6cf6SRichard Henderson     env->cc_x = (ccr & CCF_X ? 1 : 0);
1338620c6cf6SRichard Henderson     env->cc_n = (ccr & CCF_N ? -1 : 0);
1339620c6cf6SRichard Henderson     env->cc_z = (ccr & CCF_Z ? 0 : 1);
1340620c6cf6SRichard Henderson     env->cc_v = (ccr & CCF_V ? -1 : 0);
1341620c6cf6SRichard Henderson     env->cc_c = (ccr & CCF_C ? 1 : 0);
1342620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1343620c6cf6SRichard Henderson }
1344620c6cf6SRichard Henderson 
1345620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1346620c6cf6SRichard Henderson {
1347620c6cf6SRichard Henderson     cpu_m68k_set_ccr(env, ccr);
1348620c6cf6SRichard Henderson }
1349620c6cf6SRichard Henderson 
1350620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1351620c6cf6SRichard Henderson {
1352620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1353620c6cf6SRichard Henderson 
1354620c6cf6SRichard Henderson     COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1355620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1356e1f3808eSpbrook }
1357e1f3808eSpbrook 
13582b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1359e1f3808eSpbrook {
1360e1f3808eSpbrook     int rem;
1361e1f3808eSpbrook     uint32_t result;
1362e1f3808eSpbrook 
1363e1f3808eSpbrook     if (env->macsr & MACSR_SU) {
1364e1f3808eSpbrook         /* 16-bit rounding.  */
1365e1f3808eSpbrook         rem = val & 0xffffff;
1366e1f3808eSpbrook         val = (val >> 24) & 0xffffu;
1367e1f3808eSpbrook         if (rem > 0x800000)
1368e1f3808eSpbrook             val++;
1369e1f3808eSpbrook         else if (rem == 0x800000)
1370e1f3808eSpbrook             val += (val & 1);
1371e1f3808eSpbrook     } else if (env->macsr & MACSR_RT) {
1372e1f3808eSpbrook         /* 32-bit rounding.  */
1373e1f3808eSpbrook         rem = val & 0xff;
1374e1f3808eSpbrook         val >>= 8;
1375e1f3808eSpbrook         if (rem > 0x80)
1376e1f3808eSpbrook             val++;
1377e1f3808eSpbrook         else if (rem == 0x80)
1378e1f3808eSpbrook             val += (val & 1);
1379e1f3808eSpbrook     } else {
1380e1f3808eSpbrook         /* No rounding.  */
1381e1f3808eSpbrook         val >>= 8;
1382e1f3808eSpbrook     }
1383e1f3808eSpbrook     if (env->macsr & MACSR_OMC) {
1384e1f3808eSpbrook         /* Saturate.  */
1385e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1386e1f3808eSpbrook             if (val != (uint16_t) val) {
1387e1f3808eSpbrook                 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1388e1f3808eSpbrook             } else {
1389e1f3808eSpbrook                 result = val & 0xffff;
1390e1f3808eSpbrook             }
1391e1f3808eSpbrook         } else {
1392e1f3808eSpbrook             if (val != (uint32_t)val) {
1393e1f3808eSpbrook                 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1394e1f3808eSpbrook             } else {
1395e1f3808eSpbrook                 result = (uint32_t)val;
1396e1f3808eSpbrook             }
1397e1f3808eSpbrook         }
1398e1f3808eSpbrook     } else {
1399e1f3808eSpbrook         /* No saturation.  */
1400e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1401e1f3808eSpbrook             result = val & 0xffff;
1402e1f3808eSpbrook         } else {
1403e1f3808eSpbrook             result = (uint32_t)val;
1404e1f3808eSpbrook         }
1405e1f3808eSpbrook     }
1406e1f3808eSpbrook     return result;
1407e1f3808eSpbrook }
1408e1f3808eSpbrook 
1409e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val)
1410e1f3808eSpbrook {
1411e1f3808eSpbrook     if (val == (int32_t)val) {
1412e1f3808eSpbrook         return (int32_t)val;
1413e1f3808eSpbrook     } else {
1414e1f3808eSpbrook         return (val >> 61) ^ ~SIGNBIT;
1415e1f3808eSpbrook     }
1416e1f3808eSpbrook }
1417e1f3808eSpbrook 
1418e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val)
1419e1f3808eSpbrook {
1420e1f3808eSpbrook     if ((val >> 32) == 0) {
1421e1f3808eSpbrook         return (uint32_t)val;
1422e1f3808eSpbrook     } else {
1423e1f3808eSpbrook         return 0xffffffffu;
1424e1f3808eSpbrook     }
1425e1f3808eSpbrook }
1426e1f3808eSpbrook 
14272b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1428e1f3808eSpbrook {
1429e1f3808eSpbrook     uint32_t val;
1430e1f3808eSpbrook     val = env->macc[acc] & 0x00ff;
14315ce747cfSPaolo Bonzini     val |= (env->macc[acc] >> 32) & 0xff00;
1432e1f3808eSpbrook     val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1433e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1434e1f3808eSpbrook     return val;
1435e1f3808eSpbrook }
1436e1f3808eSpbrook 
14372b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1438e1f3808eSpbrook {
1439e1f3808eSpbrook     uint32_t val;
1440e1f3808eSpbrook     val = (env->macc[acc] >> 32) & 0xffff;
1441e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1442e1f3808eSpbrook     return val;
1443e1f3808eSpbrook }
1444e1f3808eSpbrook 
14452b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1446e1f3808eSpbrook {
1447e1f3808eSpbrook     int64_t res;
1448e1f3808eSpbrook     int32_t tmp;
1449e1f3808eSpbrook     res = env->macc[acc] & 0xffffffff00ull;
1450e1f3808eSpbrook     tmp = (int16_t)(val & 0xff00);
1451e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1452e1f3808eSpbrook     res |= val & 0xff;
1453e1f3808eSpbrook     env->macc[acc] = res;
1454e1f3808eSpbrook     res = env->macc[acc + 1] & 0xffffffff00ull;
1455e1f3808eSpbrook     tmp = (val & 0xff000000);
1456e1f3808eSpbrook     res |= ((int64_t)tmp) << 16;
1457e1f3808eSpbrook     res |= (val >> 16) & 0xff;
1458e1f3808eSpbrook     env->macc[acc + 1] = res;
1459e1f3808eSpbrook }
1460e1f3808eSpbrook 
14612b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
1462e1f3808eSpbrook {
1463e1f3808eSpbrook     int64_t res;
1464e1f3808eSpbrook     int32_t tmp;
1465e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1466e1f3808eSpbrook     tmp = (int16_t)val;
1467e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1468e1f3808eSpbrook     env->macc[acc] = res;
1469e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1470e1f3808eSpbrook     tmp = val & 0xffff0000;
1471e1f3808eSpbrook     res |= (int64_t)tmp << 16;
1472e1f3808eSpbrook     env->macc[acc + 1] = res;
1473e1f3808eSpbrook }
1474e1f3808eSpbrook 
14752b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
1476e1f3808eSpbrook {
1477e1f3808eSpbrook     uint64_t res;
1478e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1479e1f3808eSpbrook     res |= ((uint64_t)(val & 0xffff)) << 32;
1480e1f3808eSpbrook     env->macc[acc] = res;
1481e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1482e1f3808eSpbrook     res |= (uint64_t)(val & 0xffff0000) << 16;
1483e1f3808eSpbrook     env->macc[acc + 1] = res;
1484e1f3808eSpbrook }
14850bdb2b3bSLaurent Vivier 
14860bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU)
1487e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1488e55886c3SLaurent Vivier {
1489e55886c3SLaurent Vivier     hwaddr physical;
1490e55886c3SLaurent Vivier     int access_type;
1491e55886c3SLaurent Vivier     int prot;
1492e55886c3SLaurent Vivier     int ret;
1493e55886c3SLaurent Vivier     target_ulong page_size;
1494e55886c3SLaurent Vivier 
1495e55886c3SLaurent Vivier     access_type = ACCESS_PTEST;
1496e55886c3SLaurent Vivier     if (env->dfc & 4) {
1497e55886c3SLaurent Vivier         access_type |= ACCESS_SUPER;
1498e55886c3SLaurent Vivier     }
1499e55886c3SLaurent Vivier     if ((env->dfc & 3) == 2) {
1500e55886c3SLaurent Vivier         access_type |= ACCESS_CODE;
1501e55886c3SLaurent Vivier     }
1502e55886c3SLaurent Vivier     if (!is_read) {
1503e55886c3SLaurent Vivier         access_type |= ACCESS_STORE;
1504e55886c3SLaurent Vivier     }
1505e55886c3SLaurent Vivier 
1506e55886c3SLaurent Vivier     env->mmu.mmusr = 0;
1507e55886c3SLaurent Vivier     env->mmu.ssw = 0;
1508e55886c3SLaurent Vivier     ret = get_physical_address(env, &physical, &prot, addr,
1509e55886c3SLaurent Vivier                                access_type, &page_size);
1510e55886c3SLaurent Vivier     if (ret == 0) {
1511852002b5SMark Cave-Ayland         tlb_set_page(env_cpu(env), addr & TARGET_PAGE_MASK,
1512852002b5SMark Cave-Ayland                      physical & TARGET_PAGE_MASK,
1513e55886c3SLaurent Vivier                      prot, access_type & ACCESS_SUPER ?
1514e55886c3SLaurent Vivier                      MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1515e55886c3SLaurent Vivier     }
1516e55886c3SLaurent Vivier }
1517e55886c3SLaurent Vivier 
1518e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1519e55886c3SLaurent Vivier {
1520a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
1521e55886c3SLaurent Vivier 
1522e55886c3SLaurent Vivier     switch (opmode) {
1523e55886c3SLaurent Vivier     case 0: /* Flush page entry if not global */
1524e55886c3SLaurent Vivier     case 1: /* Flush page entry */
1525a8d92fd8SRichard Henderson         tlb_flush_page(cs, addr);
1526e55886c3SLaurent Vivier         break;
1527e55886c3SLaurent Vivier     case 2: /* Flush all except global entries */
1528a8d92fd8SRichard Henderson         tlb_flush(cs);
1529e55886c3SLaurent Vivier         break;
1530e55886c3SLaurent Vivier     case 3: /* Flush all entries */
1531a8d92fd8SRichard Henderson         tlb_flush(cs);
1532e55886c3SLaurent Vivier         break;
1533e55886c3SLaurent Vivier     }
1534e55886c3SLaurent Vivier }
1535e55886c3SLaurent Vivier 
15360bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env)
15370bdb2b3bSLaurent Vivier {
15380bdb2b3bSLaurent Vivier     /* FIXME: reset all except CPU */
15390bdb2b3bSLaurent Vivier }
15400bdb2b3bSLaurent Vivier #endif
1541