xref: /qemu/target/m68k/helper.c (revision 0442428a8976b4f94e04d24b5db9eb1b678d82c4)
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
10d749fb85SThomas Huth  * version 2.1 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
15d749fb85SThomas Huth  * Lesser 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"
252ef6175aSRichard Henderson #include "exec/helper-proto.h"
2624f91e81SAlex Bennée #include "fpu/softfloat.h"
27*0442428aSMarkus Armbruster #include "qemu/qemu-print.h"
28e1f3808eSpbrook 
29e1f3808eSpbrook #define SIGNBIT (1u << 31)
30e1f3808eSpbrook 
3111150915SAndreas Färber /* Sort alphabetically, except for "any". */
3211150915SAndreas Färber static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b)
3311150915SAndreas Färber {
3411150915SAndreas Färber     ObjectClass *class_a = (ObjectClass *)a;
3511150915SAndreas Färber     ObjectClass *class_b = (ObjectClass *)b;
3611150915SAndreas Färber     const char *name_a, *name_b;
37aaed909aSbellard 
3811150915SAndreas Färber     name_a = object_class_get_name(class_a);
3911150915SAndreas Färber     name_b = object_class_get_name(class_b);
407a9f812bSAndreas Färber     if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) {
4111150915SAndreas Färber         return 1;
427a9f812bSAndreas Färber     } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
4311150915SAndreas Färber         return -1;
4411150915SAndreas Färber     } else {
4511150915SAndreas Färber         return strcasecmp(name_a, name_b);
4611150915SAndreas Färber     }
4711150915SAndreas Färber }
480402f767Spbrook 
4911150915SAndreas Färber static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
5011150915SAndreas Färber {
5111150915SAndreas Färber     ObjectClass *c = 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));
57*0442428aSMarkus Armbruster     qemu_printf("%s\n", name);
587a9f812bSAndreas Färber     g_free(name);
5911150915SAndreas Färber }
600402f767Spbrook 
61*0442428aSMarkus Armbruster void m68k_cpu_list(void)
62009a4356SLaurent Vivier {
6311150915SAndreas Färber     GSList *list;
64009a4356SLaurent Vivier 
6511150915SAndreas Färber     list = object_class_get_list(TYPE_M68K_CPU, false);
6611150915SAndreas Färber     list = g_slist_sort(list, m68k_cpu_list_compare);
67*0442428aSMarkus Armbruster     g_slist_foreach(list, m68k_cpu_list_entry, NULL);
6811150915SAndreas Färber     g_slist_free(list);
69009a4356SLaurent Vivier }
70009a4356SLaurent Vivier 
71f83311e4SLaurent Vivier static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
7256aebc89Spbrook {
7356aebc89Spbrook     if (n < 8) {
74f83311e4SLaurent Vivier         float_status s;
75f83311e4SLaurent Vivier         stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
7656aebc89Spbrook         return 8;
7756aebc89Spbrook     }
78ba624944SLaurent Vivier     switch (n) {
79ba624944SLaurent Vivier     case 8: /* fpcontrol */
80ba624944SLaurent Vivier         stl_be_p(mem_buf, env->fpcr);
81ba624944SLaurent Vivier         return 4;
82ba624944SLaurent Vivier     case 9: /* fpstatus */
83ba624944SLaurent Vivier         stl_be_p(mem_buf, env->fpsr);
84ba624944SLaurent Vivier         return 4;
85ba624944SLaurent Vivier     case 10: /* fpiar, not implemented */
8656aebc89Spbrook         memset(mem_buf, 0, 4);
8756aebc89Spbrook         return 4;
8856aebc89Spbrook     }
8956aebc89Spbrook     return 0;
9056aebc89Spbrook }
9156aebc89Spbrook 
92f83311e4SLaurent Vivier static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
9356aebc89Spbrook {
9456aebc89Spbrook     if (n < 8) {
95f83311e4SLaurent Vivier         float_status s;
96f83311e4SLaurent Vivier         env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
9756aebc89Spbrook         return 8;
9856aebc89Spbrook     }
99ba624944SLaurent Vivier     switch (n) {
100ba624944SLaurent Vivier     case 8: /* fpcontrol */
101ba624944SLaurent Vivier         cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
102ba624944SLaurent Vivier         return 4;
103ba624944SLaurent Vivier     case 9: /* fpstatus */
104ba624944SLaurent Vivier         env->fpsr = ldl_p(mem_buf);
105ba624944SLaurent Vivier         return 4;
106ba624944SLaurent Vivier     case 10: /* fpiar, not implemented */
10756aebc89Spbrook         return 4;
10856aebc89Spbrook     }
10956aebc89Spbrook     return 0;
11056aebc89Spbrook }
11156aebc89Spbrook 
1125a4526b2SLaurent Vivier static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
1135a4526b2SLaurent Vivier {
1145a4526b2SLaurent Vivier     if (n < 8) {
1155a4526b2SLaurent Vivier         stw_be_p(mem_buf, env->fregs[n].l.upper);
1165a4526b2SLaurent Vivier         memset(mem_buf + 2, 0, 2);
1175a4526b2SLaurent Vivier         stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
1185a4526b2SLaurent Vivier         return 12;
1195a4526b2SLaurent Vivier     }
1205a4526b2SLaurent Vivier     switch (n) {
1215a4526b2SLaurent Vivier     case 8: /* fpcontrol */
1225a4526b2SLaurent Vivier         stl_be_p(mem_buf, env->fpcr);
1235a4526b2SLaurent Vivier         return 4;
1245a4526b2SLaurent Vivier     case 9: /* fpstatus */
1255a4526b2SLaurent Vivier         stl_be_p(mem_buf, env->fpsr);
1265a4526b2SLaurent Vivier         return 4;
1275a4526b2SLaurent Vivier     case 10: /* fpiar, not implemented */
1285a4526b2SLaurent Vivier         memset(mem_buf, 0, 4);
1295a4526b2SLaurent Vivier         return 4;
1305a4526b2SLaurent Vivier     }
1315a4526b2SLaurent Vivier     return 0;
1325a4526b2SLaurent Vivier }
1335a4526b2SLaurent Vivier 
1345a4526b2SLaurent Vivier static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
1355a4526b2SLaurent Vivier {
1365a4526b2SLaurent Vivier     if (n < 8) {
1375a4526b2SLaurent Vivier         env->fregs[n].l.upper = lduw_be_p(mem_buf);
1385a4526b2SLaurent Vivier         env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
1395a4526b2SLaurent Vivier         return 12;
1405a4526b2SLaurent Vivier     }
1415a4526b2SLaurent Vivier     switch (n) {
1425a4526b2SLaurent Vivier     case 8: /* fpcontrol */
143ba624944SLaurent Vivier         cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
1445a4526b2SLaurent Vivier         return 4;
1455a4526b2SLaurent Vivier     case 9: /* fpstatus */
1465a4526b2SLaurent Vivier         env->fpsr = ldl_p(mem_buf);
1475a4526b2SLaurent Vivier         return 4;
1485a4526b2SLaurent Vivier     case 10: /* fpiar, not implemented */
1495a4526b2SLaurent Vivier         return 4;
1505a4526b2SLaurent Vivier     }
1515a4526b2SLaurent Vivier     return 0;
1525a4526b2SLaurent Vivier }
1535a4526b2SLaurent Vivier 
1546d1bbc62SAndreas Färber void m68k_cpu_init_gdb(M68kCPU *cpu)
1556d1bbc62SAndreas Färber {
15622169d41SAndreas Färber     CPUState *cs = CPU(cpu);
1576d1bbc62SAndreas Färber     CPUM68KState *env = &cpu->env;
1586d1bbc62SAndreas Färber 
15911150915SAndreas Färber     if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
160f83311e4SLaurent Vivier         gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
16111150915SAndreas Färber                                  11, "cf-fp.xml", 18);
1625a4526b2SLaurent Vivier     } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
1635a4526b2SLaurent Vivier         gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
1645a4526b2SLaurent Vivier                                  m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
165aaed909aSbellard     }
16611150915SAndreas Färber     /* TODO: Add [E]MAC registers.  */
167aaed909aSbellard }
168aaed909aSbellard 
1696e22b28eSLaurent Vivier void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
1700633879fSpbrook {
171a47dddd7SAndreas Färber     M68kCPU *cpu = m68k_env_get_cpu(env);
172a47dddd7SAndreas Färber 
1730633879fSpbrook     switch (reg) {
1746e22b28eSLaurent Vivier     case M68K_CR_CACR:
17520dcee94Spbrook         env->cacr = val;
17620dcee94Spbrook         m68k_switch_sp(env);
17720dcee94Spbrook         break;
1786e22b28eSLaurent Vivier     case M68K_CR_ACR0:
1796e22b28eSLaurent Vivier     case M68K_CR_ACR1:
1806e22b28eSLaurent Vivier     case M68K_CR_ACR2:
1816e22b28eSLaurent Vivier     case M68K_CR_ACR3:
18220dcee94Spbrook         /* TODO: Implement Access Control Registers.  */
1830633879fSpbrook         break;
1846e22b28eSLaurent Vivier     case M68K_CR_VBR:
1850633879fSpbrook         env->vbr = val;
1860633879fSpbrook         break;
1870633879fSpbrook     /* TODO: Implement control registers.  */
1880633879fSpbrook     default:
1896e22b28eSLaurent Vivier         cpu_abort(CPU(cpu),
1906e22b28eSLaurent Vivier                   "Unimplemented control register write 0x%x = 0x%x\n",
1916e22b28eSLaurent Vivier                   reg, val);
1926e22b28eSLaurent Vivier     }
1936e22b28eSLaurent Vivier }
1946e22b28eSLaurent Vivier 
1956e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
1966e22b28eSLaurent Vivier {
1976e22b28eSLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
1986e22b28eSLaurent Vivier 
1996e22b28eSLaurent Vivier     switch (reg) {
2006e22b28eSLaurent Vivier     /* MC680[1234]0 */
2015fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
2025fa9f1f2SLaurent Vivier         env->sfc = val & 7;
2035fa9f1f2SLaurent Vivier         return;
2045fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
2055fa9f1f2SLaurent Vivier         env->dfc = val & 7;
2065fa9f1f2SLaurent Vivier         return;
2076e22b28eSLaurent Vivier     case M68K_CR_VBR:
2086e22b28eSLaurent Vivier         env->vbr = val;
2096e22b28eSLaurent Vivier         return;
2106e22b28eSLaurent Vivier     /* MC680[234]0 */
2116e22b28eSLaurent Vivier     case M68K_CR_CACR:
2126e22b28eSLaurent Vivier         env->cacr = val;
2136e22b28eSLaurent Vivier         m68k_switch_sp(env);
2146e22b28eSLaurent Vivier         return;
2156e22b28eSLaurent Vivier     /* MC680[34]0 */
21688b2fef6SLaurent Vivier     case M68K_CR_TC:
21788b2fef6SLaurent Vivier         env->mmu.tcr = val;
21888b2fef6SLaurent Vivier         return;
219e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
220e55886c3SLaurent Vivier         env->mmu.mmusr = val;
221e55886c3SLaurent Vivier         return;
22288b2fef6SLaurent Vivier     case M68K_CR_SRP:
22388b2fef6SLaurent Vivier         env->mmu.srp = val;
22488b2fef6SLaurent Vivier         return;
22588b2fef6SLaurent Vivier     case M68K_CR_URP:
22688b2fef6SLaurent Vivier         env->mmu.urp = val;
22788b2fef6SLaurent Vivier         return;
2286e22b28eSLaurent Vivier     case M68K_CR_USP:
2296e22b28eSLaurent Vivier         env->sp[M68K_USP] = val;
2306e22b28eSLaurent Vivier         return;
2316e22b28eSLaurent Vivier     case M68K_CR_MSP:
2326e22b28eSLaurent Vivier         env->sp[M68K_SSP] = val;
2336e22b28eSLaurent Vivier         return;
2346e22b28eSLaurent Vivier     case M68K_CR_ISP:
2356e22b28eSLaurent Vivier         env->sp[M68K_ISP] = val;
2366e22b28eSLaurent Vivier         return;
237c05c73b0SLaurent Vivier     /* MC68040/MC68LC040 */
238c05c73b0SLaurent Vivier     case M68K_CR_ITT0:
239c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_ITTR0] = val;
240c05c73b0SLaurent Vivier         return;
241c05c73b0SLaurent Vivier     case M68K_CR_ITT1:
242c05c73b0SLaurent Vivier          env->mmu.ttr[M68K_ITTR1] = val;
243c05c73b0SLaurent Vivier         return;
244c05c73b0SLaurent Vivier     case M68K_CR_DTT0:
245c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_DTTR0] = val;
246c05c73b0SLaurent Vivier         return;
247c05c73b0SLaurent Vivier     case M68K_CR_DTT1:
248c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_DTTR1] = val;
249c05c73b0SLaurent Vivier         return;
2506e22b28eSLaurent Vivier     }
251a47dddd7SAndreas Färber     cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
2520633879fSpbrook               reg, val);
2530633879fSpbrook }
2546e22b28eSLaurent Vivier 
2556e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
2566e22b28eSLaurent Vivier {
2576e22b28eSLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
2586e22b28eSLaurent Vivier 
2596e22b28eSLaurent Vivier     switch (reg) {
2606e22b28eSLaurent Vivier     /* MC680[1234]0 */
2615fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
2625fa9f1f2SLaurent Vivier         return env->sfc;
2635fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
2645fa9f1f2SLaurent Vivier         return env->dfc;
2656e22b28eSLaurent Vivier     case M68K_CR_VBR:
2666e22b28eSLaurent Vivier         return env->vbr;
2676e22b28eSLaurent Vivier     /* MC680[234]0 */
2686e22b28eSLaurent Vivier     case M68K_CR_CACR:
2696e22b28eSLaurent Vivier         return env->cacr;
2706e22b28eSLaurent Vivier     /* MC680[34]0 */
27188b2fef6SLaurent Vivier     case M68K_CR_TC:
27288b2fef6SLaurent Vivier         return env->mmu.tcr;
273e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
274e55886c3SLaurent Vivier         return env->mmu.mmusr;
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 
3722097dca6SLaurent Vivier static void print_address_zone(FILE *f, fprintf_function cpu_fprintf,
3732097dca6SLaurent Vivier                                uint32_t logical, uint32_t physical,
3742097dca6SLaurent Vivier                                uint32_t size, int attr)
3752097dca6SLaurent Vivier {
3762097dca6SLaurent Vivier     cpu_fprintf(f, "%08x - %08x -> %08x - %08x %c ",
3772097dca6SLaurent Vivier                 logical, logical + size - 1,
3782097dca6SLaurent Vivier                 physical, physical + size - 1,
3792097dca6SLaurent Vivier                 attr & 4 ? 'W' : '-');
3802097dca6SLaurent Vivier     size >>= 10;
3812097dca6SLaurent Vivier     if (size < 1024) {
3822097dca6SLaurent Vivier         cpu_fprintf(f, "(%d KiB)\n", size);
3832097dca6SLaurent Vivier     } else {
3842097dca6SLaurent Vivier         size >>= 10;
3852097dca6SLaurent Vivier         if (size < 1024) {
3862097dca6SLaurent Vivier             cpu_fprintf(f, "(%d MiB)\n", size);
3872097dca6SLaurent Vivier         } else {
3882097dca6SLaurent Vivier             size >>= 10;
3892097dca6SLaurent Vivier             cpu_fprintf(f, "(%d GiB)\n", size);
3902097dca6SLaurent Vivier         }
3912097dca6SLaurent Vivier     }
3922097dca6SLaurent Vivier }
3932097dca6SLaurent Vivier 
3942097dca6SLaurent Vivier static void dump_address_map(FILE *f, fprintf_function cpu_fprintf,
3952097dca6SLaurent Vivier                              CPUM68KState *env, uint32_t root_pointer)
3962097dca6SLaurent Vivier {
3972097dca6SLaurent Vivier     int i, j, k;
3982097dca6SLaurent Vivier     int tic_size, tic_shift;
3992097dca6SLaurent Vivier     uint32_t tib_mask;
4002097dca6SLaurent Vivier     uint32_t tia, tib, tic;
4012097dca6SLaurent Vivier     uint32_t logical = 0xffffffff, physical = 0xffffffff;
4022097dca6SLaurent Vivier     uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
4032097dca6SLaurent Vivier     uint32_t last_logical, last_physical;
4042097dca6SLaurent Vivier     int32_t size;
4052097dca6SLaurent Vivier     int last_attr = -1, attr = -1;
4062097dca6SLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
4072097dca6SLaurent Vivier     CPUState *cs = CPU(cpu);
4082097dca6SLaurent Vivier 
4092097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
4102097dca6SLaurent Vivier         /* 8k page */
4112097dca6SLaurent Vivier         tic_size = 32;
4122097dca6SLaurent Vivier         tic_shift = 13;
4132097dca6SLaurent Vivier         tib_mask = M68K_8K_PAGE_MASK;
4142097dca6SLaurent Vivier     } else {
4152097dca6SLaurent Vivier         /* 4k page */
4162097dca6SLaurent Vivier         tic_size = 64;
4172097dca6SLaurent Vivier         tic_shift = 12;
4182097dca6SLaurent Vivier         tib_mask = M68K_4K_PAGE_MASK;
4192097dca6SLaurent Vivier     }
4202097dca6SLaurent Vivier     for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
4212097dca6SLaurent Vivier         tia = ldl_phys(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4);
4222097dca6SLaurent Vivier         if (!M68K_UDT_VALID(tia)) {
4232097dca6SLaurent Vivier             continue;
4242097dca6SLaurent Vivier         }
4252097dca6SLaurent Vivier         for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
4262097dca6SLaurent Vivier             tib = ldl_phys(cs->as, M68K_POINTER_BASE(tia) + j * 4);
4272097dca6SLaurent Vivier             if (!M68K_UDT_VALID(tib)) {
4282097dca6SLaurent Vivier                 continue;
4292097dca6SLaurent Vivier             }
4302097dca6SLaurent Vivier             for (k = 0; k < tic_size; k++) {
4312097dca6SLaurent Vivier                 tic = ldl_phys(cs->as, (tib & tib_mask) + k * 4);
4322097dca6SLaurent Vivier                 if (!M68K_PDT_VALID(tic)) {
4332097dca6SLaurent Vivier                     continue;
4342097dca6SLaurent Vivier                 }
4352097dca6SLaurent Vivier                 if (M68K_PDT_INDIRECT(tic)) {
4362097dca6SLaurent Vivier                     tic = ldl_phys(cs->as, M68K_INDIRECT_POINTER(tic));
4372097dca6SLaurent Vivier                 }
4382097dca6SLaurent Vivier 
4392097dca6SLaurent Vivier                 last_logical = logical;
4402097dca6SLaurent Vivier                 logical = (i << M68K_TTS_ROOT_SHIFT) |
4412097dca6SLaurent Vivier                           (j << M68K_TTS_POINTER_SHIFT) |
4422097dca6SLaurent Vivier                           (k << tic_shift);
4432097dca6SLaurent Vivier 
4442097dca6SLaurent Vivier                 last_physical = physical;
4452097dca6SLaurent Vivier                 physical = tic & ~((1 << tic_shift) - 1);
4462097dca6SLaurent Vivier 
4472097dca6SLaurent Vivier                 last_attr = attr;
4482097dca6SLaurent Vivier                 attr = tic & ((1 << tic_shift) - 1);
4492097dca6SLaurent Vivier 
4502097dca6SLaurent Vivier                 if ((logical != (last_logical + (1 << tic_shift))) ||
4512097dca6SLaurent Vivier                     (physical != (last_physical + (1 << tic_shift))) ||
4522097dca6SLaurent Vivier                     (attr & 4) != (last_attr & 4)) {
4532097dca6SLaurent Vivier 
4542097dca6SLaurent Vivier                     if (first_logical != 0xffffffff) {
4552097dca6SLaurent Vivier                         size = last_logical + (1 << tic_shift) -
4562097dca6SLaurent Vivier                                first_logical;
4572097dca6SLaurent Vivier                         print_address_zone(f, cpu_fprintf, first_logical,
4582097dca6SLaurent Vivier                                            first_physical, size, last_attr);
4592097dca6SLaurent Vivier                     }
4602097dca6SLaurent Vivier                     first_logical = logical;
4612097dca6SLaurent Vivier                     first_physical = physical;
4622097dca6SLaurent Vivier                 }
4632097dca6SLaurent Vivier             }
4642097dca6SLaurent Vivier         }
4652097dca6SLaurent Vivier     }
4662097dca6SLaurent Vivier     if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
4672097dca6SLaurent Vivier         size = logical + (1 << tic_shift) - first_logical;
4682097dca6SLaurent Vivier         print_address_zone(f, cpu_fprintf, first_logical, first_physical, size,
4692097dca6SLaurent Vivier                            last_attr);
4702097dca6SLaurent Vivier     }
4712097dca6SLaurent Vivier }
4722097dca6SLaurent Vivier 
4732097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \
4742097dca6SLaurent Vivier     switch (a & M68K_DESC_CACHEMODE) { \
4752097dca6SLaurent Vivier     case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
4762097dca6SLaurent Vivier         cpu_fprintf(f, "T"); \
4772097dca6SLaurent Vivier         break; \
4782097dca6SLaurent Vivier     case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
4792097dca6SLaurent Vivier         cpu_fprintf(f, "C"); \
4802097dca6SLaurent Vivier         break; \
4812097dca6SLaurent Vivier     case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
4822097dca6SLaurent Vivier         cpu_fprintf(f, "S"); \
4832097dca6SLaurent Vivier         break; \
4842097dca6SLaurent Vivier     case M68K_DESC_CM_NCACHE: /* noncachable */ \
4852097dca6SLaurent Vivier         cpu_fprintf(f, "N"); \
4862097dca6SLaurent Vivier         break; \
4872097dca6SLaurent Vivier     }
4882097dca6SLaurent Vivier 
4892097dca6SLaurent Vivier static void dump_ttr(FILE *f, fprintf_function cpu_fprintf, uint32_t ttr)
4902097dca6SLaurent Vivier {
4912097dca6SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
4922097dca6SLaurent Vivier         cpu_fprintf(f, "disabled\n");
4932097dca6SLaurent Vivier         return;
4942097dca6SLaurent Vivier     }
4952097dca6SLaurent Vivier     cpu_fprintf(f, "Base: 0x%08x Mask: 0x%08x Control: ",
4962097dca6SLaurent Vivier                 ttr & M68K_TTR_ADDR_BASE,
4972097dca6SLaurent Vivier                 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
4982097dca6SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
4992097dca6SLaurent Vivier     case M68K_TTR_SFIELD_USER:
5002097dca6SLaurent Vivier         cpu_fprintf(f, "U");
5012097dca6SLaurent Vivier         break;
5022097dca6SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
5032097dca6SLaurent Vivier         cpu_fprintf(f, "S");
5042097dca6SLaurent Vivier         break;
5052097dca6SLaurent Vivier     default:
5062097dca6SLaurent Vivier         cpu_fprintf(f, "*");
5072097dca6SLaurent Vivier         break;
5082097dca6SLaurent Vivier     }
5092097dca6SLaurent Vivier     DUMP_CACHEFLAGS(ttr);
5102097dca6SLaurent Vivier     if (ttr & M68K_DESC_WRITEPROT) {
5112097dca6SLaurent Vivier         cpu_fprintf(f, "R");
5122097dca6SLaurent Vivier     } else {
5132097dca6SLaurent Vivier         cpu_fprintf(f, "W");
5142097dca6SLaurent Vivier     }
5152097dca6SLaurent Vivier     cpu_fprintf(f, " U: %d\n", (ttr & M68K_DESC_USERATTR) >>
5162097dca6SLaurent Vivier                                M68K_DESC_USERATTR_SHIFT);
5172097dca6SLaurent Vivier }
5182097dca6SLaurent Vivier 
5192097dca6SLaurent Vivier void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env)
5202097dca6SLaurent Vivier {
5212097dca6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
5222097dca6SLaurent Vivier         cpu_fprintf(f, "Translation disabled\n");
5232097dca6SLaurent Vivier         return;
5242097dca6SLaurent Vivier     }
5252097dca6SLaurent Vivier     cpu_fprintf(f, "Page Size: ");
5262097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
5272097dca6SLaurent Vivier         cpu_fprintf(f, "8kB\n");
5282097dca6SLaurent Vivier     } else {
5292097dca6SLaurent Vivier         cpu_fprintf(f, "4kB\n");
5302097dca6SLaurent Vivier     }
5312097dca6SLaurent Vivier 
5322097dca6SLaurent Vivier     cpu_fprintf(f, "MMUSR: ");
5332097dca6SLaurent Vivier     if (env->mmu.mmusr & M68K_MMU_B_040) {
5342097dca6SLaurent Vivier         cpu_fprintf(f, "BUS ERROR\n");
5352097dca6SLaurent Vivier     } else {
5362097dca6SLaurent Vivier         cpu_fprintf(f, "Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
5372097dca6SLaurent Vivier         /* flags found on the page descriptor */
5382097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_G_040) {
5392097dca6SLaurent Vivier             cpu_fprintf(f, "G"); /* Global */
5402097dca6SLaurent Vivier         } else {
5412097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5422097dca6SLaurent Vivier         }
5432097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_S_040) {
5442097dca6SLaurent Vivier             cpu_fprintf(f, "S"); /* Supervisor */
5452097dca6SLaurent Vivier         } else {
5462097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5472097dca6SLaurent Vivier         }
5482097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_M_040) {
5492097dca6SLaurent Vivier             cpu_fprintf(f, "M"); /* Modified */
5502097dca6SLaurent Vivier         } else {
5512097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5522097dca6SLaurent Vivier         }
5532097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_WP_040) {
5542097dca6SLaurent Vivier             cpu_fprintf(f, "W"); /* Write protect */
5552097dca6SLaurent Vivier         } else {
5562097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5572097dca6SLaurent Vivier         }
5582097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_T_040) {
5592097dca6SLaurent Vivier             cpu_fprintf(f, "T"); /* Transparent */
5602097dca6SLaurent Vivier         } else {
5612097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5622097dca6SLaurent Vivier         }
5632097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_R_040) {
5642097dca6SLaurent Vivier             cpu_fprintf(f, "R"); /* Resident */
5652097dca6SLaurent Vivier         } else {
5662097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5672097dca6SLaurent Vivier         }
5682097dca6SLaurent Vivier         cpu_fprintf(f, " Cache: ");
5692097dca6SLaurent Vivier         DUMP_CACHEFLAGS(env->mmu.mmusr);
5702097dca6SLaurent Vivier         cpu_fprintf(f, " U: %d\n", (env->mmu.mmusr >> 8) & 3);
5712097dca6SLaurent Vivier         cpu_fprintf(f, "\n");
5722097dca6SLaurent Vivier     }
5732097dca6SLaurent Vivier 
5742097dca6SLaurent Vivier     cpu_fprintf(f, "ITTR0: ");
5752097dca6SLaurent Vivier     dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR0]);
5762097dca6SLaurent Vivier     cpu_fprintf(f, "ITTR1: ");
5772097dca6SLaurent Vivier     dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR1]);
5782097dca6SLaurent Vivier     cpu_fprintf(f, "DTTR0: ");
5792097dca6SLaurent Vivier     dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR0]);
5802097dca6SLaurent Vivier     cpu_fprintf(f, "DTTR1: ");
5812097dca6SLaurent Vivier     dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR1]);
5822097dca6SLaurent Vivier 
5832097dca6SLaurent Vivier     cpu_fprintf(f, "SRP: 0x%08x\n", env->mmu.srp);
5842097dca6SLaurent Vivier     dump_address_map(f, cpu_fprintf, env, env->mmu.srp);
5852097dca6SLaurent Vivier 
5862097dca6SLaurent Vivier     cpu_fprintf(f, "URP: 0x%08x\n", env->mmu.urp);
5872097dca6SLaurent Vivier     dump_address_map(f, cpu_fprintf, env, env->mmu.urp);
5882097dca6SLaurent Vivier }
5892097dca6SLaurent Vivier 
590c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
591c05c73b0SLaurent Vivier                      int access_type)
592c05c73b0SLaurent Vivier {
593c05c73b0SLaurent Vivier     uint32_t base, mask;
594c05c73b0SLaurent Vivier 
595c05c73b0SLaurent Vivier     /* check if transparent translation is enabled */
596c05c73b0SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
597c05c73b0SLaurent Vivier         return 0;
598c05c73b0SLaurent Vivier     }
599c05c73b0SLaurent Vivier 
600c05c73b0SLaurent Vivier     /* check mode access */
601c05c73b0SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
602c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_USER:
603c05c73b0SLaurent Vivier         /* match only if user */
604c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) != 0) {
605c05c73b0SLaurent Vivier             return 0;
606c05c73b0SLaurent Vivier         }
607c05c73b0SLaurent Vivier         break;
608c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
609c05c73b0SLaurent Vivier         /* match only if supervisor */
610c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
611c05c73b0SLaurent Vivier             return 0;
612c05c73b0SLaurent Vivier         }
613c05c73b0SLaurent Vivier         break;
614c05c73b0SLaurent Vivier     default:
615c05c73b0SLaurent Vivier         /* all other values disable mode matching (FC2) */
616c05c73b0SLaurent Vivier         break;
617c05c73b0SLaurent Vivier     }
618c05c73b0SLaurent Vivier 
619c05c73b0SLaurent Vivier     /* check address matching */
620c05c73b0SLaurent Vivier 
621c05c73b0SLaurent Vivier     base = ttr & M68K_TTR_ADDR_BASE;
622c05c73b0SLaurent Vivier     mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
623c05c73b0SLaurent Vivier     mask <<= M68K_TTR_ADDR_MASK_SHIFT;
624c05c73b0SLaurent Vivier 
625c05c73b0SLaurent Vivier     if ((addr & mask) != (base & mask)) {
626c05c73b0SLaurent Vivier         return 0;
627c05c73b0SLaurent Vivier     }
628c05c73b0SLaurent Vivier 
629c05c73b0SLaurent Vivier     *prot = PAGE_READ | PAGE_EXEC;
630c05c73b0SLaurent Vivier     if ((ttr & M68K_DESC_WRITEPROT) == 0) {
631c05c73b0SLaurent Vivier         *prot |= PAGE_WRITE;
632c05c73b0SLaurent Vivier     }
633c05c73b0SLaurent Vivier 
634c05c73b0SLaurent Vivier     return 1;
635c05c73b0SLaurent Vivier }
636c05c73b0SLaurent Vivier 
63788b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical,
63888b2fef6SLaurent Vivier                                 int *prot, target_ulong address,
63988b2fef6SLaurent Vivier                                 int access_type, target_ulong *page_size)
64088b2fef6SLaurent Vivier {
64188b2fef6SLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
64288b2fef6SLaurent Vivier     CPUState *cs = CPU(cpu);
64388b2fef6SLaurent Vivier     uint32_t entry;
64488b2fef6SLaurent Vivier     uint32_t next;
64588b2fef6SLaurent Vivier     target_ulong page_mask;
64688b2fef6SLaurent Vivier     bool debug = access_type & ACCESS_DEBUG;
64788b2fef6SLaurent Vivier     int page_bits;
648c05c73b0SLaurent Vivier     int i;
649c05c73b0SLaurent Vivier 
650c05c73b0SLaurent Vivier     /* Transparent Translation (physical = logical) */
651c05c73b0SLaurent Vivier     for (i = 0; i < M68K_MAX_TTR; i++) {
652c05c73b0SLaurent Vivier         if (check_TTR(env->mmu.TTR(access_type, i),
653c05c73b0SLaurent Vivier                       prot, address, access_type)) {
654e55886c3SLaurent Vivier             if (access_type & ACCESS_PTEST) {
655e55886c3SLaurent Vivier                 /* Transparent Translation Register bit */
656e55886c3SLaurent Vivier                 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
657e55886c3SLaurent Vivier             }
658c05c73b0SLaurent Vivier             *physical = address & TARGET_PAGE_MASK;
659c05c73b0SLaurent Vivier             *page_size = TARGET_PAGE_SIZE;
660c05c73b0SLaurent Vivier             return 0;
661c05c73b0SLaurent Vivier         }
662c05c73b0SLaurent Vivier     }
66388b2fef6SLaurent Vivier 
66488b2fef6SLaurent Vivier     /* Page Table Root Pointer */
66588b2fef6SLaurent Vivier     *prot = PAGE_READ | PAGE_WRITE;
66688b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
66788b2fef6SLaurent Vivier         *prot |= PAGE_EXEC;
66888b2fef6SLaurent Vivier     }
66988b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
67088b2fef6SLaurent Vivier         next = env->mmu.srp;
67188b2fef6SLaurent Vivier     } else {
67288b2fef6SLaurent Vivier         next = env->mmu.urp;
67388b2fef6SLaurent Vivier     }
67488b2fef6SLaurent Vivier 
67588b2fef6SLaurent Vivier     /* Root Index */
67688b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
67788b2fef6SLaurent Vivier 
67888b2fef6SLaurent Vivier     next = ldl_phys(cs->as, entry);
67988b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
68088b2fef6SLaurent Vivier         return -1;
68188b2fef6SLaurent Vivier     }
68288b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
68388b2fef6SLaurent Vivier         stl_phys(cs->as, entry, next | M68K_DESC_USED);
68488b2fef6SLaurent Vivier     }
68588b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
686e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
687e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
688e55886c3SLaurent Vivier         }
68988b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
69088b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
69188b2fef6SLaurent Vivier             return -1;
69288b2fef6SLaurent Vivier         }
69388b2fef6SLaurent Vivier     }
69488b2fef6SLaurent Vivier 
69588b2fef6SLaurent Vivier     /* Pointer Index */
69688b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
69788b2fef6SLaurent Vivier 
69888b2fef6SLaurent Vivier     next = ldl_phys(cs->as, entry);
69988b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
70088b2fef6SLaurent Vivier         return -1;
70188b2fef6SLaurent Vivier     }
70288b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
70388b2fef6SLaurent Vivier         stl_phys(cs->as, entry, next | M68K_DESC_USED);
70488b2fef6SLaurent Vivier     }
70588b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
706e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
707e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
708e55886c3SLaurent Vivier         }
70988b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
71088b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
71188b2fef6SLaurent Vivier             return -1;
71288b2fef6SLaurent Vivier         }
71388b2fef6SLaurent Vivier     }
71488b2fef6SLaurent Vivier 
71588b2fef6SLaurent Vivier     /* Page Index */
71688b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
71788b2fef6SLaurent Vivier         entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
71888b2fef6SLaurent Vivier     } else {
71988b2fef6SLaurent Vivier         entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
72088b2fef6SLaurent Vivier     }
72188b2fef6SLaurent Vivier 
72288b2fef6SLaurent Vivier     next = ldl_phys(cs->as, entry);
72388b2fef6SLaurent Vivier 
72488b2fef6SLaurent Vivier     if (!M68K_PDT_VALID(next)) {
72588b2fef6SLaurent Vivier         return -1;
72688b2fef6SLaurent Vivier     }
72788b2fef6SLaurent Vivier     if (M68K_PDT_INDIRECT(next)) {
72888b2fef6SLaurent Vivier         next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next));
72988b2fef6SLaurent Vivier     }
73088b2fef6SLaurent Vivier     if (access_type & ACCESS_STORE) {
73188b2fef6SLaurent Vivier         if (next & M68K_DESC_WRITEPROT) {
73288b2fef6SLaurent Vivier             if (!(next & M68K_DESC_USED) && !debug) {
73388b2fef6SLaurent Vivier                 stl_phys(cs->as, entry, next | M68K_DESC_USED);
73488b2fef6SLaurent Vivier             }
73588b2fef6SLaurent Vivier         } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
73688b2fef6SLaurent Vivier                            (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
73788b2fef6SLaurent Vivier                 stl_phys(cs->as, entry,
73888b2fef6SLaurent Vivier                          next | (M68K_DESC_MODIFIED | M68K_DESC_USED));
73988b2fef6SLaurent Vivier         }
74088b2fef6SLaurent Vivier     } else {
74188b2fef6SLaurent Vivier         if (!(next & M68K_DESC_USED) && !debug) {
74288b2fef6SLaurent Vivier             stl_phys(cs->as, entry, next | M68K_DESC_USED);
74388b2fef6SLaurent Vivier         }
74488b2fef6SLaurent Vivier     }
74588b2fef6SLaurent Vivier 
74688b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
74788b2fef6SLaurent Vivier         page_bits = 13;
74888b2fef6SLaurent Vivier     } else {
74988b2fef6SLaurent Vivier         page_bits = 12;
75088b2fef6SLaurent Vivier     }
75188b2fef6SLaurent Vivier     *page_size = 1 << page_bits;
75288b2fef6SLaurent Vivier     page_mask = ~(*page_size - 1);
75388b2fef6SLaurent Vivier     *physical = next & page_mask;
75488b2fef6SLaurent Vivier 
755e55886c3SLaurent Vivier     if (access_type & ACCESS_PTEST) {
756e55886c3SLaurent Vivier         env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
757e55886c3SLaurent Vivier         env->mmu.mmusr |= *physical & 0xfffff000;
758e55886c3SLaurent Vivier         env->mmu.mmusr |= M68K_MMU_R_040;
759e55886c3SLaurent Vivier     }
760e55886c3SLaurent Vivier 
76188b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
76288b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
76388b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
76488b2fef6SLaurent Vivier             return -1;
76588b2fef6SLaurent Vivier         }
76688b2fef6SLaurent Vivier     }
76788b2fef6SLaurent Vivier     if (next & M68K_DESC_SUPERONLY) {
76888b2fef6SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
76988b2fef6SLaurent Vivier             return -1;
77088b2fef6SLaurent Vivier         }
77188b2fef6SLaurent Vivier     }
77288b2fef6SLaurent Vivier 
77388b2fef6SLaurent Vivier     return 0;
77488b2fef6SLaurent Vivier }
77588b2fef6SLaurent Vivier 
77600b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
7774fcc562bSPaul Brook {
77888b2fef6SLaurent Vivier     M68kCPU *cpu = M68K_CPU(cs);
77988b2fef6SLaurent Vivier     CPUM68KState *env = &cpu->env;
78088b2fef6SLaurent Vivier     hwaddr phys_addr;
78188b2fef6SLaurent Vivier     int prot;
78288b2fef6SLaurent Vivier     int access_type;
78388b2fef6SLaurent Vivier     target_ulong page_size;
78488b2fef6SLaurent Vivier 
78588b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
78688b2fef6SLaurent Vivier         /* MMU disabled */
7874fcc562bSPaul Brook         return addr;
7884fcc562bSPaul Brook     }
7894fcc562bSPaul Brook 
79088b2fef6SLaurent Vivier     access_type = ACCESS_DATA | ACCESS_DEBUG;
79188b2fef6SLaurent Vivier     if (env->sr & SR_S) {
79288b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
79388b2fef6SLaurent Vivier     }
79488b2fef6SLaurent Vivier     if (get_physical_address(env, &phys_addr, &prot,
79588b2fef6SLaurent Vivier                              addr, access_type, &page_size) != 0) {
79688b2fef6SLaurent Vivier         return -1;
79788b2fef6SLaurent Vivier     }
79888b2fef6SLaurent Vivier     return phys_addr;
79988b2fef6SLaurent Vivier }
80088b2fef6SLaurent Vivier 
80198670d47SLaurent Vivier int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
80297b348e7SBlue Swirl                               int mmu_idx)
8030633879fSpbrook {
80488b2fef6SLaurent Vivier     M68kCPU *cpu = M68K_CPU(cs);
80588b2fef6SLaurent Vivier     CPUM68KState *env = &cpu->env;
80688b2fef6SLaurent Vivier     hwaddr physical;
8070633879fSpbrook     int prot;
80888b2fef6SLaurent Vivier     int access_type;
80988b2fef6SLaurent Vivier     int ret;
81088b2fef6SLaurent Vivier     target_ulong page_size;
8110633879fSpbrook 
81288b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
81388b2fef6SLaurent Vivier         /* MMU disabled */
81488b2fef6SLaurent Vivier         tlb_set_page(cs, address & TARGET_PAGE_MASK,
81588b2fef6SLaurent Vivier                      address & TARGET_PAGE_MASK,
81688b2fef6SLaurent Vivier                      PAGE_READ | PAGE_WRITE | PAGE_EXEC,
81788b2fef6SLaurent Vivier                      mmu_idx, TARGET_PAGE_SIZE);
818d4c430a8SPaul Brook         return 0;
8190633879fSpbrook     }
8200633879fSpbrook 
82188b2fef6SLaurent Vivier     if (rw == 2) {
82288b2fef6SLaurent Vivier         access_type = ACCESS_CODE;
82388b2fef6SLaurent Vivier         rw = 0;
82488b2fef6SLaurent Vivier     } else {
82588b2fef6SLaurent Vivier         access_type = ACCESS_DATA;
82688b2fef6SLaurent Vivier         if (rw) {
82788b2fef6SLaurent Vivier             access_type |= ACCESS_STORE;
82888b2fef6SLaurent Vivier         }
82988b2fef6SLaurent Vivier     }
83088b2fef6SLaurent Vivier 
83188b2fef6SLaurent Vivier     if (mmu_idx != MMU_USER_IDX) {
83288b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
83388b2fef6SLaurent Vivier     }
83488b2fef6SLaurent Vivier 
83588b2fef6SLaurent Vivier     ret = get_physical_address(&cpu->env, &physical, &prot,
83688b2fef6SLaurent Vivier                                address, access_type, &page_size);
83788b2fef6SLaurent Vivier     if (ret == 0) {
83888b2fef6SLaurent Vivier         address &= TARGET_PAGE_MASK;
83988b2fef6SLaurent Vivier         physical += address & (page_size - 1);
84088b2fef6SLaurent Vivier         tlb_set_page(cs, address, physical,
84188b2fef6SLaurent Vivier                      prot, mmu_idx, TARGET_PAGE_SIZE);
84288b2fef6SLaurent Vivier         return 0;
84388b2fef6SLaurent Vivier     }
84488b2fef6SLaurent Vivier     /* page fault */
84588b2fef6SLaurent Vivier     env->mmu.ssw = M68K_ATC_040;
84688b2fef6SLaurent Vivier     switch (size) {
84788b2fef6SLaurent Vivier     case 1:
84888b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_BYTE;
84988b2fef6SLaurent Vivier         break;
85088b2fef6SLaurent Vivier     case 2:
85188b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_WORD;
85288b2fef6SLaurent Vivier         break;
85388b2fef6SLaurent Vivier     case 4:
85488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_LONG;
85588b2fef6SLaurent Vivier         break;
85688b2fef6SLaurent Vivier     }
85788b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
85888b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_SUPER;
85988b2fef6SLaurent Vivier     }
86088b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
86188b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_CODE;
86288b2fef6SLaurent Vivier     } else {
86388b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_DATA;
86488b2fef6SLaurent Vivier     }
86588b2fef6SLaurent Vivier     if (!(access_type & ACCESS_STORE)) {
86688b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_RW_040;
86788b2fef6SLaurent Vivier     }
86888b2fef6SLaurent Vivier     env->mmu.ar = address;
86988b2fef6SLaurent Vivier     cs->exception_index = EXCP_ACCESS;
87088b2fef6SLaurent Vivier     return 1;
87188b2fef6SLaurent Vivier }
87288b2fef6SLaurent Vivier 
8730633879fSpbrook /* Notify CPU of a pending interrupt.  Prioritization and vectoring should
8740633879fSpbrook    be handled by the interrupt controller.  Real hardware only requests
8750633879fSpbrook    the vector when the interrupt is acknowledged by the CPU.  For
8760633879fSpbrook    simplicitly we calculate it when the interrupt is signalled.  */
877cb3fb38eSAndreas Färber void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
8780633879fSpbrook {
879d8ed887bSAndreas Färber     CPUState *cs = CPU(cpu);
880cb3fb38eSAndreas Färber     CPUM68KState *env = &cpu->env;
881cb3fb38eSAndreas Färber 
8820633879fSpbrook     env->pending_level = level;
8830633879fSpbrook     env->pending_vector = vector;
884d8ed887bSAndreas Färber     if (level) {
885c3affe56SAndreas Färber         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
886d8ed887bSAndreas Färber     } else {
887d8ed887bSAndreas Färber         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
888d8ed887bSAndreas Färber     }
8890633879fSpbrook }
8900633879fSpbrook 
8910633879fSpbrook #endif
892e1f3808eSpbrook 
893e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x)
894e1f3808eSpbrook {
895e1f3808eSpbrook     x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
896e1f3808eSpbrook     x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
897e1f3808eSpbrook     x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
898e1f3808eSpbrook     return bswap32(x);
899e1f3808eSpbrook }
900e1f3808eSpbrook 
901e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x)
902e1f3808eSpbrook {
903e1f3808eSpbrook     int n;
904e1f3808eSpbrook     for (n = 32; x; n--)
905e1f3808eSpbrook         x >>= 1;
906e1f3808eSpbrook     return n;
907e1f3808eSpbrook }
908e1f3808eSpbrook 
909620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v)
910e1f3808eSpbrook {
911e1f3808eSpbrook     /* The result has the opposite sign to the original value.  */
912620c6cf6SRichard Henderson     if ((int32_t)v < 0) {
913e1f3808eSpbrook         val = (((int32_t)val) >> 31) ^ SIGNBIT;
914620c6cf6SRichard Henderson     }
915e1f3808eSpbrook     return val;
916e1f3808eSpbrook }
917e1f3808eSpbrook 
918d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
919e1f3808eSpbrook {
920d2f8fb8eSLaurent Vivier     env->sr = sr & 0xffe0;
921d2f8fb8eSLaurent Vivier     cpu_m68k_set_ccr(env, sr);
922e1f3808eSpbrook     m68k_switch_sp(env);
923e1f3808eSpbrook }
924e1f3808eSpbrook 
925d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
926d2f8fb8eSLaurent Vivier {
927d2f8fb8eSLaurent Vivier     cpu_m68k_set_sr(env, val);
928d2f8fb8eSLaurent Vivier }
929e1f3808eSpbrook 
930e1f3808eSpbrook /* MAC unit.  */
931e1f3808eSpbrook /* FIXME: The MAC unit implementation is a bit of a mess.  Some helpers
932e1f3808eSpbrook    take values,  others take register numbers and manipulate the contents
933e1f3808eSpbrook    in-place.  */
9342b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
935e1f3808eSpbrook {
936e1f3808eSpbrook     uint32_t mask;
937e1f3808eSpbrook     env->macc[dest] = env->macc[src];
938e1f3808eSpbrook     mask = MACSR_PAV0 << dest;
939e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << src))
940e1f3808eSpbrook         env->macsr |= mask;
941e1f3808eSpbrook     else
942e1f3808eSpbrook         env->macsr &= ~mask;
943e1f3808eSpbrook }
944e1f3808eSpbrook 
9452b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
946e1f3808eSpbrook {
947e1f3808eSpbrook     int64_t product;
948e1f3808eSpbrook     int64_t res;
949e1f3808eSpbrook 
950e1f3808eSpbrook     product = (uint64_t)op1 * op2;
951e1f3808eSpbrook     res = (product << 24) >> 24;
952e1f3808eSpbrook     if (res != product) {
953e1f3808eSpbrook         env->macsr |= MACSR_V;
954e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
955e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
956e1f3808eSpbrook             if (product < 0)
957e1f3808eSpbrook                 res = ~(1ll << 50);
958e1f3808eSpbrook             else
959e1f3808eSpbrook                 res = 1ll << 50;
960e1f3808eSpbrook         }
961e1f3808eSpbrook     }
962e1f3808eSpbrook     return res;
963e1f3808eSpbrook }
964e1f3808eSpbrook 
9652b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
966e1f3808eSpbrook {
967e1f3808eSpbrook     uint64_t product;
968e1f3808eSpbrook 
969e1f3808eSpbrook     product = (uint64_t)op1 * op2;
970e1f3808eSpbrook     if (product & (0xffffffull << 40)) {
971e1f3808eSpbrook         env->macsr |= MACSR_V;
972e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
973e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
974e1f3808eSpbrook             product = 1ll << 50;
975e1f3808eSpbrook         } else {
976e1f3808eSpbrook             product &= ((1ull << 40) - 1);
977e1f3808eSpbrook         }
978e1f3808eSpbrook     }
979e1f3808eSpbrook     return product;
980e1f3808eSpbrook }
981e1f3808eSpbrook 
9822b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
983e1f3808eSpbrook {
984e1f3808eSpbrook     uint64_t product;
985e1f3808eSpbrook     uint32_t remainder;
986e1f3808eSpbrook 
987e1f3808eSpbrook     product = (uint64_t)op1 * op2;
988e1f3808eSpbrook     if (env->macsr & MACSR_RT) {
989e1f3808eSpbrook         remainder = product & 0xffffff;
990e1f3808eSpbrook         product >>= 24;
991e1f3808eSpbrook         if (remainder > 0x800000)
992e1f3808eSpbrook             product++;
993e1f3808eSpbrook         else if (remainder == 0x800000)
994e1f3808eSpbrook             product += (product & 1);
995e1f3808eSpbrook     } else {
996e1f3808eSpbrook         product >>= 24;
997e1f3808eSpbrook     }
998e1f3808eSpbrook     return product;
999e1f3808eSpbrook }
1000e1f3808eSpbrook 
10012b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
1002e1f3808eSpbrook {
1003e1f3808eSpbrook     int64_t tmp;
1004e1f3808eSpbrook     int64_t result;
1005e1f3808eSpbrook     tmp = env->macc[acc];
1006e1f3808eSpbrook     result = ((tmp << 16) >> 16);
1007e1f3808eSpbrook     if (result != tmp) {
1008e1f3808eSpbrook         env->macsr |= MACSR_V;
1009e1f3808eSpbrook     }
1010e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1011e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1012e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1013a1c7273bSStefan Weil             /* The result is saturated to 32 bits, despite overflow occurring
1014e1f3808eSpbrook                at 48 bits.  Seems weird, but that's what the hardware docs
1015e1f3808eSpbrook                say.  */
1016e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffff;
1017e1f3808eSpbrook         }
1018e1f3808eSpbrook     }
1019e1f3808eSpbrook     env->macc[acc] = result;
1020e1f3808eSpbrook }
1021e1f3808eSpbrook 
10222b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1023e1f3808eSpbrook {
1024e1f3808eSpbrook     uint64_t val;
1025e1f3808eSpbrook 
1026e1f3808eSpbrook     val = env->macc[acc];
1027e1f3808eSpbrook     if (val & (0xffffull << 48)) {
1028e1f3808eSpbrook         env->macsr |= MACSR_V;
1029e1f3808eSpbrook     }
1030e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1031e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1032e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1033e1f3808eSpbrook             if (val > (1ull << 53))
1034e1f3808eSpbrook                 val = 0;
1035e1f3808eSpbrook             else
1036e1f3808eSpbrook                 val = (1ull << 48) - 1;
1037e1f3808eSpbrook         } else {
1038e1f3808eSpbrook             val &= ((1ull << 48) - 1);
1039e1f3808eSpbrook         }
1040e1f3808eSpbrook     }
1041e1f3808eSpbrook     env->macc[acc] = val;
1042e1f3808eSpbrook }
1043e1f3808eSpbrook 
10442b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1045e1f3808eSpbrook {
1046e1f3808eSpbrook     int64_t sum;
1047e1f3808eSpbrook     int64_t result;
1048e1f3808eSpbrook 
1049e1f3808eSpbrook     sum = env->macc[acc];
1050e1f3808eSpbrook     result = (sum << 16) >> 16;
1051e1f3808eSpbrook     if (result != sum) {
1052e1f3808eSpbrook         env->macsr |= MACSR_V;
1053e1f3808eSpbrook     }
1054e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1055e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1056e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1057e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffffffffll;
1058e1f3808eSpbrook         }
1059e1f3808eSpbrook     }
1060e1f3808eSpbrook     env->macc[acc] = result;
1061e1f3808eSpbrook }
1062e1f3808eSpbrook 
10632b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1064e1f3808eSpbrook {
1065e1f3808eSpbrook     uint64_t val;
1066e1f3808eSpbrook     val = env->macc[acc];
1067c4162574SBlue Swirl     if (val == 0) {
1068e1f3808eSpbrook         env->macsr |= MACSR_Z;
1069c4162574SBlue Swirl     } else if (val & (1ull << 47)) {
1070e1f3808eSpbrook         env->macsr |= MACSR_N;
1071c4162574SBlue Swirl     }
1072e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << acc)) {
1073e1f3808eSpbrook         env->macsr |= MACSR_V;
1074e1f3808eSpbrook     }
1075e1f3808eSpbrook     if (env->macsr & MACSR_FI) {
1076e1f3808eSpbrook         val = ((int64_t)val) >> 40;
1077e1f3808eSpbrook         if (val != 0 && val != -1)
1078e1f3808eSpbrook             env->macsr |= MACSR_EV;
1079e1f3808eSpbrook     } else if (env->macsr & MACSR_SU) {
1080e1f3808eSpbrook         val = ((int64_t)val) >> 32;
1081e1f3808eSpbrook         if (val != 0 && val != -1)
1082e1f3808eSpbrook             env->macsr |= MACSR_EV;
1083e1f3808eSpbrook     } else {
1084e1f3808eSpbrook         if ((val >> 32) != 0)
1085e1f3808eSpbrook             env->macsr |= MACSR_EV;
1086e1f3808eSpbrook     }
1087e1f3808eSpbrook }
1088e1f3808eSpbrook 
1089db3d7945SLaurent Vivier #define EXTSIGN(val, index) (     \
1090db3d7945SLaurent Vivier     (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1091db3d7945SLaurent Vivier )
1092620c6cf6SRichard Henderson 
1093620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) {                                   \
1094620c6cf6SRichard Henderson     switch (op) {                                                          \
1095620c6cf6SRichard Henderson     case CC_OP_FLAGS:                                                      \
1096620c6cf6SRichard Henderson         /* Everything in place.  */                                        \
1097620c6cf6SRichard Henderson         break;                                                             \
1098db3d7945SLaurent Vivier     case CC_OP_ADDB:                                                       \
1099db3d7945SLaurent Vivier     case CC_OP_ADDW:                                                       \
1100db3d7945SLaurent Vivier     case CC_OP_ADDL:                                                       \
1101620c6cf6SRichard Henderson         res = n;                                                           \
1102620c6cf6SRichard Henderson         src2 = v;                                                          \
1103db3d7945SLaurent Vivier         src1 = EXTSIGN(res - src2, op - CC_OP_ADDB);                       \
1104620c6cf6SRichard Henderson         c = x;                                                             \
1105620c6cf6SRichard Henderson         z = n;                                                             \
1106620c6cf6SRichard Henderson         v = (res ^ src1) & ~(src1 ^ src2);                                 \
1107620c6cf6SRichard Henderson         break;                                                             \
1108db3d7945SLaurent Vivier     case CC_OP_SUBB:                                                       \
1109db3d7945SLaurent Vivier     case CC_OP_SUBW:                                                       \
1110db3d7945SLaurent Vivier     case CC_OP_SUBL:                                                       \
1111620c6cf6SRichard Henderson         res = n;                                                           \
1112620c6cf6SRichard Henderson         src2 = v;                                                          \
1113db3d7945SLaurent Vivier         src1 = EXTSIGN(res + src2, op - CC_OP_SUBB);                       \
1114620c6cf6SRichard Henderson         c = x;                                                             \
1115620c6cf6SRichard Henderson         z = n;                                                             \
1116620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1117620c6cf6SRichard Henderson         break;                                                             \
1118db3d7945SLaurent Vivier     case CC_OP_CMPB:                                                       \
1119db3d7945SLaurent Vivier     case CC_OP_CMPW:                                                       \
1120db3d7945SLaurent Vivier     case CC_OP_CMPL:                                                       \
1121620c6cf6SRichard Henderson         src1 = n;                                                          \
1122620c6cf6SRichard Henderson         src2 = v;                                                          \
1123db3d7945SLaurent Vivier         res = EXTSIGN(src1 - src2, op - CC_OP_CMPB);                       \
1124620c6cf6SRichard Henderson         n = res;                                                           \
1125620c6cf6SRichard Henderson         z = res;                                                           \
1126620c6cf6SRichard Henderson         c = src1 < src2;                                                   \
1127620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1128620c6cf6SRichard Henderson         break;                                                             \
1129620c6cf6SRichard Henderson     case CC_OP_LOGIC:                                                      \
1130620c6cf6SRichard Henderson         c = v = 0;                                                         \
1131620c6cf6SRichard Henderson         z = n;                                                             \
1132620c6cf6SRichard Henderson         break;                                                             \
1133620c6cf6SRichard Henderson     default:                                                               \
1134620c6cf6SRichard Henderson         cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op);         \
1135620c6cf6SRichard Henderson     }                                                                      \
1136620c6cf6SRichard Henderson } while (0)
1137620c6cf6SRichard Henderson 
1138620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1139e1f3808eSpbrook {
1140620c6cf6SRichard Henderson     uint32_t x, c, n, z, v;
1141620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1142620c6cf6SRichard Henderson 
1143620c6cf6SRichard Henderson     x = env->cc_x;
1144620c6cf6SRichard Henderson     n = env->cc_n;
1145620c6cf6SRichard Henderson     z = env->cc_z;
1146620c6cf6SRichard Henderson     v = env->cc_v;
1147db3d7945SLaurent Vivier     c = env->cc_c;
1148620c6cf6SRichard Henderson 
1149620c6cf6SRichard Henderson     COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1150620c6cf6SRichard Henderson 
1151620c6cf6SRichard Henderson     n = n >> 31;
1152620c6cf6SRichard Henderson     z = (z == 0);
1153db3d7945SLaurent Vivier     v = v >> 31;
1154620c6cf6SRichard Henderson 
1155620c6cf6SRichard Henderson     return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1156620c6cf6SRichard Henderson }
1157620c6cf6SRichard Henderson 
1158620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env)
1159620c6cf6SRichard Henderson {
1160620c6cf6SRichard Henderson     return cpu_m68k_get_ccr(env);
1161620c6cf6SRichard Henderson }
1162620c6cf6SRichard Henderson 
1163620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1164620c6cf6SRichard Henderson {
1165620c6cf6SRichard Henderson     env->cc_x = (ccr & CCF_X ? 1 : 0);
1166620c6cf6SRichard Henderson     env->cc_n = (ccr & CCF_N ? -1 : 0);
1167620c6cf6SRichard Henderson     env->cc_z = (ccr & CCF_Z ? 0 : 1);
1168620c6cf6SRichard Henderson     env->cc_v = (ccr & CCF_V ? -1 : 0);
1169620c6cf6SRichard Henderson     env->cc_c = (ccr & CCF_C ? 1 : 0);
1170620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1171620c6cf6SRichard Henderson }
1172620c6cf6SRichard Henderson 
1173620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1174620c6cf6SRichard Henderson {
1175620c6cf6SRichard Henderson     cpu_m68k_set_ccr(env, ccr);
1176620c6cf6SRichard Henderson }
1177620c6cf6SRichard Henderson 
1178620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1179620c6cf6SRichard Henderson {
1180620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1181620c6cf6SRichard Henderson 
1182620c6cf6SRichard Henderson     COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1183620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1184e1f3808eSpbrook }
1185e1f3808eSpbrook 
11862b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1187e1f3808eSpbrook {
1188e1f3808eSpbrook     int rem;
1189e1f3808eSpbrook     uint32_t result;
1190e1f3808eSpbrook 
1191e1f3808eSpbrook     if (env->macsr & MACSR_SU) {
1192e1f3808eSpbrook         /* 16-bit rounding.  */
1193e1f3808eSpbrook         rem = val & 0xffffff;
1194e1f3808eSpbrook         val = (val >> 24) & 0xffffu;
1195e1f3808eSpbrook         if (rem > 0x800000)
1196e1f3808eSpbrook             val++;
1197e1f3808eSpbrook         else if (rem == 0x800000)
1198e1f3808eSpbrook             val += (val & 1);
1199e1f3808eSpbrook     } else if (env->macsr & MACSR_RT) {
1200e1f3808eSpbrook         /* 32-bit rounding.  */
1201e1f3808eSpbrook         rem = val & 0xff;
1202e1f3808eSpbrook         val >>= 8;
1203e1f3808eSpbrook         if (rem > 0x80)
1204e1f3808eSpbrook             val++;
1205e1f3808eSpbrook         else if (rem == 0x80)
1206e1f3808eSpbrook             val += (val & 1);
1207e1f3808eSpbrook     } else {
1208e1f3808eSpbrook         /* No rounding.  */
1209e1f3808eSpbrook         val >>= 8;
1210e1f3808eSpbrook     }
1211e1f3808eSpbrook     if (env->macsr & MACSR_OMC) {
1212e1f3808eSpbrook         /* Saturate.  */
1213e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1214e1f3808eSpbrook             if (val != (uint16_t) val) {
1215e1f3808eSpbrook                 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1216e1f3808eSpbrook             } else {
1217e1f3808eSpbrook                 result = val & 0xffff;
1218e1f3808eSpbrook             }
1219e1f3808eSpbrook         } else {
1220e1f3808eSpbrook             if (val != (uint32_t)val) {
1221e1f3808eSpbrook                 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1222e1f3808eSpbrook             } else {
1223e1f3808eSpbrook                 result = (uint32_t)val;
1224e1f3808eSpbrook             }
1225e1f3808eSpbrook         }
1226e1f3808eSpbrook     } else {
1227e1f3808eSpbrook         /* No saturation.  */
1228e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1229e1f3808eSpbrook             result = val & 0xffff;
1230e1f3808eSpbrook         } else {
1231e1f3808eSpbrook             result = (uint32_t)val;
1232e1f3808eSpbrook         }
1233e1f3808eSpbrook     }
1234e1f3808eSpbrook     return result;
1235e1f3808eSpbrook }
1236e1f3808eSpbrook 
1237e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val)
1238e1f3808eSpbrook {
1239e1f3808eSpbrook     if (val == (int32_t)val) {
1240e1f3808eSpbrook         return (int32_t)val;
1241e1f3808eSpbrook     } else {
1242e1f3808eSpbrook         return (val >> 61) ^ ~SIGNBIT;
1243e1f3808eSpbrook     }
1244e1f3808eSpbrook }
1245e1f3808eSpbrook 
1246e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val)
1247e1f3808eSpbrook {
1248e1f3808eSpbrook     if ((val >> 32) == 0) {
1249e1f3808eSpbrook         return (uint32_t)val;
1250e1f3808eSpbrook     } else {
1251e1f3808eSpbrook         return 0xffffffffu;
1252e1f3808eSpbrook     }
1253e1f3808eSpbrook }
1254e1f3808eSpbrook 
12552b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1256e1f3808eSpbrook {
1257e1f3808eSpbrook     uint32_t val;
1258e1f3808eSpbrook     val = env->macc[acc] & 0x00ff;
12595ce747cfSPaolo Bonzini     val |= (env->macc[acc] >> 32) & 0xff00;
1260e1f3808eSpbrook     val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1261e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1262e1f3808eSpbrook     return val;
1263e1f3808eSpbrook }
1264e1f3808eSpbrook 
12652b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1266e1f3808eSpbrook {
1267e1f3808eSpbrook     uint32_t val;
1268e1f3808eSpbrook     val = (env->macc[acc] >> 32) & 0xffff;
1269e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1270e1f3808eSpbrook     return val;
1271e1f3808eSpbrook }
1272e1f3808eSpbrook 
12732b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1274e1f3808eSpbrook {
1275e1f3808eSpbrook     int64_t res;
1276e1f3808eSpbrook     int32_t tmp;
1277e1f3808eSpbrook     res = env->macc[acc] & 0xffffffff00ull;
1278e1f3808eSpbrook     tmp = (int16_t)(val & 0xff00);
1279e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1280e1f3808eSpbrook     res |= val & 0xff;
1281e1f3808eSpbrook     env->macc[acc] = res;
1282e1f3808eSpbrook     res = env->macc[acc + 1] & 0xffffffff00ull;
1283e1f3808eSpbrook     tmp = (val & 0xff000000);
1284e1f3808eSpbrook     res |= ((int64_t)tmp) << 16;
1285e1f3808eSpbrook     res |= (val >> 16) & 0xff;
1286e1f3808eSpbrook     env->macc[acc + 1] = res;
1287e1f3808eSpbrook }
1288e1f3808eSpbrook 
12892b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
1290e1f3808eSpbrook {
1291e1f3808eSpbrook     int64_t res;
1292e1f3808eSpbrook     int32_t tmp;
1293e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1294e1f3808eSpbrook     tmp = (int16_t)val;
1295e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1296e1f3808eSpbrook     env->macc[acc] = res;
1297e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1298e1f3808eSpbrook     tmp = val & 0xffff0000;
1299e1f3808eSpbrook     res |= (int64_t)tmp << 16;
1300e1f3808eSpbrook     env->macc[acc + 1] = res;
1301e1f3808eSpbrook }
1302e1f3808eSpbrook 
13032b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
1304e1f3808eSpbrook {
1305e1f3808eSpbrook     uint64_t res;
1306e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1307e1f3808eSpbrook     res |= ((uint64_t)(val & 0xffff)) << 32;
1308e1f3808eSpbrook     env->macc[acc] = res;
1309e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1310e1f3808eSpbrook     res |= (uint64_t)(val & 0xffff0000) << 16;
1311e1f3808eSpbrook     env->macc[acc + 1] = res;
1312e1f3808eSpbrook }
13130bdb2b3bSLaurent Vivier 
13140bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU)
1315e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1316e55886c3SLaurent Vivier {
1317e55886c3SLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
1318e55886c3SLaurent Vivier     CPUState *cs = CPU(cpu);
1319e55886c3SLaurent Vivier     hwaddr physical;
1320e55886c3SLaurent Vivier     int access_type;
1321e55886c3SLaurent Vivier     int prot;
1322e55886c3SLaurent Vivier     int ret;
1323e55886c3SLaurent Vivier     target_ulong page_size;
1324e55886c3SLaurent Vivier 
1325e55886c3SLaurent Vivier     access_type = ACCESS_PTEST;
1326e55886c3SLaurent Vivier     if (env->dfc & 4) {
1327e55886c3SLaurent Vivier         access_type |= ACCESS_SUPER;
1328e55886c3SLaurent Vivier     }
1329e55886c3SLaurent Vivier     if ((env->dfc & 3) == 2) {
1330e55886c3SLaurent Vivier         access_type |= ACCESS_CODE;
1331e55886c3SLaurent Vivier     }
1332e55886c3SLaurent Vivier     if (!is_read) {
1333e55886c3SLaurent Vivier         access_type |= ACCESS_STORE;
1334e55886c3SLaurent Vivier     }
1335e55886c3SLaurent Vivier 
1336e55886c3SLaurent Vivier     env->mmu.mmusr = 0;
1337e55886c3SLaurent Vivier     env->mmu.ssw = 0;
1338e55886c3SLaurent Vivier     ret = get_physical_address(env, &physical, &prot, addr,
1339e55886c3SLaurent Vivier                                access_type, &page_size);
1340e55886c3SLaurent Vivier     if (ret == 0) {
1341e55886c3SLaurent Vivier         addr &= TARGET_PAGE_MASK;
1342e55886c3SLaurent Vivier         physical += addr & (page_size - 1);
1343e55886c3SLaurent Vivier         tlb_set_page(cs, addr, physical,
1344e55886c3SLaurent Vivier                      prot, access_type & ACCESS_SUPER ?
1345e55886c3SLaurent Vivier                      MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1346e55886c3SLaurent Vivier     }
1347e55886c3SLaurent Vivier }
1348e55886c3SLaurent Vivier 
1349e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1350e55886c3SLaurent Vivier {
1351e55886c3SLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
1352e55886c3SLaurent Vivier 
1353e55886c3SLaurent Vivier     switch (opmode) {
1354e55886c3SLaurent Vivier     case 0: /* Flush page entry if not global */
1355e55886c3SLaurent Vivier     case 1: /* Flush page entry */
1356e55886c3SLaurent Vivier         tlb_flush_page(CPU(cpu), addr);
1357e55886c3SLaurent Vivier         break;
1358e55886c3SLaurent Vivier     case 2: /* Flush all except global entries */
1359e55886c3SLaurent Vivier         tlb_flush(CPU(cpu));
1360e55886c3SLaurent Vivier         break;
1361e55886c3SLaurent Vivier     case 3: /* Flush all entries */
1362e55886c3SLaurent Vivier         tlb_flush(CPU(cpu));
1363e55886c3SLaurent Vivier         break;
1364e55886c3SLaurent Vivier     }
1365e55886c3SLaurent Vivier }
1366e55886c3SLaurent Vivier 
13670bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env)
13680bdb2b3bSLaurent Vivier {
13690bdb2b3bSLaurent Vivier     /* FIXME: reset all except CPU */
13700bdb2b3bSLaurent Vivier }
13710bdb2b3bSLaurent Vivier #endif
1372