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 174*6e22b28eSLaurent 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) { 179*6e22b28eSLaurent Vivier case M68K_CR_CACR: 18020dcee94Spbrook env->cacr = val; 18120dcee94Spbrook m68k_switch_sp(env); 18220dcee94Spbrook break; 183*6e22b28eSLaurent Vivier case M68K_CR_ACR0: 184*6e22b28eSLaurent Vivier case M68K_CR_ACR1: 185*6e22b28eSLaurent Vivier case M68K_CR_ACR2: 186*6e22b28eSLaurent Vivier case M68K_CR_ACR3: 18720dcee94Spbrook /* TODO: Implement Access Control Registers. */ 1880633879fSpbrook break; 189*6e22b28eSLaurent Vivier case M68K_CR_VBR: 1900633879fSpbrook env->vbr = val; 1910633879fSpbrook break; 1920633879fSpbrook /* TODO: Implement control registers. */ 1930633879fSpbrook default: 194*6e22b28eSLaurent Vivier cpu_abort(CPU(cpu), 195*6e22b28eSLaurent Vivier "Unimplemented control register write 0x%x = 0x%x\n", 196*6e22b28eSLaurent Vivier reg, val); 197*6e22b28eSLaurent Vivier } 198*6e22b28eSLaurent Vivier } 199*6e22b28eSLaurent Vivier 200*6e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) 201*6e22b28eSLaurent Vivier { 202*6e22b28eSLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 203*6e22b28eSLaurent Vivier 204*6e22b28eSLaurent Vivier switch (reg) { 205*6e22b28eSLaurent Vivier /* MC680[1234]0 */ 206*6e22b28eSLaurent Vivier case M68K_CR_VBR: 207*6e22b28eSLaurent Vivier env->vbr = val; 208*6e22b28eSLaurent Vivier return; 209*6e22b28eSLaurent Vivier /* MC680[234]0 */ 210*6e22b28eSLaurent Vivier case M68K_CR_CACR: 211*6e22b28eSLaurent Vivier env->cacr = val; 212*6e22b28eSLaurent Vivier m68k_switch_sp(env); 213*6e22b28eSLaurent Vivier return; 214*6e22b28eSLaurent Vivier /* MC680[34]0 */ 215*6e22b28eSLaurent Vivier case M68K_CR_USP: 216*6e22b28eSLaurent Vivier env->sp[M68K_USP] = val; 217*6e22b28eSLaurent Vivier return; 218*6e22b28eSLaurent Vivier case M68K_CR_MSP: 219*6e22b28eSLaurent Vivier env->sp[M68K_SSP] = val; 220*6e22b28eSLaurent Vivier return; 221*6e22b28eSLaurent Vivier case M68K_CR_ISP: 222*6e22b28eSLaurent Vivier env->sp[M68K_ISP] = val; 223*6e22b28eSLaurent Vivier return; 224*6e22b28eSLaurent Vivier } 225a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", 2260633879fSpbrook reg, val); 2270633879fSpbrook } 228*6e22b28eSLaurent Vivier 229*6e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) 230*6e22b28eSLaurent Vivier { 231*6e22b28eSLaurent Vivier M68kCPU *cpu = m68k_env_get_cpu(env); 232*6e22b28eSLaurent Vivier 233*6e22b28eSLaurent Vivier switch (reg) { 234*6e22b28eSLaurent Vivier /* MC680[1234]0 */ 235*6e22b28eSLaurent Vivier case M68K_CR_VBR: 236*6e22b28eSLaurent Vivier return env->vbr; 237*6e22b28eSLaurent Vivier /* MC680[234]0 */ 238*6e22b28eSLaurent Vivier case M68K_CR_CACR: 239*6e22b28eSLaurent Vivier return env->cacr; 240*6e22b28eSLaurent Vivier /* MC680[34]0 */ 241*6e22b28eSLaurent Vivier case M68K_CR_USP: 242*6e22b28eSLaurent Vivier return env->sp[M68K_USP]; 243*6e22b28eSLaurent Vivier case M68K_CR_MSP: 244*6e22b28eSLaurent Vivier return env->sp[M68K_SSP]; 245*6e22b28eSLaurent Vivier case M68K_CR_ISP: 246*6e22b28eSLaurent Vivier return env->sp[M68K_ISP]; 247*6e22b28eSLaurent Vivier } 248*6e22b28eSLaurent Vivier cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n", 249*6e22b28eSLaurent Vivier reg); 2500633879fSpbrook } 2510633879fSpbrook 252e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) 253acf930aaSpbrook { 254acf930aaSpbrook uint32_t acc; 255acf930aaSpbrook int8_t exthigh; 256acf930aaSpbrook uint8_t extlow; 257acf930aaSpbrook uint64_t regval; 258acf930aaSpbrook int i; 259acf930aaSpbrook if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { 260acf930aaSpbrook for (i = 0; i < 4; i++) { 261acf930aaSpbrook regval = env->macc[i]; 262acf930aaSpbrook exthigh = regval >> 40; 263acf930aaSpbrook if (env->macsr & MACSR_FI) { 264acf930aaSpbrook acc = regval >> 8; 265acf930aaSpbrook extlow = regval; 266acf930aaSpbrook } else { 267acf930aaSpbrook acc = regval; 268acf930aaSpbrook extlow = regval >> 32; 269acf930aaSpbrook } 270acf930aaSpbrook if (env->macsr & MACSR_FI) { 271acf930aaSpbrook regval = (((uint64_t)acc) << 8) | extlow; 272acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 273acf930aaSpbrook } else if (env->macsr & MACSR_SU) { 274acf930aaSpbrook regval = acc | (((int64_t)extlow) << 32); 275acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 276acf930aaSpbrook } else { 277acf930aaSpbrook regval = acc | (((uint64_t)extlow) << 32); 278acf930aaSpbrook regval |= ((uint64_t)(uint8_t)exthigh) << 40; 279acf930aaSpbrook } 280acf930aaSpbrook env->macc[i] = regval; 281acf930aaSpbrook } 282acf930aaSpbrook } 283acf930aaSpbrook env->macsr = val; 284acf930aaSpbrook } 285acf930aaSpbrook 28620dcee94Spbrook void m68k_switch_sp(CPUM68KState *env) 28720dcee94Spbrook { 28820dcee94Spbrook int new_sp; 28920dcee94Spbrook 29020dcee94Spbrook env->sp[env->current_sp] = env->aregs[7]; 291*6e22b28eSLaurent Vivier if (m68k_feature(env, M68K_FEATURE_M68000)) { 292*6e22b28eSLaurent Vivier if (env->sr & SR_S) { 293*6e22b28eSLaurent Vivier if (env->sr & SR_M) { 294*6e22b28eSLaurent Vivier new_sp = M68K_SSP; 295*6e22b28eSLaurent Vivier } else { 296*6e22b28eSLaurent Vivier new_sp = M68K_ISP; 297*6e22b28eSLaurent Vivier } 298*6e22b28eSLaurent Vivier } else { 299*6e22b28eSLaurent Vivier new_sp = M68K_USP; 300*6e22b28eSLaurent Vivier } 301*6e22b28eSLaurent Vivier } else { 30220dcee94Spbrook new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) 30320dcee94Spbrook ? M68K_SSP : M68K_USP; 304*6e22b28eSLaurent Vivier } 30520dcee94Spbrook env->aregs[7] = env->sp[new_sp]; 30620dcee94Spbrook env->current_sp = new_sp; 30720dcee94Spbrook } 30820dcee94Spbrook 3090633879fSpbrook #if defined(CONFIG_USER_ONLY) 3100633879fSpbrook 3117510454eSAndreas Färber int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, 31297b348e7SBlue Swirl int mmu_idx) 3130633879fSpbrook { 3147510454eSAndreas Färber M68kCPU *cpu = M68K_CPU(cs); 3157510454eSAndreas Färber 31627103424SAndreas Färber cs->exception_index = EXCP_ACCESS; 3177510454eSAndreas Färber cpu->env.mmu.ar = address; 3180633879fSpbrook return 1; 3190633879fSpbrook } 3200633879fSpbrook 3210633879fSpbrook #else 3220633879fSpbrook 3234fcc562bSPaul Brook /* MMU */ 3244fcc562bSPaul Brook 3254fcc562bSPaul Brook /* TODO: This will need fixing once the MMU is implemented. */ 32600b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 3274fcc562bSPaul Brook { 3284fcc562bSPaul Brook return addr; 3294fcc562bSPaul Brook } 3304fcc562bSPaul Brook 3317510454eSAndreas Färber int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, 33297b348e7SBlue Swirl int mmu_idx) 3330633879fSpbrook { 3340633879fSpbrook int prot; 3350633879fSpbrook 3360633879fSpbrook address &= TARGET_PAGE_MASK; 337d4c430a8SPaul Brook prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 3380c591eb0SAndreas Färber tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); 339d4c430a8SPaul Brook return 0; 3400633879fSpbrook } 3410633879fSpbrook 3420633879fSpbrook /* Notify CPU of a pending interrupt. Prioritization and vectoring should 3430633879fSpbrook be handled by the interrupt controller. Real hardware only requests 3440633879fSpbrook the vector when the interrupt is acknowledged by the CPU. For 3450633879fSpbrook simplicitly we calculate it when the interrupt is signalled. */ 346cb3fb38eSAndreas Färber void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) 3470633879fSpbrook { 348d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 349cb3fb38eSAndreas Färber CPUM68KState *env = &cpu->env; 350cb3fb38eSAndreas Färber 3510633879fSpbrook env->pending_level = level; 3520633879fSpbrook env->pending_vector = vector; 353d8ed887bSAndreas Färber if (level) { 354c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 355d8ed887bSAndreas Färber } else { 356d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 357d8ed887bSAndreas Färber } 3580633879fSpbrook } 3590633879fSpbrook 3600633879fSpbrook #endif 361e1f3808eSpbrook 362e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x) 363e1f3808eSpbrook { 364e1f3808eSpbrook x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); 365e1f3808eSpbrook x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); 366e1f3808eSpbrook x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); 367e1f3808eSpbrook return bswap32(x); 368e1f3808eSpbrook } 369e1f3808eSpbrook 370e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x) 371e1f3808eSpbrook { 372e1f3808eSpbrook int n; 373e1f3808eSpbrook for (n = 32; x; n--) 374e1f3808eSpbrook x >>= 1; 375e1f3808eSpbrook return n; 376e1f3808eSpbrook } 377e1f3808eSpbrook 378620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v) 379e1f3808eSpbrook { 380e1f3808eSpbrook /* The result has the opposite sign to the original value. */ 381620c6cf6SRichard Henderson if ((int32_t)v < 0) { 382e1f3808eSpbrook val = (((int32_t)val) >> 31) ^ SIGNBIT; 383620c6cf6SRichard Henderson } 384e1f3808eSpbrook return val; 385e1f3808eSpbrook } 386e1f3808eSpbrook 387d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) 388e1f3808eSpbrook { 389d2f8fb8eSLaurent Vivier env->sr = sr & 0xffe0; 390d2f8fb8eSLaurent Vivier cpu_m68k_set_ccr(env, sr); 391e1f3808eSpbrook m68k_switch_sp(env); 392e1f3808eSpbrook } 393e1f3808eSpbrook 394d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val) 395d2f8fb8eSLaurent Vivier { 396d2f8fb8eSLaurent Vivier cpu_m68k_set_sr(env, val); 397d2f8fb8eSLaurent Vivier } 398e1f3808eSpbrook 399e1f3808eSpbrook /* MAC unit. */ 400e1f3808eSpbrook /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers 401e1f3808eSpbrook take values, others take register numbers and manipulate the contents 402e1f3808eSpbrook in-place. */ 4032b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) 404e1f3808eSpbrook { 405e1f3808eSpbrook uint32_t mask; 406e1f3808eSpbrook env->macc[dest] = env->macc[src]; 407e1f3808eSpbrook mask = MACSR_PAV0 << dest; 408e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << src)) 409e1f3808eSpbrook env->macsr |= mask; 410e1f3808eSpbrook else 411e1f3808eSpbrook env->macsr &= ~mask; 412e1f3808eSpbrook } 413e1f3808eSpbrook 4142b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) 415e1f3808eSpbrook { 416e1f3808eSpbrook int64_t product; 417e1f3808eSpbrook int64_t res; 418e1f3808eSpbrook 419e1f3808eSpbrook product = (uint64_t)op1 * op2; 420e1f3808eSpbrook res = (product << 24) >> 24; 421e1f3808eSpbrook if (res != product) { 422e1f3808eSpbrook env->macsr |= MACSR_V; 423e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 424e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 425e1f3808eSpbrook if (product < 0) 426e1f3808eSpbrook res = ~(1ll << 50); 427e1f3808eSpbrook else 428e1f3808eSpbrook res = 1ll << 50; 429e1f3808eSpbrook } 430e1f3808eSpbrook } 431e1f3808eSpbrook return res; 432e1f3808eSpbrook } 433e1f3808eSpbrook 4342b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) 435e1f3808eSpbrook { 436e1f3808eSpbrook uint64_t product; 437e1f3808eSpbrook 438e1f3808eSpbrook product = (uint64_t)op1 * op2; 439e1f3808eSpbrook if (product & (0xffffffull << 40)) { 440e1f3808eSpbrook env->macsr |= MACSR_V; 441e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 442e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 443e1f3808eSpbrook product = 1ll << 50; 444e1f3808eSpbrook } else { 445e1f3808eSpbrook product &= ((1ull << 40) - 1); 446e1f3808eSpbrook } 447e1f3808eSpbrook } 448e1f3808eSpbrook return product; 449e1f3808eSpbrook } 450e1f3808eSpbrook 4512b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) 452e1f3808eSpbrook { 453e1f3808eSpbrook uint64_t product; 454e1f3808eSpbrook uint32_t remainder; 455e1f3808eSpbrook 456e1f3808eSpbrook product = (uint64_t)op1 * op2; 457e1f3808eSpbrook if (env->macsr & MACSR_RT) { 458e1f3808eSpbrook remainder = product & 0xffffff; 459e1f3808eSpbrook product >>= 24; 460e1f3808eSpbrook if (remainder > 0x800000) 461e1f3808eSpbrook product++; 462e1f3808eSpbrook else if (remainder == 0x800000) 463e1f3808eSpbrook product += (product & 1); 464e1f3808eSpbrook } else { 465e1f3808eSpbrook product >>= 24; 466e1f3808eSpbrook } 467e1f3808eSpbrook return product; 468e1f3808eSpbrook } 469e1f3808eSpbrook 4702b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc) 471e1f3808eSpbrook { 472e1f3808eSpbrook int64_t tmp; 473e1f3808eSpbrook int64_t result; 474e1f3808eSpbrook tmp = env->macc[acc]; 475e1f3808eSpbrook result = ((tmp << 16) >> 16); 476e1f3808eSpbrook if (result != tmp) { 477e1f3808eSpbrook env->macsr |= MACSR_V; 478e1f3808eSpbrook } 479e1f3808eSpbrook if (env->macsr & MACSR_V) { 480e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 481e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 482a1c7273bSStefan Weil /* The result is saturated to 32 bits, despite overflow occurring 483e1f3808eSpbrook at 48 bits. Seems weird, but that's what the hardware docs 484e1f3808eSpbrook say. */ 485e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffff; 486e1f3808eSpbrook } 487e1f3808eSpbrook } 488e1f3808eSpbrook env->macc[acc] = result; 489e1f3808eSpbrook } 490e1f3808eSpbrook 4912b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) 492e1f3808eSpbrook { 493e1f3808eSpbrook uint64_t val; 494e1f3808eSpbrook 495e1f3808eSpbrook val = env->macc[acc]; 496e1f3808eSpbrook if (val & (0xffffull << 48)) { 497e1f3808eSpbrook env->macsr |= MACSR_V; 498e1f3808eSpbrook } 499e1f3808eSpbrook if (env->macsr & MACSR_V) { 500e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 501e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 502e1f3808eSpbrook if (val > (1ull << 53)) 503e1f3808eSpbrook val = 0; 504e1f3808eSpbrook else 505e1f3808eSpbrook val = (1ull << 48) - 1; 506e1f3808eSpbrook } else { 507e1f3808eSpbrook val &= ((1ull << 48) - 1); 508e1f3808eSpbrook } 509e1f3808eSpbrook } 510e1f3808eSpbrook env->macc[acc] = val; 511e1f3808eSpbrook } 512e1f3808eSpbrook 5132b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) 514e1f3808eSpbrook { 515e1f3808eSpbrook int64_t sum; 516e1f3808eSpbrook int64_t result; 517e1f3808eSpbrook 518e1f3808eSpbrook sum = env->macc[acc]; 519e1f3808eSpbrook result = (sum << 16) >> 16; 520e1f3808eSpbrook if (result != sum) { 521e1f3808eSpbrook env->macsr |= MACSR_V; 522e1f3808eSpbrook } 523e1f3808eSpbrook if (env->macsr & MACSR_V) { 524e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 525e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 526e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffffffffll; 527e1f3808eSpbrook } 528e1f3808eSpbrook } 529e1f3808eSpbrook env->macc[acc] = result; 530e1f3808eSpbrook } 531e1f3808eSpbrook 5322b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) 533e1f3808eSpbrook { 534e1f3808eSpbrook uint64_t val; 535e1f3808eSpbrook val = env->macc[acc]; 536c4162574SBlue Swirl if (val == 0) { 537e1f3808eSpbrook env->macsr |= MACSR_Z; 538c4162574SBlue Swirl } else if (val & (1ull << 47)) { 539e1f3808eSpbrook env->macsr |= MACSR_N; 540c4162574SBlue Swirl } 541e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << acc)) { 542e1f3808eSpbrook env->macsr |= MACSR_V; 543e1f3808eSpbrook } 544e1f3808eSpbrook if (env->macsr & MACSR_FI) { 545e1f3808eSpbrook val = ((int64_t)val) >> 40; 546e1f3808eSpbrook if (val != 0 && val != -1) 547e1f3808eSpbrook env->macsr |= MACSR_EV; 548e1f3808eSpbrook } else if (env->macsr & MACSR_SU) { 549e1f3808eSpbrook val = ((int64_t)val) >> 32; 550e1f3808eSpbrook if (val != 0 && val != -1) 551e1f3808eSpbrook env->macsr |= MACSR_EV; 552e1f3808eSpbrook } else { 553e1f3808eSpbrook if ((val >> 32) != 0) 554e1f3808eSpbrook env->macsr |= MACSR_EV; 555e1f3808eSpbrook } 556e1f3808eSpbrook } 557e1f3808eSpbrook 558db3d7945SLaurent Vivier #define EXTSIGN(val, index) ( \ 559db3d7945SLaurent Vivier (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ 560db3d7945SLaurent Vivier ) 561620c6cf6SRichard Henderson 562620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) { \ 563620c6cf6SRichard Henderson switch (op) { \ 564620c6cf6SRichard Henderson case CC_OP_FLAGS: \ 565620c6cf6SRichard Henderson /* Everything in place. */ \ 566620c6cf6SRichard Henderson break; \ 567db3d7945SLaurent Vivier case CC_OP_ADDB: \ 568db3d7945SLaurent Vivier case CC_OP_ADDW: \ 569db3d7945SLaurent Vivier case CC_OP_ADDL: \ 570620c6cf6SRichard Henderson res = n; \ 571620c6cf6SRichard Henderson src2 = v; \ 572db3d7945SLaurent Vivier src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ 573620c6cf6SRichard Henderson c = x; \ 574620c6cf6SRichard Henderson z = n; \ 575620c6cf6SRichard Henderson v = (res ^ src1) & ~(src1 ^ src2); \ 576620c6cf6SRichard Henderson break; \ 577db3d7945SLaurent Vivier case CC_OP_SUBB: \ 578db3d7945SLaurent Vivier case CC_OP_SUBW: \ 579db3d7945SLaurent Vivier case CC_OP_SUBL: \ 580620c6cf6SRichard Henderson res = n; \ 581620c6cf6SRichard Henderson src2 = v; \ 582db3d7945SLaurent Vivier src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ 583620c6cf6SRichard Henderson c = x; \ 584620c6cf6SRichard Henderson z = n; \ 585620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 586620c6cf6SRichard Henderson break; \ 587db3d7945SLaurent Vivier case CC_OP_CMPB: \ 588db3d7945SLaurent Vivier case CC_OP_CMPW: \ 589db3d7945SLaurent Vivier case CC_OP_CMPL: \ 590620c6cf6SRichard Henderson src1 = n; \ 591620c6cf6SRichard Henderson src2 = v; \ 592db3d7945SLaurent Vivier res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ 593620c6cf6SRichard Henderson n = res; \ 594620c6cf6SRichard Henderson z = res; \ 595620c6cf6SRichard Henderson c = src1 < src2; \ 596620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 597620c6cf6SRichard Henderson break; \ 598620c6cf6SRichard Henderson case CC_OP_LOGIC: \ 599620c6cf6SRichard Henderson c = v = 0; \ 600620c6cf6SRichard Henderson z = n; \ 601620c6cf6SRichard Henderson break; \ 602620c6cf6SRichard Henderson default: \ 603620c6cf6SRichard Henderson cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \ 604620c6cf6SRichard Henderson } \ 605620c6cf6SRichard Henderson } while (0) 606620c6cf6SRichard Henderson 607620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env) 608e1f3808eSpbrook { 609620c6cf6SRichard Henderson uint32_t x, c, n, z, v; 610620c6cf6SRichard Henderson uint32_t res, src1, src2; 611620c6cf6SRichard Henderson 612620c6cf6SRichard Henderson x = env->cc_x; 613620c6cf6SRichard Henderson n = env->cc_n; 614620c6cf6SRichard Henderson z = env->cc_z; 615620c6cf6SRichard Henderson v = env->cc_v; 616db3d7945SLaurent Vivier c = env->cc_c; 617620c6cf6SRichard Henderson 618620c6cf6SRichard Henderson COMPUTE_CCR(env->cc_op, x, n, z, v, c); 619620c6cf6SRichard Henderson 620620c6cf6SRichard Henderson n = n >> 31; 621620c6cf6SRichard Henderson z = (z == 0); 622db3d7945SLaurent Vivier v = v >> 31; 623620c6cf6SRichard Henderson 624620c6cf6SRichard Henderson return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; 625620c6cf6SRichard Henderson } 626620c6cf6SRichard Henderson 627620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env) 628620c6cf6SRichard Henderson { 629620c6cf6SRichard Henderson return cpu_m68k_get_ccr(env); 630620c6cf6SRichard Henderson } 631620c6cf6SRichard Henderson 632620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) 633620c6cf6SRichard Henderson { 634620c6cf6SRichard Henderson env->cc_x = (ccr & CCF_X ? 1 : 0); 635620c6cf6SRichard Henderson env->cc_n = (ccr & CCF_N ? -1 : 0); 636620c6cf6SRichard Henderson env->cc_z = (ccr & CCF_Z ? 0 : 1); 637620c6cf6SRichard Henderson env->cc_v = (ccr & CCF_V ? -1 : 0); 638620c6cf6SRichard Henderson env->cc_c = (ccr & CCF_C ? 1 : 0); 639620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 640620c6cf6SRichard Henderson } 641620c6cf6SRichard Henderson 642620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) 643620c6cf6SRichard Henderson { 644620c6cf6SRichard Henderson cpu_m68k_set_ccr(env, ccr); 645620c6cf6SRichard Henderson } 646620c6cf6SRichard Henderson 647620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) 648620c6cf6SRichard Henderson { 649620c6cf6SRichard Henderson uint32_t res, src1, src2; 650620c6cf6SRichard Henderson 651620c6cf6SRichard Henderson COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); 652620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 653e1f3808eSpbrook } 654e1f3808eSpbrook 6552b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) 656e1f3808eSpbrook { 657e1f3808eSpbrook int rem; 658e1f3808eSpbrook uint32_t result; 659e1f3808eSpbrook 660e1f3808eSpbrook if (env->macsr & MACSR_SU) { 661e1f3808eSpbrook /* 16-bit rounding. */ 662e1f3808eSpbrook rem = val & 0xffffff; 663e1f3808eSpbrook val = (val >> 24) & 0xffffu; 664e1f3808eSpbrook if (rem > 0x800000) 665e1f3808eSpbrook val++; 666e1f3808eSpbrook else if (rem == 0x800000) 667e1f3808eSpbrook val += (val & 1); 668e1f3808eSpbrook } else if (env->macsr & MACSR_RT) { 669e1f3808eSpbrook /* 32-bit rounding. */ 670e1f3808eSpbrook rem = val & 0xff; 671e1f3808eSpbrook val >>= 8; 672e1f3808eSpbrook if (rem > 0x80) 673e1f3808eSpbrook val++; 674e1f3808eSpbrook else if (rem == 0x80) 675e1f3808eSpbrook val += (val & 1); 676e1f3808eSpbrook } else { 677e1f3808eSpbrook /* No rounding. */ 678e1f3808eSpbrook val >>= 8; 679e1f3808eSpbrook } 680e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 681e1f3808eSpbrook /* Saturate. */ 682e1f3808eSpbrook if (env->macsr & MACSR_SU) { 683e1f3808eSpbrook if (val != (uint16_t) val) { 684e1f3808eSpbrook result = ((val >> 63) ^ 0x7fff) & 0xffff; 685e1f3808eSpbrook } else { 686e1f3808eSpbrook result = val & 0xffff; 687e1f3808eSpbrook } 688e1f3808eSpbrook } else { 689e1f3808eSpbrook if (val != (uint32_t)val) { 690e1f3808eSpbrook result = ((uint32_t)(val >> 63) & 0x7fffffff); 691e1f3808eSpbrook } else { 692e1f3808eSpbrook result = (uint32_t)val; 693e1f3808eSpbrook } 694e1f3808eSpbrook } 695e1f3808eSpbrook } else { 696e1f3808eSpbrook /* No saturation. */ 697e1f3808eSpbrook if (env->macsr & MACSR_SU) { 698e1f3808eSpbrook result = val & 0xffff; 699e1f3808eSpbrook } else { 700e1f3808eSpbrook result = (uint32_t)val; 701e1f3808eSpbrook } 702e1f3808eSpbrook } 703e1f3808eSpbrook return result; 704e1f3808eSpbrook } 705e1f3808eSpbrook 706e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val) 707e1f3808eSpbrook { 708e1f3808eSpbrook if (val == (int32_t)val) { 709e1f3808eSpbrook return (int32_t)val; 710e1f3808eSpbrook } else { 711e1f3808eSpbrook return (val >> 61) ^ ~SIGNBIT; 712e1f3808eSpbrook } 713e1f3808eSpbrook } 714e1f3808eSpbrook 715e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val) 716e1f3808eSpbrook { 717e1f3808eSpbrook if ((val >> 32) == 0) { 718e1f3808eSpbrook return (uint32_t)val; 719e1f3808eSpbrook } else { 720e1f3808eSpbrook return 0xffffffffu; 721e1f3808eSpbrook } 722e1f3808eSpbrook } 723e1f3808eSpbrook 7242b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) 725e1f3808eSpbrook { 726e1f3808eSpbrook uint32_t val; 727e1f3808eSpbrook val = env->macc[acc] & 0x00ff; 7285ce747cfSPaolo Bonzini val |= (env->macc[acc] >> 32) & 0xff00; 729e1f3808eSpbrook val |= (env->macc[acc + 1] << 16) & 0x00ff0000; 730e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xff000000; 731e1f3808eSpbrook return val; 732e1f3808eSpbrook } 733e1f3808eSpbrook 7342b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) 735e1f3808eSpbrook { 736e1f3808eSpbrook uint32_t val; 737e1f3808eSpbrook val = (env->macc[acc] >> 32) & 0xffff; 738e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xffff0000; 739e1f3808eSpbrook return val; 740e1f3808eSpbrook } 741e1f3808eSpbrook 7422b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) 743e1f3808eSpbrook { 744e1f3808eSpbrook int64_t res; 745e1f3808eSpbrook int32_t tmp; 746e1f3808eSpbrook res = env->macc[acc] & 0xffffffff00ull; 747e1f3808eSpbrook tmp = (int16_t)(val & 0xff00); 748e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 749e1f3808eSpbrook res |= val & 0xff; 750e1f3808eSpbrook env->macc[acc] = res; 751e1f3808eSpbrook res = env->macc[acc + 1] & 0xffffffff00ull; 752e1f3808eSpbrook tmp = (val & 0xff000000); 753e1f3808eSpbrook res |= ((int64_t)tmp) << 16; 754e1f3808eSpbrook res |= (val >> 16) & 0xff; 755e1f3808eSpbrook env->macc[acc + 1] = res; 756e1f3808eSpbrook } 757e1f3808eSpbrook 7582b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) 759e1f3808eSpbrook { 760e1f3808eSpbrook int64_t res; 761e1f3808eSpbrook int32_t tmp; 762e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 763e1f3808eSpbrook tmp = (int16_t)val; 764e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 765e1f3808eSpbrook env->macc[acc] = res; 766e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 767e1f3808eSpbrook tmp = val & 0xffff0000; 768e1f3808eSpbrook res |= (int64_t)tmp << 16; 769e1f3808eSpbrook env->macc[acc + 1] = res; 770e1f3808eSpbrook } 771e1f3808eSpbrook 7722b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) 773e1f3808eSpbrook { 774e1f3808eSpbrook uint64_t res; 775e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 776e1f3808eSpbrook res |= ((uint64_t)(val & 0xffff)) << 32; 777e1f3808eSpbrook env->macc[acc] = res; 778e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 779e1f3808eSpbrook res |= (uint64_t)(val & 0xffff0000) << 16; 780e1f3808eSpbrook env->macc[acc + 1] = res; 781e1f3808eSpbrook } 7820bdb2b3bSLaurent Vivier 7830bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU) 7840bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env) 7850bdb2b3bSLaurent Vivier { 7860bdb2b3bSLaurent Vivier /* FIXME: reset all except CPU */ 7870bdb2b3bSLaurent Vivier } 7880bdb2b3bSLaurent Vivier #endif 789