aspeed/smc: Fix MemoryRegionOps definition
[qemu/ar7.git] / target / m68k / helper.c
blob3ff57657958ca0b1c83f2d33be8dbbe9f43902a4
1 /*
2 * m68k op helpers
4 * Copyright (c) 2006-2007 CodeSourcery
5 * Written by Paul Brook
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/exec-all.h"
24 #include "exec/gdbstub.h"
25 #include "exec/helper-proto.h"
26 #include "fpu/softfloat.h"
27 #include "qemu/qemu-print.h"
29 #define SIGNBIT (1u << 31)
31 /* Sort alphabetically, except for "any". */
32 static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b)
34 ObjectClass *class_a = (ObjectClass *)a;
35 ObjectClass *class_b = (ObjectClass *)b;
36 const char *name_a, *name_b;
38 name_a = object_class_get_name(class_a);
39 name_b = object_class_get_name(class_b);
40 if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) {
41 return 1;
42 } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
43 return -1;
44 } else {
45 return strcasecmp(name_a, name_b);
49 static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
51 ObjectClass *c = data;
52 const char *typename;
53 char *name;
55 typename = object_class_get_name(c);
56 name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
57 qemu_printf("%s\n", name);
58 g_free(name);
61 void m68k_cpu_list(void)
63 GSList *list;
65 list = object_class_get_list(TYPE_M68K_CPU, false);
66 list = g_slist_sort(list, m68k_cpu_list_compare);
67 g_slist_foreach(list, m68k_cpu_list_entry, NULL);
68 g_slist_free(list);
71 static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
73 if (n < 8) {
74 float_status s;
75 return gdb_get_float64(mem_buf,
76 floatx80_to_float64(env->fregs[n].d, &s));
78 switch (n) {
79 case 8: /* fpcontrol */
80 return gdb_get_reg32(mem_buf, env->fpcr);
81 case 9: /* fpstatus */
82 return gdb_get_reg32(mem_buf, env->fpsr);
83 case 10: /* fpiar, not implemented */
84 return gdb_get_reg32(mem_buf, 0);
86 return 0;
89 static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
91 if (n < 8) {
92 float_status s;
93 env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
94 return 8;
96 switch (n) {
97 case 8: /* fpcontrol */
98 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
99 return 4;
100 case 9: /* fpstatus */
101 env->fpsr = ldl_p(mem_buf);
102 return 4;
103 case 10: /* fpiar, not implemented */
104 return 4;
106 return 0;
109 static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
111 if (n < 8) {
112 int len = gdb_get_reg16(mem_buf, env->fregs[n].l.upper);
113 len += gdb_get_reg16(mem_buf, 0);
114 len += gdb_get_reg64(mem_buf, env->fregs[n].l.lower);
115 return len;
117 switch (n) {
118 case 8: /* fpcontrol */
119 return gdb_get_reg32(mem_buf, env->fpcr);
120 case 9: /* fpstatus */
121 return gdb_get_reg32(mem_buf, env->fpsr);
122 case 10: /* fpiar, not implemented */
123 return gdb_get_reg32(mem_buf, 0);
125 return 0;
128 static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
130 if (n < 8) {
131 env->fregs[n].l.upper = lduw_be_p(mem_buf);
132 env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
133 return 12;
135 switch (n) {
136 case 8: /* fpcontrol */
137 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
138 return 4;
139 case 9: /* fpstatus */
140 env->fpsr = ldl_p(mem_buf);
141 return 4;
142 case 10: /* fpiar, not implemented */
143 return 4;
145 return 0;
148 void m68k_cpu_init_gdb(M68kCPU *cpu)
150 CPUState *cs = CPU(cpu);
151 CPUM68KState *env = &cpu->env;
153 if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
154 gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
155 11, "cf-fp.xml", 18);
156 } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
157 gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
158 m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
160 /* TODO: Add [E]MAC registers. */
163 void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
165 switch (reg) {
166 case M68K_CR_CACR:
167 env->cacr = val;
168 m68k_switch_sp(env);
169 break;
170 case M68K_CR_ACR0:
171 case M68K_CR_ACR1:
172 case M68K_CR_ACR2:
173 case M68K_CR_ACR3:
174 /* TODO: Implement Access Control Registers. */
175 break;
176 case M68K_CR_VBR:
177 env->vbr = val;
178 break;
179 /* TODO: Implement control registers. */
180 default:
181 cpu_abort(env_cpu(env),
182 "Unimplemented control register write 0x%x = 0x%x\n",
183 reg, val);
187 void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
189 switch (reg) {
190 /* MC680[1234]0 */
191 case M68K_CR_SFC:
192 env->sfc = val & 7;
193 return;
194 case M68K_CR_DFC:
195 env->dfc = val & 7;
196 return;
197 case M68K_CR_VBR:
198 env->vbr = val;
199 return;
200 /* MC680[2346]0 */
201 case M68K_CR_CACR:
202 if (m68k_feature(env, M68K_FEATURE_M68020)) {
203 env->cacr = val & 0x0000000f;
204 } else if (m68k_feature(env, M68K_FEATURE_M68030)) {
205 env->cacr = val & 0x00003f1f;
206 } else if (m68k_feature(env, M68K_FEATURE_M68040)) {
207 env->cacr = val & 0x80008000;
208 } else if (m68k_feature(env, M68K_FEATURE_M68060)) {
209 env->cacr = val & 0xf8e0e000;
211 m68k_switch_sp(env);
212 return;
213 /* MC680[34]0 */
214 case M68K_CR_TC:
215 env->mmu.tcr = val;
216 return;
217 case M68K_CR_MMUSR:
218 env->mmu.mmusr = val;
219 return;
220 case M68K_CR_SRP:
221 env->mmu.srp = val;
222 return;
223 case M68K_CR_URP:
224 env->mmu.urp = val;
225 return;
226 case M68K_CR_USP:
227 env->sp[M68K_USP] = val;
228 return;
229 case M68K_CR_MSP:
230 env->sp[M68K_SSP] = val;
231 return;
232 case M68K_CR_ISP:
233 env->sp[M68K_ISP] = val;
234 return;
235 /* MC68040/MC68LC040 */
236 case M68K_CR_ITT0:
237 env->mmu.ttr[M68K_ITTR0] = val;
238 return;
239 case M68K_CR_ITT1:
240 env->mmu.ttr[M68K_ITTR1] = val;
241 return;
242 case M68K_CR_DTT0:
243 env->mmu.ttr[M68K_DTTR0] = val;
244 return;
245 case M68K_CR_DTT1:
246 env->mmu.ttr[M68K_DTTR1] = val;
247 return;
249 cpu_abort(env_cpu(env),
250 "Unimplemented control register write 0x%x = 0x%x\n",
251 reg, val);
254 uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
256 switch (reg) {
257 /* MC680[1234]0 */
258 case M68K_CR_SFC:
259 return env->sfc;
260 case M68K_CR_DFC:
261 return env->dfc;
262 case M68K_CR_VBR:
263 return env->vbr;
264 /* MC680[234]0 */
265 case M68K_CR_CACR:
266 return env->cacr;
267 /* MC680[34]0 */
268 case M68K_CR_TC:
269 return env->mmu.tcr;
270 case M68K_CR_MMUSR:
271 return env->mmu.mmusr;
272 case M68K_CR_SRP:
273 return env->mmu.srp;
274 case M68K_CR_USP:
275 return env->sp[M68K_USP];
276 case M68K_CR_MSP:
277 return env->sp[M68K_SSP];
278 case M68K_CR_ISP:
279 return env->sp[M68K_ISP];
280 /* MC68040/MC68LC040 */
281 case M68K_CR_URP:
282 return env->mmu.urp;
283 case M68K_CR_ITT0:
284 return env->mmu.ttr[M68K_ITTR0];
285 case M68K_CR_ITT1:
286 return env->mmu.ttr[M68K_ITTR1];
287 case M68K_CR_DTT0:
288 return env->mmu.ttr[M68K_DTTR0];
289 case M68K_CR_DTT1:
290 return env->mmu.ttr[M68K_DTTR1];
292 cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n",
293 reg);
296 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
298 uint32_t acc;
299 int8_t exthigh;
300 uint8_t extlow;
301 uint64_t regval;
302 int i;
303 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
304 for (i = 0; i < 4; i++) {
305 regval = env->macc[i];
306 exthigh = regval >> 40;
307 if (env->macsr & MACSR_FI) {
308 acc = regval >> 8;
309 extlow = regval;
310 } else {
311 acc = regval;
312 extlow = regval >> 32;
314 if (env->macsr & MACSR_FI) {
315 regval = (((uint64_t)acc) << 8) | extlow;
316 regval |= ((int64_t)exthigh) << 40;
317 } else if (env->macsr & MACSR_SU) {
318 regval = acc | (((int64_t)extlow) << 32);
319 regval |= ((int64_t)exthigh) << 40;
320 } else {
321 regval = acc | (((uint64_t)extlow) << 32);
322 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
324 env->macc[i] = regval;
327 env->macsr = val;
330 void m68k_switch_sp(CPUM68KState *env)
332 int new_sp;
334 env->sp[env->current_sp] = env->aregs[7];
335 if (m68k_feature(env, M68K_FEATURE_M68000)) {
336 if (env->sr & SR_S) {
337 if (env->sr & SR_M) {
338 new_sp = M68K_SSP;
339 } else {
340 new_sp = M68K_ISP;
342 } else {
343 new_sp = M68K_USP;
345 } else {
346 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
347 ? M68K_SSP : M68K_USP;
349 env->aregs[7] = env->sp[new_sp];
350 env->current_sp = new_sp;
353 #if !defined(CONFIG_USER_ONLY)
354 /* MMU: 68040 only */
356 static void print_address_zone(uint32_t logical, uint32_t physical,
357 uint32_t size, int attr)
359 qemu_printf("%08x - %08x -> %08x - %08x %c ",
360 logical, logical + size - 1,
361 physical, physical + size - 1,
362 attr & 4 ? 'W' : '-');
363 size >>= 10;
364 if (size < 1024) {
365 qemu_printf("(%d KiB)\n", size);
366 } else {
367 size >>= 10;
368 if (size < 1024) {
369 qemu_printf("(%d MiB)\n", size);
370 } else {
371 size >>= 10;
372 qemu_printf("(%d GiB)\n", size);
377 static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
379 int i, j, k;
380 int tic_size, tic_shift;
381 uint32_t tib_mask;
382 uint32_t tia, tib, tic;
383 uint32_t logical = 0xffffffff, physical = 0xffffffff;
384 uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
385 uint32_t last_logical, last_physical;
386 int32_t size;
387 int last_attr = -1, attr = -1;
388 CPUState *cs = env_cpu(env);
389 MemTxResult txres;
391 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
392 /* 8k page */
393 tic_size = 32;
394 tic_shift = 13;
395 tib_mask = M68K_8K_PAGE_MASK;
396 } else {
397 /* 4k page */
398 tic_size = 64;
399 tic_shift = 12;
400 tib_mask = M68K_4K_PAGE_MASK;
402 for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
403 tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4,
404 MEMTXATTRS_UNSPECIFIED, &txres);
405 if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) {
406 continue;
408 for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
409 tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4,
410 MEMTXATTRS_UNSPECIFIED, &txres);
411 if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) {
412 continue;
414 for (k = 0; k < tic_size; k++) {
415 tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4,
416 MEMTXATTRS_UNSPECIFIED, &txres);
417 if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) {
418 continue;
420 if (M68K_PDT_INDIRECT(tic)) {
421 tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic),
422 MEMTXATTRS_UNSPECIFIED, &txres);
423 if (txres != MEMTX_OK) {
424 continue;
428 last_logical = logical;
429 logical = (i << M68K_TTS_ROOT_SHIFT) |
430 (j << M68K_TTS_POINTER_SHIFT) |
431 (k << tic_shift);
433 last_physical = physical;
434 physical = tic & ~((1 << tic_shift) - 1);
436 last_attr = attr;
437 attr = tic & ((1 << tic_shift) - 1);
439 if ((logical != (last_logical + (1 << tic_shift))) ||
440 (physical != (last_physical + (1 << tic_shift))) ||
441 (attr & 4) != (last_attr & 4)) {
443 if (first_logical != 0xffffffff) {
444 size = last_logical + (1 << tic_shift) -
445 first_logical;
446 print_address_zone(first_logical,
447 first_physical, size, last_attr);
449 first_logical = logical;
450 first_physical = physical;
455 if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
456 size = logical + (1 << tic_shift) - first_logical;
457 print_address_zone(first_logical, first_physical, size, last_attr);
461 #define DUMP_CACHEFLAGS(a) \
462 switch (a & M68K_DESC_CACHEMODE) { \
463 case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
464 qemu_printf("T"); \
465 break; \
466 case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
467 qemu_printf("C"); \
468 break; \
469 case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
470 qemu_printf("S"); \
471 break; \
472 case M68K_DESC_CM_NCACHE: /* noncachable */ \
473 qemu_printf("N"); \
474 break; \
477 static void dump_ttr(uint32_t ttr)
479 if ((ttr & M68K_TTR_ENABLED) == 0) {
480 qemu_printf("disabled\n");
481 return;
483 qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ",
484 ttr & M68K_TTR_ADDR_BASE,
485 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
486 switch (ttr & M68K_TTR_SFIELD) {
487 case M68K_TTR_SFIELD_USER:
488 qemu_printf("U");
489 break;
490 case M68K_TTR_SFIELD_SUPER:
491 qemu_printf("S");
492 break;
493 default:
494 qemu_printf("*");
495 break;
497 DUMP_CACHEFLAGS(ttr);
498 if (ttr & M68K_DESC_WRITEPROT) {
499 qemu_printf("R");
500 } else {
501 qemu_printf("W");
503 qemu_printf(" U: %d\n", (ttr & M68K_DESC_USERATTR) >>
504 M68K_DESC_USERATTR_SHIFT);
507 void dump_mmu(CPUM68KState *env)
509 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
510 qemu_printf("Translation disabled\n");
511 return;
513 qemu_printf("Page Size: ");
514 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
515 qemu_printf("8kB\n");
516 } else {
517 qemu_printf("4kB\n");
520 qemu_printf("MMUSR: ");
521 if (env->mmu.mmusr & M68K_MMU_B_040) {
522 qemu_printf("BUS ERROR\n");
523 } else {
524 qemu_printf("Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
525 /* flags found on the page descriptor */
526 if (env->mmu.mmusr & M68K_MMU_G_040) {
527 qemu_printf("G"); /* Global */
528 } else {
529 qemu_printf(".");
531 if (env->mmu.mmusr & M68K_MMU_S_040) {
532 qemu_printf("S"); /* Supervisor */
533 } else {
534 qemu_printf(".");
536 if (env->mmu.mmusr & M68K_MMU_M_040) {
537 qemu_printf("M"); /* Modified */
538 } else {
539 qemu_printf(".");
541 if (env->mmu.mmusr & M68K_MMU_WP_040) {
542 qemu_printf("W"); /* Write protect */
543 } else {
544 qemu_printf(".");
546 if (env->mmu.mmusr & M68K_MMU_T_040) {
547 qemu_printf("T"); /* Transparent */
548 } else {
549 qemu_printf(".");
551 if (env->mmu.mmusr & M68K_MMU_R_040) {
552 qemu_printf("R"); /* Resident */
553 } else {
554 qemu_printf(".");
556 qemu_printf(" Cache: ");
557 DUMP_CACHEFLAGS(env->mmu.mmusr);
558 qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3);
559 qemu_printf("\n");
562 qemu_printf("ITTR0: ");
563 dump_ttr(env->mmu.ttr[M68K_ITTR0]);
564 qemu_printf("ITTR1: ");
565 dump_ttr(env->mmu.ttr[M68K_ITTR1]);
566 qemu_printf("DTTR0: ");
567 dump_ttr(env->mmu.ttr[M68K_DTTR0]);
568 qemu_printf("DTTR1: ");
569 dump_ttr(env->mmu.ttr[M68K_DTTR1]);
571 qemu_printf("SRP: 0x%08x\n", env->mmu.srp);
572 dump_address_map(env, env->mmu.srp);
574 qemu_printf("URP: 0x%08x\n", env->mmu.urp);
575 dump_address_map(env, env->mmu.urp);
578 static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
579 int access_type)
581 uint32_t base, mask;
583 /* check if transparent translation is enabled */
584 if ((ttr & M68K_TTR_ENABLED) == 0) {
585 return 0;
588 /* check mode access */
589 switch (ttr & M68K_TTR_SFIELD) {
590 case M68K_TTR_SFIELD_USER:
591 /* match only if user */
592 if ((access_type & ACCESS_SUPER) != 0) {
593 return 0;
595 break;
596 case M68K_TTR_SFIELD_SUPER:
597 /* match only if supervisor */
598 if ((access_type & ACCESS_SUPER) == 0) {
599 return 0;
601 break;
602 default:
603 /* all other values disable mode matching (FC2) */
604 break;
607 /* check address matching */
609 base = ttr & M68K_TTR_ADDR_BASE;
610 mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
611 mask <<= M68K_TTR_ADDR_MASK_SHIFT;
613 if ((addr & mask) != (base & mask)) {
614 return 0;
617 *prot = PAGE_READ | PAGE_EXEC;
618 if ((ttr & M68K_DESC_WRITEPROT) == 0) {
619 *prot |= PAGE_WRITE;
622 return 1;
625 static int get_physical_address(CPUM68KState *env, hwaddr *physical,
626 int *prot, target_ulong address,
627 int access_type, target_ulong *page_size)
629 CPUState *cs = env_cpu(env);
630 uint32_t entry;
631 uint32_t next;
632 target_ulong page_mask;
633 bool debug = access_type & ACCESS_DEBUG;
634 int page_bits;
635 int i;
636 MemTxResult txres;
638 /* Transparent Translation (physical = logical) */
639 for (i = 0; i < M68K_MAX_TTR; i++) {
640 if (check_TTR(env->mmu.TTR(access_type, i),
641 prot, address, access_type)) {
642 if (access_type & ACCESS_PTEST) {
643 /* Transparent Translation Register bit */
644 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
646 *physical = address;
647 *page_size = TARGET_PAGE_SIZE;
648 return 0;
652 /* Page Table Root Pointer */
653 *prot = PAGE_READ | PAGE_WRITE;
654 if (access_type & ACCESS_CODE) {
655 *prot |= PAGE_EXEC;
657 if (access_type & ACCESS_SUPER) {
658 next = env->mmu.srp;
659 } else {
660 next = env->mmu.urp;
663 /* Root Index */
664 entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
666 next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
667 if (txres != MEMTX_OK) {
668 goto txfail;
670 if (!M68K_UDT_VALID(next)) {
671 return -1;
673 if (!(next & M68K_DESC_USED) && !debug) {
674 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
675 MEMTXATTRS_UNSPECIFIED, &txres);
676 if (txres != MEMTX_OK) {
677 goto txfail;
680 if (next & M68K_DESC_WRITEPROT) {
681 if (access_type & ACCESS_PTEST) {
682 env->mmu.mmusr |= M68K_MMU_WP_040;
684 *prot &= ~PAGE_WRITE;
685 if (access_type & ACCESS_STORE) {
686 return -1;
690 /* Pointer Index */
691 entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
693 next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
694 if (txres != MEMTX_OK) {
695 goto txfail;
697 if (!M68K_UDT_VALID(next)) {
698 return -1;
700 if (!(next & M68K_DESC_USED) && !debug) {
701 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
702 MEMTXATTRS_UNSPECIFIED, &txres);
703 if (txres != MEMTX_OK) {
704 goto txfail;
707 if (next & M68K_DESC_WRITEPROT) {
708 if (access_type & ACCESS_PTEST) {
709 env->mmu.mmusr |= M68K_MMU_WP_040;
711 *prot &= ~PAGE_WRITE;
712 if (access_type & ACCESS_STORE) {
713 return -1;
717 /* Page Index */
718 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
719 entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
720 } else {
721 entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
724 next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
725 if (txres != MEMTX_OK) {
726 goto txfail;
729 if (!M68K_PDT_VALID(next)) {
730 return -1;
732 if (M68K_PDT_INDIRECT(next)) {
733 next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next),
734 MEMTXATTRS_UNSPECIFIED, &txres);
735 if (txres != MEMTX_OK) {
736 goto txfail;
739 if (access_type & ACCESS_STORE) {
740 if (next & M68K_DESC_WRITEPROT) {
741 if (!(next & M68K_DESC_USED) && !debug) {
742 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
743 MEMTXATTRS_UNSPECIFIED, &txres);
744 if (txres != MEMTX_OK) {
745 goto txfail;
748 } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
749 (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
750 address_space_stl(cs->as, entry,
751 next | (M68K_DESC_MODIFIED | M68K_DESC_USED),
752 MEMTXATTRS_UNSPECIFIED, &txres);
753 if (txres != MEMTX_OK) {
754 goto txfail;
757 } else {
758 if (!(next & M68K_DESC_USED) && !debug) {
759 address_space_stl(cs->as, entry, next | M68K_DESC_USED,
760 MEMTXATTRS_UNSPECIFIED, &txres);
761 if (txres != MEMTX_OK) {
762 goto txfail;
767 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
768 page_bits = 13;
769 } else {
770 page_bits = 12;
772 *page_size = 1 << page_bits;
773 page_mask = ~(*page_size - 1);
774 *physical = (next & page_mask) + (address & (*page_size - 1));
776 if (access_type & ACCESS_PTEST) {
777 env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
778 env->mmu.mmusr |= *physical & 0xfffff000;
779 env->mmu.mmusr |= M68K_MMU_R_040;
782 if (next & M68K_DESC_WRITEPROT) {
783 *prot &= ~PAGE_WRITE;
784 if (access_type & ACCESS_STORE) {
785 return -1;
788 if (next & M68K_DESC_SUPERONLY) {
789 if ((access_type & ACCESS_SUPER) == 0) {
790 return -1;
794 return 0;
796 txfail:
798 * A page table load/store failed. TODO: we should really raise a
799 * suitable guest fault here if this is not a debug access.
800 * For now just return that the translation failed.
802 return -1;
805 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
807 M68kCPU *cpu = M68K_CPU(cs);
808 CPUM68KState *env = &cpu->env;
809 hwaddr phys_addr;
810 int prot;
811 int access_type;
812 target_ulong page_size;
814 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
815 /* MMU disabled */
816 return addr;
819 access_type = ACCESS_DATA | ACCESS_DEBUG;
820 if (env->sr & SR_S) {
821 access_type |= ACCESS_SUPER;
824 if (get_physical_address(env, &phys_addr, &prot,
825 addr, access_type, &page_size) != 0) {
826 return -1;
829 return phys_addr;
833 * Notify CPU of a pending interrupt. Prioritization and vectoring should
834 * be handled by the interrupt controller. Real hardware only requests
835 * the vector when the interrupt is acknowledged by the CPU. For
836 * simplicity we calculate it when the interrupt is signalled.
838 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
840 CPUState *cs = CPU(cpu);
841 CPUM68KState *env = &cpu->env;
843 env->pending_level = level;
844 env->pending_vector = vector;
845 if (level) {
846 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
847 } else {
848 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
852 #endif
854 bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
855 MMUAccessType qemu_access_type, int mmu_idx,
856 bool probe, uintptr_t retaddr)
858 M68kCPU *cpu = M68K_CPU(cs);
859 CPUM68KState *env = &cpu->env;
861 #ifndef CONFIG_USER_ONLY
862 hwaddr physical;
863 int prot;
864 int access_type;
865 int ret;
866 target_ulong page_size;
868 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
869 /* MMU disabled */
870 tlb_set_page(cs, address & TARGET_PAGE_MASK,
871 address & TARGET_PAGE_MASK,
872 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
873 mmu_idx, TARGET_PAGE_SIZE);
874 return true;
877 if (qemu_access_type == MMU_INST_FETCH) {
878 access_type = ACCESS_CODE;
879 } else {
880 access_type = ACCESS_DATA;
881 if (qemu_access_type == MMU_DATA_STORE) {
882 access_type |= ACCESS_STORE;
885 if (mmu_idx != MMU_USER_IDX) {
886 access_type |= ACCESS_SUPER;
889 ret = get_physical_address(&cpu->env, &physical, &prot,
890 address, access_type, &page_size);
891 if (likely(ret == 0)) {
892 tlb_set_page(cs, address & TARGET_PAGE_MASK,
893 physical & TARGET_PAGE_MASK, prot, mmu_idx, page_size);
894 return true;
897 if (probe) {
898 return false;
901 /* page fault */
902 env->mmu.ssw = M68K_ATC_040;
903 switch (size) {
904 case 1:
905 env->mmu.ssw |= M68K_BA_SIZE_BYTE;
906 break;
907 case 2:
908 env->mmu.ssw |= M68K_BA_SIZE_WORD;
909 break;
910 case 4:
911 env->mmu.ssw |= M68K_BA_SIZE_LONG;
912 break;
914 if (access_type & ACCESS_SUPER) {
915 env->mmu.ssw |= M68K_TM_040_SUPER;
917 if (access_type & ACCESS_CODE) {
918 env->mmu.ssw |= M68K_TM_040_CODE;
919 } else {
920 env->mmu.ssw |= M68K_TM_040_DATA;
922 if (!(access_type & ACCESS_STORE)) {
923 env->mmu.ssw |= M68K_RW_040;
925 #endif
927 cs->exception_index = EXCP_ACCESS;
928 env->mmu.ar = address;
929 cpu_loop_exit_restore(cs, retaddr);
932 uint32_t HELPER(bitrev)(uint32_t x)
934 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
935 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
936 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
937 return bswap32(x);
940 uint32_t HELPER(ff1)(uint32_t x)
942 int n;
943 for (n = 32; x; n--)
944 x >>= 1;
945 return n;
948 uint32_t HELPER(sats)(uint32_t val, uint32_t v)
950 /* The result has the opposite sign to the original value. */
951 if ((int32_t)v < 0) {
952 val = (((int32_t)val) >> 31) ^ SIGNBIT;
954 return val;
957 void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
959 env->sr = sr & 0xffe0;
960 cpu_m68k_set_ccr(env, sr);
961 m68k_switch_sp(env);
964 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
966 cpu_m68k_set_sr(env, val);
969 /* MAC unit. */
971 * FIXME: The MAC unit implementation is a bit of a mess. Some helpers
972 * take values, others take register numbers and manipulate the contents
973 * in-place.
975 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
977 uint32_t mask;
978 env->macc[dest] = env->macc[src];
979 mask = MACSR_PAV0 << dest;
980 if (env->macsr & (MACSR_PAV0 << src))
981 env->macsr |= mask;
982 else
983 env->macsr &= ~mask;
986 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
988 int64_t product;
989 int64_t res;
991 product = (uint64_t)op1 * op2;
992 res = (product << 24) >> 24;
993 if (res != product) {
994 env->macsr |= MACSR_V;
995 if (env->macsr & MACSR_OMC) {
996 /* Make sure the accumulate operation overflows. */
997 if (product < 0)
998 res = ~(1ll << 50);
999 else
1000 res = 1ll << 50;
1003 return res;
1006 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1008 uint64_t product;
1010 product = (uint64_t)op1 * op2;
1011 if (product & (0xffffffull << 40)) {
1012 env->macsr |= MACSR_V;
1013 if (env->macsr & MACSR_OMC) {
1014 /* Make sure the accumulate operation overflows. */
1015 product = 1ll << 50;
1016 } else {
1017 product &= ((1ull << 40) - 1);
1020 return product;
1023 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1025 uint64_t product;
1026 uint32_t remainder;
1028 product = (uint64_t)op1 * op2;
1029 if (env->macsr & MACSR_RT) {
1030 remainder = product & 0xffffff;
1031 product >>= 24;
1032 if (remainder > 0x800000)
1033 product++;
1034 else if (remainder == 0x800000)
1035 product += (product & 1);
1036 } else {
1037 product >>= 24;
1039 return product;
1042 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
1044 int64_t tmp;
1045 int64_t result;
1046 tmp = env->macc[acc];
1047 result = ((tmp << 16) >> 16);
1048 if (result != tmp) {
1049 env->macsr |= MACSR_V;
1051 if (env->macsr & MACSR_V) {
1052 env->macsr |= MACSR_PAV0 << acc;
1053 if (env->macsr & MACSR_OMC) {
1055 * The result is saturated to 32 bits, despite overflow occurring
1056 * at 48 bits. Seems weird, but that's what the hardware docs
1057 * say.
1059 result = (result >> 63) ^ 0x7fffffff;
1062 env->macc[acc] = result;
1065 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1067 uint64_t val;
1069 val = env->macc[acc];
1070 if (val & (0xffffull << 48)) {
1071 env->macsr |= MACSR_V;
1073 if (env->macsr & MACSR_V) {
1074 env->macsr |= MACSR_PAV0 << acc;
1075 if (env->macsr & MACSR_OMC) {
1076 if (val > (1ull << 53))
1077 val = 0;
1078 else
1079 val = (1ull << 48) - 1;
1080 } else {
1081 val &= ((1ull << 48) - 1);
1084 env->macc[acc] = val;
1087 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1089 int64_t sum;
1090 int64_t result;
1092 sum = env->macc[acc];
1093 result = (sum << 16) >> 16;
1094 if (result != sum) {
1095 env->macsr |= MACSR_V;
1097 if (env->macsr & MACSR_V) {
1098 env->macsr |= MACSR_PAV0 << acc;
1099 if (env->macsr & MACSR_OMC) {
1100 result = (result >> 63) ^ 0x7fffffffffffll;
1103 env->macc[acc] = result;
1106 void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1108 uint64_t val;
1109 val = env->macc[acc];
1110 if (val == 0) {
1111 env->macsr |= MACSR_Z;
1112 } else if (val & (1ull << 47)) {
1113 env->macsr |= MACSR_N;
1115 if (env->macsr & (MACSR_PAV0 << acc)) {
1116 env->macsr |= MACSR_V;
1118 if (env->macsr & MACSR_FI) {
1119 val = ((int64_t)val) >> 40;
1120 if (val != 0 && val != -1)
1121 env->macsr |= MACSR_EV;
1122 } else if (env->macsr & MACSR_SU) {
1123 val = ((int64_t)val) >> 32;
1124 if (val != 0 && val != -1)
1125 env->macsr |= MACSR_EV;
1126 } else {
1127 if ((val >> 32) != 0)
1128 env->macsr |= MACSR_EV;
1132 #define EXTSIGN(val, index) ( \
1133 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1136 #define COMPUTE_CCR(op, x, n, z, v, c) { \
1137 switch (op) { \
1138 case CC_OP_FLAGS: \
1139 /* Everything in place. */ \
1140 break; \
1141 case CC_OP_ADDB: \
1142 case CC_OP_ADDW: \
1143 case CC_OP_ADDL: \
1144 res = n; \
1145 src2 = v; \
1146 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
1147 c = x; \
1148 z = n; \
1149 v = (res ^ src1) & ~(src1 ^ src2); \
1150 break; \
1151 case CC_OP_SUBB: \
1152 case CC_OP_SUBW: \
1153 case CC_OP_SUBL: \
1154 res = n; \
1155 src2 = v; \
1156 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
1157 c = x; \
1158 z = n; \
1159 v = (res ^ src1) & (src1 ^ src2); \
1160 break; \
1161 case CC_OP_CMPB: \
1162 case CC_OP_CMPW: \
1163 case CC_OP_CMPL: \
1164 src1 = n; \
1165 src2 = v; \
1166 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
1167 n = res; \
1168 z = res; \
1169 c = src1 < src2; \
1170 v = (res ^ src1) & (src1 ^ src2); \
1171 break; \
1172 case CC_OP_LOGIC: \
1173 c = v = 0; \
1174 z = n; \
1175 break; \
1176 default: \
1177 cpu_abort(env_cpu(env), "Bad CC_OP %d", op); \
1179 } while (0)
1181 uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1183 uint32_t x, c, n, z, v;
1184 uint32_t res, src1, src2;
1186 x = env->cc_x;
1187 n = env->cc_n;
1188 z = env->cc_z;
1189 v = env->cc_v;
1190 c = env->cc_c;
1192 COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1194 n = n >> 31;
1195 z = (z == 0);
1196 v = v >> 31;
1198 return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1201 uint32_t HELPER(get_ccr)(CPUM68KState *env)
1203 return cpu_m68k_get_ccr(env);
1206 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1208 env->cc_x = (ccr & CCF_X ? 1 : 0);
1209 env->cc_n = (ccr & CCF_N ? -1 : 0);
1210 env->cc_z = (ccr & CCF_Z ? 0 : 1);
1211 env->cc_v = (ccr & CCF_V ? -1 : 0);
1212 env->cc_c = (ccr & CCF_C ? 1 : 0);
1213 env->cc_op = CC_OP_FLAGS;
1216 void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1218 cpu_m68k_set_ccr(env, ccr);
1221 void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1223 uint32_t res, src1, src2;
1225 COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1226 env->cc_op = CC_OP_FLAGS;
1229 uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1231 int rem;
1232 uint32_t result;
1234 if (env->macsr & MACSR_SU) {
1235 /* 16-bit rounding. */
1236 rem = val & 0xffffff;
1237 val = (val >> 24) & 0xffffu;
1238 if (rem > 0x800000)
1239 val++;
1240 else if (rem == 0x800000)
1241 val += (val & 1);
1242 } else if (env->macsr & MACSR_RT) {
1243 /* 32-bit rounding. */
1244 rem = val & 0xff;
1245 val >>= 8;
1246 if (rem > 0x80)
1247 val++;
1248 else if (rem == 0x80)
1249 val += (val & 1);
1250 } else {
1251 /* No rounding. */
1252 val >>= 8;
1254 if (env->macsr & MACSR_OMC) {
1255 /* Saturate. */
1256 if (env->macsr & MACSR_SU) {
1257 if (val != (uint16_t) val) {
1258 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1259 } else {
1260 result = val & 0xffff;
1262 } else {
1263 if (val != (uint32_t)val) {
1264 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1265 } else {
1266 result = (uint32_t)val;
1269 } else {
1270 /* No saturation. */
1271 if (env->macsr & MACSR_SU) {
1272 result = val & 0xffff;
1273 } else {
1274 result = (uint32_t)val;
1277 return result;
1280 uint32_t HELPER(get_macs)(uint64_t val)
1282 if (val == (int32_t)val) {
1283 return (int32_t)val;
1284 } else {
1285 return (val >> 61) ^ ~SIGNBIT;
1289 uint32_t HELPER(get_macu)(uint64_t val)
1291 if ((val >> 32) == 0) {
1292 return (uint32_t)val;
1293 } else {
1294 return 0xffffffffu;
1298 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1300 uint32_t val;
1301 val = env->macc[acc] & 0x00ff;
1302 val |= (env->macc[acc] >> 32) & 0xff00;
1303 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1304 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1305 return val;
1308 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1310 uint32_t val;
1311 val = (env->macc[acc] >> 32) & 0xffff;
1312 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1313 return val;
1316 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1318 int64_t res;
1319 int32_t tmp;
1320 res = env->macc[acc] & 0xffffffff00ull;
1321 tmp = (int16_t)(val & 0xff00);
1322 res |= ((int64_t)tmp) << 32;
1323 res |= val & 0xff;
1324 env->macc[acc] = res;
1325 res = env->macc[acc + 1] & 0xffffffff00ull;
1326 tmp = (val & 0xff000000);
1327 res |= ((int64_t)tmp) << 16;
1328 res |= (val >> 16) & 0xff;
1329 env->macc[acc + 1] = res;
1332 void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
1334 int64_t res;
1335 int32_t tmp;
1336 res = (uint32_t)env->macc[acc];
1337 tmp = (int16_t)val;
1338 res |= ((int64_t)tmp) << 32;
1339 env->macc[acc] = res;
1340 res = (uint32_t)env->macc[acc + 1];
1341 tmp = val & 0xffff0000;
1342 res |= (int64_t)tmp << 16;
1343 env->macc[acc + 1] = res;
1346 void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
1348 uint64_t res;
1349 res = (uint32_t)env->macc[acc];
1350 res |= ((uint64_t)(val & 0xffff)) << 32;
1351 env->macc[acc] = res;
1352 res = (uint32_t)env->macc[acc + 1];
1353 res |= (uint64_t)(val & 0xffff0000) << 16;
1354 env->macc[acc + 1] = res;
1357 #if defined(CONFIG_SOFTMMU)
1358 void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1360 hwaddr physical;
1361 int access_type;
1362 int prot;
1363 int ret;
1364 target_ulong page_size;
1366 access_type = ACCESS_PTEST;
1367 if (env->dfc & 4) {
1368 access_type |= ACCESS_SUPER;
1370 if ((env->dfc & 3) == 2) {
1371 access_type |= ACCESS_CODE;
1373 if (!is_read) {
1374 access_type |= ACCESS_STORE;
1377 env->mmu.mmusr = 0;
1378 env->mmu.ssw = 0;
1379 ret = get_physical_address(env, &physical, &prot, addr,
1380 access_type, &page_size);
1381 if (ret == 0) {
1382 tlb_set_page(env_cpu(env), addr & TARGET_PAGE_MASK,
1383 physical & TARGET_PAGE_MASK,
1384 prot, access_type & ACCESS_SUPER ?
1385 MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1389 void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1391 CPUState *cs = env_cpu(env);
1393 switch (opmode) {
1394 case 0: /* Flush page entry if not global */
1395 case 1: /* Flush page entry */
1396 tlb_flush_page(cs, addr);
1397 break;
1398 case 2: /* Flush all except global entries */
1399 tlb_flush(cs);
1400 break;
1401 case 3: /* Flush all entries */
1402 tlb_flush(cs);
1403 break;
1407 void HELPER(reset)(CPUM68KState *env)
1409 /* FIXME: reset all except CPU */
1411 #endif