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 10e6e5906bSpbrook * version 2 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 15e6e5906bSpbrook * 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" 25e6e5906bSpbrook 262ef6175aSRichard Henderson #include "exec/helper-proto.h" 27*24f91e81SAlex Bennée #include "fpu/softfloat.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; 5292a31361SAndreas Färber CPUListState *s = user_data; 537a9f812bSAndreas Färber const char *typename; 547a9f812bSAndreas Färber char *name; 5511150915SAndreas Färber 567a9f812bSAndreas Färber typename = object_class_get_name(c); 577a9f812bSAndreas Färber name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU)); 5811150915SAndreas Färber (*s->cpu_fprintf)(s->file, "%s\n", 597a9f812bSAndreas Färber name); 607a9f812bSAndreas Färber g_free(name); 6111150915SAndreas Färber } 620402f767Spbrook 639a78eeadSStefan Weil void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) 64009a4356SLaurent Vivier { 6592a31361SAndreas Färber CPUListState s = { 6611150915SAndreas Färber .file = f, 6711150915SAndreas Färber .cpu_fprintf = cpu_fprintf, 6811150915SAndreas Färber }; 6911150915SAndreas Färber GSList *list; 70009a4356SLaurent Vivier 7111150915SAndreas Färber list = object_class_get_list(TYPE_M68K_CPU, false); 7211150915SAndreas Färber list = g_slist_sort(list, m68k_cpu_list_compare); 7311150915SAndreas Färber g_slist_foreach(list, m68k_cpu_list_entry, &s); 7411150915SAndreas Färber g_slist_free(list); 75009a4356SLaurent Vivier } 76009a4356SLaurent Vivier 77f83311e4SLaurent Vivier static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 7856aebc89Spbrook { 7956aebc89Spbrook if (n < 8) { 80f83311e4SLaurent Vivier float_status s; 81f83311e4SLaurent Vivier stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); 8256aebc89Spbrook return 8; 8356aebc89Spbrook } 84ba624944SLaurent Vivier switch (n) { 85ba624944SLaurent Vivier case 8: /* fpcontrol */ 86ba624944SLaurent Vivier stl_be_p(mem_buf, env->fpcr); 87ba624944SLaurent Vivier return 4; 88ba624944SLaurent Vivier case 9: /* fpstatus */ 89ba624944SLaurent Vivier stl_be_p(mem_buf, env->fpsr); 90ba624944SLaurent Vivier return 4; 91ba624944SLaurent Vivier case 10: /* fpiar, not implemented */ 9256aebc89Spbrook memset(mem_buf, 0, 4); 9356aebc89Spbrook return 4; 9456aebc89Spbrook } 9556aebc89Spbrook return 0; 9656aebc89Spbrook } 9756aebc89Spbrook 98f83311e4SLaurent Vivier static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 9956aebc89Spbrook { 10056aebc89Spbrook if (n < 8) { 101f83311e4SLaurent Vivier float_status s; 102f83311e4SLaurent Vivier env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s); 10356aebc89Spbrook return 8; 10456aebc89Spbrook } 105ba624944SLaurent Vivier switch (n) { 106ba624944SLaurent Vivier case 8: /* fpcontrol */ 107ba624944SLaurent Vivier cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); 108ba624944SLaurent Vivier return 4; 109ba624944SLaurent Vivier case 9: /* fpstatus */ 110ba624944SLaurent Vivier env->fpsr = ldl_p(mem_buf); 111ba624944SLaurent Vivier return 4; 112ba624944SLaurent Vivier case 10: /* fpiar, not implemented */ 11356aebc89Spbrook return 4; 11456aebc89Spbrook } 11556aebc89Spbrook return 0; 11656aebc89Spbrook } 11756aebc89Spbrook 1185a4526b2SLaurent Vivier static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 1195a4526b2SLaurent Vivier { 1205a4526b2SLaurent Vivier if (n < 8) { 1215a4526b2SLaurent Vivier stw_be_p(mem_buf, env->fregs[n].l.upper); 1225a4526b2SLaurent Vivier memset(mem_buf + 2, 0, 2); 1235a4526b2SLaurent Vivier stq_be_p(mem_buf + 4, env->fregs[n].l.lower); 1245a4526b2SLaurent Vivier return 12; 1255a4526b2SLaurent Vivier } 1265a4526b2SLaurent Vivier switch (n) { 1275a4526b2SLaurent Vivier case 8: /* fpcontrol */ 1285a4526b2SLaurent Vivier stl_be_p(mem_buf, env->fpcr); 1295a4526b2SLaurent Vivier return 4; 1305a4526b2SLaurent Vivier case 9: /* fpstatus */ 1315a4526b2SLaurent Vivier stl_be_p(mem_buf, env->fpsr); 1325a4526b2SLaurent Vivier return 4; 1335a4526b2SLaurent Vivier case 10: /* fpiar, not implemented */ 1345a4526b2SLaurent Vivier memset(mem_buf, 0, 4); 1355a4526b2SLaurent Vivier return 4; 1365a4526b2SLaurent Vivier } 1375a4526b2SLaurent Vivier return 0; 1385a4526b2SLaurent Vivier } 1395a4526b2SLaurent Vivier 1405a4526b2SLaurent Vivier static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 1415a4526b2SLaurent Vivier { 1425a4526b2SLaurent Vivier if (n < 8) { 1435a4526b2SLaurent Vivier env->fregs[n].l.upper = lduw_be_p(mem_buf); 1445a4526b2SLaurent Vivier env->fregs[n].l.lower = ldq_be_p(mem_buf + 4); 1455a4526b2SLaurent Vivier return 12; 1465a4526b2SLaurent Vivier } 1475a4526b2SLaurent Vivier switch (n) { 1485a4526b2SLaurent Vivier case 8: /* fpcontrol */ 149ba624944SLaurent Vivier cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); 1505a4526b2SLaurent Vivier return 4; 1515a4526b2SLaurent Vivier case 9: /* fpstatus */ 1525a4526b2SLaurent Vivier env->fpsr = ldl_p(mem_buf); 1535a4526b2SLaurent Vivier return 4; 1545a4526b2SLaurent Vivier case 10: /* fpiar, not implemented */ 1555a4526b2SLaurent Vivier return 4; 1565a4526b2SLaurent Vivier } 1575a4526b2SLaurent Vivier return 0; 1585a4526b2SLaurent Vivier } 1595a4526b2SLaurent Vivier 1606d1bbc62SAndreas Färber void m68k_cpu_init_gdb(M68kCPU *cpu) 1616d1bbc62SAndreas Färber { 16222169d41SAndreas Färber CPUState *cs = CPU(cpu); 1636d1bbc62SAndreas Färber CPUM68KState *env = &cpu->env; 1646d1bbc62SAndreas Färber 16511150915SAndreas Färber if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { 166f83311e4SLaurent Vivier gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg, 16711150915SAndreas Färber 11, "cf-fp.xml", 18); 1685a4526b2SLaurent Vivier } else if (m68k_feature(env, M68K_FEATURE_FPU)) { 1695a4526b2SLaurent Vivier gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg, 1705a4526b2SLaurent Vivier m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18); 171aaed909aSbellard } 17211150915SAndreas Färber /* TODO: Add [E]MAC registers. */ 173aaed909aSbellard } 174aaed909aSbellard 1756e22b28eSLaurent Vivier void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) 1760633879fSpbrook { 177a47dddd7SAndreas Färber M68kCPU *cpu = m68k_env_get_cpu(env); 178a47dddd7SAndreas Färber 1790633879fSpbrook switch (reg) { 1806e22b28eSLaurent Vivier case M68K_CR_CACR: 18120dcee94Spbrook env->cacr = val; 18220dcee94Spbrook m68k_switch_sp(env); 18320dcee94Spbrook break; 1846e22b28eSLaurent Vivier case M68K_CR_ACR0: 1856e22b28eSLaurent Vivier case M68K_CR_ACR1: 1866e22b28eSLaurent Vivier case M68K_CR_ACR2: 1876e22b28eSLaurent Vivier case M68K_CR_ACR3: 18820dcee94Spbrook /* TODO: Implement Access Control Registers. */ 1890633879fSpbrook break; 1906e22b28eSLaurent Vivier case M68K_CR_VBR: 1910633879fSpbrook env->vbr = val; 1920633879fSpbrook break; 1930633879fSpbrook /* TODO: Implement control registers. */ 1940633879fSpbrook default: 1956e22b28eSLaurent Vivier cpu_abort(CPU(cpu), 1966e22b28eSLaurent Vivier "Unimplemented control register write 0x%x = 0x%x\n", 1976e22b28eSLaurent Vivier reg, val); 1986e22b28eSLaurent Vivier } 1996e22b28eSLaurent Vivier } 2006e22b28eSLaurent Vivier 2016e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) 2026e22b28eSLaurent Vivier { 2036e22b28eSLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 2046e22b28eSLaurent Vivier 2056e22b28eSLaurent Vivier switch (reg) { 2066e22b28eSLaurent Vivier /* MC680[1234]0 */ 2075fa9f1f2SLaurent Vivier case M68K_CR_SFC: 2085fa9f1f2SLaurent Vivier env->sfc = val & 7; 2095fa9f1f2SLaurent Vivier return; 2105fa9f1f2SLaurent Vivier case M68K_CR_DFC: 2115fa9f1f2SLaurent Vivier env->dfc = val & 7; 2125fa9f1f2SLaurent Vivier return; 2136e22b28eSLaurent Vivier case M68K_CR_VBR: 2146e22b28eSLaurent Vivier env->vbr = val; 2156e22b28eSLaurent Vivier return; 2166e22b28eSLaurent Vivier /* MC680[234]0 */ 2176e22b28eSLaurent Vivier case M68K_CR_CACR: 2186e22b28eSLaurent Vivier env->cacr = val; 2196e22b28eSLaurent Vivier m68k_switch_sp(env); 2206e22b28eSLaurent Vivier return; 2216e22b28eSLaurent Vivier /* MC680[34]0 */ 22288b2fef6SLaurent Vivier case M68K_CR_TC: 22388b2fef6SLaurent Vivier env->mmu.tcr = val; 22488b2fef6SLaurent Vivier return; 225e55886c3SLaurent Vivier case M68K_CR_MMUSR: 226e55886c3SLaurent Vivier env->mmu.mmusr = val; 227e55886c3SLaurent Vivier return; 22888b2fef6SLaurent Vivier case M68K_CR_SRP: 22988b2fef6SLaurent Vivier env->mmu.srp = val; 23088b2fef6SLaurent Vivier return; 23188b2fef6SLaurent Vivier case M68K_CR_URP: 23288b2fef6SLaurent Vivier env->mmu.urp = val; 23388b2fef6SLaurent Vivier return; 2346e22b28eSLaurent Vivier case M68K_CR_USP: 2356e22b28eSLaurent Vivier env->sp[M68K_USP] = val; 2366e22b28eSLaurent Vivier return; 2376e22b28eSLaurent Vivier case M68K_CR_MSP: 2386e22b28eSLaurent Vivier env->sp[M68K_SSP] = val; 2396e22b28eSLaurent Vivier return; 2406e22b28eSLaurent Vivier case M68K_CR_ISP: 2416e22b28eSLaurent Vivier env->sp[M68K_ISP] = val; 2426e22b28eSLaurent Vivier return; 243c05c73b0SLaurent Vivier /* MC68040/MC68LC040 */ 244c05c73b0SLaurent Vivier case M68K_CR_ITT0: 245c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR0] = val; 246c05c73b0SLaurent Vivier return; 247c05c73b0SLaurent Vivier case M68K_CR_ITT1: 248c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR1] = val; 249c05c73b0SLaurent Vivier return; 250c05c73b0SLaurent Vivier case M68K_CR_DTT0: 251c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR0] = val; 252c05c73b0SLaurent Vivier return; 253c05c73b0SLaurent Vivier case M68K_CR_DTT1: 254c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR1] = val; 255c05c73b0SLaurent Vivier return; 2566e22b28eSLaurent Vivier } 257a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", 2580633879fSpbrook reg, val); 2590633879fSpbrook } 2606e22b28eSLaurent Vivier 2616e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) 2626e22b28eSLaurent Vivier { 2636e22b28eSLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 2646e22b28eSLaurent Vivier 2656e22b28eSLaurent Vivier switch (reg) { 2666e22b28eSLaurent Vivier /* MC680[1234]0 */ 2675fa9f1f2SLaurent Vivier case M68K_CR_SFC: 2685fa9f1f2SLaurent Vivier return env->sfc; 2695fa9f1f2SLaurent Vivier case M68K_CR_DFC: 2705fa9f1f2SLaurent Vivier return env->dfc; 2716e22b28eSLaurent Vivier case M68K_CR_VBR: 2726e22b28eSLaurent Vivier return env->vbr; 2736e22b28eSLaurent Vivier /* MC680[234]0 */ 2746e22b28eSLaurent Vivier case M68K_CR_CACR: 2756e22b28eSLaurent Vivier return env->cacr; 2766e22b28eSLaurent Vivier /* MC680[34]0 */ 27788b2fef6SLaurent Vivier case M68K_CR_TC: 27888b2fef6SLaurent Vivier return env->mmu.tcr; 279e55886c3SLaurent Vivier case M68K_CR_MMUSR: 280e55886c3SLaurent Vivier return env->mmu.mmusr; 28188b2fef6SLaurent Vivier case M68K_CR_SRP: 28288b2fef6SLaurent Vivier return env->mmu.srp; 2836e22b28eSLaurent Vivier case M68K_CR_USP: 2846e22b28eSLaurent Vivier return env->sp[M68K_USP]; 2856e22b28eSLaurent Vivier case M68K_CR_MSP: 2866e22b28eSLaurent Vivier return env->sp[M68K_SSP]; 2876e22b28eSLaurent Vivier case M68K_CR_ISP: 2886e22b28eSLaurent Vivier return env->sp[M68K_ISP]; 28988b2fef6SLaurent Vivier /* MC68040/MC68LC040 */ 29088b2fef6SLaurent Vivier case M68K_CR_URP: 29188b2fef6SLaurent Vivier return env->mmu.urp; 292c05c73b0SLaurent Vivier case M68K_CR_ITT0: 293c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_ITTR0]; 294c05c73b0SLaurent Vivier case M68K_CR_ITT1: 295c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_ITTR1]; 296c05c73b0SLaurent Vivier case M68K_CR_DTT0: 297c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_DTTR0]; 298c05c73b0SLaurent Vivier case M68K_CR_DTT1: 299c05c73b0SLaurent Vivier return env->mmu.ttr[M68K_DTTR1]; 3006e22b28eSLaurent Vivier } 3016e22b28eSLaurent Vivier cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n", 3026e22b28eSLaurent Vivier reg); 3030633879fSpbrook } 3040633879fSpbrook 305e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) 306acf930aaSpbrook { 307acf930aaSpbrook uint32_t acc; 308acf930aaSpbrook int8_t exthigh; 309acf930aaSpbrook uint8_t extlow; 310acf930aaSpbrook uint64_t regval; 311acf930aaSpbrook int i; 312acf930aaSpbrook if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { 313acf930aaSpbrook for (i = 0; i < 4; i++) { 314acf930aaSpbrook regval = env->macc[i]; 315acf930aaSpbrook exthigh = regval >> 40; 316acf930aaSpbrook if (env->macsr & MACSR_FI) { 317acf930aaSpbrook acc = regval >> 8; 318acf930aaSpbrook extlow = regval; 319acf930aaSpbrook } else { 320acf930aaSpbrook acc = regval; 321acf930aaSpbrook extlow = regval >> 32; 322acf930aaSpbrook } 323acf930aaSpbrook if (env->macsr & MACSR_FI) { 324acf930aaSpbrook regval = (((uint64_t)acc) << 8) | extlow; 325acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 326acf930aaSpbrook } else if (env->macsr & MACSR_SU) { 327acf930aaSpbrook regval = acc | (((int64_t)extlow) << 32); 328acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 329acf930aaSpbrook } else { 330acf930aaSpbrook regval = acc | (((uint64_t)extlow) << 32); 331acf930aaSpbrook regval |= ((uint64_t)(uint8_t)exthigh) << 40; 332acf930aaSpbrook } 333acf930aaSpbrook env->macc[i] = regval; 334acf930aaSpbrook } 335acf930aaSpbrook } 336acf930aaSpbrook env->macsr = val; 337acf930aaSpbrook } 338acf930aaSpbrook 33920dcee94Spbrook void m68k_switch_sp(CPUM68KState *env) 34020dcee94Spbrook { 34120dcee94Spbrook int new_sp; 34220dcee94Spbrook 34320dcee94Spbrook env->sp[env->current_sp] = env->aregs[7]; 3446e22b28eSLaurent Vivier if (m68k_feature(env, M68K_FEATURE_M68000)) { 3456e22b28eSLaurent Vivier if (env->sr & SR_S) { 3466e22b28eSLaurent Vivier if (env->sr & SR_M) { 3476e22b28eSLaurent Vivier new_sp = M68K_SSP; 3486e22b28eSLaurent Vivier } else { 3496e22b28eSLaurent Vivier new_sp = M68K_ISP; 3506e22b28eSLaurent Vivier } 3516e22b28eSLaurent Vivier } else { 3526e22b28eSLaurent Vivier new_sp = M68K_USP; 3536e22b28eSLaurent Vivier } 3546e22b28eSLaurent Vivier } else { 35520dcee94Spbrook new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) 35620dcee94Spbrook ? M68K_SSP : M68K_USP; 3576e22b28eSLaurent Vivier } 35820dcee94Spbrook env->aregs[7] = env->sp[new_sp]; 35920dcee94Spbrook env->current_sp = new_sp; 36020dcee94Spbrook } 36120dcee94Spbrook 3620633879fSpbrook #if defined(CONFIG_USER_ONLY) 3630633879fSpbrook 36498670d47SLaurent Vivier int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, 36597b348e7SBlue Swirl int mmu_idx) 3660633879fSpbrook { 3677510454eSAndreas Färber M68kCPU *cpu = M68K_CPU(cs); 3687510454eSAndreas Färber 36927103424SAndreas Färber cs->exception_index = EXCP_ACCESS; 3707510454eSAndreas Färber cpu->env.mmu.ar = address; 3710633879fSpbrook return 1; 3720633879fSpbrook } 3730633879fSpbrook 3740633879fSpbrook #else 3750633879fSpbrook 37688b2fef6SLaurent Vivier /* MMU: 68040 only */ 3774fcc562bSPaul Brook 3782097dca6SLaurent Vivier static void print_address_zone(FILE *f, fprintf_function cpu_fprintf, 3792097dca6SLaurent Vivier uint32_t logical, uint32_t physical, 3802097dca6SLaurent Vivier uint32_t size, int attr) 3812097dca6SLaurent Vivier { 3822097dca6SLaurent Vivier cpu_fprintf(f, "%08x - %08x -> %08x - %08x %c ", 3832097dca6SLaurent Vivier logical, logical + size - 1, 3842097dca6SLaurent Vivier physical, physical + size - 1, 3852097dca6SLaurent Vivier attr & 4 ? 'W' : '-'); 3862097dca6SLaurent Vivier size >>= 10; 3872097dca6SLaurent Vivier if (size < 1024) { 3882097dca6SLaurent Vivier cpu_fprintf(f, "(%d KiB)\n", size); 3892097dca6SLaurent Vivier } else { 3902097dca6SLaurent Vivier size >>= 10; 3912097dca6SLaurent Vivier if (size < 1024) { 3922097dca6SLaurent Vivier cpu_fprintf(f, "(%d MiB)\n", size); 3932097dca6SLaurent Vivier } else { 3942097dca6SLaurent Vivier size >>= 10; 3952097dca6SLaurent Vivier cpu_fprintf(f, "(%d GiB)\n", size); 3962097dca6SLaurent Vivier } 3972097dca6SLaurent Vivier } 3982097dca6SLaurent Vivier } 3992097dca6SLaurent Vivier 4002097dca6SLaurent Vivier static void dump_address_map(FILE *f, fprintf_function cpu_fprintf, 4012097dca6SLaurent Vivier CPUM68KState *env, uint32_t root_pointer) 4022097dca6SLaurent Vivier { 4032097dca6SLaurent Vivier int i, j, k; 4042097dca6SLaurent Vivier int tic_size, tic_shift; 4052097dca6SLaurent Vivier uint32_t tib_mask; 4062097dca6SLaurent Vivier uint32_t tia, tib, tic; 4072097dca6SLaurent Vivier uint32_t logical = 0xffffffff, physical = 0xffffffff; 4082097dca6SLaurent Vivier uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff; 4092097dca6SLaurent Vivier uint32_t last_logical, last_physical; 4102097dca6SLaurent Vivier int32_t size; 4112097dca6SLaurent Vivier int last_attr = -1, attr = -1; 4122097dca6SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 4132097dca6SLaurent Vivier CPUState *cs = CPU(cpu); 4142097dca6SLaurent Vivier 4152097dca6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 4162097dca6SLaurent Vivier /* 8k page */ 4172097dca6SLaurent Vivier tic_size = 32; 4182097dca6SLaurent Vivier tic_shift = 13; 4192097dca6SLaurent Vivier tib_mask = M68K_8K_PAGE_MASK; 4202097dca6SLaurent Vivier } else { 4212097dca6SLaurent Vivier /* 4k page */ 4222097dca6SLaurent Vivier tic_size = 64; 4232097dca6SLaurent Vivier tic_shift = 12; 4242097dca6SLaurent Vivier tib_mask = M68K_4K_PAGE_MASK; 4252097dca6SLaurent Vivier } 4262097dca6SLaurent Vivier for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) { 4272097dca6SLaurent Vivier tia = ldl_phys(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4); 4282097dca6SLaurent Vivier if (!M68K_UDT_VALID(tia)) { 4292097dca6SLaurent Vivier continue; 4302097dca6SLaurent Vivier } 4312097dca6SLaurent Vivier for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) { 4322097dca6SLaurent Vivier tib = ldl_phys(cs->as, M68K_POINTER_BASE(tia) + j * 4); 4332097dca6SLaurent Vivier if (!M68K_UDT_VALID(tib)) { 4342097dca6SLaurent Vivier continue; 4352097dca6SLaurent Vivier } 4362097dca6SLaurent Vivier for (k = 0; k < tic_size; k++) { 4372097dca6SLaurent Vivier tic = ldl_phys(cs->as, (tib & tib_mask) + k * 4); 4382097dca6SLaurent Vivier if (!M68K_PDT_VALID(tic)) { 4392097dca6SLaurent Vivier continue; 4402097dca6SLaurent Vivier } 4412097dca6SLaurent Vivier if (M68K_PDT_INDIRECT(tic)) { 4422097dca6SLaurent Vivier tic = ldl_phys(cs->as, M68K_INDIRECT_POINTER(tic)); 4432097dca6SLaurent Vivier } 4442097dca6SLaurent Vivier 4452097dca6SLaurent Vivier last_logical = logical; 4462097dca6SLaurent Vivier logical = (i << M68K_TTS_ROOT_SHIFT) | 4472097dca6SLaurent Vivier (j << M68K_TTS_POINTER_SHIFT) | 4482097dca6SLaurent Vivier (k << tic_shift); 4492097dca6SLaurent Vivier 4502097dca6SLaurent Vivier last_physical = physical; 4512097dca6SLaurent Vivier physical = tic & ~((1 << tic_shift) - 1); 4522097dca6SLaurent Vivier 4532097dca6SLaurent Vivier last_attr = attr; 4542097dca6SLaurent Vivier attr = tic & ((1 << tic_shift) - 1); 4552097dca6SLaurent Vivier 4562097dca6SLaurent Vivier if ((logical != (last_logical + (1 << tic_shift))) || 4572097dca6SLaurent Vivier (physical != (last_physical + (1 << tic_shift))) || 4582097dca6SLaurent Vivier (attr & 4) != (last_attr & 4)) { 4592097dca6SLaurent Vivier 4602097dca6SLaurent Vivier if (first_logical != 0xffffffff) { 4612097dca6SLaurent Vivier size = last_logical + (1 << tic_shift) - 4622097dca6SLaurent Vivier first_logical; 4632097dca6SLaurent Vivier print_address_zone(f, cpu_fprintf, first_logical, 4642097dca6SLaurent Vivier first_physical, size, last_attr); 4652097dca6SLaurent Vivier } 4662097dca6SLaurent Vivier first_logical = logical; 4672097dca6SLaurent Vivier first_physical = physical; 4682097dca6SLaurent Vivier } 4692097dca6SLaurent Vivier } 4702097dca6SLaurent Vivier } 4712097dca6SLaurent Vivier } 4722097dca6SLaurent Vivier if (first_logical != logical || (attr & 4) != (last_attr & 4)) { 4732097dca6SLaurent Vivier size = logical + (1 << tic_shift) - first_logical; 4742097dca6SLaurent Vivier print_address_zone(f, cpu_fprintf, first_logical, first_physical, size, 4752097dca6SLaurent Vivier last_attr); 4762097dca6SLaurent Vivier } 4772097dca6SLaurent Vivier } 4782097dca6SLaurent Vivier 4792097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \ 4802097dca6SLaurent Vivier switch (a & M68K_DESC_CACHEMODE) { \ 4812097dca6SLaurent Vivier case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \ 4822097dca6SLaurent Vivier cpu_fprintf(f, "T"); \ 4832097dca6SLaurent Vivier break; \ 4842097dca6SLaurent Vivier case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \ 4852097dca6SLaurent Vivier cpu_fprintf(f, "C"); \ 4862097dca6SLaurent Vivier break; \ 4872097dca6SLaurent Vivier case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \ 4882097dca6SLaurent Vivier cpu_fprintf(f, "S"); \ 4892097dca6SLaurent Vivier break; \ 4902097dca6SLaurent Vivier case M68K_DESC_CM_NCACHE: /* noncachable */ \ 4912097dca6SLaurent Vivier cpu_fprintf(f, "N"); \ 4922097dca6SLaurent Vivier break; \ 4932097dca6SLaurent Vivier } 4942097dca6SLaurent Vivier 4952097dca6SLaurent Vivier static void dump_ttr(FILE *f, fprintf_function cpu_fprintf, uint32_t ttr) 4962097dca6SLaurent Vivier { 4972097dca6SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 4982097dca6SLaurent Vivier cpu_fprintf(f, "disabled\n"); 4992097dca6SLaurent Vivier return; 5002097dca6SLaurent Vivier } 5012097dca6SLaurent Vivier cpu_fprintf(f, "Base: 0x%08x Mask: 0x%08x Control: ", 5022097dca6SLaurent Vivier ttr & M68K_TTR_ADDR_BASE, 5032097dca6SLaurent Vivier (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT); 5042097dca6SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 5052097dca6SLaurent Vivier case M68K_TTR_SFIELD_USER: 5062097dca6SLaurent Vivier cpu_fprintf(f, "U"); 5072097dca6SLaurent Vivier break; 5082097dca6SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 5092097dca6SLaurent Vivier cpu_fprintf(f, "S"); 5102097dca6SLaurent Vivier break; 5112097dca6SLaurent Vivier default: 5122097dca6SLaurent Vivier cpu_fprintf(f, "*"); 5132097dca6SLaurent Vivier break; 5142097dca6SLaurent Vivier } 5152097dca6SLaurent Vivier DUMP_CACHEFLAGS(ttr); 5162097dca6SLaurent Vivier if (ttr & M68K_DESC_WRITEPROT) { 5172097dca6SLaurent Vivier cpu_fprintf(f, "R"); 5182097dca6SLaurent Vivier } else { 5192097dca6SLaurent Vivier cpu_fprintf(f, "W"); 5202097dca6SLaurent Vivier } 5212097dca6SLaurent Vivier cpu_fprintf(f, " U: %d\n", (ttr & M68K_DESC_USERATTR) >> 5222097dca6SLaurent Vivier M68K_DESC_USERATTR_SHIFT); 5232097dca6SLaurent Vivier } 5242097dca6SLaurent Vivier 5252097dca6SLaurent Vivier void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env) 5262097dca6SLaurent Vivier { 5272097dca6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 5282097dca6SLaurent Vivier cpu_fprintf(f, "Translation disabled\n"); 5292097dca6SLaurent Vivier return; 5302097dca6SLaurent Vivier } 5312097dca6SLaurent Vivier cpu_fprintf(f, "Page Size: "); 5322097dca6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 5332097dca6SLaurent Vivier cpu_fprintf(f, "8kB\n"); 5342097dca6SLaurent Vivier } else { 5352097dca6SLaurent Vivier cpu_fprintf(f, "4kB\n"); 5362097dca6SLaurent Vivier } 5372097dca6SLaurent Vivier 5382097dca6SLaurent Vivier cpu_fprintf(f, "MMUSR: "); 5392097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_B_040) { 5402097dca6SLaurent Vivier cpu_fprintf(f, "BUS ERROR\n"); 5412097dca6SLaurent Vivier } else { 5422097dca6SLaurent Vivier cpu_fprintf(f, "Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000); 5432097dca6SLaurent Vivier /* flags found on the page descriptor */ 5442097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_G_040) { 5452097dca6SLaurent Vivier cpu_fprintf(f, "G"); /* Global */ 5462097dca6SLaurent Vivier } else { 5472097dca6SLaurent Vivier cpu_fprintf(f, "."); 5482097dca6SLaurent Vivier } 5492097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_S_040) { 5502097dca6SLaurent Vivier cpu_fprintf(f, "S"); /* Supervisor */ 5512097dca6SLaurent Vivier } else { 5522097dca6SLaurent Vivier cpu_fprintf(f, "."); 5532097dca6SLaurent Vivier } 5542097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_M_040) { 5552097dca6SLaurent Vivier cpu_fprintf(f, "M"); /* Modified */ 5562097dca6SLaurent Vivier } else { 5572097dca6SLaurent Vivier cpu_fprintf(f, "."); 5582097dca6SLaurent Vivier } 5592097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_WP_040) { 5602097dca6SLaurent Vivier cpu_fprintf(f, "W"); /* Write protect */ 5612097dca6SLaurent Vivier } else { 5622097dca6SLaurent Vivier cpu_fprintf(f, "."); 5632097dca6SLaurent Vivier } 5642097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_T_040) { 5652097dca6SLaurent Vivier cpu_fprintf(f, "T"); /* Transparent */ 5662097dca6SLaurent Vivier } else { 5672097dca6SLaurent Vivier cpu_fprintf(f, "."); 5682097dca6SLaurent Vivier } 5692097dca6SLaurent Vivier if (env->mmu.mmusr & M68K_MMU_R_040) { 5702097dca6SLaurent Vivier cpu_fprintf(f, "R"); /* Resident */ 5712097dca6SLaurent Vivier } else { 5722097dca6SLaurent Vivier cpu_fprintf(f, "."); 5732097dca6SLaurent Vivier } 5742097dca6SLaurent Vivier cpu_fprintf(f, " Cache: "); 5752097dca6SLaurent Vivier DUMP_CACHEFLAGS(env->mmu.mmusr); 5762097dca6SLaurent Vivier cpu_fprintf(f, " U: %d\n", (env->mmu.mmusr >> 8) & 3); 5772097dca6SLaurent Vivier cpu_fprintf(f, "\n"); 5782097dca6SLaurent Vivier } 5792097dca6SLaurent Vivier 5802097dca6SLaurent Vivier cpu_fprintf(f, "ITTR0: "); 5812097dca6SLaurent Vivier dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR0]); 5822097dca6SLaurent Vivier cpu_fprintf(f, "ITTR1: "); 5832097dca6SLaurent Vivier dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR1]); 5842097dca6SLaurent Vivier cpu_fprintf(f, "DTTR0: "); 5852097dca6SLaurent Vivier dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR0]); 5862097dca6SLaurent Vivier cpu_fprintf(f, "DTTR1: "); 5872097dca6SLaurent Vivier dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR1]); 5882097dca6SLaurent Vivier 5892097dca6SLaurent Vivier cpu_fprintf(f, "SRP: 0x%08x\n", env->mmu.srp); 5902097dca6SLaurent Vivier dump_address_map(f, cpu_fprintf, env, env->mmu.srp); 5912097dca6SLaurent Vivier 5922097dca6SLaurent Vivier cpu_fprintf(f, "URP: 0x%08x\n", env->mmu.urp); 5932097dca6SLaurent Vivier dump_address_map(f, cpu_fprintf, env, env->mmu.urp); 5942097dca6SLaurent Vivier } 5952097dca6SLaurent Vivier 596c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr, 597c05c73b0SLaurent Vivier int access_type) 598c05c73b0SLaurent Vivier { 599c05c73b0SLaurent Vivier uint32_t base, mask; 600c05c73b0SLaurent Vivier 601c05c73b0SLaurent Vivier /* check if transparent translation is enabled */ 602c05c73b0SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 603c05c73b0SLaurent Vivier return 0; 604c05c73b0SLaurent Vivier } 605c05c73b0SLaurent Vivier 606c05c73b0SLaurent Vivier /* check mode access */ 607c05c73b0SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 608c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_USER: 609c05c73b0SLaurent Vivier /* match only if user */ 610c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) != 0) { 611c05c73b0SLaurent Vivier return 0; 612c05c73b0SLaurent Vivier } 613c05c73b0SLaurent Vivier break; 614c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 615c05c73b0SLaurent Vivier /* match only if supervisor */ 616c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 617c05c73b0SLaurent Vivier return 0; 618c05c73b0SLaurent Vivier } 619c05c73b0SLaurent Vivier break; 620c05c73b0SLaurent Vivier default: 621c05c73b0SLaurent Vivier /* all other values disable mode matching (FC2) */ 622c05c73b0SLaurent Vivier break; 623c05c73b0SLaurent Vivier } 624c05c73b0SLaurent Vivier 625c05c73b0SLaurent Vivier /* check address matching */ 626c05c73b0SLaurent Vivier 627c05c73b0SLaurent Vivier base = ttr & M68K_TTR_ADDR_BASE; 628c05c73b0SLaurent Vivier mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK; 629c05c73b0SLaurent Vivier mask <<= M68K_TTR_ADDR_MASK_SHIFT; 630c05c73b0SLaurent Vivier 631c05c73b0SLaurent Vivier if ((addr & mask) != (base & mask)) { 632c05c73b0SLaurent Vivier return 0; 633c05c73b0SLaurent Vivier } 634c05c73b0SLaurent Vivier 635c05c73b0SLaurent Vivier *prot = PAGE_READ | PAGE_EXEC; 636c05c73b0SLaurent Vivier if ((ttr & M68K_DESC_WRITEPROT) == 0) { 637c05c73b0SLaurent Vivier *prot |= PAGE_WRITE; 638c05c73b0SLaurent Vivier } 639c05c73b0SLaurent Vivier 640c05c73b0SLaurent Vivier return 1; 641c05c73b0SLaurent Vivier } 642c05c73b0SLaurent Vivier 64388b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical, 64488b2fef6SLaurent Vivier int *prot, target_ulong address, 64588b2fef6SLaurent Vivier int access_type, target_ulong *page_size) 64688b2fef6SLaurent Vivier { 64788b2fef6SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 64888b2fef6SLaurent Vivier CPUState *cs = CPU(cpu); 64988b2fef6SLaurent Vivier uint32_t entry; 65088b2fef6SLaurent Vivier uint32_t next; 65188b2fef6SLaurent Vivier target_ulong page_mask; 65288b2fef6SLaurent Vivier bool debug = access_type & ACCESS_DEBUG; 65388b2fef6SLaurent Vivier int page_bits; 654c05c73b0SLaurent Vivier int i; 655c05c73b0SLaurent Vivier 656c05c73b0SLaurent Vivier /* Transparent Translation (physical = logical) */ 657c05c73b0SLaurent Vivier for (i = 0; i < M68K_MAX_TTR; i++) { 658c05c73b0SLaurent Vivier if (check_TTR(env->mmu.TTR(access_type, i), 659c05c73b0SLaurent Vivier prot, address, access_type)) { 660e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 661e55886c3SLaurent Vivier /* Transparent Translation Register bit */ 662e55886c3SLaurent Vivier env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040; 663e55886c3SLaurent Vivier } 664c05c73b0SLaurent Vivier *physical = address & TARGET_PAGE_MASK; 665c05c73b0SLaurent Vivier *page_size = TARGET_PAGE_SIZE; 666c05c73b0SLaurent Vivier return 0; 667c05c73b0SLaurent Vivier } 668c05c73b0SLaurent Vivier } 66988b2fef6SLaurent Vivier 67088b2fef6SLaurent Vivier /* Page Table Root Pointer */ 67188b2fef6SLaurent Vivier *prot = PAGE_READ | PAGE_WRITE; 67288b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 67388b2fef6SLaurent Vivier *prot |= PAGE_EXEC; 67488b2fef6SLaurent Vivier } 67588b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 67688b2fef6SLaurent Vivier next = env->mmu.srp; 67788b2fef6SLaurent Vivier } else { 67888b2fef6SLaurent Vivier next = env->mmu.urp; 67988b2fef6SLaurent Vivier } 68088b2fef6SLaurent Vivier 68188b2fef6SLaurent Vivier /* Root Index */ 68288b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address); 68388b2fef6SLaurent Vivier 68488b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 68588b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 68688b2fef6SLaurent Vivier return -1; 68788b2fef6SLaurent Vivier } 68888b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 68988b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 69088b2fef6SLaurent Vivier } 69188b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 692e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 693e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_WP_040; 694e55886c3SLaurent Vivier } 69588b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 69688b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 69788b2fef6SLaurent Vivier return -1; 69888b2fef6SLaurent Vivier } 69988b2fef6SLaurent Vivier } 70088b2fef6SLaurent Vivier 70188b2fef6SLaurent Vivier /* Pointer Index */ 70288b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address); 70388b2fef6SLaurent Vivier 70488b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 70588b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 70688b2fef6SLaurent Vivier return -1; 70788b2fef6SLaurent Vivier } 70888b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 70988b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 71088b2fef6SLaurent Vivier } 71188b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 712e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 713e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_WP_040; 714e55886c3SLaurent Vivier } 71588b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 71688b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 71788b2fef6SLaurent Vivier return -1; 71888b2fef6SLaurent Vivier } 71988b2fef6SLaurent Vivier } 72088b2fef6SLaurent Vivier 72188b2fef6SLaurent Vivier /* Page Index */ 72288b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 72388b2fef6SLaurent Vivier entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address); 72488b2fef6SLaurent Vivier } else { 72588b2fef6SLaurent Vivier entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address); 72688b2fef6SLaurent Vivier } 72788b2fef6SLaurent Vivier 72888b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 72988b2fef6SLaurent Vivier 73088b2fef6SLaurent Vivier if (!M68K_PDT_VALID(next)) { 73188b2fef6SLaurent Vivier return -1; 73288b2fef6SLaurent Vivier } 73388b2fef6SLaurent Vivier if (M68K_PDT_INDIRECT(next)) { 73488b2fef6SLaurent Vivier next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next)); 73588b2fef6SLaurent Vivier } 73688b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 73788b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 73888b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 73988b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 74088b2fef6SLaurent Vivier } 74188b2fef6SLaurent Vivier } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) != 74288b2fef6SLaurent Vivier (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) { 74388b2fef6SLaurent Vivier stl_phys(cs->as, entry, 74488b2fef6SLaurent Vivier next | (M68K_DESC_MODIFIED | M68K_DESC_USED)); 74588b2fef6SLaurent Vivier } 74688b2fef6SLaurent Vivier } else { 74788b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 74888b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 74988b2fef6SLaurent Vivier } 75088b2fef6SLaurent Vivier } 75188b2fef6SLaurent Vivier 75288b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 75388b2fef6SLaurent Vivier page_bits = 13; 75488b2fef6SLaurent Vivier } else { 75588b2fef6SLaurent Vivier page_bits = 12; 75688b2fef6SLaurent Vivier } 75788b2fef6SLaurent Vivier *page_size = 1 << page_bits; 75888b2fef6SLaurent Vivier page_mask = ~(*page_size - 1); 75988b2fef6SLaurent Vivier *physical = next & page_mask; 76088b2fef6SLaurent Vivier 761e55886c3SLaurent Vivier if (access_type & ACCESS_PTEST) { 762e55886c3SLaurent Vivier env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040; 763e55886c3SLaurent Vivier env->mmu.mmusr |= *physical & 0xfffff000; 764e55886c3SLaurent Vivier env->mmu.mmusr |= M68K_MMU_R_040; 765e55886c3SLaurent Vivier } 766e55886c3SLaurent Vivier 76788b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 76888b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 76988b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 77088b2fef6SLaurent Vivier return -1; 77188b2fef6SLaurent Vivier } 77288b2fef6SLaurent Vivier } 77388b2fef6SLaurent Vivier if (next & M68K_DESC_SUPERONLY) { 77488b2fef6SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 77588b2fef6SLaurent Vivier return -1; 77688b2fef6SLaurent Vivier } 77788b2fef6SLaurent Vivier } 77888b2fef6SLaurent Vivier 77988b2fef6SLaurent Vivier return 0; 78088b2fef6SLaurent Vivier } 78188b2fef6SLaurent Vivier 78200b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 7834fcc562bSPaul Brook { 78488b2fef6SLaurent Vivier M68kCPU *cpu = M68K_CPU(cs); 78588b2fef6SLaurent Vivier CPUM68KState *env = &cpu->env; 78688b2fef6SLaurent Vivier hwaddr phys_addr; 78788b2fef6SLaurent Vivier int prot; 78888b2fef6SLaurent Vivier int access_type; 78988b2fef6SLaurent Vivier target_ulong page_size; 79088b2fef6SLaurent Vivier 79188b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 79288b2fef6SLaurent Vivier /* MMU disabled */ 7934fcc562bSPaul Brook return addr; 7944fcc562bSPaul Brook } 7954fcc562bSPaul Brook 79688b2fef6SLaurent Vivier access_type = ACCESS_DATA | ACCESS_DEBUG; 79788b2fef6SLaurent Vivier if (env->sr & SR_S) { 79888b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 79988b2fef6SLaurent Vivier } 80088b2fef6SLaurent Vivier if (get_physical_address(env, &phys_addr, &prot, 80188b2fef6SLaurent Vivier addr, access_type, &page_size) != 0) { 80288b2fef6SLaurent Vivier return -1; 80388b2fef6SLaurent Vivier } 80488b2fef6SLaurent Vivier return phys_addr; 80588b2fef6SLaurent Vivier } 80688b2fef6SLaurent Vivier 80798670d47SLaurent Vivier int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, 80897b348e7SBlue Swirl int mmu_idx) 8090633879fSpbrook { 81088b2fef6SLaurent Vivier M68kCPU *cpu = M68K_CPU(cs); 81188b2fef6SLaurent Vivier CPUM68KState *env = &cpu->env; 81288b2fef6SLaurent Vivier hwaddr physical; 8130633879fSpbrook int prot; 81488b2fef6SLaurent Vivier int access_type; 81588b2fef6SLaurent Vivier int ret; 81688b2fef6SLaurent Vivier target_ulong page_size; 8170633879fSpbrook 81888b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 81988b2fef6SLaurent Vivier /* MMU disabled */ 82088b2fef6SLaurent Vivier tlb_set_page(cs, address & TARGET_PAGE_MASK, 82188b2fef6SLaurent Vivier address & TARGET_PAGE_MASK, 82288b2fef6SLaurent Vivier PAGE_READ | PAGE_WRITE | PAGE_EXEC, 82388b2fef6SLaurent Vivier mmu_idx, TARGET_PAGE_SIZE); 824d4c430a8SPaul Brook return 0; 8250633879fSpbrook } 8260633879fSpbrook 82788b2fef6SLaurent Vivier if (rw == 2) { 82888b2fef6SLaurent Vivier access_type = ACCESS_CODE; 82988b2fef6SLaurent Vivier rw = 0; 83088b2fef6SLaurent Vivier } else { 83188b2fef6SLaurent Vivier access_type = ACCESS_DATA; 83288b2fef6SLaurent Vivier if (rw) { 83388b2fef6SLaurent Vivier access_type |= ACCESS_STORE; 83488b2fef6SLaurent Vivier } 83588b2fef6SLaurent Vivier } 83688b2fef6SLaurent Vivier 83788b2fef6SLaurent Vivier if (mmu_idx != MMU_USER_IDX) { 83888b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 83988b2fef6SLaurent Vivier } 84088b2fef6SLaurent Vivier 84188b2fef6SLaurent Vivier ret = get_physical_address(&cpu->env, &physical, &prot, 84288b2fef6SLaurent Vivier address, access_type, &page_size); 84388b2fef6SLaurent Vivier if (ret == 0) { 84488b2fef6SLaurent Vivier address &= TARGET_PAGE_MASK; 84588b2fef6SLaurent Vivier physical += address & (page_size - 1); 84688b2fef6SLaurent Vivier tlb_set_page(cs, address, physical, 84788b2fef6SLaurent Vivier prot, mmu_idx, TARGET_PAGE_SIZE); 84888b2fef6SLaurent Vivier return 0; 84988b2fef6SLaurent Vivier } 85088b2fef6SLaurent Vivier /* page fault */ 85188b2fef6SLaurent Vivier env->mmu.ssw = M68K_ATC_040; 85288b2fef6SLaurent Vivier switch (size) { 85388b2fef6SLaurent Vivier case 1: 85488b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_BYTE; 85588b2fef6SLaurent Vivier break; 85688b2fef6SLaurent Vivier case 2: 85788b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_WORD; 85888b2fef6SLaurent Vivier break; 85988b2fef6SLaurent Vivier case 4: 86088b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_LONG; 86188b2fef6SLaurent Vivier break; 86288b2fef6SLaurent Vivier } 86388b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 86488b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_SUPER; 86588b2fef6SLaurent Vivier } 86688b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 86788b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_CODE; 86888b2fef6SLaurent Vivier } else { 86988b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_DATA; 87088b2fef6SLaurent Vivier } 87188b2fef6SLaurent Vivier if (!(access_type & ACCESS_STORE)) { 87288b2fef6SLaurent Vivier env->mmu.ssw |= M68K_RW_040; 87388b2fef6SLaurent Vivier } 87488b2fef6SLaurent Vivier env->mmu.ar = address; 87588b2fef6SLaurent Vivier cs->exception_index = EXCP_ACCESS; 87688b2fef6SLaurent Vivier return 1; 87788b2fef6SLaurent Vivier } 87888b2fef6SLaurent Vivier 8790633879fSpbrook /* Notify CPU of a pending interrupt. Prioritization and vectoring should 8800633879fSpbrook be handled by the interrupt controller. Real hardware only requests 8810633879fSpbrook the vector when the interrupt is acknowledged by the CPU. For 8820633879fSpbrook simplicitly we calculate it when the interrupt is signalled. */ 883cb3fb38eSAndreas Färber void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) 8840633879fSpbrook { 885d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 886cb3fb38eSAndreas Färber CPUM68KState *env = &cpu->env; 887cb3fb38eSAndreas Färber 8880633879fSpbrook env->pending_level = level; 8890633879fSpbrook env->pending_vector = vector; 890d8ed887bSAndreas Färber if (level) { 891c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 892d8ed887bSAndreas Färber } else { 893d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 894d8ed887bSAndreas Färber } 8950633879fSpbrook } 8960633879fSpbrook 8970633879fSpbrook #endif 898e1f3808eSpbrook 899e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x) 900e1f3808eSpbrook { 901e1f3808eSpbrook x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); 902e1f3808eSpbrook x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); 903e1f3808eSpbrook x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); 904e1f3808eSpbrook return bswap32(x); 905e1f3808eSpbrook } 906e1f3808eSpbrook 907e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x) 908e1f3808eSpbrook { 909e1f3808eSpbrook int n; 910e1f3808eSpbrook for (n = 32; x; n--) 911e1f3808eSpbrook x >>= 1; 912e1f3808eSpbrook return n; 913e1f3808eSpbrook } 914e1f3808eSpbrook 915620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v) 916e1f3808eSpbrook { 917e1f3808eSpbrook /* The result has the opposite sign to the original value. */ 918620c6cf6SRichard Henderson if ((int32_t)v < 0) { 919e1f3808eSpbrook val = (((int32_t)val) >> 31) ^ SIGNBIT; 920620c6cf6SRichard Henderson } 921e1f3808eSpbrook return val; 922e1f3808eSpbrook } 923e1f3808eSpbrook 924d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) 925e1f3808eSpbrook { 926d2f8fb8eSLaurent Vivier env->sr = sr & 0xffe0; 927d2f8fb8eSLaurent Vivier cpu_m68k_set_ccr(env, sr); 928e1f3808eSpbrook m68k_switch_sp(env); 929e1f3808eSpbrook } 930e1f3808eSpbrook 931d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val) 932d2f8fb8eSLaurent Vivier { 933d2f8fb8eSLaurent Vivier cpu_m68k_set_sr(env, val); 934d2f8fb8eSLaurent Vivier } 935e1f3808eSpbrook 936e1f3808eSpbrook /* MAC unit. */ 937e1f3808eSpbrook /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers 938e1f3808eSpbrook take values, others take register numbers and manipulate the contents 939e1f3808eSpbrook in-place. */ 9402b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) 941e1f3808eSpbrook { 942e1f3808eSpbrook uint32_t mask; 943e1f3808eSpbrook env->macc[dest] = env->macc[src]; 944e1f3808eSpbrook mask = MACSR_PAV0 << dest; 945e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << src)) 946e1f3808eSpbrook env->macsr |= mask; 947e1f3808eSpbrook else 948e1f3808eSpbrook env->macsr &= ~mask; 949e1f3808eSpbrook } 950e1f3808eSpbrook 9512b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) 952e1f3808eSpbrook { 953e1f3808eSpbrook int64_t product; 954e1f3808eSpbrook int64_t res; 955e1f3808eSpbrook 956e1f3808eSpbrook product = (uint64_t)op1 * op2; 957e1f3808eSpbrook res = (product << 24) >> 24; 958e1f3808eSpbrook if (res != product) { 959e1f3808eSpbrook env->macsr |= MACSR_V; 960e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 961e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 962e1f3808eSpbrook if (product < 0) 963e1f3808eSpbrook res = ~(1ll << 50); 964e1f3808eSpbrook else 965e1f3808eSpbrook res = 1ll << 50; 966e1f3808eSpbrook } 967e1f3808eSpbrook } 968e1f3808eSpbrook return res; 969e1f3808eSpbrook } 970e1f3808eSpbrook 9712b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) 972e1f3808eSpbrook { 973e1f3808eSpbrook uint64_t product; 974e1f3808eSpbrook 975e1f3808eSpbrook product = (uint64_t)op1 * op2; 976e1f3808eSpbrook if (product & (0xffffffull << 40)) { 977e1f3808eSpbrook env->macsr |= MACSR_V; 978e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 979e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 980e1f3808eSpbrook product = 1ll << 50; 981e1f3808eSpbrook } else { 982e1f3808eSpbrook product &= ((1ull << 40) - 1); 983e1f3808eSpbrook } 984e1f3808eSpbrook } 985e1f3808eSpbrook return product; 986e1f3808eSpbrook } 987e1f3808eSpbrook 9882b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) 989e1f3808eSpbrook { 990e1f3808eSpbrook uint64_t product; 991e1f3808eSpbrook uint32_t remainder; 992e1f3808eSpbrook 993e1f3808eSpbrook product = (uint64_t)op1 * op2; 994e1f3808eSpbrook if (env->macsr & MACSR_RT) { 995e1f3808eSpbrook remainder = product & 0xffffff; 996e1f3808eSpbrook product >>= 24; 997e1f3808eSpbrook if (remainder > 0x800000) 998e1f3808eSpbrook product++; 999e1f3808eSpbrook else if (remainder == 0x800000) 1000e1f3808eSpbrook product += (product & 1); 1001e1f3808eSpbrook } else { 1002e1f3808eSpbrook product >>= 24; 1003e1f3808eSpbrook } 1004e1f3808eSpbrook return product; 1005e1f3808eSpbrook } 1006e1f3808eSpbrook 10072b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc) 1008e1f3808eSpbrook { 1009e1f3808eSpbrook int64_t tmp; 1010e1f3808eSpbrook int64_t result; 1011e1f3808eSpbrook tmp = env->macc[acc]; 1012e1f3808eSpbrook result = ((tmp << 16) >> 16); 1013e1f3808eSpbrook if (result != tmp) { 1014e1f3808eSpbrook env->macsr |= MACSR_V; 1015e1f3808eSpbrook } 1016e1f3808eSpbrook if (env->macsr & MACSR_V) { 1017e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1018e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1019a1c7273bSStefan Weil /* The result is saturated to 32 bits, despite overflow occurring 1020e1f3808eSpbrook at 48 bits. Seems weird, but that's what the hardware docs 1021e1f3808eSpbrook say. */ 1022e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffff; 1023e1f3808eSpbrook } 1024e1f3808eSpbrook } 1025e1f3808eSpbrook env->macc[acc] = result; 1026e1f3808eSpbrook } 1027e1f3808eSpbrook 10282b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) 1029e1f3808eSpbrook { 1030e1f3808eSpbrook uint64_t val; 1031e1f3808eSpbrook 1032e1f3808eSpbrook val = env->macc[acc]; 1033e1f3808eSpbrook if (val & (0xffffull << 48)) { 1034e1f3808eSpbrook env->macsr |= MACSR_V; 1035e1f3808eSpbrook } 1036e1f3808eSpbrook if (env->macsr & MACSR_V) { 1037e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1038e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1039e1f3808eSpbrook if (val > (1ull << 53)) 1040e1f3808eSpbrook val = 0; 1041e1f3808eSpbrook else 1042e1f3808eSpbrook val = (1ull << 48) - 1; 1043e1f3808eSpbrook } else { 1044e1f3808eSpbrook val &= ((1ull << 48) - 1); 1045e1f3808eSpbrook } 1046e1f3808eSpbrook } 1047e1f3808eSpbrook env->macc[acc] = val; 1048e1f3808eSpbrook } 1049e1f3808eSpbrook 10502b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) 1051e1f3808eSpbrook { 1052e1f3808eSpbrook int64_t sum; 1053e1f3808eSpbrook int64_t result; 1054e1f3808eSpbrook 1055e1f3808eSpbrook sum = env->macc[acc]; 1056e1f3808eSpbrook result = (sum << 16) >> 16; 1057e1f3808eSpbrook if (result != sum) { 1058e1f3808eSpbrook env->macsr |= MACSR_V; 1059e1f3808eSpbrook } 1060e1f3808eSpbrook if (env->macsr & MACSR_V) { 1061e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 1062e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1063e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffffffffll; 1064e1f3808eSpbrook } 1065e1f3808eSpbrook } 1066e1f3808eSpbrook env->macc[acc] = result; 1067e1f3808eSpbrook } 1068e1f3808eSpbrook 10692b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) 1070e1f3808eSpbrook { 1071e1f3808eSpbrook uint64_t val; 1072e1f3808eSpbrook val = env->macc[acc]; 1073c4162574SBlue Swirl if (val == 0) { 1074e1f3808eSpbrook env->macsr |= MACSR_Z; 1075c4162574SBlue Swirl } else if (val & (1ull << 47)) { 1076e1f3808eSpbrook env->macsr |= MACSR_N; 1077c4162574SBlue Swirl } 1078e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << acc)) { 1079e1f3808eSpbrook env->macsr |= MACSR_V; 1080e1f3808eSpbrook } 1081e1f3808eSpbrook if (env->macsr & MACSR_FI) { 1082e1f3808eSpbrook val = ((int64_t)val) >> 40; 1083e1f3808eSpbrook if (val != 0 && val != -1) 1084e1f3808eSpbrook env->macsr |= MACSR_EV; 1085e1f3808eSpbrook } else if (env->macsr & MACSR_SU) { 1086e1f3808eSpbrook val = ((int64_t)val) >> 32; 1087e1f3808eSpbrook if (val != 0 && val != -1) 1088e1f3808eSpbrook env->macsr |= MACSR_EV; 1089e1f3808eSpbrook } else { 1090e1f3808eSpbrook if ((val >> 32) != 0) 1091e1f3808eSpbrook env->macsr |= MACSR_EV; 1092e1f3808eSpbrook } 1093e1f3808eSpbrook } 1094e1f3808eSpbrook 1095db3d7945SLaurent Vivier #define EXTSIGN(val, index) ( \ 1096db3d7945SLaurent Vivier (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ 1097db3d7945SLaurent Vivier ) 1098620c6cf6SRichard Henderson 1099620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) { \ 1100620c6cf6SRichard Henderson switch (op) { \ 1101620c6cf6SRichard Henderson case CC_OP_FLAGS: \ 1102620c6cf6SRichard Henderson /* Everything in place. */ \ 1103620c6cf6SRichard Henderson break; \ 1104db3d7945SLaurent Vivier case CC_OP_ADDB: \ 1105db3d7945SLaurent Vivier case CC_OP_ADDW: \ 1106db3d7945SLaurent Vivier case CC_OP_ADDL: \ 1107620c6cf6SRichard Henderson res = n; \ 1108620c6cf6SRichard Henderson src2 = v; \ 1109db3d7945SLaurent Vivier src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ 1110620c6cf6SRichard Henderson c = x; \ 1111620c6cf6SRichard Henderson z = n; \ 1112620c6cf6SRichard Henderson v = (res ^ src1) & ~(src1 ^ src2); \ 1113620c6cf6SRichard Henderson break; \ 1114db3d7945SLaurent Vivier case CC_OP_SUBB: \ 1115db3d7945SLaurent Vivier case CC_OP_SUBW: \ 1116db3d7945SLaurent Vivier case CC_OP_SUBL: \ 1117620c6cf6SRichard Henderson res = n; \ 1118620c6cf6SRichard Henderson src2 = v; \ 1119db3d7945SLaurent Vivier src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ 1120620c6cf6SRichard Henderson c = x; \ 1121620c6cf6SRichard Henderson z = n; \ 1122620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 1123620c6cf6SRichard Henderson break; \ 1124db3d7945SLaurent Vivier case CC_OP_CMPB: \ 1125db3d7945SLaurent Vivier case CC_OP_CMPW: \ 1126db3d7945SLaurent Vivier case CC_OP_CMPL: \ 1127620c6cf6SRichard Henderson src1 = n; \ 1128620c6cf6SRichard Henderson src2 = v; \ 1129db3d7945SLaurent Vivier res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ 1130620c6cf6SRichard Henderson n = res; \ 1131620c6cf6SRichard Henderson z = res; \ 1132620c6cf6SRichard Henderson c = src1 < src2; \ 1133620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 1134620c6cf6SRichard Henderson break; \ 1135620c6cf6SRichard Henderson case CC_OP_LOGIC: \ 1136620c6cf6SRichard Henderson c = v = 0; \ 1137620c6cf6SRichard Henderson z = n; \ 1138620c6cf6SRichard Henderson break; \ 1139620c6cf6SRichard Henderson default: \ 1140620c6cf6SRichard Henderson cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \ 1141620c6cf6SRichard Henderson } \ 1142620c6cf6SRichard Henderson } while (0) 1143620c6cf6SRichard Henderson 1144620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env) 1145e1f3808eSpbrook { 1146620c6cf6SRichard Henderson uint32_t x, c, n, z, v; 1147620c6cf6SRichard Henderson uint32_t res, src1, src2; 1148620c6cf6SRichard Henderson 1149620c6cf6SRichard Henderson x = env->cc_x; 1150620c6cf6SRichard Henderson n = env->cc_n; 1151620c6cf6SRichard Henderson z = env->cc_z; 1152620c6cf6SRichard Henderson v = env->cc_v; 1153db3d7945SLaurent Vivier c = env->cc_c; 1154620c6cf6SRichard Henderson 1155620c6cf6SRichard Henderson COMPUTE_CCR(env->cc_op, x, n, z, v, c); 1156620c6cf6SRichard Henderson 1157620c6cf6SRichard Henderson n = n >> 31; 1158620c6cf6SRichard Henderson z = (z == 0); 1159db3d7945SLaurent Vivier v = v >> 31; 1160620c6cf6SRichard Henderson 1161620c6cf6SRichard Henderson return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; 1162620c6cf6SRichard Henderson } 1163620c6cf6SRichard Henderson 1164620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env) 1165620c6cf6SRichard Henderson { 1166620c6cf6SRichard Henderson return cpu_m68k_get_ccr(env); 1167620c6cf6SRichard Henderson } 1168620c6cf6SRichard Henderson 1169620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) 1170620c6cf6SRichard Henderson { 1171620c6cf6SRichard Henderson env->cc_x = (ccr & CCF_X ? 1 : 0); 1172620c6cf6SRichard Henderson env->cc_n = (ccr & CCF_N ? -1 : 0); 1173620c6cf6SRichard Henderson env->cc_z = (ccr & CCF_Z ? 0 : 1); 1174620c6cf6SRichard Henderson env->cc_v = (ccr & CCF_V ? -1 : 0); 1175620c6cf6SRichard Henderson env->cc_c = (ccr & CCF_C ? 1 : 0); 1176620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 1177620c6cf6SRichard Henderson } 1178620c6cf6SRichard Henderson 1179620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) 1180620c6cf6SRichard Henderson { 1181620c6cf6SRichard Henderson cpu_m68k_set_ccr(env, ccr); 1182620c6cf6SRichard Henderson } 1183620c6cf6SRichard Henderson 1184620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) 1185620c6cf6SRichard Henderson { 1186620c6cf6SRichard Henderson uint32_t res, src1, src2; 1187620c6cf6SRichard Henderson 1188620c6cf6SRichard Henderson COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); 1189620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 1190e1f3808eSpbrook } 1191e1f3808eSpbrook 11922b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) 1193e1f3808eSpbrook { 1194e1f3808eSpbrook int rem; 1195e1f3808eSpbrook uint32_t result; 1196e1f3808eSpbrook 1197e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1198e1f3808eSpbrook /* 16-bit rounding. */ 1199e1f3808eSpbrook rem = val & 0xffffff; 1200e1f3808eSpbrook val = (val >> 24) & 0xffffu; 1201e1f3808eSpbrook if (rem > 0x800000) 1202e1f3808eSpbrook val++; 1203e1f3808eSpbrook else if (rem == 0x800000) 1204e1f3808eSpbrook val += (val & 1); 1205e1f3808eSpbrook } else if (env->macsr & MACSR_RT) { 1206e1f3808eSpbrook /* 32-bit rounding. */ 1207e1f3808eSpbrook rem = val & 0xff; 1208e1f3808eSpbrook val >>= 8; 1209e1f3808eSpbrook if (rem > 0x80) 1210e1f3808eSpbrook val++; 1211e1f3808eSpbrook else if (rem == 0x80) 1212e1f3808eSpbrook val += (val & 1); 1213e1f3808eSpbrook } else { 1214e1f3808eSpbrook /* No rounding. */ 1215e1f3808eSpbrook val >>= 8; 1216e1f3808eSpbrook } 1217e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 1218e1f3808eSpbrook /* Saturate. */ 1219e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1220e1f3808eSpbrook if (val != (uint16_t) val) { 1221e1f3808eSpbrook result = ((val >> 63) ^ 0x7fff) & 0xffff; 1222e1f3808eSpbrook } else { 1223e1f3808eSpbrook result = val & 0xffff; 1224e1f3808eSpbrook } 1225e1f3808eSpbrook } else { 1226e1f3808eSpbrook if (val != (uint32_t)val) { 1227e1f3808eSpbrook result = ((uint32_t)(val >> 63) & 0x7fffffff); 1228e1f3808eSpbrook } else { 1229e1f3808eSpbrook result = (uint32_t)val; 1230e1f3808eSpbrook } 1231e1f3808eSpbrook } 1232e1f3808eSpbrook } else { 1233e1f3808eSpbrook /* No saturation. */ 1234e1f3808eSpbrook if (env->macsr & MACSR_SU) { 1235e1f3808eSpbrook result = val & 0xffff; 1236e1f3808eSpbrook } else { 1237e1f3808eSpbrook result = (uint32_t)val; 1238e1f3808eSpbrook } 1239e1f3808eSpbrook } 1240e1f3808eSpbrook return result; 1241e1f3808eSpbrook } 1242e1f3808eSpbrook 1243e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val) 1244e1f3808eSpbrook { 1245e1f3808eSpbrook if (val == (int32_t)val) { 1246e1f3808eSpbrook return (int32_t)val; 1247e1f3808eSpbrook } else { 1248e1f3808eSpbrook return (val >> 61) ^ ~SIGNBIT; 1249e1f3808eSpbrook } 1250e1f3808eSpbrook } 1251e1f3808eSpbrook 1252e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val) 1253e1f3808eSpbrook { 1254e1f3808eSpbrook if ((val >> 32) == 0) { 1255e1f3808eSpbrook return (uint32_t)val; 1256e1f3808eSpbrook } else { 1257e1f3808eSpbrook return 0xffffffffu; 1258e1f3808eSpbrook } 1259e1f3808eSpbrook } 1260e1f3808eSpbrook 12612b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) 1262e1f3808eSpbrook { 1263e1f3808eSpbrook uint32_t val; 1264e1f3808eSpbrook val = env->macc[acc] & 0x00ff; 12655ce747cfSPaolo Bonzini val |= (env->macc[acc] >> 32) & 0xff00; 1266e1f3808eSpbrook val |= (env->macc[acc + 1] << 16) & 0x00ff0000; 1267e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xff000000; 1268e1f3808eSpbrook return val; 1269e1f3808eSpbrook } 1270e1f3808eSpbrook 12712b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) 1272e1f3808eSpbrook { 1273e1f3808eSpbrook uint32_t val; 1274e1f3808eSpbrook val = (env->macc[acc] >> 32) & 0xffff; 1275e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xffff0000; 1276e1f3808eSpbrook return val; 1277e1f3808eSpbrook } 1278e1f3808eSpbrook 12792b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) 1280e1f3808eSpbrook { 1281e1f3808eSpbrook int64_t res; 1282e1f3808eSpbrook int32_t tmp; 1283e1f3808eSpbrook res = env->macc[acc] & 0xffffffff00ull; 1284e1f3808eSpbrook tmp = (int16_t)(val & 0xff00); 1285e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1286e1f3808eSpbrook res |= val & 0xff; 1287e1f3808eSpbrook env->macc[acc] = res; 1288e1f3808eSpbrook res = env->macc[acc + 1] & 0xffffffff00ull; 1289e1f3808eSpbrook tmp = (val & 0xff000000); 1290e1f3808eSpbrook res |= ((int64_t)tmp) << 16; 1291e1f3808eSpbrook res |= (val >> 16) & 0xff; 1292e1f3808eSpbrook env->macc[acc + 1] = res; 1293e1f3808eSpbrook } 1294e1f3808eSpbrook 12952b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) 1296e1f3808eSpbrook { 1297e1f3808eSpbrook int64_t res; 1298e1f3808eSpbrook int32_t tmp; 1299e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1300e1f3808eSpbrook tmp = (int16_t)val; 1301e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1302e1f3808eSpbrook env->macc[acc] = res; 1303e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1304e1f3808eSpbrook tmp = val & 0xffff0000; 1305e1f3808eSpbrook res |= (int64_t)tmp << 16; 1306e1f3808eSpbrook env->macc[acc + 1] = res; 1307e1f3808eSpbrook } 1308e1f3808eSpbrook 13092b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) 1310e1f3808eSpbrook { 1311e1f3808eSpbrook uint64_t res; 1312e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1313e1f3808eSpbrook res |= ((uint64_t)(val & 0xffff)) << 32; 1314e1f3808eSpbrook env->macc[acc] = res; 1315e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1316e1f3808eSpbrook res |= (uint64_t)(val & 0xffff0000) << 16; 1317e1f3808eSpbrook env->macc[acc + 1] = res; 1318e1f3808eSpbrook } 13190bdb2b3bSLaurent Vivier 13200bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU) 1321e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read) 1322e55886c3SLaurent Vivier { 1323e55886c3SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 1324e55886c3SLaurent Vivier CPUState *cs = CPU(cpu); 1325e55886c3SLaurent Vivier hwaddr physical; 1326e55886c3SLaurent Vivier int access_type; 1327e55886c3SLaurent Vivier int prot; 1328e55886c3SLaurent Vivier int ret; 1329e55886c3SLaurent Vivier target_ulong page_size; 1330e55886c3SLaurent Vivier 1331e55886c3SLaurent Vivier access_type = ACCESS_PTEST; 1332e55886c3SLaurent Vivier if (env->dfc & 4) { 1333e55886c3SLaurent Vivier access_type |= ACCESS_SUPER; 1334e55886c3SLaurent Vivier } 1335e55886c3SLaurent Vivier if ((env->dfc & 3) == 2) { 1336e55886c3SLaurent Vivier access_type |= ACCESS_CODE; 1337e55886c3SLaurent Vivier } 1338e55886c3SLaurent Vivier if (!is_read) { 1339e55886c3SLaurent Vivier access_type |= ACCESS_STORE; 1340e55886c3SLaurent Vivier } 1341e55886c3SLaurent Vivier 1342e55886c3SLaurent Vivier env->mmu.mmusr = 0; 1343e55886c3SLaurent Vivier env->mmu.ssw = 0; 1344e55886c3SLaurent Vivier ret = get_physical_address(env, &physical, &prot, addr, 1345e55886c3SLaurent Vivier access_type, &page_size); 1346e55886c3SLaurent Vivier if (ret == 0) { 1347e55886c3SLaurent Vivier addr &= TARGET_PAGE_MASK; 1348e55886c3SLaurent Vivier physical += addr & (page_size - 1); 1349e55886c3SLaurent Vivier tlb_set_page(cs, addr, physical, 1350e55886c3SLaurent Vivier prot, access_type & ACCESS_SUPER ? 1351e55886c3SLaurent Vivier MMU_KERNEL_IDX : MMU_USER_IDX, page_size); 1352e55886c3SLaurent Vivier } 1353e55886c3SLaurent Vivier } 1354e55886c3SLaurent Vivier 1355e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode) 1356e55886c3SLaurent Vivier { 1357e55886c3SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 1358e55886c3SLaurent Vivier 1359e55886c3SLaurent Vivier switch (opmode) { 1360e55886c3SLaurent Vivier case 0: /* Flush page entry if not global */ 1361e55886c3SLaurent Vivier case 1: /* Flush page entry */ 1362e55886c3SLaurent Vivier tlb_flush_page(CPU(cpu), addr); 1363e55886c3SLaurent Vivier break; 1364e55886c3SLaurent Vivier case 2: /* Flush all except global entries */ 1365e55886c3SLaurent Vivier tlb_flush(CPU(cpu)); 1366e55886c3SLaurent Vivier break; 1367e55886c3SLaurent Vivier case 3: /* Flush all entries */ 1368e55886c3SLaurent Vivier tlb_flush(CPU(cpu)); 1369e55886c3SLaurent Vivier break; 1370e55886c3SLaurent Vivier } 1371e55886c3SLaurent Vivier } 1372e55886c3SLaurent Vivier 13730bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env) 13740bdb2b3bSLaurent Vivier { 13750bdb2b3bSLaurent Vivier /* FIXME: reset all except CPU */ 13760bdb2b3bSLaurent Vivier } 13770bdb2b3bSLaurent Vivier #endif 1378