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