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