xref: /qemu/target/m68k/helper.c (revision 7cef6d686309e2792186504ae17cf4f3eb57ef68)
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"
23eb9b25c6SPhilippe Mathieu-Daudé #include "exec/cputlb.h"
2474781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
25*9c2ff9cdSPierrick Bouvier #include "exec/target_page.h"
26022c62cbSPaolo Bonzini #include "exec/gdbstub.h"
272ef6175aSRichard Henderson #include "exec/helper-proto.h"
28342e313dSPierrick Bouvier #include "system/memory.h"
294ea5fe99SAlex Bennée #include "gdbstub/helpers.h"
3024f91e81SAlex Bennée #include "fpu/softfloat.h"
310442428aSMarkus Armbruster #include "qemu/qemu-print.h"
32e1f3808eSpbrook 
33e1f3808eSpbrook #define SIGNBIT (1u << 31)
34e1f3808eSpbrook 
cf_fpu_gdb_get_reg(CPUState * cs,GByteArray * mem_buf,int n)3566260159SAkihiko Odaki static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
3656aebc89Spbrook {
3766260159SAkihiko Odaki     M68kCPU *cpu = M68K_CPU(cs);
3866260159SAkihiko Odaki     CPUM68KState *env = &cpu->env;
3966260159SAkihiko Odaki 
4056aebc89Spbrook     if (n < 8) {
41ca81533eSPeter Maydell         /* Use scratch float_status so any exceptions don't change CPU state */
42ca81533eSPeter Maydell         float_status s = env->fp_status;
437ed51401SPeter Maydell         return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
4456aebc89Spbrook     }
45ba624944SLaurent Vivier     switch (n) {
46ba624944SLaurent Vivier     case 8: /* fpcontrol */
47462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, env->fpcr);
48ba624944SLaurent Vivier     case 9: /* fpstatus */
49462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, env->fpsr);
50ba624944SLaurent Vivier     case 10: /* fpiar, not implemented */
51462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, 0);
5256aebc89Spbrook     }
5356aebc89Spbrook     return 0;
5456aebc89Spbrook }
5556aebc89Spbrook 
cf_fpu_gdb_set_reg(CPUState * cs,uint8_t * mem_buf,int n)5666260159SAkihiko Odaki static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
5756aebc89Spbrook {
5866260159SAkihiko Odaki     M68kCPU *cpu = M68K_CPU(cs);
5966260159SAkihiko Odaki     CPUM68KState *env = &cpu->env;
6066260159SAkihiko Odaki 
6156aebc89Spbrook     if (n < 8) {
62ca81533eSPeter Maydell         /* Use scratch float_status so any exceptions don't change CPU state */
63ca81533eSPeter Maydell         float_status s = env->fp_status;
643a76d302SPhilippe Mathieu-Daudé         env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s);
6556aebc89Spbrook         return 8;
6656aebc89Spbrook     }
67ba624944SLaurent Vivier     switch (n) {
68ba624944SLaurent Vivier     case 8: /* fpcontrol */
693a76d302SPhilippe Mathieu-Daudé         cpu_m68k_set_fpcr(env, ldl_be_p(mem_buf));
70ba624944SLaurent Vivier         return 4;
71ba624944SLaurent Vivier     case 9: /* fpstatus */
723a76d302SPhilippe Mathieu-Daudé         env->fpsr = ldl_be_p(mem_buf);
73ba624944SLaurent Vivier         return 4;
74ba624944SLaurent Vivier     case 10: /* fpiar, not implemented */
7556aebc89Spbrook         return 4;
7656aebc89Spbrook     }
7756aebc89Spbrook     return 0;
7856aebc89Spbrook }
7956aebc89Spbrook 
m68k_fpu_gdb_get_reg(CPUState * cs,GByteArray * mem_buf,int n)8066260159SAkihiko Odaki static int m68k_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
815a4526b2SLaurent Vivier {
8266260159SAkihiko Odaki     M68kCPU *cpu = M68K_CPU(cs);
8366260159SAkihiko Odaki     CPUM68KState *env = &cpu->env;
8466260159SAkihiko Odaki 
855a4526b2SLaurent Vivier     if (n < 8) {
86462474d7SAlex Bennée         int len = gdb_get_reg16(mem_buf, env->fregs[n].l.upper);
874b27f9b0SPhilippe Mathieu-Daudé         len += gdb_get_reg16(mem_buf, 0);
884b27f9b0SPhilippe Mathieu-Daudé         len += gdb_get_reg64(mem_buf, env->fregs[n].l.lower);
89462474d7SAlex Bennée         return len;
905a4526b2SLaurent Vivier     }
915a4526b2SLaurent Vivier     switch (n) {
925a4526b2SLaurent Vivier     case 8: /* fpcontrol */
93462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, env->fpcr);
945a4526b2SLaurent Vivier     case 9: /* fpstatus */
9558883579SKeith Packard         return gdb_get_reg32(mem_buf, cpu_m68k_get_fpsr(env));
965a4526b2SLaurent Vivier     case 10: /* fpiar, not implemented */
97462474d7SAlex Bennée         return gdb_get_reg32(mem_buf, 0);
985a4526b2SLaurent Vivier     }
995a4526b2SLaurent Vivier     return 0;
1005a4526b2SLaurent Vivier }
1015a4526b2SLaurent Vivier 
m68k_fpu_gdb_set_reg(CPUState * cs,uint8_t * mem_buf,int n)10266260159SAkihiko Odaki static int m68k_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
1035a4526b2SLaurent Vivier {
10466260159SAkihiko Odaki     M68kCPU *cpu = M68K_CPU(cs);
10566260159SAkihiko Odaki     CPUM68KState *env = &cpu->env;
10666260159SAkihiko Odaki 
1075a4526b2SLaurent Vivier     if (n < 8) {
1085a4526b2SLaurent Vivier         env->fregs[n].l.upper = lduw_be_p(mem_buf);
1095a4526b2SLaurent Vivier         env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
1105a4526b2SLaurent Vivier         return 12;
1115a4526b2SLaurent Vivier     }
1125a4526b2SLaurent Vivier     switch (n) {
1135a4526b2SLaurent Vivier     case 8: /* fpcontrol */
1143a76d302SPhilippe Mathieu-Daudé         cpu_m68k_set_fpcr(env, ldl_be_p(mem_buf));
1155a4526b2SLaurent Vivier         return 4;
1165a4526b2SLaurent Vivier     case 9: /* fpstatus */
1173a76d302SPhilippe Mathieu-Daudé         cpu_m68k_set_fpsr(env, ldl_be_p(mem_buf));
1185a4526b2SLaurent Vivier         return 4;
1195a4526b2SLaurent Vivier     case 10: /* fpiar, not implemented */
1205a4526b2SLaurent Vivier         return 4;
1215a4526b2SLaurent Vivier     }
1225a4526b2SLaurent Vivier     return 0;
1235a4526b2SLaurent Vivier }
1245a4526b2SLaurent Vivier 
m68k_cpu_init_gdb(M68kCPU * cpu)1256d1bbc62SAndreas Färber void m68k_cpu_init_gdb(M68kCPU *cpu)
1266d1bbc62SAndreas Färber {
12722169d41SAndreas Färber     CPUState *cs = CPU(cpu);
1286d1bbc62SAndreas Färber     CPUM68KState *env = &cpu->env;
1296d1bbc62SAndreas Färber 
13011150915SAndreas Färber     if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
131f83311e4SLaurent Vivier         gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
132ac1e8671SAkihiko Odaki                                  gdb_find_static_feature("cf-fp.xml"), 18);
1335a4526b2SLaurent Vivier     } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
134ac1e8671SAkihiko Odaki         gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg, m68k_fpu_gdb_set_reg,
135ac1e8671SAkihiko Odaki                                  gdb_find_static_feature("m68k-fp.xml"), 18);
136aaed909aSbellard     }
13711150915SAndreas Färber     /* TODO: Add [E]MAC registers.  */
138aaed909aSbellard }
139aaed909aSbellard 
HELPER(cf_movec_to)1406e22b28eSLaurent Vivier void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
1410633879fSpbrook {
1420633879fSpbrook     switch (reg) {
1436e22b28eSLaurent Vivier     case M68K_CR_CACR:
14420dcee94Spbrook         env->cacr = val;
14520dcee94Spbrook         m68k_switch_sp(env);
14620dcee94Spbrook         break;
1476e22b28eSLaurent Vivier     case M68K_CR_ACR0:
1486e22b28eSLaurent Vivier     case M68K_CR_ACR1:
1496e22b28eSLaurent Vivier     case M68K_CR_ACR2:
1506e22b28eSLaurent Vivier     case M68K_CR_ACR3:
15120dcee94Spbrook         /* TODO: Implement Access Control Registers.  */
1520633879fSpbrook         break;
1536e22b28eSLaurent Vivier     case M68K_CR_VBR:
1540633879fSpbrook         env->vbr = val;
1550633879fSpbrook         break;
1560633879fSpbrook     /* TODO: Implement control registers.  */
1570633879fSpbrook     default:
158a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env),
1596e22b28eSLaurent Vivier                   "Unimplemented control register write 0x%x = 0x%x\n",
1606e22b28eSLaurent Vivier                   reg, val);
1616e22b28eSLaurent Vivier     }
1626e22b28eSLaurent Vivier }
1636e22b28eSLaurent Vivier 
raise_exception_ra(CPUM68KState * env,int tt,uintptr_t raddr)1648df0e6aeSLucien Murray-Pitts static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
1658df0e6aeSLucien Murray-Pitts {
1668df0e6aeSLucien Murray-Pitts     CPUState *cs = env_cpu(env);
1678df0e6aeSLucien Murray-Pitts 
1688df0e6aeSLucien Murray-Pitts     cs->exception_index = tt;
1698df0e6aeSLucien Murray-Pitts     cpu_loop_exit_restore(cs, raddr);
1708df0e6aeSLucien Murray-Pitts }
1718df0e6aeSLucien Murray-Pitts 
HELPER(m68k_movec_to)1726e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
1736e22b28eSLaurent Vivier {
1746e22b28eSLaurent Vivier     switch (reg) {
17560d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
1765fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
1775fa9f1f2SLaurent Vivier         env->sfc = val & 7;
1785fa9f1f2SLaurent Vivier         return;
17960d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
1805fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
1815fa9f1f2SLaurent Vivier         env->dfc = val & 7;
1825fa9f1f2SLaurent Vivier         return;
18360d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
1846e22b28eSLaurent Vivier     case M68K_CR_VBR:
1856e22b28eSLaurent Vivier         env->vbr = val;
1866e22b28eSLaurent Vivier         return;
18718b6102eSLaurent Vivier     /* MC680[2346]0 */
1886e22b28eSLaurent Vivier     case M68K_CR_CACR:
18918b6102eSLaurent Vivier         if (m68k_feature(env, M68K_FEATURE_M68020)) {
19018b6102eSLaurent Vivier             env->cacr = val & 0x0000000f;
19118b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68030)) {
19218b6102eSLaurent Vivier             env->cacr = val & 0x00003f1f;
19318b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68040)) {
19418b6102eSLaurent Vivier             env->cacr = val & 0x80008000;
19518b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68060)) {
19618b6102eSLaurent Vivier             env->cacr = val & 0xf8e0e000;
1978df0e6aeSLucien Murray-Pitts         } else {
1988df0e6aeSLucien Murray-Pitts             break;
19918b6102eSLaurent Vivier         }
2006e22b28eSLaurent Vivier         m68k_switch_sp(env);
2016e22b28eSLaurent Vivier         return;
20260d8e964SLucien Murray-Pitts     /* MC680[46]0 */
20388b2fef6SLaurent Vivier     case M68K_CR_TC:
2048df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
2058df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
20688b2fef6SLaurent Vivier             env->mmu.tcr = val;
20788b2fef6SLaurent Vivier             return;
2088df0e6aeSLucien Murray-Pitts         }
2098df0e6aeSLucien Murray-Pitts         break;
21060d8e964SLucien Murray-Pitts     /* MC68040 */
211e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
2128df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
213e55886c3SLaurent Vivier             env->mmu.mmusr = val;
214e55886c3SLaurent Vivier             return;
2158df0e6aeSLucien Murray-Pitts         }
2168df0e6aeSLucien Murray-Pitts         break;
21760d8e964SLucien Murray-Pitts     /* MC680[46]0 */
21888b2fef6SLaurent Vivier     case M68K_CR_SRP:
2198df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
2208df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
22188b2fef6SLaurent Vivier             env->mmu.srp = val;
22288b2fef6SLaurent Vivier             return;
2238df0e6aeSLucien Murray-Pitts         }
2248df0e6aeSLucien Murray-Pitts         break;
2258df0e6aeSLucien Murray-Pitts     /* MC680[46]0 */
22688b2fef6SLaurent Vivier     case M68K_CR_URP:
2278df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
2288df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
22988b2fef6SLaurent Vivier             env->mmu.urp = val;
23088b2fef6SLaurent Vivier             return;
2318df0e6aeSLucien Murray-Pitts         }
2328df0e6aeSLucien Murray-Pitts         break;
2338df0e6aeSLucien Murray-Pitts     /* MC680[12346]0 */
2346e22b28eSLaurent Vivier     case M68K_CR_USP:
2356e22b28eSLaurent Vivier         env->sp[M68K_USP] = val;
2366e22b28eSLaurent Vivier         return;
23760d8e964SLucien Murray-Pitts     /* MC680[234]0 */
2386e22b28eSLaurent Vivier     case M68K_CR_MSP:
2398df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
2408df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
2418df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)) {
2426e22b28eSLaurent Vivier             env->sp[M68K_SSP] = val;
2436e22b28eSLaurent Vivier             return;
2448df0e6aeSLucien Murray-Pitts         }
2458df0e6aeSLucien Murray-Pitts         break;
24660d8e964SLucien Murray-Pitts     /* MC680[234]0 */
2476e22b28eSLaurent Vivier     case M68K_CR_ISP:
2488df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
2498df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
2508df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)) {
2516e22b28eSLaurent Vivier             env->sp[M68K_ISP] = val;
2526e22b28eSLaurent Vivier             return;
2538df0e6aeSLucien Murray-Pitts         }
2548df0e6aeSLucien Murray-Pitts         break;
255c05c73b0SLaurent Vivier     /* MC68040/MC68LC040 */
2568df0e6aeSLucien Murray-Pitts     case M68K_CR_ITT0: /* MC68EC040 only: M68K_CR_IACR0 */
2578df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
258c05c73b0SLaurent Vivier             env->mmu.ttr[M68K_ITTR0] = val;
259c05c73b0SLaurent Vivier             return;
2608df0e6aeSLucien Murray-Pitts         }
2618df0e6aeSLucien Murray-Pitts         break;
26260d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
2638df0e6aeSLucien Murray-Pitts     case M68K_CR_ITT1: /* MC68EC040 only: M68K_CR_IACR1 */
2648df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
265c05c73b0SLaurent Vivier             env->mmu.ttr[M68K_ITTR1] = val;
266c05c73b0SLaurent Vivier             return;
2678df0e6aeSLucien Murray-Pitts         }
2688df0e6aeSLucien Murray-Pitts         break;
26960d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
2708df0e6aeSLucien Murray-Pitts     case M68K_CR_DTT0: /* MC68EC040 only: M68K_CR_DACR0 */
2718df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
272c05c73b0SLaurent Vivier             env->mmu.ttr[M68K_DTTR0] = val;
273c05c73b0SLaurent Vivier             return;
2748df0e6aeSLucien Murray-Pitts         }
2758df0e6aeSLucien Murray-Pitts         break;
27660d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
2778df0e6aeSLucien Murray-Pitts     case M68K_CR_DTT1: /* MC68EC040 only: M68K_CR_DACR1 */
2788df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
279c05c73b0SLaurent Vivier             env->mmu.ttr[M68K_DTTR1] = val;
280c05c73b0SLaurent Vivier             return;
2818df0e6aeSLucien Murray-Pitts         }
2828df0e6aeSLucien Murray-Pitts         break;
2835736526cSLucien Murray-Pitts     /* Unimplemented Registers */
2845736526cSLucien Murray-Pitts     case M68K_CR_CAAR:
2855736526cSLucien Murray-Pitts     case M68K_CR_PCR:
2865736526cSLucien Murray-Pitts     case M68K_CR_BUSCR:
287a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env),
288a8d92fd8SRichard Henderson                   "Unimplemented control register write 0x%x = 0x%x\n",
2890633879fSpbrook                   reg, val);
2900633879fSpbrook     }
2916e22b28eSLaurent Vivier 
2928df0e6aeSLucien Murray-Pitts     /* Invalid control registers will generate an exception. */
2938df0e6aeSLucien Murray-Pitts     raise_exception_ra(env, EXCP_ILLEGAL, 0);
2948df0e6aeSLucien Murray-Pitts }
2958df0e6aeSLucien Murray-Pitts 
HELPER(m68k_movec_from)2966e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
2976e22b28eSLaurent Vivier {
2986e22b28eSLaurent Vivier     switch (reg) {
29960d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
3005fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
3015fa9f1f2SLaurent Vivier         return env->sfc;
30260d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
3035fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
3045fa9f1f2SLaurent Vivier         return env->dfc;
30560d8e964SLucien Murray-Pitts     /* MC680[12346]0 */
3066e22b28eSLaurent Vivier     case M68K_CR_VBR:
3076e22b28eSLaurent Vivier         return env->vbr;
30860d8e964SLucien Murray-Pitts     /* MC680[2346]0 */
3096e22b28eSLaurent Vivier     case M68K_CR_CACR:
3108df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
3118df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
3128df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)
3138df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
3146e22b28eSLaurent Vivier             return env->cacr;
3158df0e6aeSLucien Murray-Pitts         }
3168df0e6aeSLucien Murray-Pitts         break;
31760d8e964SLucien Murray-Pitts     /* MC680[46]0 */
31888b2fef6SLaurent Vivier     case M68K_CR_TC:
3198df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
3208df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
32188b2fef6SLaurent Vivier             return env->mmu.tcr;
3228df0e6aeSLucien Murray-Pitts         }
3238df0e6aeSLucien Murray-Pitts         break;
32460d8e964SLucien Murray-Pitts     /* MC68040 */
325e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
3268df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
327e55886c3SLaurent Vivier             return env->mmu.mmusr;
3288df0e6aeSLucien Murray-Pitts         }
3298df0e6aeSLucien Murray-Pitts         break;
33060d8e964SLucien Murray-Pitts     /* MC680[46]0 */
33188b2fef6SLaurent Vivier     case M68K_CR_SRP:
3328df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
3338df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
33488b2fef6SLaurent Vivier             return env->mmu.srp;
3358df0e6aeSLucien Murray-Pitts         }
3368df0e6aeSLucien Murray-Pitts         break;
3378df0e6aeSLucien Murray-Pitts     /* MC68040/MC68LC040 */
3388df0e6aeSLucien Murray-Pitts     case M68K_CR_URP:
3398df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)
3408df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68060)) {
3418df0e6aeSLucien Murray-Pitts             return env->mmu.urp;
3428df0e6aeSLucien Murray-Pitts         }
3438df0e6aeSLucien Murray-Pitts         break;
34460d8e964SLucien Murray-Pitts     /* MC680[46]0 */
3456e22b28eSLaurent Vivier     case M68K_CR_USP:
3466e22b28eSLaurent Vivier         return env->sp[M68K_USP];
34760d8e964SLucien Murray-Pitts     /* MC680[234]0 */
3486e22b28eSLaurent Vivier     case M68K_CR_MSP:
3498df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
3508df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
3518df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)) {
3526e22b28eSLaurent Vivier             return env->sp[M68K_SSP];
3538df0e6aeSLucien Murray-Pitts         }
3548df0e6aeSLucien Murray-Pitts         break;
35560d8e964SLucien Murray-Pitts     /* MC680[234]0 */
3566e22b28eSLaurent Vivier     case M68K_CR_ISP:
3578df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68020)
3588df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68030)
3598df0e6aeSLucien Murray-Pitts          || m68k_feature(env, M68K_FEATURE_M68040)) {
3606e22b28eSLaurent Vivier             return env->sp[M68K_ISP];
3618df0e6aeSLucien Murray-Pitts         }
3628df0e6aeSLucien Murray-Pitts         break;
36360d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
36460d8e964SLucien Murray-Pitts     case M68K_CR_ITT0: /* MC68EC040 only: M68K_CR_IACR0 */
3658df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
366c05c73b0SLaurent Vivier             return env->mmu.ttr[M68K_ITTR0];
3678df0e6aeSLucien Murray-Pitts         }
3688df0e6aeSLucien Murray-Pitts         break;
36960d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
37060d8e964SLucien Murray-Pitts     case M68K_CR_ITT1: /* MC68EC040 only: M68K_CR_IACR1 */
3718df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
372c05c73b0SLaurent Vivier             return env->mmu.ttr[M68K_ITTR1];
3738df0e6aeSLucien Murray-Pitts         }
3748df0e6aeSLucien Murray-Pitts         break;
37560d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
37660d8e964SLucien Murray-Pitts     case M68K_CR_DTT0: /* MC68EC040 only: M68K_CR_DACR0 */
3778df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
378c05c73b0SLaurent Vivier             return env->mmu.ttr[M68K_DTTR0];
3798df0e6aeSLucien Murray-Pitts         }
3808df0e6aeSLucien Murray-Pitts         break;
38160d8e964SLucien Murray-Pitts     /* MC68040/MC68LC040 */
38260d8e964SLucien Murray-Pitts     case M68K_CR_DTT1: /* MC68EC040 only: M68K_CR_DACR1 */
3838df0e6aeSLucien Murray-Pitts         if (m68k_feature(env, M68K_FEATURE_M68040)) {
384c05c73b0SLaurent Vivier             return env->mmu.ttr[M68K_DTTR1];
3858df0e6aeSLucien Murray-Pitts         }
3868df0e6aeSLucien Murray-Pitts         break;
3875736526cSLucien Murray-Pitts     /* Unimplemented Registers */
3885736526cSLucien Murray-Pitts     case M68K_CR_CAAR:
3895736526cSLucien Murray-Pitts     case M68K_CR_PCR:
3905736526cSLucien Murray-Pitts     case M68K_CR_BUSCR:
391a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n",
3926e22b28eSLaurent Vivier                   reg);
3930633879fSpbrook     }
3940633879fSpbrook 
3958df0e6aeSLucien Murray-Pitts     /* Invalid control registers will generate an exception. */
3968df0e6aeSLucien Murray-Pitts     raise_exception_ra(env, EXCP_ILLEGAL, 0);
3978df0e6aeSLucien Murray-Pitts 
3988df0e6aeSLucien Murray-Pitts     return 0;
3998df0e6aeSLucien Murray-Pitts }
4008df0e6aeSLucien Murray-Pitts 
HELPER(set_macsr)401e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
402acf930aaSpbrook {
403acf930aaSpbrook     uint32_t acc;
404acf930aaSpbrook     int8_t exthigh;
405acf930aaSpbrook     uint8_t extlow;
406acf930aaSpbrook     uint64_t regval;
407acf930aaSpbrook     int i;
408acf930aaSpbrook     if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
409acf930aaSpbrook         for (i = 0; i < 4; i++) {
410acf930aaSpbrook             regval = env->macc[i];
411acf930aaSpbrook             exthigh = regval >> 40;
412acf930aaSpbrook             if (env->macsr & MACSR_FI) {
413acf930aaSpbrook                 acc = regval >> 8;
414acf930aaSpbrook                 extlow = regval;
415acf930aaSpbrook             } else {
416acf930aaSpbrook                 acc = regval;
417acf930aaSpbrook                 extlow = regval >> 32;
418acf930aaSpbrook             }
419acf930aaSpbrook             if (env->macsr & MACSR_FI) {
420acf930aaSpbrook                 regval = (((uint64_t)acc) << 8) | extlow;
421acf930aaSpbrook                 regval |= ((int64_t)exthigh) << 40;
422acf930aaSpbrook             } else if (env->macsr & MACSR_SU) {
423acf930aaSpbrook                 regval = acc | (((int64_t)extlow) << 32);
424acf930aaSpbrook                 regval |= ((int64_t)exthigh) << 40;
425acf930aaSpbrook             } else {
426acf930aaSpbrook                 regval = acc | (((uint64_t)extlow) << 32);
427acf930aaSpbrook                 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
428acf930aaSpbrook             }
429acf930aaSpbrook             env->macc[i] = regval;
430acf930aaSpbrook         }
431acf930aaSpbrook     }
432acf930aaSpbrook     env->macsr = val;
433acf930aaSpbrook }
434acf930aaSpbrook 
m68k_switch_sp(CPUM68KState * env)43520dcee94Spbrook void m68k_switch_sp(CPUM68KState *env)
43620dcee94Spbrook {
43720dcee94Spbrook     int new_sp;
43820dcee94Spbrook 
43920dcee94Spbrook     env->sp[env->current_sp] = env->aregs[7];
440aece90d8SMark Cave-Ayland     if (m68k_feature(env, M68K_FEATURE_M68K)) {
4416e22b28eSLaurent Vivier         if (env->sr & SR_S) {
4427525a9b9SLucien Murray-Pitts             /* SR:Master-Mode bit unimplemented then ISP is not available */
4437525a9b9SLucien Murray-Pitts             if (!m68k_feature(env, M68K_FEATURE_MSP) || env->sr & SR_M) {
4446e22b28eSLaurent Vivier                 new_sp = M68K_SSP;
4456e22b28eSLaurent Vivier             } else {
4466e22b28eSLaurent Vivier                 new_sp = M68K_ISP;
4476e22b28eSLaurent Vivier             }
4486e22b28eSLaurent Vivier         } else {
4496e22b28eSLaurent Vivier             new_sp = M68K_USP;
4506e22b28eSLaurent Vivier         }
4516e22b28eSLaurent Vivier     } else {
45220dcee94Spbrook         new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
45320dcee94Spbrook                  ? M68K_SSP : M68K_USP;
4546e22b28eSLaurent Vivier     }
45520dcee94Spbrook     env->aregs[7] = env->sp[new_sp];
45620dcee94Spbrook     env->current_sp = new_sp;
45720dcee94Spbrook }
45820dcee94Spbrook 
459fe5f7b1bSRichard Henderson #if !defined(CONFIG_USER_ONLY)
46088b2fef6SLaurent Vivier /* MMU: 68040 only */
4614fcc562bSPaul Brook 
print_address_zone(uint32_t logical,uint32_t physical,uint32_t size,int attr)462fad866daSMarkus Armbruster static void print_address_zone(uint32_t logical, uint32_t physical,
4632097dca6SLaurent Vivier                                uint32_t size, int attr)
4642097dca6SLaurent Vivier {
465fad866daSMarkus Armbruster     qemu_printf("%08x - %08x -> %08x - %08x %c ",
4662097dca6SLaurent Vivier                 logical, logical + size - 1,
4672097dca6SLaurent Vivier                 physical, physical + size - 1,
4682097dca6SLaurent Vivier                 attr & 4 ? 'W' : '-');
4692097dca6SLaurent Vivier     size >>= 10;
4702097dca6SLaurent Vivier     if (size < 1024) {
471fad866daSMarkus Armbruster         qemu_printf("(%d KiB)\n", size);
4722097dca6SLaurent Vivier     } else {
4732097dca6SLaurent Vivier         size >>= 10;
4742097dca6SLaurent Vivier         if (size < 1024) {
475fad866daSMarkus Armbruster             qemu_printf("(%d MiB)\n", size);
4762097dca6SLaurent Vivier         } else {
4772097dca6SLaurent Vivier             size >>= 10;
478fad866daSMarkus Armbruster             qemu_printf("(%d GiB)\n", size);
4792097dca6SLaurent Vivier         }
4802097dca6SLaurent Vivier     }
4812097dca6SLaurent Vivier }
4822097dca6SLaurent Vivier 
dump_address_map(CPUM68KState * env,uint32_t root_pointer)483fad866daSMarkus Armbruster static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
4842097dca6SLaurent Vivier {
4852097dca6SLaurent Vivier     int tic_size, tic_shift;
4862097dca6SLaurent Vivier     uint32_t tib_mask;
4872097dca6SLaurent Vivier     uint32_t tia, tib, tic;
4882097dca6SLaurent Vivier     uint32_t logical = 0xffffffff, physical = 0xffffffff;
4892097dca6SLaurent Vivier     uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
4902097dca6SLaurent Vivier     uint32_t last_logical, last_physical;
4912097dca6SLaurent Vivier     int32_t size;
4922097dca6SLaurent Vivier     int last_attr = -1, attr = -1;
493a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
494f80b551dSPeter Maydell     MemTxResult txres;
4952097dca6SLaurent Vivier 
4962097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
4972097dca6SLaurent Vivier         /* 8k page */
4982097dca6SLaurent Vivier         tic_size = 32;
4992097dca6SLaurent Vivier         tic_shift = 13;
5002097dca6SLaurent Vivier         tib_mask = M68K_8K_PAGE_MASK;
5012097dca6SLaurent Vivier     } else {
5022097dca6SLaurent Vivier         /* 4k page */
5032097dca6SLaurent Vivier         tic_size = 64;
5042097dca6SLaurent Vivier         tic_shift = 12;
5052097dca6SLaurent Vivier         tib_mask = M68K_4K_PAGE_MASK;
5062097dca6SLaurent Vivier     }
5077d01623aSPeter Maydell     for (unsigned i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
508f80b551dSPeter Maydell         tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4,
509f80b551dSPeter Maydell                                 MEMTXATTRS_UNSPECIFIED, &txres);
510f80b551dSPeter Maydell         if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) {
5112097dca6SLaurent Vivier             continue;
5122097dca6SLaurent Vivier         }
5137d01623aSPeter Maydell         for (unsigned j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
514f80b551dSPeter Maydell             tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4,
515f80b551dSPeter Maydell                                     MEMTXATTRS_UNSPECIFIED, &txres);
516f80b551dSPeter Maydell             if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) {
5172097dca6SLaurent Vivier                 continue;
5182097dca6SLaurent Vivier             }
5197d01623aSPeter Maydell             for (unsigned k = 0; k < tic_size; k++) {
520f80b551dSPeter Maydell                 tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4,
521f80b551dSPeter Maydell                                         MEMTXATTRS_UNSPECIFIED, &txres);
522f80b551dSPeter Maydell                 if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) {
5232097dca6SLaurent Vivier                     continue;
5242097dca6SLaurent Vivier                 }
5252097dca6SLaurent Vivier                 if (M68K_PDT_INDIRECT(tic)) {
526f80b551dSPeter Maydell                     tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic),
527f80b551dSPeter Maydell                                             MEMTXATTRS_UNSPECIFIED, &txres);
528f80b551dSPeter Maydell                     if (txres != MEMTX_OK) {
529f80b551dSPeter Maydell                         continue;
530f80b551dSPeter Maydell                     }
5312097dca6SLaurent Vivier                 }
5322097dca6SLaurent Vivier 
5332097dca6SLaurent Vivier                 last_logical = logical;
5342097dca6SLaurent Vivier                 logical = (i << M68K_TTS_ROOT_SHIFT) |
5352097dca6SLaurent Vivier                           (j << M68K_TTS_POINTER_SHIFT) |
5362097dca6SLaurent Vivier                           (k << tic_shift);
5372097dca6SLaurent Vivier 
5382097dca6SLaurent Vivier                 last_physical = physical;
5392097dca6SLaurent Vivier                 physical = tic & ~((1 << tic_shift) - 1);
5402097dca6SLaurent Vivier 
5412097dca6SLaurent Vivier                 last_attr = attr;
5422097dca6SLaurent Vivier                 attr = tic & ((1 << tic_shift) - 1);
5432097dca6SLaurent Vivier 
5442097dca6SLaurent Vivier                 if ((logical != (last_logical + (1 << tic_shift))) ||
5452097dca6SLaurent Vivier                     (physical != (last_physical + (1 << tic_shift))) ||
5462097dca6SLaurent Vivier                     (attr & 4) != (last_attr & 4)) {
5472097dca6SLaurent Vivier 
5482097dca6SLaurent Vivier                     if (first_logical != 0xffffffff) {
5492097dca6SLaurent Vivier                         size = last_logical + (1 << tic_shift) -
5502097dca6SLaurent Vivier                                first_logical;
551fad866daSMarkus Armbruster                         print_address_zone(first_logical,
5522097dca6SLaurent Vivier                                            first_physical, size, last_attr);
5532097dca6SLaurent Vivier                     }
5542097dca6SLaurent Vivier                     first_logical = logical;
5552097dca6SLaurent Vivier                     first_physical = physical;
5562097dca6SLaurent Vivier                 }
5572097dca6SLaurent Vivier             }
5582097dca6SLaurent Vivier         }
5592097dca6SLaurent Vivier     }
5602097dca6SLaurent Vivier     if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
5612097dca6SLaurent Vivier         size = logical + (1 << tic_shift) - first_logical;
562fad866daSMarkus Armbruster         print_address_zone(first_logical, first_physical, size, last_attr);
5632097dca6SLaurent Vivier     }
5642097dca6SLaurent Vivier }
5652097dca6SLaurent Vivier 
5662097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \
5672097dca6SLaurent Vivier     switch (a & M68K_DESC_CACHEMODE) { \
5688b81968cSMichael Tokarev     case M68K_DESC_CM_WRTHRU: /* cacheable, write-through */ \
569fad866daSMarkus Armbruster         qemu_printf("T"); \
5702097dca6SLaurent Vivier         break; \
5718b81968cSMichael Tokarev     case M68K_DESC_CM_COPYBK: /* cacheable, copyback */ \
572fad866daSMarkus Armbruster         qemu_printf("C"); \
5732097dca6SLaurent Vivier         break; \
5742097dca6SLaurent Vivier     case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
575fad866daSMarkus Armbruster         qemu_printf("S"); \
5762097dca6SLaurent Vivier         break; \
5772097dca6SLaurent Vivier     case M68K_DESC_CM_NCACHE: /* noncachable */ \
578fad866daSMarkus Armbruster         qemu_printf("N"); \
5792097dca6SLaurent Vivier         break; \
5802097dca6SLaurent Vivier     }
5812097dca6SLaurent Vivier 
dump_ttr(uint32_t ttr)582fad866daSMarkus Armbruster static void dump_ttr(uint32_t ttr)
5832097dca6SLaurent Vivier {
5842097dca6SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
585fad866daSMarkus Armbruster         qemu_printf("disabled\n");
5862097dca6SLaurent Vivier         return;
5872097dca6SLaurent Vivier     }
588fad866daSMarkus Armbruster     qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ",
5892097dca6SLaurent Vivier                 ttr & M68K_TTR_ADDR_BASE,
5902097dca6SLaurent Vivier                 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
5912097dca6SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
5922097dca6SLaurent Vivier     case M68K_TTR_SFIELD_USER:
593fad866daSMarkus Armbruster         qemu_printf("U");
5942097dca6SLaurent Vivier         break;
5952097dca6SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
596fad866daSMarkus Armbruster         qemu_printf("S");
5972097dca6SLaurent Vivier         break;
5982097dca6SLaurent Vivier     default:
599fad866daSMarkus Armbruster         qemu_printf("*");
6002097dca6SLaurent Vivier         break;
6012097dca6SLaurent Vivier     }
6022097dca6SLaurent Vivier     DUMP_CACHEFLAGS(ttr);
6032097dca6SLaurent Vivier     if (ttr & M68K_DESC_WRITEPROT) {
604fad866daSMarkus Armbruster         qemu_printf("R");
6052097dca6SLaurent Vivier     } else {
606fad866daSMarkus Armbruster         qemu_printf("W");
6072097dca6SLaurent Vivier     }
608fad866daSMarkus Armbruster     qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >>
6092097dca6SLaurent Vivier                                M68K_DESC_USERATTR_SHIFT);
6102097dca6SLaurent Vivier }
6112097dca6SLaurent Vivier 
dump_mmu(CPUM68KState * env)612fad866daSMarkus Armbruster void dump_mmu(CPUM68KState *env)
6132097dca6SLaurent Vivier {
6142097dca6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
615fad866daSMarkus Armbruster         qemu_printf("Translation disabled\n");
6162097dca6SLaurent Vivier         return;
6172097dca6SLaurent Vivier     }
618fad866daSMarkus Armbruster     qemu_printf("Page Size: ");
6192097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
620fad866daSMarkus Armbruster         qemu_printf("8kB\n");
6212097dca6SLaurent Vivier     } else {
622fad866daSMarkus Armbruster         qemu_printf("4kB\n");
6232097dca6SLaurent Vivier     }
6242097dca6SLaurent Vivier 
625fad866daSMarkus Armbruster     qemu_printf("MMUSR: ");
6262097dca6SLaurent Vivier     if (env->mmu.mmusr & M68K_MMU_B_040) {
627fad866daSMarkus Armbruster         qemu_printf("BUS ERROR\n");
6282097dca6SLaurent Vivier     } else {
629fad866daSMarkus Armbruster         qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
6302097dca6SLaurent Vivier         /* flags found on the page descriptor */
6312097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_G_040) {
632fad866daSMarkus Armbruster             qemu_printf("G"); /* Global */
6332097dca6SLaurent Vivier         } else {
634fad866daSMarkus Armbruster             qemu_printf(".");
6352097dca6SLaurent Vivier         }
6362097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_S_040) {
637fad866daSMarkus Armbruster             qemu_printf("S"); /* Supervisor */
6382097dca6SLaurent Vivier         } else {
639fad866daSMarkus Armbruster             qemu_printf(".");
6402097dca6SLaurent Vivier         }
6412097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_M_040) {
642fad866daSMarkus Armbruster             qemu_printf("M"); /* Modified */
6432097dca6SLaurent Vivier         } else {
644fad866daSMarkus Armbruster             qemu_printf(".");
6452097dca6SLaurent Vivier         }
6462097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_WP_040) {
647fad866daSMarkus Armbruster             qemu_printf("W"); /* Write protect */
6482097dca6SLaurent Vivier         } else {
649fad866daSMarkus Armbruster             qemu_printf(".");
6502097dca6SLaurent Vivier         }
6512097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_T_040) {
652fad866daSMarkus Armbruster             qemu_printf("T"); /* Transparent */
6532097dca6SLaurent Vivier         } else {
654fad866daSMarkus Armbruster             qemu_printf(".");
6552097dca6SLaurent Vivier         }
6562097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_R_040) {
657fad866daSMarkus Armbruster             qemu_printf("R"); /* Resident */
6582097dca6SLaurent Vivier         } else {
659fad866daSMarkus Armbruster             qemu_printf(".");
6602097dca6SLaurent Vivier         }
661fad866daSMarkus Armbruster         qemu_printf(" Cache: ");
6622097dca6SLaurent Vivier         DUMP_CACHEFLAGS(env->mmu.mmusr);
663fad866daSMarkus Armbruster         qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3);
664fad866daSMarkus Armbruster         qemu_printf("\n");
6652097dca6SLaurent Vivier     }
6662097dca6SLaurent Vivier 
667fad866daSMarkus Armbruster     qemu_printf("ITTR0: ");
668fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_ITTR0]);
669fad866daSMarkus Armbruster     qemu_printf("ITTR1: ");
670fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_ITTR1]);
671fad866daSMarkus Armbruster     qemu_printf("DTTR0: ");
672fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_DTTR0]);
673fad866daSMarkus Armbruster     qemu_printf("DTTR1: ");
674fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_DTTR1]);
6752097dca6SLaurent Vivier 
676fad866daSMarkus Armbruster     qemu_printf("SRP: 0x%08x\n", env->mmu.srp);
677fad866daSMarkus Armbruster     dump_address_map(env, env->mmu.srp);
6782097dca6SLaurent Vivier 
679fad866daSMarkus Armbruster     qemu_printf("URP: 0x%08x\n", env->mmu.urp);
680fad866daSMarkus Armbruster     dump_address_map(env, env->mmu.urp);
6812097dca6SLaurent Vivier }
6822097dca6SLaurent Vivier 
check_TTR(uint32_t ttr,int * prot,target_ulong addr,int access_type)683c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
684c05c73b0SLaurent Vivier                      int access_type)
685c05c73b0SLaurent Vivier {
686c05c73b0SLaurent Vivier     uint32_t base, mask;
687c05c73b0SLaurent Vivier 
688c05c73b0SLaurent Vivier     /* check if transparent translation is enabled */
689c05c73b0SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
690c05c73b0SLaurent Vivier         return 0;
691c05c73b0SLaurent Vivier     }
692c05c73b0SLaurent Vivier 
693c05c73b0SLaurent Vivier     /* check mode access */
694c05c73b0SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
695c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_USER:
696c05c73b0SLaurent Vivier         /* match only if user */
697c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) != 0) {
698c05c73b0SLaurent Vivier             return 0;
699c05c73b0SLaurent Vivier         }
700c05c73b0SLaurent Vivier         break;
701c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
702c05c73b0SLaurent Vivier         /* match only if supervisor */
703c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
704c05c73b0SLaurent Vivier             return 0;
705c05c73b0SLaurent Vivier         }
706c05c73b0SLaurent Vivier         break;
707c05c73b0SLaurent Vivier     default:
708c05c73b0SLaurent Vivier         /* all other values disable mode matching (FC2) */
709c05c73b0SLaurent Vivier         break;
710c05c73b0SLaurent Vivier     }
711c05c73b0SLaurent Vivier 
712c05c73b0SLaurent Vivier     /* check address matching */
713c05c73b0SLaurent Vivier 
714c05c73b0SLaurent Vivier     base = ttr & M68K_TTR_ADDR_BASE;
715c05c73b0SLaurent Vivier     mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
716c05c73b0SLaurent Vivier     mask <<= M68K_TTR_ADDR_MASK_SHIFT;
717c05c73b0SLaurent Vivier 
718c05c73b0SLaurent Vivier     if ((addr & mask) != (base & mask)) {
719c05c73b0SLaurent Vivier         return 0;
720c05c73b0SLaurent Vivier     }
721c05c73b0SLaurent Vivier 
722c05c73b0SLaurent Vivier     *prot = PAGE_READ | PAGE_EXEC;
723c05c73b0SLaurent Vivier     if ((ttr & M68K_DESC_WRITEPROT) == 0) {
724c05c73b0SLaurent Vivier         *prot |= PAGE_WRITE;
725c05c73b0SLaurent Vivier     }
726c05c73b0SLaurent Vivier 
727c05c73b0SLaurent Vivier     return 1;
728c05c73b0SLaurent Vivier }
729c05c73b0SLaurent Vivier 
get_physical_address(CPUM68KState * env,hwaddr * physical,int * prot,target_ulong address,int access_type,target_ulong * page_size)73088b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical,
73188b2fef6SLaurent Vivier                                 int *prot, target_ulong address,
73288b2fef6SLaurent Vivier                                 int access_type, target_ulong *page_size)
73388b2fef6SLaurent Vivier {
734a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
73588b2fef6SLaurent Vivier     uint32_t entry;
73688b2fef6SLaurent Vivier     uint32_t next;
73788b2fef6SLaurent Vivier     target_ulong page_mask;
73888b2fef6SLaurent Vivier     bool debug = access_type & ACCESS_DEBUG;
73988b2fef6SLaurent Vivier     int page_bits;
740c05c73b0SLaurent Vivier     int i;
741adcf0bf0SPeter Maydell     MemTxResult txres;
742c05c73b0SLaurent Vivier 
743c05c73b0SLaurent Vivier     /* Transparent Translation (physical = logical) */
744c05c73b0SLaurent Vivier     for (i = 0; i < M68K_MAX_TTR; i++) {
745c05c73b0SLaurent Vivier         if (check_TTR(env->mmu.TTR(access_type, i),
746c05c73b0SLaurent Vivier                       prot, address, access_type)) {
747e55886c3SLaurent Vivier             if (access_type & ACCESS_PTEST) {
748e55886c3SLaurent Vivier                 /* Transparent Translation Register bit */
749e55886c3SLaurent Vivier                 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
750e55886c3SLaurent Vivier             }
751852002b5SMark Cave-Ayland             *physical = address;
752c05c73b0SLaurent Vivier             *page_size = TARGET_PAGE_SIZE;
753c05c73b0SLaurent Vivier             return 0;
754c05c73b0SLaurent Vivier         }
755c05c73b0SLaurent Vivier     }
75688b2fef6SLaurent Vivier 
75788b2fef6SLaurent Vivier     /* Page Table Root Pointer */
75888b2fef6SLaurent Vivier     *prot = PAGE_READ | PAGE_WRITE;
75988b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
76088b2fef6SLaurent Vivier         *prot |= PAGE_EXEC;
76188b2fef6SLaurent Vivier     }
76288b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
76388b2fef6SLaurent Vivier         next = env->mmu.srp;
76488b2fef6SLaurent Vivier     } else {
76588b2fef6SLaurent Vivier         next = env->mmu.urp;
76688b2fef6SLaurent Vivier     }
76788b2fef6SLaurent Vivier 
76888b2fef6SLaurent Vivier     /* Root Index */
76988b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
77088b2fef6SLaurent Vivier 
771adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
772adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
773adcf0bf0SPeter Maydell         goto txfail;
774adcf0bf0SPeter Maydell     }
77588b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
77688b2fef6SLaurent Vivier         return -1;
77788b2fef6SLaurent Vivier     }
77888b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
779adcf0bf0SPeter Maydell         address_space_stl(cs->as, entry, next | M68K_DESC_USED,
780adcf0bf0SPeter Maydell                           MEMTXATTRS_UNSPECIFIED, &txres);
781adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
782adcf0bf0SPeter Maydell             goto txfail;
783adcf0bf0SPeter Maydell         }
78488b2fef6SLaurent Vivier     }
78588b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
786e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
787e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
788e55886c3SLaurent Vivier         }
78988b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
79088b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
79188b2fef6SLaurent Vivier             return -1;
79288b2fef6SLaurent Vivier         }
79388b2fef6SLaurent Vivier     }
79488b2fef6SLaurent Vivier 
79588b2fef6SLaurent Vivier     /* Pointer Index */
79688b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
79788b2fef6SLaurent Vivier 
798adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
799adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
800adcf0bf0SPeter Maydell         goto txfail;
801adcf0bf0SPeter Maydell     }
80288b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
80388b2fef6SLaurent Vivier         return -1;
80488b2fef6SLaurent Vivier     }
80588b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
806adcf0bf0SPeter Maydell         address_space_stl(cs->as, entry, next | M68K_DESC_USED,
807adcf0bf0SPeter Maydell                           MEMTXATTRS_UNSPECIFIED, &txres);
808adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
809adcf0bf0SPeter Maydell             goto txfail;
810adcf0bf0SPeter Maydell         }
81188b2fef6SLaurent Vivier     }
81288b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
813e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
814e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
815e55886c3SLaurent Vivier         }
81688b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
81788b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
81888b2fef6SLaurent Vivier             return -1;
81988b2fef6SLaurent Vivier         }
82088b2fef6SLaurent Vivier     }
82188b2fef6SLaurent Vivier 
82288b2fef6SLaurent Vivier     /* Page Index */
82388b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
82488b2fef6SLaurent Vivier         entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
82588b2fef6SLaurent Vivier     } else {
82688b2fef6SLaurent Vivier         entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
82788b2fef6SLaurent Vivier     }
82888b2fef6SLaurent Vivier 
829adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
830adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
831adcf0bf0SPeter Maydell         goto txfail;
832adcf0bf0SPeter Maydell     }
83388b2fef6SLaurent Vivier 
83488b2fef6SLaurent Vivier     if (!M68K_PDT_VALID(next)) {
83588b2fef6SLaurent Vivier         return -1;
83688b2fef6SLaurent Vivier     }
83788b2fef6SLaurent Vivier     if (M68K_PDT_INDIRECT(next)) {
838adcf0bf0SPeter Maydell         next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next),
839adcf0bf0SPeter Maydell                                  MEMTXATTRS_UNSPECIFIED, &txres);
840adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
841adcf0bf0SPeter Maydell             goto txfail;
842adcf0bf0SPeter Maydell         }
84388b2fef6SLaurent Vivier     }
84488b2fef6SLaurent Vivier     if (access_type & ACCESS_STORE) {
84588b2fef6SLaurent Vivier         if (next & M68K_DESC_WRITEPROT) {
84688b2fef6SLaurent Vivier             if (!(next & M68K_DESC_USED) && !debug) {
847adcf0bf0SPeter Maydell                 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
848adcf0bf0SPeter Maydell                                   MEMTXATTRS_UNSPECIFIED, &txres);
849adcf0bf0SPeter Maydell                 if (txres != MEMTX_OK) {
850adcf0bf0SPeter Maydell                     goto txfail;
851adcf0bf0SPeter Maydell                 }
85288b2fef6SLaurent Vivier             }
85388b2fef6SLaurent Vivier         } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
85488b2fef6SLaurent Vivier                            (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
855adcf0bf0SPeter Maydell             address_space_stl(cs->as, entry,
856adcf0bf0SPeter Maydell                               next | (M68K_DESC_MODIFIED | M68K_DESC_USED),
857adcf0bf0SPeter Maydell                               MEMTXATTRS_UNSPECIFIED, &txres);
858adcf0bf0SPeter Maydell             if (txres != MEMTX_OK) {
859adcf0bf0SPeter Maydell                 goto txfail;
860adcf0bf0SPeter Maydell             }
86188b2fef6SLaurent Vivier         }
86288b2fef6SLaurent Vivier     } else {
86388b2fef6SLaurent Vivier         if (!(next & M68K_DESC_USED) && !debug) {
864adcf0bf0SPeter Maydell             address_space_stl(cs->as, entry, next | M68K_DESC_USED,
865adcf0bf0SPeter Maydell                               MEMTXATTRS_UNSPECIFIED, &txres);
866adcf0bf0SPeter Maydell             if (txres != MEMTX_OK) {
867adcf0bf0SPeter Maydell                 goto txfail;
868adcf0bf0SPeter Maydell             }
86988b2fef6SLaurent Vivier         }
87088b2fef6SLaurent Vivier     }
87188b2fef6SLaurent Vivier 
87288b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
87388b2fef6SLaurent Vivier         page_bits = 13;
87488b2fef6SLaurent Vivier     } else {
87588b2fef6SLaurent Vivier         page_bits = 12;
87688b2fef6SLaurent Vivier     }
87788b2fef6SLaurent Vivier     *page_size = 1 << page_bits;
87888b2fef6SLaurent Vivier     page_mask = ~(*page_size - 1);
879852002b5SMark Cave-Ayland     *physical = (next & page_mask) + (address & (*page_size - 1));
88088b2fef6SLaurent Vivier 
881e55886c3SLaurent Vivier     if (access_type & ACCESS_PTEST) {
882e55886c3SLaurent Vivier         env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
883e55886c3SLaurent Vivier         env->mmu.mmusr |= *physical & 0xfffff000;
884e55886c3SLaurent Vivier         env->mmu.mmusr |= M68K_MMU_R_040;
885e55886c3SLaurent Vivier     }
886e55886c3SLaurent Vivier 
88788b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
88888b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
88988b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
89088b2fef6SLaurent Vivier             return -1;
89188b2fef6SLaurent Vivier         }
89288b2fef6SLaurent Vivier     }
89388b2fef6SLaurent Vivier     if (next & M68K_DESC_SUPERONLY) {
89488b2fef6SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
89588b2fef6SLaurent Vivier             return -1;
89688b2fef6SLaurent Vivier         }
89788b2fef6SLaurent Vivier     }
89888b2fef6SLaurent Vivier 
89988b2fef6SLaurent Vivier     return 0;
900adcf0bf0SPeter Maydell 
901adcf0bf0SPeter Maydell txfail:
902adcf0bf0SPeter Maydell     /*
903adcf0bf0SPeter Maydell      * A page table load/store failed. TODO: we should really raise a
904adcf0bf0SPeter Maydell      * suitable guest fault here if this is not a debug access.
905adcf0bf0SPeter Maydell      * For now just return that the translation failed.
906adcf0bf0SPeter Maydell      */
907adcf0bf0SPeter Maydell     return -1;
90888b2fef6SLaurent Vivier }
90988b2fef6SLaurent Vivier 
m68k_cpu_get_phys_page_debug(CPUState * cs,vaddr addr)91000b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
9114fcc562bSPaul Brook {
912e22a4560SPhilippe Mathieu-Daudé     CPUM68KState *env = cpu_env(cs);
91388b2fef6SLaurent Vivier     hwaddr phys_addr;
91488b2fef6SLaurent Vivier     int prot;
91588b2fef6SLaurent Vivier     int access_type;
91688b2fef6SLaurent Vivier     target_ulong page_size;
91788b2fef6SLaurent Vivier 
91888b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
91988b2fef6SLaurent Vivier         /* MMU disabled */
9204fcc562bSPaul Brook         return addr;
9214fcc562bSPaul Brook     }
9224fcc562bSPaul Brook 
92388b2fef6SLaurent Vivier     access_type = ACCESS_DATA | ACCESS_DEBUG;
92488b2fef6SLaurent Vivier     if (env->sr & SR_S) {
92588b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
92688b2fef6SLaurent Vivier     }
92778318119SMark Cave-Ayland 
92888b2fef6SLaurent Vivier     if (get_physical_address(env, &phys_addr, &prot,
92988b2fef6SLaurent Vivier                              addr, access_type, &page_size) != 0) {
93088b2fef6SLaurent Vivier         return -1;
93188b2fef6SLaurent Vivier     }
93278318119SMark Cave-Ayland 
93388b2fef6SLaurent Vivier     return phys_addr;
93488b2fef6SLaurent Vivier }
93588b2fef6SLaurent Vivier 
936fe5f7b1bSRichard Henderson /*
937fe5f7b1bSRichard Henderson  * Notify CPU of a pending interrupt.  Prioritization and vectoring should
938fe5f7b1bSRichard Henderson  * be handled by the interrupt controller.  Real hardware only requests
939fe5f7b1bSRichard Henderson  * the vector when the interrupt is acknowledged by the CPU.  For
940fe5f7b1bSRichard Henderson  * simplicity we calculate it when the interrupt is signalled.
941fe5f7b1bSRichard Henderson  */
m68k_set_irq_level(M68kCPU * cpu,int level,uint8_t vector)942fe5f7b1bSRichard Henderson void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
943fe5f7b1bSRichard Henderson {
944fe5f7b1bSRichard Henderson     CPUState *cs = CPU(cpu);
945fe5f7b1bSRichard Henderson     CPUM68KState *env = &cpu->env;
946fe5f7b1bSRichard Henderson 
947fe5f7b1bSRichard Henderson     env->pending_level = level;
948fe5f7b1bSRichard Henderson     env->pending_vector = vector;
949fe5f7b1bSRichard Henderson     if (level) {
950fe5f7b1bSRichard Henderson         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
951fe5f7b1bSRichard Henderson     } else {
952fe5f7b1bSRichard Henderson         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
953fe5f7b1bSRichard Henderson     }
954fe5f7b1bSRichard Henderson }
955fe5f7b1bSRichard Henderson 
m68k_cpu_tlb_fill(CPUState * cs,vaddr address,int size,MMUAccessType qemu_access_type,int mmu_idx,bool probe,uintptr_t retaddr)956fe5f7b1bSRichard Henderson bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
957fe5f7b1bSRichard Henderson                        MMUAccessType qemu_access_type, int mmu_idx,
958fe5f7b1bSRichard Henderson                        bool probe, uintptr_t retaddr)
9590633879fSpbrook {
960e22a4560SPhilippe Mathieu-Daudé     CPUM68KState *env = cpu_env(cs);
96188b2fef6SLaurent Vivier     hwaddr physical;
9620633879fSpbrook     int prot;
96388b2fef6SLaurent Vivier     int access_type;
96488b2fef6SLaurent Vivier     int ret;
96588b2fef6SLaurent Vivier     target_ulong page_size;
9660633879fSpbrook 
96788b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
96888b2fef6SLaurent Vivier         /* MMU disabled */
96988b2fef6SLaurent Vivier         tlb_set_page(cs, address & TARGET_PAGE_MASK,
97088b2fef6SLaurent Vivier                      address & TARGET_PAGE_MASK,
97188b2fef6SLaurent Vivier                      PAGE_READ | PAGE_WRITE | PAGE_EXEC,
97288b2fef6SLaurent Vivier                      mmu_idx, TARGET_PAGE_SIZE);
973fe5f7b1bSRichard Henderson         return true;
9740633879fSpbrook     }
9750633879fSpbrook 
976fe5f7b1bSRichard Henderson     if (qemu_access_type == MMU_INST_FETCH) {
97788b2fef6SLaurent Vivier         access_type = ACCESS_CODE;
97888b2fef6SLaurent Vivier     } else {
97988b2fef6SLaurent Vivier         access_type = ACCESS_DATA;
980fe5f7b1bSRichard Henderson         if (qemu_access_type == MMU_DATA_STORE) {
98188b2fef6SLaurent Vivier             access_type |= ACCESS_STORE;
98288b2fef6SLaurent Vivier         }
98388b2fef6SLaurent Vivier     }
98488b2fef6SLaurent Vivier     if (mmu_idx != MMU_USER_IDX) {
98588b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
98688b2fef6SLaurent Vivier     }
98788b2fef6SLaurent Vivier 
988ee1004bbSPhilippe Mathieu-Daudé     ret = get_physical_address(env, &physical, &prot,
98988b2fef6SLaurent Vivier                                address, access_type, &page_size);
990fe5f7b1bSRichard Henderson     if (likely(ret == 0)) {
991852002b5SMark Cave-Ayland         tlb_set_page(cs, address & TARGET_PAGE_MASK,
992852002b5SMark Cave-Ayland                      physical & TARGET_PAGE_MASK, prot, mmu_idx, page_size);
993fe5f7b1bSRichard Henderson         return true;
99488b2fef6SLaurent Vivier     }
995fe5f7b1bSRichard Henderson 
996fe5f7b1bSRichard Henderson     if (probe) {
997fe5f7b1bSRichard Henderson         return false;
998fe5f7b1bSRichard Henderson     }
999fe5f7b1bSRichard Henderson 
100088b2fef6SLaurent Vivier     /* page fault */
100188b2fef6SLaurent Vivier     env->mmu.ssw = M68K_ATC_040;
100288b2fef6SLaurent Vivier     switch (size) {
100388b2fef6SLaurent Vivier     case 1:
100488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_BYTE;
100588b2fef6SLaurent Vivier         break;
100688b2fef6SLaurent Vivier     case 2:
100788b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_WORD;
100888b2fef6SLaurent Vivier         break;
100988b2fef6SLaurent Vivier     case 4:
101088b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_LONG;
101188b2fef6SLaurent Vivier         break;
101288b2fef6SLaurent Vivier     }
101388b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
101488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_SUPER;
101588b2fef6SLaurent Vivier     }
101688b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
101788b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_CODE;
101888b2fef6SLaurent Vivier     } else {
101988b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_DATA;
102088b2fef6SLaurent Vivier     }
102188b2fef6SLaurent Vivier     if (!(access_type & ACCESS_STORE)) {
102288b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_RW_040;
102388b2fef6SLaurent Vivier     }
1024fe5f7b1bSRichard Henderson 
102588b2fef6SLaurent Vivier     cs->exception_index = EXCP_ACCESS;
1026fe5f7b1bSRichard Henderson     env->mmu.ar = address;
1027fe5f7b1bSRichard Henderson     cpu_loop_exit_restore(cs, retaddr);
102888b2fef6SLaurent Vivier }
1029028772c4SRichard Henderson #endif /* !CONFIG_USER_ONLY */
103088b2fef6SLaurent Vivier 
HELPER(bitrev)1031e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x)
1032e1f3808eSpbrook {
1033e1f3808eSpbrook     x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
1034e1f3808eSpbrook     x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
1035e1f3808eSpbrook     x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
1036e1f3808eSpbrook     return bswap32(x);
1037e1f3808eSpbrook }
1038e1f3808eSpbrook 
HELPER(ff1)1039e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x)
1040e1f3808eSpbrook {
1041e1f3808eSpbrook     int n;
1042e1f3808eSpbrook     for (n = 32; x; n--)
1043e1f3808eSpbrook         x >>= 1;
1044e1f3808eSpbrook     return n;
1045e1f3808eSpbrook }
1046e1f3808eSpbrook 
HELPER(sats)1047620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v)
1048e1f3808eSpbrook {
1049e1f3808eSpbrook     /* The result has the opposite sign to the original value.  */
1050620c6cf6SRichard Henderson     if ((int32_t)v < 0) {
1051e1f3808eSpbrook         val = (((int32_t)val) >> 31) ^ SIGNBIT;
1052620c6cf6SRichard Henderson     }
1053e1f3808eSpbrook     return val;
1054e1f3808eSpbrook }
1055e1f3808eSpbrook 
cpu_m68k_set_sr(CPUM68KState * env,uint32_t sr)1056d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
1057e1f3808eSpbrook {
1058d2f8fb8eSLaurent Vivier     env->sr = sr & 0xffe0;
1059d2f8fb8eSLaurent Vivier     cpu_m68k_set_ccr(env, sr);
1060e1f3808eSpbrook     m68k_switch_sp(env);
1061e1f3808eSpbrook }
1062e1f3808eSpbrook 
HELPER(set_sr)1063d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
1064d2f8fb8eSLaurent Vivier {
1065d2f8fb8eSLaurent Vivier     cpu_m68k_set_sr(env, val);
1066d2f8fb8eSLaurent Vivier }
1067e1f3808eSpbrook 
1068e1f3808eSpbrook /* MAC unit.  */
1069808d77bcSLucien Murray-Pitts /*
1070808d77bcSLucien Murray-Pitts  * FIXME: The MAC unit implementation is a bit of a mess.  Some helpers
1071808d77bcSLucien Murray-Pitts  * take values,  others take register numbers and manipulate the contents
1072808d77bcSLucien Murray-Pitts  * in-place.
1073808d77bcSLucien Murray-Pitts  */
HELPER(mac_move)10742b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
1075e1f3808eSpbrook {
1076e1f3808eSpbrook     uint32_t mask;
1077e1f3808eSpbrook     env->macc[dest] = env->macc[src];
1078e1f3808eSpbrook     mask = MACSR_PAV0 << dest;
1079e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << src))
1080e1f3808eSpbrook         env->macsr |= mask;
1081e1f3808eSpbrook     else
1082e1f3808eSpbrook         env->macsr &= ~mask;
1083e1f3808eSpbrook }
1084e1f3808eSpbrook 
HELPER(macmuls)10852b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1086e1f3808eSpbrook {
1087e1f3808eSpbrook     int64_t product;
1088e1f3808eSpbrook     int64_t res;
1089e1f3808eSpbrook 
1090e1f3808eSpbrook     product = (uint64_t)op1 * op2;
1091e1f3808eSpbrook     res = (product << 24) >> 24;
1092e1f3808eSpbrook     if (res != product) {
1093e1f3808eSpbrook         env->macsr |= MACSR_V;
1094e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1095e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
1096e1f3808eSpbrook             if (product < 0)
1097e1f3808eSpbrook                 res = ~(1ll << 50);
1098e1f3808eSpbrook             else
1099e1f3808eSpbrook                 res = 1ll << 50;
1100e1f3808eSpbrook         }
1101e1f3808eSpbrook     }
1102e1f3808eSpbrook     return res;
1103e1f3808eSpbrook }
1104e1f3808eSpbrook 
HELPER(macmulu)11052b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1106e1f3808eSpbrook {
1107e1f3808eSpbrook     uint64_t product;
1108e1f3808eSpbrook 
1109e1f3808eSpbrook     product = (uint64_t)op1 * op2;
1110e1f3808eSpbrook     if (product & (0xffffffull << 40)) {
1111e1f3808eSpbrook         env->macsr |= MACSR_V;
1112e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1113e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
1114e1f3808eSpbrook             product = 1ll << 50;
1115e1f3808eSpbrook         } else {
1116e1f3808eSpbrook             product &= ((1ull << 40) - 1);
1117e1f3808eSpbrook         }
1118e1f3808eSpbrook     }
1119e1f3808eSpbrook     return product;
1120e1f3808eSpbrook }
1121e1f3808eSpbrook 
HELPER(macmulf)11222b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1123e1f3808eSpbrook {
1124e1f3808eSpbrook     uint64_t product;
1125e1f3808eSpbrook     uint32_t remainder;
1126e1f3808eSpbrook 
1127e1f3808eSpbrook     product = (uint64_t)op1 * op2;
1128e1f3808eSpbrook     if (env->macsr & MACSR_RT) {
1129e1f3808eSpbrook         remainder = product & 0xffffff;
1130e1f3808eSpbrook         product >>= 24;
1131e1f3808eSpbrook         if (remainder > 0x800000)
1132e1f3808eSpbrook             product++;
1133e1f3808eSpbrook         else if (remainder == 0x800000)
1134e1f3808eSpbrook             product += (product & 1);
1135e1f3808eSpbrook     } else {
1136e1f3808eSpbrook         product >>= 24;
1137e1f3808eSpbrook     }
1138e1f3808eSpbrook     return product;
1139e1f3808eSpbrook }
1140e1f3808eSpbrook 
HELPER(macsats)11412b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
1142e1f3808eSpbrook {
1143e1f3808eSpbrook     int64_t tmp;
1144e1f3808eSpbrook     int64_t result;
1145e1f3808eSpbrook     tmp = env->macc[acc];
1146e1f3808eSpbrook     result = ((tmp << 16) >> 16);
1147e1f3808eSpbrook     if (result != tmp) {
1148e1f3808eSpbrook         env->macsr |= MACSR_V;
1149e1f3808eSpbrook     }
1150e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1151e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1152e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1153808d77bcSLucien Murray-Pitts             /*
1154808d77bcSLucien Murray-Pitts              * The result is saturated to 32 bits, despite overflow occurring
1155808d77bcSLucien Murray-Pitts              * at 48 bits.  Seems weird, but that's what the hardware docs
1156808d77bcSLucien Murray-Pitts              * say.
1157808d77bcSLucien Murray-Pitts              */
1158e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffff;
1159e1f3808eSpbrook         }
1160e1f3808eSpbrook     }
1161e1f3808eSpbrook     env->macc[acc] = result;
1162e1f3808eSpbrook }
1163e1f3808eSpbrook 
HELPER(macsatu)11642b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1165e1f3808eSpbrook {
1166e1f3808eSpbrook     uint64_t val;
1167e1f3808eSpbrook 
1168e1f3808eSpbrook     val = env->macc[acc];
1169e1f3808eSpbrook     if (val & (0xffffull << 48)) {
1170e1f3808eSpbrook         env->macsr |= MACSR_V;
1171e1f3808eSpbrook     }
1172e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1173e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1174e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1175e1f3808eSpbrook             if (val > (1ull << 53))
1176e1f3808eSpbrook                 val = 0;
1177e1f3808eSpbrook             else
1178e1f3808eSpbrook                 val = (1ull << 48) - 1;
1179e1f3808eSpbrook         } else {
1180e1f3808eSpbrook             val &= ((1ull << 48) - 1);
1181e1f3808eSpbrook         }
1182e1f3808eSpbrook     }
1183e1f3808eSpbrook     env->macc[acc] = val;
1184e1f3808eSpbrook }
1185e1f3808eSpbrook 
HELPER(macsatf)11862b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1187e1f3808eSpbrook {
1188e1f3808eSpbrook     int64_t sum;
1189e1f3808eSpbrook     int64_t result;
1190e1f3808eSpbrook 
1191e1f3808eSpbrook     sum = env->macc[acc];
1192e1f3808eSpbrook     result = (sum << 16) >> 16;
1193e1f3808eSpbrook     if (result != sum) {
1194e1f3808eSpbrook         env->macsr |= MACSR_V;
1195e1f3808eSpbrook     }
1196e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1197e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1198e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1199e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffffffffll;
1200e1f3808eSpbrook         }
1201e1f3808eSpbrook     }
1202e1f3808eSpbrook     env->macc[acc] = result;
1203e1f3808eSpbrook }
1204e1f3808eSpbrook 
HELPER(mac_set_flags)12052b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1206e1f3808eSpbrook {
1207e1f3808eSpbrook     uint64_t val;
1208e1f3808eSpbrook     val = env->macc[acc];
1209c4162574SBlue Swirl     if (val == 0) {
1210e1f3808eSpbrook         env->macsr |= MACSR_Z;
1211c4162574SBlue Swirl     } else if (val & (1ull << 47)) {
1212e1f3808eSpbrook         env->macsr |= MACSR_N;
1213c4162574SBlue Swirl     }
1214e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << acc)) {
1215e1f3808eSpbrook         env->macsr |= MACSR_V;
1216e1f3808eSpbrook     }
1217e1f3808eSpbrook     if (env->macsr & MACSR_FI) {
1218e1f3808eSpbrook         val = ((int64_t)val) >> 40;
1219e1f3808eSpbrook         if (val != 0 && val != -1)
1220e1f3808eSpbrook             env->macsr |= MACSR_EV;
1221e1f3808eSpbrook     } else if (env->macsr & MACSR_SU) {
1222e1f3808eSpbrook         val = ((int64_t)val) >> 32;
1223e1f3808eSpbrook         if (val != 0 && val != -1)
1224e1f3808eSpbrook             env->macsr |= MACSR_EV;
1225e1f3808eSpbrook     } else {
1226e1f3808eSpbrook         if ((val >> 32) != 0)
1227e1f3808eSpbrook             env->macsr |= MACSR_EV;
1228e1f3808eSpbrook     }
1229e1f3808eSpbrook }
1230e1f3808eSpbrook 
1231db3d7945SLaurent Vivier #define EXTSIGN(val, index) (     \
1232db3d7945SLaurent Vivier     (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1233db3d7945SLaurent Vivier )
1234620c6cf6SRichard Henderson 
1235620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) {                                   \
1236620c6cf6SRichard Henderson     switch (op) {                                                          \
1237620c6cf6SRichard Henderson     case CC_OP_FLAGS:                                                      \
1238620c6cf6SRichard Henderson         /* Everything in place.  */                                        \
1239620c6cf6SRichard Henderson         break;                                                             \
1240db3d7945SLaurent Vivier     case CC_OP_ADDB:                                                       \
1241db3d7945SLaurent Vivier     case CC_OP_ADDW:                                                       \
1242db3d7945SLaurent Vivier     case CC_OP_ADDL:                                                       \
1243620c6cf6SRichard Henderson         res = n;                                                           \
1244620c6cf6SRichard Henderson         src2 = v;                                                          \
1245db3d7945SLaurent Vivier         src1 = EXTSIGN(res - src2, op - CC_OP_ADDB);                       \
1246620c6cf6SRichard Henderson         c = x;                                                             \
1247620c6cf6SRichard Henderson         z = n;                                                             \
1248620c6cf6SRichard Henderson         v = (res ^ src1) & ~(src1 ^ src2);                                 \
1249620c6cf6SRichard Henderson         break;                                                             \
1250db3d7945SLaurent Vivier     case CC_OP_SUBB:                                                       \
1251db3d7945SLaurent Vivier     case CC_OP_SUBW:                                                       \
1252db3d7945SLaurent Vivier     case CC_OP_SUBL:                                                       \
1253620c6cf6SRichard Henderson         res = n;                                                           \
1254620c6cf6SRichard Henderson         src2 = v;                                                          \
1255db3d7945SLaurent Vivier         src1 = EXTSIGN(res + src2, op - CC_OP_SUBB);                       \
1256620c6cf6SRichard Henderson         c = x;                                                             \
1257620c6cf6SRichard Henderson         z = n;                                                             \
1258620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1259620c6cf6SRichard Henderson         break;                                                             \
1260db3d7945SLaurent Vivier     case CC_OP_CMPB:                                                       \
1261db3d7945SLaurent Vivier     case CC_OP_CMPW:                                                       \
1262db3d7945SLaurent Vivier     case CC_OP_CMPL:                                                       \
1263620c6cf6SRichard Henderson         src1 = n;                                                          \
1264620c6cf6SRichard Henderson         src2 = v;                                                          \
1265db3d7945SLaurent Vivier         res = EXTSIGN(src1 - src2, op - CC_OP_CMPB);                       \
1266620c6cf6SRichard Henderson         n = res;                                                           \
1267620c6cf6SRichard Henderson         z = res;                                                           \
1268620c6cf6SRichard Henderson         c = src1 < src2;                                                   \
1269620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1270620c6cf6SRichard Henderson         break;                                                             \
1271620c6cf6SRichard Henderson     case CC_OP_LOGIC:                                                      \
1272620c6cf6SRichard Henderson         c = v = 0;                                                         \
1273620c6cf6SRichard Henderson         z = n;                                                             \
1274620c6cf6SRichard Henderson         break;                                                             \
1275620c6cf6SRichard Henderson     default:                                                               \
1276a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env), "Bad CC_OP %d", op);                       \
1277620c6cf6SRichard Henderson     }                                                                      \
1278620c6cf6SRichard Henderson } while (0)
1279620c6cf6SRichard Henderson 
cpu_m68k_get_ccr(CPUM68KState * env)1280620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1281e1f3808eSpbrook {
1282620c6cf6SRichard Henderson     uint32_t x, c, n, z, v;
1283620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1284620c6cf6SRichard Henderson 
1285620c6cf6SRichard Henderson     x = env->cc_x;
1286620c6cf6SRichard Henderson     n = env->cc_n;
1287620c6cf6SRichard Henderson     z = env->cc_z;
1288620c6cf6SRichard Henderson     v = env->cc_v;
1289db3d7945SLaurent Vivier     c = env->cc_c;
1290620c6cf6SRichard Henderson 
1291620c6cf6SRichard Henderson     COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1292620c6cf6SRichard Henderson 
1293620c6cf6SRichard Henderson     n = n >> 31;
1294620c6cf6SRichard Henderson     z = (z == 0);
1295db3d7945SLaurent Vivier     v = v >> 31;
1296620c6cf6SRichard Henderson 
1297620c6cf6SRichard Henderson     return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1298620c6cf6SRichard Henderson }
1299620c6cf6SRichard Henderson 
HELPER(get_ccr)1300620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env)
1301620c6cf6SRichard Henderson {
1302620c6cf6SRichard Henderson     return cpu_m68k_get_ccr(env);
1303620c6cf6SRichard Henderson }
1304620c6cf6SRichard Henderson 
cpu_m68k_set_ccr(CPUM68KState * env,uint32_t ccr)1305620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1306620c6cf6SRichard Henderson {
1307620c6cf6SRichard Henderson     env->cc_x = (ccr & CCF_X ? 1 : 0);
1308620c6cf6SRichard Henderson     env->cc_n = (ccr & CCF_N ? -1 : 0);
1309620c6cf6SRichard Henderson     env->cc_z = (ccr & CCF_Z ? 0 : 1);
1310620c6cf6SRichard Henderson     env->cc_v = (ccr & CCF_V ? -1 : 0);
1311620c6cf6SRichard Henderson     env->cc_c = (ccr & CCF_C ? 1 : 0);
1312620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1313620c6cf6SRichard Henderson }
1314620c6cf6SRichard Henderson 
HELPER(set_ccr)1315620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1316620c6cf6SRichard Henderson {
1317620c6cf6SRichard Henderson     cpu_m68k_set_ccr(env, ccr);
1318620c6cf6SRichard Henderson }
1319620c6cf6SRichard Henderson 
HELPER(flush_flags)1320620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1321620c6cf6SRichard Henderson {
1322620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1323620c6cf6SRichard Henderson 
1324620c6cf6SRichard Henderson     COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1325620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1326e1f3808eSpbrook }
1327e1f3808eSpbrook 
HELPER(get_macf)13282b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1329e1f3808eSpbrook {
1330e1f3808eSpbrook     int rem;
1331e1f3808eSpbrook     uint32_t result;
1332e1f3808eSpbrook 
1333e1f3808eSpbrook     if (env->macsr & MACSR_SU) {
1334e1f3808eSpbrook         /* 16-bit rounding.  */
1335e1f3808eSpbrook         rem = val & 0xffffff;
1336e1f3808eSpbrook         val = (val >> 24) & 0xffffu;
1337e1f3808eSpbrook         if (rem > 0x800000)
1338e1f3808eSpbrook             val++;
1339e1f3808eSpbrook         else if (rem == 0x800000)
1340e1f3808eSpbrook             val += (val & 1);
1341e1f3808eSpbrook     } else if (env->macsr & MACSR_RT) {
1342e1f3808eSpbrook         /* 32-bit rounding.  */
1343e1f3808eSpbrook         rem = val & 0xff;
1344e1f3808eSpbrook         val >>= 8;
1345e1f3808eSpbrook         if (rem > 0x80)
1346e1f3808eSpbrook             val++;
1347e1f3808eSpbrook         else if (rem == 0x80)
1348e1f3808eSpbrook             val += (val & 1);
1349e1f3808eSpbrook     } else {
1350e1f3808eSpbrook         /* No rounding.  */
1351e1f3808eSpbrook         val >>= 8;
1352e1f3808eSpbrook     }
1353e1f3808eSpbrook     if (env->macsr & MACSR_OMC) {
1354e1f3808eSpbrook         /* Saturate.  */
1355e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1356e1f3808eSpbrook             if (val != (uint16_t) val) {
1357e1f3808eSpbrook                 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1358e1f3808eSpbrook             } else {
1359e1f3808eSpbrook                 result = val & 0xffff;
1360e1f3808eSpbrook             }
1361e1f3808eSpbrook         } else {
1362e1f3808eSpbrook             if (val != (uint32_t)val) {
1363e1f3808eSpbrook                 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1364e1f3808eSpbrook             } else {
1365e1f3808eSpbrook                 result = (uint32_t)val;
1366e1f3808eSpbrook             }
1367e1f3808eSpbrook         }
1368e1f3808eSpbrook     } else {
1369e1f3808eSpbrook         /* No saturation.  */
1370e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1371e1f3808eSpbrook             result = val & 0xffff;
1372e1f3808eSpbrook         } else {
1373e1f3808eSpbrook             result = (uint32_t)val;
1374e1f3808eSpbrook         }
1375e1f3808eSpbrook     }
1376e1f3808eSpbrook     return result;
1377e1f3808eSpbrook }
1378e1f3808eSpbrook 
HELPER(get_macs)1379e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val)
1380e1f3808eSpbrook {
1381e1f3808eSpbrook     if (val == (int32_t)val) {
1382e1f3808eSpbrook         return (int32_t)val;
1383e1f3808eSpbrook     } else {
1384e1f3808eSpbrook         return (val >> 61) ^ ~SIGNBIT;
1385e1f3808eSpbrook     }
1386e1f3808eSpbrook }
1387e1f3808eSpbrook 
HELPER(get_macu)1388e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val)
1389e1f3808eSpbrook {
1390e1f3808eSpbrook     if ((val >> 32) == 0) {
1391e1f3808eSpbrook         return (uint32_t)val;
1392e1f3808eSpbrook     } else {
1393e1f3808eSpbrook         return 0xffffffffu;
1394e1f3808eSpbrook     }
1395e1f3808eSpbrook }
1396e1f3808eSpbrook 
HELPER(get_mac_extf)13972b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1398e1f3808eSpbrook {
1399e1f3808eSpbrook     uint32_t val;
1400e1f3808eSpbrook     val = env->macc[acc] & 0x00ff;
14015ce747cfSPaolo Bonzini     val |= (env->macc[acc] >> 32) & 0xff00;
1402e1f3808eSpbrook     val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1403e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1404e1f3808eSpbrook     return val;
1405e1f3808eSpbrook }
1406e1f3808eSpbrook 
HELPER(get_mac_exti)14072b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1408e1f3808eSpbrook {
1409e1f3808eSpbrook     uint32_t val;
1410e1f3808eSpbrook     val = (env->macc[acc] >> 32) & 0xffff;
1411e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1412e1f3808eSpbrook     return val;
1413e1f3808eSpbrook }
1414e1f3808eSpbrook 
HELPER(set_mac_extf)14152b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1416e1f3808eSpbrook {
1417e1f3808eSpbrook     int64_t res;
1418e1f3808eSpbrook     int32_t tmp;
1419e1f3808eSpbrook     res = env->macc[acc] & 0xffffffff00ull;
1420e1f3808eSpbrook     tmp = (int16_t)(val & 0xff00);
1421e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1422e1f3808eSpbrook     res |= val & 0xff;
1423e1f3808eSpbrook     env->macc[acc] = res;
1424e1f3808eSpbrook     res = env->macc[acc + 1] & 0xffffffff00ull;
1425e1f3808eSpbrook     tmp = (val & 0xff000000);
1426e1f3808eSpbrook     res |= ((int64_t)tmp) << 16;
1427e1f3808eSpbrook     res |= (val >> 16) & 0xff;
1428e1f3808eSpbrook     env->macc[acc + 1] = res;
1429e1f3808eSpbrook }
1430e1f3808eSpbrook 
HELPER(set_mac_exts)14312b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
1432e1f3808eSpbrook {
1433e1f3808eSpbrook     int64_t res;
1434e1f3808eSpbrook     int32_t tmp;
1435e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1436e1f3808eSpbrook     tmp = (int16_t)val;
1437e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1438e1f3808eSpbrook     env->macc[acc] = res;
1439e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1440e1f3808eSpbrook     tmp = val & 0xffff0000;
1441e1f3808eSpbrook     res |= (int64_t)tmp << 16;
1442e1f3808eSpbrook     env->macc[acc + 1] = res;
1443e1f3808eSpbrook }
1444e1f3808eSpbrook 
HELPER(set_mac_extu)14452b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
1446e1f3808eSpbrook {
1447e1f3808eSpbrook     uint64_t res;
1448e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1449e1f3808eSpbrook     res |= ((uint64_t)(val & 0xffff)) << 32;
1450e1f3808eSpbrook     env->macc[acc] = res;
1451e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1452e1f3808eSpbrook     res |= (uint64_t)(val & 0xffff0000) << 16;
1453e1f3808eSpbrook     env->macc[acc + 1] = res;
1454e1f3808eSpbrook }
14550bdb2b3bSLaurent Vivier 
14566a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
HELPER(ptest)1457e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1458e55886c3SLaurent Vivier {
1459e55886c3SLaurent Vivier     hwaddr physical;
1460e55886c3SLaurent Vivier     int access_type;
1461e55886c3SLaurent Vivier     int prot;
1462e55886c3SLaurent Vivier     int ret;
1463e55886c3SLaurent Vivier     target_ulong page_size;
1464e55886c3SLaurent Vivier 
1465e55886c3SLaurent Vivier     access_type = ACCESS_PTEST;
1466e55886c3SLaurent Vivier     if (env->dfc & 4) {
1467e55886c3SLaurent Vivier         access_type |= ACCESS_SUPER;
1468e55886c3SLaurent Vivier     }
1469e55886c3SLaurent Vivier     if ((env->dfc & 3) == 2) {
1470e55886c3SLaurent Vivier         access_type |= ACCESS_CODE;
1471e55886c3SLaurent Vivier     }
1472e55886c3SLaurent Vivier     if (!is_read) {
1473e55886c3SLaurent Vivier         access_type |= ACCESS_STORE;
1474e55886c3SLaurent Vivier     }
1475e55886c3SLaurent Vivier 
1476e55886c3SLaurent Vivier     env->mmu.mmusr = 0;
1477e55886c3SLaurent Vivier     env->mmu.ssw = 0;
1478e55886c3SLaurent Vivier     ret = get_physical_address(env, &physical, &prot, addr,
1479e55886c3SLaurent Vivier                                access_type, &page_size);
1480e55886c3SLaurent Vivier     if (ret == 0) {
1481852002b5SMark Cave-Ayland         tlb_set_page(env_cpu(env), addr & TARGET_PAGE_MASK,
1482852002b5SMark Cave-Ayland                      physical & TARGET_PAGE_MASK,
1483e55886c3SLaurent Vivier                      prot, access_type & ACCESS_SUPER ?
1484e55886c3SLaurent Vivier                      MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1485e55886c3SLaurent Vivier     }
1486e55886c3SLaurent Vivier }
1487e55886c3SLaurent Vivier 
HELPER(pflush)1488e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1489e55886c3SLaurent Vivier {
1490a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
1491e55886c3SLaurent Vivier 
1492e55886c3SLaurent Vivier     switch (opmode) {
1493e55886c3SLaurent Vivier     case 0: /* Flush page entry if not global */
1494e55886c3SLaurent Vivier     case 1: /* Flush page entry */
1495a8d92fd8SRichard Henderson         tlb_flush_page(cs, addr);
1496e55886c3SLaurent Vivier         break;
1497e55886c3SLaurent Vivier     case 2: /* Flush all except global entries */
1498a8d92fd8SRichard Henderson         tlb_flush(cs);
1499e55886c3SLaurent Vivier         break;
1500e55886c3SLaurent Vivier     case 3: /* Flush all entries */
1501a8d92fd8SRichard Henderson         tlb_flush(cs);
1502e55886c3SLaurent Vivier         break;
1503e55886c3SLaurent Vivier     }
1504e55886c3SLaurent Vivier }
1505e55886c3SLaurent Vivier 
HELPER(reset)15060bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env)
15070bdb2b3bSLaurent Vivier {
15080bdb2b3bSLaurent Vivier     /* FIXME: reset all except CPU */
15090bdb2b3bSLaurent Vivier }
15106a140586SPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */
1511