xref: /qemu/target/m68k/helper.c (revision 18b6102e51bb317d25ee61b49b7b56702b79560c)
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"
270442428aSMarkus 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));
570442428aSMarkus Armbruster     qemu_printf("%s\n", name);
587a9f812bSAndreas Färber     g_free(name);
5911150915SAndreas Färber }
600402f767Spbrook 
610442428aSMarkus 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);
670442428aSMarkus 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 {
1710633879fSpbrook     switch (reg) {
1726e22b28eSLaurent Vivier     case M68K_CR_CACR:
17320dcee94Spbrook         env->cacr = val;
17420dcee94Spbrook         m68k_switch_sp(env);
17520dcee94Spbrook         break;
1766e22b28eSLaurent Vivier     case M68K_CR_ACR0:
1776e22b28eSLaurent Vivier     case M68K_CR_ACR1:
1786e22b28eSLaurent Vivier     case M68K_CR_ACR2:
1796e22b28eSLaurent Vivier     case M68K_CR_ACR3:
18020dcee94Spbrook         /* TODO: Implement Access Control Registers.  */
1810633879fSpbrook         break;
1826e22b28eSLaurent Vivier     case M68K_CR_VBR:
1830633879fSpbrook         env->vbr = val;
1840633879fSpbrook         break;
1850633879fSpbrook     /* TODO: Implement control registers.  */
1860633879fSpbrook     default:
187a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env),
1886e22b28eSLaurent Vivier                   "Unimplemented control register write 0x%x = 0x%x\n",
1896e22b28eSLaurent Vivier                   reg, val);
1906e22b28eSLaurent Vivier     }
1916e22b28eSLaurent Vivier }
1926e22b28eSLaurent Vivier 
1936e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
1946e22b28eSLaurent Vivier {
1956e22b28eSLaurent Vivier     switch (reg) {
1966e22b28eSLaurent Vivier     /* MC680[1234]0 */
1975fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
1985fa9f1f2SLaurent Vivier         env->sfc = val & 7;
1995fa9f1f2SLaurent Vivier         return;
2005fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
2015fa9f1f2SLaurent Vivier         env->dfc = val & 7;
2025fa9f1f2SLaurent Vivier         return;
2036e22b28eSLaurent Vivier     case M68K_CR_VBR:
2046e22b28eSLaurent Vivier         env->vbr = val;
2056e22b28eSLaurent Vivier         return;
206*18b6102eSLaurent Vivier     /* MC680[2346]0 */
2076e22b28eSLaurent Vivier     case M68K_CR_CACR:
208*18b6102eSLaurent Vivier         if (m68k_feature(env, M68K_FEATURE_M68020)) {
209*18b6102eSLaurent Vivier             env->cacr = val & 0x0000000f;
210*18b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68030)) {
211*18b6102eSLaurent Vivier             env->cacr = val & 0x00003f1f;
212*18b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68040)) {
213*18b6102eSLaurent Vivier             env->cacr = val & 0x80008000;
214*18b6102eSLaurent Vivier         } else if (m68k_feature(env, M68K_FEATURE_M68060)) {
215*18b6102eSLaurent Vivier             env->cacr = val & 0xf8e0e000;
216*18b6102eSLaurent Vivier         }
2176e22b28eSLaurent Vivier         m68k_switch_sp(env);
2186e22b28eSLaurent Vivier         return;
2196e22b28eSLaurent Vivier     /* MC680[34]0 */
22088b2fef6SLaurent Vivier     case M68K_CR_TC:
22188b2fef6SLaurent Vivier         env->mmu.tcr = val;
22288b2fef6SLaurent Vivier         return;
223e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
224e55886c3SLaurent Vivier         env->mmu.mmusr = val;
225e55886c3SLaurent Vivier         return;
22688b2fef6SLaurent Vivier     case M68K_CR_SRP:
22788b2fef6SLaurent Vivier         env->mmu.srp = val;
22888b2fef6SLaurent Vivier         return;
22988b2fef6SLaurent Vivier     case M68K_CR_URP:
23088b2fef6SLaurent Vivier         env->mmu.urp = val;
23188b2fef6SLaurent Vivier         return;
2326e22b28eSLaurent Vivier     case M68K_CR_USP:
2336e22b28eSLaurent Vivier         env->sp[M68K_USP] = val;
2346e22b28eSLaurent Vivier         return;
2356e22b28eSLaurent Vivier     case M68K_CR_MSP:
2366e22b28eSLaurent Vivier         env->sp[M68K_SSP] = val;
2376e22b28eSLaurent Vivier         return;
2386e22b28eSLaurent Vivier     case M68K_CR_ISP:
2396e22b28eSLaurent Vivier         env->sp[M68K_ISP] = val;
2406e22b28eSLaurent Vivier         return;
241c05c73b0SLaurent Vivier     /* MC68040/MC68LC040 */
242c05c73b0SLaurent Vivier     case M68K_CR_ITT0:
243c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_ITTR0] = val;
244c05c73b0SLaurent Vivier         return;
245c05c73b0SLaurent Vivier     case M68K_CR_ITT1:
246c05c73b0SLaurent Vivier          env->mmu.ttr[M68K_ITTR1] = val;
247c05c73b0SLaurent Vivier         return;
248c05c73b0SLaurent Vivier     case M68K_CR_DTT0:
249c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_DTTR0] = val;
250c05c73b0SLaurent Vivier         return;
251c05c73b0SLaurent Vivier     case M68K_CR_DTT1:
252c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_DTTR1] = val;
253c05c73b0SLaurent Vivier         return;
2546e22b28eSLaurent Vivier     }
255a8d92fd8SRichard Henderson     cpu_abort(env_cpu(env),
256a8d92fd8SRichard Henderson               "Unimplemented control register write 0x%x = 0x%x\n",
2570633879fSpbrook               reg, val);
2580633879fSpbrook }
2596e22b28eSLaurent Vivier 
2606e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
2616e22b28eSLaurent Vivier {
2626e22b28eSLaurent Vivier     switch (reg) {
2636e22b28eSLaurent Vivier     /* MC680[1234]0 */
2645fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
2655fa9f1f2SLaurent Vivier         return env->sfc;
2665fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
2675fa9f1f2SLaurent Vivier         return env->dfc;
2686e22b28eSLaurent Vivier     case M68K_CR_VBR:
2696e22b28eSLaurent Vivier         return env->vbr;
2706e22b28eSLaurent Vivier     /* MC680[234]0 */
2716e22b28eSLaurent Vivier     case M68K_CR_CACR:
2726e22b28eSLaurent Vivier         return env->cacr;
2736e22b28eSLaurent Vivier     /* MC680[34]0 */
27488b2fef6SLaurent Vivier     case M68K_CR_TC:
27588b2fef6SLaurent Vivier         return env->mmu.tcr;
276e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
277e55886c3SLaurent Vivier         return env->mmu.mmusr;
27888b2fef6SLaurent Vivier     case M68K_CR_SRP:
27988b2fef6SLaurent Vivier         return env->mmu.srp;
2806e22b28eSLaurent Vivier     case M68K_CR_USP:
2816e22b28eSLaurent Vivier         return env->sp[M68K_USP];
2826e22b28eSLaurent Vivier     case M68K_CR_MSP:
2836e22b28eSLaurent Vivier         return env->sp[M68K_SSP];
2846e22b28eSLaurent Vivier     case M68K_CR_ISP:
2856e22b28eSLaurent Vivier         return env->sp[M68K_ISP];
28688b2fef6SLaurent Vivier     /* MC68040/MC68LC040 */
28788b2fef6SLaurent Vivier     case M68K_CR_URP:
28888b2fef6SLaurent Vivier         return env->mmu.urp;
289c05c73b0SLaurent Vivier     case M68K_CR_ITT0:
290c05c73b0SLaurent Vivier         return env->mmu.ttr[M68K_ITTR0];
291c05c73b0SLaurent Vivier     case M68K_CR_ITT1:
292c05c73b0SLaurent Vivier         return env->mmu.ttr[M68K_ITTR1];
293c05c73b0SLaurent Vivier     case M68K_CR_DTT0:
294c05c73b0SLaurent Vivier         return env->mmu.ttr[M68K_DTTR0];
295c05c73b0SLaurent Vivier     case M68K_CR_DTT1:
296c05c73b0SLaurent Vivier         return env->mmu.ttr[M68K_DTTR1];
2976e22b28eSLaurent Vivier     }
298a8d92fd8SRichard Henderson     cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n",
2996e22b28eSLaurent Vivier               reg);
3000633879fSpbrook }
3010633879fSpbrook 
302e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
303acf930aaSpbrook {
304acf930aaSpbrook     uint32_t acc;
305acf930aaSpbrook     int8_t exthigh;
306acf930aaSpbrook     uint8_t extlow;
307acf930aaSpbrook     uint64_t regval;
308acf930aaSpbrook     int i;
309acf930aaSpbrook     if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
310acf930aaSpbrook         for (i = 0; i < 4; i++) {
311acf930aaSpbrook             regval = env->macc[i];
312acf930aaSpbrook             exthigh = regval >> 40;
313acf930aaSpbrook             if (env->macsr & MACSR_FI) {
314acf930aaSpbrook                 acc = regval >> 8;
315acf930aaSpbrook                 extlow = regval;
316acf930aaSpbrook             } else {
317acf930aaSpbrook                 acc = regval;
318acf930aaSpbrook                 extlow = regval >> 32;
319acf930aaSpbrook             }
320acf930aaSpbrook             if (env->macsr & MACSR_FI) {
321acf930aaSpbrook                 regval = (((uint64_t)acc) << 8) | extlow;
322acf930aaSpbrook                 regval |= ((int64_t)exthigh) << 40;
323acf930aaSpbrook             } else if (env->macsr & MACSR_SU) {
324acf930aaSpbrook                 regval = acc | (((int64_t)extlow) << 32);
325acf930aaSpbrook                 regval |= ((int64_t)exthigh) << 40;
326acf930aaSpbrook             } else {
327acf930aaSpbrook                 regval = acc | (((uint64_t)extlow) << 32);
328acf930aaSpbrook                 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
329acf930aaSpbrook             }
330acf930aaSpbrook             env->macc[i] = regval;
331acf930aaSpbrook         }
332acf930aaSpbrook     }
333acf930aaSpbrook     env->macsr = val;
334acf930aaSpbrook }
335acf930aaSpbrook 
33620dcee94Spbrook void m68k_switch_sp(CPUM68KState *env)
33720dcee94Spbrook {
33820dcee94Spbrook     int new_sp;
33920dcee94Spbrook 
34020dcee94Spbrook     env->sp[env->current_sp] = env->aregs[7];
3416e22b28eSLaurent Vivier     if (m68k_feature(env, M68K_FEATURE_M68000)) {
3426e22b28eSLaurent Vivier         if (env->sr & SR_S) {
3436e22b28eSLaurent Vivier             if (env->sr & SR_M) {
3446e22b28eSLaurent Vivier                 new_sp = M68K_SSP;
3456e22b28eSLaurent Vivier             } else {
3466e22b28eSLaurent Vivier                 new_sp = M68K_ISP;
3476e22b28eSLaurent Vivier             }
3486e22b28eSLaurent Vivier         } else {
3496e22b28eSLaurent Vivier             new_sp = M68K_USP;
3506e22b28eSLaurent Vivier         }
3516e22b28eSLaurent Vivier     } else {
35220dcee94Spbrook         new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
35320dcee94Spbrook                  ? M68K_SSP : M68K_USP;
3546e22b28eSLaurent Vivier     }
35520dcee94Spbrook     env->aregs[7] = env->sp[new_sp];
35620dcee94Spbrook     env->current_sp = new_sp;
35720dcee94Spbrook }
35820dcee94Spbrook 
359fe5f7b1bSRichard Henderson #if !defined(CONFIG_USER_ONLY)
36088b2fef6SLaurent Vivier /* MMU: 68040 only */
3614fcc562bSPaul Brook 
362fad866daSMarkus Armbruster static void print_address_zone(uint32_t logical, uint32_t physical,
3632097dca6SLaurent Vivier                                uint32_t size, int attr)
3642097dca6SLaurent Vivier {
365fad866daSMarkus Armbruster     qemu_printf("%08x - %08x -> %08x - %08x %c ",
3662097dca6SLaurent Vivier                 logical, logical + size - 1,
3672097dca6SLaurent Vivier                 physical, physical + size - 1,
3682097dca6SLaurent Vivier                 attr & 4 ? 'W' : '-');
3692097dca6SLaurent Vivier     size >>= 10;
3702097dca6SLaurent Vivier     if (size < 1024) {
371fad866daSMarkus Armbruster         qemu_printf("(%d KiB)\n", size);
3722097dca6SLaurent Vivier     } else {
3732097dca6SLaurent Vivier         size >>= 10;
3742097dca6SLaurent Vivier         if (size < 1024) {
375fad866daSMarkus Armbruster             qemu_printf("(%d MiB)\n", size);
3762097dca6SLaurent Vivier         } else {
3772097dca6SLaurent Vivier             size >>= 10;
378fad866daSMarkus Armbruster             qemu_printf("(%d GiB)\n", size);
3792097dca6SLaurent Vivier         }
3802097dca6SLaurent Vivier     }
3812097dca6SLaurent Vivier }
3822097dca6SLaurent Vivier 
383fad866daSMarkus Armbruster static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
3842097dca6SLaurent Vivier {
3852097dca6SLaurent Vivier     int i, j, k;
3862097dca6SLaurent Vivier     int tic_size, tic_shift;
3872097dca6SLaurent Vivier     uint32_t tib_mask;
3882097dca6SLaurent Vivier     uint32_t tia, tib, tic;
3892097dca6SLaurent Vivier     uint32_t logical = 0xffffffff, physical = 0xffffffff;
3902097dca6SLaurent Vivier     uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
3912097dca6SLaurent Vivier     uint32_t last_logical, last_physical;
3922097dca6SLaurent Vivier     int32_t size;
3932097dca6SLaurent Vivier     int last_attr = -1, attr = -1;
394a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
395f80b551dSPeter Maydell     MemTxResult txres;
3962097dca6SLaurent Vivier 
3972097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
3982097dca6SLaurent Vivier         /* 8k page */
3992097dca6SLaurent Vivier         tic_size = 32;
4002097dca6SLaurent Vivier         tic_shift = 13;
4012097dca6SLaurent Vivier         tib_mask = M68K_8K_PAGE_MASK;
4022097dca6SLaurent Vivier     } else {
4032097dca6SLaurent Vivier         /* 4k page */
4042097dca6SLaurent Vivier         tic_size = 64;
4052097dca6SLaurent Vivier         tic_shift = 12;
4062097dca6SLaurent Vivier         tib_mask = M68K_4K_PAGE_MASK;
4072097dca6SLaurent Vivier     }
4082097dca6SLaurent Vivier     for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
409f80b551dSPeter Maydell         tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4,
410f80b551dSPeter Maydell                                 MEMTXATTRS_UNSPECIFIED, &txres);
411f80b551dSPeter Maydell         if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) {
4122097dca6SLaurent Vivier             continue;
4132097dca6SLaurent Vivier         }
4142097dca6SLaurent Vivier         for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
415f80b551dSPeter Maydell             tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4,
416f80b551dSPeter Maydell                                     MEMTXATTRS_UNSPECIFIED, &txres);
417f80b551dSPeter Maydell             if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) {
4182097dca6SLaurent Vivier                 continue;
4192097dca6SLaurent Vivier             }
4202097dca6SLaurent Vivier             for (k = 0; k < tic_size; k++) {
421f80b551dSPeter Maydell                 tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4,
422f80b551dSPeter Maydell                                         MEMTXATTRS_UNSPECIFIED, &txres);
423f80b551dSPeter Maydell                 if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) {
4242097dca6SLaurent Vivier                     continue;
4252097dca6SLaurent Vivier                 }
4262097dca6SLaurent Vivier                 if (M68K_PDT_INDIRECT(tic)) {
427f80b551dSPeter Maydell                     tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic),
428f80b551dSPeter Maydell                                             MEMTXATTRS_UNSPECIFIED, &txres);
429f80b551dSPeter Maydell                     if (txres != MEMTX_OK) {
430f80b551dSPeter Maydell                         continue;
431f80b551dSPeter Maydell                     }
4322097dca6SLaurent Vivier                 }
4332097dca6SLaurent Vivier 
4342097dca6SLaurent Vivier                 last_logical = logical;
4352097dca6SLaurent Vivier                 logical = (i << M68K_TTS_ROOT_SHIFT) |
4362097dca6SLaurent Vivier                           (j << M68K_TTS_POINTER_SHIFT) |
4372097dca6SLaurent Vivier                           (k << tic_shift);
4382097dca6SLaurent Vivier 
4392097dca6SLaurent Vivier                 last_physical = physical;
4402097dca6SLaurent Vivier                 physical = tic & ~((1 << tic_shift) - 1);
4412097dca6SLaurent Vivier 
4422097dca6SLaurent Vivier                 last_attr = attr;
4432097dca6SLaurent Vivier                 attr = tic & ((1 << tic_shift) - 1);
4442097dca6SLaurent Vivier 
4452097dca6SLaurent Vivier                 if ((logical != (last_logical + (1 << tic_shift))) ||
4462097dca6SLaurent Vivier                     (physical != (last_physical + (1 << tic_shift))) ||
4472097dca6SLaurent Vivier                     (attr & 4) != (last_attr & 4)) {
4482097dca6SLaurent Vivier 
4492097dca6SLaurent Vivier                     if (first_logical != 0xffffffff) {
4502097dca6SLaurent Vivier                         size = last_logical + (1 << tic_shift) -
4512097dca6SLaurent Vivier                                first_logical;
452fad866daSMarkus Armbruster                         print_address_zone(first_logical,
4532097dca6SLaurent Vivier                                            first_physical, size, last_attr);
4542097dca6SLaurent Vivier                     }
4552097dca6SLaurent Vivier                     first_logical = logical;
4562097dca6SLaurent Vivier                     first_physical = physical;
4572097dca6SLaurent Vivier                 }
4582097dca6SLaurent Vivier             }
4592097dca6SLaurent Vivier         }
4602097dca6SLaurent Vivier     }
4612097dca6SLaurent Vivier     if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
4622097dca6SLaurent Vivier         size = logical + (1 << tic_shift) - first_logical;
463fad866daSMarkus Armbruster         print_address_zone(first_logical, first_physical, size, last_attr);
4642097dca6SLaurent Vivier     }
4652097dca6SLaurent Vivier }
4662097dca6SLaurent Vivier 
4672097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \
4682097dca6SLaurent Vivier     switch (a & M68K_DESC_CACHEMODE) { \
4692097dca6SLaurent Vivier     case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
470fad866daSMarkus Armbruster         qemu_printf("T"); \
4712097dca6SLaurent Vivier         break; \
4722097dca6SLaurent Vivier     case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
473fad866daSMarkus Armbruster         qemu_printf("C"); \
4742097dca6SLaurent Vivier         break; \
4752097dca6SLaurent Vivier     case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
476fad866daSMarkus Armbruster         qemu_printf("S"); \
4772097dca6SLaurent Vivier         break; \
4782097dca6SLaurent Vivier     case M68K_DESC_CM_NCACHE: /* noncachable */ \
479fad866daSMarkus Armbruster         qemu_printf("N"); \
4802097dca6SLaurent Vivier         break; \
4812097dca6SLaurent Vivier     }
4822097dca6SLaurent Vivier 
483fad866daSMarkus Armbruster static void dump_ttr(uint32_t ttr)
4842097dca6SLaurent Vivier {
4852097dca6SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
486fad866daSMarkus Armbruster         qemu_printf("disabled\n");
4872097dca6SLaurent Vivier         return;
4882097dca6SLaurent Vivier     }
489fad866daSMarkus Armbruster     qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ",
4902097dca6SLaurent Vivier                 ttr & M68K_TTR_ADDR_BASE,
4912097dca6SLaurent Vivier                 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
4922097dca6SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
4932097dca6SLaurent Vivier     case M68K_TTR_SFIELD_USER:
494fad866daSMarkus Armbruster         qemu_printf("U");
4952097dca6SLaurent Vivier         break;
4962097dca6SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
497fad866daSMarkus Armbruster         qemu_printf("S");
4982097dca6SLaurent Vivier         break;
4992097dca6SLaurent Vivier     default:
500fad866daSMarkus Armbruster         qemu_printf("*");
5012097dca6SLaurent Vivier         break;
5022097dca6SLaurent Vivier     }
5032097dca6SLaurent Vivier     DUMP_CACHEFLAGS(ttr);
5042097dca6SLaurent Vivier     if (ttr & M68K_DESC_WRITEPROT) {
505fad866daSMarkus Armbruster         qemu_printf("R");
5062097dca6SLaurent Vivier     } else {
507fad866daSMarkus Armbruster         qemu_printf("W");
5082097dca6SLaurent Vivier     }
509fad866daSMarkus Armbruster     qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >>
5102097dca6SLaurent Vivier                                M68K_DESC_USERATTR_SHIFT);
5112097dca6SLaurent Vivier }
5122097dca6SLaurent Vivier 
513fad866daSMarkus Armbruster void dump_mmu(CPUM68KState *env)
5142097dca6SLaurent Vivier {
5152097dca6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
516fad866daSMarkus Armbruster         qemu_printf("Translation disabled\n");
5172097dca6SLaurent Vivier         return;
5182097dca6SLaurent Vivier     }
519fad866daSMarkus Armbruster     qemu_printf("Page Size: ");
5202097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
521fad866daSMarkus Armbruster         qemu_printf("8kB\n");
5222097dca6SLaurent Vivier     } else {
523fad866daSMarkus Armbruster         qemu_printf("4kB\n");
5242097dca6SLaurent Vivier     }
5252097dca6SLaurent Vivier 
526fad866daSMarkus Armbruster     qemu_printf("MMUSR: ");
5272097dca6SLaurent Vivier     if (env->mmu.mmusr & M68K_MMU_B_040) {
528fad866daSMarkus Armbruster         qemu_printf("BUS ERROR\n");
5292097dca6SLaurent Vivier     } else {
530fad866daSMarkus Armbruster         qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
5312097dca6SLaurent Vivier         /* flags found on the page descriptor */
5322097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_G_040) {
533fad866daSMarkus Armbruster             qemu_printf("G"); /* Global */
5342097dca6SLaurent Vivier         } else {
535fad866daSMarkus Armbruster             qemu_printf(".");
5362097dca6SLaurent Vivier         }
5372097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_S_040) {
538fad866daSMarkus Armbruster             qemu_printf("S"); /* Supervisor */
5392097dca6SLaurent Vivier         } else {
540fad866daSMarkus Armbruster             qemu_printf(".");
5412097dca6SLaurent Vivier         }
5422097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_M_040) {
543fad866daSMarkus Armbruster             qemu_printf("M"); /* Modified */
5442097dca6SLaurent Vivier         } else {
545fad866daSMarkus Armbruster             qemu_printf(".");
5462097dca6SLaurent Vivier         }
5472097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_WP_040) {
548fad866daSMarkus Armbruster             qemu_printf("W"); /* Write protect */
5492097dca6SLaurent Vivier         } else {
550fad866daSMarkus Armbruster             qemu_printf(".");
5512097dca6SLaurent Vivier         }
5522097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_T_040) {
553fad866daSMarkus Armbruster             qemu_printf("T"); /* Transparent */
5542097dca6SLaurent Vivier         } else {
555fad866daSMarkus Armbruster             qemu_printf(".");
5562097dca6SLaurent Vivier         }
5572097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_R_040) {
558fad866daSMarkus Armbruster             qemu_printf("R"); /* Resident */
5592097dca6SLaurent Vivier         } else {
560fad866daSMarkus Armbruster             qemu_printf(".");
5612097dca6SLaurent Vivier         }
562fad866daSMarkus Armbruster         qemu_printf(" Cache: ");
5632097dca6SLaurent Vivier         DUMP_CACHEFLAGS(env->mmu.mmusr);
564fad866daSMarkus Armbruster         qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3);
565fad866daSMarkus Armbruster         qemu_printf("\n");
5662097dca6SLaurent Vivier     }
5672097dca6SLaurent Vivier 
568fad866daSMarkus Armbruster     qemu_printf("ITTR0: ");
569fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_ITTR0]);
570fad866daSMarkus Armbruster     qemu_printf("ITTR1: ");
571fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_ITTR1]);
572fad866daSMarkus Armbruster     qemu_printf("DTTR0: ");
573fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_DTTR0]);
574fad866daSMarkus Armbruster     qemu_printf("DTTR1: ");
575fad866daSMarkus Armbruster     dump_ttr(env->mmu.ttr[M68K_DTTR1]);
5762097dca6SLaurent Vivier 
577fad866daSMarkus Armbruster     qemu_printf("SRP: 0x%08x\n", env->mmu.srp);
578fad866daSMarkus Armbruster     dump_address_map(env, env->mmu.srp);
5792097dca6SLaurent Vivier 
580fad866daSMarkus Armbruster     qemu_printf("URP: 0x%08x\n", env->mmu.urp);
581fad866daSMarkus Armbruster     dump_address_map(env, env->mmu.urp);
5822097dca6SLaurent Vivier }
5832097dca6SLaurent Vivier 
584c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
585c05c73b0SLaurent Vivier                      int access_type)
586c05c73b0SLaurent Vivier {
587c05c73b0SLaurent Vivier     uint32_t base, mask;
588c05c73b0SLaurent Vivier 
589c05c73b0SLaurent Vivier     /* check if transparent translation is enabled */
590c05c73b0SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
591c05c73b0SLaurent Vivier         return 0;
592c05c73b0SLaurent Vivier     }
593c05c73b0SLaurent Vivier 
594c05c73b0SLaurent Vivier     /* check mode access */
595c05c73b0SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
596c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_USER:
597c05c73b0SLaurent Vivier         /* match only if user */
598c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) != 0) {
599c05c73b0SLaurent Vivier             return 0;
600c05c73b0SLaurent Vivier         }
601c05c73b0SLaurent Vivier         break;
602c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
603c05c73b0SLaurent Vivier         /* match only if supervisor */
604c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
605c05c73b0SLaurent Vivier             return 0;
606c05c73b0SLaurent Vivier         }
607c05c73b0SLaurent Vivier         break;
608c05c73b0SLaurent Vivier     default:
609c05c73b0SLaurent Vivier         /* all other values disable mode matching (FC2) */
610c05c73b0SLaurent Vivier         break;
611c05c73b0SLaurent Vivier     }
612c05c73b0SLaurent Vivier 
613c05c73b0SLaurent Vivier     /* check address matching */
614c05c73b0SLaurent Vivier 
615c05c73b0SLaurent Vivier     base = ttr & M68K_TTR_ADDR_BASE;
616c05c73b0SLaurent Vivier     mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
617c05c73b0SLaurent Vivier     mask <<= M68K_TTR_ADDR_MASK_SHIFT;
618c05c73b0SLaurent Vivier 
619c05c73b0SLaurent Vivier     if ((addr & mask) != (base & mask)) {
620c05c73b0SLaurent Vivier         return 0;
621c05c73b0SLaurent Vivier     }
622c05c73b0SLaurent Vivier 
623c05c73b0SLaurent Vivier     *prot = PAGE_READ | PAGE_EXEC;
624c05c73b0SLaurent Vivier     if ((ttr & M68K_DESC_WRITEPROT) == 0) {
625c05c73b0SLaurent Vivier         *prot |= PAGE_WRITE;
626c05c73b0SLaurent Vivier     }
627c05c73b0SLaurent Vivier 
628c05c73b0SLaurent Vivier     return 1;
629c05c73b0SLaurent Vivier }
630c05c73b0SLaurent Vivier 
63188b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical,
63288b2fef6SLaurent Vivier                                 int *prot, target_ulong address,
63388b2fef6SLaurent Vivier                                 int access_type, target_ulong *page_size)
63488b2fef6SLaurent Vivier {
635a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
63688b2fef6SLaurent Vivier     uint32_t entry;
63788b2fef6SLaurent Vivier     uint32_t next;
63888b2fef6SLaurent Vivier     target_ulong page_mask;
63988b2fef6SLaurent Vivier     bool debug = access_type & ACCESS_DEBUG;
64088b2fef6SLaurent Vivier     int page_bits;
641c05c73b0SLaurent Vivier     int i;
642adcf0bf0SPeter Maydell     MemTxResult txres;
643c05c73b0SLaurent Vivier 
644c05c73b0SLaurent Vivier     /* Transparent Translation (physical = logical) */
645c05c73b0SLaurent Vivier     for (i = 0; i < M68K_MAX_TTR; i++) {
646c05c73b0SLaurent Vivier         if (check_TTR(env->mmu.TTR(access_type, i),
647c05c73b0SLaurent Vivier                       prot, address, access_type)) {
648e55886c3SLaurent Vivier             if (access_type & ACCESS_PTEST) {
649e55886c3SLaurent Vivier                 /* Transparent Translation Register bit */
650e55886c3SLaurent Vivier                 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
651e55886c3SLaurent Vivier             }
652c05c73b0SLaurent Vivier             *physical = address & TARGET_PAGE_MASK;
653c05c73b0SLaurent Vivier             *page_size = TARGET_PAGE_SIZE;
654c05c73b0SLaurent Vivier             return 0;
655c05c73b0SLaurent Vivier         }
656c05c73b0SLaurent Vivier     }
65788b2fef6SLaurent Vivier 
65888b2fef6SLaurent Vivier     /* Page Table Root Pointer */
65988b2fef6SLaurent Vivier     *prot = PAGE_READ | PAGE_WRITE;
66088b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
66188b2fef6SLaurent Vivier         *prot |= PAGE_EXEC;
66288b2fef6SLaurent Vivier     }
66388b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
66488b2fef6SLaurent Vivier         next = env->mmu.srp;
66588b2fef6SLaurent Vivier     } else {
66688b2fef6SLaurent Vivier         next = env->mmu.urp;
66788b2fef6SLaurent Vivier     }
66888b2fef6SLaurent Vivier 
66988b2fef6SLaurent Vivier     /* Root Index */
67088b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
67188b2fef6SLaurent Vivier 
672adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
673adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
674adcf0bf0SPeter Maydell         goto txfail;
675adcf0bf0SPeter Maydell     }
67688b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
67788b2fef6SLaurent Vivier         return -1;
67888b2fef6SLaurent Vivier     }
67988b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
680adcf0bf0SPeter Maydell         address_space_stl(cs->as, entry, next | M68K_DESC_USED,
681adcf0bf0SPeter Maydell                           MEMTXATTRS_UNSPECIFIED, &txres);
682adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
683adcf0bf0SPeter Maydell             goto txfail;
684adcf0bf0SPeter Maydell         }
68588b2fef6SLaurent Vivier     }
68688b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
687e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
688e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
689e55886c3SLaurent Vivier         }
69088b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
69188b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
69288b2fef6SLaurent Vivier             return -1;
69388b2fef6SLaurent Vivier         }
69488b2fef6SLaurent Vivier     }
69588b2fef6SLaurent Vivier 
69688b2fef6SLaurent Vivier     /* Pointer Index */
69788b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
69888b2fef6SLaurent Vivier 
699adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
700adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
701adcf0bf0SPeter Maydell         goto txfail;
702adcf0bf0SPeter Maydell     }
70388b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
70488b2fef6SLaurent Vivier         return -1;
70588b2fef6SLaurent Vivier     }
70688b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
707adcf0bf0SPeter Maydell         address_space_stl(cs->as, entry, next | M68K_DESC_USED,
708adcf0bf0SPeter Maydell                           MEMTXATTRS_UNSPECIFIED, &txres);
709adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
710adcf0bf0SPeter Maydell             goto txfail;
711adcf0bf0SPeter Maydell         }
71288b2fef6SLaurent Vivier     }
71388b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
714e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
715e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
716e55886c3SLaurent Vivier         }
71788b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
71888b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
71988b2fef6SLaurent Vivier             return -1;
72088b2fef6SLaurent Vivier         }
72188b2fef6SLaurent Vivier     }
72288b2fef6SLaurent Vivier 
72388b2fef6SLaurent Vivier     /* Page Index */
72488b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
72588b2fef6SLaurent Vivier         entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
72688b2fef6SLaurent Vivier     } else {
72788b2fef6SLaurent Vivier         entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
72888b2fef6SLaurent Vivier     }
72988b2fef6SLaurent Vivier 
730adcf0bf0SPeter Maydell     next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
731adcf0bf0SPeter Maydell     if (txres != MEMTX_OK) {
732adcf0bf0SPeter Maydell         goto txfail;
733adcf0bf0SPeter Maydell     }
73488b2fef6SLaurent Vivier 
73588b2fef6SLaurent Vivier     if (!M68K_PDT_VALID(next)) {
73688b2fef6SLaurent Vivier         return -1;
73788b2fef6SLaurent Vivier     }
73888b2fef6SLaurent Vivier     if (M68K_PDT_INDIRECT(next)) {
739adcf0bf0SPeter Maydell         next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next),
740adcf0bf0SPeter Maydell                                  MEMTXATTRS_UNSPECIFIED, &txres);
741adcf0bf0SPeter Maydell         if (txres != MEMTX_OK) {
742adcf0bf0SPeter Maydell             goto txfail;
743adcf0bf0SPeter Maydell         }
74488b2fef6SLaurent Vivier     }
74588b2fef6SLaurent Vivier     if (access_type & ACCESS_STORE) {
74688b2fef6SLaurent Vivier         if (next & M68K_DESC_WRITEPROT) {
74788b2fef6SLaurent Vivier             if (!(next & M68K_DESC_USED) && !debug) {
748adcf0bf0SPeter Maydell                 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
749adcf0bf0SPeter Maydell                                   MEMTXATTRS_UNSPECIFIED, &txres);
750adcf0bf0SPeter Maydell                 if (txres != MEMTX_OK) {
751adcf0bf0SPeter Maydell                     goto txfail;
752adcf0bf0SPeter Maydell                 }
75388b2fef6SLaurent Vivier             }
75488b2fef6SLaurent Vivier         } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
75588b2fef6SLaurent Vivier                            (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
756adcf0bf0SPeter Maydell             address_space_stl(cs->as, entry,
757adcf0bf0SPeter Maydell                               next | (M68K_DESC_MODIFIED | M68K_DESC_USED),
758adcf0bf0SPeter Maydell                               MEMTXATTRS_UNSPECIFIED, &txres);
759adcf0bf0SPeter Maydell             if (txres != MEMTX_OK) {
760adcf0bf0SPeter Maydell                 goto txfail;
761adcf0bf0SPeter Maydell             }
76288b2fef6SLaurent Vivier         }
76388b2fef6SLaurent Vivier     } else {
76488b2fef6SLaurent Vivier         if (!(next & M68K_DESC_USED) && !debug) {
765adcf0bf0SPeter Maydell             address_space_stl(cs->as, entry, next | M68K_DESC_USED,
766adcf0bf0SPeter Maydell                               MEMTXATTRS_UNSPECIFIED, &txres);
767adcf0bf0SPeter Maydell             if (txres != MEMTX_OK) {
768adcf0bf0SPeter Maydell                 goto txfail;
769adcf0bf0SPeter Maydell             }
77088b2fef6SLaurent Vivier         }
77188b2fef6SLaurent Vivier     }
77288b2fef6SLaurent Vivier 
77388b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
77488b2fef6SLaurent Vivier         page_bits = 13;
77588b2fef6SLaurent Vivier     } else {
77688b2fef6SLaurent Vivier         page_bits = 12;
77788b2fef6SLaurent Vivier     }
77888b2fef6SLaurent Vivier     *page_size = 1 << page_bits;
77988b2fef6SLaurent Vivier     page_mask = ~(*page_size - 1);
78088b2fef6SLaurent Vivier     *physical = next & page_mask;
78188b2fef6SLaurent Vivier 
782e55886c3SLaurent Vivier     if (access_type & ACCESS_PTEST) {
783e55886c3SLaurent Vivier         env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
784e55886c3SLaurent Vivier         env->mmu.mmusr |= *physical & 0xfffff000;
785e55886c3SLaurent Vivier         env->mmu.mmusr |= M68K_MMU_R_040;
786e55886c3SLaurent Vivier     }
787e55886c3SLaurent Vivier 
78888b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
78988b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
79088b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
79188b2fef6SLaurent Vivier             return -1;
79288b2fef6SLaurent Vivier         }
79388b2fef6SLaurent Vivier     }
79488b2fef6SLaurent Vivier     if (next & M68K_DESC_SUPERONLY) {
79588b2fef6SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
79688b2fef6SLaurent Vivier             return -1;
79788b2fef6SLaurent Vivier         }
79888b2fef6SLaurent Vivier     }
79988b2fef6SLaurent Vivier 
80088b2fef6SLaurent Vivier     return 0;
801adcf0bf0SPeter Maydell 
802adcf0bf0SPeter Maydell txfail:
803adcf0bf0SPeter Maydell     /*
804adcf0bf0SPeter Maydell      * A page table load/store failed. TODO: we should really raise a
805adcf0bf0SPeter Maydell      * suitable guest fault here if this is not a debug access.
806adcf0bf0SPeter Maydell      * For now just return that the translation failed.
807adcf0bf0SPeter Maydell      */
808adcf0bf0SPeter Maydell     return -1;
80988b2fef6SLaurent Vivier }
81088b2fef6SLaurent Vivier 
81100b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
8124fcc562bSPaul Brook {
81388b2fef6SLaurent Vivier     M68kCPU *cpu = M68K_CPU(cs);
81488b2fef6SLaurent Vivier     CPUM68KState *env = &cpu->env;
81588b2fef6SLaurent Vivier     hwaddr phys_addr;
81688b2fef6SLaurent Vivier     int prot;
81788b2fef6SLaurent Vivier     int access_type;
81888b2fef6SLaurent Vivier     target_ulong page_size;
81988b2fef6SLaurent Vivier 
82088b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
82188b2fef6SLaurent Vivier         /* MMU disabled */
8224fcc562bSPaul Brook         return addr;
8234fcc562bSPaul Brook     }
8244fcc562bSPaul Brook 
82588b2fef6SLaurent Vivier     access_type = ACCESS_DATA | ACCESS_DEBUG;
82688b2fef6SLaurent Vivier     if (env->sr & SR_S) {
82788b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
82888b2fef6SLaurent Vivier     }
82988b2fef6SLaurent Vivier     if (get_physical_address(env, &phys_addr, &prot,
83088b2fef6SLaurent Vivier                              addr, access_type, &page_size) != 0) {
83188b2fef6SLaurent Vivier         return -1;
83288b2fef6SLaurent Vivier     }
83388b2fef6SLaurent Vivier     return phys_addr;
83488b2fef6SLaurent Vivier }
83588b2fef6SLaurent Vivier 
836fe5f7b1bSRichard Henderson /*
837fe5f7b1bSRichard Henderson  * Notify CPU of a pending interrupt.  Prioritization and vectoring should
838fe5f7b1bSRichard Henderson  * be handled by the interrupt controller.  Real hardware only requests
839fe5f7b1bSRichard Henderson  * the vector when the interrupt is acknowledged by the CPU.  For
840fe5f7b1bSRichard Henderson  * simplicity we calculate it when the interrupt is signalled.
841fe5f7b1bSRichard Henderson  */
842fe5f7b1bSRichard Henderson void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
843fe5f7b1bSRichard Henderson {
844fe5f7b1bSRichard Henderson     CPUState *cs = CPU(cpu);
845fe5f7b1bSRichard Henderson     CPUM68KState *env = &cpu->env;
846fe5f7b1bSRichard Henderson 
847fe5f7b1bSRichard Henderson     env->pending_level = level;
848fe5f7b1bSRichard Henderson     env->pending_vector = vector;
849fe5f7b1bSRichard Henderson     if (level) {
850fe5f7b1bSRichard Henderson         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
851fe5f7b1bSRichard Henderson     } else {
852fe5f7b1bSRichard Henderson         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
853fe5f7b1bSRichard Henderson     }
854fe5f7b1bSRichard Henderson }
855fe5f7b1bSRichard Henderson 
856fe5f7b1bSRichard Henderson #endif
857fe5f7b1bSRichard Henderson 
858fe5f7b1bSRichard Henderson bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
859fe5f7b1bSRichard Henderson                        MMUAccessType qemu_access_type, int mmu_idx,
860fe5f7b1bSRichard Henderson                        bool probe, uintptr_t retaddr)
8610633879fSpbrook {
86288b2fef6SLaurent Vivier     M68kCPU *cpu = M68K_CPU(cs);
86388b2fef6SLaurent Vivier     CPUM68KState *env = &cpu->env;
864fe5f7b1bSRichard Henderson 
865fe5f7b1bSRichard Henderson #ifndef CONFIG_USER_ONLY
86688b2fef6SLaurent Vivier     hwaddr physical;
8670633879fSpbrook     int prot;
86888b2fef6SLaurent Vivier     int access_type;
86988b2fef6SLaurent Vivier     int ret;
87088b2fef6SLaurent Vivier     target_ulong page_size;
8710633879fSpbrook 
87288b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
87388b2fef6SLaurent Vivier         /* MMU disabled */
87488b2fef6SLaurent Vivier         tlb_set_page(cs, address & TARGET_PAGE_MASK,
87588b2fef6SLaurent Vivier                      address & TARGET_PAGE_MASK,
87688b2fef6SLaurent Vivier                      PAGE_READ | PAGE_WRITE | PAGE_EXEC,
87788b2fef6SLaurent Vivier                      mmu_idx, TARGET_PAGE_SIZE);
878fe5f7b1bSRichard Henderson         return true;
8790633879fSpbrook     }
8800633879fSpbrook 
881fe5f7b1bSRichard Henderson     if (qemu_access_type == MMU_INST_FETCH) {
88288b2fef6SLaurent Vivier         access_type = ACCESS_CODE;
88388b2fef6SLaurent Vivier     } else {
88488b2fef6SLaurent Vivier         access_type = ACCESS_DATA;
885fe5f7b1bSRichard Henderson         if (qemu_access_type == MMU_DATA_STORE) {
88688b2fef6SLaurent Vivier             access_type |= ACCESS_STORE;
88788b2fef6SLaurent Vivier         }
88888b2fef6SLaurent Vivier     }
88988b2fef6SLaurent Vivier     if (mmu_idx != MMU_USER_IDX) {
89088b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
89188b2fef6SLaurent Vivier     }
89288b2fef6SLaurent Vivier 
89388b2fef6SLaurent Vivier     ret = get_physical_address(&cpu->env, &physical, &prot,
89488b2fef6SLaurent Vivier                                address, access_type, &page_size);
895fe5f7b1bSRichard Henderson     if (likely(ret == 0)) {
89688b2fef6SLaurent Vivier         address &= TARGET_PAGE_MASK;
89788b2fef6SLaurent Vivier         physical += address & (page_size - 1);
89888b2fef6SLaurent Vivier         tlb_set_page(cs, address, physical,
89988b2fef6SLaurent Vivier                      prot, mmu_idx, TARGET_PAGE_SIZE);
900fe5f7b1bSRichard Henderson         return true;
90188b2fef6SLaurent Vivier     }
902fe5f7b1bSRichard Henderson 
903fe5f7b1bSRichard Henderson     if (probe) {
904fe5f7b1bSRichard Henderson         return false;
905fe5f7b1bSRichard Henderson     }
906fe5f7b1bSRichard Henderson 
90788b2fef6SLaurent Vivier     /* page fault */
90888b2fef6SLaurent Vivier     env->mmu.ssw = M68K_ATC_040;
90988b2fef6SLaurent Vivier     switch (size) {
91088b2fef6SLaurent Vivier     case 1:
91188b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_BYTE;
91288b2fef6SLaurent Vivier         break;
91388b2fef6SLaurent Vivier     case 2:
91488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_WORD;
91588b2fef6SLaurent Vivier         break;
91688b2fef6SLaurent Vivier     case 4:
91788b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_LONG;
91888b2fef6SLaurent Vivier         break;
91988b2fef6SLaurent Vivier     }
92088b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
92188b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_SUPER;
92288b2fef6SLaurent Vivier     }
92388b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
92488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_CODE;
92588b2fef6SLaurent Vivier     } else {
92688b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_DATA;
92788b2fef6SLaurent Vivier     }
92888b2fef6SLaurent Vivier     if (!(access_type & ACCESS_STORE)) {
92988b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_RW_040;
93088b2fef6SLaurent Vivier     }
931fe5f7b1bSRichard Henderson #endif
932fe5f7b1bSRichard Henderson 
93388b2fef6SLaurent Vivier     cs->exception_index = EXCP_ACCESS;
934fe5f7b1bSRichard Henderson     env->mmu.ar = address;
935fe5f7b1bSRichard Henderson     cpu_loop_exit_restore(cs, retaddr);
93688b2fef6SLaurent Vivier }
93788b2fef6SLaurent Vivier 
938e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x)
939e1f3808eSpbrook {
940e1f3808eSpbrook     x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
941e1f3808eSpbrook     x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
942e1f3808eSpbrook     x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
943e1f3808eSpbrook     return bswap32(x);
944e1f3808eSpbrook }
945e1f3808eSpbrook 
946e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x)
947e1f3808eSpbrook {
948e1f3808eSpbrook     int n;
949e1f3808eSpbrook     for (n = 32; x; n--)
950e1f3808eSpbrook         x >>= 1;
951e1f3808eSpbrook     return n;
952e1f3808eSpbrook }
953e1f3808eSpbrook 
954620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v)
955e1f3808eSpbrook {
956e1f3808eSpbrook     /* The result has the opposite sign to the original value.  */
957620c6cf6SRichard Henderson     if ((int32_t)v < 0) {
958e1f3808eSpbrook         val = (((int32_t)val) >> 31) ^ SIGNBIT;
959620c6cf6SRichard Henderson     }
960e1f3808eSpbrook     return val;
961e1f3808eSpbrook }
962e1f3808eSpbrook 
963d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
964e1f3808eSpbrook {
965d2f8fb8eSLaurent Vivier     env->sr = sr & 0xffe0;
966d2f8fb8eSLaurent Vivier     cpu_m68k_set_ccr(env, sr);
967e1f3808eSpbrook     m68k_switch_sp(env);
968e1f3808eSpbrook }
969e1f3808eSpbrook 
970d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
971d2f8fb8eSLaurent Vivier {
972d2f8fb8eSLaurent Vivier     cpu_m68k_set_sr(env, val);
973d2f8fb8eSLaurent Vivier }
974e1f3808eSpbrook 
975e1f3808eSpbrook /* MAC unit.  */
976808d77bcSLucien Murray-Pitts /*
977808d77bcSLucien Murray-Pitts  * FIXME: The MAC unit implementation is a bit of a mess.  Some helpers
978808d77bcSLucien Murray-Pitts  * take values,  others take register numbers and manipulate the contents
979808d77bcSLucien Murray-Pitts  * in-place.
980808d77bcSLucien Murray-Pitts  */
9812b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
982e1f3808eSpbrook {
983e1f3808eSpbrook     uint32_t mask;
984e1f3808eSpbrook     env->macc[dest] = env->macc[src];
985e1f3808eSpbrook     mask = MACSR_PAV0 << dest;
986e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << src))
987e1f3808eSpbrook         env->macsr |= mask;
988e1f3808eSpbrook     else
989e1f3808eSpbrook         env->macsr &= ~mask;
990e1f3808eSpbrook }
991e1f3808eSpbrook 
9922b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
993e1f3808eSpbrook {
994e1f3808eSpbrook     int64_t product;
995e1f3808eSpbrook     int64_t res;
996e1f3808eSpbrook 
997e1f3808eSpbrook     product = (uint64_t)op1 * op2;
998e1f3808eSpbrook     res = (product << 24) >> 24;
999e1f3808eSpbrook     if (res != product) {
1000e1f3808eSpbrook         env->macsr |= MACSR_V;
1001e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1002e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
1003e1f3808eSpbrook             if (product < 0)
1004e1f3808eSpbrook                 res = ~(1ll << 50);
1005e1f3808eSpbrook             else
1006e1f3808eSpbrook                 res = 1ll << 50;
1007e1f3808eSpbrook         }
1008e1f3808eSpbrook     }
1009e1f3808eSpbrook     return res;
1010e1f3808eSpbrook }
1011e1f3808eSpbrook 
10122b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1013e1f3808eSpbrook {
1014e1f3808eSpbrook     uint64_t product;
1015e1f3808eSpbrook 
1016e1f3808eSpbrook     product = (uint64_t)op1 * op2;
1017e1f3808eSpbrook     if (product & (0xffffffull << 40)) {
1018e1f3808eSpbrook         env->macsr |= MACSR_V;
1019e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1020e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
1021e1f3808eSpbrook             product = 1ll << 50;
1022e1f3808eSpbrook         } else {
1023e1f3808eSpbrook             product &= ((1ull << 40) - 1);
1024e1f3808eSpbrook         }
1025e1f3808eSpbrook     }
1026e1f3808eSpbrook     return product;
1027e1f3808eSpbrook }
1028e1f3808eSpbrook 
10292b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1030e1f3808eSpbrook {
1031e1f3808eSpbrook     uint64_t product;
1032e1f3808eSpbrook     uint32_t remainder;
1033e1f3808eSpbrook 
1034e1f3808eSpbrook     product = (uint64_t)op1 * op2;
1035e1f3808eSpbrook     if (env->macsr & MACSR_RT) {
1036e1f3808eSpbrook         remainder = product & 0xffffff;
1037e1f3808eSpbrook         product >>= 24;
1038e1f3808eSpbrook         if (remainder > 0x800000)
1039e1f3808eSpbrook             product++;
1040e1f3808eSpbrook         else if (remainder == 0x800000)
1041e1f3808eSpbrook             product += (product & 1);
1042e1f3808eSpbrook     } else {
1043e1f3808eSpbrook         product >>= 24;
1044e1f3808eSpbrook     }
1045e1f3808eSpbrook     return product;
1046e1f3808eSpbrook }
1047e1f3808eSpbrook 
10482b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
1049e1f3808eSpbrook {
1050e1f3808eSpbrook     int64_t tmp;
1051e1f3808eSpbrook     int64_t result;
1052e1f3808eSpbrook     tmp = env->macc[acc];
1053e1f3808eSpbrook     result = ((tmp << 16) >> 16);
1054e1f3808eSpbrook     if (result != tmp) {
1055e1f3808eSpbrook         env->macsr |= MACSR_V;
1056e1f3808eSpbrook     }
1057e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1058e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1059e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1060808d77bcSLucien Murray-Pitts             /*
1061808d77bcSLucien Murray-Pitts              * The result is saturated to 32 bits, despite overflow occurring
1062808d77bcSLucien Murray-Pitts              * at 48 bits.  Seems weird, but that's what the hardware docs
1063808d77bcSLucien Murray-Pitts              * say.
1064808d77bcSLucien Murray-Pitts              */
1065e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffff;
1066e1f3808eSpbrook         }
1067e1f3808eSpbrook     }
1068e1f3808eSpbrook     env->macc[acc] = result;
1069e1f3808eSpbrook }
1070e1f3808eSpbrook 
10712b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1072e1f3808eSpbrook {
1073e1f3808eSpbrook     uint64_t val;
1074e1f3808eSpbrook 
1075e1f3808eSpbrook     val = env->macc[acc];
1076e1f3808eSpbrook     if (val & (0xffffull << 48)) {
1077e1f3808eSpbrook         env->macsr |= MACSR_V;
1078e1f3808eSpbrook     }
1079e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1080e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1081e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1082e1f3808eSpbrook             if (val > (1ull << 53))
1083e1f3808eSpbrook                 val = 0;
1084e1f3808eSpbrook             else
1085e1f3808eSpbrook                 val = (1ull << 48) - 1;
1086e1f3808eSpbrook         } else {
1087e1f3808eSpbrook             val &= ((1ull << 48) - 1);
1088e1f3808eSpbrook         }
1089e1f3808eSpbrook     }
1090e1f3808eSpbrook     env->macc[acc] = val;
1091e1f3808eSpbrook }
1092e1f3808eSpbrook 
10932b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1094e1f3808eSpbrook {
1095e1f3808eSpbrook     int64_t sum;
1096e1f3808eSpbrook     int64_t result;
1097e1f3808eSpbrook 
1098e1f3808eSpbrook     sum = env->macc[acc];
1099e1f3808eSpbrook     result = (sum << 16) >> 16;
1100e1f3808eSpbrook     if (result != sum) {
1101e1f3808eSpbrook         env->macsr |= MACSR_V;
1102e1f3808eSpbrook     }
1103e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1104e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1105e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1106e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffffffffll;
1107e1f3808eSpbrook         }
1108e1f3808eSpbrook     }
1109e1f3808eSpbrook     env->macc[acc] = result;
1110e1f3808eSpbrook }
1111e1f3808eSpbrook 
11122b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1113e1f3808eSpbrook {
1114e1f3808eSpbrook     uint64_t val;
1115e1f3808eSpbrook     val = env->macc[acc];
1116c4162574SBlue Swirl     if (val == 0) {
1117e1f3808eSpbrook         env->macsr |= MACSR_Z;
1118c4162574SBlue Swirl     } else if (val & (1ull << 47)) {
1119e1f3808eSpbrook         env->macsr |= MACSR_N;
1120c4162574SBlue Swirl     }
1121e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << acc)) {
1122e1f3808eSpbrook         env->macsr |= MACSR_V;
1123e1f3808eSpbrook     }
1124e1f3808eSpbrook     if (env->macsr & MACSR_FI) {
1125e1f3808eSpbrook         val = ((int64_t)val) >> 40;
1126e1f3808eSpbrook         if (val != 0 && val != -1)
1127e1f3808eSpbrook             env->macsr |= MACSR_EV;
1128e1f3808eSpbrook     } else if (env->macsr & MACSR_SU) {
1129e1f3808eSpbrook         val = ((int64_t)val) >> 32;
1130e1f3808eSpbrook         if (val != 0 && val != -1)
1131e1f3808eSpbrook             env->macsr |= MACSR_EV;
1132e1f3808eSpbrook     } else {
1133e1f3808eSpbrook         if ((val >> 32) != 0)
1134e1f3808eSpbrook             env->macsr |= MACSR_EV;
1135e1f3808eSpbrook     }
1136e1f3808eSpbrook }
1137e1f3808eSpbrook 
1138db3d7945SLaurent Vivier #define EXTSIGN(val, index) (     \
1139db3d7945SLaurent Vivier     (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1140db3d7945SLaurent Vivier )
1141620c6cf6SRichard Henderson 
1142620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) {                                   \
1143620c6cf6SRichard Henderson     switch (op) {                                                          \
1144620c6cf6SRichard Henderson     case CC_OP_FLAGS:                                                      \
1145620c6cf6SRichard Henderson         /* Everything in place.  */                                        \
1146620c6cf6SRichard Henderson         break;                                                             \
1147db3d7945SLaurent Vivier     case CC_OP_ADDB:                                                       \
1148db3d7945SLaurent Vivier     case CC_OP_ADDW:                                                       \
1149db3d7945SLaurent Vivier     case CC_OP_ADDL:                                                       \
1150620c6cf6SRichard Henderson         res = n;                                                           \
1151620c6cf6SRichard Henderson         src2 = v;                                                          \
1152db3d7945SLaurent Vivier         src1 = EXTSIGN(res - src2, op - CC_OP_ADDB);                       \
1153620c6cf6SRichard Henderson         c = x;                                                             \
1154620c6cf6SRichard Henderson         z = n;                                                             \
1155620c6cf6SRichard Henderson         v = (res ^ src1) & ~(src1 ^ src2);                                 \
1156620c6cf6SRichard Henderson         break;                                                             \
1157db3d7945SLaurent Vivier     case CC_OP_SUBB:                                                       \
1158db3d7945SLaurent Vivier     case CC_OP_SUBW:                                                       \
1159db3d7945SLaurent Vivier     case CC_OP_SUBL:                                                       \
1160620c6cf6SRichard Henderson         res = n;                                                           \
1161620c6cf6SRichard Henderson         src2 = v;                                                          \
1162db3d7945SLaurent Vivier         src1 = EXTSIGN(res + src2, op - CC_OP_SUBB);                       \
1163620c6cf6SRichard Henderson         c = x;                                                             \
1164620c6cf6SRichard Henderson         z = n;                                                             \
1165620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1166620c6cf6SRichard Henderson         break;                                                             \
1167db3d7945SLaurent Vivier     case CC_OP_CMPB:                                                       \
1168db3d7945SLaurent Vivier     case CC_OP_CMPW:                                                       \
1169db3d7945SLaurent Vivier     case CC_OP_CMPL:                                                       \
1170620c6cf6SRichard Henderson         src1 = n;                                                          \
1171620c6cf6SRichard Henderson         src2 = v;                                                          \
1172db3d7945SLaurent Vivier         res = EXTSIGN(src1 - src2, op - CC_OP_CMPB);                       \
1173620c6cf6SRichard Henderson         n = res;                                                           \
1174620c6cf6SRichard Henderson         z = res;                                                           \
1175620c6cf6SRichard Henderson         c = src1 < src2;                                                   \
1176620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1177620c6cf6SRichard Henderson         break;                                                             \
1178620c6cf6SRichard Henderson     case CC_OP_LOGIC:                                                      \
1179620c6cf6SRichard Henderson         c = v = 0;                                                         \
1180620c6cf6SRichard Henderson         z = n;                                                             \
1181620c6cf6SRichard Henderson         break;                                                             \
1182620c6cf6SRichard Henderson     default:                                                               \
1183a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env), "Bad CC_OP %d", op);                       \
1184620c6cf6SRichard Henderson     }                                                                      \
1185620c6cf6SRichard Henderson } while (0)
1186620c6cf6SRichard Henderson 
1187620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1188e1f3808eSpbrook {
1189620c6cf6SRichard Henderson     uint32_t x, c, n, z, v;
1190620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1191620c6cf6SRichard Henderson 
1192620c6cf6SRichard Henderson     x = env->cc_x;
1193620c6cf6SRichard Henderson     n = env->cc_n;
1194620c6cf6SRichard Henderson     z = env->cc_z;
1195620c6cf6SRichard Henderson     v = env->cc_v;
1196db3d7945SLaurent Vivier     c = env->cc_c;
1197620c6cf6SRichard Henderson 
1198620c6cf6SRichard Henderson     COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1199620c6cf6SRichard Henderson 
1200620c6cf6SRichard Henderson     n = n >> 31;
1201620c6cf6SRichard Henderson     z = (z == 0);
1202db3d7945SLaurent Vivier     v = v >> 31;
1203620c6cf6SRichard Henderson 
1204620c6cf6SRichard Henderson     return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1205620c6cf6SRichard Henderson }
1206620c6cf6SRichard Henderson 
1207620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env)
1208620c6cf6SRichard Henderson {
1209620c6cf6SRichard Henderson     return cpu_m68k_get_ccr(env);
1210620c6cf6SRichard Henderson }
1211620c6cf6SRichard Henderson 
1212620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1213620c6cf6SRichard Henderson {
1214620c6cf6SRichard Henderson     env->cc_x = (ccr & CCF_X ? 1 : 0);
1215620c6cf6SRichard Henderson     env->cc_n = (ccr & CCF_N ? -1 : 0);
1216620c6cf6SRichard Henderson     env->cc_z = (ccr & CCF_Z ? 0 : 1);
1217620c6cf6SRichard Henderson     env->cc_v = (ccr & CCF_V ? -1 : 0);
1218620c6cf6SRichard Henderson     env->cc_c = (ccr & CCF_C ? 1 : 0);
1219620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1220620c6cf6SRichard Henderson }
1221620c6cf6SRichard Henderson 
1222620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1223620c6cf6SRichard Henderson {
1224620c6cf6SRichard Henderson     cpu_m68k_set_ccr(env, ccr);
1225620c6cf6SRichard Henderson }
1226620c6cf6SRichard Henderson 
1227620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1228620c6cf6SRichard Henderson {
1229620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1230620c6cf6SRichard Henderson 
1231620c6cf6SRichard Henderson     COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1232620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1233e1f3808eSpbrook }
1234e1f3808eSpbrook 
12352b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1236e1f3808eSpbrook {
1237e1f3808eSpbrook     int rem;
1238e1f3808eSpbrook     uint32_t result;
1239e1f3808eSpbrook 
1240e1f3808eSpbrook     if (env->macsr & MACSR_SU) {
1241e1f3808eSpbrook         /* 16-bit rounding.  */
1242e1f3808eSpbrook         rem = val & 0xffffff;
1243e1f3808eSpbrook         val = (val >> 24) & 0xffffu;
1244e1f3808eSpbrook         if (rem > 0x800000)
1245e1f3808eSpbrook             val++;
1246e1f3808eSpbrook         else if (rem == 0x800000)
1247e1f3808eSpbrook             val += (val & 1);
1248e1f3808eSpbrook     } else if (env->macsr & MACSR_RT) {
1249e1f3808eSpbrook         /* 32-bit rounding.  */
1250e1f3808eSpbrook         rem = val & 0xff;
1251e1f3808eSpbrook         val >>= 8;
1252e1f3808eSpbrook         if (rem > 0x80)
1253e1f3808eSpbrook             val++;
1254e1f3808eSpbrook         else if (rem == 0x80)
1255e1f3808eSpbrook             val += (val & 1);
1256e1f3808eSpbrook     } else {
1257e1f3808eSpbrook         /* No rounding.  */
1258e1f3808eSpbrook         val >>= 8;
1259e1f3808eSpbrook     }
1260e1f3808eSpbrook     if (env->macsr & MACSR_OMC) {
1261e1f3808eSpbrook         /* Saturate.  */
1262e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1263e1f3808eSpbrook             if (val != (uint16_t) val) {
1264e1f3808eSpbrook                 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1265e1f3808eSpbrook             } else {
1266e1f3808eSpbrook                 result = val & 0xffff;
1267e1f3808eSpbrook             }
1268e1f3808eSpbrook         } else {
1269e1f3808eSpbrook             if (val != (uint32_t)val) {
1270e1f3808eSpbrook                 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1271e1f3808eSpbrook             } else {
1272e1f3808eSpbrook                 result = (uint32_t)val;
1273e1f3808eSpbrook             }
1274e1f3808eSpbrook         }
1275e1f3808eSpbrook     } else {
1276e1f3808eSpbrook         /* No saturation.  */
1277e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1278e1f3808eSpbrook             result = val & 0xffff;
1279e1f3808eSpbrook         } else {
1280e1f3808eSpbrook             result = (uint32_t)val;
1281e1f3808eSpbrook         }
1282e1f3808eSpbrook     }
1283e1f3808eSpbrook     return result;
1284e1f3808eSpbrook }
1285e1f3808eSpbrook 
1286e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val)
1287e1f3808eSpbrook {
1288e1f3808eSpbrook     if (val == (int32_t)val) {
1289e1f3808eSpbrook         return (int32_t)val;
1290e1f3808eSpbrook     } else {
1291e1f3808eSpbrook         return (val >> 61) ^ ~SIGNBIT;
1292e1f3808eSpbrook     }
1293e1f3808eSpbrook }
1294e1f3808eSpbrook 
1295e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val)
1296e1f3808eSpbrook {
1297e1f3808eSpbrook     if ((val >> 32) == 0) {
1298e1f3808eSpbrook         return (uint32_t)val;
1299e1f3808eSpbrook     } else {
1300e1f3808eSpbrook         return 0xffffffffu;
1301e1f3808eSpbrook     }
1302e1f3808eSpbrook }
1303e1f3808eSpbrook 
13042b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1305e1f3808eSpbrook {
1306e1f3808eSpbrook     uint32_t val;
1307e1f3808eSpbrook     val = env->macc[acc] & 0x00ff;
13085ce747cfSPaolo Bonzini     val |= (env->macc[acc] >> 32) & 0xff00;
1309e1f3808eSpbrook     val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1310e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1311e1f3808eSpbrook     return val;
1312e1f3808eSpbrook }
1313e1f3808eSpbrook 
13142b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1315e1f3808eSpbrook {
1316e1f3808eSpbrook     uint32_t val;
1317e1f3808eSpbrook     val = (env->macc[acc] >> 32) & 0xffff;
1318e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1319e1f3808eSpbrook     return val;
1320e1f3808eSpbrook }
1321e1f3808eSpbrook 
13222b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1323e1f3808eSpbrook {
1324e1f3808eSpbrook     int64_t res;
1325e1f3808eSpbrook     int32_t tmp;
1326e1f3808eSpbrook     res = env->macc[acc] & 0xffffffff00ull;
1327e1f3808eSpbrook     tmp = (int16_t)(val & 0xff00);
1328e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1329e1f3808eSpbrook     res |= val & 0xff;
1330e1f3808eSpbrook     env->macc[acc] = res;
1331e1f3808eSpbrook     res = env->macc[acc + 1] & 0xffffffff00ull;
1332e1f3808eSpbrook     tmp = (val & 0xff000000);
1333e1f3808eSpbrook     res |= ((int64_t)tmp) << 16;
1334e1f3808eSpbrook     res |= (val >> 16) & 0xff;
1335e1f3808eSpbrook     env->macc[acc + 1] = res;
1336e1f3808eSpbrook }
1337e1f3808eSpbrook 
13382b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
1339e1f3808eSpbrook {
1340e1f3808eSpbrook     int64_t res;
1341e1f3808eSpbrook     int32_t tmp;
1342e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1343e1f3808eSpbrook     tmp = (int16_t)val;
1344e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1345e1f3808eSpbrook     env->macc[acc] = res;
1346e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1347e1f3808eSpbrook     tmp = val & 0xffff0000;
1348e1f3808eSpbrook     res |= (int64_t)tmp << 16;
1349e1f3808eSpbrook     env->macc[acc + 1] = res;
1350e1f3808eSpbrook }
1351e1f3808eSpbrook 
13522b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
1353e1f3808eSpbrook {
1354e1f3808eSpbrook     uint64_t res;
1355e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1356e1f3808eSpbrook     res |= ((uint64_t)(val & 0xffff)) << 32;
1357e1f3808eSpbrook     env->macc[acc] = res;
1358e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1359e1f3808eSpbrook     res |= (uint64_t)(val & 0xffff0000) << 16;
1360e1f3808eSpbrook     env->macc[acc + 1] = res;
1361e1f3808eSpbrook }
13620bdb2b3bSLaurent Vivier 
13630bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU)
1364e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1365e55886c3SLaurent Vivier {
1366e55886c3SLaurent Vivier     hwaddr physical;
1367e55886c3SLaurent Vivier     int access_type;
1368e55886c3SLaurent Vivier     int prot;
1369e55886c3SLaurent Vivier     int ret;
1370e55886c3SLaurent Vivier     target_ulong page_size;
1371e55886c3SLaurent Vivier 
1372e55886c3SLaurent Vivier     access_type = ACCESS_PTEST;
1373e55886c3SLaurent Vivier     if (env->dfc & 4) {
1374e55886c3SLaurent Vivier         access_type |= ACCESS_SUPER;
1375e55886c3SLaurent Vivier     }
1376e55886c3SLaurent Vivier     if ((env->dfc & 3) == 2) {
1377e55886c3SLaurent Vivier         access_type |= ACCESS_CODE;
1378e55886c3SLaurent Vivier     }
1379e55886c3SLaurent Vivier     if (!is_read) {
1380e55886c3SLaurent Vivier         access_type |= ACCESS_STORE;
1381e55886c3SLaurent Vivier     }
1382e55886c3SLaurent Vivier 
1383e55886c3SLaurent Vivier     env->mmu.mmusr = 0;
1384e55886c3SLaurent Vivier     env->mmu.ssw = 0;
1385e55886c3SLaurent Vivier     ret = get_physical_address(env, &physical, &prot, addr,
1386e55886c3SLaurent Vivier                                access_type, &page_size);
1387e55886c3SLaurent Vivier     if (ret == 0) {
1388e55886c3SLaurent Vivier         addr &= TARGET_PAGE_MASK;
1389e55886c3SLaurent Vivier         physical += addr & (page_size - 1);
1390a8d92fd8SRichard Henderson         tlb_set_page(env_cpu(env), addr, physical,
1391e55886c3SLaurent Vivier                      prot, access_type & ACCESS_SUPER ?
1392e55886c3SLaurent Vivier                      MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1393e55886c3SLaurent Vivier     }
1394e55886c3SLaurent Vivier }
1395e55886c3SLaurent Vivier 
1396e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1397e55886c3SLaurent Vivier {
1398a8d92fd8SRichard Henderson     CPUState *cs = env_cpu(env);
1399e55886c3SLaurent Vivier 
1400e55886c3SLaurent Vivier     switch (opmode) {
1401e55886c3SLaurent Vivier     case 0: /* Flush page entry if not global */
1402e55886c3SLaurent Vivier     case 1: /* Flush page entry */
1403a8d92fd8SRichard Henderson         tlb_flush_page(cs, addr);
1404e55886c3SLaurent Vivier         break;
1405e55886c3SLaurent Vivier     case 2: /* Flush all except global entries */
1406a8d92fd8SRichard Henderson         tlb_flush(cs);
1407e55886c3SLaurent Vivier         break;
1408e55886c3SLaurent Vivier     case 3: /* Flush all entries */
1409a8d92fd8SRichard Henderson         tlb_flush(cs);
1410e55886c3SLaurent Vivier         break;
1411e55886c3SLaurent Vivier     }
1412e55886c3SLaurent Vivier }
1413e55886c3SLaurent Vivier 
14140bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env)
14150bdb2b3bSLaurent Vivier {
14160bdb2b3bSLaurent Vivier     /* FIXME: reset all except CPU */
14170bdb2b3bSLaurent Vivier }
14180bdb2b3bSLaurent Vivier #endif
1419