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"
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) {
42 } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
45 return strcasecmp(name_a, name_b);
49 static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
51 ObjectClass *c = data;
55 typename = object_class_get_name(c);
56 name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
57 qemu_printf("%s\n", name);
61 void m68k_cpu_list(void)
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);
71 static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
75 return gdb_get_float64(mem_buf,
76 floatx80_to_float64(env->fregs[n].d, &s));
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);
89 static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
93 env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
97 case 8: /* fpcontrol */
98 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
100 case 9: /* fpstatus */
101 env->fpsr = ldl_p(mem_buf);
103 case 10: /* fpiar, not implemented */
109 static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
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);
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);
128 static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
131 env->fregs[n].l.upper = lduw_be_p(mem_buf);
132 env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
136 case 8: /* fpcontrol */
137 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
139 case 9: /* fpstatus */
140 env->fpsr = ldl_p(mem_buf);
142 case 10: /* fpiar, not implemented */
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)
174 /* TODO: Implement Access Control Registers. */
179 /* TODO: Implement control registers. */
181 cpu_abort(env_cpu(env),
182 "Unimplemented control register write 0x%x = 0x%x\n",
187 void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
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;
218 env->mmu.mmusr = val;
227 env->sp[M68K_USP] = val;
230 env->sp[M68K_SSP] = val;
233 env->sp[M68K_ISP] = val;
235 /* MC68040/MC68LC040 */
237 env->mmu.ttr[M68K_ITTR0] = val;
240 env->mmu.ttr[M68K_ITTR1] = val;
243 env->mmu.ttr[M68K_DTTR0] = val;
246 env->mmu.ttr[M68K_DTTR1] = val;
249 cpu_abort(env_cpu(env),
250 "Unimplemented control register write 0x%x = 0x%x\n",
254 uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
271 return env->mmu.mmusr;
275 return env->sp[M68K_USP];
277 return env->sp[M68K_SSP];
279 return env->sp[M68K_ISP];
280 /* MC68040/MC68LC040 */
284 return env->mmu.ttr[M68K_ITTR0];
286 return env->mmu.ttr[M68K_ITTR1];
288 return env->mmu.ttr[M68K_DTTR0];
290 return env->mmu.ttr[M68K_DTTR1];
292 cpu_abort(env_cpu(env), "Unimplemented control register read 0x%x\n",
296 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
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) {
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;
321 regval = acc | (((uint64_t)extlow) << 32);
322 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
324 env->macc[i] = regval;
330 void m68k_switch_sp(CPUM68KState *env)
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) {
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' : '-');
365 qemu_printf("(%d KiB)\n", size);
369 qemu_printf("(%d MiB)\n", size);
372 qemu_printf("(%d GiB)\n", size);
377 static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
380 int tic_size, tic_shift;
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;
387 int last_attr = -1, attr = -1;
388 CPUState *cs = env_cpu(env);
391 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
395 tib_mask = M68K_8K_PAGE_MASK;
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)) {
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)) {
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)) {
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) {
428 last_logical = logical;
429 logical = (i << M68K_TTS_ROOT_SHIFT) |
430 (j << M68K_TTS_POINTER_SHIFT) |
433 last_physical = physical;
434 physical = tic & ~((1 << tic_shift) - 1);
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) -
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 */ \
466 case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
469 case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
472 case M68K_DESC_CM_NCACHE: /* noncachable */ \
477 static void dump_ttr(uint32_t ttr)
479 if ((ttr & M68K_TTR_ENABLED) == 0) {
480 qemu_printf("disabled\n");
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:
490 case M68K_TTR_SFIELD_SUPER:
497 DUMP_CACHEFLAGS(ttr);
498 if (ttr & M68K_DESC_WRITEPROT) {
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");
513 qemu_printf("Page Size: ");
514 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
515 qemu_printf("8kB\n");
517 qemu_printf("4kB\n");
520 qemu_printf("MMUSR: ");
521 if (env->mmu.mmusr & M68K_MMU_B_040) {
522 qemu_printf("BUS ERROR\n");
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 */
531 if (env->mmu.mmusr & M68K_MMU_S_040) {
532 qemu_printf("S"); /* Supervisor */
536 if (env->mmu.mmusr & M68K_MMU_M_040) {
537 qemu_printf("M"); /* Modified */
541 if (env->mmu.mmusr & M68K_MMU_WP_040) {
542 qemu_printf("W"); /* Write protect */
546 if (env->mmu.mmusr & M68K_MMU_T_040) {
547 qemu_printf("T"); /* Transparent */
551 if (env->mmu.mmusr & M68K_MMU_R_040) {
552 qemu_printf("R"); /* Resident */
556 qemu_printf(" Cache: ");
557 DUMP_CACHEFLAGS(env->mmu.mmusr);
558 qemu_printf(" U: %d\n", (env->mmu.mmusr >> 8) & 3);
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,
583 /* check if transparent translation is enabled */
584 if ((ttr & M68K_TTR_ENABLED) == 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) {
596 case M68K_TTR_SFIELD_SUPER:
597 /* match only if supervisor */
598 if ((access_type & ACCESS_SUPER) == 0) {
603 /* all other values disable mode matching (FC2) */
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)) {
617 *prot = PAGE_READ | PAGE_EXEC;
618 if ((ttr & M68K_DESC_WRITEPROT) == 0) {
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);
632 target_ulong page_mask;
633 bool debug = access_type & ACCESS_DEBUG;
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;
647 *page_size = TARGET_PAGE_SIZE;
652 /* Page Table Root Pointer */
653 *prot = PAGE_READ | PAGE_WRITE;
654 if (access_type & ACCESS_CODE) {
657 if (access_type & ACCESS_SUPER) {
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) {
670 if (!M68K_UDT_VALID(next)) {
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) {
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) {
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) {
697 if (!M68K_UDT_VALID(next)) {
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) {
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) {
718 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
719 entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
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) {
729 if (!M68K_PDT_VALID(next)) {
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) {
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) {
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) {
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) {
767 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
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) {
788 if (next & M68K_DESC_SUPERONLY) {
789 if ((access_type & ACCESS_SUPER) == 0) {
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.
805 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
807 M68kCPU *cpu = M68K_CPU(cs);
808 CPUM68KState *env = &cpu->env;
812 target_ulong page_size;
814 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
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) {
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;
846 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
848 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
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
866 target_ulong page_size;
868 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
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);
877 if (qemu_access_type == MMU_INST_FETCH) {
878 access_type = ACCESS_CODE;
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);
902 env->mmu.ssw = M68K_ATC_040;
905 env->mmu.ssw |= M68K_BA_SIZE_BYTE;
908 env->mmu.ssw |= M68K_BA_SIZE_WORD;
911 env->mmu.ssw |= M68K_BA_SIZE_LONG;
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;
920 env->mmu.ssw |= M68K_TM_040_DATA;
922 if (!(access_type & ACCESS_STORE)) {
923 env->mmu.ssw |= M68K_RW_040;
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);
940 uint32_t HELPER(ff1)(uint32_t x)
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;
957 void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
959 env->sr = sr & 0xffe0;
960 cpu_m68k_set_ccr(env, sr);
964 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
966 cpu_m68k_set_sr(env, val);
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
975 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
978 env->macc[dest] = env->macc[src];
979 mask = MACSR_PAV0 << dest;
980 if (env->macsr & (MACSR_PAV0 << src))
986 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
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. */
1006 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
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;
1017 product &= ((1ull << 40) - 1);
1023 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
1028 product = (uint64_t)op1 * op2;
1029 if (env->macsr & MACSR_RT) {
1030 remainder = product & 0xffffff;
1032 if (remainder > 0x800000)
1034 else if (remainder == 0x800000)
1035 product += (product & 1);
1042 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
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
1059 result = (result >> 63) ^ 0x7fffffff;
1062 env->macc[acc] = result;
1065 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
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))
1079 val = (1ull << 48) - 1;
1081 val &= ((1ull << 48) - 1);
1084 env->macc[acc] = val;
1087 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
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)
1109 val = env->macc[acc];
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;
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) { \
1139 /* Everything in place. */ \
1146 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
1149 v = (res ^ src1) & ~(src1 ^ src2); \
1156 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
1159 v = (res ^ src1) & (src1 ^ src2); \
1166 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
1170 v = (res ^ src1) & (src1 ^ src2); \
1177 cpu_abort(env_cpu(env), "Bad CC_OP %d", op); \
1181 uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1183 uint32_t x, c, n, z, v;
1184 uint32_t res, src1, src2;
1192 COMPUTE_CCR(env->cc_op, x, n, z, v, c);
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)
1234 if (env->macsr & MACSR_SU) {
1235 /* 16-bit rounding. */
1236 rem = val & 0xffffff;
1237 val = (val >> 24) & 0xffffu;
1240 else if (rem == 0x800000)
1242 } else if (env->macsr & MACSR_RT) {
1243 /* 32-bit rounding. */
1248 else if (rem == 0x80)
1254 if (env->macsr & MACSR_OMC) {
1256 if (env->macsr & MACSR_SU) {
1257 if (val != (uint16_t) val) {
1258 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1260 result = val & 0xffff;
1263 if (val != (uint32_t)val) {
1264 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1266 result = (uint32_t)val;
1270 /* No saturation. */
1271 if (env->macsr & MACSR_SU) {
1272 result = val & 0xffff;
1274 result = (uint32_t)val;
1280 uint32_t HELPER(get_macs)(uint64_t val)
1282 if (val == (int32_t)val) {
1283 return (int32_t)val;
1285 return (val >> 61) ^ ~SIGNBIT;
1289 uint32_t HELPER(get_macu)(uint64_t val)
1291 if ((val >> 32) == 0) {
1292 return (uint32_t)val;
1298 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
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;
1308 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1311 val = (env->macc[acc] >> 32) & 0xffff;
1312 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1316 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1320 res = env->macc[acc] & 0xffffffff00ull;
1321 tmp = (int16_t)(val & 0xff00);
1322 res |= ((int64_t)tmp) << 32;
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)
1336 res = (uint32_t)env->macc[acc];
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)
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)
1364 target_ulong page_size;
1366 access_type = ACCESS_PTEST;
1368 access_type |= ACCESS_SUPER;
1370 if ((env->dfc & 3) == 2) {
1371 access_type |= ACCESS_CODE;
1374 access_type |= ACCESS_STORE;
1379 ret = get_physical_address(env, &physical, &prot, addr,
1380 access_type, &page_size);
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);
1394 case 0: /* Flush page entry if not global */
1395 case 1: /* Flush page entry */
1396 tlb_flush_page(cs, addr);
1398 case 2: /* Flush all except global entries */
1401 case 3: /* Flush all entries */
1407 void HELPER(reset)(CPUM68KState *env)
1409 /* FIXME: reset all except CPU */