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" 2463c91552SPaolo Bonzini #include "exec/exec-all.h" 2574781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h" 26022c62cbSPaolo Bonzini #include "exec/gdbstub.h" 272ef6175aSRichard Henderson #include "exec/helper-proto.h" 28*342e313dSPierrick 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 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 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 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 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 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 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 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 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 return; 2958df0e6aeSLucien Murray-Pitts } 2968df0e6aeSLucien Murray-Pitts 2976e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) 2986e22b28eSLaurent Vivier { 2996e22b28eSLaurent Vivier switch (reg) { 30060d8e964SLucien Murray-Pitts /* MC680[12346]0 */ 3015fa9f1f2SLaurent Vivier case M68K_CR_SFC: 3025fa9f1f2SLaurent Vivier return env->sfc; 30360d8e964SLucien Murray-Pitts /* MC680[12346]0 */ 3045fa9f1f2SLaurent Vivier case M68K_CR_DFC: 3055fa9f1f2SLaurent Vivier return env->dfc; 30660d8e964SLucien Murray-Pitts /* MC680[12346]0 */ 3076e22b28eSLaurent Vivier case M68K_CR_VBR: 3086e22b28eSLaurent Vivier return env->vbr; 30960d8e964SLucien Murray-Pitts /* MC680[2346]0 */ 3106e22b28eSLaurent Vivier case M68K_CR_CACR: 3118df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68020) 3128df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68030) 3138df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68040) 3148df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68060)) { 3156e22b28eSLaurent Vivier return env->cacr; 3168df0e6aeSLucien Murray-Pitts } 3178df0e6aeSLucien Murray-Pitts break; 31860d8e964SLucien Murray-Pitts /* MC680[46]0 */ 31988b2fef6SLaurent Vivier case M68K_CR_TC: 3208df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68040) 3218df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68060)) { 32288b2fef6SLaurent Vivier return env->mmu.tcr; 3238df0e6aeSLucien Murray-Pitts } 3248df0e6aeSLucien Murray-Pitts break; 32560d8e964SLucien Murray-Pitts /* MC68040 */ 326e55886c3SLaurent Vivier case M68K_CR_MMUSR: 3278df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68040)) { 328e55886c3SLaurent Vivier return env->mmu.mmusr; 3298df0e6aeSLucien Murray-Pitts } 3308df0e6aeSLucien Murray-Pitts break; 33160d8e964SLucien Murray-Pitts /* MC680[46]0 */ 33288b2fef6SLaurent Vivier case M68K_CR_SRP: 3338df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68040) 3348df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68060)) { 33588b2fef6SLaurent Vivier return env->mmu.srp; 3368df0e6aeSLucien Murray-Pitts } 3378df0e6aeSLucien Murray-Pitts break; 3388df0e6aeSLucien Murray-Pitts /* MC68040/MC68LC040 */ 3398df0e6aeSLucien Murray-Pitts case M68K_CR_URP: 3408df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68040) 3418df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68060)) { 3428df0e6aeSLucien Murray-Pitts return env->mmu.urp; 3438df0e6aeSLucien Murray-Pitts } 3448df0e6aeSLucien Murray-Pitts break; 34560d8e964SLucien Murray-Pitts /* MC680[46]0 */ 3466e22b28eSLaurent Vivier case M68K_CR_USP: 3476e22b28eSLaurent Vivier return env->sp[M68K_USP]; 34860d8e964SLucien Murray-Pitts /* MC680[234]0 */ 3496e22b28eSLaurent Vivier case M68K_CR_MSP: 3508df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68020) 3518df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68030) 3528df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68040)) { 3536e22b28eSLaurent Vivier return env->sp[M68K_SSP]; 3548df0e6aeSLucien Murray-Pitts } 3558df0e6aeSLucien Murray-Pitts break; 35660d8e964SLucien Murray-Pitts /* MC680[234]0 */ 3576e22b28eSLaurent Vivier case M68K_CR_ISP: 3588df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68020) 3598df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68030) 3608df0e6aeSLucien Murray-Pitts || m68k_feature(env, M68K_FEATURE_M68040)) { 3616e22b28eSLaurent Vivier return env->sp[M68K_ISP]; 3628df0e6aeSLucien Murray-Pitts } 3638df0e6aeSLucien Murray-Pitts break; 36460d8e964SLucien Murray-Pitts /* MC68040/MC68LC040 */ 36560d8e964SLucien Murray-Pitts case M68K_CR_ITT0: /* MC68EC040 only: M68K_CR_IACR0 */ 3668df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68040)) { 367c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_ITTR0]; 3688df0e6aeSLucien Murray-Pitts } 3698df0e6aeSLucien Murray-Pitts break; 37060d8e964SLucien Murray-Pitts /* MC68040/MC68LC040 */ 37160d8e964SLucien Murray-Pitts case M68K_CR_ITT1: /* MC68EC040 only: M68K_CR_IACR1 */ 3728df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68040)) { 373c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_ITTR1]; 3748df0e6aeSLucien Murray-Pitts } 3758df0e6aeSLucien Murray-Pitts break; 37660d8e964SLucien Murray-Pitts /* MC68040/MC68LC040 */ 37760d8e964SLucien Murray-Pitts case M68K_CR_DTT0: /* MC68EC040 only: M68K_CR_DACR0 */ 3788df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68040)) { 379c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_DTTR0]; 3808df0e6aeSLucien Murray-Pitts } 3818df0e6aeSLucien Murray-Pitts break; 38260d8e964SLucien Murray-Pitts /* MC68040/MC68LC040 */ 38360d8e964SLucien Murray-Pitts case M68K_CR_DTT1: /* MC68EC040 only: M68K_CR_DACR1 */ 3848df0e6aeSLucien Murray-Pitts if (m68k_feature(env, M68K_FEATURE_M68040)) { 385c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_DTTR1]; 3868df0e6aeSLucien Murray-Pitts } 3878df0e6aeSLucien Murray-Pitts break; 3885736526cSLucien Murray-Pitts /* Unimplemented Registers */ 3895736526cSLucien Murray-Pitts case M68K_CR_CAAR: 3905736526cSLucien Murray-Pitts case M68K_CR_PCR: 3915736526cSLucien Murray-Pitts case M68K_CR_BUSCR: 392a8d92fd8SRichard Henderson cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n", 3936e22b28eSLaurent Vivier reg); 3940633879fSpbrook } 3950633879fSpbrook 3968df0e6aeSLucien Murray-Pitts /* Invalid control registers will generate an exception. */ 3978df0e6aeSLucien Murray-Pitts raise_exception_ra(env, EXCP_ILLEGAL, 0); 3988df0e6aeSLucien Murray-Pitts 3998df0e6aeSLucien Murray-Pitts return 0; 4008df0e6aeSLucien Murray-Pitts } 4018df0e6aeSLucien Murray-Pitts 402e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) 403acf930aaSpbrook { 404acf930aaSpbrook uint32_t acc; 405acf930aaSpbrook int8_t exthigh; 406acf930aaSpbrook uint8_t extlow; 407acf930aaSpbrook uint64_t regval; 408acf930aaSpbrook int i; 409acf930aaSpbrook if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { 410acf930aaSpbrook for (i = 0; i < 4; i++) { 411acf930aaSpbrook regval = env->macc[i]; 412acf930aaSpbrook exthigh = regval >> 40; 413acf930aaSpbrook if (env->macsr & MACSR_FI) { 414acf930aaSpbrook acc = regval >> 8; 415acf930aaSpbrook extlow = regval; 416acf930aaSpbrook } else { 417acf930aaSpbrook acc = regval; 418acf930aaSpbrook extlow = regval >> 32; 419acf930aaSpbrook } 420acf930aaSpbrook if (env->macsr & MACSR_FI) { 421acf930aaSpbrook regval = (((uint64_t)acc) << 8) | extlow; 422acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 423acf930aaSpbrook } else if (env->macsr & MACSR_SU) { 424acf930aaSpbrook regval = acc | (((int64_t)extlow) << 32); 425acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 426acf930aaSpbrook } else { 427acf930aaSpbrook regval = acc | (((uint64_t)extlow) << 32); 428acf930aaSpbrook regval |= ((uint64_t)(uint8_t)exthigh) << 40; 429acf930aaSpbrook } 430acf930aaSpbrook env->macc[i] = regval; 431acf930aaSpbrook } 432acf930aaSpbrook } 433acf930aaSpbrook env->macsr = val; 434acf930aaSpbrook } 435acf930aaSpbrook 43620dcee94Spbrook void m68k_switch_sp(CPUM68KState *env) 43720dcee94Spbrook { 43820dcee94Spbrook int new_sp; 43920dcee94Spbrook 44020dcee94Spbrook env->sp[env->current_sp] = env->aregs[7]; 441aece90d8SMark Cave-Ayland if (m68k_feature(env, M68K_FEATURE_M68K)) { 4426e22b28eSLaurent Vivier if (env->sr & SR_S) { 4437525a9b9SLucien Murray-Pitts /* SR:Master-Mode bit unimplemented then ISP is not available */ 4447525a9b9SLucien Murray-Pitts if (!m68k_feature(env, M68K_FEATURE_MSP) || env->sr & SR_M) { 4456e22b28eSLaurent Vivier new_sp = M68K_SSP; 4466e22b28eSLaurent Vivier } else { 4476e22b28eSLaurent Vivier new_sp = M68K_ISP; 4486e22b28eSLaurent Vivier } 4496e22b28eSLaurent Vivier } else { 4506e22b28eSLaurent Vivier new_sp = M68K_USP; 4516e22b28eSLaurent Vivier } 4526e22b28eSLaurent Vivier } else { 45320dcee94Spbrook new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) 45420dcee94Spbrook ? M68K_SSP : M68K_USP; 4556e22b28eSLaurent Vivier } 45620dcee94Spbrook env->aregs[7] = env->sp[new_sp]; 45720dcee94Spbrook env->current_sp = new_sp; 45820dcee94Spbrook } 45920dcee94Spbrook 460fe5f7b1bSRichard Henderson #if !defined(CONFIG_USER_ONLY) 46188b2fef6SLaurent Vivier /* MMU: 68040 only */ 4624fcc562bSPaul Brook 463fad866daSMarkus Armbruster static void print_address_zone(uint32_t logical, uint32_t physical, 4642097dca6SLaurent Vivier uint32_t size, int attr) 4652097dca6SLaurent Vivier { 466fad866daSMarkus Armbruster qemu_printf("%08x - %08x -> %08x - %08x %c ", 4672097dca6SLaurent Vivier logical, logical + size - 1, 4682097dca6SLaurent Vivier physical, physical + size - 1, 4692097dca6SLaurent Vivier attr & 4 ? 'W' : '-'); 4702097dca6SLaurent Vivier size >>= 10; 4712097dca6SLaurent Vivier if (size < 1024) { 472fad866daSMarkus Armbruster qemu_printf("(%d KiB)\n", size); 4732097dca6SLaurent Vivier } else { 4742097dca6SLaurent Vivier size >>= 10; 4752097dca6SLaurent Vivier if (size < 1024) { 476fad866daSMarkus Armbruster qemu_printf("(%d MiB)\n", size); 4772097dca6SLaurent Vivier } else { 4782097dca6SLaurent Vivier size >>= 10; 479fad866daSMarkus Armbruster qemu_printf("(%d GiB)\n", size); 4802097dca6SLaurent Vivier } 4812097dca6SLaurent Vivier } 4822097dca6SLaurent Vivier } 4832097dca6SLaurent Vivier 484fad866daSMarkus Armbruster static void dump_address_map(CPUM68KState *env, uint32_t root_pointer) 4852097dca6SLaurent Vivier { 4862097dca6SLaurent Vivier int tic_size, tic_shift; 4872097dca6SLaurent Vivier uint32_t tib_mask; 4882097dca6SLaurent Vivier uint32_t tia, tib, tic; 4892097dca6SLaurent Vivier uint32_t logical = 0xffffffff, physical = 0xffffffff; 4902097dca6SLaurent Vivier uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff; 4912097dca6SLaurent Vivier uint32_t last_logical, last_physical; 4922097dca6SLaurent Vivier int32_t size; 4932097dca6SLaurent Vivier int last_attr = -1, attr = -1; 494a8d92fd8SRichard Henderson CPUState *cs = env_cpu(env); 495f80b551dSPeter Maydell MemTxResult txres; 4962097dca6SLaurent Vivier 4972097dca6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 4982097dca6SLaurent Vivier /* 8k page */ 4992097dca6SLaurent Vivier tic_size = 32; 5002097dca6SLaurent Vivier tic_shift = 13; 5012097dca6SLaurent Vivier tib_mask = M68K_8K_PAGE_MASK; 5022097dca6SLaurent Vivier } else { 5032097dca6SLaurent Vivier /* 4k page */ 5042097dca6SLaurent Vivier tic_size = 64; 5052097dca6SLaurent Vivier tic_shift = 12; 5062097dca6SLaurent Vivier tib_mask = M68K_4K_PAGE_MASK; 5072097dca6SLaurent Vivier } 5087d01623aSPeter Maydell for (unsigned i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) { 509f80b551dSPeter Maydell tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4, 510f80b551dSPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 511f80b551dSPeter Maydell if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) { 5122097dca6SLaurent Vivier continue; 5132097dca6SLaurent Vivier } 5147d01623aSPeter Maydell for (unsigned j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) { 515f80b551dSPeter Maydell tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4, 516f80b551dSPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 517f80b551dSPeter Maydell if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) { 5182097dca6SLaurent Vivier continue; 5192097dca6SLaurent Vivier } 5207d01623aSPeter Maydell for (unsigned k = 0; k < tic_size; k++) { 521f80b551dSPeter Maydell tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4, 522f80b551dSPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 523f80b551dSPeter Maydell if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) { 5242097dca6SLaurent Vivier continue; 5252097dca6SLaurent Vivier } 5262097dca6SLaurent Vivier if (M68K_PDT_INDIRECT(tic)) { 527f80b551dSPeter Maydell tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic), 528f80b551dSPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 529f80b551dSPeter Maydell if (txres != MEMTX_OK) { 530f80b551dSPeter Maydell continue; 531f80b551dSPeter Maydell } 5322097dca6SLaurent Vivier } 5332097dca6SLaurent Vivier 5342097dca6SLaurent Vivier last_logical = logical; 5352097dca6SLaurent Vivier logical = (i << M68K_TTS_ROOT_SHIFT) | 5362097dca6SLaurent Vivier (j << M68K_TTS_POINTER_SHIFT) | 5372097dca6SLaurent Vivier (k << tic_shift); 5382097dca6SLaurent Vivier 5392097dca6SLaurent Vivier last_physical = physical; 5402097dca6SLaurent Vivier physical = tic & ~((1 << tic_shift) - 1); 5412097dca6SLaurent Vivier 5422097dca6SLaurent Vivier last_attr = attr; 5432097dca6SLaurent Vivier attr = tic & ((1 << tic_shift) - 1); 5442097dca6SLaurent Vivier 5452097dca6SLaurent Vivier if ((logical != (last_logical + (1 << tic_shift))) || 5462097dca6SLaurent Vivier (physical != (last_physical + (1 << tic_shift))) || 5472097dca6SLaurent Vivier (attr & 4) != (last_attr & 4)) { 5482097dca6SLaurent Vivier 5492097dca6SLaurent Vivier if (first_logical != 0xffffffff) { 5502097dca6SLaurent Vivier size = last_logical + (1 << tic_shift) - 5512097dca6SLaurent Vivier first_logical; 552fad866daSMarkus Armbruster print_address_zone(first_logical, 5532097dca6SLaurent Vivier first_physical, size, last_attr); 5542097dca6SLaurent Vivier } 5552097dca6SLaurent Vivier first_logical = logical; 5562097dca6SLaurent Vivier first_physical = physical; 5572097dca6SLaurent Vivier } 5582097dca6SLaurent Vivier } 5592097dca6SLaurent Vivier } 5602097dca6SLaurent Vivier } 5612097dca6SLaurent Vivier if (first_logical != logical || (attr & 4) != (last_attr & 4)) { 5622097dca6SLaurent Vivier size = logical + (1 << tic_shift) - first_logical; 563fad866daSMarkus Armbruster print_address_zone(first_logical, first_physical, size, last_attr); 5642097dca6SLaurent Vivier } 5652097dca6SLaurent Vivier } 5662097dca6SLaurent Vivier 5672097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \ 5682097dca6SLaurent Vivier switch (a & M68K_DESC_CACHEMODE) { \ 5698b81968cSMichael Tokarev case M68K_DESC_CM_WRTHRU: /* cacheable, write-through */ \ 570fad866daSMarkus Armbruster qemu_printf("T"); \ 5712097dca6SLaurent Vivier break; \ 5728b81968cSMichael Tokarev case M68K_DESC_CM_COPYBK: /* cacheable, copyback */ \ 573fad866daSMarkus Armbruster qemu_printf("C"); \ 5742097dca6SLaurent Vivier break; \ 5752097dca6SLaurent Vivier case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \ 576fad866daSMarkus Armbruster qemu_printf("S"); \ 5772097dca6SLaurent Vivier break; \ 5782097dca6SLaurent Vivier case M68K_DESC_CM_NCACHE: /* noncachable */ \ 579fad866daSMarkus Armbruster qemu_printf("N"); \ 5802097dca6SLaurent Vivier break; \ 5812097dca6SLaurent Vivier } 5822097dca6SLaurent Vivier 583fad866daSMarkus Armbruster static void dump_ttr(uint32_t ttr) 5842097dca6SLaurent Vivier { 5852097dca6SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 586fad866daSMarkus Armbruster qemu_printf("disabled\n"); 5872097dca6SLaurent Vivier return; 5882097dca6SLaurent Vivier } 589fad866daSMarkus Armbruster qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ", 5902097dca6SLaurent Vivier ttr & M68K_TTR_ADDR_BASE, 5912097dca6SLaurent Vivier (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT); 5922097dca6SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 5932097dca6SLaurent Vivier case M68K_TTR_SFIELD_USER: 594fad866daSMarkus Armbruster qemu_printf("U"); 5952097dca6SLaurent Vivier break; 5962097dca6SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 597fad866daSMarkus Armbruster qemu_printf("S"); 5982097dca6SLaurent Vivier break; 5992097dca6SLaurent Vivier default: 600fad866daSMarkus Armbruster qemu_printf("*"); 6012097dca6SLaurent Vivier break; 6022097dca6SLaurent Vivier } 6032097dca6SLaurent Vivier DUMP_CACHEFLAGS(ttr); 6042097dca6SLaurent Vivier if (ttr & M68K_DESC_WRITEPROT) { 605fad866daSMarkus Armbruster qemu_printf("R"); 6062097dca6SLaurent Vivier } else { 607fad866daSMarkus Armbruster qemu_printf("W"); 6082097dca6SLaurent Vivier } 609fad866daSMarkus Armbruster qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >> 6102097dca6SLaurent Vivier M68K_DESC_USERATTR_SHIFT); 6112097dca6SLaurent Vivier } 6122097dca6SLaurent Vivier 613fad866daSMarkus Armbruster void dump_mmu(CPUM68KState *env) 6142097dca6SLaurent Vivier { 6152097dca6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 616fad866daSMarkus Armbruster qemu_printf("Translation disabled\n"); 6172097dca6SLaurent Vivier return; 6182097dca6SLaurent Vivier } 619fad866daSMarkus Armbruster qemu_printf("Page Size: "); 6202097dca6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 621fad866daSMarkus Armbruster qemu_printf("8kB\n"); 6222097dca6SLaurent Vivier } else { 623fad866daSMarkus Armbruster qemu_printf("4kB\n"); 6242097dca6SLaurent Vivier } 6252097dca6SLaurent Vivier 626fad866daSMarkus Armbruster qemu_printf("MMUSR: "); 6272097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_B_040) { 628fad866daSMarkus Armbruster qemu_printf("BUS ERROR\n"); 6292097dca6SLaurent Vivier } else { 630fad866daSMarkus Armbruster qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000); 6312097dca6SLaurent Vivier /* flags found on the page descriptor */ 6322097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_G_040) { 633fad866daSMarkus Armbruster qemu_printf("G"); /* Global */ 6342097dca6SLaurent Vivier } else { 635fad866daSMarkus Armbruster qemu_printf("."); 6362097dca6SLaurent Vivier } 6372097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_S_040) { 638fad866daSMarkus Armbruster qemu_printf("S"); /* Supervisor */ 6392097dca6SLaurent Vivier } else { 640fad866daSMarkus Armbruster qemu_printf("."); 6412097dca6SLaurent Vivier } 6422097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_M_040) { 643fad866daSMarkus Armbruster qemu_printf("M"); /* Modified */ 6442097dca6SLaurent Vivier } else { 645fad866daSMarkus Armbruster qemu_printf("."); 6462097dca6SLaurent Vivier } 6472097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_WP_040) { 648fad866daSMarkus Armbruster qemu_printf("W"); /* Write protect */ 6492097dca6SLaurent Vivier } else { 650fad866daSMarkus Armbruster qemu_printf("."); 6512097dca6SLaurent Vivier } 6522097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_T_040) { 653fad866daSMarkus Armbruster qemu_printf("T"); /* Transparent */ 6542097dca6SLaurent Vivier } else { 655fad866daSMarkus Armbruster qemu_printf("."); 6562097dca6SLaurent Vivier } 6572097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_R_040) { 658fad866daSMarkus Armbruster qemu_printf("R"); /* Resident */ 6592097dca6SLaurent Vivier } else { 660fad866daSMarkus Armbruster qemu_printf("."); 6612097dca6SLaurent Vivier } 662fad866daSMarkus Armbruster qemu_printf(" Cache: "); 6632097dca6SLaurent Vivier DUMP_CACHEFLAGS(env->mmu.mmusr); 664fad866daSMarkus Armbruster qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3); 665fad866daSMarkus Armbruster qemu_printf("\n"); 6662097dca6SLaurent Vivier } 6672097dca6SLaurent Vivier 668fad866daSMarkus Armbruster qemu_printf("ITTR0: "); 669fad866daSMarkus Armbruster dump_ttr(env->mmu.ttr[M68K_ITTR0]); 670fad866daSMarkus Armbruster qemu_printf("ITTR1: "); 671fad866daSMarkus Armbruster dump_ttr(env->mmu.ttr[M68K_ITTR1]); 672fad866daSMarkus Armbruster qemu_printf("DTTR0: "); 673fad866daSMarkus Armbruster dump_ttr(env->mmu.ttr[M68K_DTTR0]); 674fad866daSMarkus Armbruster qemu_printf("DTTR1: "); 675fad866daSMarkus Armbruster dump_ttr(env->mmu.ttr[M68K_DTTR1]); 6762097dca6SLaurent Vivier 677fad866daSMarkus Armbruster qemu_printf("SRP: 0x%08x\n", env->mmu.srp); 678fad866daSMarkus Armbruster dump_address_map(env, env->mmu.srp); 6792097dca6SLaurent Vivier 680fad866daSMarkus Armbruster qemu_printf("URP: 0x%08x\n", env->mmu.urp); 681fad866daSMarkus Armbruster dump_address_map(env, env->mmu.urp); 6822097dca6SLaurent Vivier } 6832097dca6SLaurent Vivier 684c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr, 685c05c73b0SLaurent Vivier int access_type) 686c05c73b0SLaurent Vivier { 687c05c73b0SLaurent Vivier uint32_t base, mask; 688c05c73b0SLaurent Vivier 689c05c73b0SLaurent Vivier /* check if transparent translation is enabled */ 690c05c73b0SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 691c05c73b0SLaurent Vivier return 0; 692c05c73b0SLaurent Vivier } 693c05c73b0SLaurent Vivier 694c05c73b0SLaurent Vivier /* check mode access */ 695c05c73b0SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 696c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_USER: 697c05c73b0SLaurent Vivier /* match only if user */ 698c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) != 0) { 699c05c73b0SLaurent Vivier return 0; 700c05c73b0SLaurent Vivier } 701c05c73b0SLaurent Vivier break; 702c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 703c05c73b0SLaurent Vivier /* match only if supervisor */ 704c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 705c05c73b0SLaurent Vivier return 0; 706c05c73b0SLaurent Vivier } 707c05c73b0SLaurent Vivier break; 708c05c73b0SLaurent Vivier default: 709c05c73b0SLaurent Vivier /* all other values disable mode matching (FC2) */ 710c05c73b0SLaurent Vivier break; 711c05c73b0SLaurent Vivier } 712c05c73b0SLaurent Vivier 713c05c73b0SLaurent Vivier /* check address matching */ 714c05c73b0SLaurent Vivier 715c05c73b0SLaurent Vivier base = ttr & M68K_TTR_ADDR_BASE; 716c05c73b0SLaurent Vivier mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK; 717c05c73b0SLaurent Vivier mask <<= M68K_TTR_ADDR_MASK_SHIFT; 718c05c73b0SLaurent Vivier 719c05c73b0SLaurent Vivier if ((addr & mask) != (base & mask)) { 720c05c73b0SLaurent Vivier return 0; 721c05c73b0SLaurent Vivier } 722c05c73b0SLaurent Vivier 723c05c73b0SLaurent Vivier *prot = PAGE_READ | PAGE_EXEC; 724c05c73b0SLaurent Vivier if ((ttr & M68K_DESC_WRITEPROT) == 0) { 725c05c73b0SLaurent Vivier *prot |= PAGE_WRITE; 726c05c73b0SLaurent Vivier } 727c05c73b0SLaurent Vivier 728c05c73b0SLaurent Vivier return 1; 729c05c73b0SLaurent Vivier } 730c05c73b0SLaurent Vivier 73188b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical, 73288b2fef6SLaurent Vivier int *prot, target_ulong address, 73388b2fef6SLaurent Vivier int access_type, target_ulong *page_size) 73488b2fef6SLaurent Vivier { 735a8d92fd8SRichard Henderson CPUState *cs = env_cpu(env); 73688b2fef6SLaurent Vivier uint32_t entry; 73788b2fef6SLaurent Vivier uint32_t next; 73888b2fef6SLaurent Vivier target_ulong page_mask; 73988b2fef6SLaurent Vivier bool debug = access_type & ACCESS_DEBUG; 74088b2fef6SLaurent Vivier int page_bits; 741c05c73b0SLaurent Vivier int i; 742adcf0bf0SPeter Maydell MemTxResult txres; 743c05c73b0SLaurent Vivier 744c05c73b0SLaurent Vivier /* Transparent Translation (physical = logical) */ 745c05c73b0SLaurent Vivier for (i = 0; i < M68K_MAX_TTR; i++) { 746c05c73b0SLaurent Vivier if (check_TTR(env->mmu.TTR(access_type, i), 747c05c73b0SLaurent Vivier prot, address, access_type)) { 748e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 749e55886c3SLaurent Vivier /* Transparent Translation Register bit */ 750e55886c3SLaurent Vivier env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040; 751e55886c3SLaurent Vivier } 752852002b5SMark Cave-Ayland *physical = address; 753c05c73b0SLaurent Vivier *page_size = TARGET_PAGE_SIZE; 754c05c73b0SLaurent Vivier return 0; 755c05c73b0SLaurent Vivier } 756c05c73b0SLaurent Vivier } 75788b2fef6SLaurent Vivier 75888b2fef6SLaurent Vivier /* Page Table Root Pointer */ 75988b2fef6SLaurent Vivier *prot = PAGE_READ | PAGE_WRITE; 76088b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 76188b2fef6SLaurent Vivier *prot |= PAGE_EXEC; 76288b2fef6SLaurent Vivier } 76388b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 76488b2fef6SLaurent Vivier next = env->mmu.srp; 76588b2fef6SLaurent Vivier } else { 76688b2fef6SLaurent Vivier next = env->mmu.urp; 76788b2fef6SLaurent Vivier } 76888b2fef6SLaurent Vivier 76988b2fef6SLaurent Vivier /* Root Index */ 77088b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address); 77188b2fef6SLaurent Vivier 772adcf0bf0SPeter Maydell next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres); 773adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 774adcf0bf0SPeter Maydell goto txfail; 775adcf0bf0SPeter Maydell } 77688b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 77788b2fef6SLaurent Vivier return -1; 77888b2fef6SLaurent Vivier } 77988b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 780adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, next | M68K_DESC_USED, 781adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 782adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 783adcf0bf0SPeter Maydell goto txfail; 784adcf0bf0SPeter Maydell } 78588b2fef6SLaurent Vivier } 78688b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 787e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 788e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_WP_040; 789e55886c3SLaurent Vivier } 79088b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 79188b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 79288b2fef6SLaurent Vivier return -1; 79388b2fef6SLaurent Vivier } 79488b2fef6SLaurent Vivier } 79588b2fef6SLaurent Vivier 79688b2fef6SLaurent Vivier /* Pointer Index */ 79788b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address); 79888b2fef6SLaurent Vivier 799adcf0bf0SPeter Maydell next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres); 800adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 801adcf0bf0SPeter Maydell goto txfail; 802adcf0bf0SPeter Maydell } 80388b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 80488b2fef6SLaurent Vivier return -1; 80588b2fef6SLaurent Vivier } 80688b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 807adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, next | M68K_DESC_USED, 808adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 809adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 810adcf0bf0SPeter Maydell goto txfail; 811adcf0bf0SPeter Maydell } 81288b2fef6SLaurent Vivier } 81388b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 814e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 815e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_WP_040; 816e55886c3SLaurent Vivier } 81788b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 81888b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 81988b2fef6SLaurent Vivier return -1; 82088b2fef6SLaurent Vivier } 82188b2fef6SLaurent Vivier } 82288b2fef6SLaurent Vivier 82388b2fef6SLaurent Vivier /* Page Index */ 82488b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 82588b2fef6SLaurent Vivier entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address); 82688b2fef6SLaurent Vivier } else { 82788b2fef6SLaurent Vivier entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address); 82888b2fef6SLaurent Vivier } 82988b2fef6SLaurent Vivier 830adcf0bf0SPeter Maydell next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres); 831adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 832adcf0bf0SPeter Maydell goto txfail; 833adcf0bf0SPeter Maydell } 83488b2fef6SLaurent Vivier 83588b2fef6SLaurent Vivier if (!M68K_PDT_VALID(next)) { 83688b2fef6SLaurent Vivier return -1; 83788b2fef6SLaurent Vivier } 83888b2fef6SLaurent Vivier if (M68K_PDT_INDIRECT(next)) { 839adcf0bf0SPeter Maydell next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next), 840adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 841adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 842adcf0bf0SPeter Maydell goto txfail; 843adcf0bf0SPeter Maydell } 84488b2fef6SLaurent Vivier } 84588b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 84688b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 84788b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 848adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, next | M68K_DESC_USED, 849adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 850adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 851adcf0bf0SPeter Maydell goto txfail; 852adcf0bf0SPeter Maydell } 85388b2fef6SLaurent Vivier } 85488b2fef6SLaurent Vivier } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) != 85588b2fef6SLaurent Vivier (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) { 856adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, 857adcf0bf0SPeter Maydell next | (M68K_DESC_MODIFIED | M68K_DESC_USED), 858adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 859adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 860adcf0bf0SPeter Maydell goto txfail; 861adcf0bf0SPeter Maydell } 86288b2fef6SLaurent Vivier } 86388b2fef6SLaurent Vivier } else { 86488b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 865adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, next | M68K_DESC_USED, 866adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 867adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 868adcf0bf0SPeter Maydell goto txfail; 869adcf0bf0SPeter Maydell } 87088b2fef6SLaurent Vivier } 87188b2fef6SLaurent Vivier } 87288b2fef6SLaurent Vivier 87388b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 87488b2fef6SLaurent Vivier page_bits = 13; 87588b2fef6SLaurent Vivier } else { 87688b2fef6SLaurent Vivier page_bits = 12; 87788b2fef6SLaurent Vivier } 87888b2fef6SLaurent Vivier *page_size = 1 << page_bits; 87988b2fef6SLaurent Vivier page_mask = ~(*page_size - 1); 880852002b5SMark Cave-Ayland *physical = (next & page_mask) + (address & (*page_size - 1)); 88188b2fef6SLaurent Vivier 882e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 883e55886c3SLaurent Vivier env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040; 884e55886c3SLaurent Vivier env->mmu.mmusr |= *physical & 0xfffff000; 885e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_R_040; 886e55886c3SLaurent Vivier } 887e55886c3SLaurent Vivier 88888b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 88988b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 89088b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 89188b2fef6SLaurent Vivier return -1; 89288b2fef6SLaurent Vivier } 89388b2fef6SLaurent Vivier } 89488b2fef6SLaurent Vivier if (next & M68K_DESC_SUPERONLY) { 89588b2fef6SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 89688b2fef6SLaurent Vivier return -1; 89788b2fef6SLaurent Vivier } 89888b2fef6SLaurent Vivier } 89988b2fef6SLaurent Vivier 90088b2fef6SLaurent Vivier return 0; 901adcf0bf0SPeter Maydell 902adcf0bf0SPeter Maydell txfail: 903adcf0bf0SPeter Maydell /* 904adcf0bf0SPeter Maydell * A page table load/store failed. TODO: we should really raise a 905adcf0bf0SPeter Maydell * suitable guest fault here if this is not a debug access. 906adcf0bf0SPeter Maydell * For now just return that the translation failed. 907adcf0bf0SPeter Maydell */ 908adcf0bf0SPeter Maydell return -1; 90988b2fef6SLaurent Vivier } 91088b2fef6SLaurent Vivier 91100b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 9124fcc562bSPaul Brook { 913e22a4560SPhilippe Mathieu-Daudé CPUM68KState *env = cpu_env(cs); 91488b2fef6SLaurent Vivier hwaddr phys_addr; 91588b2fef6SLaurent Vivier int prot; 91688b2fef6SLaurent Vivier int access_type; 91788b2fef6SLaurent Vivier target_ulong page_size; 91888b2fef6SLaurent Vivier 91988b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 92088b2fef6SLaurent Vivier /* MMU disabled */ 9214fcc562bSPaul Brook return addr; 9224fcc562bSPaul Brook } 9234fcc562bSPaul Brook 92488b2fef6SLaurent Vivier access_type = ACCESS_DATA | ACCESS_DEBUG; 92588b2fef6SLaurent Vivier if (env->sr & SR_S) { 92688b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 92788b2fef6SLaurent Vivier } 92878318119SMark Cave-Ayland 92988b2fef6SLaurent Vivier if (get_physical_address(env, &phys_addr, &prot, 93088b2fef6SLaurent Vivier addr, access_type, &page_size) != 0) { 93188b2fef6SLaurent Vivier return -1; 93288b2fef6SLaurent Vivier } 93378318119SMark Cave-Ayland 93488b2fef6SLaurent Vivier return phys_addr; 93588b2fef6SLaurent Vivier } 93688b2fef6SLaurent Vivier 937fe5f7b1bSRichard Henderson /* 938fe5f7b1bSRichard Henderson * Notify CPU of a pending interrupt. Prioritization and vectoring should 939fe5f7b1bSRichard Henderson * be handled by the interrupt controller. Real hardware only requests 940fe5f7b1bSRichard Henderson * the vector when the interrupt is acknowledged by the CPU. For 941fe5f7b1bSRichard Henderson * simplicity we calculate it when the interrupt is signalled. 942fe5f7b1bSRichard Henderson */ 943fe5f7b1bSRichard Henderson void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) 944fe5f7b1bSRichard Henderson { 945fe5f7b1bSRichard Henderson CPUState *cs = CPU(cpu); 946fe5f7b1bSRichard Henderson CPUM68KState *env = &cpu->env; 947fe5f7b1bSRichard Henderson 948fe5f7b1bSRichard Henderson env->pending_level = level; 949fe5f7b1bSRichard Henderson env->pending_vector = vector; 950fe5f7b1bSRichard Henderson if (level) { 951fe5f7b1bSRichard Henderson cpu_interrupt(cs, CPU_INTERRUPT_HARD); 952fe5f7b1bSRichard Henderson } else { 953fe5f7b1bSRichard Henderson cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 954fe5f7b1bSRichard Henderson } 955fe5f7b1bSRichard Henderson } 956fe5f7b1bSRichard Henderson 957fe5f7b1bSRichard Henderson bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 958fe5f7b1bSRichard Henderson MMUAccessType qemu_access_type, int mmu_idx, 959fe5f7b1bSRichard Henderson bool probe, uintptr_t retaddr) 9600633879fSpbrook { 961e22a4560SPhilippe Mathieu-Daudé CPUM68KState *env = cpu_env(cs); 96288b2fef6SLaurent Vivier hwaddr physical; 9630633879fSpbrook int prot; 96488b2fef6SLaurent Vivier int access_type; 96588b2fef6SLaurent Vivier int ret; 96688b2fef6SLaurent Vivier target_ulong page_size; 9670633879fSpbrook 96888b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 96988b2fef6SLaurent Vivier /* MMU disabled */ 97088b2fef6SLaurent Vivier tlb_set_page(cs, address & TARGET_PAGE_MASK, 97188b2fef6SLaurent Vivier address & TARGET_PAGE_MASK, 97288b2fef6SLaurent Vivier PAGE_READ | PAGE_WRITE | PAGE_EXEC, 97388b2fef6SLaurent Vivier mmu_idx, TARGET_PAGE_SIZE); 974fe5f7b1bSRichard Henderson return true; 9750633879fSpbrook } 9760633879fSpbrook 977fe5f7b1bSRichard Henderson if (qemu_access_type == MMU_INST_FETCH) { 97888b2fef6SLaurent Vivier access_type = ACCESS_CODE; 97988b2fef6SLaurent Vivier } else { 98088b2fef6SLaurent Vivier access_type = ACCESS_DATA; 981fe5f7b1bSRichard Henderson if (qemu_access_type == MMU_DATA_STORE) { 98288b2fef6SLaurent Vivier access_type |= ACCESS_STORE; 98388b2fef6SLaurent Vivier } 98488b2fef6SLaurent Vivier } 98588b2fef6SLaurent Vivier if (mmu_idx != MMU_USER_IDX) { 98688b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 98788b2fef6SLaurent Vivier } 98888b2fef6SLaurent Vivier 989ee1004bbSPhilippe Mathieu-Daudé ret = get_physical_address(env, &physical, &prot, 99088b2fef6SLaurent Vivier address, access_type, &page_size); 991fe5f7b1bSRichard Henderson if (likely(ret == 0)) { 992852002b5SMark Cave-Ayland tlb_set_page(cs, address & TARGET_PAGE_MASK, 993852002b5SMark Cave-Ayland physical & TARGET_PAGE_MASK, prot, mmu_idx, page_size); 994fe5f7b1bSRichard Henderson return true; 99588b2fef6SLaurent Vivier } 996fe5f7b1bSRichard Henderson 997fe5f7b1bSRichard Henderson if (probe) { 998fe5f7b1bSRichard Henderson return false; 999fe5f7b1bSRichard Henderson } 1000fe5f7b1bSRichard Henderson 100188b2fef6SLaurent Vivier /* page fault */ 100288b2fef6SLaurent Vivier env->mmu.ssw = M68K_ATC_040; 100388b2fef6SLaurent Vivier switch (size) { 100488b2fef6SLaurent Vivier case 1: 100588b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_BYTE; 100688b2fef6SLaurent Vivier break; 100788b2fef6SLaurent Vivier case 2: 100888b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_WORD; 100988b2fef6SLaurent Vivier break; 101088b2fef6SLaurent Vivier case 4: 101188b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_LONG; 101288b2fef6SLaurent Vivier break; 101388b2fef6SLaurent Vivier } 101488b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 101588b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_SUPER; 101688b2fef6SLaurent Vivier } 101788b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 101888b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_CODE; 101988b2fef6SLaurent Vivier } else { 102088b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_DATA; 102188b2fef6SLaurent Vivier } 102288b2fef6SLaurent Vivier if (!(access_type & ACCESS_STORE)) { 102388b2fef6SLaurent Vivier env->mmu.ssw |= M68K_RW_040; 102488b2fef6SLaurent Vivier } 1025fe5f7b1bSRichard Henderson 102688b2fef6SLaurent Vivier cs->exception_index = EXCP_ACCESS; 1027fe5f7b1bSRichard Henderson env->mmu.ar = address; 1028fe5f7b1bSRichard Henderson cpu_loop_exit_restore(cs, retaddr); 102988b2fef6SLaurent Vivier } 1030028772c4SRichard Henderson #endif /* !CONFIG_USER_ONLY */ 103188b2fef6SLaurent Vivier 1032e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x) 1033e1f3808eSpbrook { 1034e1f3808eSpbrook x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); 1035e1f3808eSpbrook x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); 1036e1f3808eSpbrook x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); 1037e1f3808eSpbrook return bswap32(x); 1038e1f3808eSpbrook } 1039e1f3808eSpbrook 1040e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x) 1041e1f3808eSpbrook { 1042e1f3808eSpbrook int n; 1043e1f3808eSpbrook for (n = 32; x; n--) 1044e1f3808eSpbrook x >>= 1; 1045e1f3808eSpbrook return n; 1046e1f3808eSpbrook } 1047e1f3808eSpbrook 1048620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v) 1049e1f3808eSpbrook { 1050e1f3808eSpbrook /* The result has the opposite sign to the original value. */ 1051620c6cf6SRichard Henderson if ((int32_t)v < 0) { 1052e1f3808eSpbrook val = (((int32_t)val) >> 31) ^ SIGNBIT; 1053620c6cf6SRichard Henderson } 1054e1f3808eSpbrook return val; 1055e1f3808eSpbrook } 1056e1f3808eSpbrook 1057d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) 1058e1f3808eSpbrook { 1059d2f8fb8eSLaurent Vivier env->sr = sr & 0xffe0; 1060d2f8fb8eSLaurent Vivier cpu_m68k_set_ccr(env, sr); 1061e1f3808eSpbrook m68k_switch_sp(env); 1062e1f3808eSpbrook } 1063e1f3808eSpbrook 1064d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val) 1065d2f8fb8eSLaurent Vivier { 1066d2f8fb8eSLaurent Vivier cpu_m68k_set_sr(env, val); 1067d2f8fb8eSLaurent Vivier } 1068e1f3808eSpbrook 1069e1f3808eSpbrook /* MAC unit. */ 1070808d77bcSLucien Murray-Pitts /* 1071808d77bcSLucien Murray-Pitts * FIXME: The MAC unit implementation is a bit of a mess. Some helpers 1072808d77bcSLucien Murray-Pitts * take values, others take register numbers and manipulate the contents 1073808d77bcSLucien Murray-Pitts * in-place. 1074808d77bcSLucien Murray-Pitts */ 10752b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) 1076e1f3808eSpbrook { 1077e1f3808eSpbrook uint32_t mask; 1078e1f3808eSpbrook env->macc[dest] = env->macc[src]; 1079e1f3808eSpbrook mask = MACSR_PAV0 << dest; 1080e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << src)) 1081e1f3808eSpbrook env->macsr |= mask; 1082e1f3808eSpbrook else 1083e1f3808eSpbrook env->macsr &= ~mask; 1084e1f3808eSpbrook } 1085e1f3808eSpbrook 10862b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) 1087e1f3808eSpbrook { 1088e1f3808eSpbrook int64_t product; 1089e1f3808eSpbrook int64_t res; 1090e1f3808eSpbrook 1091e1f3808eSpbrook product = (uint64_t)op1 * op2; 1092e1f3808eSpbrook res = (product << 24) >> 24; 1093e1f3808eSpbrook if (res != product) { 1094e1f3808eSpbrook env->macsr |= MACSR_V; 1095e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1096e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 1097e1f3808eSpbrook if (product < 0) 1098e1f3808eSpbrook res = ~(1ll << 50); 1099e1f3808eSpbrook else 1100e1f3808eSpbrook res = 1ll << 50; 1101e1f3808eSpbrook } 1102e1f3808eSpbrook } 1103e1f3808eSpbrook return res; 1104e1f3808eSpbrook } 1105e1f3808eSpbrook 11062b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) 1107e1f3808eSpbrook { 1108e1f3808eSpbrook uint64_t product; 1109e1f3808eSpbrook 1110e1f3808eSpbrook product = (uint64_t)op1 * op2; 1111e1f3808eSpbrook if (product & (0xffffffull << 40)) { 1112e1f3808eSpbrook env->macsr |= MACSR_V; 1113e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1114e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 1115e1f3808eSpbrook product = 1ll << 50; 1116e1f3808eSpbrook } else { 1117e1f3808eSpbrook product &= ((1ull << 40) - 1); 1118e1f3808eSpbrook } 1119e1f3808eSpbrook } 1120e1f3808eSpbrook return product; 1121e1f3808eSpbrook } 1122e1f3808eSpbrook 11232b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) 1124e1f3808eSpbrook { 1125e1f3808eSpbrook uint64_t product; 1126e1f3808eSpbrook uint32_t remainder; 1127e1f3808eSpbrook 1128e1f3808eSpbrook product = (uint64_t)op1 * op2; 1129e1f3808eSpbrook if (env->macsr & MACSR_RT) { 1130e1f3808eSpbrook remainder = product & 0xffffff; 1131e1f3808eSpbrook product >>= 24; 1132e1f3808eSpbrook if (remainder > 0x800000) 1133e1f3808eSpbrook product++; 1134e1f3808eSpbrook else if (remainder == 0x800000) 1135e1f3808eSpbrook product += (product & 1); 1136e1f3808eSpbrook } else { 1137e1f3808eSpbrook product >>= 24; 1138e1f3808eSpbrook } 1139e1f3808eSpbrook return product; 1140e1f3808eSpbrook } 1141e1f3808eSpbrook 11422b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc) 1143e1f3808eSpbrook { 1144e1f3808eSpbrook int64_t tmp; 1145e1f3808eSpbrook int64_t result; 1146e1f3808eSpbrook tmp = env->macc[acc]; 1147e1f3808eSpbrook result = ((tmp << 16) >> 16); 1148e1f3808eSpbrook if (result != tmp) { 1149e1f3808eSpbrook env->macsr |= MACSR_V; 1150e1f3808eSpbrook } 1151e1f3808eSpbrook if (env->macsr & MACSR_V) { 1152e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1153e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1154808d77bcSLucien Murray-Pitts /* 1155808d77bcSLucien Murray-Pitts * The result is saturated to 32 bits, despite overflow occurring 1156808d77bcSLucien Murray-Pitts * at 48 bits. Seems weird, but that's what the hardware docs 1157808d77bcSLucien Murray-Pitts * say. 1158808d77bcSLucien Murray-Pitts */ 1159e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffff; 1160e1f3808eSpbrook } 1161e1f3808eSpbrook } 1162e1f3808eSpbrook env->macc[acc] = result; 1163e1f3808eSpbrook } 1164e1f3808eSpbrook 11652b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) 1166e1f3808eSpbrook { 1167e1f3808eSpbrook uint64_t val; 1168e1f3808eSpbrook 1169e1f3808eSpbrook val = env->macc[acc]; 1170e1f3808eSpbrook if (val & (0xffffull << 48)) { 1171e1f3808eSpbrook env->macsr |= MACSR_V; 1172e1f3808eSpbrook } 1173e1f3808eSpbrook if (env->macsr & MACSR_V) { 1174e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1175e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1176e1f3808eSpbrook if (val > (1ull << 53)) 1177e1f3808eSpbrook val = 0; 1178e1f3808eSpbrook else 1179e1f3808eSpbrook val = (1ull << 48) - 1; 1180e1f3808eSpbrook } else { 1181e1f3808eSpbrook val &= ((1ull << 48) - 1); 1182e1f3808eSpbrook } 1183e1f3808eSpbrook } 1184e1f3808eSpbrook env->macc[acc] = val; 1185e1f3808eSpbrook } 1186e1f3808eSpbrook 11872b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) 1188e1f3808eSpbrook { 1189e1f3808eSpbrook int64_t sum; 1190e1f3808eSpbrook int64_t result; 1191e1f3808eSpbrook 1192e1f3808eSpbrook sum = env->macc[acc]; 1193e1f3808eSpbrook result = (sum << 16) >> 16; 1194e1f3808eSpbrook if (result != sum) { 1195e1f3808eSpbrook env->macsr |= MACSR_V; 1196e1f3808eSpbrook } 1197e1f3808eSpbrook if (env->macsr & MACSR_V) { 1198e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1199e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1200e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffffffffll; 1201e1f3808eSpbrook } 1202e1f3808eSpbrook } 1203e1f3808eSpbrook env->macc[acc] = result; 1204e1f3808eSpbrook } 1205e1f3808eSpbrook 12062b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) 1207e1f3808eSpbrook { 1208e1f3808eSpbrook uint64_t val; 1209e1f3808eSpbrook val = env->macc[acc]; 1210c4162574SBlue Swirl if (val == 0) { 1211e1f3808eSpbrook env->macsr |= MACSR_Z; 1212c4162574SBlue Swirl } else if (val & (1ull << 47)) { 1213e1f3808eSpbrook env->macsr |= MACSR_N; 1214c4162574SBlue Swirl } 1215e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << acc)) { 1216e1f3808eSpbrook env->macsr |= MACSR_V; 1217e1f3808eSpbrook } 1218e1f3808eSpbrook if (env->macsr & MACSR_FI) { 1219e1f3808eSpbrook val = ((int64_t)val) >> 40; 1220e1f3808eSpbrook if (val != 0 && val != -1) 1221e1f3808eSpbrook env->macsr |= MACSR_EV; 1222e1f3808eSpbrook } else if (env->macsr & MACSR_SU) { 1223e1f3808eSpbrook val = ((int64_t)val) >> 32; 1224e1f3808eSpbrook if (val != 0 && val != -1) 1225e1f3808eSpbrook env->macsr |= MACSR_EV; 1226e1f3808eSpbrook } else { 1227e1f3808eSpbrook if ((val >> 32) != 0) 1228e1f3808eSpbrook env->macsr |= MACSR_EV; 1229e1f3808eSpbrook } 1230e1f3808eSpbrook } 1231e1f3808eSpbrook 1232db3d7945SLaurent Vivier #define EXTSIGN(val, index) ( \ 1233db3d7945SLaurent Vivier (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ 1234db3d7945SLaurent Vivier ) 1235620c6cf6SRichard Henderson 1236620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) { \ 1237620c6cf6SRichard Henderson switch (op) { \ 1238620c6cf6SRichard Henderson case CC_OP_FLAGS: \ 1239620c6cf6SRichard Henderson /* Everything in place. */ \ 1240620c6cf6SRichard Henderson break; \ 1241db3d7945SLaurent Vivier case CC_OP_ADDB: \ 1242db3d7945SLaurent Vivier case CC_OP_ADDW: \ 1243db3d7945SLaurent Vivier case CC_OP_ADDL: \ 1244620c6cf6SRichard Henderson res = n; \ 1245620c6cf6SRichard Henderson src2 = v; \ 1246db3d7945SLaurent Vivier src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ 1247620c6cf6SRichard Henderson c = x; \ 1248620c6cf6SRichard Henderson z = n; \ 1249620c6cf6SRichard Henderson v = (res ^ src1) & ~(src1 ^ src2); \ 1250620c6cf6SRichard Henderson break; \ 1251db3d7945SLaurent Vivier case CC_OP_SUBB: \ 1252db3d7945SLaurent Vivier case CC_OP_SUBW: \ 1253db3d7945SLaurent Vivier case CC_OP_SUBL: \ 1254620c6cf6SRichard Henderson res = n; \ 1255620c6cf6SRichard Henderson src2 = v; \ 1256db3d7945SLaurent Vivier src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ 1257620c6cf6SRichard Henderson c = x; \ 1258620c6cf6SRichard Henderson z = n; \ 1259620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 1260620c6cf6SRichard Henderson break; \ 1261db3d7945SLaurent Vivier case CC_OP_CMPB: \ 1262db3d7945SLaurent Vivier case CC_OP_CMPW: \ 1263db3d7945SLaurent Vivier case CC_OP_CMPL: \ 1264620c6cf6SRichard Henderson src1 = n; \ 1265620c6cf6SRichard Henderson src2 = v; \ 1266db3d7945SLaurent Vivier res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ 1267620c6cf6SRichard Henderson n = res; \ 1268620c6cf6SRichard Henderson z = res; \ 1269620c6cf6SRichard Henderson c = src1 < src2; \ 1270620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 1271620c6cf6SRichard Henderson break; \ 1272620c6cf6SRichard Henderson case CC_OP_LOGIC: \ 1273620c6cf6SRichard Henderson c = v = 0; \ 1274620c6cf6SRichard Henderson z = n; \ 1275620c6cf6SRichard Henderson break; \ 1276620c6cf6SRichard Henderson default: \ 1277a8d92fd8SRichard Henderson cpu_abort(env_cpu(env), "Bad CC_OP %d", op); \ 1278620c6cf6SRichard Henderson } \ 1279620c6cf6SRichard Henderson } while (0) 1280620c6cf6SRichard Henderson 1281620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env) 1282e1f3808eSpbrook { 1283620c6cf6SRichard Henderson uint32_t x, c, n, z, v; 1284620c6cf6SRichard Henderson uint32_t res, src1, src2; 1285620c6cf6SRichard Henderson 1286620c6cf6SRichard Henderson x = env->cc_x; 1287620c6cf6SRichard Henderson n = env->cc_n; 1288620c6cf6SRichard Henderson z = env->cc_z; 1289620c6cf6SRichard Henderson v = env->cc_v; 1290db3d7945SLaurent Vivier c = env->cc_c; 1291620c6cf6SRichard Henderson 1292620c6cf6SRichard Henderson COMPUTE_CCR(env->cc_op, x, n, z, v, c); 1293620c6cf6SRichard Henderson 1294620c6cf6SRichard Henderson n = n >> 31; 1295620c6cf6SRichard Henderson z = (z == 0); 1296db3d7945SLaurent Vivier v = v >> 31; 1297620c6cf6SRichard Henderson 1298620c6cf6SRichard Henderson return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; 1299620c6cf6SRichard Henderson } 1300620c6cf6SRichard Henderson 1301620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env) 1302620c6cf6SRichard Henderson { 1303620c6cf6SRichard Henderson return cpu_m68k_get_ccr(env); 1304620c6cf6SRichard Henderson } 1305620c6cf6SRichard Henderson 1306620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) 1307620c6cf6SRichard Henderson { 1308620c6cf6SRichard Henderson env->cc_x = (ccr & CCF_X ? 1 : 0); 1309620c6cf6SRichard Henderson env->cc_n = (ccr & CCF_N ? -1 : 0); 1310620c6cf6SRichard Henderson env->cc_z = (ccr & CCF_Z ? 0 : 1); 1311620c6cf6SRichard Henderson env->cc_v = (ccr & CCF_V ? -1 : 0); 1312620c6cf6SRichard Henderson env->cc_c = (ccr & CCF_C ? 1 : 0); 1313620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 1314620c6cf6SRichard Henderson } 1315620c6cf6SRichard Henderson 1316620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) 1317620c6cf6SRichard Henderson { 1318620c6cf6SRichard Henderson cpu_m68k_set_ccr(env, ccr); 1319620c6cf6SRichard Henderson } 1320620c6cf6SRichard Henderson 1321620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) 1322620c6cf6SRichard Henderson { 1323620c6cf6SRichard Henderson uint32_t res, src1, src2; 1324620c6cf6SRichard Henderson 1325620c6cf6SRichard Henderson COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); 1326620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 1327e1f3808eSpbrook } 1328e1f3808eSpbrook 13292b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) 1330e1f3808eSpbrook { 1331e1f3808eSpbrook int rem; 1332e1f3808eSpbrook uint32_t result; 1333e1f3808eSpbrook 1334e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1335e1f3808eSpbrook /* 16-bit rounding. */ 1336e1f3808eSpbrook rem = val & 0xffffff; 1337e1f3808eSpbrook val = (val >> 24) & 0xffffu; 1338e1f3808eSpbrook if (rem > 0x800000) 1339e1f3808eSpbrook val++; 1340e1f3808eSpbrook else if (rem == 0x800000) 1341e1f3808eSpbrook val += (val & 1); 1342e1f3808eSpbrook } else if (env->macsr & MACSR_RT) { 1343e1f3808eSpbrook /* 32-bit rounding. */ 1344e1f3808eSpbrook rem = val & 0xff; 1345e1f3808eSpbrook val >>= 8; 1346e1f3808eSpbrook if (rem > 0x80) 1347e1f3808eSpbrook val++; 1348e1f3808eSpbrook else if (rem == 0x80) 1349e1f3808eSpbrook val += (val & 1); 1350e1f3808eSpbrook } else { 1351e1f3808eSpbrook /* No rounding. */ 1352e1f3808eSpbrook val >>= 8; 1353e1f3808eSpbrook } 1354e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1355e1f3808eSpbrook /* Saturate. */ 1356e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1357e1f3808eSpbrook if (val != (uint16_t) val) { 1358e1f3808eSpbrook result = ((val >> 63) ^ 0x7fff) & 0xffff; 1359e1f3808eSpbrook } else { 1360e1f3808eSpbrook result = val & 0xffff; 1361e1f3808eSpbrook } 1362e1f3808eSpbrook } else { 1363e1f3808eSpbrook if (val != (uint32_t)val) { 1364e1f3808eSpbrook result = ((uint32_t)(val >> 63) & 0x7fffffff); 1365e1f3808eSpbrook } else { 1366e1f3808eSpbrook result = (uint32_t)val; 1367e1f3808eSpbrook } 1368e1f3808eSpbrook } 1369e1f3808eSpbrook } else { 1370e1f3808eSpbrook /* No saturation. */ 1371e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1372e1f3808eSpbrook result = val & 0xffff; 1373e1f3808eSpbrook } else { 1374e1f3808eSpbrook result = (uint32_t)val; 1375e1f3808eSpbrook } 1376e1f3808eSpbrook } 1377e1f3808eSpbrook return result; 1378e1f3808eSpbrook } 1379e1f3808eSpbrook 1380e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val) 1381e1f3808eSpbrook { 1382e1f3808eSpbrook if (val == (int32_t)val) { 1383e1f3808eSpbrook return (int32_t)val; 1384e1f3808eSpbrook } else { 1385e1f3808eSpbrook return (val >> 61) ^ ~SIGNBIT; 1386e1f3808eSpbrook } 1387e1f3808eSpbrook } 1388e1f3808eSpbrook 1389e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val) 1390e1f3808eSpbrook { 1391e1f3808eSpbrook if ((val >> 32) == 0) { 1392e1f3808eSpbrook return (uint32_t)val; 1393e1f3808eSpbrook } else { 1394e1f3808eSpbrook return 0xffffffffu; 1395e1f3808eSpbrook } 1396e1f3808eSpbrook } 1397e1f3808eSpbrook 13982b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) 1399e1f3808eSpbrook { 1400e1f3808eSpbrook uint32_t val; 1401e1f3808eSpbrook val = env->macc[acc] & 0x00ff; 14025ce747cfSPaolo Bonzini val |= (env->macc[acc] >> 32) & 0xff00; 1403e1f3808eSpbrook val |= (env->macc[acc + 1] << 16) & 0x00ff0000; 1404e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xff000000; 1405e1f3808eSpbrook return val; 1406e1f3808eSpbrook } 1407e1f3808eSpbrook 14082b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) 1409e1f3808eSpbrook { 1410e1f3808eSpbrook uint32_t val; 1411e1f3808eSpbrook val = (env->macc[acc] >> 32) & 0xffff; 1412e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xffff0000; 1413e1f3808eSpbrook return val; 1414e1f3808eSpbrook } 1415e1f3808eSpbrook 14162b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) 1417e1f3808eSpbrook { 1418e1f3808eSpbrook int64_t res; 1419e1f3808eSpbrook int32_t tmp; 1420e1f3808eSpbrook res = env->macc[acc] & 0xffffffff00ull; 1421e1f3808eSpbrook tmp = (int16_t)(val & 0xff00); 1422e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1423e1f3808eSpbrook res |= val & 0xff; 1424e1f3808eSpbrook env->macc[acc] = res; 1425e1f3808eSpbrook res = env->macc[acc + 1] & 0xffffffff00ull; 1426e1f3808eSpbrook tmp = (val & 0xff000000); 1427e1f3808eSpbrook res |= ((int64_t)tmp) << 16; 1428e1f3808eSpbrook res |= (val >> 16) & 0xff; 1429e1f3808eSpbrook env->macc[acc + 1] = res; 1430e1f3808eSpbrook } 1431e1f3808eSpbrook 14322b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) 1433e1f3808eSpbrook { 1434e1f3808eSpbrook int64_t res; 1435e1f3808eSpbrook int32_t tmp; 1436e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1437e1f3808eSpbrook tmp = (int16_t)val; 1438e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1439e1f3808eSpbrook env->macc[acc] = res; 1440e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1441e1f3808eSpbrook tmp = val & 0xffff0000; 1442e1f3808eSpbrook res |= (int64_t)tmp << 16; 1443e1f3808eSpbrook env->macc[acc + 1] = res; 1444e1f3808eSpbrook } 1445e1f3808eSpbrook 14462b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) 1447e1f3808eSpbrook { 1448e1f3808eSpbrook uint64_t res; 1449e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1450e1f3808eSpbrook res |= ((uint64_t)(val & 0xffff)) << 32; 1451e1f3808eSpbrook env->macc[acc] = res; 1452e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1453e1f3808eSpbrook res |= (uint64_t)(val & 0xffff0000) << 16; 1454e1f3808eSpbrook env->macc[acc + 1] = res; 1455e1f3808eSpbrook } 14560bdb2b3bSLaurent Vivier 14576a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY) 1458e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read) 1459e55886c3SLaurent Vivier { 1460e55886c3SLaurent Vivier hwaddr physical; 1461e55886c3SLaurent Vivier int access_type; 1462e55886c3SLaurent Vivier int prot; 1463e55886c3SLaurent Vivier int ret; 1464e55886c3SLaurent Vivier target_ulong page_size; 1465e55886c3SLaurent Vivier 1466e55886c3SLaurent Vivier access_type = ACCESS_PTEST; 1467e55886c3SLaurent Vivier if (env->dfc & 4) { 1468e55886c3SLaurent Vivier access_type |= ACCESS_SUPER; 1469e55886c3SLaurent Vivier } 1470e55886c3SLaurent Vivier if ((env->dfc & 3) == 2) { 1471e55886c3SLaurent Vivier access_type |= ACCESS_CODE; 1472e55886c3SLaurent Vivier } 1473e55886c3SLaurent Vivier if (!is_read) { 1474e55886c3SLaurent Vivier access_type |= ACCESS_STORE; 1475e55886c3SLaurent Vivier } 1476e55886c3SLaurent Vivier 1477e55886c3SLaurent Vivier env->mmu.mmusr = 0; 1478e55886c3SLaurent Vivier env->mmu.ssw = 0; 1479e55886c3SLaurent Vivier ret = get_physical_address(env, &physical, &prot, addr, 1480e55886c3SLaurent Vivier access_type, &page_size); 1481e55886c3SLaurent Vivier if (ret == 0) { 1482852002b5SMark Cave-Ayland tlb_set_page(env_cpu(env), addr & TARGET_PAGE_MASK, 1483852002b5SMark Cave-Ayland physical & TARGET_PAGE_MASK, 1484e55886c3SLaurent Vivier prot, access_type & ACCESS_SUPER ? 1485e55886c3SLaurent Vivier MMU_KERNEL_IDX : MMU_USER_IDX, page_size); 1486e55886c3SLaurent Vivier } 1487e55886c3SLaurent Vivier } 1488e55886c3SLaurent Vivier 1489e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode) 1490e55886c3SLaurent Vivier { 1491a8d92fd8SRichard Henderson CPUState *cs = env_cpu(env); 1492e55886c3SLaurent Vivier 1493e55886c3SLaurent Vivier switch (opmode) { 1494e55886c3SLaurent Vivier case 0: /* Flush page entry if not global */ 1495e55886c3SLaurent Vivier case 1: /* Flush page entry */ 1496a8d92fd8SRichard Henderson tlb_flush_page(cs, addr); 1497e55886c3SLaurent Vivier break; 1498e55886c3SLaurent Vivier case 2: /* Flush all except global entries */ 1499a8d92fd8SRichard Henderson tlb_flush(cs); 1500e55886c3SLaurent Vivier break; 1501e55886c3SLaurent Vivier case 3: /* Flush all entries */ 1502a8d92fd8SRichard Henderson tlb_flush(cs); 1503e55886c3SLaurent Vivier break; 1504e55886c3SLaurent Vivier } 1505e55886c3SLaurent Vivier } 1506e55886c3SLaurent Vivier 15070bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env) 15080bdb2b3bSLaurent Vivier { 15090bdb2b3bSLaurent Vivier /* FIXME: reset all except CPU */ 15100bdb2b3bSLaurent Vivier } 15116a140586SPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */ 1512