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 71f83311e4SLaurent Vivier static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 7256aebc89Spbrook { 7356aebc89Spbrook if (n < 8) { 74f83311e4SLaurent Vivier float_status s; 75f83311e4SLaurent Vivier stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); 7656aebc89Spbrook return 8; 7756aebc89Spbrook } 78ba624944SLaurent Vivier switch (n) { 79ba624944SLaurent Vivier case 8: /* fpcontrol */ 80ba624944SLaurent Vivier stl_be_p(mem_buf, env->fpcr); 81ba624944SLaurent Vivier return 4; 82ba624944SLaurent Vivier case 9: /* fpstatus */ 83ba624944SLaurent Vivier stl_be_p(mem_buf, env->fpsr); 84ba624944SLaurent Vivier return 4; 85ba624944SLaurent Vivier case 10: /* fpiar, not implemented */ 8656aebc89Spbrook memset(mem_buf, 0, 4); 8756aebc89Spbrook return 4; 8856aebc89Spbrook } 8956aebc89Spbrook return 0; 9056aebc89Spbrook } 9156aebc89Spbrook 92f83311e4SLaurent Vivier static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 9356aebc89Spbrook { 9456aebc89Spbrook if (n < 8) { 95f83311e4SLaurent Vivier float_status s; 96f83311e4SLaurent Vivier env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s); 9756aebc89Spbrook return 8; 9856aebc89Spbrook } 99ba624944SLaurent Vivier switch (n) { 100ba624944SLaurent Vivier case 8: /* fpcontrol */ 101ba624944SLaurent Vivier cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); 102ba624944SLaurent Vivier return 4; 103ba624944SLaurent Vivier case 9: /* fpstatus */ 104ba624944SLaurent Vivier env->fpsr = ldl_p(mem_buf); 105ba624944SLaurent Vivier return 4; 106ba624944SLaurent Vivier case 10: /* fpiar, not implemented */ 10756aebc89Spbrook return 4; 10856aebc89Spbrook } 10956aebc89Spbrook return 0; 11056aebc89Spbrook } 11156aebc89Spbrook 1125a4526b2SLaurent Vivier static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 1135a4526b2SLaurent Vivier { 1145a4526b2SLaurent Vivier if (n < 8) { 1155a4526b2SLaurent Vivier stw_be_p(mem_buf, env->fregs[n].l.upper); 1165a4526b2SLaurent Vivier memset(mem_buf + 2, 0, 2); 1175a4526b2SLaurent Vivier stq_be_p(mem_buf + 4, env->fregs[n].l.lower); 1185a4526b2SLaurent Vivier return 12; 1195a4526b2SLaurent Vivier } 1205a4526b2SLaurent Vivier switch (n) { 1215a4526b2SLaurent Vivier case 8: /* fpcontrol */ 1225a4526b2SLaurent Vivier stl_be_p(mem_buf, env->fpcr); 1235a4526b2SLaurent Vivier return 4; 1245a4526b2SLaurent Vivier case 9: /* fpstatus */ 1255a4526b2SLaurent Vivier stl_be_p(mem_buf, env->fpsr); 1265a4526b2SLaurent Vivier return 4; 1275a4526b2SLaurent Vivier case 10: /* fpiar, not implemented */ 1285a4526b2SLaurent Vivier memset(mem_buf, 0, 4); 1295a4526b2SLaurent Vivier return 4; 1305a4526b2SLaurent Vivier } 1315a4526b2SLaurent Vivier return 0; 1325a4526b2SLaurent Vivier } 1335a4526b2SLaurent Vivier 1345a4526b2SLaurent Vivier static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 1355a4526b2SLaurent Vivier { 1365a4526b2SLaurent Vivier if (n < 8) { 1375a4526b2SLaurent Vivier env->fregs[n].l.upper = lduw_be_p(mem_buf); 1385a4526b2SLaurent Vivier env->fregs[n].l.lower = ldq_be_p(mem_buf + 4); 1395a4526b2SLaurent Vivier return 12; 1405a4526b2SLaurent Vivier } 1415a4526b2SLaurent Vivier switch (n) { 1425a4526b2SLaurent Vivier case 8: /* fpcontrol */ 143ba624944SLaurent Vivier cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); 1445a4526b2SLaurent Vivier return 4; 1455a4526b2SLaurent Vivier case 9: /* fpstatus */ 1465a4526b2SLaurent Vivier env->fpsr = ldl_p(mem_buf); 1475a4526b2SLaurent Vivier return 4; 1485a4526b2SLaurent Vivier case 10: /* fpiar, not implemented */ 1495a4526b2SLaurent Vivier return 4; 1505a4526b2SLaurent Vivier } 1515a4526b2SLaurent Vivier return 0; 1525a4526b2SLaurent Vivier } 1535a4526b2SLaurent Vivier 1546d1bbc62SAndreas Färber void m68k_cpu_init_gdb(M68kCPU *cpu) 1556d1bbc62SAndreas Färber { 15622169d41SAndreas Färber CPUState *cs = CPU(cpu); 1576d1bbc62SAndreas Färber CPUM68KState *env = &cpu->env; 1586d1bbc62SAndreas Färber 15911150915SAndreas Färber if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { 160f83311e4SLaurent Vivier gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg, 16111150915SAndreas Färber 11, "cf-fp.xml", 18); 1625a4526b2SLaurent Vivier } else if (m68k_feature(env, M68K_FEATURE_FPU)) { 1635a4526b2SLaurent Vivier gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg, 1645a4526b2SLaurent Vivier m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18); 165aaed909aSbellard } 16611150915SAndreas Färber /* TODO: Add [E]MAC registers. */ 167aaed909aSbellard } 168aaed909aSbellard 1696e22b28eSLaurent Vivier void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) 1700633879fSpbrook { 1710633879fSpbrook switch (reg) { 1726e22b28eSLaurent Vivier case M68K_CR_CACR: 17320dcee94Spbrook env->cacr = val; 17420dcee94Spbrook m68k_switch_sp(env); 17520dcee94Spbrook break; 1766e22b28eSLaurent Vivier case M68K_CR_ACR0: 1776e22b28eSLaurent Vivier case M68K_CR_ACR1: 1786e22b28eSLaurent Vivier case M68K_CR_ACR2: 1796e22b28eSLaurent Vivier case M68K_CR_ACR3: 18020dcee94Spbrook /* TODO: Implement Access Control Registers. */ 1810633879fSpbrook break; 1826e22b28eSLaurent Vivier case M68K_CR_VBR: 1830633879fSpbrook env->vbr = val; 1840633879fSpbrook break; 1850633879fSpbrook /* TODO: Implement control registers. */ 1860633879fSpbrook default: 187a8d92fd8SRichard Henderson cpu_abort(env_cpu(env), 1886e22b28eSLaurent Vivier "Unimplemented control register write 0x%x = 0x%x\n", 1896e22b28eSLaurent Vivier reg, val); 1906e22b28eSLaurent Vivier } 1916e22b28eSLaurent Vivier } 1926e22b28eSLaurent Vivier 1936e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) 1946e22b28eSLaurent Vivier { 1956e22b28eSLaurent Vivier switch (reg) { 1966e22b28eSLaurent Vivier /* MC680[1234]0 */ 1975fa9f1f2SLaurent Vivier case M68K_CR_SFC: 1985fa9f1f2SLaurent Vivier env->sfc = val & 7; 1995fa9f1f2SLaurent Vivier return; 2005fa9f1f2SLaurent Vivier case M68K_CR_DFC: 2015fa9f1f2SLaurent Vivier env->dfc = val & 7; 2025fa9f1f2SLaurent Vivier return; 2036e22b28eSLaurent Vivier case M68K_CR_VBR: 2046e22b28eSLaurent Vivier env->vbr = val; 2056e22b28eSLaurent Vivier return; 206*18b6102eSLaurent Vivier /* MC680[2346]0 */ 2076e22b28eSLaurent Vivier case M68K_CR_CACR: 208*18b6102eSLaurent Vivier if (m68k_feature(env, M68K_FEATURE_M68020)) { 209*18b6102eSLaurent Vivier env->cacr = val & 0x0000000f; 210*18b6102eSLaurent Vivier } else if (m68k_feature(env, M68K_FEATURE_M68030)) { 211*18b6102eSLaurent Vivier env->cacr = val & 0x00003f1f; 212*18b6102eSLaurent Vivier } else if (m68k_feature(env, M68K_FEATURE_M68040)) { 213*18b6102eSLaurent Vivier env->cacr = val & 0x80008000; 214*18b6102eSLaurent Vivier } else if (m68k_feature(env, M68K_FEATURE_M68060)) { 215*18b6102eSLaurent Vivier env->cacr = val & 0xf8e0e000; 216*18b6102eSLaurent Vivier } 2176e22b28eSLaurent Vivier m68k_switch_sp(env); 2186e22b28eSLaurent Vivier return; 2196e22b28eSLaurent Vivier /* MC680[34]0 */ 22088b2fef6SLaurent Vivier case M68K_CR_TC: 22188b2fef6SLaurent Vivier env->mmu.tcr = val; 22288b2fef6SLaurent Vivier return; 223e55886c3SLaurent Vivier case M68K_CR_MMUSR: 224e55886c3SLaurent Vivier env->mmu.mmusr = val; 225e55886c3SLaurent Vivier return; 22688b2fef6SLaurent Vivier case M68K_CR_SRP: 22788b2fef6SLaurent Vivier env->mmu.srp = val; 22888b2fef6SLaurent Vivier return; 22988b2fef6SLaurent Vivier case M68K_CR_URP: 23088b2fef6SLaurent Vivier env->mmu.urp = val; 23188b2fef6SLaurent Vivier return; 2326e22b28eSLaurent Vivier case M68K_CR_USP: 2336e22b28eSLaurent Vivier env->sp[M68K_USP] = val; 2346e22b28eSLaurent Vivier return; 2356e22b28eSLaurent Vivier case M68K_CR_MSP: 2366e22b28eSLaurent Vivier env->sp[M68K_SSP] = val; 2376e22b28eSLaurent Vivier return; 2386e22b28eSLaurent Vivier case M68K_CR_ISP: 2396e22b28eSLaurent Vivier env->sp[M68K_ISP] = val; 2406e22b28eSLaurent Vivier return; 241c05c73b0SLaurent Vivier /* MC68040/MC68LC040 */ 242c05c73b0SLaurent Vivier case M68K_CR_ITT0: 243c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR0] = val; 244c05c73b0SLaurent Vivier return; 245c05c73b0SLaurent Vivier case M68K_CR_ITT1: 246c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR1] = val; 247c05c73b0SLaurent Vivier return; 248c05c73b0SLaurent Vivier case M68K_CR_DTT0: 249c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR0] = val; 250c05c73b0SLaurent Vivier return; 251c05c73b0SLaurent Vivier case M68K_CR_DTT1: 252c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR1] = val; 253c05c73b0SLaurent Vivier return; 2546e22b28eSLaurent Vivier } 255a8d92fd8SRichard Henderson cpu_abort(env_cpu(env), 256a8d92fd8SRichard Henderson "Unimplemented control register write 0x%x = 0x%x\n", 2570633879fSpbrook reg, val); 2580633879fSpbrook } 2596e22b28eSLaurent Vivier 2606e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) 2616e22b28eSLaurent Vivier { 2626e22b28eSLaurent Vivier switch (reg) { 2636e22b28eSLaurent Vivier /* MC680[1234]0 */ 2645fa9f1f2SLaurent Vivier case M68K_CR_SFC: 2655fa9f1f2SLaurent Vivier return env->sfc; 2665fa9f1f2SLaurent Vivier case M68K_CR_DFC: 2675fa9f1f2SLaurent Vivier return env->dfc; 2686e22b28eSLaurent Vivier case M68K_CR_VBR: 2696e22b28eSLaurent Vivier return env->vbr; 2706e22b28eSLaurent Vivier /* MC680[234]0 */ 2716e22b28eSLaurent Vivier case M68K_CR_CACR: 2726e22b28eSLaurent Vivier return env->cacr; 2736e22b28eSLaurent Vivier /* MC680[34]0 */ 27488b2fef6SLaurent Vivier case M68K_CR_TC: 27588b2fef6SLaurent Vivier return env->mmu.tcr; 276e55886c3SLaurent Vivier case M68K_CR_MMUSR: 277e55886c3SLaurent Vivier return env->mmu.mmusr; 27888b2fef6SLaurent Vivier case M68K_CR_SRP: 27988b2fef6SLaurent Vivier return env->mmu.srp; 2806e22b28eSLaurent Vivier case M68K_CR_USP: 2816e22b28eSLaurent Vivier return env->sp[M68K_USP]; 2826e22b28eSLaurent Vivier case M68K_CR_MSP: 2836e22b28eSLaurent Vivier return env->sp[M68K_SSP]; 2846e22b28eSLaurent Vivier case M68K_CR_ISP: 2856e22b28eSLaurent Vivier return env->sp[M68K_ISP]; 28688b2fef6SLaurent Vivier /* MC68040/MC68LC040 */ 28788b2fef6SLaurent Vivier case M68K_CR_URP: 28888b2fef6SLaurent Vivier return env->mmu.urp; 289c05c73b0SLaurent Vivier case M68K_CR_ITT0: 290c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_ITTR0]; 291c05c73b0SLaurent Vivier case M68K_CR_ITT1: 292c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_ITTR1]; 293c05c73b0SLaurent Vivier case M68K_CR_DTT0: 294c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_DTTR0]; 295c05c73b0SLaurent Vivier case M68K_CR_DTT1: 296c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_DTTR1]; 2976e22b28eSLaurent Vivier } 298a8d92fd8SRichard Henderson cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n", 2996e22b28eSLaurent Vivier reg); 3000633879fSpbrook } 3010633879fSpbrook 302e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) 303acf930aaSpbrook { 304acf930aaSpbrook uint32_t acc; 305acf930aaSpbrook int8_t exthigh; 306acf930aaSpbrook uint8_t extlow; 307acf930aaSpbrook uint64_t regval; 308acf930aaSpbrook int i; 309acf930aaSpbrook if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { 310acf930aaSpbrook for (i = 0; i < 4; i++) { 311acf930aaSpbrook regval = env->macc[i]; 312acf930aaSpbrook exthigh = regval >> 40; 313acf930aaSpbrook if (env->macsr & MACSR_FI) { 314acf930aaSpbrook acc = regval >> 8; 315acf930aaSpbrook extlow = regval; 316acf930aaSpbrook } else { 317acf930aaSpbrook acc = regval; 318acf930aaSpbrook extlow = regval >> 32; 319acf930aaSpbrook } 320acf930aaSpbrook if (env->macsr & MACSR_FI) { 321acf930aaSpbrook regval = (((uint64_t)acc) << 8) | extlow; 322acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 323acf930aaSpbrook } else if (env->macsr & MACSR_SU) { 324acf930aaSpbrook regval = acc | (((int64_t)extlow) << 32); 325acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 326acf930aaSpbrook } else { 327acf930aaSpbrook regval = acc | (((uint64_t)extlow) << 32); 328acf930aaSpbrook regval |= ((uint64_t)(uint8_t)exthigh) << 40; 329acf930aaSpbrook } 330acf930aaSpbrook env->macc[i] = regval; 331acf930aaSpbrook } 332acf930aaSpbrook } 333acf930aaSpbrook env->macsr = val; 334acf930aaSpbrook } 335acf930aaSpbrook 33620dcee94Spbrook void m68k_switch_sp(CPUM68KState *env) 33720dcee94Spbrook { 33820dcee94Spbrook int new_sp; 33920dcee94Spbrook 34020dcee94Spbrook env->sp[env->current_sp] = env->aregs[7]; 3416e22b28eSLaurent Vivier if (m68k_feature(env, M68K_FEATURE_M68000)) { 3426e22b28eSLaurent Vivier if (env->sr & SR_S) { 3436e22b28eSLaurent Vivier if (env->sr & SR_M) { 3446e22b28eSLaurent Vivier new_sp = M68K_SSP; 3456e22b28eSLaurent Vivier } else { 3466e22b28eSLaurent Vivier new_sp = M68K_ISP; 3476e22b28eSLaurent Vivier } 3486e22b28eSLaurent Vivier } else { 3496e22b28eSLaurent Vivier new_sp = M68K_USP; 3506e22b28eSLaurent Vivier } 3516e22b28eSLaurent Vivier } else { 35220dcee94Spbrook new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) 35320dcee94Spbrook ? M68K_SSP : M68K_USP; 3546e22b28eSLaurent Vivier } 35520dcee94Spbrook env->aregs[7] = env->sp[new_sp]; 35620dcee94Spbrook env->current_sp = new_sp; 35720dcee94Spbrook } 35820dcee94Spbrook 359fe5f7b1bSRichard Henderson #if !defined(CONFIG_USER_ONLY) 36088b2fef6SLaurent Vivier /* MMU: 68040 only */ 3614fcc562bSPaul Brook 362fad866daSMarkus Armbruster static void print_address_zone(uint32_t logical, uint32_t physical, 3632097dca6SLaurent Vivier uint32_t size, int attr) 3642097dca6SLaurent Vivier { 365fad866daSMarkus Armbruster qemu_printf("%08x - %08x -> %08x - %08x %c ", 3662097dca6SLaurent Vivier logical, logical + size - 1, 3672097dca6SLaurent Vivier physical, physical + size - 1, 3682097dca6SLaurent Vivier attr & 4 ? 'W' : '-'); 3692097dca6SLaurent Vivier size >>= 10; 3702097dca6SLaurent Vivier if (size < 1024) { 371fad866daSMarkus Armbruster qemu_printf("(%d KiB)\n", size); 3722097dca6SLaurent Vivier } else { 3732097dca6SLaurent Vivier size >>= 10; 3742097dca6SLaurent Vivier if (size < 1024) { 375fad866daSMarkus Armbruster qemu_printf("(%d MiB)\n", size); 3762097dca6SLaurent Vivier } else { 3772097dca6SLaurent Vivier size >>= 10; 378fad866daSMarkus Armbruster qemu_printf("(%d GiB)\n", size); 3792097dca6SLaurent Vivier } 3802097dca6SLaurent Vivier } 3812097dca6SLaurent Vivier } 3822097dca6SLaurent Vivier 383fad866daSMarkus Armbruster static void dump_address_map(CPUM68KState *env, uint32_t root_pointer) 3842097dca6SLaurent Vivier { 3852097dca6SLaurent Vivier int i, j, k; 3862097dca6SLaurent Vivier int tic_size, tic_shift; 3872097dca6SLaurent Vivier uint32_t tib_mask; 3882097dca6SLaurent Vivier uint32_t tia, tib, tic; 3892097dca6SLaurent Vivier uint32_t logical = 0xffffffff, physical = 0xffffffff; 3902097dca6SLaurent Vivier uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff; 3912097dca6SLaurent Vivier uint32_t last_logical, last_physical; 3922097dca6SLaurent Vivier int32_t size; 3932097dca6SLaurent Vivier int last_attr = -1, attr = -1; 394a8d92fd8SRichard Henderson CPUState *cs = env_cpu(env); 395f80b551dSPeter Maydell MemTxResult txres; 3962097dca6SLaurent Vivier 3972097dca6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 3982097dca6SLaurent Vivier /* 8k page */ 3992097dca6SLaurent Vivier tic_size = 32; 4002097dca6SLaurent Vivier tic_shift = 13; 4012097dca6SLaurent Vivier tib_mask = M68K_8K_PAGE_MASK; 4022097dca6SLaurent Vivier } else { 4032097dca6SLaurent Vivier /* 4k page */ 4042097dca6SLaurent Vivier tic_size = 64; 4052097dca6SLaurent Vivier tic_shift = 12; 4062097dca6SLaurent Vivier tib_mask = M68K_4K_PAGE_MASK; 4072097dca6SLaurent Vivier } 4082097dca6SLaurent Vivier for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) { 409f80b551dSPeter Maydell tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4, 410f80b551dSPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 411f80b551dSPeter Maydell if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) { 4122097dca6SLaurent Vivier continue; 4132097dca6SLaurent Vivier } 4142097dca6SLaurent Vivier for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) { 415f80b551dSPeter Maydell tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4, 416f80b551dSPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 417f80b551dSPeter Maydell if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) { 4182097dca6SLaurent Vivier continue; 4192097dca6SLaurent Vivier } 4202097dca6SLaurent Vivier for (k = 0; k < tic_size; k++) { 421f80b551dSPeter Maydell tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4, 422f80b551dSPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 423f80b551dSPeter Maydell if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) { 4242097dca6SLaurent Vivier continue; 4252097dca6SLaurent Vivier } 4262097dca6SLaurent Vivier if (M68K_PDT_INDIRECT(tic)) { 427f80b551dSPeter Maydell tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic), 428f80b551dSPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 429f80b551dSPeter Maydell if (txres != MEMTX_OK) { 430f80b551dSPeter Maydell continue; 431f80b551dSPeter Maydell } 4322097dca6SLaurent Vivier } 4332097dca6SLaurent Vivier 4342097dca6SLaurent Vivier last_logical = logical; 4352097dca6SLaurent Vivier logical = (i << M68K_TTS_ROOT_SHIFT) | 4362097dca6SLaurent Vivier (j << M68K_TTS_POINTER_SHIFT) | 4372097dca6SLaurent Vivier (k << tic_shift); 4382097dca6SLaurent Vivier 4392097dca6SLaurent Vivier last_physical = physical; 4402097dca6SLaurent Vivier physical = tic & ~((1 << tic_shift) - 1); 4412097dca6SLaurent Vivier 4422097dca6SLaurent Vivier last_attr = attr; 4432097dca6SLaurent Vivier attr = tic & ((1 << tic_shift) - 1); 4442097dca6SLaurent Vivier 4452097dca6SLaurent Vivier if ((logical != (last_logical + (1 << tic_shift))) || 4462097dca6SLaurent Vivier (physical != (last_physical + (1 << tic_shift))) || 4472097dca6SLaurent Vivier (attr & 4) != (last_attr & 4)) { 4482097dca6SLaurent Vivier 4492097dca6SLaurent Vivier if (first_logical != 0xffffffff) { 4502097dca6SLaurent Vivier size = last_logical + (1 << tic_shift) - 4512097dca6SLaurent Vivier first_logical; 452fad866daSMarkus Armbruster print_address_zone(first_logical, 4532097dca6SLaurent Vivier first_physical, size, last_attr); 4542097dca6SLaurent Vivier } 4552097dca6SLaurent Vivier first_logical = logical; 4562097dca6SLaurent Vivier first_physical = physical; 4572097dca6SLaurent Vivier } 4582097dca6SLaurent Vivier } 4592097dca6SLaurent Vivier } 4602097dca6SLaurent Vivier } 4612097dca6SLaurent Vivier if (first_logical != logical || (attr & 4) != (last_attr & 4)) { 4622097dca6SLaurent Vivier size = logical + (1 << tic_shift) - first_logical; 463fad866daSMarkus Armbruster print_address_zone(first_logical, first_physical, size, last_attr); 4642097dca6SLaurent Vivier } 4652097dca6SLaurent Vivier } 4662097dca6SLaurent Vivier 4672097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \ 4682097dca6SLaurent Vivier switch (a & M68K_DESC_CACHEMODE) { \ 4692097dca6SLaurent Vivier case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \ 470fad866daSMarkus Armbruster qemu_printf("T"); \ 4712097dca6SLaurent Vivier break; \ 4722097dca6SLaurent Vivier case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \ 473fad866daSMarkus Armbruster qemu_printf("C"); \ 4742097dca6SLaurent Vivier break; \ 4752097dca6SLaurent Vivier case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \ 476fad866daSMarkus Armbruster qemu_printf("S"); \ 4772097dca6SLaurent Vivier break; \ 4782097dca6SLaurent Vivier case M68K_DESC_CM_NCACHE: /* noncachable */ \ 479fad866daSMarkus Armbruster qemu_printf("N"); \ 4802097dca6SLaurent Vivier break; \ 4812097dca6SLaurent Vivier } 4822097dca6SLaurent Vivier 483fad866daSMarkus Armbruster static void dump_ttr(uint32_t ttr) 4842097dca6SLaurent Vivier { 4852097dca6SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 486fad866daSMarkus Armbruster qemu_printf("disabled\n"); 4872097dca6SLaurent Vivier return; 4882097dca6SLaurent Vivier } 489fad866daSMarkus Armbruster qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ", 4902097dca6SLaurent Vivier ttr & M68K_TTR_ADDR_BASE, 4912097dca6SLaurent Vivier (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT); 4922097dca6SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 4932097dca6SLaurent Vivier case M68K_TTR_SFIELD_USER: 494fad866daSMarkus Armbruster qemu_printf("U"); 4952097dca6SLaurent Vivier break; 4962097dca6SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 497fad866daSMarkus Armbruster qemu_printf("S"); 4982097dca6SLaurent Vivier break; 4992097dca6SLaurent Vivier default: 500fad866daSMarkus Armbruster qemu_printf("*"); 5012097dca6SLaurent Vivier break; 5022097dca6SLaurent Vivier } 5032097dca6SLaurent Vivier DUMP_CACHEFLAGS(ttr); 5042097dca6SLaurent Vivier if (ttr & M68K_DESC_WRITEPROT) { 505fad866daSMarkus Armbruster qemu_printf("R"); 5062097dca6SLaurent Vivier } else { 507fad866daSMarkus Armbruster qemu_printf("W"); 5082097dca6SLaurent Vivier } 509fad866daSMarkus Armbruster qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >> 5102097dca6SLaurent Vivier M68K_DESC_USERATTR_SHIFT); 5112097dca6SLaurent Vivier } 5122097dca6SLaurent Vivier 513fad866daSMarkus Armbruster void dump_mmu(CPUM68KState *env) 5142097dca6SLaurent Vivier { 5152097dca6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 516fad866daSMarkus Armbruster qemu_printf("Translation disabled\n"); 5172097dca6SLaurent Vivier return; 5182097dca6SLaurent Vivier } 519fad866daSMarkus Armbruster qemu_printf("Page Size: "); 5202097dca6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 521fad866daSMarkus Armbruster qemu_printf("8kB\n"); 5222097dca6SLaurent Vivier } else { 523fad866daSMarkus Armbruster qemu_printf("4kB\n"); 5242097dca6SLaurent Vivier } 5252097dca6SLaurent Vivier 526fad866daSMarkus Armbruster qemu_printf("MMUSR: "); 5272097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_B_040) { 528fad866daSMarkus Armbruster qemu_printf("BUS ERROR\n"); 5292097dca6SLaurent Vivier } else { 530fad866daSMarkus Armbruster qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000); 5312097dca6SLaurent Vivier /* flags found on the page descriptor */ 5322097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_G_040) { 533fad866daSMarkus Armbruster qemu_printf("G"); /* Global */ 5342097dca6SLaurent Vivier } else { 535fad866daSMarkus Armbruster qemu_printf("."); 5362097dca6SLaurent Vivier } 5372097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_S_040) { 538fad866daSMarkus Armbruster qemu_printf("S"); /* Supervisor */ 5392097dca6SLaurent Vivier } else { 540fad866daSMarkus Armbruster qemu_printf("."); 5412097dca6SLaurent Vivier } 5422097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_M_040) { 543fad866daSMarkus Armbruster qemu_printf("M"); /* Modified */ 5442097dca6SLaurent Vivier } else { 545fad866daSMarkus Armbruster qemu_printf("."); 5462097dca6SLaurent Vivier } 5472097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_WP_040) { 548fad866daSMarkus Armbruster qemu_printf("W"); /* Write protect */ 5492097dca6SLaurent Vivier } else { 550fad866daSMarkus Armbruster qemu_printf("."); 5512097dca6SLaurent Vivier } 5522097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_T_040) { 553fad866daSMarkus Armbruster qemu_printf("T"); /* Transparent */ 5542097dca6SLaurent Vivier } else { 555fad866daSMarkus Armbruster qemu_printf("."); 5562097dca6SLaurent Vivier } 5572097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_R_040) { 558fad866daSMarkus Armbruster qemu_printf("R"); /* Resident */ 5592097dca6SLaurent Vivier } else { 560fad866daSMarkus Armbruster qemu_printf("."); 5612097dca6SLaurent Vivier } 562fad866daSMarkus Armbruster qemu_printf(" Cache: "); 5632097dca6SLaurent Vivier DUMP_CACHEFLAGS(env->mmu.mmusr); 564fad866daSMarkus Armbruster qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3); 565fad866daSMarkus Armbruster qemu_printf("\n"); 5662097dca6SLaurent Vivier } 5672097dca6SLaurent Vivier 568fad866daSMarkus Armbruster qemu_printf("ITTR0: "); 569fad866daSMarkus Armbruster dump_ttr(env->mmu.ttr[M68K_ITTR0]); 570fad866daSMarkus Armbruster qemu_printf("ITTR1: "); 571fad866daSMarkus Armbruster dump_ttr(env->mmu.ttr[M68K_ITTR1]); 572fad866daSMarkus Armbruster qemu_printf("DTTR0: "); 573fad866daSMarkus Armbruster dump_ttr(env->mmu.ttr[M68K_DTTR0]); 574fad866daSMarkus Armbruster qemu_printf("DTTR1: "); 575fad866daSMarkus Armbruster dump_ttr(env->mmu.ttr[M68K_DTTR1]); 5762097dca6SLaurent Vivier 577fad866daSMarkus Armbruster qemu_printf("SRP: 0x%08x\n", env->mmu.srp); 578fad866daSMarkus Armbruster dump_address_map(env, env->mmu.srp); 5792097dca6SLaurent Vivier 580fad866daSMarkus Armbruster qemu_printf("URP: 0x%08x\n", env->mmu.urp); 581fad866daSMarkus Armbruster dump_address_map(env, env->mmu.urp); 5822097dca6SLaurent Vivier } 5832097dca6SLaurent Vivier 584c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr, 585c05c73b0SLaurent Vivier int access_type) 586c05c73b0SLaurent Vivier { 587c05c73b0SLaurent Vivier uint32_t base, mask; 588c05c73b0SLaurent Vivier 589c05c73b0SLaurent Vivier /* check if transparent translation is enabled */ 590c05c73b0SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 591c05c73b0SLaurent Vivier return 0; 592c05c73b0SLaurent Vivier } 593c05c73b0SLaurent Vivier 594c05c73b0SLaurent Vivier /* check mode access */ 595c05c73b0SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 596c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_USER: 597c05c73b0SLaurent Vivier /* match only if user */ 598c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) != 0) { 599c05c73b0SLaurent Vivier return 0; 600c05c73b0SLaurent Vivier } 601c05c73b0SLaurent Vivier break; 602c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 603c05c73b0SLaurent Vivier /* match only if supervisor */ 604c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 605c05c73b0SLaurent Vivier return 0; 606c05c73b0SLaurent Vivier } 607c05c73b0SLaurent Vivier break; 608c05c73b0SLaurent Vivier default: 609c05c73b0SLaurent Vivier /* all other values disable mode matching (FC2) */ 610c05c73b0SLaurent Vivier break; 611c05c73b0SLaurent Vivier } 612c05c73b0SLaurent Vivier 613c05c73b0SLaurent Vivier /* check address matching */ 614c05c73b0SLaurent Vivier 615c05c73b0SLaurent Vivier base = ttr & M68K_TTR_ADDR_BASE; 616c05c73b0SLaurent Vivier mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK; 617c05c73b0SLaurent Vivier mask <<= M68K_TTR_ADDR_MASK_SHIFT; 618c05c73b0SLaurent Vivier 619c05c73b0SLaurent Vivier if ((addr & mask) != (base & mask)) { 620c05c73b0SLaurent Vivier return 0; 621c05c73b0SLaurent Vivier } 622c05c73b0SLaurent Vivier 623c05c73b0SLaurent Vivier *prot = PAGE_READ | PAGE_EXEC; 624c05c73b0SLaurent Vivier if ((ttr & M68K_DESC_WRITEPROT) == 0) { 625c05c73b0SLaurent Vivier *prot |= PAGE_WRITE; 626c05c73b0SLaurent Vivier } 627c05c73b0SLaurent Vivier 628c05c73b0SLaurent Vivier return 1; 629c05c73b0SLaurent Vivier } 630c05c73b0SLaurent Vivier 63188b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical, 63288b2fef6SLaurent Vivier int *prot, target_ulong address, 63388b2fef6SLaurent Vivier int access_type, target_ulong *page_size) 63488b2fef6SLaurent Vivier { 635a8d92fd8SRichard Henderson CPUState *cs = env_cpu(env); 63688b2fef6SLaurent Vivier uint32_t entry; 63788b2fef6SLaurent Vivier uint32_t next; 63888b2fef6SLaurent Vivier target_ulong page_mask; 63988b2fef6SLaurent Vivier bool debug = access_type & ACCESS_DEBUG; 64088b2fef6SLaurent Vivier int page_bits; 641c05c73b0SLaurent Vivier int i; 642adcf0bf0SPeter Maydell MemTxResult txres; 643c05c73b0SLaurent Vivier 644c05c73b0SLaurent Vivier /* Transparent Translation (physical = logical) */ 645c05c73b0SLaurent Vivier for (i = 0; i < M68K_MAX_TTR; i++) { 646c05c73b0SLaurent Vivier if (check_TTR(env->mmu.TTR(access_type, i), 647c05c73b0SLaurent Vivier prot, address, access_type)) { 648e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 649e55886c3SLaurent Vivier /* Transparent Translation Register bit */ 650e55886c3SLaurent Vivier env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040; 651e55886c3SLaurent Vivier } 652c05c73b0SLaurent Vivier *physical = address & TARGET_PAGE_MASK; 653c05c73b0SLaurent Vivier *page_size = TARGET_PAGE_SIZE; 654c05c73b0SLaurent Vivier return 0; 655c05c73b0SLaurent Vivier } 656c05c73b0SLaurent Vivier } 65788b2fef6SLaurent Vivier 65888b2fef6SLaurent Vivier /* Page Table Root Pointer */ 65988b2fef6SLaurent Vivier *prot = PAGE_READ | PAGE_WRITE; 66088b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 66188b2fef6SLaurent Vivier *prot |= PAGE_EXEC; 66288b2fef6SLaurent Vivier } 66388b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 66488b2fef6SLaurent Vivier next = env->mmu.srp; 66588b2fef6SLaurent Vivier } else { 66688b2fef6SLaurent Vivier next = env->mmu.urp; 66788b2fef6SLaurent Vivier } 66888b2fef6SLaurent Vivier 66988b2fef6SLaurent Vivier /* Root Index */ 67088b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address); 67188b2fef6SLaurent Vivier 672adcf0bf0SPeter Maydell next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres); 673adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 674adcf0bf0SPeter Maydell goto txfail; 675adcf0bf0SPeter Maydell } 67688b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 67788b2fef6SLaurent Vivier return -1; 67888b2fef6SLaurent Vivier } 67988b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 680adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, next | M68K_DESC_USED, 681adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 682adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 683adcf0bf0SPeter Maydell goto txfail; 684adcf0bf0SPeter Maydell } 68588b2fef6SLaurent Vivier } 68688b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 687e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 688e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_WP_040; 689e55886c3SLaurent Vivier } 69088b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 69188b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 69288b2fef6SLaurent Vivier return -1; 69388b2fef6SLaurent Vivier } 69488b2fef6SLaurent Vivier } 69588b2fef6SLaurent Vivier 69688b2fef6SLaurent Vivier /* Pointer Index */ 69788b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address); 69888b2fef6SLaurent Vivier 699adcf0bf0SPeter Maydell next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres); 700adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 701adcf0bf0SPeter Maydell goto txfail; 702adcf0bf0SPeter Maydell } 70388b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 70488b2fef6SLaurent Vivier return -1; 70588b2fef6SLaurent Vivier } 70688b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 707adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, next | M68K_DESC_USED, 708adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 709adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 710adcf0bf0SPeter Maydell goto txfail; 711adcf0bf0SPeter Maydell } 71288b2fef6SLaurent Vivier } 71388b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 714e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 715e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_WP_040; 716e55886c3SLaurent Vivier } 71788b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 71888b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 71988b2fef6SLaurent Vivier return -1; 72088b2fef6SLaurent Vivier } 72188b2fef6SLaurent Vivier } 72288b2fef6SLaurent Vivier 72388b2fef6SLaurent Vivier /* Page Index */ 72488b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 72588b2fef6SLaurent Vivier entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address); 72688b2fef6SLaurent Vivier } else { 72788b2fef6SLaurent Vivier entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address); 72888b2fef6SLaurent Vivier } 72988b2fef6SLaurent Vivier 730adcf0bf0SPeter Maydell next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres); 731adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 732adcf0bf0SPeter Maydell goto txfail; 733adcf0bf0SPeter Maydell } 73488b2fef6SLaurent Vivier 73588b2fef6SLaurent Vivier if (!M68K_PDT_VALID(next)) { 73688b2fef6SLaurent Vivier return -1; 73788b2fef6SLaurent Vivier } 73888b2fef6SLaurent Vivier if (M68K_PDT_INDIRECT(next)) { 739adcf0bf0SPeter Maydell next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next), 740adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 741adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 742adcf0bf0SPeter Maydell goto txfail; 743adcf0bf0SPeter Maydell } 74488b2fef6SLaurent Vivier } 74588b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 74688b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 74788b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 748adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, next | M68K_DESC_USED, 749adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 750adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 751adcf0bf0SPeter Maydell goto txfail; 752adcf0bf0SPeter Maydell } 75388b2fef6SLaurent Vivier } 75488b2fef6SLaurent Vivier } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) != 75588b2fef6SLaurent Vivier (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) { 756adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, 757adcf0bf0SPeter Maydell next | (M68K_DESC_MODIFIED | M68K_DESC_USED), 758adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 759adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 760adcf0bf0SPeter Maydell goto txfail; 761adcf0bf0SPeter Maydell } 76288b2fef6SLaurent Vivier } 76388b2fef6SLaurent Vivier } else { 76488b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 765adcf0bf0SPeter Maydell address_space_stl(cs->as, entry, next | M68K_DESC_USED, 766adcf0bf0SPeter Maydell MEMTXATTRS_UNSPECIFIED, &txres); 767adcf0bf0SPeter Maydell if (txres != MEMTX_OK) { 768adcf0bf0SPeter Maydell goto txfail; 769adcf0bf0SPeter Maydell } 77088b2fef6SLaurent Vivier } 77188b2fef6SLaurent Vivier } 77288b2fef6SLaurent Vivier 77388b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 77488b2fef6SLaurent Vivier page_bits = 13; 77588b2fef6SLaurent Vivier } else { 77688b2fef6SLaurent Vivier page_bits = 12; 77788b2fef6SLaurent Vivier } 77888b2fef6SLaurent Vivier *page_size = 1 << page_bits; 77988b2fef6SLaurent Vivier page_mask = ~(*page_size - 1); 78088b2fef6SLaurent Vivier *physical = next & page_mask; 78188b2fef6SLaurent Vivier 782e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 783e55886c3SLaurent Vivier env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040; 784e55886c3SLaurent Vivier env->mmu.mmusr |= *physical & 0xfffff000; 785e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_R_040; 786e55886c3SLaurent Vivier } 787e55886c3SLaurent Vivier 78888b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 78988b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 79088b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 79188b2fef6SLaurent Vivier return -1; 79288b2fef6SLaurent Vivier } 79388b2fef6SLaurent Vivier } 79488b2fef6SLaurent Vivier if (next & M68K_DESC_SUPERONLY) { 79588b2fef6SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 79688b2fef6SLaurent Vivier return -1; 79788b2fef6SLaurent Vivier } 79888b2fef6SLaurent Vivier } 79988b2fef6SLaurent Vivier 80088b2fef6SLaurent Vivier return 0; 801adcf0bf0SPeter Maydell 802adcf0bf0SPeter Maydell txfail: 803adcf0bf0SPeter Maydell /* 804adcf0bf0SPeter Maydell * A page table load/store failed. TODO: we should really raise a 805adcf0bf0SPeter Maydell * suitable guest fault here if this is not a debug access. 806adcf0bf0SPeter Maydell * For now just return that the translation failed. 807adcf0bf0SPeter Maydell */ 808adcf0bf0SPeter Maydell return -1; 80988b2fef6SLaurent Vivier } 81088b2fef6SLaurent Vivier 81100b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 8124fcc562bSPaul Brook { 81388b2fef6SLaurent Vivier M68kCPU *cpu = M68K_CPU(cs); 81488b2fef6SLaurent Vivier CPUM68KState *env = &cpu->env; 81588b2fef6SLaurent Vivier hwaddr phys_addr; 81688b2fef6SLaurent Vivier int prot; 81788b2fef6SLaurent Vivier int access_type; 81888b2fef6SLaurent Vivier target_ulong page_size; 81988b2fef6SLaurent Vivier 82088b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 82188b2fef6SLaurent Vivier /* MMU disabled */ 8224fcc562bSPaul Brook return addr; 8234fcc562bSPaul Brook } 8244fcc562bSPaul Brook 82588b2fef6SLaurent Vivier access_type = ACCESS_DATA | ACCESS_DEBUG; 82688b2fef6SLaurent Vivier if (env->sr & SR_S) { 82788b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 82888b2fef6SLaurent Vivier } 82988b2fef6SLaurent Vivier if (get_physical_address(env, &phys_addr, &prot, 83088b2fef6SLaurent Vivier addr, access_type, &page_size) != 0) { 83188b2fef6SLaurent Vivier return -1; 83288b2fef6SLaurent Vivier } 83388b2fef6SLaurent Vivier return phys_addr; 83488b2fef6SLaurent Vivier } 83588b2fef6SLaurent Vivier 836fe5f7b1bSRichard Henderson /* 837fe5f7b1bSRichard Henderson * Notify CPU of a pending interrupt. Prioritization and vectoring should 838fe5f7b1bSRichard Henderson * be handled by the interrupt controller. Real hardware only requests 839fe5f7b1bSRichard Henderson * the vector when the interrupt is acknowledged by the CPU. For 840fe5f7b1bSRichard Henderson * simplicity we calculate it when the interrupt is signalled. 841fe5f7b1bSRichard Henderson */ 842fe5f7b1bSRichard Henderson void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) 843fe5f7b1bSRichard Henderson { 844fe5f7b1bSRichard Henderson CPUState *cs = CPU(cpu); 845fe5f7b1bSRichard Henderson CPUM68KState *env = &cpu->env; 846fe5f7b1bSRichard Henderson 847fe5f7b1bSRichard Henderson env->pending_level = level; 848fe5f7b1bSRichard Henderson env->pending_vector = vector; 849fe5f7b1bSRichard Henderson if (level) { 850fe5f7b1bSRichard Henderson cpu_interrupt(cs, CPU_INTERRUPT_HARD); 851fe5f7b1bSRichard Henderson } else { 852fe5f7b1bSRichard Henderson cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 853fe5f7b1bSRichard Henderson } 854fe5f7b1bSRichard Henderson } 855fe5f7b1bSRichard Henderson 856fe5f7b1bSRichard Henderson #endif 857fe5f7b1bSRichard Henderson 858fe5f7b1bSRichard Henderson bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 859fe5f7b1bSRichard Henderson MMUAccessType qemu_access_type, int mmu_idx, 860fe5f7b1bSRichard Henderson bool probe, uintptr_t retaddr) 8610633879fSpbrook { 86288b2fef6SLaurent Vivier M68kCPU *cpu = M68K_CPU(cs); 86388b2fef6SLaurent Vivier CPUM68KState *env = &cpu->env; 864fe5f7b1bSRichard Henderson 865fe5f7b1bSRichard Henderson #ifndef CONFIG_USER_ONLY 86688b2fef6SLaurent Vivier hwaddr physical; 8670633879fSpbrook int prot; 86888b2fef6SLaurent Vivier int access_type; 86988b2fef6SLaurent Vivier int ret; 87088b2fef6SLaurent Vivier target_ulong page_size; 8710633879fSpbrook 87288b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 87388b2fef6SLaurent Vivier /* MMU disabled */ 87488b2fef6SLaurent Vivier tlb_set_page(cs, address & TARGET_PAGE_MASK, 87588b2fef6SLaurent Vivier address & TARGET_PAGE_MASK, 87688b2fef6SLaurent Vivier PAGE_READ | PAGE_WRITE | PAGE_EXEC, 87788b2fef6SLaurent Vivier mmu_idx, TARGET_PAGE_SIZE); 878fe5f7b1bSRichard Henderson return true; 8790633879fSpbrook } 8800633879fSpbrook 881fe5f7b1bSRichard Henderson if (qemu_access_type == MMU_INST_FETCH) { 88288b2fef6SLaurent Vivier access_type = ACCESS_CODE; 88388b2fef6SLaurent Vivier } else { 88488b2fef6SLaurent Vivier access_type = ACCESS_DATA; 885fe5f7b1bSRichard Henderson if (qemu_access_type == MMU_DATA_STORE) { 88688b2fef6SLaurent Vivier access_type |= ACCESS_STORE; 88788b2fef6SLaurent Vivier } 88888b2fef6SLaurent Vivier } 88988b2fef6SLaurent Vivier if (mmu_idx != MMU_USER_IDX) { 89088b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 89188b2fef6SLaurent Vivier } 89288b2fef6SLaurent Vivier 89388b2fef6SLaurent Vivier ret = get_physical_address(&cpu->env, &physical, &prot, 89488b2fef6SLaurent Vivier address, access_type, &page_size); 895fe5f7b1bSRichard Henderson if (likely(ret == 0)) { 89688b2fef6SLaurent Vivier address &= TARGET_PAGE_MASK; 89788b2fef6SLaurent Vivier physical += address & (page_size - 1); 89888b2fef6SLaurent Vivier tlb_set_page(cs, address, physical, 89988b2fef6SLaurent Vivier prot, mmu_idx, TARGET_PAGE_SIZE); 900fe5f7b1bSRichard Henderson return true; 90188b2fef6SLaurent Vivier } 902fe5f7b1bSRichard Henderson 903fe5f7b1bSRichard Henderson if (probe) { 904fe5f7b1bSRichard Henderson return false; 905fe5f7b1bSRichard Henderson } 906fe5f7b1bSRichard Henderson 90788b2fef6SLaurent Vivier /* page fault */ 90888b2fef6SLaurent Vivier env->mmu.ssw = M68K_ATC_040; 90988b2fef6SLaurent Vivier switch (size) { 91088b2fef6SLaurent Vivier case 1: 91188b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_BYTE; 91288b2fef6SLaurent Vivier break; 91388b2fef6SLaurent Vivier case 2: 91488b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_WORD; 91588b2fef6SLaurent Vivier break; 91688b2fef6SLaurent Vivier case 4: 91788b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_LONG; 91888b2fef6SLaurent Vivier break; 91988b2fef6SLaurent Vivier } 92088b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 92188b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_SUPER; 92288b2fef6SLaurent Vivier } 92388b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 92488b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_CODE; 92588b2fef6SLaurent Vivier } else { 92688b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_DATA; 92788b2fef6SLaurent Vivier } 92888b2fef6SLaurent Vivier if (!(access_type & ACCESS_STORE)) { 92988b2fef6SLaurent Vivier env->mmu.ssw |= M68K_RW_040; 93088b2fef6SLaurent Vivier } 931fe5f7b1bSRichard Henderson #endif 932fe5f7b1bSRichard Henderson 93388b2fef6SLaurent Vivier cs->exception_index = EXCP_ACCESS; 934fe5f7b1bSRichard Henderson env->mmu.ar = address; 935fe5f7b1bSRichard Henderson cpu_loop_exit_restore(cs, retaddr); 93688b2fef6SLaurent Vivier } 93788b2fef6SLaurent Vivier 938e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x) 939e1f3808eSpbrook { 940e1f3808eSpbrook x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); 941e1f3808eSpbrook x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); 942e1f3808eSpbrook x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); 943e1f3808eSpbrook return bswap32(x); 944e1f3808eSpbrook } 945e1f3808eSpbrook 946e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x) 947e1f3808eSpbrook { 948e1f3808eSpbrook int n; 949e1f3808eSpbrook for (n = 32; x; n--) 950e1f3808eSpbrook x >>= 1; 951e1f3808eSpbrook return n; 952e1f3808eSpbrook } 953e1f3808eSpbrook 954620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v) 955e1f3808eSpbrook { 956e1f3808eSpbrook /* The result has the opposite sign to the original value. */ 957620c6cf6SRichard Henderson if ((int32_t)v < 0) { 958e1f3808eSpbrook val = (((int32_t)val) >> 31) ^ SIGNBIT; 959620c6cf6SRichard Henderson } 960e1f3808eSpbrook return val; 961e1f3808eSpbrook } 962e1f3808eSpbrook 963d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) 964e1f3808eSpbrook { 965d2f8fb8eSLaurent Vivier env->sr = sr & 0xffe0; 966d2f8fb8eSLaurent Vivier cpu_m68k_set_ccr(env, sr); 967e1f3808eSpbrook m68k_switch_sp(env); 968e1f3808eSpbrook } 969e1f3808eSpbrook 970d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val) 971d2f8fb8eSLaurent Vivier { 972d2f8fb8eSLaurent Vivier cpu_m68k_set_sr(env, val); 973d2f8fb8eSLaurent Vivier } 974e1f3808eSpbrook 975e1f3808eSpbrook /* MAC unit. */ 976808d77bcSLucien Murray-Pitts /* 977808d77bcSLucien Murray-Pitts * FIXME: The MAC unit implementation is a bit of a mess. Some helpers 978808d77bcSLucien Murray-Pitts * take values, others take register numbers and manipulate the contents 979808d77bcSLucien Murray-Pitts * in-place. 980808d77bcSLucien Murray-Pitts */ 9812b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) 982e1f3808eSpbrook { 983e1f3808eSpbrook uint32_t mask; 984e1f3808eSpbrook env->macc[dest] = env->macc[src]; 985e1f3808eSpbrook mask = MACSR_PAV0 << dest; 986e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << src)) 987e1f3808eSpbrook env->macsr |= mask; 988e1f3808eSpbrook else 989e1f3808eSpbrook env->macsr &= ~mask; 990e1f3808eSpbrook } 991e1f3808eSpbrook 9922b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) 993e1f3808eSpbrook { 994e1f3808eSpbrook int64_t product; 995e1f3808eSpbrook int64_t res; 996e1f3808eSpbrook 997e1f3808eSpbrook product = (uint64_t)op1 * op2; 998e1f3808eSpbrook res = (product << 24) >> 24; 999e1f3808eSpbrook if (res != product) { 1000e1f3808eSpbrook env->macsr |= MACSR_V; 1001e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1002e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 1003e1f3808eSpbrook if (product < 0) 1004e1f3808eSpbrook res = ~(1ll << 50); 1005e1f3808eSpbrook else 1006e1f3808eSpbrook res = 1ll << 50; 1007e1f3808eSpbrook } 1008e1f3808eSpbrook } 1009e1f3808eSpbrook return res; 1010e1f3808eSpbrook } 1011e1f3808eSpbrook 10122b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) 1013e1f3808eSpbrook { 1014e1f3808eSpbrook uint64_t product; 1015e1f3808eSpbrook 1016e1f3808eSpbrook product = (uint64_t)op1 * op2; 1017e1f3808eSpbrook if (product & (0xffffffull << 40)) { 1018e1f3808eSpbrook env->macsr |= MACSR_V; 1019e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1020e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 1021e1f3808eSpbrook product = 1ll << 50; 1022e1f3808eSpbrook } else { 1023e1f3808eSpbrook product &= ((1ull << 40) - 1); 1024e1f3808eSpbrook } 1025e1f3808eSpbrook } 1026e1f3808eSpbrook return product; 1027e1f3808eSpbrook } 1028e1f3808eSpbrook 10292b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) 1030e1f3808eSpbrook { 1031e1f3808eSpbrook uint64_t product; 1032e1f3808eSpbrook uint32_t remainder; 1033e1f3808eSpbrook 1034e1f3808eSpbrook product = (uint64_t)op1 * op2; 1035e1f3808eSpbrook if (env->macsr & MACSR_RT) { 1036e1f3808eSpbrook remainder = product & 0xffffff; 1037e1f3808eSpbrook product >>= 24; 1038e1f3808eSpbrook if (remainder > 0x800000) 1039e1f3808eSpbrook product++; 1040e1f3808eSpbrook else if (remainder == 0x800000) 1041e1f3808eSpbrook product += (product & 1); 1042e1f3808eSpbrook } else { 1043e1f3808eSpbrook product >>= 24; 1044e1f3808eSpbrook } 1045e1f3808eSpbrook return product; 1046e1f3808eSpbrook } 1047e1f3808eSpbrook 10482b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc) 1049e1f3808eSpbrook { 1050e1f3808eSpbrook int64_t tmp; 1051e1f3808eSpbrook int64_t result; 1052e1f3808eSpbrook tmp = env->macc[acc]; 1053e1f3808eSpbrook result = ((tmp << 16) >> 16); 1054e1f3808eSpbrook if (result != tmp) { 1055e1f3808eSpbrook env->macsr |= MACSR_V; 1056e1f3808eSpbrook } 1057e1f3808eSpbrook if (env->macsr & MACSR_V) { 1058e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1059e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1060808d77bcSLucien Murray-Pitts /* 1061808d77bcSLucien Murray-Pitts * The result is saturated to 32 bits, despite overflow occurring 1062808d77bcSLucien Murray-Pitts * at 48 bits. Seems weird, but that's what the hardware docs 1063808d77bcSLucien Murray-Pitts * say. 1064808d77bcSLucien Murray-Pitts */ 1065e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffff; 1066e1f3808eSpbrook } 1067e1f3808eSpbrook } 1068e1f3808eSpbrook env->macc[acc] = result; 1069e1f3808eSpbrook } 1070e1f3808eSpbrook 10712b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) 1072e1f3808eSpbrook { 1073e1f3808eSpbrook uint64_t val; 1074e1f3808eSpbrook 1075e1f3808eSpbrook val = env->macc[acc]; 1076e1f3808eSpbrook if (val & (0xffffull << 48)) { 1077e1f3808eSpbrook env->macsr |= MACSR_V; 1078e1f3808eSpbrook } 1079e1f3808eSpbrook if (env->macsr & MACSR_V) { 1080e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1081e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1082e1f3808eSpbrook if (val > (1ull << 53)) 1083e1f3808eSpbrook val = 0; 1084e1f3808eSpbrook else 1085e1f3808eSpbrook val = (1ull << 48) - 1; 1086e1f3808eSpbrook } else { 1087e1f3808eSpbrook val &= ((1ull << 48) - 1); 1088e1f3808eSpbrook } 1089e1f3808eSpbrook } 1090e1f3808eSpbrook env->macc[acc] = val; 1091e1f3808eSpbrook } 1092e1f3808eSpbrook 10932b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) 1094e1f3808eSpbrook { 1095e1f3808eSpbrook int64_t sum; 1096e1f3808eSpbrook int64_t result; 1097e1f3808eSpbrook 1098e1f3808eSpbrook sum = env->macc[acc]; 1099e1f3808eSpbrook result = (sum << 16) >> 16; 1100e1f3808eSpbrook if (result != sum) { 1101e1f3808eSpbrook env->macsr |= MACSR_V; 1102e1f3808eSpbrook } 1103e1f3808eSpbrook if (env->macsr & MACSR_V) { 1104e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1105e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1106e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffffffffll; 1107e1f3808eSpbrook } 1108e1f3808eSpbrook } 1109e1f3808eSpbrook env->macc[acc] = result; 1110e1f3808eSpbrook } 1111e1f3808eSpbrook 11122b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) 1113e1f3808eSpbrook { 1114e1f3808eSpbrook uint64_t val; 1115e1f3808eSpbrook val = env->macc[acc]; 1116c4162574SBlue Swirl if (val == 0) { 1117e1f3808eSpbrook env->macsr |= MACSR_Z; 1118c4162574SBlue Swirl } else if (val & (1ull << 47)) { 1119e1f3808eSpbrook env->macsr |= MACSR_N; 1120c4162574SBlue Swirl } 1121e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << acc)) { 1122e1f3808eSpbrook env->macsr |= MACSR_V; 1123e1f3808eSpbrook } 1124e1f3808eSpbrook if (env->macsr & MACSR_FI) { 1125e1f3808eSpbrook val = ((int64_t)val) >> 40; 1126e1f3808eSpbrook if (val != 0 && val != -1) 1127e1f3808eSpbrook env->macsr |= MACSR_EV; 1128e1f3808eSpbrook } else if (env->macsr & MACSR_SU) { 1129e1f3808eSpbrook val = ((int64_t)val) >> 32; 1130e1f3808eSpbrook if (val != 0 && val != -1) 1131e1f3808eSpbrook env->macsr |= MACSR_EV; 1132e1f3808eSpbrook } else { 1133e1f3808eSpbrook if ((val >> 32) != 0) 1134e1f3808eSpbrook env->macsr |= MACSR_EV; 1135e1f3808eSpbrook } 1136e1f3808eSpbrook } 1137e1f3808eSpbrook 1138db3d7945SLaurent Vivier #define EXTSIGN(val, index) ( \ 1139db3d7945SLaurent Vivier (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ 1140db3d7945SLaurent Vivier ) 1141620c6cf6SRichard Henderson 1142620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) { \ 1143620c6cf6SRichard Henderson switch (op) { \ 1144620c6cf6SRichard Henderson case CC_OP_FLAGS: \ 1145620c6cf6SRichard Henderson /* Everything in place. */ \ 1146620c6cf6SRichard Henderson break; \ 1147db3d7945SLaurent Vivier case CC_OP_ADDB: \ 1148db3d7945SLaurent Vivier case CC_OP_ADDW: \ 1149db3d7945SLaurent Vivier case CC_OP_ADDL: \ 1150620c6cf6SRichard Henderson res = n; \ 1151620c6cf6SRichard Henderson src2 = v; \ 1152db3d7945SLaurent Vivier src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ 1153620c6cf6SRichard Henderson c = x; \ 1154620c6cf6SRichard Henderson z = n; \ 1155620c6cf6SRichard Henderson v = (res ^ src1) & ~(src1 ^ src2); \ 1156620c6cf6SRichard Henderson break; \ 1157db3d7945SLaurent Vivier case CC_OP_SUBB: \ 1158db3d7945SLaurent Vivier case CC_OP_SUBW: \ 1159db3d7945SLaurent Vivier case CC_OP_SUBL: \ 1160620c6cf6SRichard Henderson res = n; \ 1161620c6cf6SRichard Henderson src2 = v; \ 1162db3d7945SLaurent Vivier src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ 1163620c6cf6SRichard Henderson c = x; \ 1164620c6cf6SRichard Henderson z = n; \ 1165620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 1166620c6cf6SRichard Henderson break; \ 1167db3d7945SLaurent Vivier case CC_OP_CMPB: \ 1168db3d7945SLaurent Vivier case CC_OP_CMPW: \ 1169db3d7945SLaurent Vivier case CC_OP_CMPL: \ 1170620c6cf6SRichard Henderson src1 = n; \ 1171620c6cf6SRichard Henderson src2 = v; \ 1172db3d7945SLaurent Vivier res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ 1173620c6cf6SRichard Henderson n = res; \ 1174620c6cf6SRichard Henderson z = res; \ 1175620c6cf6SRichard Henderson c = src1 < src2; \ 1176620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 1177620c6cf6SRichard Henderson break; \ 1178620c6cf6SRichard Henderson case CC_OP_LOGIC: \ 1179620c6cf6SRichard Henderson c = v = 0; \ 1180620c6cf6SRichard Henderson z = n; \ 1181620c6cf6SRichard Henderson break; \ 1182620c6cf6SRichard Henderson default: \ 1183a8d92fd8SRichard Henderson cpu_abort(env_cpu(env), "Bad CC_OP %d", op); \ 1184620c6cf6SRichard Henderson } \ 1185620c6cf6SRichard Henderson } while (0) 1186620c6cf6SRichard Henderson 1187620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env) 1188e1f3808eSpbrook { 1189620c6cf6SRichard Henderson uint32_t x, c, n, z, v; 1190620c6cf6SRichard Henderson uint32_t res, src1, src2; 1191620c6cf6SRichard Henderson 1192620c6cf6SRichard Henderson x = env->cc_x; 1193620c6cf6SRichard Henderson n = env->cc_n; 1194620c6cf6SRichard Henderson z = env->cc_z; 1195620c6cf6SRichard Henderson v = env->cc_v; 1196db3d7945SLaurent Vivier c = env->cc_c; 1197620c6cf6SRichard Henderson 1198620c6cf6SRichard Henderson COMPUTE_CCR(env->cc_op, x, n, z, v, c); 1199620c6cf6SRichard Henderson 1200620c6cf6SRichard Henderson n = n >> 31; 1201620c6cf6SRichard Henderson z = (z == 0); 1202db3d7945SLaurent Vivier v = v >> 31; 1203620c6cf6SRichard Henderson 1204620c6cf6SRichard Henderson return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; 1205620c6cf6SRichard Henderson } 1206620c6cf6SRichard Henderson 1207620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env) 1208620c6cf6SRichard Henderson { 1209620c6cf6SRichard Henderson return cpu_m68k_get_ccr(env); 1210620c6cf6SRichard Henderson } 1211620c6cf6SRichard Henderson 1212620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) 1213620c6cf6SRichard Henderson { 1214620c6cf6SRichard Henderson env->cc_x = (ccr & CCF_X ? 1 : 0); 1215620c6cf6SRichard Henderson env->cc_n = (ccr & CCF_N ? -1 : 0); 1216620c6cf6SRichard Henderson env->cc_z = (ccr & CCF_Z ? 0 : 1); 1217620c6cf6SRichard Henderson env->cc_v = (ccr & CCF_V ? -1 : 0); 1218620c6cf6SRichard Henderson env->cc_c = (ccr & CCF_C ? 1 : 0); 1219620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 1220620c6cf6SRichard Henderson } 1221620c6cf6SRichard Henderson 1222620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) 1223620c6cf6SRichard Henderson { 1224620c6cf6SRichard Henderson cpu_m68k_set_ccr(env, ccr); 1225620c6cf6SRichard Henderson } 1226620c6cf6SRichard Henderson 1227620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) 1228620c6cf6SRichard Henderson { 1229620c6cf6SRichard Henderson uint32_t res, src1, src2; 1230620c6cf6SRichard Henderson 1231620c6cf6SRichard Henderson COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); 1232620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 1233e1f3808eSpbrook } 1234e1f3808eSpbrook 12352b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) 1236e1f3808eSpbrook { 1237e1f3808eSpbrook int rem; 1238e1f3808eSpbrook uint32_t result; 1239e1f3808eSpbrook 1240e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1241e1f3808eSpbrook /* 16-bit rounding. */ 1242e1f3808eSpbrook rem = val & 0xffffff; 1243e1f3808eSpbrook val = (val >> 24) & 0xffffu; 1244e1f3808eSpbrook if (rem > 0x800000) 1245e1f3808eSpbrook val++; 1246e1f3808eSpbrook else if (rem == 0x800000) 1247e1f3808eSpbrook val += (val & 1); 1248e1f3808eSpbrook } else if (env->macsr & MACSR_RT) { 1249e1f3808eSpbrook /* 32-bit rounding. */ 1250e1f3808eSpbrook rem = val & 0xff; 1251e1f3808eSpbrook val >>= 8; 1252e1f3808eSpbrook if (rem > 0x80) 1253e1f3808eSpbrook val++; 1254e1f3808eSpbrook else if (rem == 0x80) 1255e1f3808eSpbrook val += (val & 1); 1256e1f3808eSpbrook } else { 1257e1f3808eSpbrook /* No rounding. */ 1258e1f3808eSpbrook val >>= 8; 1259e1f3808eSpbrook } 1260e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1261e1f3808eSpbrook /* Saturate. */ 1262e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1263e1f3808eSpbrook if (val != (uint16_t) val) { 1264e1f3808eSpbrook result = ((val >> 63) ^ 0x7fff) & 0xffff; 1265e1f3808eSpbrook } else { 1266e1f3808eSpbrook result = val & 0xffff; 1267e1f3808eSpbrook } 1268e1f3808eSpbrook } else { 1269e1f3808eSpbrook if (val != (uint32_t)val) { 1270e1f3808eSpbrook result = ((uint32_t)(val >> 63) & 0x7fffffff); 1271e1f3808eSpbrook } else { 1272e1f3808eSpbrook result = (uint32_t)val; 1273e1f3808eSpbrook } 1274e1f3808eSpbrook } 1275e1f3808eSpbrook } else { 1276e1f3808eSpbrook /* No saturation. */ 1277e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1278e1f3808eSpbrook result = val & 0xffff; 1279e1f3808eSpbrook } else { 1280e1f3808eSpbrook result = (uint32_t)val; 1281e1f3808eSpbrook } 1282e1f3808eSpbrook } 1283e1f3808eSpbrook return result; 1284e1f3808eSpbrook } 1285e1f3808eSpbrook 1286e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val) 1287e1f3808eSpbrook { 1288e1f3808eSpbrook if (val == (int32_t)val) { 1289e1f3808eSpbrook return (int32_t)val; 1290e1f3808eSpbrook } else { 1291e1f3808eSpbrook return (val >> 61) ^ ~SIGNBIT; 1292e1f3808eSpbrook } 1293e1f3808eSpbrook } 1294e1f3808eSpbrook 1295e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val) 1296e1f3808eSpbrook { 1297e1f3808eSpbrook if ((val >> 32) == 0) { 1298e1f3808eSpbrook return (uint32_t)val; 1299e1f3808eSpbrook } else { 1300e1f3808eSpbrook return 0xffffffffu; 1301e1f3808eSpbrook } 1302e1f3808eSpbrook } 1303e1f3808eSpbrook 13042b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) 1305e1f3808eSpbrook { 1306e1f3808eSpbrook uint32_t val; 1307e1f3808eSpbrook val = env->macc[acc] & 0x00ff; 13085ce747cfSPaolo Bonzini val |= (env->macc[acc] >> 32) & 0xff00; 1309e1f3808eSpbrook val |= (env->macc[acc + 1] << 16) & 0x00ff0000; 1310e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xff000000; 1311e1f3808eSpbrook return val; 1312e1f3808eSpbrook } 1313e1f3808eSpbrook 13142b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) 1315e1f3808eSpbrook { 1316e1f3808eSpbrook uint32_t val; 1317e1f3808eSpbrook val = (env->macc[acc] >> 32) & 0xffff; 1318e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xffff0000; 1319e1f3808eSpbrook return val; 1320e1f3808eSpbrook } 1321e1f3808eSpbrook 13222b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) 1323e1f3808eSpbrook { 1324e1f3808eSpbrook int64_t res; 1325e1f3808eSpbrook int32_t tmp; 1326e1f3808eSpbrook res = env->macc[acc] & 0xffffffff00ull; 1327e1f3808eSpbrook tmp = (int16_t)(val & 0xff00); 1328e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1329e1f3808eSpbrook res |= val & 0xff; 1330e1f3808eSpbrook env->macc[acc] = res; 1331e1f3808eSpbrook res = env->macc[acc + 1] & 0xffffffff00ull; 1332e1f3808eSpbrook tmp = (val & 0xff000000); 1333e1f3808eSpbrook res |= ((int64_t)tmp) << 16; 1334e1f3808eSpbrook res |= (val >> 16) & 0xff; 1335e1f3808eSpbrook env->macc[acc + 1] = res; 1336e1f3808eSpbrook } 1337e1f3808eSpbrook 13382b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) 1339e1f3808eSpbrook { 1340e1f3808eSpbrook int64_t res; 1341e1f3808eSpbrook int32_t tmp; 1342e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1343e1f3808eSpbrook tmp = (int16_t)val; 1344e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1345e1f3808eSpbrook env->macc[acc] = res; 1346e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1347e1f3808eSpbrook tmp = val & 0xffff0000; 1348e1f3808eSpbrook res |= (int64_t)tmp << 16; 1349e1f3808eSpbrook env->macc[acc + 1] = res; 1350e1f3808eSpbrook } 1351e1f3808eSpbrook 13522b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) 1353e1f3808eSpbrook { 1354e1f3808eSpbrook uint64_t res; 1355e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1356e1f3808eSpbrook res |= ((uint64_t)(val & 0xffff)) << 32; 1357e1f3808eSpbrook env->macc[acc] = res; 1358e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1359e1f3808eSpbrook res |= (uint64_t)(val & 0xffff0000) << 16; 1360e1f3808eSpbrook env->macc[acc + 1] = res; 1361e1f3808eSpbrook } 13620bdb2b3bSLaurent Vivier 13630bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU) 1364e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read) 1365e55886c3SLaurent Vivier { 1366e55886c3SLaurent Vivier hwaddr physical; 1367e55886c3SLaurent Vivier int access_type; 1368e55886c3SLaurent Vivier int prot; 1369e55886c3SLaurent Vivier int ret; 1370e55886c3SLaurent Vivier target_ulong page_size; 1371e55886c3SLaurent Vivier 1372e55886c3SLaurent Vivier access_type = ACCESS_PTEST; 1373e55886c3SLaurent Vivier if (env->dfc & 4) { 1374e55886c3SLaurent Vivier access_type |= ACCESS_SUPER; 1375e55886c3SLaurent Vivier } 1376e55886c3SLaurent Vivier if ((env->dfc & 3) == 2) { 1377e55886c3SLaurent Vivier access_type |= ACCESS_CODE; 1378e55886c3SLaurent Vivier } 1379e55886c3SLaurent Vivier if (!is_read) { 1380e55886c3SLaurent Vivier access_type |= ACCESS_STORE; 1381e55886c3SLaurent Vivier } 1382e55886c3SLaurent Vivier 1383e55886c3SLaurent Vivier env->mmu.mmusr = 0; 1384e55886c3SLaurent Vivier env->mmu.ssw = 0; 1385e55886c3SLaurent Vivier ret = get_physical_address(env, &physical, &prot, addr, 1386e55886c3SLaurent Vivier access_type, &page_size); 1387e55886c3SLaurent Vivier if (ret == 0) { 1388e55886c3SLaurent Vivier addr &= TARGET_PAGE_MASK; 1389e55886c3SLaurent Vivier physical += addr & (page_size - 1); 1390a8d92fd8SRichard Henderson tlb_set_page(env_cpu(env), addr, physical, 1391e55886c3SLaurent Vivier prot, access_type & ACCESS_SUPER ? 1392e55886c3SLaurent Vivier MMU_KERNEL_IDX : MMU_USER_IDX, page_size); 1393e55886c3SLaurent Vivier } 1394e55886c3SLaurent Vivier } 1395e55886c3SLaurent Vivier 1396e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode) 1397e55886c3SLaurent Vivier { 1398a8d92fd8SRichard Henderson CPUState *cs = env_cpu(env); 1399e55886c3SLaurent Vivier 1400e55886c3SLaurent Vivier switch (opmode) { 1401e55886c3SLaurent Vivier case 0: /* Flush page entry if not global */ 1402e55886c3SLaurent Vivier case 1: /* Flush page entry */ 1403a8d92fd8SRichard Henderson tlb_flush_page(cs, addr); 1404e55886c3SLaurent Vivier break; 1405e55886c3SLaurent Vivier case 2: /* Flush all except global entries */ 1406a8d92fd8SRichard Henderson tlb_flush(cs); 1407e55886c3SLaurent Vivier break; 1408e55886c3SLaurent Vivier case 3: /* Flush all entries */ 1409a8d92fd8SRichard Henderson tlb_flush(cs); 1410e55886c3SLaurent Vivier break; 1411e55886c3SLaurent Vivier } 1412e55886c3SLaurent Vivier } 1413e55886c3SLaurent Vivier 14140bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env) 14150bdb2b3bSLaurent Vivier { 14160bdb2b3bSLaurent Vivier /* FIXME: reset all except CPU */ 14170bdb2b3bSLaurent Vivier } 14180bdb2b3bSLaurent Vivier #endif 1419