xref: /qemu/target/m68k/helper.c (revision ba62494483ab51ee31c70952b6ce5171a31860b1)
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