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" 27e1f3808eSpbrook 28e1f3808eSpbrook #define SIGNBIT (1u << 31) 29e1f3808eSpbrook 3011150915SAndreas Färber /* Sort alphabetically, except for "any". */ 3111150915SAndreas Färber static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) 3211150915SAndreas Färber { 3311150915SAndreas Färber ObjectClass *class_a = (ObjectClass *)a; 3411150915SAndreas Färber ObjectClass *class_b = (ObjectClass *)b; 3511150915SAndreas Färber const char *name_a, *name_b; 36aaed909aSbellard 3711150915SAndreas Färber name_a = object_class_get_name(class_a); 3811150915SAndreas Färber name_b = object_class_get_name(class_b); 397a9f812bSAndreas Färber if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) { 4011150915SAndreas Färber return 1; 417a9f812bSAndreas Färber } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) { 4211150915SAndreas Färber return -1; 4311150915SAndreas Färber } else { 4411150915SAndreas Färber return strcasecmp(name_a, name_b); 4511150915SAndreas Färber } 4611150915SAndreas Färber } 470402f767Spbrook 4811150915SAndreas Färber static void m68k_cpu_list_entry(gpointer data, gpointer user_data) 4911150915SAndreas Färber { 5011150915SAndreas Färber ObjectClass *c = data; 5192a31361SAndreas Färber CPUListState *s = user_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)); 5711150915SAndreas Färber (*s->cpu_fprintf)(s->file, "%s\n", 587a9f812bSAndreas Färber name); 597a9f812bSAndreas Färber g_free(name); 6011150915SAndreas Färber } 610402f767Spbrook 629a78eeadSStefan Weil void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) 63009a4356SLaurent Vivier { 6492a31361SAndreas Färber CPUListState s = { 6511150915SAndreas Färber .file = f, 6611150915SAndreas Färber .cpu_fprintf = cpu_fprintf, 6711150915SAndreas Färber }; 6811150915SAndreas Färber GSList *list; 69009a4356SLaurent Vivier 7011150915SAndreas Färber list = object_class_get_list(TYPE_M68K_CPU, false); 7111150915SAndreas Färber list = g_slist_sort(list, m68k_cpu_list_compare); 7211150915SAndreas Färber g_slist_foreach(list, m68k_cpu_list_entry, &s); 7311150915SAndreas Färber g_slist_free(list); 74009a4356SLaurent Vivier } 75009a4356SLaurent Vivier 76f83311e4SLaurent Vivier static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 7756aebc89Spbrook { 7856aebc89Spbrook if (n < 8) { 79f83311e4SLaurent Vivier float_status s; 80f83311e4SLaurent Vivier stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); 8156aebc89Spbrook return 8; 8256aebc89Spbrook } 83ba624944SLaurent Vivier switch (n) { 84ba624944SLaurent Vivier case 8: /* fpcontrol */ 85ba624944SLaurent Vivier stl_be_p(mem_buf, env->fpcr); 86ba624944SLaurent Vivier return 4; 87ba624944SLaurent Vivier case 9: /* fpstatus */ 88ba624944SLaurent Vivier stl_be_p(mem_buf, env->fpsr); 89ba624944SLaurent Vivier return 4; 90ba624944SLaurent Vivier case 10: /* fpiar, not implemented */ 9156aebc89Spbrook memset(mem_buf, 0, 4); 9256aebc89Spbrook return 4; 9356aebc89Spbrook } 9456aebc89Spbrook return 0; 9556aebc89Spbrook } 9656aebc89Spbrook 97f83311e4SLaurent Vivier static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 9856aebc89Spbrook { 9956aebc89Spbrook if (n < 8) { 100f83311e4SLaurent Vivier float_status s; 101f83311e4SLaurent Vivier env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s); 10256aebc89Spbrook return 8; 10356aebc89Spbrook } 104ba624944SLaurent Vivier switch (n) { 105ba624944SLaurent Vivier case 8: /* fpcontrol */ 106ba624944SLaurent Vivier cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); 107ba624944SLaurent Vivier return 4; 108ba624944SLaurent Vivier case 9: /* fpstatus */ 109ba624944SLaurent Vivier env->fpsr = ldl_p(mem_buf); 110ba624944SLaurent Vivier return 4; 111ba624944SLaurent Vivier case 10: /* fpiar, not implemented */ 11256aebc89Spbrook return 4; 11356aebc89Spbrook } 11456aebc89Spbrook return 0; 11556aebc89Spbrook } 11656aebc89Spbrook 1175a4526b2SLaurent Vivier static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 1185a4526b2SLaurent Vivier { 1195a4526b2SLaurent Vivier if (n < 8) { 1205a4526b2SLaurent Vivier stw_be_p(mem_buf, env->fregs[n].l.upper); 1215a4526b2SLaurent Vivier memset(mem_buf + 2, 0, 2); 1225a4526b2SLaurent Vivier stq_be_p(mem_buf + 4, env->fregs[n].l.lower); 1235a4526b2SLaurent Vivier return 12; 1245a4526b2SLaurent Vivier } 1255a4526b2SLaurent Vivier switch (n) { 1265a4526b2SLaurent Vivier case 8: /* fpcontrol */ 1275a4526b2SLaurent Vivier stl_be_p(mem_buf, env->fpcr); 1285a4526b2SLaurent Vivier return 4; 1295a4526b2SLaurent Vivier case 9: /* fpstatus */ 1305a4526b2SLaurent Vivier stl_be_p(mem_buf, env->fpsr); 1315a4526b2SLaurent Vivier return 4; 1325a4526b2SLaurent Vivier case 10: /* fpiar, not implemented */ 1335a4526b2SLaurent Vivier memset(mem_buf, 0, 4); 1345a4526b2SLaurent Vivier return 4; 1355a4526b2SLaurent Vivier } 1365a4526b2SLaurent Vivier return 0; 1375a4526b2SLaurent Vivier } 1385a4526b2SLaurent Vivier 1395a4526b2SLaurent Vivier static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 1405a4526b2SLaurent Vivier { 1415a4526b2SLaurent Vivier if (n < 8) { 1425a4526b2SLaurent Vivier env->fregs[n].l.upper = lduw_be_p(mem_buf); 1435a4526b2SLaurent Vivier env->fregs[n].l.lower = ldq_be_p(mem_buf + 4); 1445a4526b2SLaurent Vivier return 12; 1455a4526b2SLaurent Vivier } 1465a4526b2SLaurent Vivier switch (n) { 1475a4526b2SLaurent Vivier case 8: /* fpcontrol */ 148ba624944SLaurent Vivier cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); 1495a4526b2SLaurent Vivier return 4; 1505a4526b2SLaurent Vivier case 9: /* fpstatus */ 1515a4526b2SLaurent Vivier env->fpsr = ldl_p(mem_buf); 1525a4526b2SLaurent Vivier return 4; 1535a4526b2SLaurent Vivier case 10: /* fpiar, not implemented */ 1545a4526b2SLaurent Vivier return 4; 1555a4526b2SLaurent Vivier } 1565a4526b2SLaurent Vivier return 0; 1575a4526b2SLaurent Vivier } 1585a4526b2SLaurent Vivier 1596d1bbc62SAndreas Färber void m68k_cpu_init_gdb(M68kCPU *cpu) 1606d1bbc62SAndreas Färber { 16122169d41SAndreas Färber CPUState *cs = CPU(cpu); 1626d1bbc62SAndreas Färber CPUM68KState *env = &cpu->env; 1636d1bbc62SAndreas Färber 16411150915SAndreas Färber if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { 165f83311e4SLaurent Vivier gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg, 16611150915SAndreas Färber 11, "cf-fp.xml", 18); 1675a4526b2SLaurent Vivier } else if (m68k_feature(env, M68K_FEATURE_FPU)) { 1685a4526b2SLaurent Vivier gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg, 1695a4526b2SLaurent Vivier m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18); 170aaed909aSbellard } 17111150915SAndreas Färber /* TODO: Add [E]MAC registers. */ 172aaed909aSbellard } 173aaed909aSbellard 1746e22b28eSLaurent Vivier void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) 1750633879fSpbrook { 176a47dddd7SAndreas Färber M68kCPU *cpu = m68k_env_get_cpu(env); 177a47dddd7SAndreas Färber 1780633879fSpbrook switch (reg) { 1796e22b28eSLaurent Vivier case M68K_CR_CACR: 18020dcee94Spbrook env->cacr = val; 18120dcee94Spbrook m68k_switch_sp(env); 18220dcee94Spbrook break; 1836e22b28eSLaurent Vivier case M68K_CR_ACR0: 1846e22b28eSLaurent Vivier case M68K_CR_ACR1: 1856e22b28eSLaurent Vivier case M68K_CR_ACR2: 1866e22b28eSLaurent Vivier case M68K_CR_ACR3: 18720dcee94Spbrook /* TODO: Implement Access Control Registers. */ 1880633879fSpbrook break; 1896e22b28eSLaurent Vivier case M68K_CR_VBR: 1900633879fSpbrook env->vbr = val; 1910633879fSpbrook break; 1920633879fSpbrook /* TODO: Implement control registers. */ 1930633879fSpbrook default: 1946e22b28eSLaurent Vivier cpu_abort(CPU(cpu), 1956e22b28eSLaurent Vivier "Unimplemented control register write 0x%x = 0x%x\n", 1966e22b28eSLaurent Vivier reg, val); 1976e22b28eSLaurent Vivier } 1986e22b28eSLaurent Vivier } 1996e22b28eSLaurent Vivier 2006e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) 2016e22b28eSLaurent Vivier { 2026e22b28eSLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 2036e22b28eSLaurent Vivier 2046e22b28eSLaurent Vivier switch (reg) { 2056e22b28eSLaurent Vivier /* MC680[1234]0 */ 206*5fa9f1f2SLaurent Vivier case M68K_CR_SFC: 207*5fa9f1f2SLaurent Vivier env->sfc = val & 7; 208*5fa9f1f2SLaurent Vivier return; 209*5fa9f1f2SLaurent Vivier case M68K_CR_DFC: 210*5fa9f1f2SLaurent Vivier env->dfc = val & 7; 211*5fa9f1f2SLaurent Vivier return; 2126e22b28eSLaurent Vivier case M68K_CR_VBR: 2136e22b28eSLaurent Vivier env->vbr = val; 2146e22b28eSLaurent Vivier return; 2156e22b28eSLaurent Vivier /* MC680[234]0 */ 2166e22b28eSLaurent Vivier case M68K_CR_CACR: 2176e22b28eSLaurent Vivier env->cacr = val; 2186e22b28eSLaurent Vivier m68k_switch_sp(env); 2196e22b28eSLaurent Vivier return; 2206e22b28eSLaurent Vivier /* MC680[34]0 */ 22188b2fef6SLaurent Vivier case M68K_CR_TC: 22288b2fef6SLaurent Vivier env->mmu.tcr = val; 22388b2fef6SLaurent Vivier return; 22488b2fef6SLaurent Vivier case M68K_CR_SRP: 22588b2fef6SLaurent Vivier env->mmu.srp = val; 22688b2fef6SLaurent Vivier return; 22788b2fef6SLaurent Vivier case M68K_CR_URP: 22888b2fef6SLaurent Vivier env->mmu.urp = val; 22988b2fef6SLaurent Vivier return; 2306e22b28eSLaurent Vivier case M68K_CR_USP: 2316e22b28eSLaurent Vivier env->sp[M68K_USP] = val; 2326e22b28eSLaurent Vivier return; 2336e22b28eSLaurent Vivier case M68K_CR_MSP: 2346e22b28eSLaurent Vivier env->sp[M68K_SSP] = val; 2356e22b28eSLaurent Vivier return; 2366e22b28eSLaurent Vivier case M68K_CR_ISP: 2376e22b28eSLaurent Vivier env->sp[M68K_ISP] = val; 2386e22b28eSLaurent Vivier return; 239c05c73b0SLaurent Vivier /* MC68040/MC68LC040 */ 240c05c73b0SLaurent Vivier case M68K_CR_ITT0: 241c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR0] = val; 242c05c73b0SLaurent Vivier return; 243c05c73b0SLaurent Vivier case M68K_CR_ITT1: 244c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR1] = val; 245c05c73b0SLaurent Vivier return; 246c05c73b0SLaurent Vivier case M68K_CR_DTT0: 247c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR0] = val; 248c05c73b0SLaurent Vivier return; 249c05c73b0SLaurent Vivier case M68K_CR_DTT1: 250c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR1] = val; 251c05c73b0SLaurent Vivier return; 2526e22b28eSLaurent Vivier } 253a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", 2540633879fSpbrook reg, val); 2550633879fSpbrook } 2566e22b28eSLaurent Vivier 2576e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) 2586e22b28eSLaurent Vivier { 2596e22b28eSLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 2606e22b28eSLaurent Vivier 2616e22b28eSLaurent Vivier switch (reg) { 2626e22b28eSLaurent Vivier /* MC680[1234]0 */ 263*5fa9f1f2SLaurent Vivier case M68K_CR_SFC: 264*5fa9f1f2SLaurent Vivier return env->sfc; 265*5fa9f1f2SLaurent Vivier case M68K_CR_DFC: 266*5fa9f1f2SLaurent Vivier return env->dfc; 2676e22b28eSLaurent Vivier case M68K_CR_VBR: 2686e22b28eSLaurent Vivier return env->vbr; 2696e22b28eSLaurent Vivier /* MC680[234]0 */ 2706e22b28eSLaurent Vivier case M68K_CR_CACR: 2716e22b28eSLaurent Vivier return env->cacr; 2726e22b28eSLaurent Vivier /* MC680[34]0 */ 27388b2fef6SLaurent Vivier case M68K_CR_TC: 27488b2fef6SLaurent Vivier return env->mmu.tcr; 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 372c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr, 373c05c73b0SLaurent Vivier int access_type) 374c05c73b0SLaurent Vivier { 375c05c73b0SLaurent Vivier uint32_t base, mask; 376c05c73b0SLaurent Vivier 377c05c73b0SLaurent Vivier /* check if transparent translation is enabled */ 378c05c73b0SLaurent Vivier if ((ttr & M68K_TTR_ENABLED) == 0) { 379c05c73b0SLaurent Vivier return 0; 380c05c73b0SLaurent Vivier } 381c05c73b0SLaurent Vivier 382c05c73b0SLaurent Vivier /* check mode access */ 383c05c73b0SLaurent Vivier switch (ttr & M68K_TTR_SFIELD) { 384c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_USER: 385c05c73b0SLaurent Vivier /* match only if user */ 386c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) != 0) { 387c05c73b0SLaurent Vivier return 0; 388c05c73b0SLaurent Vivier } 389c05c73b0SLaurent Vivier break; 390c05c73b0SLaurent Vivier case M68K_TTR_SFIELD_SUPER: 391c05c73b0SLaurent Vivier /* match only if supervisor */ 392c05c73b0SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 393c05c73b0SLaurent Vivier return 0; 394c05c73b0SLaurent Vivier } 395c05c73b0SLaurent Vivier break; 396c05c73b0SLaurent Vivier default: 397c05c73b0SLaurent Vivier /* all other values disable mode matching (FC2) */ 398c05c73b0SLaurent Vivier break; 399c05c73b0SLaurent Vivier } 400c05c73b0SLaurent Vivier 401c05c73b0SLaurent Vivier /* check address matching */ 402c05c73b0SLaurent Vivier 403c05c73b0SLaurent Vivier base = ttr & M68K_TTR_ADDR_BASE; 404c05c73b0SLaurent Vivier mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK; 405c05c73b0SLaurent Vivier mask <<= M68K_TTR_ADDR_MASK_SHIFT; 406c05c73b0SLaurent Vivier 407c05c73b0SLaurent Vivier if ((addr & mask) != (base & mask)) { 408c05c73b0SLaurent Vivier return 0; 409c05c73b0SLaurent Vivier } 410c05c73b0SLaurent Vivier 411c05c73b0SLaurent Vivier *prot = PAGE_READ | PAGE_EXEC; 412c05c73b0SLaurent Vivier if ((ttr & M68K_DESC_WRITEPROT) == 0) { 413c05c73b0SLaurent Vivier *prot |= PAGE_WRITE; 414c05c73b0SLaurent Vivier } 415c05c73b0SLaurent Vivier 416c05c73b0SLaurent Vivier return 1; 417c05c73b0SLaurent Vivier } 418c05c73b0SLaurent Vivier 41988b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical, 42088b2fef6SLaurent Vivier int *prot, target_ulong address, 42188b2fef6SLaurent Vivier int access_type, target_ulong *page_size) 42288b2fef6SLaurent Vivier { 42388b2fef6SLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 42488b2fef6SLaurent Vivier CPUState *cs = CPU(cpu); 42588b2fef6SLaurent Vivier uint32_t entry; 42688b2fef6SLaurent Vivier uint32_t next; 42788b2fef6SLaurent Vivier target_ulong page_mask; 42888b2fef6SLaurent Vivier bool debug = access_type & ACCESS_DEBUG; 42988b2fef6SLaurent Vivier int page_bits; 430c05c73b0SLaurent Vivier int i; 431c05c73b0SLaurent Vivier 432c05c73b0SLaurent Vivier /* Transparent Translation (physical = logical) */ 433c05c73b0SLaurent Vivier for (i = 0; i < M68K_MAX_TTR; i++) { 434c05c73b0SLaurent Vivier if (check_TTR(env->mmu.TTR(access_type, i), 435c05c73b0SLaurent Vivier prot, address, access_type)) { 436c05c73b0SLaurent Vivier *physical = address & TARGET_PAGE_MASK; 437c05c73b0SLaurent Vivier *page_size = TARGET_PAGE_SIZE; 438c05c73b0SLaurent Vivier return 0; 439c05c73b0SLaurent Vivier } 440c05c73b0SLaurent Vivier } 44188b2fef6SLaurent Vivier 44288b2fef6SLaurent Vivier /* Page Table Root Pointer */ 44388b2fef6SLaurent Vivier *prot = PAGE_READ | PAGE_WRITE; 44488b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 44588b2fef6SLaurent Vivier *prot |= PAGE_EXEC; 44688b2fef6SLaurent Vivier } 44788b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 44888b2fef6SLaurent Vivier next = env->mmu.srp; 44988b2fef6SLaurent Vivier } else { 45088b2fef6SLaurent Vivier next = env->mmu.urp; 45188b2fef6SLaurent Vivier } 45288b2fef6SLaurent Vivier 45388b2fef6SLaurent Vivier /* Root Index */ 45488b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address); 45588b2fef6SLaurent Vivier 45688b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 45788b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 45888b2fef6SLaurent Vivier return -1; 45988b2fef6SLaurent Vivier } 46088b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 46188b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 46288b2fef6SLaurent Vivier } 46388b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 46488b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 46588b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 46688b2fef6SLaurent Vivier return -1; 46788b2fef6SLaurent Vivier } 46888b2fef6SLaurent Vivier } 46988b2fef6SLaurent Vivier 47088b2fef6SLaurent Vivier /* Pointer Index */ 47188b2fef6SLaurent Vivier entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address); 47288b2fef6SLaurent Vivier 47388b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 47488b2fef6SLaurent Vivier if (!M68K_UDT_VALID(next)) { 47588b2fef6SLaurent Vivier return -1; 47688b2fef6SLaurent Vivier } 47788b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 47888b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 47988b2fef6SLaurent Vivier } 48088b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 48188b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 48288b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 48388b2fef6SLaurent Vivier return -1; 48488b2fef6SLaurent Vivier } 48588b2fef6SLaurent Vivier } 48688b2fef6SLaurent Vivier 48788b2fef6SLaurent Vivier /* Page Index */ 48888b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 48988b2fef6SLaurent Vivier entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address); 49088b2fef6SLaurent Vivier } else { 49188b2fef6SLaurent Vivier entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address); 49288b2fef6SLaurent Vivier } 49388b2fef6SLaurent Vivier 49488b2fef6SLaurent Vivier next = ldl_phys(cs->as, entry); 49588b2fef6SLaurent Vivier 49688b2fef6SLaurent Vivier if (!M68K_PDT_VALID(next)) { 49788b2fef6SLaurent Vivier return -1; 49888b2fef6SLaurent Vivier } 49988b2fef6SLaurent Vivier if (M68K_PDT_INDIRECT(next)) { 50088b2fef6SLaurent Vivier next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next)); 50188b2fef6SLaurent Vivier } 50288b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 50388b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 50488b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 50588b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 50688b2fef6SLaurent Vivier } 50788b2fef6SLaurent Vivier } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) != 50888b2fef6SLaurent Vivier (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) { 50988b2fef6SLaurent Vivier stl_phys(cs->as, entry, 51088b2fef6SLaurent Vivier next | (M68K_DESC_MODIFIED | M68K_DESC_USED)); 51188b2fef6SLaurent Vivier } 51288b2fef6SLaurent Vivier } else { 51388b2fef6SLaurent Vivier if (!(next & M68K_DESC_USED) && !debug) { 51488b2fef6SLaurent Vivier stl_phys(cs->as, entry, next | M68K_DESC_USED); 51588b2fef6SLaurent Vivier } 51688b2fef6SLaurent Vivier } 51788b2fef6SLaurent Vivier 51888b2fef6SLaurent Vivier if (env->mmu.tcr & M68K_TCR_PAGE_8K) { 51988b2fef6SLaurent Vivier page_bits = 13; 52088b2fef6SLaurent Vivier } else { 52188b2fef6SLaurent Vivier page_bits = 12; 52288b2fef6SLaurent Vivier } 52388b2fef6SLaurent Vivier *page_size = 1 << page_bits; 52488b2fef6SLaurent Vivier page_mask = ~(*page_size - 1); 52588b2fef6SLaurent Vivier *physical = next & page_mask; 52688b2fef6SLaurent Vivier 52788b2fef6SLaurent Vivier if (next & M68K_DESC_WRITEPROT) { 52888b2fef6SLaurent Vivier *prot &= ~PAGE_WRITE; 52988b2fef6SLaurent Vivier if (access_type & ACCESS_STORE) { 53088b2fef6SLaurent Vivier return -1; 53188b2fef6SLaurent Vivier } 53288b2fef6SLaurent Vivier } 53388b2fef6SLaurent Vivier if (next & M68K_DESC_SUPERONLY) { 53488b2fef6SLaurent Vivier if ((access_type & ACCESS_SUPER) == 0) { 53588b2fef6SLaurent Vivier return -1; 53688b2fef6SLaurent Vivier } 53788b2fef6SLaurent Vivier } 53888b2fef6SLaurent Vivier 53988b2fef6SLaurent Vivier return 0; 54088b2fef6SLaurent Vivier } 54188b2fef6SLaurent Vivier 54200b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 5434fcc562bSPaul Brook { 54488b2fef6SLaurent Vivier M68kCPU *cpu = M68K_CPU(cs); 54588b2fef6SLaurent Vivier CPUM68KState *env = &cpu->env; 54688b2fef6SLaurent Vivier hwaddr phys_addr; 54788b2fef6SLaurent Vivier int prot; 54888b2fef6SLaurent Vivier int access_type; 54988b2fef6SLaurent Vivier target_ulong page_size; 55088b2fef6SLaurent Vivier 55188b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 55288b2fef6SLaurent Vivier /* MMU disabled */ 5534fcc562bSPaul Brook return addr; 5544fcc562bSPaul Brook } 5554fcc562bSPaul Brook 55688b2fef6SLaurent Vivier access_type = ACCESS_DATA | ACCESS_DEBUG; 55788b2fef6SLaurent Vivier if (env->sr & SR_S) { 55888b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 55988b2fef6SLaurent Vivier } 56088b2fef6SLaurent Vivier if (get_physical_address(env, &phys_addr, &prot, 56188b2fef6SLaurent Vivier addr, access_type, &page_size) != 0) { 56288b2fef6SLaurent Vivier return -1; 56388b2fef6SLaurent Vivier } 56488b2fef6SLaurent Vivier return phys_addr; 56588b2fef6SLaurent Vivier } 56688b2fef6SLaurent Vivier 56798670d47SLaurent Vivier int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, 56897b348e7SBlue Swirl int mmu_idx) 5690633879fSpbrook { 57088b2fef6SLaurent Vivier M68kCPU *cpu = M68K_CPU(cs); 57188b2fef6SLaurent Vivier CPUM68KState *env = &cpu->env; 57288b2fef6SLaurent Vivier hwaddr physical; 5730633879fSpbrook int prot; 57488b2fef6SLaurent Vivier int access_type; 57588b2fef6SLaurent Vivier int ret; 57688b2fef6SLaurent Vivier target_ulong page_size; 5770633879fSpbrook 57888b2fef6SLaurent Vivier if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { 57988b2fef6SLaurent Vivier /* MMU disabled */ 58088b2fef6SLaurent Vivier tlb_set_page(cs, address & TARGET_PAGE_MASK, 58188b2fef6SLaurent Vivier address & TARGET_PAGE_MASK, 58288b2fef6SLaurent Vivier PAGE_READ | PAGE_WRITE | PAGE_EXEC, 58388b2fef6SLaurent Vivier mmu_idx, TARGET_PAGE_SIZE); 584d4c430a8SPaul Brook return 0; 5850633879fSpbrook } 5860633879fSpbrook 58788b2fef6SLaurent Vivier if (rw == 2) { 58888b2fef6SLaurent Vivier access_type = ACCESS_CODE; 58988b2fef6SLaurent Vivier rw = 0; 59088b2fef6SLaurent Vivier } else { 59188b2fef6SLaurent Vivier access_type = ACCESS_DATA; 59288b2fef6SLaurent Vivier if (rw) { 59388b2fef6SLaurent Vivier access_type |= ACCESS_STORE; 59488b2fef6SLaurent Vivier } 59588b2fef6SLaurent Vivier } 59688b2fef6SLaurent Vivier 59788b2fef6SLaurent Vivier if (mmu_idx != MMU_USER_IDX) { 59888b2fef6SLaurent Vivier access_type |= ACCESS_SUPER; 59988b2fef6SLaurent Vivier } 60088b2fef6SLaurent Vivier 60188b2fef6SLaurent Vivier ret = get_physical_address(&cpu->env, &physical, &prot, 60288b2fef6SLaurent Vivier address, access_type, &page_size); 60388b2fef6SLaurent Vivier if (ret == 0) { 60488b2fef6SLaurent Vivier address &= TARGET_PAGE_MASK; 60588b2fef6SLaurent Vivier physical += address & (page_size - 1); 60688b2fef6SLaurent Vivier tlb_set_page(cs, address, physical, 60788b2fef6SLaurent Vivier prot, mmu_idx, TARGET_PAGE_SIZE); 60888b2fef6SLaurent Vivier return 0; 60988b2fef6SLaurent Vivier } 61088b2fef6SLaurent Vivier /* page fault */ 61188b2fef6SLaurent Vivier env->mmu.ssw = M68K_ATC_040; 61288b2fef6SLaurent Vivier switch (size) { 61388b2fef6SLaurent Vivier case 1: 61488b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_BYTE; 61588b2fef6SLaurent Vivier break; 61688b2fef6SLaurent Vivier case 2: 61788b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_WORD; 61888b2fef6SLaurent Vivier break; 61988b2fef6SLaurent Vivier case 4: 62088b2fef6SLaurent Vivier env->mmu.ssw |= M68K_BA_SIZE_LONG; 62188b2fef6SLaurent Vivier break; 62288b2fef6SLaurent Vivier } 62388b2fef6SLaurent Vivier if (access_type & ACCESS_SUPER) { 62488b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_SUPER; 62588b2fef6SLaurent Vivier } 62688b2fef6SLaurent Vivier if (access_type & ACCESS_CODE) { 62788b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_CODE; 62888b2fef6SLaurent Vivier } else { 62988b2fef6SLaurent Vivier env->mmu.ssw |= M68K_TM_040_DATA; 63088b2fef6SLaurent Vivier } 63188b2fef6SLaurent Vivier if (!(access_type & ACCESS_STORE)) { 63288b2fef6SLaurent Vivier env->mmu.ssw |= M68K_RW_040; 63388b2fef6SLaurent Vivier } 63488b2fef6SLaurent Vivier env->mmu.ar = address; 63588b2fef6SLaurent Vivier cs->exception_index = EXCP_ACCESS; 63688b2fef6SLaurent Vivier return 1; 63788b2fef6SLaurent Vivier } 63888b2fef6SLaurent Vivier 6390633879fSpbrook /* Notify CPU of a pending interrupt. Prioritization and vectoring should 6400633879fSpbrook be handled by the interrupt controller. Real hardware only requests 6410633879fSpbrook the vector when the interrupt is acknowledged by the CPU. For 6420633879fSpbrook simplicitly we calculate it when the interrupt is signalled. */ 643cb3fb38eSAndreas Färber void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) 6440633879fSpbrook { 645d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 646cb3fb38eSAndreas Färber CPUM68KState *env = &cpu->env; 647cb3fb38eSAndreas Färber 6480633879fSpbrook env->pending_level = level; 6490633879fSpbrook env->pending_vector = vector; 650d8ed887bSAndreas Färber if (level) { 651c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 652d8ed887bSAndreas Färber } else { 653d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 654d8ed887bSAndreas Färber } 6550633879fSpbrook } 6560633879fSpbrook 6570633879fSpbrook #endif 658e1f3808eSpbrook 659e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x) 660e1f3808eSpbrook { 661e1f3808eSpbrook x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); 662e1f3808eSpbrook x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); 663e1f3808eSpbrook x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); 664e1f3808eSpbrook return bswap32(x); 665e1f3808eSpbrook } 666e1f3808eSpbrook 667e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x) 668e1f3808eSpbrook { 669e1f3808eSpbrook int n; 670e1f3808eSpbrook for (n = 32; x; n--) 671e1f3808eSpbrook x >>= 1; 672e1f3808eSpbrook return n; 673e1f3808eSpbrook } 674e1f3808eSpbrook 675620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v) 676e1f3808eSpbrook { 677e1f3808eSpbrook /* The result has the opposite sign to the original value. */ 678620c6cf6SRichard Henderson if ((int32_t)v < 0) { 679e1f3808eSpbrook val = (((int32_t)val) >> 31) ^ SIGNBIT; 680620c6cf6SRichard Henderson } 681e1f3808eSpbrook return val; 682e1f3808eSpbrook } 683e1f3808eSpbrook 684d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) 685e1f3808eSpbrook { 686d2f8fb8eSLaurent Vivier env->sr = sr & 0xffe0; 687d2f8fb8eSLaurent Vivier cpu_m68k_set_ccr(env, sr); 688e1f3808eSpbrook m68k_switch_sp(env); 689e1f3808eSpbrook } 690e1f3808eSpbrook 691d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val) 692d2f8fb8eSLaurent Vivier { 693d2f8fb8eSLaurent Vivier cpu_m68k_set_sr(env, val); 694d2f8fb8eSLaurent Vivier } 695e1f3808eSpbrook 696e1f3808eSpbrook /* MAC unit. */ 697e1f3808eSpbrook /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers 698e1f3808eSpbrook take values, others take register numbers and manipulate the contents 699e1f3808eSpbrook in-place. */ 7002b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) 701e1f3808eSpbrook { 702e1f3808eSpbrook uint32_t mask; 703e1f3808eSpbrook env->macc[dest] = env->macc[src]; 704e1f3808eSpbrook mask = MACSR_PAV0 << dest; 705e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << src)) 706e1f3808eSpbrook env->macsr |= mask; 707e1f3808eSpbrook else 708e1f3808eSpbrook env->macsr &= ~mask; 709e1f3808eSpbrook } 710e1f3808eSpbrook 7112b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) 712e1f3808eSpbrook { 713e1f3808eSpbrook int64_t product; 714e1f3808eSpbrook int64_t res; 715e1f3808eSpbrook 716e1f3808eSpbrook product = (uint64_t)op1 * op2; 717e1f3808eSpbrook res = (product << 24) >> 24; 718e1f3808eSpbrook if (res != product) { 719e1f3808eSpbrook env->macsr |= MACSR_V; 720e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 721e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 722e1f3808eSpbrook if (product < 0) 723e1f3808eSpbrook res = ~(1ll << 50); 724e1f3808eSpbrook else 725e1f3808eSpbrook res = 1ll << 50; 726e1f3808eSpbrook } 727e1f3808eSpbrook } 728e1f3808eSpbrook return res; 729e1f3808eSpbrook } 730e1f3808eSpbrook 7312b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) 732e1f3808eSpbrook { 733e1f3808eSpbrook uint64_t product; 734e1f3808eSpbrook 735e1f3808eSpbrook product = (uint64_t)op1 * op2; 736e1f3808eSpbrook if (product & (0xffffffull << 40)) { 737e1f3808eSpbrook env->macsr |= MACSR_V; 738e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 739e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 740e1f3808eSpbrook product = 1ll << 50; 741e1f3808eSpbrook } else { 742e1f3808eSpbrook product &= ((1ull << 40) - 1); 743e1f3808eSpbrook } 744e1f3808eSpbrook } 745e1f3808eSpbrook return product; 746e1f3808eSpbrook } 747e1f3808eSpbrook 7482b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) 749e1f3808eSpbrook { 750e1f3808eSpbrook uint64_t product; 751e1f3808eSpbrook uint32_t remainder; 752e1f3808eSpbrook 753e1f3808eSpbrook product = (uint64_t)op1 * op2; 754e1f3808eSpbrook if (env->macsr & MACSR_RT) { 755e1f3808eSpbrook remainder = product & 0xffffff; 756e1f3808eSpbrook product >>= 24; 757e1f3808eSpbrook if (remainder > 0x800000) 758e1f3808eSpbrook product++; 759e1f3808eSpbrook else if (remainder == 0x800000) 760e1f3808eSpbrook product += (product & 1); 761e1f3808eSpbrook } else { 762e1f3808eSpbrook product >>= 24; 763e1f3808eSpbrook } 764e1f3808eSpbrook return product; 765e1f3808eSpbrook } 766e1f3808eSpbrook 7672b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc) 768e1f3808eSpbrook { 769e1f3808eSpbrook int64_t tmp; 770e1f3808eSpbrook int64_t result; 771e1f3808eSpbrook tmp = env->macc[acc]; 772e1f3808eSpbrook result = ((tmp << 16) >> 16); 773e1f3808eSpbrook if (result != tmp) { 774e1f3808eSpbrook env->macsr |= MACSR_V; 775e1f3808eSpbrook } 776e1f3808eSpbrook if (env->macsr & MACSR_V) { 777e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 778e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 779a1c7273bSStefan Weil /* The result is saturated to 32 bits, despite overflow occurring 780e1f3808eSpbrook at 48 bits. Seems weird, but that's what the hardware docs 781e1f3808eSpbrook say. */ 782e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffff; 783e1f3808eSpbrook } 784e1f3808eSpbrook } 785e1f3808eSpbrook env->macc[acc] = result; 786e1f3808eSpbrook } 787e1f3808eSpbrook 7882b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) 789e1f3808eSpbrook { 790e1f3808eSpbrook uint64_t val; 791e1f3808eSpbrook 792e1f3808eSpbrook val = env->macc[acc]; 793e1f3808eSpbrook if (val & (0xffffull << 48)) { 794e1f3808eSpbrook env->macsr |= MACSR_V; 795e1f3808eSpbrook } 796e1f3808eSpbrook if (env->macsr & MACSR_V) { 797e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 798e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 799e1f3808eSpbrook if (val > (1ull << 53)) 800e1f3808eSpbrook val = 0; 801e1f3808eSpbrook else 802e1f3808eSpbrook val = (1ull << 48) - 1; 803e1f3808eSpbrook } else { 804e1f3808eSpbrook val &= ((1ull << 48) - 1); 805e1f3808eSpbrook } 806e1f3808eSpbrook } 807e1f3808eSpbrook env->macc[acc] = val; 808e1f3808eSpbrook } 809e1f3808eSpbrook 8102b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) 811e1f3808eSpbrook { 812e1f3808eSpbrook int64_t sum; 813e1f3808eSpbrook int64_t result; 814e1f3808eSpbrook 815e1f3808eSpbrook sum = env->macc[acc]; 816e1f3808eSpbrook result = (sum << 16) >> 16; 817e1f3808eSpbrook if (result != sum) { 818e1f3808eSpbrook env->macsr |= MACSR_V; 819e1f3808eSpbrook } 820e1f3808eSpbrook if (env->macsr & MACSR_V) { 821e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 822e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 823e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffffffffll; 824e1f3808eSpbrook } 825e1f3808eSpbrook } 826e1f3808eSpbrook env->macc[acc] = result; 827e1f3808eSpbrook } 828e1f3808eSpbrook 8292b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) 830e1f3808eSpbrook { 831e1f3808eSpbrook uint64_t val; 832e1f3808eSpbrook val = env->macc[acc]; 833c4162574SBlue Swirl if (val == 0) { 834e1f3808eSpbrook env->macsr |= MACSR_Z; 835c4162574SBlue Swirl } else if (val & (1ull << 47)) { 836e1f3808eSpbrook env->macsr |= MACSR_N; 837c4162574SBlue Swirl } 838e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << acc)) { 839e1f3808eSpbrook env->macsr |= MACSR_V; 840e1f3808eSpbrook } 841e1f3808eSpbrook if (env->macsr & MACSR_FI) { 842e1f3808eSpbrook val = ((int64_t)val) >> 40; 843e1f3808eSpbrook if (val != 0 && val != -1) 844e1f3808eSpbrook env->macsr |= MACSR_EV; 845e1f3808eSpbrook } else if (env->macsr & MACSR_SU) { 846e1f3808eSpbrook val = ((int64_t)val) >> 32; 847e1f3808eSpbrook if (val != 0 && val != -1) 848e1f3808eSpbrook env->macsr |= MACSR_EV; 849e1f3808eSpbrook } else { 850e1f3808eSpbrook if ((val >> 32) != 0) 851e1f3808eSpbrook env->macsr |= MACSR_EV; 852e1f3808eSpbrook } 853e1f3808eSpbrook } 854e1f3808eSpbrook 855db3d7945SLaurent Vivier #define EXTSIGN(val, index) ( \ 856db3d7945SLaurent Vivier (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ 857db3d7945SLaurent Vivier ) 858620c6cf6SRichard Henderson 859620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) { \ 860620c6cf6SRichard Henderson switch (op) { \ 861620c6cf6SRichard Henderson case CC_OP_FLAGS: \ 862620c6cf6SRichard Henderson /* Everything in place. */ \ 863620c6cf6SRichard Henderson break; \ 864db3d7945SLaurent Vivier case CC_OP_ADDB: \ 865db3d7945SLaurent Vivier case CC_OP_ADDW: \ 866db3d7945SLaurent Vivier case CC_OP_ADDL: \ 867620c6cf6SRichard Henderson res = n; \ 868620c6cf6SRichard Henderson src2 = v; \ 869db3d7945SLaurent Vivier src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ 870620c6cf6SRichard Henderson c = x; \ 871620c6cf6SRichard Henderson z = n; \ 872620c6cf6SRichard Henderson v = (res ^ src1) & ~(src1 ^ src2); \ 873620c6cf6SRichard Henderson break; \ 874db3d7945SLaurent Vivier case CC_OP_SUBB: \ 875db3d7945SLaurent Vivier case CC_OP_SUBW: \ 876db3d7945SLaurent Vivier case CC_OP_SUBL: \ 877620c6cf6SRichard Henderson res = n; \ 878620c6cf6SRichard Henderson src2 = v; \ 879db3d7945SLaurent Vivier src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ 880620c6cf6SRichard Henderson c = x; \ 881620c6cf6SRichard Henderson z = n; \ 882620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 883620c6cf6SRichard Henderson break; \ 884db3d7945SLaurent Vivier case CC_OP_CMPB: \ 885db3d7945SLaurent Vivier case CC_OP_CMPW: \ 886db3d7945SLaurent Vivier case CC_OP_CMPL: \ 887620c6cf6SRichard Henderson src1 = n; \ 888620c6cf6SRichard Henderson src2 = v; \ 889db3d7945SLaurent Vivier res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ 890620c6cf6SRichard Henderson n = res; \ 891620c6cf6SRichard Henderson z = res; \ 892620c6cf6SRichard Henderson c = src1 < src2; \ 893620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 894620c6cf6SRichard Henderson break; \ 895620c6cf6SRichard Henderson case CC_OP_LOGIC: \ 896620c6cf6SRichard Henderson c = v = 0; \ 897620c6cf6SRichard Henderson z = n; \ 898620c6cf6SRichard Henderson break; \ 899620c6cf6SRichard Henderson default: \ 900620c6cf6SRichard Henderson cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \ 901620c6cf6SRichard Henderson } \ 902620c6cf6SRichard Henderson } while (0) 903620c6cf6SRichard Henderson 904620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env) 905e1f3808eSpbrook { 906620c6cf6SRichard Henderson uint32_t x, c, n, z, v; 907620c6cf6SRichard Henderson uint32_t res, src1, src2; 908620c6cf6SRichard Henderson 909620c6cf6SRichard Henderson x = env->cc_x; 910620c6cf6SRichard Henderson n = env->cc_n; 911620c6cf6SRichard Henderson z = env->cc_z; 912620c6cf6SRichard Henderson v = env->cc_v; 913db3d7945SLaurent Vivier c = env->cc_c; 914620c6cf6SRichard Henderson 915620c6cf6SRichard Henderson COMPUTE_CCR(env->cc_op, x, n, z, v, c); 916620c6cf6SRichard Henderson 917620c6cf6SRichard Henderson n = n >> 31; 918620c6cf6SRichard Henderson z = (z == 0); 919db3d7945SLaurent Vivier v = v >> 31; 920620c6cf6SRichard Henderson 921620c6cf6SRichard Henderson return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; 922620c6cf6SRichard Henderson } 923620c6cf6SRichard Henderson 924620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env) 925620c6cf6SRichard Henderson { 926620c6cf6SRichard Henderson return cpu_m68k_get_ccr(env); 927620c6cf6SRichard Henderson } 928620c6cf6SRichard Henderson 929620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) 930620c6cf6SRichard Henderson { 931620c6cf6SRichard Henderson env->cc_x = (ccr & CCF_X ? 1 : 0); 932620c6cf6SRichard Henderson env->cc_n = (ccr & CCF_N ? -1 : 0); 933620c6cf6SRichard Henderson env->cc_z = (ccr & CCF_Z ? 0 : 1); 934620c6cf6SRichard Henderson env->cc_v = (ccr & CCF_V ? -1 : 0); 935620c6cf6SRichard Henderson env->cc_c = (ccr & CCF_C ? 1 : 0); 936620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 937620c6cf6SRichard Henderson } 938620c6cf6SRichard Henderson 939620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) 940620c6cf6SRichard Henderson { 941620c6cf6SRichard Henderson cpu_m68k_set_ccr(env, ccr); 942620c6cf6SRichard Henderson } 943620c6cf6SRichard Henderson 944620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) 945620c6cf6SRichard Henderson { 946620c6cf6SRichard Henderson uint32_t res, src1, src2; 947620c6cf6SRichard Henderson 948620c6cf6SRichard Henderson COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); 949620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 950e1f3808eSpbrook } 951e1f3808eSpbrook 9522b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) 953e1f3808eSpbrook { 954e1f3808eSpbrook int rem; 955e1f3808eSpbrook uint32_t result; 956e1f3808eSpbrook 957e1f3808eSpbrook if (env->macsr & MACSR_SU) { 958e1f3808eSpbrook /* 16-bit rounding. */ 959e1f3808eSpbrook rem = val & 0xffffff; 960e1f3808eSpbrook val = (val >> 24) & 0xffffu; 961e1f3808eSpbrook if (rem > 0x800000) 962e1f3808eSpbrook val++; 963e1f3808eSpbrook else if (rem == 0x800000) 964e1f3808eSpbrook val += (val & 1); 965e1f3808eSpbrook } else if (env->macsr & MACSR_RT) { 966e1f3808eSpbrook /* 32-bit rounding. */ 967e1f3808eSpbrook rem = val & 0xff; 968e1f3808eSpbrook val >>= 8; 969e1f3808eSpbrook if (rem > 0x80) 970e1f3808eSpbrook val++; 971e1f3808eSpbrook else if (rem == 0x80) 972e1f3808eSpbrook val += (val & 1); 973e1f3808eSpbrook } else { 974e1f3808eSpbrook /* No rounding. */ 975e1f3808eSpbrook val >>= 8; 976e1f3808eSpbrook } 977e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 978e1f3808eSpbrook /* Saturate. */ 979e1f3808eSpbrook if (env->macsr & MACSR_SU) { 980e1f3808eSpbrook if (val != (uint16_t) val) { 981e1f3808eSpbrook result = ((val >> 63) ^ 0x7fff) & 0xffff; 982e1f3808eSpbrook } else { 983e1f3808eSpbrook result = val & 0xffff; 984e1f3808eSpbrook } 985e1f3808eSpbrook } else { 986e1f3808eSpbrook if (val != (uint32_t)val) { 987e1f3808eSpbrook result = ((uint32_t)(val >> 63) & 0x7fffffff); 988e1f3808eSpbrook } else { 989e1f3808eSpbrook result = (uint32_t)val; 990e1f3808eSpbrook } 991e1f3808eSpbrook } 992e1f3808eSpbrook } else { 993e1f3808eSpbrook /* No saturation. */ 994e1f3808eSpbrook if (env->macsr & MACSR_SU) { 995e1f3808eSpbrook result = val & 0xffff; 996e1f3808eSpbrook } else { 997e1f3808eSpbrook result = (uint32_t)val; 998e1f3808eSpbrook } 999e1f3808eSpbrook } 1000e1f3808eSpbrook return result; 1001e1f3808eSpbrook } 1002e1f3808eSpbrook 1003e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val) 1004e1f3808eSpbrook { 1005e1f3808eSpbrook if (val == (int32_t)val) { 1006e1f3808eSpbrook return (int32_t)val; 1007e1f3808eSpbrook } else { 1008e1f3808eSpbrook return (val >> 61) ^ ~SIGNBIT; 1009e1f3808eSpbrook } 1010e1f3808eSpbrook } 1011e1f3808eSpbrook 1012e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val) 1013e1f3808eSpbrook { 1014e1f3808eSpbrook if ((val >> 32) == 0) { 1015e1f3808eSpbrook return (uint32_t)val; 1016e1f3808eSpbrook } else { 1017e1f3808eSpbrook return 0xffffffffu; 1018e1f3808eSpbrook } 1019e1f3808eSpbrook } 1020e1f3808eSpbrook 10212b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) 1022e1f3808eSpbrook { 1023e1f3808eSpbrook uint32_t val; 1024e1f3808eSpbrook val = env->macc[acc] & 0x00ff; 10255ce747cfSPaolo Bonzini val |= (env->macc[acc] >> 32) & 0xff00; 1026e1f3808eSpbrook val |= (env->macc[acc + 1] << 16) & 0x00ff0000; 1027e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xff000000; 1028e1f3808eSpbrook return val; 1029e1f3808eSpbrook } 1030e1f3808eSpbrook 10312b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) 1032e1f3808eSpbrook { 1033e1f3808eSpbrook uint32_t val; 1034e1f3808eSpbrook val = (env->macc[acc] >> 32) & 0xffff; 1035e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xffff0000; 1036e1f3808eSpbrook return val; 1037e1f3808eSpbrook } 1038e1f3808eSpbrook 10392b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) 1040e1f3808eSpbrook { 1041e1f3808eSpbrook int64_t res; 1042e1f3808eSpbrook int32_t tmp; 1043e1f3808eSpbrook res = env->macc[acc] & 0xffffffff00ull; 1044e1f3808eSpbrook tmp = (int16_t)(val & 0xff00); 1045e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1046e1f3808eSpbrook res |= val & 0xff; 1047e1f3808eSpbrook env->macc[acc] = res; 1048e1f3808eSpbrook res = env->macc[acc + 1] & 0xffffffff00ull; 1049e1f3808eSpbrook tmp = (val & 0xff000000); 1050e1f3808eSpbrook res |= ((int64_t)tmp) << 16; 1051e1f3808eSpbrook res |= (val >> 16) & 0xff; 1052e1f3808eSpbrook env->macc[acc + 1] = res; 1053e1f3808eSpbrook } 1054e1f3808eSpbrook 10552b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) 1056e1f3808eSpbrook { 1057e1f3808eSpbrook int64_t res; 1058e1f3808eSpbrook int32_t tmp; 1059e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1060e1f3808eSpbrook tmp = (int16_t)val; 1061e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 1062e1f3808eSpbrook env->macc[acc] = res; 1063e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1064e1f3808eSpbrook tmp = val & 0xffff0000; 1065e1f3808eSpbrook res |= (int64_t)tmp << 16; 1066e1f3808eSpbrook env->macc[acc + 1] = res; 1067e1f3808eSpbrook } 1068e1f3808eSpbrook 10692b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) 1070e1f3808eSpbrook { 1071e1f3808eSpbrook uint64_t res; 1072e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 1073e1f3808eSpbrook res |= ((uint64_t)(val & 0xffff)) << 32; 1074e1f3808eSpbrook env->macc[acc] = res; 1075e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 1076e1f3808eSpbrook res |= (uint64_t)(val & 0xffff0000) << 16; 1077e1f3808eSpbrook env->macc[acc + 1] = res; 1078e1f3808eSpbrook } 10790bdb2b3bSLaurent Vivier 10800bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU) 10810bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env) 10820bdb2b3bSLaurent Vivier { 10830bdb2b3bSLaurent Vivier /* FIXME: reset all except CPU */ 10840bdb2b3bSLaurent Vivier } 10850bdb2b3bSLaurent Vivier #endif 1086