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" 27*0442428aSMarkus 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)); 57*0442428aSMarkus Armbruster qemu_printf("%s\n", name); 587a9f812bSAndreas Färber g_free(name); 5911150915SAndreas Färber } 600402f767Spbrook 61*0442428aSMarkus 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); 67*0442428aSMarkus 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 { 171a47dddd7SAndreas Färber M68kCPU *cpu = m68k_env_get_cpu(env); 172a47dddd7SAndreas Färber 1730633879fSpbrook switch (reg) { 1746e22b28eSLaurent Vivier case M68K_CR_CACR: 17520dcee94Spbrook env->cacr = val; 17620dcee94Spbrook m68k_switch_sp(env); 17720dcee94Spbrook break; 1786e22b28eSLaurent Vivier case M68K_CR_ACR0: 1796e22b28eSLaurent Vivier case M68K_CR_ACR1: 1806e22b28eSLaurent Vivier case M68K_CR_ACR2: 1816e22b28eSLaurent Vivier case M68K_CR_ACR3: 18220dcee94Spbrook /* TODO: Implement Access Control Registers. */ 1830633879fSpbrook break; 1846e22b28eSLaurent Vivier case M68K_CR_VBR: 1850633879fSpbrook env->vbr = val; 1860633879fSpbrook break; 1870633879fSpbrook /* TODO: Implement control registers. */ 1880633879fSpbrook default: 1896e22b28eSLaurent Vivier cpu_abort(CPU(cpu), 1906e22b28eSLaurent Vivier "Unimplemented control register write 0x%x = 0x%x\n", 1916e22b28eSLaurent Vivier reg, val); 1926e22b28eSLaurent Vivier } 1936e22b28eSLaurent Vivier } 1946e22b28eSLaurent Vivier 1956e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) 1966e22b28eSLaurent Vivier { 1976e22b28eSLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 1986e22b28eSLaurent Vivier 1996e22b28eSLaurent Vivier switch (reg) { 2006e22b28eSLaurent Vivier /* MC680[1234]0 */ 2015fa9f1f2SLaurent Vivier case M68K_CR_SFC: 2025fa9f1f2SLaurent Vivier env->sfc = val & 7; 2035fa9f1f2SLaurent Vivier return; 2045fa9f1f2SLaurent Vivier case M68K_CR_DFC: 2055fa9f1f2SLaurent Vivier env->dfc = val & 7; 2065fa9f1f2SLaurent Vivier return; 2076e22b28eSLaurent Vivier case M68K_CR_VBR: 2086e22b28eSLaurent Vivier env->vbr = val; 2096e22b28eSLaurent Vivier return; 2106e22b28eSLaurent Vivier /* MC680[234]0 */ 2116e22b28eSLaurent Vivier case M68K_CR_CACR: 2126e22b28eSLaurent Vivier env->cacr = val; 2136e22b28eSLaurent Vivier m68k_switch_sp(env); 2146e22b28eSLaurent Vivier return; 2156e22b28eSLaurent Vivier /* MC680[34]0 */ 21688b2fef6SLaurent Vivier case M68K_CR_TC: 21788b2fef6SLaurent Vivier env->mmu.tcr = val; 21888b2fef6SLaurent Vivier return; 219e55886c3SLaurent Vivier case M68K_CR_MMUSR: 220e55886c3SLaurent Vivier env->mmu.mmusr = val; 221e55886c3SLaurent Vivier return; 22288b2fef6SLaurent Vivier case M68K_CR_SRP: 22388b2fef6SLaurent Vivier env->mmu.srp = val; 22488b2fef6SLaurent Vivier return; 22588b2fef6SLaurent Vivier case M68K_CR_URP: 22688b2fef6SLaurent Vivier env->mmu.urp = val; 22788b2fef6SLaurent Vivier return; 2286e22b28eSLaurent Vivier case M68K_CR_USP: 2296e22b28eSLaurent Vivier env->sp[M68K_USP] = val; 2306e22b28eSLaurent Vivier return; 2316e22b28eSLaurent Vivier case M68K_CR_MSP: 2326e22b28eSLaurent Vivier env->sp[M68K_SSP] = val; 2336e22b28eSLaurent Vivier return; 2346e22b28eSLaurent Vivier case M68K_CR_ISP: 2356e22b28eSLaurent Vivier env->sp[M68K_ISP] = val; 2366e22b28eSLaurent Vivier return; 237c05c73b0SLaurent Vivier /* MC68040/MC68LC040 */ 238c05c73b0SLaurent Vivier case M68K_CR_ITT0: 239c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR0] = val; 240c05c73b0SLaurent Vivier return; 241c05c73b0SLaurent Vivier case M68K_CR_ITT1: 242c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR1] = val; 243c05c73b0SLaurent Vivier return; 244c05c73b0SLaurent Vivier case M68K_CR_DTT0: 245c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR0] = val; 246c05c73b0SLaurent Vivier return; 247c05c73b0SLaurent Vivier case M68K_CR_DTT1: 248c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR1] = val; 249c05c73b0SLaurent Vivier return; 2506e22b28eSLaurent Vivier } 251a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", 2520633879fSpbrook reg, val); 2530633879fSpbrook } 2546e22b28eSLaurent Vivier 2556e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) 2566e22b28eSLaurent Vivier { 2576e22b28eSLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 2586e22b28eSLaurent Vivier 2596e22b28eSLaurent Vivier switch (reg) { 2606e22b28eSLaurent Vivier /* MC680[1234]0 */ 2615fa9f1f2SLaurent Vivier case M68K_CR_SFC: 2625fa9f1f2SLaurent Vivier return env->sfc; 2635fa9f1f2SLaurent Vivier case M68K_CR_DFC: 2645fa9f1f2SLaurent Vivier return env->dfc; 2656e22b28eSLaurent Vivier case M68K_CR_VBR: 2666e22b28eSLaurent Vivier return env->vbr; 2676e22b28eSLaurent Vivier /* MC680[234]0 */ 2686e22b28eSLaurent Vivier case M68K_CR_CACR: 2696e22b28eSLaurent Vivier return env->cacr; 2706e22b28eSLaurent Vivier /* MC680[34]0 */ 27188b2fef6SLaurent Vivier case M68K_CR_TC: 27288b2fef6SLaurent Vivier return env->mmu.tcr; 273e55886c3SLaurent Vivier case M68K_CR_MMUSR: 274e55886c3SLaurent Vivier return env->mmu.mmusr; 27588b2fef6SLaurent Vivier case M68K_CR_SRP: 27688b2fef6SLaurent Vivier return env->mmu.srp; 2776e22b28eSLaurent Vivier case M68K_CR_USP: 2786e22b28eSLaurent Vivier return env->sp[M68K_USP]; 2796e22b28eSLaurent Vivier case M68K_CR_MSP: 2806e22b28eSLaurent Vivier return env->sp[M68K_SSP]; 2816e22b28eSLaurent Vivier case M68K_CR_ISP: 2826e22b28eSLaurent Vivier return env->sp[M68K_ISP]; 28388b2fef6SLaurent Vivier /* MC68040/MC68LC040 */ 28488b2fef6SLaurent Vivier case M68K_CR_URP: 28588b2fef6SLaurent Vivier return env->mmu.urp; 286c05c73b0SLaurent Vivier case M68K_CR_ITT0: 287c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_ITTR0]; 288c05c73b0SLaurent Vivier case M68K_CR_ITT1: 289c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_ITTR1]; 290c05c73b0SLaurent Vivier case M68K_CR_DTT0: 291c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_DTTR0]; 292c05c73b0SLaurent Vivier case M68K_CR_DTT1: 293c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_DTTR1]; 2946e22b28eSLaurent Vivier } 2956e22b28eSLaurent Vivier cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n", 2966e22b28eSLaurent Vivier reg); 2970633879fSpbrook } 2980633879fSpbrook 299e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) 300acf930aaSpbrook { 301acf930aaSpbrook uint32_t acc; 302acf930aaSpbrook int8_t exthigh; 303acf930aaSpbrook uint8_t extlow; 304acf930aaSpbrook uint64_t regval; 305acf930aaSpbrook int i; 306acf930aaSpbrook if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { 307acf930aaSpbrook for (i = 0; i < 4; i++) { 308acf930aaSpbrook regval = env->macc[i]; 309acf930aaSpbrook exthigh = regval >> 40; 310acf930aaSpbrook if (env->macsr & MACSR_FI) { 311acf930aaSpbrook acc = regval >> 8; 312acf930aaSpbrook extlow = regval; 313acf930aaSpbrook } else { 314acf930aaSpbrook acc = regval; 315acf930aaSpbrook extlow = regval >> 32; 316acf930aaSpbrook } 317acf930aaSpbrook if (env->macsr & MACSR_FI) { 318acf930aaSpbrook regval = (((uint64_t)acc) << 8) | extlow; 319acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 320acf930aaSpbrook } else if (env->macsr & MACSR_SU) { 321acf930aaSpbrook regval = acc | (((int64_t)extlow) << 32); 322acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 323acf930aaSpbrook } else { 324acf930aaSpbrook regval = acc | (((uint64_t)extlow) << 32); 325acf930aaSpbrook regval |= ((uint64_t)(uint8_t)exthigh) << 40; 326acf930aaSpbrook } 327acf930aaSpbrook env->macc[i] = regval; 328acf930aaSpbrook } 329acf930aaSpbrook } 330acf930aaSpbrook env->macsr = val; 331acf930aaSpbrook } 332acf930aaSpbrook 33320dcee94Spbrook void m68k_switch_sp(CPUM68KState *env) 33420dcee94Spbrook { 33520dcee94Spbrook int new_sp; 33620dcee94Spbrook 33720dcee94Spbrook env->sp[env->current_sp] = env->aregs[7]; 3386e22b28eSLaurent Vivier if (m68k_feature(env, M68K_FEATURE_M68000)) { 3396e22b28eSLaurent Vivier if (env->sr & SR_S) { 3406e22b28eSLaurent Vivier if (env->sr & SR_M) { 3416e22b28eSLaurent Vivier new_sp = M68K_SSP; 3426e22b28eSLaurent Vivier } else { 3436e22b28eSLaurent Vivier new_sp = M68K_ISP; 3446e22b28eSLaurent Vivier } 3456e22b28eSLaurent Vivier } else { 3466e22b28eSLaurent Vivier new_sp = M68K_USP; 3476e22b28eSLaurent Vivier } 3486e22b28eSLaurent Vivier } else { 34920dcee94Spbrook new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) 35020dcee94Spbrook ? M68K_SSP : M68K_USP; 3516e22b28eSLaurent Vivier } 35220dcee94Spbrook env->aregs[7] = env->sp[new_sp]; 35320dcee94Spbrook env->current_sp = new_sp; 35420dcee94Spbrook } 35520dcee94Spbrook 3560633879fSpbrook #if defined(CONFIG_USER_ONLY) 3570633879fSpbrook 35898670d47SLaurent Vivier int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, 35997b348e7SBlue Swirl int mmu_idx) 3600633879fSpbrook { 3617510454eSAndreas Färber M68kCPU *cpu = M68K_CPU(cs); 3627510454eSAndreas Färber 36327103424SAndreas Färber cs->exception_index = EXCP_ACCESS; 3647510454eSAndreas Färber cpu->env.mmu.ar = address; 3650633879fSpbrook return 1; 3660633879fSpbrook } 3670633879fSpbrook 3680633879fSpbrook #else 3690633879fSpbrook 37088b2fef6SLaurent Vivier /* MMU: 68040 only */ 3714fcc562bSPaul Brook 3722097dca6SLaurent Vivier static void print_address_zone(FILE *f, fprintf_function cpu_fprintf, 3732097dca6SLaurent Vivier uint32_t logical, uint32_t physical, 3742097dca6SLaurent Vivier uint32_t size, int attr) 3752097dca6SLaurent Vivier { 3762097dca6SLaurent Vivier cpu_fprintf(f, "%08x - %08x -> %08x - %08x %c ", 3772097dca6SLaurent Vivier logical, logical + size - 1, 3782097dca6SLaurent Vivier physical, physical + size - 1, 3792097dca6SLaurent Vivier attr & 4 ? 'W' : '-'); 3802097dca6SLaurent Vivier size >>= 10; 3812097dca6SLaurent Vivier if (size < 1024) { 3822097dca6SLaurent Vivier cpu_fprintf(f, "(%d KiB)\n", size); 3832097dca6SLaurent Vivier } else { 3842097dca6SLaurent Vivier size >>= 10; 3852097dca6SLaurent Vivier if (size < 1024) { 3862097dca6SLaurent Vivier cpu_fprintf(f, "(%d MiB)\n", size); 3872097dca6SLaurent Vivier } else { 3882097dca6SLaurent Vivier size >>= 10; 3892097dca6SLaurent Vivier cpu_fprintf(f, "(%d GiB)\n", size); 3902097dca6SLaurent Vivier } 3912097dca6SLaurent Vivier } 3922097dca6SLaurent Vivier } 3932097dca6SLaurent Vivier 3942097dca6SLaurent Vivier static void dump_address_map(FILE *f, fprintf_function cpu_fprintf, 3952097dca6SLaurent Vivier CPUM68KState *env, uint32_t root_pointer) 3962097dca6SLaurent Vivier { 3972097dca6SLaurent Vivier int i, j, k; 3982097dca6SLaurent Vivier int tic_size, tic_shift; 3992097dca6SLaurent Vivier uint32_t tib_mask; 4002097dca6SLaurent Vivier uint32_t tia, tib, tic; 4012097dca6SLaurent Vivier uint32_t logical = 0xffffffff, physical = 0xffffffff; 4022097dca6SLaurent Vivier uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff; 4032097dca6SLaurent Vivier uint32_t last_logical, last_physical; 4042097dca6SLaurent Vivier int32_t size; 4052097dca6SLaurent Vivier int last_attr = -1, attr = -1; 4062097dca6SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 4072097dca6SLaurent Vivier CPUState *cs = CPU(cpu); 4082097dca6SLaurent Vivier 4092097dca6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 4102097dca6SLaurent Vivier /* 8k page */ 4112097dca6SLaurent Vivier tic_size = 32; 4122097dca6SLaurent Vivier tic_shift = 13; 4132097dca6SLaurent Vivier tib_mask = M68K_8K_PAGE_MASK; 4142097dca6SLaurent Vivier } else { 4152097dca6SLaurent Vivier /* 4k page */ 4162097dca6SLaurent Vivier tic_size = 64; 4172097dca6SLaurent Vivier tic_shift = 12; 4182097dca6SLaurent Vivier tib_mask = M68K_4K_PAGE_MASK; 4192097dca6SLaurent Vivier } 4202097dca6SLaurent Vivier for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) { 4212097dca6SLaurent Vivier tia = ldl_phys(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4); 4222097dca6SLaurent Vivier if (!M68K_UDT_VALID(tia)) { 4232097dca6SLaurent Vivier continue; 4242097dca6SLaurent Vivier } 4252097dca6SLaurent Vivier for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) { 4262097dca6SLaurent Vivier tib = ldl_phys(cs->as, M68K_POINTER_BASE(tia) + j * 4); 4272097dca6SLaurent Vivier if (!M68K_UDT_VALID(tib)) { 4282097dca6SLaurent Vivier continue; 4292097dca6SLaurent Vivier } 4302097dca6SLaurent Vivier for (k = 0; k < tic_size; k++) { 4312097dca6SLaurent Vivier tic = ldl_phys(cs->as, (tib & tib_mask) + k * 4); 4322097dca6SLaurent Vivier if (!M68K_PDT_VALID(tic)) { 4332097dca6SLaurent Vivier continue; 4342097dca6SLaurent Vivier } 4352097dca6SLaurent Vivier if (M68K_PDT_INDIRECT(tic)) { 4362097dca6SLaurent Vivier tic = ldl_phys(cs->as, M68K_INDIRECT_POINTER(tic)); 4372097dca6SLaurent Vivier } 4382097dca6SLaurent Vivier 4392097dca6SLaurent Vivier last_logical = logical; 4402097dca6SLaurent Vivier logical = (i << M68K_TTS_ROOT_SHIFT) | 4412097dca6SLaurent Vivier (j << M68K_TTS_POINTER_SHIFT) | 4422097dca6SLaurent Vivier (k << tic_shift); 4432097dca6SLaurent Vivier 4442097dca6SLaurent Vivier last_physical = physical; 4452097dca6SLaurent Vivier physical = tic & ~((1 << tic_shift) - 1); 4462097dca6SLaurent Vivier 4472097dca6SLaurent Vivier last_attr = attr; 4482097dca6SLaurent Vivier attr = tic & ((1 << tic_shift) - 1); 4492097dca6SLaurent Vivier 4502097dca6SLaurent Vivier if ((logical != (last_logical + (1 << tic_shift))) || 4512097dca6SLaurent Vivier (physical != (last_physical + (1 << tic_shift))) || 4522097dca6SLaurent Vivier (attr & 4) != (last_attr & 4)) { 4532097dca6SLaurent Vivier 4542097dca6SLaurent Vivier if (first_logical != 0xffffffff) { 4552097dca6SLaurent Vivier size = last_logical + (1 << tic_shift) - 4562097dca6SLaurent Vivier first_logical; 4572097dca6SLaurent Vivier print_address_zone(f, cpu_fprintf, first_logical, 4582097dca6SLaurent Vivier first_physical, size, last_attr); 4592097dca6SLaurent Vivier } 4602097dca6SLaurent Vivier first_logical = logical; 4612097dca6SLaurent Vivier first_physical = physical; 4622097dca6SLaurent Vivier } 4632097dca6SLaurent Vivier } 4642097dca6SLaurent Vivier } 4652097dca6SLaurent Vivier } 4662097dca6SLaurent Vivier if (first_logical != logical || (attr & 4) != (last_attr & 4)) { 4672097dca6SLaurent Vivier size = logical + (1 << tic_shift) - first_logical; 4682097dca6SLaurent Vivier print_address_zone(f, cpu_fprintf, first_logical, first_physical, size, 4692097dca6SLaurent Vivier last_attr); 4702097dca6SLaurent Vivier } 4712097dca6SLaurent Vivier } 4722097dca6SLaurent Vivier 4732097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \ 4742097dca6SLaurent Vivier switch (a & M68K_DESC_CACHEMODE) { \ 4752097dca6SLaurent Vivier case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \ 4762097dca6SLaurent Vivier cpu_fprintf(f, "T"); \ 4772097dca6SLaurent Vivier break; \ 4782097dca6SLaurent Vivier case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \ 4792097dca6SLaurent Vivier cpu_fprintf(f, "C"); \ 4802097dca6SLaurent Vivier break; \ 4812097dca6SLaurent Vivier case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \ 4822097dca6SLaurent Vivier cpu_fprintf(f, "S"); \ 4832097dca6SLaurent Vivier break; \ 4842097dca6SLaurent Vivier case M68K_DESC_CM_NCACHE: /* noncachable */ \ 4852097dca6SLaurent Vivier cpu_fprintf(f, "N"); \ 4862097dca6SLaurent Vivier break; \ 4872097dca6SLaurent Vivier } 4882097dca6SLaurent Vivier 4892097dca6SLaurent Vivier static void dump_ttr(FILE *f, fprintf_function cpu_fprintf, uint32_t ttr) 4902097dca6SLaurent Vivier { 4912097dca6SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 4922097dca6SLaurent Vivier cpu_fprintf(f, "disabled\n"); 4932097dca6SLaurent Vivier return; 4942097dca6SLaurent Vivier } 4952097dca6SLaurent Vivier cpu_fprintf(f, "Base: 0x%08x Mask: 0x%08x Control: ", 4962097dca6SLaurent Vivier ttr & M68K_TTR_ADDR_BASE, 4972097dca6SLaurent Vivier (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT); 4982097dca6SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 4992097dca6SLaurent Vivier case M68K_TTR_SFIELD_USER: 5002097dca6SLaurent Vivier cpu_fprintf(f, "U"); 5012097dca6SLaurent Vivier break; 5022097dca6SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 5032097dca6SLaurent Vivier cpu_fprintf(f, "S"); 5042097dca6SLaurent Vivier break; 5052097dca6SLaurent Vivier default: 5062097dca6SLaurent Vivier cpu_fprintf(f, "*"); 5072097dca6SLaurent Vivier break; 5082097dca6SLaurent Vivier } 5092097dca6SLaurent Vivier DUMP_CACHEFLAGS(ttr); 5102097dca6SLaurent Vivier if (ttr & M68K_DESC_WRITEPROT) { 5112097dca6SLaurent Vivier cpu_fprintf(f, "R"); 5122097dca6SLaurent Vivier } else { 5132097dca6SLaurent Vivier cpu_fprintf(f, "W"); 5142097dca6SLaurent Vivier } 5152097dca6SLaurent Vivier cpu_fprintf(f, " U: %d\n", (ttr & M68K_DESC_USERATTR) >> 5162097dca6SLaurent Vivier M68K_DESC_USERATTR_SHIFT); 5172097dca6SLaurent Vivier } 5182097dca6SLaurent Vivier 5192097dca6SLaurent Vivier void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env) 5202097dca6SLaurent Vivier { 5212097dca6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 5222097dca6SLaurent Vivier cpu_fprintf(f, "Translation disabled\n"); 5232097dca6SLaurent Vivier return; 5242097dca6SLaurent Vivier } 5252097dca6SLaurent Vivier cpu_fprintf(f, "Page Size: "); 5262097dca6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 5272097dca6SLaurent Vivier cpu_fprintf(f, "8kB\n"); 5282097dca6SLaurent Vivier } else { 5292097dca6SLaurent Vivier cpu_fprintf(f, "4kB\n"); 5302097dca6SLaurent Vivier } 5312097dca6SLaurent Vivier 5322097dca6SLaurent Vivier cpu_fprintf(f, "MMUSR: "); 5332097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_B_040) { 5342097dca6SLaurent Vivier cpu_fprintf(f, "BUS ERROR\n"); 5352097dca6SLaurent Vivier } else { 5362097dca6SLaurent Vivier cpu_fprintf(f, "Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000); 5372097dca6SLaurent Vivier /* flags found on the page descriptor */ 5382097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_G_040) { 5392097dca6SLaurent Vivier cpu_fprintf(f, "G"); /* Global */ 5402097dca6SLaurent Vivier } else { 5412097dca6SLaurent Vivier cpu_fprintf(f, "."); 5422097dca6SLaurent Vivier } 5432097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_S_040) { 5442097dca6SLaurent Vivier cpu_fprintf(f, "S"); /* Supervisor */ 5452097dca6SLaurent Vivier } else { 5462097dca6SLaurent Vivier cpu_fprintf(f, "."); 5472097dca6SLaurent Vivier } 5482097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_M_040) { 5492097dca6SLaurent Vivier cpu_fprintf(f, "M"); /* Modified */ 5502097dca6SLaurent Vivier } else { 5512097dca6SLaurent Vivier cpu_fprintf(f, "."); 5522097dca6SLaurent Vivier } 5532097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_WP_040) { 5542097dca6SLaurent Vivier cpu_fprintf(f, "W"); /* Write protect */ 5552097dca6SLaurent Vivier } else { 5562097dca6SLaurent Vivier cpu_fprintf(f, "."); 5572097dca6SLaurent Vivier } 5582097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_T_040) { 5592097dca6SLaurent Vivier cpu_fprintf(f, "T"); /* Transparent */ 5602097dca6SLaurent Vivier } else { 5612097dca6SLaurent Vivier cpu_fprintf(f, "."); 5622097dca6SLaurent Vivier } 5632097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_R_040) { 5642097dca6SLaurent Vivier cpu_fprintf(f, "R"); /* Resident */ 5652097dca6SLaurent Vivier } else { 5662097dca6SLaurent Vivier cpu_fprintf(f, "."); 5672097dca6SLaurent Vivier } 5682097dca6SLaurent Vivier cpu_fprintf(f, " Cache: "); 5692097dca6SLaurent Vivier DUMP_CACHEFLAGS(env->mmu.mmusr); 5702097dca6SLaurent Vivier cpu_fprintf(f, " U: %d\n", (env->mmu.mmusr >> 8) & 3); 5712097dca6SLaurent Vivier cpu_fprintf(f, "\n"); 5722097dca6SLaurent Vivier } 5732097dca6SLaurent Vivier 5742097dca6SLaurent Vivier cpu_fprintf(f, "ITTR0: "); 5752097dca6SLaurent Vivier dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR0]); 5762097dca6SLaurent Vivier cpu_fprintf(f, "ITTR1: "); 5772097dca6SLaurent Vivier dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR1]); 5782097dca6SLaurent Vivier cpu_fprintf(f, "DTTR0: "); 5792097dca6SLaurent Vivier dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR0]); 5802097dca6SLaurent Vivier cpu_fprintf(f, "DTTR1: "); 5812097dca6SLaurent Vivier dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR1]); 5822097dca6SLaurent Vivier 5832097dca6SLaurent Vivier cpu_fprintf(f, "SRP: 0x%08x\n", env->mmu.srp); 5842097dca6SLaurent Vivier dump_address_map(f, cpu_fprintf, env, env->mmu.srp); 5852097dca6SLaurent Vivier 5862097dca6SLaurent Vivier cpu_fprintf(f, "URP: 0x%08x\n", env->mmu.urp); 5872097dca6SLaurent Vivier dump_address_map(f, cpu_fprintf, env, env->mmu.urp); 5882097dca6SLaurent Vivier } 5892097dca6SLaurent Vivier 590c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr, 591c05c73b0SLaurent Vivier int access_type) 592c05c73b0SLaurent Vivier { 593c05c73b0SLaurent Vivier uint32_t base, mask; 594c05c73b0SLaurent Vivier 595c05c73b0SLaurent Vivier /* check if transparent translation is enabled */ 596c05c73b0SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 597c05c73b0SLaurent Vivier return 0; 598c05c73b0SLaurent Vivier } 599c05c73b0SLaurent Vivier 600c05c73b0SLaurent Vivier /* check mode access */ 601c05c73b0SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 602c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_USER: 603c05c73b0SLaurent Vivier /* match only if user */ 604c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) != 0) { 605c05c73b0SLaurent Vivier return 0; 606c05c73b0SLaurent Vivier } 607c05c73b0SLaurent Vivier break; 608c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 609c05c73b0SLaurent Vivier /* match only if supervisor */ 610c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 611c05c73b0SLaurent Vivier return 0; 612c05c73b0SLaurent Vivier } 613c05c73b0SLaurent Vivier break; 614c05c73b0SLaurent Vivier default: 615c05c73b0SLaurent Vivier /* all other values disable mode matching (FC2) */ 616c05c73b0SLaurent Vivier break; 617c05c73b0SLaurent Vivier } 618c05c73b0SLaurent Vivier 619c05c73b0SLaurent Vivier /* check address matching */ 620c05c73b0SLaurent Vivier 621c05c73b0SLaurent Vivier base = ttr & M68K_TTR_ADDR_BASE; 622c05c73b0SLaurent Vivier mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK; 623c05c73b0SLaurent Vivier mask <<= M68K_TTR_ADDR_MASK_SHIFT; 624c05c73b0SLaurent Vivier 625c05c73b0SLaurent Vivier if ((addr & mask) != (base & mask)) { 626c05c73b0SLaurent Vivier return 0; 627c05c73b0SLaurent Vivier } 628c05c73b0SLaurent Vivier 629c05c73b0SLaurent Vivier *prot = PAGE_READ | PAGE_EXEC; 630c05c73b0SLaurent Vivier if ((ttr & M68K_DESC_WRITEPROT) == 0) { 631c05c73b0SLaurent Vivier *prot |= PAGE_WRITE; 632c05c73b0SLaurent Vivier } 633c05c73b0SLaurent Vivier 634c05c73b0SLaurent Vivier return 1; 635c05c73b0SLaurent Vivier } 636c05c73b0SLaurent Vivier 63788b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical, 63888b2fef6SLaurent Vivier int *prot, target_ulong address, 63988b2fef6SLaurent Vivier int access_type, target_ulong *page_size) 64088b2fef6SLaurent Vivier { 64188b2fef6SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 64288b2fef6SLaurent Vivier CPUState *cs = CPU(cpu); 64388b2fef6SLaurent Vivier uint32_t entry; 64488b2fef6SLaurent Vivier uint32_t next; 64588b2fef6SLaurent Vivier target_ulong page_mask; 64688b2fef6SLaurent Vivier bool debug = access_type & ACCESS_DEBUG; 64788b2fef6SLaurent Vivier int page_bits; 648c05c73b0SLaurent Vivier int i; 649c05c73b0SLaurent Vivier 650c05c73b0SLaurent Vivier /* Transparent Translation (physical = logical) */ 651c05c73b0SLaurent Vivier for (i = 0; i < M68K_MAX_TTR; i++) { 652c05c73b0SLaurent Vivier if (check_TTR(env->mmu.TTR(access_type, i), 653c05c73b0SLaurent Vivier prot, address, access_type)) { 654e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 655e55886c3SLaurent Vivier /* Transparent Translation Register bit */ 656e55886c3SLaurent Vivier env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040; 657e55886c3SLaurent Vivier } 658c05c73b0SLaurent Vivier *physical = address & TARGET_PAGE_MASK; 659c05c73b0SLaurent Vivier *page_size = TARGET_PAGE_SIZE; 660c05c73b0SLaurent Vivier return 0; 661c05c73b0SLaurent Vivier } 662c05c73b0SLaurent Vivier } 66388b2fef6SLaurent Vivier 66488b2fef6SLaurent Vivier /* Page Table Root Pointer */ 66588b2fef6SLaurent Vivier *prot = PAGE_READ | PAGE_WRITE; 66688b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 66788b2fef6SLaurent Vivier *prot |= PAGE_EXEC; 66888b2fef6SLaurent Vivier } 66988b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 67088b2fef6SLaurent Vivier next = env->mmu.srp; 67188b2fef6SLaurent Vivier } else { 67288b2fef6SLaurent Vivier next = env->mmu.urp; 67388b2fef6SLaurent Vivier } 67488b2fef6SLaurent Vivier 67588b2fef6SLaurent Vivier /* Root Index */ 67688b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address); 67788b2fef6SLaurent Vivier 67888b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 67988b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 68088b2fef6SLaurent Vivier return -1; 68188b2fef6SLaurent Vivier } 68288b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 68388b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 68488b2fef6SLaurent Vivier } 68588b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 686e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 687e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_WP_040; 688e55886c3SLaurent Vivier } 68988b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 69088b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 69188b2fef6SLaurent Vivier return -1; 69288b2fef6SLaurent Vivier } 69388b2fef6SLaurent Vivier } 69488b2fef6SLaurent Vivier 69588b2fef6SLaurent Vivier /* Pointer Index */ 69688b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address); 69788b2fef6SLaurent Vivier 69888b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 69988b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 70088b2fef6SLaurent Vivier return -1; 70188b2fef6SLaurent Vivier } 70288b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 70388b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 70488b2fef6SLaurent Vivier } 70588b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 706e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 707e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_WP_040; 708e55886c3SLaurent Vivier } 70988b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 71088b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 71188b2fef6SLaurent Vivier return -1; 71288b2fef6SLaurent Vivier } 71388b2fef6SLaurent Vivier } 71488b2fef6SLaurent Vivier 71588b2fef6SLaurent Vivier /* Page Index */ 71688b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 71788b2fef6SLaurent Vivier entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address); 71888b2fef6SLaurent Vivier } else { 71988b2fef6SLaurent Vivier entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address); 72088b2fef6SLaurent Vivier } 72188b2fef6SLaurent Vivier 72288b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 72388b2fef6SLaurent Vivier 72488b2fef6SLaurent Vivier if (!M68K_PDT_VALID(next)) { 72588b2fef6SLaurent Vivier return -1; 72688b2fef6SLaurent Vivier } 72788b2fef6SLaurent Vivier if (M68K_PDT_INDIRECT(next)) { 72888b2fef6SLaurent Vivier next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next)); 72988b2fef6SLaurent Vivier } 73088b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 73188b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 73288b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 73388b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 73488b2fef6SLaurent Vivier } 73588b2fef6SLaurent Vivier } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) != 73688b2fef6SLaurent Vivier (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) { 73788b2fef6SLaurent Vivier stl_phys(cs->as, entry, 73888b2fef6SLaurent Vivier next | (M68K_DESC_MODIFIED | M68K_DESC_USED)); 73988b2fef6SLaurent Vivier } 74088b2fef6SLaurent Vivier } else { 74188b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 74288b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 74388b2fef6SLaurent Vivier } 74488b2fef6SLaurent Vivier } 74588b2fef6SLaurent Vivier 74688b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 74788b2fef6SLaurent Vivier page_bits = 13; 74888b2fef6SLaurent Vivier } else { 74988b2fef6SLaurent Vivier page_bits = 12; 75088b2fef6SLaurent Vivier } 75188b2fef6SLaurent Vivier *page_size = 1 << page_bits; 75288b2fef6SLaurent Vivier page_mask = ~(*page_size - 1); 75388b2fef6SLaurent Vivier *physical = next & page_mask; 75488b2fef6SLaurent Vivier 755e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 756e55886c3SLaurent Vivier env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040; 757e55886c3SLaurent Vivier env->mmu.mmusr |= *physical & 0xfffff000; 758e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_R_040; 759e55886c3SLaurent Vivier } 760e55886c3SLaurent Vivier 76188b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 76288b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 76388b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 76488b2fef6SLaurent Vivier return -1; 76588b2fef6SLaurent Vivier } 76688b2fef6SLaurent Vivier } 76788b2fef6SLaurent Vivier if (next & M68K_DESC_SUPERONLY) { 76888b2fef6SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 76988b2fef6SLaurent Vivier return -1; 77088b2fef6SLaurent Vivier } 77188b2fef6SLaurent Vivier } 77288b2fef6SLaurent Vivier 77388b2fef6SLaurent Vivier return 0; 77488b2fef6SLaurent Vivier } 77588b2fef6SLaurent Vivier 77600b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 7774fcc562bSPaul Brook { 77888b2fef6SLaurent Vivier M68kCPU *cpu = M68K_CPU(cs); 77988b2fef6SLaurent Vivier CPUM68KState *env = &cpu->env; 78088b2fef6SLaurent Vivier hwaddr phys_addr; 78188b2fef6SLaurent Vivier int prot; 78288b2fef6SLaurent Vivier int access_type; 78388b2fef6SLaurent Vivier target_ulong page_size; 78488b2fef6SLaurent Vivier 78588b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 78688b2fef6SLaurent Vivier /* MMU disabled */ 7874fcc562bSPaul Brook return addr; 7884fcc562bSPaul Brook } 7894fcc562bSPaul Brook 79088b2fef6SLaurent Vivier access_type = ACCESS_DATA | ACCESS_DEBUG; 79188b2fef6SLaurent Vivier if (env->sr & SR_S) { 79288b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 79388b2fef6SLaurent Vivier } 79488b2fef6SLaurent Vivier if (get_physical_address(env, &phys_addr, &prot, 79588b2fef6SLaurent Vivier addr, access_type, &page_size) != 0) { 79688b2fef6SLaurent Vivier return -1; 79788b2fef6SLaurent Vivier } 79888b2fef6SLaurent Vivier return phys_addr; 79988b2fef6SLaurent Vivier } 80088b2fef6SLaurent Vivier 80198670d47SLaurent Vivier int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, 80297b348e7SBlue Swirl int mmu_idx) 8030633879fSpbrook { 80488b2fef6SLaurent Vivier M68kCPU *cpu = M68K_CPU(cs); 80588b2fef6SLaurent Vivier CPUM68KState *env = &cpu->env; 80688b2fef6SLaurent Vivier hwaddr physical; 8070633879fSpbrook int prot; 80888b2fef6SLaurent Vivier int access_type; 80988b2fef6SLaurent Vivier int ret; 81088b2fef6SLaurent Vivier target_ulong page_size; 8110633879fSpbrook 81288b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 81388b2fef6SLaurent Vivier /* MMU disabled */ 81488b2fef6SLaurent Vivier tlb_set_page(cs, address & TARGET_PAGE_MASK, 81588b2fef6SLaurent Vivier address & TARGET_PAGE_MASK, 81688b2fef6SLaurent Vivier PAGE_READ | PAGE_WRITE | PAGE_EXEC, 81788b2fef6SLaurent Vivier mmu_idx, TARGET_PAGE_SIZE); 818d4c430a8SPaul Brook return 0; 8190633879fSpbrook } 8200633879fSpbrook 82188b2fef6SLaurent Vivier if (rw == 2) { 82288b2fef6SLaurent Vivier access_type = ACCESS_CODE; 82388b2fef6SLaurent Vivier rw = 0; 82488b2fef6SLaurent Vivier } else { 82588b2fef6SLaurent Vivier access_type = ACCESS_DATA; 82688b2fef6SLaurent Vivier if (rw) { 82788b2fef6SLaurent Vivier access_type |= ACCESS_STORE; 82888b2fef6SLaurent Vivier } 82988b2fef6SLaurent Vivier } 83088b2fef6SLaurent Vivier 83188b2fef6SLaurent Vivier if (mmu_idx != MMU_USER_IDX) { 83288b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 83388b2fef6SLaurent Vivier } 83488b2fef6SLaurent Vivier 83588b2fef6SLaurent Vivier ret = get_physical_address(&cpu->env, &physical, &prot, 83688b2fef6SLaurent Vivier address, access_type, &page_size); 83788b2fef6SLaurent Vivier if (ret == 0) { 83888b2fef6SLaurent Vivier address &= TARGET_PAGE_MASK; 83988b2fef6SLaurent Vivier physical += address & (page_size - 1); 84088b2fef6SLaurent Vivier tlb_set_page(cs, address, physical, 84188b2fef6SLaurent Vivier prot, mmu_idx, TARGET_PAGE_SIZE); 84288b2fef6SLaurent Vivier return 0; 84388b2fef6SLaurent Vivier } 84488b2fef6SLaurent Vivier /* page fault */ 84588b2fef6SLaurent Vivier env->mmu.ssw = M68K_ATC_040; 84688b2fef6SLaurent Vivier switch (size) { 84788b2fef6SLaurent Vivier case 1: 84888b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_BYTE; 84988b2fef6SLaurent Vivier break; 85088b2fef6SLaurent Vivier case 2: 85188b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_WORD; 85288b2fef6SLaurent Vivier break; 85388b2fef6SLaurent Vivier case 4: 85488b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_LONG; 85588b2fef6SLaurent Vivier break; 85688b2fef6SLaurent Vivier } 85788b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 85888b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_SUPER; 85988b2fef6SLaurent Vivier } 86088b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 86188b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_CODE; 86288b2fef6SLaurent Vivier } else { 86388b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_DATA; 86488b2fef6SLaurent Vivier } 86588b2fef6SLaurent Vivier if (!(access_type & ACCESS_STORE)) { 86688b2fef6SLaurent Vivier env->mmu.ssw |= M68K_RW_040; 86788b2fef6SLaurent Vivier } 86888b2fef6SLaurent Vivier env->mmu.ar = address; 86988b2fef6SLaurent Vivier cs->exception_index = EXCP_ACCESS; 87088b2fef6SLaurent Vivier return 1; 87188b2fef6SLaurent Vivier } 87288b2fef6SLaurent Vivier 8730633879fSpbrook /* Notify CPU of a pending interrupt. Prioritization and vectoring should 8740633879fSpbrook be handled by the interrupt controller. Real hardware only requests 8750633879fSpbrook the vector when the interrupt is acknowledged by the CPU. For 8760633879fSpbrook simplicitly we calculate it when the interrupt is signalled. */ 877cb3fb38eSAndreas Färber void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) 8780633879fSpbrook { 879d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 880cb3fb38eSAndreas Färber CPUM68KState *env = &cpu->env; 881cb3fb38eSAndreas Färber 8820633879fSpbrook env->pending_level = level; 8830633879fSpbrook env->pending_vector = vector; 884d8ed887bSAndreas Färber if (level) { 885c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 886d8ed887bSAndreas Färber } else { 887d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 888d8ed887bSAndreas Färber } 8890633879fSpbrook } 8900633879fSpbrook 8910633879fSpbrook #endif 892e1f3808eSpbrook 893e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x) 894e1f3808eSpbrook { 895e1f3808eSpbrook x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); 896e1f3808eSpbrook x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); 897e1f3808eSpbrook x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); 898e1f3808eSpbrook return bswap32(x); 899e1f3808eSpbrook } 900e1f3808eSpbrook 901e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x) 902e1f3808eSpbrook { 903e1f3808eSpbrook int n; 904e1f3808eSpbrook for (n = 32; x; n--) 905e1f3808eSpbrook x >>= 1; 906e1f3808eSpbrook return n; 907e1f3808eSpbrook } 908e1f3808eSpbrook 909620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v) 910e1f3808eSpbrook { 911e1f3808eSpbrook /* The result has the opposite sign to the original value. */ 912620c6cf6SRichard Henderson if ((int32_t)v < 0) { 913e1f3808eSpbrook val = (((int32_t)val) >> 31) ^ SIGNBIT; 914620c6cf6SRichard Henderson } 915e1f3808eSpbrook return val; 916e1f3808eSpbrook } 917e1f3808eSpbrook 918d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) 919e1f3808eSpbrook { 920d2f8fb8eSLaurent Vivier env->sr = sr & 0xffe0; 921d2f8fb8eSLaurent Vivier cpu_m68k_set_ccr(env, sr); 922e1f3808eSpbrook m68k_switch_sp(env); 923e1f3808eSpbrook } 924e1f3808eSpbrook 925d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val) 926d2f8fb8eSLaurent Vivier { 927d2f8fb8eSLaurent Vivier cpu_m68k_set_sr(env, val); 928d2f8fb8eSLaurent Vivier } 929e1f3808eSpbrook 930e1f3808eSpbrook /* MAC unit. */ 931e1f3808eSpbrook /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers 932e1f3808eSpbrook take values, others take register numbers and manipulate the contents 933e1f3808eSpbrook in-place. */ 9342b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) 935e1f3808eSpbrook { 936e1f3808eSpbrook uint32_t mask; 937e1f3808eSpbrook env->macc[dest] = env->macc[src]; 938e1f3808eSpbrook mask = MACSR_PAV0 << dest; 939e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << src)) 940e1f3808eSpbrook env->macsr |= mask; 941e1f3808eSpbrook else 942e1f3808eSpbrook env->macsr &= ~mask; 943e1f3808eSpbrook } 944e1f3808eSpbrook 9452b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) 946e1f3808eSpbrook { 947e1f3808eSpbrook int64_t product; 948e1f3808eSpbrook int64_t res; 949e1f3808eSpbrook 950e1f3808eSpbrook product = (uint64_t)op1 * op2; 951e1f3808eSpbrook res = (product << 24) >> 24; 952e1f3808eSpbrook if (res != product) { 953e1f3808eSpbrook env->macsr |= MACSR_V; 954e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 955e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 956e1f3808eSpbrook if (product < 0) 957e1f3808eSpbrook res = ~(1ll << 50); 958e1f3808eSpbrook else 959e1f3808eSpbrook res = 1ll << 50; 960e1f3808eSpbrook } 961e1f3808eSpbrook } 962e1f3808eSpbrook return res; 963e1f3808eSpbrook } 964e1f3808eSpbrook 9652b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) 966e1f3808eSpbrook { 967e1f3808eSpbrook uint64_t product; 968e1f3808eSpbrook 969e1f3808eSpbrook product = (uint64_t)op1 * op2; 970e1f3808eSpbrook if (product & (0xffffffull << 40)) { 971e1f3808eSpbrook env->macsr |= MACSR_V; 972e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 973e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 974e1f3808eSpbrook product = 1ll << 50; 975e1f3808eSpbrook } else { 976e1f3808eSpbrook product &= ((1ull << 40) - 1); 977e1f3808eSpbrook } 978e1f3808eSpbrook } 979e1f3808eSpbrook return product; 980e1f3808eSpbrook } 981e1f3808eSpbrook 9822b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) 983e1f3808eSpbrook { 984e1f3808eSpbrook uint64_t product; 985e1f3808eSpbrook uint32_t remainder; 986e1f3808eSpbrook 987e1f3808eSpbrook product = (uint64_t)op1 * op2; 988e1f3808eSpbrook if (env->macsr & MACSR_RT) { 989e1f3808eSpbrook remainder = product & 0xffffff; 990e1f3808eSpbrook product >>= 24; 991e1f3808eSpbrook if (remainder > 0x800000) 992e1f3808eSpbrook product++; 993e1f3808eSpbrook else if (remainder == 0x800000) 994e1f3808eSpbrook product += (product & 1); 995e1f3808eSpbrook } else { 996e1f3808eSpbrook product >>= 24; 997e1f3808eSpbrook } 998e1f3808eSpbrook return product; 999e1f3808eSpbrook } 1000e1f3808eSpbrook 10012b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc) 1002e1f3808eSpbrook { 1003e1f3808eSpbrook int64_t tmp; 1004e1f3808eSpbrook int64_t result; 1005e1f3808eSpbrook tmp = env->macc[acc]; 1006e1f3808eSpbrook result = ((tmp << 16) >> 16); 1007e1f3808eSpbrook if (result != tmp) { 1008e1f3808eSpbrook env->macsr |= MACSR_V; 1009e1f3808eSpbrook } 1010e1f3808eSpbrook if (env->macsr & MACSR_V) { 1011e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1012e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1013a1c7273bSStefan Weil /* The result is saturated to 32 bits, despite overflow occurring 1014e1f3808eSpbrook at 48 bits. Seems weird, but that's what the hardware docs 1015e1f3808eSpbrook say. */ 1016e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffff; 1017e1f3808eSpbrook } 1018e1f3808eSpbrook } 1019e1f3808eSpbrook env->macc[acc] = result; 1020e1f3808eSpbrook } 1021e1f3808eSpbrook 10222b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) 1023e1f3808eSpbrook { 1024e1f3808eSpbrook uint64_t val; 1025e1f3808eSpbrook 1026e1f3808eSpbrook val = env->macc[acc]; 1027e1f3808eSpbrook if (val & (0xffffull << 48)) { 1028e1f3808eSpbrook env->macsr |= MACSR_V; 1029e1f3808eSpbrook } 1030e1f3808eSpbrook if (env->macsr & MACSR_V) { 1031e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1032e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1033e1f3808eSpbrook if (val > (1ull << 53)) 1034e1f3808eSpbrook val = 0; 1035e1f3808eSpbrook else 1036e1f3808eSpbrook val = (1ull << 48) - 1; 1037e1f3808eSpbrook } else { 1038e1f3808eSpbrook val &= ((1ull << 48) - 1); 1039e1f3808eSpbrook } 1040e1f3808eSpbrook } 1041e1f3808eSpbrook env->macc[acc] = val; 1042e1f3808eSpbrook } 1043e1f3808eSpbrook 10442b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) 1045e1f3808eSpbrook { 1046e1f3808eSpbrook int64_t sum; 1047e1f3808eSpbrook int64_t result; 1048e1f3808eSpbrook 1049e1f3808eSpbrook sum = env->macc[acc]; 1050e1f3808eSpbrook result = (sum << 16) >> 16; 1051e1f3808eSpbrook if (result != sum) { 1052e1f3808eSpbrook env->macsr |= MACSR_V; 1053e1f3808eSpbrook } 1054e1f3808eSpbrook if (env->macsr & MACSR_V) { 1055e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1056e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1057e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffffffffll; 1058e1f3808eSpbrook } 1059e1f3808eSpbrook } 1060e1f3808eSpbrook env->macc[acc] = result; 1061e1f3808eSpbrook } 1062e1f3808eSpbrook 10632b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) 1064e1f3808eSpbrook { 1065e1f3808eSpbrook uint64_t val; 1066e1f3808eSpbrook val = env->macc[acc]; 1067c4162574SBlue Swirl if (val == 0) { 1068e1f3808eSpbrook env->macsr |= MACSR_Z; 1069c4162574SBlue Swirl } else if (val & (1ull << 47)) { 1070e1f3808eSpbrook env->macsr |= MACSR_N; 1071c4162574SBlue Swirl } 1072e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << acc)) { 1073e1f3808eSpbrook env->macsr |= MACSR_V; 1074e1f3808eSpbrook } 1075e1f3808eSpbrook if (env->macsr & MACSR_FI) { 1076e1f3808eSpbrook val = ((int64_t)val) >> 40; 1077e1f3808eSpbrook if (val != 0 && val != -1) 1078e1f3808eSpbrook env->macsr |= MACSR_EV; 1079e1f3808eSpbrook } else if (env->macsr & MACSR_SU) { 1080e1f3808eSpbrook val = ((int64_t)val) >> 32; 1081e1f3808eSpbrook if (val != 0 && val != -1) 1082e1f3808eSpbrook env->macsr |= MACSR_EV; 1083e1f3808eSpbrook } else { 1084e1f3808eSpbrook if ((val >> 32) != 0) 1085e1f3808eSpbrook env->macsr |= MACSR_EV; 1086e1f3808eSpbrook } 1087e1f3808eSpbrook } 1088e1f3808eSpbrook 1089db3d7945SLaurent Vivier #define EXTSIGN(val, index) ( \ 1090db3d7945SLaurent Vivier (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ 1091db3d7945SLaurent Vivier ) 1092620c6cf6SRichard Henderson 1093620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) { \ 1094620c6cf6SRichard Henderson switch (op) { \ 1095620c6cf6SRichard Henderson case CC_OP_FLAGS: \ 1096620c6cf6SRichard Henderson /* Everything in place. */ \ 1097620c6cf6SRichard Henderson break; \ 1098db3d7945SLaurent Vivier case CC_OP_ADDB: \ 1099db3d7945SLaurent Vivier case CC_OP_ADDW: \ 1100db3d7945SLaurent Vivier case CC_OP_ADDL: \ 1101620c6cf6SRichard Henderson res = n; \ 1102620c6cf6SRichard Henderson src2 = v; \ 1103db3d7945SLaurent Vivier src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ 1104620c6cf6SRichard Henderson c = x; \ 1105620c6cf6SRichard Henderson z = n; \ 1106620c6cf6SRichard Henderson v = (res ^ src1) & ~(src1 ^ src2); \ 1107620c6cf6SRichard Henderson break; \ 1108db3d7945SLaurent Vivier case CC_OP_SUBB: \ 1109db3d7945SLaurent Vivier case CC_OP_SUBW: \ 1110db3d7945SLaurent Vivier case CC_OP_SUBL: \ 1111620c6cf6SRichard Henderson res = n; \ 1112620c6cf6SRichard Henderson src2 = v; \ 1113db3d7945SLaurent Vivier src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ 1114620c6cf6SRichard Henderson c = x; \ 1115620c6cf6SRichard Henderson z = n; \ 1116620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 1117620c6cf6SRichard Henderson break; \ 1118db3d7945SLaurent Vivier case CC_OP_CMPB: \ 1119db3d7945SLaurent Vivier case CC_OP_CMPW: \ 1120db3d7945SLaurent Vivier case CC_OP_CMPL: \ 1121620c6cf6SRichard Henderson src1 = n; \ 1122620c6cf6SRichard Henderson src2 = v; \ 1123db3d7945SLaurent Vivier res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ 1124620c6cf6SRichard Henderson n = res; \ 1125620c6cf6SRichard Henderson z = res; \ 1126620c6cf6SRichard Henderson c = src1 < src2; \ 1127620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 1128620c6cf6SRichard Henderson break; \ 1129620c6cf6SRichard Henderson case CC_OP_LOGIC: \ 1130620c6cf6SRichard Henderson c = v = 0; \ 1131620c6cf6SRichard Henderson z = n; \ 1132620c6cf6SRichard Henderson break; \ 1133620c6cf6SRichard Henderson default: \ 1134620c6cf6SRichard Henderson cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \ 1135620c6cf6SRichard Henderson } \ 1136620c6cf6SRichard Henderson } while (0) 1137620c6cf6SRichard Henderson 1138620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env) 1139e1f3808eSpbrook { 1140620c6cf6SRichard Henderson uint32_t x, c, n, z, v; 1141620c6cf6SRichard Henderson uint32_t res, src1, src2; 1142620c6cf6SRichard Henderson 1143620c6cf6SRichard Henderson x = env->cc_x; 1144620c6cf6SRichard Henderson n = env->cc_n; 1145620c6cf6SRichard Henderson z = env->cc_z; 1146620c6cf6SRichard Henderson v = env->cc_v; 1147db3d7945SLaurent Vivier c = env->cc_c; 1148620c6cf6SRichard Henderson 1149620c6cf6SRichard Henderson COMPUTE_CCR(env->cc_op, x, n, z, v, c); 1150620c6cf6SRichard Henderson 1151620c6cf6SRichard Henderson n = n >> 31; 1152620c6cf6SRichard Henderson z = (z == 0); 1153db3d7945SLaurent Vivier v = v >> 31; 1154620c6cf6SRichard Henderson 1155620c6cf6SRichard Henderson return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; 1156620c6cf6SRichard Henderson } 1157620c6cf6SRichard Henderson 1158620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env) 1159620c6cf6SRichard Henderson { 1160620c6cf6SRichard Henderson return cpu_m68k_get_ccr(env); 1161620c6cf6SRichard Henderson } 1162620c6cf6SRichard Henderson 1163620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) 1164620c6cf6SRichard Henderson { 1165620c6cf6SRichard Henderson env->cc_x = (ccr & CCF_X ? 1 : 0); 1166620c6cf6SRichard Henderson env->cc_n = (ccr & CCF_N ? -1 : 0); 1167620c6cf6SRichard Henderson env->cc_z = (ccr & CCF_Z ? 0 : 1); 1168620c6cf6SRichard Henderson env->cc_v = (ccr & CCF_V ? -1 : 0); 1169620c6cf6SRichard Henderson env->cc_c = (ccr & CCF_C ? 1 : 0); 1170620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 1171620c6cf6SRichard Henderson } 1172620c6cf6SRichard Henderson 1173620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) 1174620c6cf6SRichard Henderson { 1175620c6cf6SRichard Henderson cpu_m68k_set_ccr(env, ccr); 1176620c6cf6SRichard Henderson } 1177620c6cf6SRichard Henderson 1178620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) 1179620c6cf6SRichard Henderson { 1180620c6cf6SRichard Henderson uint32_t res, src1, src2; 1181620c6cf6SRichard Henderson 1182620c6cf6SRichard Henderson COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); 1183620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 1184e1f3808eSpbrook } 1185e1f3808eSpbrook 11862b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) 1187e1f3808eSpbrook { 1188e1f3808eSpbrook int rem; 1189e1f3808eSpbrook uint32_t result; 1190e1f3808eSpbrook 1191e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1192e1f3808eSpbrook /* 16-bit rounding. */ 1193e1f3808eSpbrook rem = val & 0xffffff; 1194e1f3808eSpbrook val = (val >> 24) & 0xffffu; 1195e1f3808eSpbrook if (rem > 0x800000) 1196e1f3808eSpbrook val++; 1197e1f3808eSpbrook else if (rem == 0x800000) 1198e1f3808eSpbrook val += (val & 1); 1199e1f3808eSpbrook } else if (env->macsr & MACSR_RT) { 1200e1f3808eSpbrook /* 32-bit rounding. */ 1201e1f3808eSpbrook rem = val & 0xff; 1202e1f3808eSpbrook val >>= 8; 1203e1f3808eSpbrook if (rem > 0x80) 1204e1f3808eSpbrook val++; 1205e1f3808eSpbrook else if (rem == 0x80) 1206e1f3808eSpbrook val += (val & 1); 1207e1f3808eSpbrook } else { 1208e1f3808eSpbrook /* No rounding. */ 1209e1f3808eSpbrook val >>= 8; 1210e1f3808eSpbrook } 1211e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1212e1f3808eSpbrook /* Saturate. */ 1213e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1214e1f3808eSpbrook if (val != (uint16_t) val) { 1215e1f3808eSpbrook result = ((val >> 63) ^ 0x7fff) & 0xffff; 1216e1f3808eSpbrook } else { 1217e1f3808eSpbrook result = val & 0xffff; 1218e1f3808eSpbrook } 1219e1f3808eSpbrook } else { 1220e1f3808eSpbrook if (val != (uint32_t)val) { 1221e1f3808eSpbrook result = ((uint32_t)(val >> 63) & 0x7fffffff); 1222e1f3808eSpbrook } else { 1223e1f3808eSpbrook result = (uint32_t)val; 1224e1f3808eSpbrook } 1225e1f3808eSpbrook } 1226e1f3808eSpbrook } else { 1227e1f3808eSpbrook /* No saturation. */ 1228e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1229e1f3808eSpbrook result = val & 0xffff; 1230e1f3808eSpbrook } else { 1231e1f3808eSpbrook result = (uint32_t)val; 1232e1f3808eSpbrook } 1233e1f3808eSpbrook } 1234e1f3808eSpbrook return result; 1235e1f3808eSpbrook } 1236e1f3808eSpbrook 1237e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val) 1238e1f3808eSpbrook { 1239e1f3808eSpbrook if (val == (int32_t)val) { 1240e1f3808eSpbrook return (int32_t)val; 1241e1f3808eSpbrook } else { 1242e1f3808eSpbrook return (val >> 61) ^ ~SIGNBIT; 1243e1f3808eSpbrook } 1244e1f3808eSpbrook } 1245e1f3808eSpbrook 1246e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val) 1247e1f3808eSpbrook { 1248e1f3808eSpbrook if ((val >> 32) == 0) { 1249e1f3808eSpbrook return (uint32_t)val; 1250e1f3808eSpbrook } else { 1251e1f3808eSpbrook return 0xffffffffu; 1252e1f3808eSpbrook } 1253e1f3808eSpbrook } 1254e1f3808eSpbrook 12552b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) 1256e1f3808eSpbrook { 1257e1f3808eSpbrook uint32_t val; 1258e1f3808eSpbrook val = env->macc[acc] & 0x00ff; 12595ce747cfSPaolo Bonzini val |= (env->macc[acc] >> 32) & 0xff00; 1260e1f3808eSpbrook val |= (env->macc[acc + 1] << 16) & 0x00ff0000; 1261e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xff000000; 1262e1f3808eSpbrook return val; 1263e1f3808eSpbrook } 1264e1f3808eSpbrook 12652b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) 1266e1f3808eSpbrook { 1267e1f3808eSpbrook uint32_t val; 1268e1f3808eSpbrook val = (env->macc[acc] >> 32) & 0xffff; 1269e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xffff0000; 1270e1f3808eSpbrook return val; 1271e1f3808eSpbrook } 1272e1f3808eSpbrook 12732b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) 1274e1f3808eSpbrook { 1275e1f3808eSpbrook int64_t res; 1276e1f3808eSpbrook int32_t tmp; 1277e1f3808eSpbrook res = env->macc[acc] & 0xffffffff00ull; 1278e1f3808eSpbrook tmp = (int16_t)(val & 0xff00); 1279e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1280e1f3808eSpbrook res |= val & 0xff; 1281e1f3808eSpbrook env->macc[acc] = res; 1282e1f3808eSpbrook res = env->macc[acc + 1] & 0xffffffff00ull; 1283e1f3808eSpbrook tmp = (val & 0xff000000); 1284e1f3808eSpbrook res |= ((int64_t)tmp) << 16; 1285e1f3808eSpbrook res |= (val >> 16) & 0xff; 1286e1f3808eSpbrook env->macc[acc + 1] = res; 1287e1f3808eSpbrook } 1288e1f3808eSpbrook 12892b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) 1290e1f3808eSpbrook { 1291e1f3808eSpbrook int64_t res; 1292e1f3808eSpbrook int32_t tmp; 1293e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1294e1f3808eSpbrook tmp = (int16_t)val; 1295e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1296e1f3808eSpbrook env->macc[acc] = res; 1297e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1298e1f3808eSpbrook tmp = val & 0xffff0000; 1299e1f3808eSpbrook res |= (int64_t)tmp << 16; 1300e1f3808eSpbrook env->macc[acc + 1] = res; 1301e1f3808eSpbrook } 1302e1f3808eSpbrook 13032b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) 1304e1f3808eSpbrook { 1305e1f3808eSpbrook uint64_t res; 1306e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1307e1f3808eSpbrook res |= ((uint64_t)(val & 0xffff)) << 32; 1308e1f3808eSpbrook env->macc[acc] = res; 1309e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1310e1f3808eSpbrook res |= (uint64_t)(val & 0xffff0000) << 16; 1311e1f3808eSpbrook env->macc[acc + 1] = res; 1312e1f3808eSpbrook } 13130bdb2b3bSLaurent Vivier 13140bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU) 1315e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read) 1316e55886c3SLaurent Vivier { 1317e55886c3SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 1318e55886c3SLaurent Vivier CPUState *cs = CPU(cpu); 1319e55886c3SLaurent Vivier hwaddr physical; 1320e55886c3SLaurent Vivier int access_type; 1321e55886c3SLaurent Vivier int prot; 1322e55886c3SLaurent Vivier int ret; 1323e55886c3SLaurent Vivier target_ulong page_size; 1324e55886c3SLaurent Vivier 1325e55886c3SLaurent Vivier access_type = ACCESS_PTEST; 1326e55886c3SLaurent Vivier if (env->dfc & 4) { 1327e55886c3SLaurent Vivier access_type |= ACCESS_SUPER; 1328e55886c3SLaurent Vivier } 1329e55886c3SLaurent Vivier if ((env->dfc & 3) == 2) { 1330e55886c3SLaurent Vivier access_type |= ACCESS_CODE; 1331e55886c3SLaurent Vivier } 1332e55886c3SLaurent Vivier if (!is_read) { 1333e55886c3SLaurent Vivier access_type |= ACCESS_STORE; 1334e55886c3SLaurent Vivier } 1335e55886c3SLaurent Vivier 1336e55886c3SLaurent Vivier env->mmu.mmusr = 0; 1337e55886c3SLaurent Vivier env->mmu.ssw = 0; 1338e55886c3SLaurent Vivier ret = get_physical_address(env, &physical, &prot, addr, 1339e55886c3SLaurent Vivier access_type, &page_size); 1340e55886c3SLaurent Vivier if (ret == 0) { 1341e55886c3SLaurent Vivier addr &= TARGET_PAGE_MASK; 1342e55886c3SLaurent Vivier physical += addr & (page_size - 1); 1343e55886c3SLaurent Vivier tlb_set_page(cs, addr, physical, 1344e55886c3SLaurent Vivier prot, access_type & ACCESS_SUPER ? 1345e55886c3SLaurent Vivier MMU_KERNEL_IDX : MMU_USER_IDX, page_size); 1346e55886c3SLaurent Vivier } 1347e55886c3SLaurent Vivier } 1348e55886c3SLaurent Vivier 1349e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode) 1350e55886c3SLaurent Vivier { 1351e55886c3SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 1352e55886c3SLaurent Vivier 1353e55886c3SLaurent Vivier switch (opmode) { 1354e55886c3SLaurent Vivier case 0: /* Flush page entry if not global */ 1355e55886c3SLaurent Vivier case 1: /* Flush page entry */ 1356e55886c3SLaurent Vivier tlb_flush_page(CPU(cpu), addr); 1357e55886c3SLaurent Vivier break; 1358e55886c3SLaurent Vivier case 2: /* Flush all except global entries */ 1359e55886c3SLaurent Vivier tlb_flush(CPU(cpu)); 1360e55886c3SLaurent Vivier break; 1361e55886c3SLaurent Vivier case 3: /* Flush all entries */ 1362e55886c3SLaurent Vivier tlb_flush(CPU(cpu)); 1363e55886c3SLaurent Vivier break; 1364e55886c3SLaurent Vivier } 1365e55886c3SLaurent Vivier } 1366e55886c3SLaurent Vivier 13670bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env) 13680bdb2b3bSLaurent Vivier { 13690bdb2b3bSLaurent Vivier /* FIXME: reset all except CPU */ 13700bdb2b3bSLaurent Vivier } 13710bdb2b3bSLaurent Vivier #endif 1372