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 } 83*ba624944SLaurent Vivier switch (n) { 84*ba624944SLaurent Vivier case 8: /* fpcontrol */ 85*ba624944SLaurent Vivier stl_be_p(mem_buf, env->fpcr); 86*ba624944SLaurent Vivier return 4; 87*ba624944SLaurent Vivier case 9: /* fpstatus */ 88*ba624944SLaurent Vivier stl_be_p(mem_buf, env->fpsr); 89*ba624944SLaurent Vivier return 4; 90*ba624944SLaurent 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 } 104*ba624944SLaurent Vivier switch (n) { 105*ba624944SLaurent Vivier case 8: /* fpcontrol */ 106*ba624944SLaurent Vivier cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); 107*ba624944SLaurent Vivier return 4; 108*ba624944SLaurent Vivier case 9: /* fpstatus */ 109*ba624944SLaurent Vivier env->fpsr = ldl_p(mem_buf); 110*ba624944SLaurent Vivier return 4; 111*ba624944SLaurent 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 */ 148*ba624944SLaurent 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 159c7937d9fSAndreas Färber M68kCPU *cpu_m68k_init(const char *cpu_model) 160aaed909aSbellard { 161b9e7a234SAndreas Färber M68kCPU *cpu; 162aaed909aSbellard CPUM68KState *env; 163bc5b2da3SAndreas Färber ObjectClass *oc; 164aaed909aSbellard 165bc5b2da3SAndreas Färber oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model); 166bc5b2da3SAndreas Färber if (oc == NULL) { 16711150915SAndreas Färber return NULL; 16811150915SAndreas Färber } 169bc5b2da3SAndreas Färber cpu = M68K_CPU(object_new(object_class_get_name(oc))); 170b9e7a234SAndreas Färber env = &cpu->env; 17101ba9816Sths 17211150915SAndreas Färber register_m68k_insns(env); 1736d1bbc62SAndreas Färber 1746d1bbc62SAndreas Färber object_property_set_bool(OBJECT(cpu), true, "realized", NULL); 1756d1bbc62SAndreas Färber 176c7937d9fSAndreas Färber return cpu; 1776d1bbc62SAndreas Färber } 1786d1bbc62SAndreas Färber 1796d1bbc62SAndreas Färber void m68k_cpu_init_gdb(M68kCPU *cpu) 1806d1bbc62SAndreas Färber { 18122169d41SAndreas Färber CPUState *cs = CPU(cpu); 1826d1bbc62SAndreas Färber CPUM68KState *env = &cpu->env; 1836d1bbc62SAndreas Färber 18411150915SAndreas Färber if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { 185f83311e4SLaurent Vivier gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg, 18611150915SAndreas Färber 11, "cf-fp.xml", 18); 1875a4526b2SLaurent Vivier } else if (m68k_feature(env, M68K_FEATURE_FPU)) { 1885a4526b2SLaurent Vivier gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg, 1895a4526b2SLaurent Vivier m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18); 190aaed909aSbellard } 19111150915SAndreas Färber /* TODO: Add [E]MAC registers. */ 192aaed909aSbellard } 193aaed909aSbellard 194e1f3808eSpbrook void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val) 1950633879fSpbrook { 196a47dddd7SAndreas Färber M68kCPU *cpu = m68k_env_get_cpu(env); 197a47dddd7SAndreas Färber 1980633879fSpbrook switch (reg) { 1990633879fSpbrook case 0x02: /* CACR */ 20020dcee94Spbrook env->cacr = val; 20120dcee94Spbrook m68k_switch_sp(env); 20220dcee94Spbrook break; 20320dcee94Spbrook case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */ 20420dcee94Spbrook /* TODO: Implement Access Control Registers. */ 2050633879fSpbrook break; 2060633879fSpbrook case 0x801: /* VBR */ 2070633879fSpbrook env->vbr = val; 2080633879fSpbrook break; 2090633879fSpbrook /* TODO: Implement control registers. */ 2100633879fSpbrook default: 211a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", 2120633879fSpbrook reg, val); 2130633879fSpbrook } 2140633879fSpbrook } 2150633879fSpbrook 216e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) 217acf930aaSpbrook { 218acf930aaSpbrook uint32_t acc; 219acf930aaSpbrook int8_t exthigh; 220acf930aaSpbrook uint8_t extlow; 221acf930aaSpbrook uint64_t regval; 222acf930aaSpbrook int i; 223acf930aaSpbrook if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { 224acf930aaSpbrook for (i = 0; i < 4; i++) { 225acf930aaSpbrook regval = env->macc[i]; 226acf930aaSpbrook exthigh = regval >> 40; 227acf930aaSpbrook if (env->macsr & MACSR_FI) { 228acf930aaSpbrook acc = regval >> 8; 229acf930aaSpbrook extlow = regval; 230acf930aaSpbrook } else { 231acf930aaSpbrook acc = regval; 232acf930aaSpbrook extlow = regval >> 32; 233acf930aaSpbrook } 234acf930aaSpbrook if (env->macsr & MACSR_FI) { 235acf930aaSpbrook regval = (((uint64_t)acc) << 8) | extlow; 236acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 237acf930aaSpbrook } else if (env->macsr & MACSR_SU) { 238acf930aaSpbrook regval = acc | (((int64_t)extlow) << 32); 239acf930aaSpbrook regval |= ((int64_t)exthigh) << 40; 240acf930aaSpbrook } else { 241acf930aaSpbrook regval = acc | (((uint64_t)extlow) << 32); 242acf930aaSpbrook regval |= ((uint64_t)(uint8_t)exthigh) << 40; 243acf930aaSpbrook } 244acf930aaSpbrook env->macc[i] = regval; 245acf930aaSpbrook } 246acf930aaSpbrook } 247acf930aaSpbrook env->macsr = val; 248acf930aaSpbrook } 249acf930aaSpbrook 25020dcee94Spbrook void m68k_switch_sp(CPUM68KState *env) 25120dcee94Spbrook { 25220dcee94Spbrook int new_sp; 25320dcee94Spbrook 25420dcee94Spbrook env->sp[env->current_sp] = env->aregs[7]; 25520dcee94Spbrook new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) 25620dcee94Spbrook ? M68K_SSP : M68K_USP; 25720dcee94Spbrook env->aregs[7] = env->sp[new_sp]; 25820dcee94Spbrook env->current_sp = new_sp; 25920dcee94Spbrook } 26020dcee94Spbrook 2610633879fSpbrook #if defined(CONFIG_USER_ONLY) 2620633879fSpbrook 2637510454eSAndreas Färber int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, 26497b348e7SBlue Swirl int mmu_idx) 2650633879fSpbrook { 2667510454eSAndreas Färber M68kCPU *cpu = M68K_CPU(cs); 2677510454eSAndreas Färber 26827103424SAndreas Färber cs->exception_index = EXCP_ACCESS; 2697510454eSAndreas Färber cpu->env.mmu.ar = address; 2700633879fSpbrook return 1; 2710633879fSpbrook } 2720633879fSpbrook 2730633879fSpbrook #else 2740633879fSpbrook 2754fcc562bSPaul Brook /* MMU */ 2764fcc562bSPaul Brook 2774fcc562bSPaul Brook /* TODO: This will need fixing once the MMU is implemented. */ 27800b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 2794fcc562bSPaul Brook { 2804fcc562bSPaul Brook return addr; 2814fcc562bSPaul Brook } 2824fcc562bSPaul Brook 2837510454eSAndreas Färber int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, 28497b348e7SBlue Swirl int mmu_idx) 2850633879fSpbrook { 2860633879fSpbrook int prot; 2870633879fSpbrook 2880633879fSpbrook address &= TARGET_PAGE_MASK; 289d4c430a8SPaul Brook prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 2900c591eb0SAndreas Färber tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); 291d4c430a8SPaul Brook return 0; 2920633879fSpbrook } 2930633879fSpbrook 2940633879fSpbrook /* Notify CPU of a pending interrupt. Prioritization and vectoring should 2950633879fSpbrook be handled by the interrupt controller. Real hardware only requests 2960633879fSpbrook the vector when the interrupt is acknowledged by the CPU. For 2970633879fSpbrook simplicitly we calculate it when the interrupt is signalled. */ 298cb3fb38eSAndreas Färber void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) 2990633879fSpbrook { 300d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 301cb3fb38eSAndreas Färber CPUM68KState *env = &cpu->env; 302cb3fb38eSAndreas Färber 3030633879fSpbrook env->pending_level = level; 3040633879fSpbrook env->pending_vector = vector; 305d8ed887bSAndreas Färber if (level) { 306c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 307d8ed887bSAndreas Färber } else { 308d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 309d8ed887bSAndreas Färber } 3100633879fSpbrook } 3110633879fSpbrook 3120633879fSpbrook #endif 313e1f3808eSpbrook 314e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x) 315e1f3808eSpbrook { 316e1f3808eSpbrook x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); 317e1f3808eSpbrook x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); 318e1f3808eSpbrook x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); 319e1f3808eSpbrook return bswap32(x); 320e1f3808eSpbrook } 321e1f3808eSpbrook 322e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x) 323e1f3808eSpbrook { 324e1f3808eSpbrook int n; 325e1f3808eSpbrook for (n = 32; x; n--) 326e1f3808eSpbrook x >>= 1; 327e1f3808eSpbrook return n; 328e1f3808eSpbrook } 329e1f3808eSpbrook 330620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v) 331e1f3808eSpbrook { 332e1f3808eSpbrook /* The result has the opposite sign to the original value. */ 333620c6cf6SRichard Henderson if ((int32_t)v < 0) { 334e1f3808eSpbrook val = (((int32_t)val) >> 31) ^ SIGNBIT; 335620c6cf6SRichard Henderson } 336e1f3808eSpbrook return val; 337e1f3808eSpbrook } 338e1f3808eSpbrook 3392b3e3cfeSAndreas Färber void HELPER(set_sr)(CPUM68KState *env, uint32_t val) 340e1f3808eSpbrook { 34199c51448SRichard Henderson env->sr = val & 0xffe0; 34299c51448SRichard Henderson cpu_m68k_set_ccr(env, val); 343e1f3808eSpbrook m68k_switch_sp(env); 344e1f3808eSpbrook } 345e1f3808eSpbrook 346e1f3808eSpbrook 347e1f3808eSpbrook /* MAC unit. */ 348e1f3808eSpbrook /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers 349e1f3808eSpbrook take values, others take register numbers and manipulate the contents 350e1f3808eSpbrook in-place. */ 3512b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) 352e1f3808eSpbrook { 353e1f3808eSpbrook uint32_t mask; 354e1f3808eSpbrook env->macc[dest] = env->macc[src]; 355e1f3808eSpbrook mask = MACSR_PAV0 << dest; 356e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << src)) 357e1f3808eSpbrook env->macsr |= mask; 358e1f3808eSpbrook else 359e1f3808eSpbrook env->macsr &= ~mask; 360e1f3808eSpbrook } 361e1f3808eSpbrook 3622b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) 363e1f3808eSpbrook { 364e1f3808eSpbrook int64_t product; 365e1f3808eSpbrook int64_t res; 366e1f3808eSpbrook 367e1f3808eSpbrook product = (uint64_t)op1 * op2; 368e1f3808eSpbrook res = (product << 24) >> 24; 369e1f3808eSpbrook if (res != product) { 370e1f3808eSpbrook env->macsr |= MACSR_V; 371e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 372e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 373e1f3808eSpbrook if (product < 0) 374e1f3808eSpbrook res = ~(1ll << 50); 375e1f3808eSpbrook else 376e1f3808eSpbrook res = 1ll << 50; 377e1f3808eSpbrook } 378e1f3808eSpbrook } 379e1f3808eSpbrook return res; 380e1f3808eSpbrook } 381e1f3808eSpbrook 3822b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) 383e1f3808eSpbrook { 384e1f3808eSpbrook uint64_t product; 385e1f3808eSpbrook 386e1f3808eSpbrook product = (uint64_t)op1 * op2; 387e1f3808eSpbrook if (product & (0xffffffull << 40)) { 388e1f3808eSpbrook env->macsr |= MACSR_V; 389e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 390e1f3808eSpbrook /* Make sure the accumulate operation overflows. */ 391e1f3808eSpbrook product = 1ll << 50; 392e1f3808eSpbrook } else { 393e1f3808eSpbrook product &= ((1ull << 40) - 1); 394e1f3808eSpbrook } 395e1f3808eSpbrook } 396e1f3808eSpbrook return product; 397e1f3808eSpbrook } 398e1f3808eSpbrook 3992b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) 400e1f3808eSpbrook { 401e1f3808eSpbrook uint64_t product; 402e1f3808eSpbrook uint32_t remainder; 403e1f3808eSpbrook 404e1f3808eSpbrook product = (uint64_t)op1 * op2; 405e1f3808eSpbrook if (env->macsr & MACSR_RT) { 406e1f3808eSpbrook remainder = product & 0xffffff; 407e1f3808eSpbrook product >>= 24; 408e1f3808eSpbrook if (remainder > 0x800000) 409e1f3808eSpbrook product++; 410e1f3808eSpbrook else if (remainder == 0x800000) 411e1f3808eSpbrook product += (product & 1); 412e1f3808eSpbrook } else { 413e1f3808eSpbrook product >>= 24; 414e1f3808eSpbrook } 415e1f3808eSpbrook return product; 416e1f3808eSpbrook } 417e1f3808eSpbrook 4182b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc) 419e1f3808eSpbrook { 420e1f3808eSpbrook int64_t tmp; 421e1f3808eSpbrook int64_t result; 422e1f3808eSpbrook tmp = env->macc[acc]; 423e1f3808eSpbrook result = ((tmp << 16) >> 16); 424e1f3808eSpbrook if (result != tmp) { 425e1f3808eSpbrook env->macsr |= MACSR_V; 426e1f3808eSpbrook } 427e1f3808eSpbrook if (env->macsr & MACSR_V) { 428e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 429e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 430a1c7273bSStefan Weil /* The result is saturated to 32 bits, despite overflow occurring 431e1f3808eSpbrook at 48 bits. Seems weird, but that's what the hardware docs 432e1f3808eSpbrook say. */ 433e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffff; 434e1f3808eSpbrook } 435e1f3808eSpbrook } 436e1f3808eSpbrook env->macc[acc] = result; 437e1f3808eSpbrook } 438e1f3808eSpbrook 4392b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) 440e1f3808eSpbrook { 441e1f3808eSpbrook uint64_t val; 442e1f3808eSpbrook 443e1f3808eSpbrook val = env->macc[acc]; 444e1f3808eSpbrook if (val & (0xffffull << 48)) { 445e1f3808eSpbrook env->macsr |= MACSR_V; 446e1f3808eSpbrook } 447e1f3808eSpbrook if (env->macsr & MACSR_V) { 448e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 449e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 450e1f3808eSpbrook if (val > (1ull << 53)) 451e1f3808eSpbrook val = 0; 452e1f3808eSpbrook else 453e1f3808eSpbrook val = (1ull << 48) - 1; 454e1f3808eSpbrook } else { 455e1f3808eSpbrook val &= ((1ull << 48) - 1); 456e1f3808eSpbrook } 457e1f3808eSpbrook } 458e1f3808eSpbrook env->macc[acc] = val; 459e1f3808eSpbrook } 460e1f3808eSpbrook 4612b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) 462e1f3808eSpbrook { 463e1f3808eSpbrook int64_t sum; 464e1f3808eSpbrook int64_t result; 465e1f3808eSpbrook 466e1f3808eSpbrook sum = env->macc[acc]; 467e1f3808eSpbrook result = (sum << 16) >> 16; 468e1f3808eSpbrook if (result != sum) { 469e1f3808eSpbrook env->macsr |= MACSR_V; 470e1f3808eSpbrook } 471e1f3808eSpbrook if (env->macsr & MACSR_V) { 472e1f3808eSpbrook env->macsr |= MACSR_PAV0 << acc; 473e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 474e1f3808eSpbrook result = (result >> 63) ^ 0x7fffffffffffll; 475e1f3808eSpbrook } 476e1f3808eSpbrook } 477e1f3808eSpbrook env->macc[acc] = result; 478e1f3808eSpbrook } 479e1f3808eSpbrook 4802b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) 481e1f3808eSpbrook { 482e1f3808eSpbrook uint64_t val; 483e1f3808eSpbrook val = env->macc[acc]; 484c4162574SBlue Swirl if (val == 0) { 485e1f3808eSpbrook env->macsr |= MACSR_Z; 486c4162574SBlue Swirl } else if (val & (1ull << 47)) { 487e1f3808eSpbrook env->macsr |= MACSR_N; 488c4162574SBlue Swirl } 489e1f3808eSpbrook if (env->macsr & (MACSR_PAV0 << acc)) { 490e1f3808eSpbrook env->macsr |= MACSR_V; 491e1f3808eSpbrook } 492e1f3808eSpbrook if (env->macsr & MACSR_FI) { 493e1f3808eSpbrook val = ((int64_t)val) >> 40; 494e1f3808eSpbrook if (val != 0 && val != -1) 495e1f3808eSpbrook env->macsr |= MACSR_EV; 496e1f3808eSpbrook } else if (env->macsr & MACSR_SU) { 497e1f3808eSpbrook val = ((int64_t)val) >> 32; 498e1f3808eSpbrook if (val != 0 && val != -1) 499e1f3808eSpbrook env->macsr |= MACSR_EV; 500e1f3808eSpbrook } else { 501e1f3808eSpbrook if ((val >> 32) != 0) 502e1f3808eSpbrook env->macsr |= MACSR_EV; 503e1f3808eSpbrook } 504e1f3808eSpbrook } 505e1f3808eSpbrook 506db3d7945SLaurent Vivier #define EXTSIGN(val, index) ( \ 507db3d7945SLaurent Vivier (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ 508db3d7945SLaurent Vivier ) 509620c6cf6SRichard Henderson 510620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) { \ 511620c6cf6SRichard Henderson switch (op) { \ 512620c6cf6SRichard Henderson case CC_OP_FLAGS: \ 513620c6cf6SRichard Henderson /* Everything in place. */ \ 514620c6cf6SRichard Henderson break; \ 515db3d7945SLaurent Vivier case CC_OP_ADDB: \ 516db3d7945SLaurent Vivier case CC_OP_ADDW: \ 517db3d7945SLaurent Vivier case CC_OP_ADDL: \ 518620c6cf6SRichard Henderson res = n; \ 519620c6cf6SRichard Henderson src2 = v; \ 520db3d7945SLaurent Vivier src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ 521620c6cf6SRichard Henderson c = x; \ 522620c6cf6SRichard Henderson z = n; \ 523620c6cf6SRichard Henderson v = (res ^ src1) & ~(src1 ^ src2); \ 524620c6cf6SRichard Henderson break; \ 525db3d7945SLaurent Vivier case CC_OP_SUBB: \ 526db3d7945SLaurent Vivier case CC_OP_SUBW: \ 527db3d7945SLaurent Vivier case CC_OP_SUBL: \ 528620c6cf6SRichard Henderson res = n; \ 529620c6cf6SRichard Henderson src2 = v; \ 530db3d7945SLaurent Vivier src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ 531620c6cf6SRichard Henderson c = x; \ 532620c6cf6SRichard Henderson z = n; \ 533620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 534620c6cf6SRichard Henderson break; \ 535db3d7945SLaurent Vivier case CC_OP_CMPB: \ 536db3d7945SLaurent Vivier case CC_OP_CMPW: \ 537db3d7945SLaurent Vivier case CC_OP_CMPL: \ 538620c6cf6SRichard Henderson src1 = n; \ 539620c6cf6SRichard Henderson src2 = v; \ 540db3d7945SLaurent Vivier res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ 541620c6cf6SRichard Henderson n = res; \ 542620c6cf6SRichard Henderson z = res; \ 543620c6cf6SRichard Henderson c = src1 < src2; \ 544620c6cf6SRichard Henderson v = (res ^ src1) & (src1 ^ src2); \ 545620c6cf6SRichard Henderson break; \ 546620c6cf6SRichard Henderson case CC_OP_LOGIC: \ 547620c6cf6SRichard Henderson c = v = 0; \ 548620c6cf6SRichard Henderson z = n; \ 549620c6cf6SRichard Henderson break; \ 550620c6cf6SRichard Henderson default: \ 551620c6cf6SRichard Henderson cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \ 552620c6cf6SRichard Henderson } \ 553620c6cf6SRichard Henderson } while (0) 554620c6cf6SRichard Henderson 555620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env) 556e1f3808eSpbrook { 557620c6cf6SRichard Henderson uint32_t x, c, n, z, v; 558620c6cf6SRichard Henderson uint32_t res, src1, src2; 559620c6cf6SRichard Henderson 560620c6cf6SRichard Henderson x = env->cc_x; 561620c6cf6SRichard Henderson n = env->cc_n; 562620c6cf6SRichard Henderson z = env->cc_z; 563620c6cf6SRichard Henderson v = env->cc_v; 564db3d7945SLaurent Vivier c = env->cc_c; 565620c6cf6SRichard Henderson 566620c6cf6SRichard Henderson COMPUTE_CCR(env->cc_op, x, n, z, v, c); 567620c6cf6SRichard Henderson 568620c6cf6SRichard Henderson n = n >> 31; 569620c6cf6SRichard Henderson z = (z == 0); 570db3d7945SLaurent Vivier v = v >> 31; 571620c6cf6SRichard Henderson 572620c6cf6SRichard Henderson return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; 573620c6cf6SRichard Henderson } 574620c6cf6SRichard Henderson 575620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env) 576620c6cf6SRichard Henderson { 577620c6cf6SRichard Henderson return cpu_m68k_get_ccr(env); 578620c6cf6SRichard Henderson } 579620c6cf6SRichard Henderson 580620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) 581620c6cf6SRichard Henderson { 582620c6cf6SRichard Henderson env->cc_x = (ccr & CCF_X ? 1 : 0); 583620c6cf6SRichard Henderson env->cc_n = (ccr & CCF_N ? -1 : 0); 584620c6cf6SRichard Henderson env->cc_z = (ccr & CCF_Z ? 0 : 1); 585620c6cf6SRichard Henderson env->cc_v = (ccr & CCF_V ? -1 : 0); 586620c6cf6SRichard Henderson env->cc_c = (ccr & CCF_C ? 1 : 0); 587620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 588620c6cf6SRichard Henderson } 589620c6cf6SRichard Henderson 590620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) 591620c6cf6SRichard Henderson { 592620c6cf6SRichard Henderson cpu_m68k_set_ccr(env, ccr); 593620c6cf6SRichard Henderson } 594620c6cf6SRichard Henderson 595620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) 596620c6cf6SRichard Henderson { 597620c6cf6SRichard Henderson uint32_t res, src1, src2; 598620c6cf6SRichard Henderson 599620c6cf6SRichard Henderson COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); 600620c6cf6SRichard Henderson env->cc_op = CC_OP_FLAGS; 601e1f3808eSpbrook } 602e1f3808eSpbrook 6032b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) 604e1f3808eSpbrook { 605e1f3808eSpbrook int rem; 606e1f3808eSpbrook uint32_t result; 607e1f3808eSpbrook 608e1f3808eSpbrook if (env->macsr & MACSR_SU) { 609e1f3808eSpbrook /* 16-bit rounding. */ 610e1f3808eSpbrook rem = val & 0xffffff; 611e1f3808eSpbrook val = (val >> 24) & 0xffffu; 612e1f3808eSpbrook if (rem > 0x800000) 613e1f3808eSpbrook val++; 614e1f3808eSpbrook else if (rem == 0x800000) 615e1f3808eSpbrook val += (val & 1); 616e1f3808eSpbrook } else if (env->macsr & MACSR_RT) { 617e1f3808eSpbrook /* 32-bit rounding. */ 618e1f3808eSpbrook rem = val & 0xff; 619e1f3808eSpbrook val >>= 8; 620e1f3808eSpbrook if (rem > 0x80) 621e1f3808eSpbrook val++; 622e1f3808eSpbrook else if (rem == 0x80) 623e1f3808eSpbrook val += (val & 1); 624e1f3808eSpbrook } else { 625e1f3808eSpbrook /* No rounding. */ 626e1f3808eSpbrook val >>= 8; 627e1f3808eSpbrook } 628e1f3808eSpbrook if (env->macsr & MACSR_OMC) { 629e1f3808eSpbrook /* Saturate. */ 630e1f3808eSpbrook if (env->macsr & MACSR_SU) { 631e1f3808eSpbrook if (val != (uint16_t) val) { 632e1f3808eSpbrook result = ((val >> 63) ^ 0x7fff) & 0xffff; 633e1f3808eSpbrook } else { 634e1f3808eSpbrook result = val & 0xffff; 635e1f3808eSpbrook } 636e1f3808eSpbrook } else { 637e1f3808eSpbrook if (val != (uint32_t)val) { 638e1f3808eSpbrook result = ((uint32_t)(val >> 63) & 0x7fffffff); 639e1f3808eSpbrook } else { 640e1f3808eSpbrook result = (uint32_t)val; 641e1f3808eSpbrook } 642e1f3808eSpbrook } 643e1f3808eSpbrook } else { 644e1f3808eSpbrook /* No saturation. */ 645e1f3808eSpbrook if (env->macsr & MACSR_SU) { 646e1f3808eSpbrook result = val & 0xffff; 647e1f3808eSpbrook } else { 648e1f3808eSpbrook result = (uint32_t)val; 649e1f3808eSpbrook } 650e1f3808eSpbrook } 651e1f3808eSpbrook return result; 652e1f3808eSpbrook } 653e1f3808eSpbrook 654e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val) 655e1f3808eSpbrook { 656e1f3808eSpbrook if (val == (int32_t)val) { 657e1f3808eSpbrook return (int32_t)val; 658e1f3808eSpbrook } else { 659e1f3808eSpbrook return (val >> 61) ^ ~SIGNBIT; 660e1f3808eSpbrook } 661e1f3808eSpbrook } 662e1f3808eSpbrook 663e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val) 664e1f3808eSpbrook { 665e1f3808eSpbrook if ((val >> 32) == 0) { 666e1f3808eSpbrook return (uint32_t)val; 667e1f3808eSpbrook } else { 668e1f3808eSpbrook return 0xffffffffu; 669e1f3808eSpbrook } 670e1f3808eSpbrook } 671e1f3808eSpbrook 6722b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) 673e1f3808eSpbrook { 674e1f3808eSpbrook uint32_t val; 675e1f3808eSpbrook val = env->macc[acc] & 0x00ff; 6765ce747cfSPaolo Bonzini val |= (env->macc[acc] >> 32) & 0xff00; 677e1f3808eSpbrook val |= (env->macc[acc + 1] << 16) & 0x00ff0000; 678e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xff000000; 679e1f3808eSpbrook return val; 680e1f3808eSpbrook } 681e1f3808eSpbrook 6822b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) 683e1f3808eSpbrook { 684e1f3808eSpbrook uint32_t val; 685e1f3808eSpbrook val = (env->macc[acc] >> 32) & 0xffff; 686e1f3808eSpbrook val |= (env->macc[acc + 1] >> 16) & 0xffff0000; 687e1f3808eSpbrook return val; 688e1f3808eSpbrook } 689e1f3808eSpbrook 6902b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) 691e1f3808eSpbrook { 692e1f3808eSpbrook int64_t res; 693e1f3808eSpbrook int32_t tmp; 694e1f3808eSpbrook res = env->macc[acc] & 0xffffffff00ull; 695e1f3808eSpbrook tmp = (int16_t)(val & 0xff00); 696e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 697e1f3808eSpbrook res |= val & 0xff; 698e1f3808eSpbrook env->macc[acc] = res; 699e1f3808eSpbrook res = env->macc[acc + 1] & 0xffffffff00ull; 700e1f3808eSpbrook tmp = (val & 0xff000000); 701e1f3808eSpbrook res |= ((int64_t)tmp) << 16; 702e1f3808eSpbrook res |= (val >> 16) & 0xff; 703e1f3808eSpbrook env->macc[acc + 1] = res; 704e1f3808eSpbrook } 705e1f3808eSpbrook 7062b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) 707e1f3808eSpbrook { 708e1f3808eSpbrook int64_t res; 709e1f3808eSpbrook int32_t tmp; 710e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 711e1f3808eSpbrook tmp = (int16_t)val; 712e1f3808eSpbrook res |= ((int64_t)tmp) << 32; 713e1f3808eSpbrook env->macc[acc] = res; 714e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 715e1f3808eSpbrook tmp = val & 0xffff0000; 716e1f3808eSpbrook res |= (int64_t)tmp << 16; 717e1f3808eSpbrook env->macc[acc + 1] = res; 718e1f3808eSpbrook } 719e1f3808eSpbrook 7202b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) 721e1f3808eSpbrook { 722e1f3808eSpbrook uint64_t res; 723e1f3808eSpbrook res = (uint32_t)env->macc[acc]; 724e1f3808eSpbrook res |= ((uint64_t)(val & 0xffff)) << 32; 725e1f3808eSpbrook env->macc[acc] = res; 726e1f3808eSpbrook res = (uint32_t)env->macc[acc + 1]; 727e1f3808eSpbrook res |= (uint64_t)(val & 0xffff0000) << 16; 728e1f3808eSpbrook env->macc[acc + 1] = res; 729e1f3808eSpbrook } 730