xref: /qemu/target/m68k/helper.c (revision 24f91e81b65fcdd0552d1f0fcb0ea7cfe3829c19)
1e6e5906bSpbrook /*
2e6e5906bSpbrook  *  m68k op helpers
3e6e5906bSpbrook  *
40633879fSpbrook  *  Copyright (c) 2006-2007 CodeSourcery
5e6e5906bSpbrook  *  Written by Paul Brook
6e6e5906bSpbrook  *
7e6e5906bSpbrook  * This library is free software; you can redistribute it and/or
8e6e5906bSpbrook  * modify it under the terms of the GNU Lesser General Public
9e6e5906bSpbrook  * License as published by the Free Software Foundation; either
10e6e5906bSpbrook  * version 2 of the License, or (at your option) any later version.
11e6e5906bSpbrook  *
12e6e5906bSpbrook  * This library is distributed in the hope that it will be useful,
13e6e5906bSpbrook  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14e6e5906bSpbrook  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15e6e5906bSpbrook  * General Public License for more details.
16e6e5906bSpbrook  *
17e6e5906bSpbrook  * You should have received a copy of the GNU Lesser General Public
188167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19e6e5906bSpbrook  */
20e6e5906bSpbrook 
21d8416665SPeter Maydell #include "qemu/osdep.h"
22e6e5906bSpbrook #include "cpu.h"
2363c91552SPaolo Bonzini #include "exec/exec-all.h"
24022c62cbSPaolo Bonzini #include "exec/gdbstub.h"
25e6e5906bSpbrook 
262ef6175aSRichard Henderson #include "exec/helper-proto.h"
27*24f91e81SAlex Bennée #include "fpu/softfloat.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;
5292a31361SAndreas Färber     CPUListState *s = user_data;
537a9f812bSAndreas Färber     const char *typename;
547a9f812bSAndreas Färber     char *name;
5511150915SAndreas Färber 
567a9f812bSAndreas Färber     typename = object_class_get_name(c);
577a9f812bSAndreas Färber     name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
5811150915SAndreas Färber     (*s->cpu_fprintf)(s->file, "%s\n",
597a9f812bSAndreas Färber                       name);
607a9f812bSAndreas Färber     g_free(name);
6111150915SAndreas Färber }
620402f767Spbrook 
639a78eeadSStefan Weil void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
64009a4356SLaurent Vivier {
6592a31361SAndreas Färber     CPUListState s = {
6611150915SAndreas Färber         .file = f,
6711150915SAndreas Färber         .cpu_fprintf = cpu_fprintf,
6811150915SAndreas Färber     };
6911150915SAndreas Färber     GSList *list;
70009a4356SLaurent Vivier 
7111150915SAndreas Färber     list = object_class_get_list(TYPE_M68K_CPU, false);
7211150915SAndreas Färber     list = g_slist_sort(list, m68k_cpu_list_compare);
7311150915SAndreas Färber     g_slist_foreach(list, m68k_cpu_list_entry, &s);
7411150915SAndreas Färber     g_slist_free(list);
75009a4356SLaurent Vivier }
76009a4356SLaurent Vivier 
77f83311e4SLaurent Vivier static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
7856aebc89Spbrook {
7956aebc89Spbrook     if (n < 8) {
80f83311e4SLaurent Vivier         float_status s;
81f83311e4SLaurent Vivier         stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
8256aebc89Spbrook         return 8;
8356aebc89Spbrook     }
84ba624944SLaurent Vivier     switch (n) {
85ba624944SLaurent Vivier     case 8: /* fpcontrol */
86ba624944SLaurent Vivier         stl_be_p(mem_buf, env->fpcr);
87ba624944SLaurent Vivier         return 4;
88ba624944SLaurent Vivier     case 9: /* fpstatus */
89ba624944SLaurent Vivier         stl_be_p(mem_buf, env->fpsr);
90ba624944SLaurent Vivier         return 4;
91ba624944SLaurent Vivier     case 10: /* fpiar, not implemented */
9256aebc89Spbrook         memset(mem_buf, 0, 4);
9356aebc89Spbrook         return 4;
9456aebc89Spbrook     }
9556aebc89Spbrook     return 0;
9656aebc89Spbrook }
9756aebc89Spbrook 
98f83311e4SLaurent Vivier static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
9956aebc89Spbrook {
10056aebc89Spbrook     if (n < 8) {
101f83311e4SLaurent Vivier         float_status s;
102f83311e4SLaurent Vivier         env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
10356aebc89Spbrook         return 8;
10456aebc89Spbrook     }
105ba624944SLaurent Vivier     switch (n) {
106ba624944SLaurent Vivier     case 8: /* fpcontrol */
107ba624944SLaurent Vivier         cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
108ba624944SLaurent Vivier         return 4;
109ba624944SLaurent Vivier     case 9: /* fpstatus */
110ba624944SLaurent Vivier         env->fpsr = ldl_p(mem_buf);
111ba624944SLaurent Vivier         return 4;
112ba624944SLaurent Vivier     case 10: /* fpiar, not implemented */
11356aebc89Spbrook         return 4;
11456aebc89Spbrook     }
11556aebc89Spbrook     return 0;
11656aebc89Spbrook }
11756aebc89Spbrook 
1185a4526b2SLaurent Vivier static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
1195a4526b2SLaurent Vivier {
1205a4526b2SLaurent Vivier     if (n < 8) {
1215a4526b2SLaurent Vivier         stw_be_p(mem_buf, env->fregs[n].l.upper);
1225a4526b2SLaurent Vivier         memset(mem_buf + 2, 0, 2);
1235a4526b2SLaurent Vivier         stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
1245a4526b2SLaurent Vivier         return 12;
1255a4526b2SLaurent Vivier     }
1265a4526b2SLaurent Vivier     switch (n) {
1275a4526b2SLaurent Vivier     case 8: /* fpcontrol */
1285a4526b2SLaurent Vivier         stl_be_p(mem_buf, env->fpcr);
1295a4526b2SLaurent Vivier         return 4;
1305a4526b2SLaurent Vivier     case 9: /* fpstatus */
1315a4526b2SLaurent Vivier         stl_be_p(mem_buf, env->fpsr);
1325a4526b2SLaurent Vivier         return 4;
1335a4526b2SLaurent Vivier     case 10: /* fpiar, not implemented */
1345a4526b2SLaurent Vivier         memset(mem_buf, 0, 4);
1355a4526b2SLaurent Vivier         return 4;
1365a4526b2SLaurent Vivier     }
1375a4526b2SLaurent Vivier     return 0;
1385a4526b2SLaurent Vivier }
1395a4526b2SLaurent Vivier 
1405a4526b2SLaurent Vivier static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
1415a4526b2SLaurent Vivier {
1425a4526b2SLaurent Vivier     if (n < 8) {
1435a4526b2SLaurent Vivier         env->fregs[n].l.upper = lduw_be_p(mem_buf);
1445a4526b2SLaurent Vivier         env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
1455a4526b2SLaurent Vivier         return 12;
1465a4526b2SLaurent Vivier     }
1475a4526b2SLaurent Vivier     switch (n) {
1485a4526b2SLaurent Vivier     case 8: /* fpcontrol */
149ba624944SLaurent Vivier         cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
1505a4526b2SLaurent Vivier         return 4;
1515a4526b2SLaurent Vivier     case 9: /* fpstatus */
1525a4526b2SLaurent Vivier         env->fpsr = ldl_p(mem_buf);
1535a4526b2SLaurent Vivier         return 4;
1545a4526b2SLaurent Vivier     case 10: /* fpiar, not implemented */
1555a4526b2SLaurent Vivier         return 4;
1565a4526b2SLaurent Vivier     }
1575a4526b2SLaurent Vivier     return 0;
1585a4526b2SLaurent Vivier }
1595a4526b2SLaurent Vivier 
1606d1bbc62SAndreas Färber void m68k_cpu_init_gdb(M68kCPU *cpu)
1616d1bbc62SAndreas Färber {
16222169d41SAndreas Färber     CPUState *cs = CPU(cpu);
1636d1bbc62SAndreas Färber     CPUM68KState *env = &cpu->env;
1646d1bbc62SAndreas Färber 
16511150915SAndreas Färber     if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
166f83311e4SLaurent Vivier         gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
16711150915SAndreas Färber                                  11, "cf-fp.xml", 18);
1685a4526b2SLaurent Vivier     } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
1695a4526b2SLaurent Vivier         gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
1705a4526b2SLaurent Vivier                                  m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
171aaed909aSbellard     }
17211150915SAndreas Färber     /* TODO: Add [E]MAC registers.  */
173aaed909aSbellard }
174aaed909aSbellard 
1756e22b28eSLaurent Vivier void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
1760633879fSpbrook {
177a47dddd7SAndreas Färber     M68kCPU *cpu = m68k_env_get_cpu(env);
178a47dddd7SAndreas Färber 
1790633879fSpbrook     switch (reg) {
1806e22b28eSLaurent Vivier     case M68K_CR_CACR:
18120dcee94Spbrook         env->cacr = val;
18220dcee94Spbrook         m68k_switch_sp(env);
18320dcee94Spbrook         break;
1846e22b28eSLaurent Vivier     case M68K_CR_ACR0:
1856e22b28eSLaurent Vivier     case M68K_CR_ACR1:
1866e22b28eSLaurent Vivier     case M68K_CR_ACR2:
1876e22b28eSLaurent Vivier     case M68K_CR_ACR3:
18820dcee94Spbrook         /* TODO: Implement Access Control Registers.  */
1890633879fSpbrook         break;
1906e22b28eSLaurent Vivier     case M68K_CR_VBR:
1910633879fSpbrook         env->vbr = val;
1920633879fSpbrook         break;
1930633879fSpbrook     /* TODO: Implement control registers.  */
1940633879fSpbrook     default:
1956e22b28eSLaurent Vivier         cpu_abort(CPU(cpu),
1966e22b28eSLaurent Vivier                   "Unimplemented control register write 0x%x = 0x%x\n",
1976e22b28eSLaurent Vivier                   reg, val);
1986e22b28eSLaurent Vivier     }
1996e22b28eSLaurent Vivier }
2006e22b28eSLaurent Vivier 
2016e22b28eSLaurent Vivier void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
2026e22b28eSLaurent Vivier {
2036e22b28eSLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
2046e22b28eSLaurent Vivier 
2056e22b28eSLaurent Vivier     switch (reg) {
2066e22b28eSLaurent Vivier     /* MC680[1234]0 */
2075fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
2085fa9f1f2SLaurent Vivier         env->sfc = val & 7;
2095fa9f1f2SLaurent Vivier         return;
2105fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
2115fa9f1f2SLaurent Vivier         env->dfc = val & 7;
2125fa9f1f2SLaurent Vivier         return;
2136e22b28eSLaurent Vivier     case M68K_CR_VBR:
2146e22b28eSLaurent Vivier         env->vbr = val;
2156e22b28eSLaurent Vivier         return;
2166e22b28eSLaurent Vivier     /* MC680[234]0 */
2176e22b28eSLaurent Vivier     case M68K_CR_CACR:
2186e22b28eSLaurent Vivier         env->cacr = val;
2196e22b28eSLaurent Vivier         m68k_switch_sp(env);
2206e22b28eSLaurent Vivier         return;
2216e22b28eSLaurent Vivier     /* MC680[34]0 */
22288b2fef6SLaurent Vivier     case M68K_CR_TC:
22388b2fef6SLaurent Vivier         env->mmu.tcr = val;
22488b2fef6SLaurent Vivier         return;
225e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
226e55886c3SLaurent Vivier         env->mmu.mmusr = val;
227e55886c3SLaurent Vivier         return;
22888b2fef6SLaurent Vivier     case M68K_CR_SRP:
22988b2fef6SLaurent Vivier         env->mmu.srp = val;
23088b2fef6SLaurent Vivier         return;
23188b2fef6SLaurent Vivier     case M68K_CR_URP:
23288b2fef6SLaurent Vivier         env->mmu.urp = val;
23388b2fef6SLaurent Vivier         return;
2346e22b28eSLaurent Vivier     case M68K_CR_USP:
2356e22b28eSLaurent Vivier         env->sp[M68K_USP] = val;
2366e22b28eSLaurent Vivier         return;
2376e22b28eSLaurent Vivier     case M68K_CR_MSP:
2386e22b28eSLaurent Vivier         env->sp[M68K_SSP] = val;
2396e22b28eSLaurent Vivier         return;
2406e22b28eSLaurent Vivier     case M68K_CR_ISP:
2416e22b28eSLaurent Vivier         env->sp[M68K_ISP] = val;
2426e22b28eSLaurent Vivier         return;
243c05c73b0SLaurent Vivier     /* MC68040/MC68LC040 */
244c05c73b0SLaurent Vivier     case M68K_CR_ITT0:
245c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_ITTR0] = val;
246c05c73b0SLaurent Vivier         return;
247c05c73b0SLaurent Vivier     case M68K_CR_ITT1:
248c05c73b0SLaurent Vivier          env->mmu.ttr[M68K_ITTR1] = val;
249c05c73b0SLaurent Vivier         return;
250c05c73b0SLaurent Vivier     case M68K_CR_DTT0:
251c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_DTTR0] = val;
252c05c73b0SLaurent Vivier         return;
253c05c73b0SLaurent Vivier     case M68K_CR_DTT1:
254c05c73b0SLaurent Vivier         env->mmu.ttr[M68K_DTTR1] = val;
255c05c73b0SLaurent Vivier         return;
2566e22b28eSLaurent Vivier     }
257a47dddd7SAndreas Färber     cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
2580633879fSpbrook               reg, val);
2590633879fSpbrook }
2606e22b28eSLaurent Vivier 
2616e22b28eSLaurent Vivier uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
2626e22b28eSLaurent Vivier {
2636e22b28eSLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
2646e22b28eSLaurent Vivier 
2656e22b28eSLaurent Vivier     switch (reg) {
2666e22b28eSLaurent Vivier     /* MC680[1234]0 */
2675fa9f1f2SLaurent Vivier     case M68K_CR_SFC:
2685fa9f1f2SLaurent Vivier         return env->sfc;
2695fa9f1f2SLaurent Vivier     case M68K_CR_DFC:
2705fa9f1f2SLaurent Vivier         return env->dfc;
2716e22b28eSLaurent Vivier     case M68K_CR_VBR:
2726e22b28eSLaurent Vivier         return env->vbr;
2736e22b28eSLaurent Vivier     /* MC680[234]0 */
2746e22b28eSLaurent Vivier     case M68K_CR_CACR:
2756e22b28eSLaurent Vivier         return env->cacr;
2766e22b28eSLaurent Vivier     /* MC680[34]0 */
27788b2fef6SLaurent Vivier     case M68K_CR_TC:
27888b2fef6SLaurent Vivier         return env->mmu.tcr;
279e55886c3SLaurent Vivier     case M68K_CR_MMUSR:
280e55886c3SLaurent Vivier         return env->mmu.mmusr;
28188b2fef6SLaurent Vivier     case M68K_CR_SRP:
28288b2fef6SLaurent Vivier         return env->mmu.srp;
2836e22b28eSLaurent Vivier     case M68K_CR_USP:
2846e22b28eSLaurent Vivier         return env->sp[M68K_USP];
2856e22b28eSLaurent Vivier     case M68K_CR_MSP:
2866e22b28eSLaurent Vivier         return env->sp[M68K_SSP];
2876e22b28eSLaurent Vivier     case M68K_CR_ISP:
2886e22b28eSLaurent Vivier         return env->sp[M68K_ISP];
28988b2fef6SLaurent Vivier     /* MC68040/MC68LC040 */
29088b2fef6SLaurent Vivier     case M68K_CR_URP:
29188b2fef6SLaurent Vivier         return env->mmu.urp;
292c05c73b0SLaurent Vivier     case M68K_CR_ITT0:
293c05c73b0SLaurent Vivier         return env->mmu.ttr[M68K_ITTR0];
294c05c73b0SLaurent Vivier     case M68K_CR_ITT1:
295c05c73b0SLaurent Vivier         return env->mmu.ttr[M68K_ITTR1];
296c05c73b0SLaurent Vivier     case M68K_CR_DTT0:
297c05c73b0SLaurent Vivier         return env->mmu.ttr[M68K_DTTR0];
298c05c73b0SLaurent Vivier     case M68K_CR_DTT1:
299c05c73b0SLaurent Vivier         return env->mmu.ttr[M68K_DTTR1];
3006e22b28eSLaurent Vivier     }
3016e22b28eSLaurent Vivier     cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n",
3026e22b28eSLaurent Vivier               reg);
3030633879fSpbrook }
3040633879fSpbrook 
305e1f3808eSpbrook void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
306acf930aaSpbrook {
307acf930aaSpbrook     uint32_t acc;
308acf930aaSpbrook     int8_t exthigh;
309acf930aaSpbrook     uint8_t extlow;
310acf930aaSpbrook     uint64_t regval;
311acf930aaSpbrook     int i;
312acf930aaSpbrook     if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
313acf930aaSpbrook         for (i = 0; i < 4; i++) {
314acf930aaSpbrook             regval = env->macc[i];
315acf930aaSpbrook             exthigh = regval >> 40;
316acf930aaSpbrook             if (env->macsr & MACSR_FI) {
317acf930aaSpbrook                 acc = regval >> 8;
318acf930aaSpbrook                 extlow = regval;
319acf930aaSpbrook             } else {
320acf930aaSpbrook                 acc = regval;
321acf930aaSpbrook                 extlow = regval >> 32;
322acf930aaSpbrook             }
323acf930aaSpbrook             if (env->macsr & MACSR_FI) {
324acf930aaSpbrook                 regval = (((uint64_t)acc) << 8) | extlow;
325acf930aaSpbrook                 regval |= ((int64_t)exthigh) << 40;
326acf930aaSpbrook             } else if (env->macsr & MACSR_SU) {
327acf930aaSpbrook                 regval = acc | (((int64_t)extlow) << 32);
328acf930aaSpbrook                 regval |= ((int64_t)exthigh) << 40;
329acf930aaSpbrook             } else {
330acf930aaSpbrook                 regval = acc | (((uint64_t)extlow) << 32);
331acf930aaSpbrook                 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
332acf930aaSpbrook             }
333acf930aaSpbrook             env->macc[i] = regval;
334acf930aaSpbrook         }
335acf930aaSpbrook     }
336acf930aaSpbrook     env->macsr = val;
337acf930aaSpbrook }
338acf930aaSpbrook 
33920dcee94Spbrook void m68k_switch_sp(CPUM68KState *env)
34020dcee94Spbrook {
34120dcee94Spbrook     int new_sp;
34220dcee94Spbrook 
34320dcee94Spbrook     env->sp[env->current_sp] = env->aregs[7];
3446e22b28eSLaurent Vivier     if (m68k_feature(env, M68K_FEATURE_M68000)) {
3456e22b28eSLaurent Vivier         if (env->sr & SR_S) {
3466e22b28eSLaurent Vivier             if (env->sr & SR_M) {
3476e22b28eSLaurent Vivier                 new_sp = M68K_SSP;
3486e22b28eSLaurent Vivier             } else {
3496e22b28eSLaurent Vivier                 new_sp = M68K_ISP;
3506e22b28eSLaurent Vivier             }
3516e22b28eSLaurent Vivier         } else {
3526e22b28eSLaurent Vivier             new_sp = M68K_USP;
3536e22b28eSLaurent Vivier         }
3546e22b28eSLaurent Vivier     } else {
35520dcee94Spbrook         new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
35620dcee94Spbrook                  ? M68K_SSP : M68K_USP;
3576e22b28eSLaurent Vivier     }
35820dcee94Spbrook     env->aregs[7] = env->sp[new_sp];
35920dcee94Spbrook     env->current_sp = new_sp;
36020dcee94Spbrook }
36120dcee94Spbrook 
3620633879fSpbrook #if defined(CONFIG_USER_ONLY)
3630633879fSpbrook 
36498670d47SLaurent Vivier int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
36597b348e7SBlue Swirl                               int mmu_idx)
3660633879fSpbrook {
3677510454eSAndreas Färber     M68kCPU *cpu = M68K_CPU(cs);
3687510454eSAndreas Färber 
36927103424SAndreas Färber     cs->exception_index = EXCP_ACCESS;
3707510454eSAndreas Färber     cpu->env.mmu.ar = address;
3710633879fSpbrook     return 1;
3720633879fSpbrook }
3730633879fSpbrook 
3740633879fSpbrook #else
3750633879fSpbrook 
37688b2fef6SLaurent Vivier /* MMU: 68040 only */
3774fcc562bSPaul Brook 
3782097dca6SLaurent Vivier static void print_address_zone(FILE *f, fprintf_function cpu_fprintf,
3792097dca6SLaurent Vivier                                uint32_t logical, uint32_t physical,
3802097dca6SLaurent Vivier                                uint32_t size, int attr)
3812097dca6SLaurent Vivier {
3822097dca6SLaurent Vivier     cpu_fprintf(f, "%08x - %08x -> %08x - %08x %c ",
3832097dca6SLaurent Vivier                 logical, logical + size - 1,
3842097dca6SLaurent Vivier                 physical, physical + size - 1,
3852097dca6SLaurent Vivier                 attr & 4 ? 'W' : '-');
3862097dca6SLaurent Vivier     size >>= 10;
3872097dca6SLaurent Vivier     if (size < 1024) {
3882097dca6SLaurent Vivier         cpu_fprintf(f, "(%d KiB)\n", size);
3892097dca6SLaurent Vivier     } else {
3902097dca6SLaurent Vivier         size >>= 10;
3912097dca6SLaurent Vivier         if (size < 1024) {
3922097dca6SLaurent Vivier             cpu_fprintf(f, "(%d MiB)\n", size);
3932097dca6SLaurent Vivier         } else {
3942097dca6SLaurent Vivier             size >>= 10;
3952097dca6SLaurent Vivier             cpu_fprintf(f, "(%d GiB)\n", size);
3962097dca6SLaurent Vivier         }
3972097dca6SLaurent Vivier     }
3982097dca6SLaurent Vivier }
3992097dca6SLaurent Vivier 
4002097dca6SLaurent Vivier static void dump_address_map(FILE *f, fprintf_function cpu_fprintf,
4012097dca6SLaurent Vivier                              CPUM68KState *env, uint32_t root_pointer)
4022097dca6SLaurent Vivier {
4032097dca6SLaurent Vivier     int i, j, k;
4042097dca6SLaurent Vivier     int tic_size, tic_shift;
4052097dca6SLaurent Vivier     uint32_t tib_mask;
4062097dca6SLaurent Vivier     uint32_t tia, tib, tic;
4072097dca6SLaurent Vivier     uint32_t logical = 0xffffffff, physical = 0xffffffff;
4082097dca6SLaurent Vivier     uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
4092097dca6SLaurent Vivier     uint32_t last_logical, last_physical;
4102097dca6SLaurent Vivier     int32_t size;
4112097dca6SLaurent Vivier     int last_attr = -1, attr = -1;
4122097dca6SLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
4132097dca6SLaurent Vivier     CPUState *cs = CPU(cpu);
4142097dca6SLaurent Vivier 
4152097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
4162097dca6SLaurent Vivier         /* 8k page */
4172097dca6SLaurent Vivier         tic_size = 32;
4182097dca6SLaurent Vivier         tic_shift = 13;
4192097dca6SLaurent Vivier         tib_mask = M68K_8K_PAGE_MASK;
4202097dca6SLaurent Vivier     } else {
4212097dca6SLaurent Vivier         /* 4k page */
4222097dca6SLaurent Vivier         tic_size = 64;
4232097dca6SLaurent Vivier         tic_shift = 12;
4242097dca6SLaurent Vivier         tib_mask = M68K_4K_PAGE_MASK;
4252097dca6SLaurent Vivier     }
4262097dca6SLaurent Vivier     for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
4272097dca6SLaurent Vivier         tia = ldl_phys(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4);
4282097dca6SLaurent Vivier         if (!M68K_UDT_VALID(tia)) {
4292097dca6SLaurent Vivier             continue;
4302097dca6SLaurent Vivier         }
4312097dca6SLaurent Vivier         for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
4322097dca6SLaurent Vivier             tib = ldl_phys(cs->as, M68K_POINTER_BASE(tia) + j * 4);
4332097dca6SLaurent Vivier             if (!M68K_UDT_VALID(tib)) {
4342097dca6SLaurent Vivier                 continue;
4352097dca6SLaurent Vivier             }
4362097dca6SLaurent Vivier             for (k = 0; k < tic_size; k++) {
4372097dca6SLaurent Vivier                 tic = ldl_phys(cs->as, (tib & tib_mask) + k * 4);
4382097dca6SLaurent Vivier                 if (!M68K_PDT_VALID(tic)) {
4392097dca6SLaurent Vivier                     continue;
4402097dca6SLaurent Vivier                 }
4412097dca6SLaurent Vivier                 if (M68K_PDT_INDIRECT(tic)) {
4422097dca6SLaurent Vivier                     tic = ldl_phys(cs->as, M68K_INDIRECT_POINTER(tic));
4432097dca6SLaurent Vivier                 }
4442097dca6SLaurent Vivier 
4452097dca6SLaurent Vivier                 last_logical = logical;
4462097dca6SLaurent Vivier                 logical = (i << M68K_TTS_ROOT_SHIFT) |
4472097dca6SLaurent Vivier                           (j << M68K_TTS_POINTER_SHIFT) |
4482097dca6SLaurent Vivier                           (k << tic_shift);
4492097dca6SLaurent Vivier 
4502097dca6SLaurent Vivier                 last_physical = physical;
4512097dca6SLaurent Vivier                 physical = tic & ~((1 << tic_shift) - 1);
4522097dca6SLaurent Vivier 
4532097dca6SLaurent Vivier                 last_attr = attr;
4542097dca6SLaurent Vivier                 attr = tic & ((1 << tic_shift) - 1);
4552097dca6SLaurent Vivier 
4562097dca6SLaurent Vivier                 if ((logical != (last_logical + (1 << tic_shift))) ||
4572097dca6SLaurent Vivier                     (physical != (last_physical + (1 << tic_shift))) ||
4582097dca6SLaurent Vivier                     (attr & 4) != (last_attr & 4)) {
4592097dca6SLaurent Vivier 
4602097dca6SLaurent Vivier                     if (first_logical != 0xffffffff) {
4612097dca6SLaurent Vivier                         size = last_logical + (1 << tic_shift) -
4622097dca6SLaurent Vivier                                first_logical;
4632097dca6SLaurent Vivier                         print_address_zone(f, cpu_fprintf, first_logical,
4642097dca6SLaurent Vivier                                            first_physical, size, last_attr);
4652097dca6SLaurent Vivier                     }
4662097dca6SLaurent Vivier                     first_logical = logical;
4672097dca6SLaurent Vivier                     first_physical = physical;
4682097dca6SLaurent Vivier                 }
4692097dca6SLaurent Vivier             }
4702097dca6SLaurent Vivier         }
4712097dca6SLaurent Vivier     }
4722097dca6SLaurent Vivier     if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
4732097dca6SLaurent Vivier         size = logical + (1 << tic_shift) - first_logical;
4742097dca6SLaurent Vivier         print_address_zone(f, cpu_fprintf, first_logical, first_physical, size,
4752097dca6SLaurent Vivier                            last_attr);
4762097dca6SLaurent Vivier     }
4772097dca6SLaurent Vivier }
4782097dca6SLaurent Vivier 
4792097dca6SLaurent Vivier #define DUMP_CACHEFLAGS(a) \
4802097dca6SLaurent Vivier     switch (a & M68K_DESC_CACHEMODE) { \
4812097dca6SLaurent Vivier     case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
4822097dca6SLaurent Vivier         cpu_fprintf(f, "T"); \
4832097dca6SLaurent Vivier         break; \
4842097dca6SLaurent Vivier     case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
4852097dca6SLaurent Vivier         cpu_fprintf(f, "C"); \
4862097dca6SLaurent Vivier         break; \
4872097dca6SLaurent Vivier     case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
4882097dca6SLaurent Vivier         cpu_fprintf(f, "S"); \
4892097dca6SLaurent Vivier         break; \
4902097dca6SLaurent Vivier     case M68K_DESC_CM_NCACHE: /* noncachable */ \
4912097dca6SLaurent Vivier         cpu_fprintf(f, "N"); \
4922097dca6SLaurent Vivier         break; \
4932097dca6SLaurent Vivier     }
4942097dca6SLaurent Vivier 
4952097dca6SLaurent Vivier static void dump_ttr(FILE *f, fprintf_function cpu_fprintf, uint32_t ttr)
4962097dca6SLaurent Vivier {
4972097dca6SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
4982097dca6SLaurent Vivier         cpu_fprintf(f, "disabled\n");
4992097dca6SLaurent Vivier         return;
5002097dca6SLaurent Vivier     }
5012097dca6SLaurent Vivier     cpu_fprintf(f, "Base: 0x%08x Mask: 0x%08x Control: ",
5022097dca6SLaurent Vivier                 ttr & M68K_TTR_ADDR_BASE,
5032097dca6SLaurent Vivier                 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
5042097dca6SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
5052097dca6SLaurent Vivier     case M68K_TTR_SFIELD_USER:
5062097dca6SLaurent Vivier         cpu_fprintf(f, "U");
5072097dca6SLaurent Vivier         break;
5082097dca6SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
5092097dca6SLaurent Vivier         cpu_fprintf(f, "S");
5102097dca6SLaurent Vivier         break;
5112097dca6SLaurent Vivier     default:
5122097dca6SLaurent Vivier         cpu_fprintf(f, "*");
5132097dca6SLaurent Vivier         break;
5142097dca6SLaurent Vivier     }
5152097dca6SLaurent Vivier     DUMP_CACHEFLAGS(ttr);
5162097dca6SLaurent Vivier     if (ttr & M68K_DESC_WRITEPROT) {
5172097dca6SLaurent Vivier         cpu_fprintf(f, "R");
5182097dca6SLaurent Vivier     } else {
5192097dca6SLaurent Vivier         cpu_fprintf(f, "W");
5202097dca6SLaurent Vivier     }
5212097dca6SLaurent Vivier     cpu_fprintf(f, " U: %d\n", (ttr & M68K_DESC_USERATTR) >>
5222097dca6SLaurent Vivier                                M68K_DESC_USERATTR_SHIFT);
5232097dca6SLaurent Vivier }
5242097dca6SLaurent Vivier 
5252097dca6SLaurent Vivier void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env)
5262097dca6SLaurent Vivier {
5272097dca6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
5282097dca6SLaurent Vivier         cpu_fprintf(f, "Translation disabled\n");
5292097dca6SLaurent Vivier         return;
5302097dca6SLaurent Vivier     }
5312097dca6SLaurent Vivier     cpu_fprintf(f, "Page Size: ");
5322097dca6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
5332097dca6SLaurent Vivier         cpu_fprintf(f, "8kB\n");
5342097dca6SLaurent Vivier     } else {
5352097dca6SLaurent Vivier         cpu_fprintf(f, "4kB\n");
5362097dca6SLaurent Vivier     }
5372097dca6SLaurent Vivier 
5382097dca6SLaurent Vivier     cpu_fprintf(f, "MMUSR: ");
5392097dca6SLaurent Vivier     if (env->mmu.mmusr & M68K_MMU_B_040) {
5402097dca6SLaurent Vivier         cpu_fprintf(f, "BUS ERROR\n");
5412097dca6SLaurent Vivier     } else {
5422097dca6SLaurent Vivier         cpu_fprintf(f, "Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
5432097dca6SLaurent Vivier         /* flags found on the page descriptor */
5442097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_G_040) {
5452097dca6SLaurent Vivier             cpu_fprintf(f, "G"); /* Global */
5462097dca6SLaurent Vivier         } else {
5472097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5482097dca6SLaurent Vivier         }
5492097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_S_040) {
5502097dca6SLaurent Vivier             cpu_fprintf(f, "S"); /* Supervisor */
5512097dca6SLaurent Vivier         } else {
5522097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5532097dca6SLaurent Vivier         }
5542097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_M_040) {
5552097dca6SLaurent Vivier             cpu_fprintf(f, "M"); /* Modified */
5562097dca6SLaurent Vivier         } else {
5572097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5582097dca6SLaurent Vivier         }
5592097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_WP_040) {
5602097dca6SLaurent Vivier             cpu_fprintf(f, "W"); /* Write protect */
5612097dca6SLaurent Vivier         } else {
5622097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5632097dca6SLaurent Vivier         }
5642097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_T_040) {
5652097dca6SLaurent Vivier             cpu_fprintf(f, "T"); /* Transparent */
5662097dca6SLaurent Vivier         } else {
5672097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5682097dca6SLaurent Vivier         }
5692097dca6SLaurent Vivier         if (env->mmu.mmusr & M68K_MMU_R_040) {
5702097dca6SLaurent Vivier             cpu_fprintf(f, "R"); /* Resident */
5712097dca6SLaurent Vivier         } else {
5722097dca6SLaurent Vivier             cpu_fprintf(f, ".");
5732097dca6SLaurent Vivier         }
5742097dca6SLaurent Vivier         cpu_fprintf(f, " Cache: ");
5752097dca6SLaurent Vivier         DUMP_CACHEFLAGS(env->mmu.mmusr);
5762097dca6SLaurent Vivier         cpu_fprintf(f, " U: %d\n", (env->mmu.mmusr >> 8) & 3);
5772097dca6SLaurent Vivier         cpu_fprintf(f, "\n");
5782097dca6SLaurent Vivier     }
5792097dca6SLaurent Vivier 
5802097dca6SLaurent Vivier     cpu_fprintf(f, "ITTR0: ");
5812097dca6SLaurent Vivier     dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR0]);
5822097dca6SLaurent Vivier     cpu_fprintf(f, "ITTR1: ");
5832097dca6SLaurent Vivier     dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR1]);
5842097dca6SLaurent Vivier     cpu_fprintf(f, "DTTR0: ");
5852097dca6SLaurent Vivier     dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR0]);
5862097dca6SLaurent Vivier     cpu_fprintf(f, "DTTR1: ");
5872097dca6SLaurent Vivier     dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR1]);
5882097dca6SLaurent Vivier 
5892097dca6SLaurent Vivier     cpu_fprintf(f, "SRP: 0x%08x\n", env->mmu.srp);
5902097dca6SLaurent Vivier     dump_address_map(f, cpu_fprintf, env, env->mmu.srp);
5912097dca6SLaurent Vivier 
5922097dca6SLaurent Vivier     cpu_fprintf(f, "URP: 0x%08x\n", env->mmu.urp);
5932097dca6SLaurent Vivier     dump_address_map(f, cpu_fprintf, env, env->mmu.urp);
5942097dca6SLaurent Vivier }
5952097dca6SLaurent Vivier 
596c05c73b0SLaurent Vivier static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
597c05c73b0SLaurent Vivier                      int access_type)
598c05c73b0SLaurent Vivier {
599c05c73b0SLaurent Vivier     uint32_t base, mask;
600c05c73b0SLaurent Vivier 
601c05c73b0SLaurent Vivier     /* check if transparent translation is enabled */
602c05c73b0SLaurent Vivier     if ((ttr & M68K_TTR_ENABLED) == 0) {
603c05c73b0SLaurent Vivier         return 0;
604c05c73b0SLaurent Vivier     }
605c05c73b0SLaurent Vivier 
606c05c73b0SLaurent Vivier     /* check mode access */
607c05c73b0SLaurent Vivier     switch (ttr & M68K_TTR_SFIELD) {
608c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_USER:
609c05c73b0SLaurent Vivier         /* match only if user */
610c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) != 0) {
611c05c73b0SLaurent Vivier             return 0;
612c05c73b0SLaurent Vivier         }
613c05c73b0SLaurent Vivier         break;
614c05c73b0SLaurent Vivier     case M68K_TTR_SFIELD_SUPER:
615c05c73b0SLaurent Vivier         /* match only if supervisor */
616c05c73b0SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
617c05c73b0SLaurent Vivier             return 0;
618c05c73b0SLaurent Vivier         }
619c05c73b0SLaurent Vivier         break;
620c05c73b0SLaurent Vivier     default:
621c05c73b0SLaurent Vivier         /* all other values disable mode matching (FC2) */
622c05c73b0SLaurent Vivier         break;
623c05c73b0SLaurent Vivier     }
624c05c73b0SLaurent Vivier 
625c05c73b0SLaurent Vivier     /* check address matching */
626c05c73b0SLaurent Vivier 
627c05c73b0SLaurent Vivier     base = ttr & M68K_TTR_ADDR_BASE;
628c05c73b0SLaurent Vivier     mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
629c05c73b0SLaurent Vivier     mask <<= M68K_TTR_ADDR_MASK_SHIFT;
630c05c73b0SLaurent Vivier 
631c05c73b0SLaurent Vivier     if ((addr & mask) != (base & mask)) {
632c05c73b0SLaurent Vivier         return 0;
633c05c73b0SLaurent Vivier     }
634c05c73b0SLaurent Vivier 
635c05c73b0SLaurent Vivier     *prot = PAGE_READ | PAGE_EXEC;
636c05c73b0SLaurent Vivier     if ((ttr & M68K_DESC_WRITEPROT) == 0) {
637c05c73b0SLaurent Vivier         *prot |= PAGE_WRITE;
638c05c73b0SLaurent Vivier     }
639c05c73b0SLaurent Vivier 
640c05c73b0SLaurent Vivier     return 1;
641c05c73b0SLaurent Vivier }
642c05c73b0SLaurent Vivier 
64388b2fef6SLaurent Vivier static int get_physical_address(CPUM68KState *env, hwaddr *physical,
64488b2fef6SLaurent Vivier                                 int *prot, target_ulong address,
64588b2fef6SLaurent Vivier                                 int access_type, target_ulong *page_size)
64688b2fef6SLaurent Vivier {
64788b2fef6SLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
64888b2fef6SLaurent Vivier     CPUState *cs = CPU(cpu);
64988b2fef6SLaurent Vivier     uint32_t entry;
65088b2fef6SLaurent Vivier     uint32_t next;
65188b2fef6SLaurent Vivier     target_ulong page_mask;
65288b2fef6SLaurent Vivier     bool debug = access_type & ACCESS_DEBUG;
65388b2fef6SLaurent Vivier     int page_bits;
654c05c73b0SLaurent Vivier     int i;
655c05c73b0SLaurent Vivier 
656c05c73b0SLaurent Vivier     /* Transparent Translation (physical = logical) */
657c05c73b0SLaurent Vivier     for (i = 0; i < M68K_MAX_TTR; i++) {
658c05c73b0SLaurent Vivier         if (check_TTR(env->mmu.TTR(access_type, i),
659c05c73b0SLaurent Vivier                       prot, address, access_type)) {
660e55886c3SLaurent Vivier             if (access_type & ACCESS_PTEST) {
661e55886c3SLaurent Vivier                 /* Transparent Translation Register bit */
662e55886c3SLaurent Vivier                 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
663e55886c3SLaurent Vivier             }
664c05c73b0SLaurent Vivier             *physical = address & TARGET_PAGE_MASK;
665c05c73b0SLaurent Vivier             *page_size = TARGET_PAGE_SIZE;
666c05c73b0SLaurent Vivier             return 0;
667c05c73b0SLaurent Vivier         }
668c05c73b0SLaurent Vivier     }
66988b2fef6SLaurent Vivier 
67088b2fef6SLaurent Vivier     /* Page Table Root Pointer */
67188b2fef6SLaurent Vivier     *prot = PAGE_READ | PAGE_WRITE;
67288b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
67388b2fef6SLaurent Vivier         *prot |= PAGE_EXEC;
67488b2fef6SLaurent Vivier     }
67588b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
67688b2fef6SLaurent Vivier         next = env->mmu.srp;
67788b2fef6SLaurent Vivier     } else {
67888b2fef6SLaurent Vivier         next = env->mmu.urp;
67988b2fef6SLaurent Vivier     }
68088b2fef6SLaurent Vivier 
68188b2fef6SLaurent Vivier     /* Root Index */
68288b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
68388b2fef6SLaurent Vivier 
68488b2fef6SLaurent Vivier     next = ldl_phys(cs->as, entry);
68588b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
68688b2fef6SLaurent Vivier         return -1;
68788b2fef6SLaurent Vivier     }
68888b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
68988b2fef6SLaurent Vivier         stl_phys(cs->as, entry, next | M68K_DESC_USED);
69088b2fef6SLaurent Vivier     }
69188b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
692e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
693e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
694e55886c3SLaurent Vivier         }
69588b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
69688b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
69788b2fef6SLaurent Vivier             return -1;
69888b2fef6SLaurent Vivier         }
69988b2fef6SLaurent Vivier     }
70088b2fef6SLaurent Vivier 
70188b2fef6SLaurent Vivier     /* Pointer Index */
70288b2fef6SLaurent Vivier     entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
70388b2fef6SLaurent Vivier 
70488b2fef6SLaurent Vivier     next = ldl_phys(cs->as, entry);
70588b2fef6SLaurent Vivier     if (!M68K_UDT_VALID(next)) {
70688b2fef6SLaurent Vivier         return -1;
70788b2fef6SLaurent Vivier     }
70888b2fef6SLaurent Vivier     if (!(next & M68K_DESC_USED) && !debug) {
70988b2fef6SLaurent Vivier         stl_phys(cs->as, entry, next | M68K_DESC_USED);
71088b2fef6SLaurent Vivier     }
71188b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
712e55886c3SLaurent Vivier         if (access_type & ACCESS_PTEST) {
713e55886c3SLaurent Vivier             env->mmu.mmusr |= M68K_MMU_WP_040;
714e55886c3SLaurent Vivier         }
71588b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
71688b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
71788b2fef6SLaurent Vivier             return -1;
71888b2fef6SLaurent Vivier         }
71988b2fef6SLaurent Vivier     }
72088b2fef6SLaurent Vivier 
72188b2fef6SLaurent Vivier     /* Page Index */
72288b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
72388b2fef6SLaurent Vivier         entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
72488b2fef6SLaurent Vivier     } else {
72588b2fef6SLaurent Vivier         entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
72688b2fef6SLaurent Vivier     }
72788b2fef6SLaurent Vivier 
72888b2fef6SLaurent Vivier     next = ldl_phys(cs->as, entry);
72988b2fef6SLaurent Vivier 
73088b2fef6SLaurent Vivier     if (!M68K_PDT_VALID(next)) {
73188b2fef6SLaurent Vivier         return -1;
73288b2fef6SLaurent Vivier     }
73388b2fef6SLaurent Vivier     if (M68K_PDT_INDIRECT(next)) {
73488b2fef6SLaurent Vivier         next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next));
73588b2fef6SLaurent Vivier     }
73688b2fef6SLaurent Vivier     if (access_type & ACCESS_STORE) {
73788b2fef6SLaurent Vivier         if (next & M68K_DESC_WRITEPROT) {
73888b2fef6SLaurent Vivier             if (!(next & M68K_DESC_USED) && !debug) {
73988b2fef6SLaurent Vivier                 stl_phys(cs->as, entry, next | M68K_DESC_USED);
74088b2fef6SLaurent Vivier             }
74188b2fef6SLaurent Vivier         } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
74288b2fef6SLaurent Vivier                            (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
74388b2fef6SLaurent Vivier                 stl_phys(cs->as, entry,
74488b2fef6SLaurent Vivier                          next | (M68K_DESC_MODIFIED | M68K_DESC_USED));
74588b2fef6SLaurent Vivier         }
74688b2fef6SLaurent Vivier     } else {
74788b2fef6SLaurent Vivier         if (!(next & M68K_DESC_USED) && !debug) {
74888b2fef6SLaurent Vivier             stl_phys(cs->as, entry, next | M68K_DESC_USED);
74988b2fef6SLaurent Vivier         }
75088b2fef6SLaurent Vivier     }
75188b2fef6SLaurent Vivier 
75288b2fef6SLaurent Vivier     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
75388b2fef6SLaurent Vivier         page_bits = 13;
75488b2fef6SLaurent Vivier     } else {
75588b2fef6SLaurent Vivier         page_bits = 12;
75688b2fef6SLaurent Vivier     }
75788b2fef6SLaurent Vivier     *page_size = 1 << page_bits;
75888b2fef6SLaurent Vivier     page_mask = ~(*page_size - 1);
75988b2fef6SLaurent Vivier     *physical = next & page_mask;
76088b2fef6SLaurent Vivier 
761e55886c3SLaurent Vivier     if (access_type & ACCESS_PTEST) {
762e55886c3SLaurent Vivier         env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
763e55886c3SLaurent Vivier         env->mmu.mmusr |= *physical & 0xfffff000;
764e55886c3SLaurent Vivier         env->mmu.mmusr |= M68K_MMU_R_040;
765e55886c3SLaurent Vivier     }
766e55886c3SLaurent Vivier 
76788b2fef6SLaurent Vivier     if (next & M68K_DESC_WRITEPROT) {
76888b2fef6SLaurent Vivier         *prot &= ~PAGE_WRITE;
76988b2fef6SLaurent Vivier         if (access_type & ACCESS_STORE) {
77088b2fef6SLaurent Vivier             return -1;
77188b2fef6SLaurent Vivier         }
77288b2fef6SLaurent Vivier     }
77388b2fef6SLaurent Vivier     if (next & M68K_DESC_SUPERONLY) {
77488b2fef6SLaurent Vivier         if ((access_type & ACCESS_SUPER) == 0) {
77588b2fef6SLaurent Vivier             return -1;
77688b2fef6SLaurent Vivier         }
77788b2fef6SLaurent Vivier     }
77888b2fef6SLaurent Vivier 
77988b2fef6SLaurent Vivier     return 0;
78088b2fef6SLaurent Vivier }
78188b2fef6SLaurent Vivier 
78200b941e5SAndreas Färber hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
7834fcc562bSPaul Brook {
78488b2fef6SLaurent Vivier     M68kCPU *cpu = M68K_CPU(cs);
78588b2fef6SLaurent Vivier     CPUM68KState *env = &cpu->env;
78688b2fef6SLaurent Vivier     hwaddr phys_addr;
78788b2fef6SLaurent Vivier     int prot;
78888b2fef6SLaurent Vivier     int access_type;
78988b2fef6SLaurent Vivier     target_ulong page_size;
79088b2fef6SLaurent Vivier 
79188b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
79288b2fef6SLaurent Vivier         /* MMU disabled */
7934fcc562bSPaul Brook         return addr;
7944fcc562bSPaul Brook     }
7954fcc562bSPaul Brook 
79688b2fef6SLaurent Vivier     access_type = ACCESS_DATA | ACCESS_DEBUG;
79788b2fef6SLaurent Vivier     if (env->sr & SR_S) {
79888b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
79988b2fef6SLaurent Vivier     }
80088b2fef6SLaurent Vivier     if (get_physical_address(env, &phys_addr, &prot,
80188b2fef6SLaurent Vivier                              addr, access_type, &page_size) != 0) {
80288b2fef6SLaurent Vivier         return -1;
80388b2fef6SLaurent Vivier     }
80488b2fef6SLaurent Vivier     return phys_addr;
80588b2fef6SLaurent Vivier }
80688b2fef6SLaurent Vivier 
80798670d47SLaurent Vivier int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
80897b348e7SBlue Swirl                               int mmu_idx)
8090633879fSpbrook {
81088b2fef6SLaurent Vivier     M68kCPU *cpu = M68K_CPU(cs);
81188b2fef6SLaurent Vivier     CPUM68KState *env = &cpu->env;
81288b2fef6SLaurent Vivier     hwaddr physical;
8130633879fSpbrook     int prot;
81488b2fef6SLaurent Vivier     int access_type;
81588b2fef6SLaurent Vivier     int ret;
81688b2fef6SLaurent Vivier     target_ulong page_size;
8170633879fSpbrook 
81888b2fef6SLaurent Vivier     if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
81988b2fef6SLaurent Vivier         /* MMU disabled */
82088b2fef6SLaurent Vivier         tlb_set_page(cs, address & TARGET_PAGE_MASK,
82188b2fef6SLaurent Vivier                      address & TARGET_PAGE_MASK,
82288b2fef6SLaurent Vivier                      PAGE_READ | PAGE_WRITE | PAGE_EXEC,
82388b2fef6SLaurent Vivier                      mmu_idx, TARGET_PAGE_SIZE);
824d4c430a8SPaul Brook         return 0;
8250633879fSpbrook     }
8260633879fSpbrook 
82788b2fef6SLaurent Vivier     if (rw == 2) {
82888b2fef6SLaurent Vivier         access_type = ACCESS_CODE;
82988b2fef6SLaurent Vivier         rw = 0;
83088b2fef6SLaurent Vivier     } else {
83188b2fef6SLaurent Vivier         access_type = ACCESS_DATA;
83288b2fef6SLaurent Vivier         if (rw) {
83388b2fef6SLaurent Vivier             access_type |= ACCESS_STORE;
83488b2fef6SLaurent Vivier         }
83588b2fef6SLaurent Vivier     }
83688b2fef6SLaurent Vivier 
83788b2fef6SLaurent Vivier     if (mmu_idx != MMU_USER_IDX) {
83888b2fef6SLaurent Vivier         access_type |= ACCESS_SUPER;
83988b2fef6SLaurent Vivier     }
84088b2fef6SLaurent Vivier 
84188b2fef6SLaurent Vivier     ret = get_physical_address(&cpu->env, &physical, &prot,
84288b2fef6SLaurent Vivier                                address, access_type, &page_size);
84388b2fef6SLaurent Vivier     if (ret == 0) {
84488b2fef6SLaurent Vivier         address &= TARGET_PAGE_MASK;
84588b2fef6SLaurent Vivier         physical += address & (page_size - 1);
84688b2fef6SLaurent Vivier         tlb_set_page(cs, address, physical,
84788b2fef6SLaurent Vivier                      prot, mmu_idx, TARGET_PAGE_SIZE);
84888b2fef6SLaurent Vivier         return 0;
84988b2fef6SLaurent Vivier     }
85088b2fef6SLaurent Vivier     /* page fault */
85188b2fef6SLaurent Vivier     env->mmu.ssw = M68K_ATC_040;
85288b2fef6SLaurent Vivier     switch (size) {
85388b2fef6SLaurent Vivier     case 1:
85488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_BYTE;
85588b2fef6SLaurent Vivier         break;
85688b2fef6SLaurent Vivier     case 2:
85788b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_WORD;
85888b2fef6SLaurent Vivier         break;
85988b2fef6SLaurent Vivier     case 4:
86088b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_BA_SIZE_LONG;
86188b2fef6SLaurent Vivier         break;
86288b2fef6SLaurent Vivier     }
86388b2fef6SLaurent Vivier     if (access_type & ACCESS_SUPER) {
86488b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_SUPER;
86588b2fef6SLaurent Vivier     }
86688b2fef6SLaurent Vivier     if (access_type & ACCESS_CODE) {
86788b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_CODE;
86888b2fef6SLaurent Vivier     } else {
86988b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_TM_040_DATA;
87088b2fef6SLaurent Vivier     }
87188b2fef6SLaurent Vivier     if (!(access_type & ACCESS_STORE)) {
87288b2fef6SLaurent Vivier         env->mmu.ssw |= M68K_RW_040;
87388b2fef6SLaurent Vivier     }
87488b2fef6SLaurent Vivier     env->mmu.ar = address;
87588b2fef6SLaurent Vivier     cs->exception_index = EXCP_ACCESS;
87688b2fef6SLaurent Vivier     return 1;
87788b2fef6SLaurent Vivier }
87888b2fef6SLaurent Vivier 
8790633879fSpbrook /* Notify CPU of a pending interrupt.  Prioritization and vectoring should
8800633879fSpbrook    be handled by the interrupt controller.  Real hardware only requests
8810633879fSpbrook    the vector when the interrupt is acknowledged by the CPU.  For
8820633879fSpbrook    simplicitly we calculate it when the interrupt is signalled.  */
883cb3fb38eSAndreas Färber void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
8840633879fSpbrook {
885d8ed887bSAndreas Färber     CPUState *cs = CPU(cpu);
886cb3fb38eSAndreas Färber     CPUM68KState *env = &cpu->env;
887cb3fb38eSAndreas Färber 
8880633879fSpbrook     env->pending_level = level;
8890633879fSpbrook     env->pending_vector = vector;
890d8ed887bSAndreas Färber     if (level) {
891c3affe56SAndreas Färber         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
892d8ed887bSAndreas Färber     } else {
893d8ed887bSAndreas Färber         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
894d8ed887bSAndreas Färber     }
8950633879fSpbrook }
8960633879fSpbrook 
8970633879fSpbrook #endif
898e1f3808eSpbrook 
899e1f3808eSpbrook uint32_t HELPER(bitrev)(uint32_t x)
900e1f3808eSpbrook {
901e1f3808eSpbrook     x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
902e1f3808eSpbrook     x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
903e1f3808eSpbrook     x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
904e1f3808eSpbrook     return bswap32(x);
905e1f3808eSpbrook }
906e1f3808eSpbrook 
907e1f3808eSpbrook uint32_t HELPER(ff1)(uint32_t x)
908e1f3808eSpbrook {
909e1f3808eSpbrook     int n;
910e1f3808eSpbrook     for (n = 32; x; n--)
911e1f3808eSpbrook         x >>= 1;
912e1f3808eSpbrook     return n;
913e1f3808eSpbrook }
914e1f3808eSpbrook 
915620c6cf6SRichard Henderson uint32_t HELPER(sats)(uint32_t val, uint32_t v)
916e1f3808eSpbrook {
917e1f3808eSpbrook     /* The result has the opposite sign to the original value.  */
918620c6cf6SRichard Henderson     if ((int32_t)v < 0) {
919e1f3808eSpbrook         val = (((int32_t)val) >> 31) ^ SIGNBIT;
920620c6cf6SRichard Henderson     }
921e1f3808eSpbrook     return val;
922e1f3808eSpbrook }
923e1f3808eSpbrook 
924d2f8fb8eSLaurent Vivier void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
925e1f3808eSpbrook {
926d2f8fb8eSLaurent Vivier     env->sr = sr & 0xffe0;
927d2f8fb8eSLaurent Vivier     cpu_m68k_set_ccr(env, sr);
928e1f3808eSpbrook     m68k_switch_sp(env);
929e1f3808eSpbrook }
930e1f3808eSpbrook 
931d2f8fb8eSLaurent Vivier void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
932d2f8fb8eSLaurent Vivier {
933d2f8fb8eSLaurent Vivier     cpu_m68k_set_sr(env, val);
934d2f8fb8eSLaurent Vivier }
935e1f3808eSpbrook 
936e1f3808eSpbrook /* MAC unit.  */
937e1f3808eSpbrook /* FIXME: The MAC unit implementation is a bit of a mess.  Some helpers
938e1f3808eSpbrook    take values,  others take register numbers and manipulate the contents
939e1f3808eSpbrook    in-place.  */
9402b3e3cfeSAndreas Färber void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
941e1f3808eSpbrook {
942e1f3808eSpbrook     uint32_t mask;
943e1f3808eSpbrook     env->macc[dest] = env->macc[src];
944e1f3808eSpbrook     mask = MACSR_PAV0 << dest;
945e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << src))
946e1f3808eSpbrook         env->macsr |= mask;
947e1f3808eSpbrook     else
948e1f3808eSpbrook         env->macsr &= ~mask;
949e1f3808eSpbrook }
950e1f3808eSpbrook 
9512b3e3cfeSAndreas Färber uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
952e1f3808eSpbrook {
953e1f3808eSpbrook     int64_t product;
954e1f3808eSpbrook     int64_t res;
955e1f3808eSpbrook 
956e1f3808eSpbrook     product = (uint64_t)op1 * op2;
957e1f3808eSpbrook     res = (product << 24) >> 24;
958e1f3808eSpbrook     if (res != product) {
959e1f3808eSpbrook         env->macsr |= MACSR_V;
960e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
961e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
962e1f3808eSpbrook             if (product < 0)
963e1f3808eSpbrook                 res = ~(1ll << 50);
964e1f3808eSpbrook             else
965e1f3808eSpbrook                 res = 1ll << 50;
966e1f3808eSpbrook         }
967e1f3808eSpbrook     }
968e1f3808eSpbrook     return res;
969e1f3808eSpbrook }
970e1f3808eSpbrook 
9712b3e3cfeSAndreas Färber uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
972e1f3808eSpbrook {
973e1f3808eSpbrook     uint64_t product;
974e1f3808eSpbrook 
975e1f3808eSpbrook     product = (uint64_t)op1 * op2;
976e1f3808eSpbrook     if (product & (0xffffffull << 40)) {
977e1f3808eSpbrook         env->macsr |= MACSR_V;
978e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
979e1f3808eSpbrook             /* Make sure the accumulate operation overflows.  */
980e1f3808eSpbrook             product = 1ll << 50;
981e1f3808eSpbrook         } else {
982e1f3808eSpbrook             product &= ((1ull << 40) - 1);
983e1f3808eSpbrook         }
984e1f3808eSpbrook     }
985e1f3808eSpbrook     return product;
986e1f3808eSpbrook }
987e1f3808eSpbrook 
9882b3e3cfeSAndreas Färber uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
989e1f3808eSpbrook {
990e1f3808eSpbrook     uint64_t product;
991e1f3808eSpbrook     uint32_t remainder;
992e1f3808eSpbrook 
993e1f3808eSpbrook     product = (uint64_t)op1 * op2;
994e1f3808eSpbrook     if (env->macsr & MACSR_RT) {
995e1f3808eSpbrook         remainder = product & 0xffffff;
996e1f3808eSpbrook         product >>= 24;
997e1f3808eSpbrook         if (remainder > 0x800000)
998e1f3808eSpbrook             product++;
999e1f3808eSpbrook         else if (remainder == 0x800000)
1000e1f3808eSpbrook             product += (product & 1);
1001e1f3808eSpbrook     } else {
1002e1f3808eSpbrook         product >>= 24;
1003e1f3808eSpbrook     }
1004e1f3808eSpbrook     return product;
1005e1f3808eSpbrook }
1006e1f3808eSpbrook 
10072b3e3cfeSAndreas Färber void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
1008e1f3808eSpbrook {
1009e1f3808eSpbrook     int64_t tmp;
1010e1f3808eSpbrook     int64_t result;
1011e1f3808eSpbrook     tmp = env->macc[acc];
1012e1f3808eSpbrook     result = ((tmp << 16) >> 16);
1013e1f3808eSpbrook     if (result != tmp) {
1014e1f3808eSpbrook         env->macsr |= MACSR_V;
1015e1f3808eSpbrook     }
1016e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1017e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1018e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1019a1c7273bSStefan Weil             /* The result is saturated to 32 bits, despite overflow occurring
1020e1f3808eSpbrook                at 48 bits.  Seems weird, but that's what the hardware docs
1021e1f3808eSpbrook                say.  */
1022e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffff;
1023e1f3808eSpbrook         }
1024e1f3808eSpbrook     }
1025e1f3808eSpbrook     env->macc[acc] = result;
1026e1f3808eSpbrook }
1027e1f3808eSpbrook 
10282b3e3cfeSAndreas Färber void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1029e1f3808eSpbrook {
1030e1f3808eSpbrook     uint64_t val;
1031e1f3808eSpbrook 
1032e1f3808eSpbrook     val = env->macc[acc];
1033e1f3808eSpbrook     if (val & (0xffffull << 48)) {
1034e1f3808eSpbrook         env->macsr |= MACSR_V;
1035e1f3808eSpbrook     }
1036e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1037e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1038e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1039e1f3808eSpbrook             if (val > (1ull << 53))
1040e1f3808eSpbrook                 val = 0;
1041e1f3808eSpbrook             else
1042e1f3808eSpbrook                 val = (1ull << 48) - 1;
1043e1f3808eSpbrook         } else {
1044e1f3808eSpbrook             val &= ((1ull << 48) - 1);
1045e1f3808eSpbrook         }
1046e1f3808eSpbrook     }
1047e1f3808eSpbrook     env->macc[acc] = val;
1048e1f3808eSpbrook }
1049e1f3808eSpbrook 
10502b3e3cfeSAndreas Färber void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1051e1f3808eSpbrook {
1052e1f3808eSpbrook     int64_t sum;
1053e1f3808eSpbrook     int64_t result;
1054e1f3808eSpbrook 
1055e1f3808eSpbrook     sum = env->macc[acc];
1056e1f3808eSpbrook     result = (sum << 16) >> 16;
1057e1f3808eSpbrook     if (result != sum) {
1058e1f3808eSpbrook         env->macsr |= MACSR_V;
1059e1f3808eSpbrook     }
1060e1f3808eSpbrook     if (env->macsr & MACSR_V) {
1061e1f3808eSpbrook         env->macsr |= MACSR_PAV0 << acc;
1062e1f3808eSpbrook         if (env->macsr & MACSR_OMC) {
1063e1f3808eSpbrook             result = (result >> 63) ^ 0x7fffffffffffll;
1064e1f3808eSpbrook         }
1065e1f3808eSpbrook     }
1066e1f3808eSpbrook     env->macc[acc] = result;
1067e1f3808eSpbrook }
1068e1f3808eSpbrook 
10692b3e3cfeSAndreas Färber void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1070e1f3808eSpbrook {
1071e1f3808eSpbrook     uint64_t val;
1072e1f3808eSpbrook     val = env->macc[acc];
1073c4162574SBlue Swirl     if (val == 0) {
1074e1f3808eSpbrook         env->macsr |= MACSR_Z;
1075c4162574SBlue Swirl     } else if (val & (1ull << 47)) {
1076e1f3808eSpbrook         env->macsr |= MACSR_N;
1077c4162574SBlue Swirl     }
1078e1f3808eSpbrook     if (env->macsr & (MACSR_PAV0 << acc)) {
1079e1f3808eSpbrook         env->macsr |= MACSR_V;
1080e1f3808eSpbrook     }
1081e1f3808eSpbrook     if (env->macsr & MACSR_FI) {
1082e1f3808eSpbrook         val = ((int64_t)val) >> 40;
1083e1f3808eSpbrook         if (val != 0 && val != -1)
1084e1f3808eSpbrook             env->macsr |= MACSR_EV;
1085e1f3808eSpbrook     } else if (env->macsr & MACSR_SU) {
1086e1f3808eSpbrook         val = ((int64_t)val) >> 32;
1087e1f3808eSpbrook         if (val != 0 && val != -1)
1088e1f3808eSpbrook             env->macsr |= MACSR_EV;
1089e1f3808eSpbrook     } else {
1090e1f3808eSpbrook         if ((val >> 32) != 0)
1091e1f3808eSpbrook             env->macsr |= MACSR_EV;
1092e1f3808eSpbrook     }
1093e1f3808eSpbrook }
1094e1f3808eSpbrook 
1095db3d7945SLaurent Vivier #define EXTSIGN(val, index) (     \
1096db3d7945SLaurent Vivier     (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1097db3d7945SLaurent Vivier )
1098620c6cf6SRichard Henderson 
1099620c6cf6SRichard Henderson #define COMPUTE_CCR(op, x, n, z, v, c) {                                   \
1100620c6cf6SRichard Henderson     switch (op) {                                                          \
1101620c6cf6SRichard Henderson     case CC_OP_FLAGS:                                                      \
1102620c6cf6SRichard Henderson         /* Everything in place.  */                                        \
1103620c6cf6SRichard Henderson         break;                                                             \
1104db3d7945SLaurent Vivier     case CC_OP_ADDB:                                                       \
1105db3d7945SLaurent Vivier     case CC_OP_ADDW:                                                       \
1106db3d7945SLaurent Vivier     case CC_OP_ADDL:                                                       \
1107620c6cf6SRichard Henderson         res = n;                                                           \
1108620c6cf6SRichard Henderson         src2 = v;                                                          \
1109db3d7945SLaurent Vivier         src1 = EXTSIGN(res - src2, op - CC_OP_ADDB);                       \
1110620c6cf6SRichard Henderson         c = x;                                                             \
1111620c6cf6SRichard Henderson         z = n;                                                             \
1112620c6cf6SRichard Henderson         v = (res ^ src1) & ~(src1 ^ src2);                                 \
1113620c6cf6SRichard Henderson         break;                                                             \
1114db3d7945SLaurent Vivier     case CC_OP_SUBB:                                                       \
1115db3d7945SLaurent Vivier     case CC_OP_SUBW:                                                       \
1116db3d7945SLaurent Vivier     case CC_OP_SUBL:                                                       \
1117620c6cf6SRichard Henderson         res = n;                                                           \
1118620c6cf6SRichard Henderson         src2 = v;                                                          \
1119db3d7945SLaurent Vivier         src1 = EXTSIGN(res + src2, op - CC_OP_SUBB);                       \
1120620c6cf6SRichard Henderson         c = x;                                                             \
1121620c6cf6SRichard Henderson         z = n;                                                             \
1122620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1123620c6cf6SRichard Henderson         break;                                                             \
1124db3d7945SLaurent Vivier     case CC_OP_CMPB:                                                       \
1125db3d7945SLaurent Vivier     case CC_OP_CMPW:                                                       \
1126db3d7945SLaurent Vivier     case CC_OP_CMPL:                                                       \
1127620c6cf6SRichard Henderson         src1 = n;                                                          \
1128620c6cf6SRichard Henderson         src2 = v;                                                          \
1129db3d7945SLaurent Vivier         res = EXTSIGN(src1 - src2, op - CC_OP_CMPB);                       \
1130620c6cf6SRichard Henderson         n = res;                                                           \
1131620c6cf6SRichard Henderson         z = res;                                                           \
1132620c6cf6SRichard Henderson         c = src1 < src2;                                                   \
1133620c6cf6SRichard Henderson         v = (res ^ src1) & (src1 ^ src2);                                  \
1134620c6cf6SRichard Henderson         break;                                                             \
1135620c6cf6SRichard Henderson     case CC_OP_LOGIC:                                                      \
1136620c6cf6SRichard Henderson         c = v = 0;                                                         \
1137620c6cf6SRichard Henderson         z = n;                                                             \
1138620c6cf6SRichard Henderson         break;                                                             \
1139620c6cf6SRichard Henderson     default:                                                               \
1140620c6cf6SRichard Henderson         cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op);         \
1141620c6cf6SRichard Henderson     }                                                                      \
1142620c6cf6SRichard Henderson } while (0)
1143620c6cf6SRichard Henderson 
1144620c6cf6SRichard Henderson uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1145e1f3808eSpbrook {
1146620c6cf6SRichard Henderson     uint32_t x, c, n, z, v;
1147620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1148620c6cf6SRichard Henderson 
1149620c6cf6SRichard Henderson     x = env->cc_x;
1150620c6cf6SRichard Henderson     n = env->cc_n;
1151620c6cf6SRichard Henderson     z = env->cc_z;
1152620c6cf6SRichard Henderson     v = env->cc_v;
1153db3d7945SLaurent Vivier     c = env->cc_c;
1154620c6cf6SRichard Henderson 
1155620c6cf6SRichard Henderson     COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1156620c6cf6SRichard Henderson 
1157620c6cf6SRichard Henderson     n = n >> 31;
1158620c6cf6SRichard Henderson     z = (z == 0);
1159db3d7945SLaurent Vivier     v = v >> 31;
1160620c6cf6SRichard Henderson 
1161620c6cf6SRichard Henderson     return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1162620c6cf6SRichard Henderson }
1163620c6cf6SRichard Henderson 
1164620c6cf6SRichard Henderson uint32_t HELPER(get_ccr)(CPUM68KState *env)
1165620c6cf6SRichard Henderson {
1166620c6cf6SRichard Henderson     return cpu_m68k_get_ccr(env);
1167620c6cf6SRichard Henderson }
1168620c6cf6SRichard Henderson 
1169620c6cf6SRichard Henderson void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1170620c6cf6SRichard Henderson {
1171620c6cf6SRichard Henderson     env->cc_x = (ccr & CCF_X ? 1 : 0);
1172620c6cf6SRichard Henderson     env->cc_n = (ccr & CCF_N ? -1 : 0);
1173620c6cf6SRichard Henderson     env->cc_z = (ccr & CCF_Z ? 0 : 1);
1174620c6cf6SRichard Henderson     env->cc_v = (ccr & CCF_V ? -1 : 0);
1175620c6cf6SRichard Henderson     env->cc_c = (ccr & CCF_C ? 1 : 0);
1176620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1177620c6cf6SRichard Henderson }
1178620c6cf6SRichard Henderson 
1179620c6cf6SRichard Henderson void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1180620c6cf6SRichard Henderson {
1181620c6cf6SRichard Henderson     cpu_m68k_set_ccr(env, ccr);
1182620c6cf6SRichard Henderson }
1183620c6cf6SRichard Henderson 
1184620c6cf6SRichard Henderson void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1185620c6cf6SRichard Henderson {
1186620c6cf6SRichard Henderson     uint32_t res, src1, src2;
1187620c6cf6SRichard Henderson 
1188620c6cf6SRichard Henderson     COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1189620c6cf6SRichard Henderson     env->cc_op = CC_OP_FLAGS;
1190e1f3808eSpbrook }
1191e1f3808eSpbrook 
11922b3e3cfeSAndreas Färber uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1193e1f3808eSpbrook {
1194e1f3808eSpbrook     int rem;
1195e1f3808eSpbrook     uint32_t result;
1196e1f3808eSpbrook 
1197e1f3808eSpbrook     if (env->macsr & MACSR_SU) {
1198e1f3808eSpbrook         /* 16-bit rounding.  */
1199e1f3808eSpbrook         rem = val & 0xffffff;
1200e1f3808eSpbrook         val = (val >> 24) & 0xffffu;
1201e1f3808eSpbrook         if (rem > 0x800000)
1202e1f3808eSpbrook             val++;
1203e1f3808eSpbrook         else if (rem == 0x800000)
1204e1f3808eSpbrook             val += (val & 1);
1205e1f3808eSpbrook     } else if (env->macsr & MACSR_RT) {
1206e1f3808eSpbrook         /* 32-bit rounding.  */
1207e1f3808eSpbrook         rem = val & 0xff;
1208e1f3808eSpbrook         val >>= 8;
1209e1f3808eSpbrook         if (rem > 0x80)
1210e1f3808eSpbrook             val++;
1211e1f3808eSpbrook         else if (rem == 0x80)
1212e1f3808eSpbrook             val += (val & 1);
1213e1f3808eSpbrook     } else {
1214e1f3808eSpbrook         /* No rounding.  */
1215e1f3808eSpbrook         val >>= 8;
1216e1f3808eSpbrook     }
1217e1f3808eSpbrook     if (env->macsr & MACSR_OMC) {
1218e1f3808eSpbrook         /* Saturate.  */
1219e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1220e1f3808eSpbrook             if (val != (uint16_t) val) {
1221e1f3808eSpbrook                 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1222e1f3808eSpbrook             } else {
1223e1f3808eSpbrook                 result = val & 0xffff;
1224e1f3808eSpbrook             }
1225e1f3808eSpbrook         } else {
1226e1f3808eSpbrook             if (val != (uint32_t)val) {
1227e1f3808eSpbrook                 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1228e1f3808eSpbrook             } else {
1229e1f3808eSpbrook                 result = (uint32_t)val;
1230e1f3808eSpbrook             }
1231e1f3808eSpbrook         }
1232e1f3808eSpbrook     } else {
1233e1f3808eSpbrook         /* No saturation.  */
1234e1f3808eSpbrook         if (env->macsr & MACSR_SU) {
1235e1f3808eSpbrook             result = val & 0xffff;
1236e1f3808eSpbrook         } else {
1237e1f3808eSpbrook             result = (uint32_t)val;
1238e1f3808eSpbrook         }
1239e1f3808eSpbrook     }
1240e1f3808eSpbrook     return result;
1241e1f3808eSpbrook }
1242e1f3808eSpbrook 
1243e1f3808eSpbrook uint32_t HELPER(get_macs)(uint64_t val)
1244e1f3808eSpbrook {
1245e1f3808eSpbrook     if (val == (int32_t)val) {
1246e1f3808eSpbrook         return (int32_t)val;
1247e1f3808eSpbrook     } else {
1248e1f3808eSpbrook         return (val >> 61) ^ ~SIGNBIT;
1249e1f3808eSpbrook     }
1250e1f3808eSpbrook }
1251e1f3808eSpbrook 
1252e1f3808eSpbrook uint32_t HELPER(get_macu)(uint64_t val)
1253e1f3808eSpbrook {
1254e1f3808eSpbrook     if ((val >> 32) == 0) {
1255e1f3808eSpbrook         return (uint32_t)val;
1256e1f3808eSpbrook     } else {
1257e1f3808eSpbrook         return 0xffffffffu;
1258e1f3808eSpbrook     }
1259e1f3808eSpbrook }
1260e1f3808eSpbrook 
12612b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1262e1f3808eSpbrook {
1263e1f3808eSpbrook     uint32_t val;
1264e1f3808eSpbrook     val = env->macc[acc] & 0x00ff;
12655ce747cfSPaolo Bonzini     val |= (env->macc[acc] >> 32) & 0xff00;
1266e1f3808eSpbrook     val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1267e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1268e1f3808eSpbrook     return val;
1269e1f3808eSpbrook }
1270e1f3808eSpbrook 
12712b3e3cfeSAndreas Färber uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1272e1f3808eSpbrook {
1273e1f3808eSpbrook     uint32_t val;
1274e1f3808eSpbrook     val = (env->macc[acc] >> 32) & 0xffff;
1275e1f3808eSpbrook     val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1276e1f3808eSpbrook     return val;
1277e1f3808eSpbrook }
1278e1f3808eSpbrook 
12792b3e3cfeSAndreas Färber void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1280e1f3808eSpbrook {
1281e1f3808eSpbrook     int64_t res;
1282e1f3808eSpbrook     int32_t tmp;
1283e1f3808eSpbrook     res = env->macc[acc] & 0xffffffff00ull;
1284e1f3808eSpbrook     tmp = (int16_t)(val & 0xff00);
1285e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1286e1f3808eSpbrook     res |= val & 0xff;
1287e1f3808eSpbrook     env->macc[acc] = res;
1288e1f3808eSpbrook     res = env->macc[acc + 1] & 0xffffffff00ull;
1289e1f3808eSpbrook     tmp = (val & 0xff000000);
1290e1f3808eSpbrook     res |= ((int64_t)tmp) << 16;
1291e1f3808eSpbrook     res |= (val >> 16) & 0xff;
1292e1f3808eSpbrook     env->macc[acc + 1] = res;
1293e1f3808eSpbrook }
1294e1f3808eSpbrook 
12952b3e3cfeSAndreas Färber void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
1296e1f3808eSpbrook {
1297e1f3808eSpbrook     int64_t res;
1298e1f3808eSpbrook     int32_t tmp;
1299e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1300e1f3808eSpbrook     tmp = (int16_t)val;
1301e1f3808eSpbrook     res |= ((int64_t)tmp) << 32;
1302e1f3808eSpbrook     env->macc[acc] = res;
1303e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1304e1f3808eSpbrook     tmp = val & 0xffff0000;
1305e1f3808eSpbrook     res |= (int64_t)tmp << 16;
1306e1f3808eSpbrook     env->macc[acc + 1] = res;
1307e1f3808eSpbrook }
1308e1f3808eSpbrook 
13092b3e3cfeSAndreas Färber void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
1310e1f3808eSpbrook {
1311e1f3808eSpbrook     uint64_t res;
1312e1f3808eSpbrook     res = (uint32_t)env->macc[acc];
1313e1f3808eSpbrook     res |= ((uint64_t)(val & 0xffff)) << 32;
1314e1f3808eSpbrook     env->macc[acc] = res;
1315e1f3808eSpbrook     res = (uint32_t)env->macc[acc + 1];
1316e1f3808eSpbrook     res |= (uint64_t)(val & 0xffff0000) << 16;
1317e1f3808eSpbrook     env->macc[acc + 1] = res;
1318e1f3808eSpbrook }
13190bdb2b3bSLaurent Vivier 
13200bdb2b3bSLaurent Vivier #if defined(CONFIG_SOFTMMU)
1321e55886c3SLaurent Vivier void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1322e55886c3SLaurent Vivier {
1323e55886c3SLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
1324e55886c3SLaurent Vivier     CPUState *cs = CPU(cpu);
1325e55886c3SLaurent Vivier     hwaddr physical;
1326e55886c3SLaurent Vivier     int access_type;
1327e55886c3SLaurent Vivier     int prot;
1328e55886c3SLaurent Vivier     int ret;
1329e55886c3SLaurent Vivier     target_ulong page_size;
1330e55886c3SLaurent Vivier 
1331e55886c3SLaurent Vivier     access_type = ACCESS_PTEST;
1332e55886c3SLaurent Vivier     if (env->dfc & 4) {
1333e55886c3SLaurent Vivier         access_type |= ACCESS_SUPER;
1334e55886c3SLaurent Vivier     }
1335e55886c3SLaurent Vivier     if ((env->dfc & 3) == 2) {
1336e55886c3SLaurent Vivier         access_type |= ACCESS_CODE;
1337e55886c3SLaurent Vivier     }
1338e55886c3SLaurent Vivier     if (!is_read) {
1339e55886c3SLaurent Vivier         access_type |= ACCESS_STORE;
1340e55886c3SLaurent Vivier     }
1341e55886c3SLaurent Vivier 
1342e55886c3SLaurent Vivier     env->mmu.mmusr = 0;
1343e55886c3SLaurent Vivier     env->mmu.ssw = 0;
1344e55886c3SLaurent Vivier     ret = get_physical_address(env, &physical, &prot, addr,
1345e55886c3SLaurent Vivier                                access_type, &page_size);
1346e55886c3SLaurent Vivier     if (ret == 0) {
1347e55886c3SLaurent Vivier         addr &= TARGET_PAGE_MASK;
1348e55886c3SLaurent Vivier         physical += addr & (page_size - 1);
1349e55886c3SLaurent Vivier         tlb_set_page(cs, addr, physical,
1350e55886c3SLaurent Vivier                      prot, access_type & ACCESS_SUPER ?
1351e55886c3SLaurent Vivier                      MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1352e55886c3SLaurent Vivier     }
1353e55886c3SLaurent Vivier }
1354e55886c3SLaurent Vivier 
1355e55886c3SLaurent Vivier void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1356e55886c3SLaurent Vivier {
1357e55886c3SLaurent Vivier     M68kCPU *cpu = m68k_env_get_cpu(env);
1358e55886c3SLaurent Vivier 
1359e55886c3SLaurent Vivier     switch (opmode) {
1360e55886c3SLaurent Vivier     case 0: /* Flush page entry if not global */
1361e55886c3SLaurent Vivier     case 1: /* Flush page entry */
1362e55886c3SLaurent Vivier         tlb_flush_page(CPU(cpu), addr);
1363e55886c3SLaurent Vivier         break;
1364e55886c3SLaurent Vivier     case 2: /* Flush all except global entries */
1365e55886c3SLaurent Vivier         tlb_flush(CPU(cpu));
1366e55886c3SLaurent Vivier         break;
1367e55886c3SLaurent Vivier     case 3: /* Flush all entries */
1368e55886c3SLaurent Vivier         tlb_flush(CPU(cpu));
1369e55886c3SLaurent Vivier         break;
1370e55886c3SLaurent Vivier     }
1371e55886c3SLaurent Vivier }
1372e55886c3SLaurent Vivier 
13730bdb2b3bSLaurent Vivier void HELPER(reset)(CPUM68KState *env)
13740bdb2b3bSLaurent Vivier {
13750bdb2b3bSLaurent Vivier     /* FIXME: reset all except CPU */
13760bdb2b3bSLaurent Vivier }
13770bdb2b3bSLaurent Vivier #endif
1378