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 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 * 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"
26 #include "exec/helper-proto.h"
28 #define SIGNBIT (1u << 31)
30 /* Sort alphabetically, except for "any". */
31 static gint
m68k_cpu_list_compare(gconstpointer a
, gconstpointer b
)
33 ObjectClass
*class_a
= (ObjectClass
*)a
;
34 ObjectClass
*class_b
= (ObjectClass
*)b
;
35 const char *name_a
, *name_b
;
37 name_a
= object_class_get_name(class_a
);
38 name_b
= object_class_get_name(class_b
);
39 if (strcmp(name_a
, "any-" TYPE_M68K_CPU
) == 0) {
41 } else if (strcmp(name_b
, "any-" TYPE_M68K_CPU
) == 0) {
44 return strcasecmp(name_a
, name_b
);
48 static void m68k_cpu_list_entry(gpointer data
, gpointer user_data
)
50 ObjectClass
*c
= data
;
51 CPUListState
*s
= user_data
;
55 typename
= object_class_get_name(c
);
56 name
= g_strndup(typename
, strlen(typename
) - strlen("-" TYPE_M68K_CPU
));
57 (*s
->cpu_fprintf
)(s
->file
, "%s\n",
62 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
66 .cpu_fprintf
= cpu_fprintf
,
70 list
= object_class_get_list(TYPE_M68K_CPU
, false);
71 list
= g_slist_sort(list
, m68k_cpu_list_compare
);
72 g_slist_foreach(list
, m68k_cpu_list_entry
, &s
);
76 static int cf_fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
80 stfq_p(mem_buf
, floatx80_to_float64(env
->fregs
[n
].d
, &s
));
84 case 8: /* fpcontrol */
85 stl_be_p(mem_buf
, env
->fpcr
);
87 case 9: /* fpstatus */
88 stl_be_p(mem_buf
, env
->fpsr
);
90 case 10: /* fpiar, not implemented */
91 memset(mem_buf
, 0, 4);
97 static int cf_fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
101 env
->fregs
[n
].d
= float64_to_floatx80(ldfq_p(mem_buf
), &s
);
105 case 8: /* fpcontrol */
106 cpu_m68k_set_fpcr(env
, ldl_p(mem_buf
));
108 case 9: /* fpstatus */
109 env
->fpsr
= ldl_p(mem_buf
);
111 case 10: /* fpiar, not implemented */
117 static int m68k_fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
120 stw_be_p(mem_buf
, env
->fregs
[n
].l
.upper
);
121 memset(mem_buf
+ 2, 0, 2);
122 stq_be_p(mem_buf
+ 4, env
->fregs
[n
].l
.lower
);
126 case 8: /* fpcontrol */
127 stl_be_p(mem_buf
, env
->fpcr
);
129 case 9: /* fpstatus */
130 stl_be_p(mem_buf
, env
->fpsr
);
132 case 10: /* fpiar, not implemented */
133 memset(mem_buf
, 0, 4);
139 static int m68k_fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
142 env
->fregs
[n
].l
.upper
= lduw_be_p(mem_buf
);
143 env
->fregs
[n
].l
.lower
= ldq_be_p(mem_buf
+ 4);
147 case 8: /* fpcontrol */
148 cpu_m68k_set_fpcr(env
, ldl_p(mem_buf
));
150 case 9: /* fpstatus */
151 env
->fpsr
= ldl_p(mem_buf
);
153 case 10: /* fpiar, not implemented */
159 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
161 CPUState
*cs
= CPU(cpu
);
162 CPUM68KState
*env
= &cpu
->env
;
164 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
165 gdb_register_coprocessor(cs
, cf_fpu_gdb_get_reg
, cf_fpu_gdb_set_reg
,
166 11, "cf-fp.xml", 18);
167 } else if (m68k_feature(env
, M68K_FEATURE_FPU
)) {
168 gdb_register_coprocessor(cs
, m68k_fpu_gdb_get_reg
,
169 m68k_fpu_gdb_set_reg
, 11, "m68k-fp.xml", 18);
171 /* TODO: Add [E]MAC registers. */
174 void HELPER(cf_movec_to
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
176 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
187 /* TODO: Implement Access Control Registers. */
192 /* TODO: Implement control registers. */
195 "Unimplemented control register write 0x%x = 0x%x\n",
200 void HELPER(m68k_movec_to
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
202 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
225 env
->mmu
.mmusr
= val
;
234 env
->sp
[M68K_USP
] = val
;
237 env
->sp
[M68K_SSP
] = val
;
240 env
->sp
[M68K_ISP
] = val
;
242 /* MC68040/MC68LC040 */
244 env
->mmu
.ttr
[M68K_ITTR0
] = val
;
247 env
->mmu
.ttr
[M68K_ITTR1
] = val
;
250 env
->mmu
.ttr
[M68K_DTTR0
] = val
;
253 env
->mmu
.ttr
[M68K_DTTR1
] = val
;
256 cpu_abort(CPU(cpu
), "Unimplemented control register write 0x%x = 0x%x\n",
260 uint32_t HELPER(m68k_movec_from
)(CPUM68KState
*env
, uint32_t reg
)
262 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
279 return env
->mmu
.mmusr
;
283 return env
->sp
[M68K_USP
];
285 return env
->sp
[M68K_SSP
];
287 return env
->sp
[M68K_ISP
];
288 /* MC68040/MC68LC040 */
292 return env
->mmu
.ttr
[M68K_ITTR0
];
294 return env
->mmu
.ttr
[M68K_ITTR1
];
296 return env
->mmu
.ttr
[M68K_DTTR0
];
298 return env
->mmu
.ttr
[M68K_DTTR1
];
300 cpu_abort(CPU(cpu
), "Unimplemented control register read 0x%x\n",
304 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
311 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
312 for (i
= 0; i
< 4; i
++) {
313 regval
= env
->macc
[i
];
314 exthigh
= regval
>> 40;
315 if (env
->macsr
& MACSR_FI
) {
320 extlow
= regval
>> 32;
322 if (env
->macsr
& MACSR_FI
) {
323 regval
= (((uint64_t)acc
) << 8) | extlow
;
324 regval
|= ((int64_t)exthigh
) << 40;
325 } else if (env
->macsr
& MACSR_SU
) {
326 regval
= acc
| (((int64_t)extlow
) << 32);
327 regval
|= ((int64_t)exthigh
) << 40;
329 regval
= acc
| (((uint64_t)extlow
) << 32);
330 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
332 env
->macc
[i
] = regval
;
338 void m68k_switch_sp(CPUM68KState
*env
)
342 env
->sp
[env
->current_sp
] = env
->aregs
[7];
343 if (m68k_feature(env
, M68K_FEATURE_M68000
)) {
344 if (env
->sr
& SR_S
) {
345 if (env
->sr
& SR_M
) {
354 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
355 ? M68K_SSP
: M68K_USP
;
357 env
->aregs
[7] = env
->sp
[new_sp
];
358 env
->current_sp
= new_sp
;
361 #if defined(CONFIG_USER_ONLY)
363 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int size
, int rw
,
366 M68kCPU
*cpu
= M68K_CPU(cs
);
368 cs
->exception_index
= EXCP_ACCESS
;
369 cpu
->env
.mmu
.ar
= address
;
375 /* MMU: 68040 only */
377 static void print_address_zone(FILE *f
, fprintf_function cpu_fprintf
,
378 uint32_t logical
, uint32_t physical
,
379 uint32_t size
, int attr
)
381 cpu_fprintf(f
, "%08x - %08x -> %08x - %08x %c ",
382 logical
, logical
+ size
- 1,
383 physical
, physical
+ size
- 1,
384 attr
& 4 ? 'W' : '-');
387 cpu_fprintf(f
, "(%d KiB)\n", size
);
391 cpu_fprintf(f
, "(%d MiB)\n", size
);
394 cpu_fprintf(f
, "(%d GiB)\n", size
);
399 static void dump_address_map(FILE *f
, fprintf_function cpu_fprintf
,
400 CPUM68KState
*env
, uint32_t root_pointer
)
403 int tic_size
, tic_shift
;
405 uint32_t tia
, tib
, tic
;
406 uint32_t logical
= 0xffffffff, physical
= 0xffffffff;
407 uint32_t first_logical
= 0xffffffff, first_physical
= 0xffffffff;
408 uint32_t last_logical
, last_physical
;
410 int last_attr
= -1, attr
= -1;
411 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
412 CPUState
*cs
= CPU(cpu
);
414 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
418 tib_mask
= M68K_8K_PAGE_MASK
;
423 tib_mask
= M68K_4K_PAGE_MASK
;
425 for (i
= 0; i
< M68K_ROOT_POINTER_ENTRIES
; i
++) {
426 tia
= ldl_phys(cs
->as
, M68K_POINTER_BASE(root_pointer
) + i
* 4);
427 if (!M68K_UDT_VALID(tia
)) {
430 for (j
= 0; j
< M68K_ROOT_POINTER_ENTRIES
; j
++) {
431 tib
= ldl_phys(cs
->as
, M68K_POINTER_BASE(tia
) + j
* 4);
432 if (!M68K_UDT_VALID(tib
)) {
435 for (k
= 0; k
< tic_size
; k
++) {
436 tic
= ldl_phys(cs
->as
, (tib
& tib_mask
) + k
* 4);
437 if (!M68K_PDT_VALID(tic
)) {
440 if (M68K_PDT_INDIRECT(tic
)) {
441 tic
= ldl_phys(cs
->as
, M68K_INDIRECT_POINTER(tic
));
444 last_logical
= logical
;
445 logical
= (i
<< M68K_TTS_ROOT_SHIFT
) |
446 (j
<< M68K_TTS_POINTER_SHIFT
) |
449 last_physical
= physical
;
450 physical
= tic
& ~((1 << tic_shift
) - 1);
453 attr
= tic
& ((1 << tic_shift
) - 1);
455 if ((logical
!= (last_logical
+ (1 << tic_shift
))) ||
456 (physical
!= (last_physical
+ (1 << tic_shift
))) ||
457 (attr
& 4) != (last_attr
& 4)) {
459 if (first_logical
!= 0xffffffff) {
460 size
= last_logical
+ (1 << tic_shift
) -
462 print_address_zone(f
, cpu_fprintf
, first_logical
,
463 first_physical
, size
, last_attr
);
465 first_logical
= logical
;
466 first_physical
= physical
;
471 if (first_logical
!= logical
|| (attr
& 4) != (last_attr
& 4)) {
472 size
= logical
+ (1 << tic_shift
) - first_logical
;
473 print_address_zone(f
, cpu_fprintf
, first_logical
, first_physical
, size
,
478 #define DUMP_CACHEFLAGS(a) \
479 switch (a & M68K_DESC_CACHEMODE) { \
480 case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
481 cpu_fprintf(f, "T"); \
483 case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
484 cpu_fprintf(f, "C"); \
486 case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
487 cpu_fprintf(f, "S"); \
489 case M68K_DESC_CM_NCACHE: /* noncachable */ \
490 cpu_fprintf(f, "N"); \
494 static void dump_ttr(FILE *f
, fprintf_function cpu_fprintf
, uint32_t ttr
)
496 if ((ttr
& M68K_TTR_ENABLED
) == 0) {
497 cpu_fprintf(f
, "disabled\n");
500 cpu_fprintf(f
, "Base: 0x%08x Mask: 0x%08x Control: ",
501 ttr
& M68K_TTR_ADDR_BASE
,
502 (ttr
& M68K_TTR_ADDR_MASK
) << M68K_TTR_ADDR_MASK_SHIFT
);
503 switch (ttr
& M68K_TTR_SFIELD
) {
504 case M68K_TTR_SFIELD_USER
:
507 case M68K_TTR_SFIELD_SUPER
:
514 DUMP_CACHEFLAGS(ttr
);
515 if (ttr
& M68K_DESC_WRITEPROT
) {
520 cpu_fprintf(f
, " U: %d\n", (ttr
& M68K_DESC_USERATTR
) >>
521 M68K_DESC_USERATTR_SHIFT
);
524 void dump_mmu(FILE *f
, fprintf_function cpu_fprintf
, CPUM68KState
*env
)
526 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
527 cpu_fprintf(f
, "Translation disabled\n");
530 cpu_fprintf(f
, "Page Size: ");
531 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
532 cpu_fprintf(f
, "8kB\n");
534 cpu_fprintf(f
, "4kB\n");
537 cpu_fprintf(f
, "MMUSR: ");
538 if (env
->mmu
.mmusr
& M68K_MMU_B_040
) {
539 cpu_fprintf(f
, "BUS ERROR\n");
541 cpu_fprintf(f
, "Phy=%08x Flags: ", env
->mmu
.mmusr
& 0xfffff000);
542 /* flags found on the page descriptor */
543 if (env
->mmu
.mmusr
& M68K_MMU_G_040
) {
544 cpu_fprintf(f
, "G"); /* Global */
548 if (env
->mmu
.mmusr
& M68K_MMU_S_040
) {
549 cpu_fprintf(f
, "S"); /* Supervisor */
553 if (env
->mmu
.mmusr
& M68K_MMU_M_040
) {
554 cpu_fprintf(f
, "M"); /* Modified */
558 if (env
->mmu
.mmusr
& M68K_MMU_WP_040
) {
559 cpu_fprintf(f
, "W"); /* Write protect */
563 if (env
->mmu
.mmusr
& M68K_MMU_T_040
) {
564 cpu_fprintf(f
, "T"); /* Transparent */
568 if (env
->mmu
.mmusr
& M68K_MMU_R_040
) {
569 cpu_fprintf(f
, "R"); /* Resident */
573 cpu_fprintf(f
, " Cache: ");
574 DUMP_CACHEFLAGS(env
->mmu
.mmusr
);
575 cpu_fprintf(f
, " U: %d\n", (env
->mmu
.mmusr
>> 8) & 3);
576 cpu_fprintf(f
, "\n");
579 cpu_fprintf(f
, "ITTR0: ");
580 dump_ttr(f
, cpu_fprintf
, env
->mmu
.ttr
[M68K_ITTR0
]);
581 cpu_fprintf(f
, "ITTR1: ");
582 dump_ttr(f
, cpu_fprintf
, env
->mmu
.ttr
[M68K_ITTR1
]);
583 cpu_fprintf(f
, "DTTR0: ");
584 dump_ttr(f
, cpu_fprintf
, env
->mmu
.ttr
[M68K_DTTR0
]);
585 cpu_fprintf(f
, "DTTR1: ");
586 dump_ttr(f
, cpu_fprintf
, env
->mmu
.ttr
[M68K_DTTR1
]);
588 cpu_fprintf(f
, "SRP: 0x%08x\n", env
->mmu
.srp
);
589 dump_address_map(f
, cpu_fprintf
, env
, env
->mmu
.srp
);
591 cpu_fprintf(f
, "URP: 0x%08x\n", env
->mmu
.urp
);
592 dump_address_map(f
, cpu_fprintf
, env
, env
->mmu
.urp
);
595 static int check_TTR(uint32_t ttr
, int *prot
, target_ulong addr
,
600 /* check if transparent translation is enabled */
601 if ((ttr
& M68K_TTR_ENABLED
) == 0) {
605 /* check mode access */
606 switch (ttr
& M68K_TTR_SFIELD
) {
607 case M68K_TTR_SFIELD_USER
:
608 /* match only if user */
609 if ((access_type
& ACCESS_SUPER
) != 0) {
613 case M68K_TTR_SFIELD_SUPER
:
614 /* match only if supervisor */
615 if ((access_type
& ACCESS_SUPER
) == 0) {
620 /* all other values disable mode matching (FC2) */
624 /* check address matching */
626 base
= ttr
& M68K_TTR_ADDR_BASE
;
627 mask
= (ttr
& M68K_TTR_ADDR_MASK
) ^ M68K_TTR_ADDR_MASK
;
628 mask
<<= M68K_TTR_ADDR_MASK_SHIFT
;
630 if ((addr
& mask
) != (base
& mask
)) {
634 *prot
= PAGE_READ
| PAGE_EXEC
;
635 if ((ttr
& M68K_DESC_WRITEPROT
) == 0) {
642 static int get_physical_address(CPUM68KState
*env
, hwaddr
*physical
,
643 int *prot
, target_ulong address
,
644 int access_type
, target_ulong
*page_size
)
646 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
647 CPUState
*cs
= CPU(cpu
);
650 target_ulong page_mask
;
651 bool debug
= access_type
& ACCESS_DEBUG
;
655 /* Transparent Translation (physical = logical) */
656 for (i
= 0; i
< M68K_MAX_TTR
; i
++) {
657 if (check_TTR(env
->mmu
.TTR(access_type
, i
),
658 prot
, address
, access_type
)) {
659 if (access_type
& ACCESS_PTEST
) {
660 /* Transparent Translation Register bit */
661 env
->mmu
.mmusr
= M68K_MMU_T_040
| M68K_MMU_R_040
;
663 *physical
= address
& TARGET_PAGE_MASK
;
664 *page_size
= TARGET_PAGE_SIZE
;
669 /* Page Table Root Pointer */
670 *prot
= PAGE_READ
| PAGE_WRITE
;
671 if (access_type
& ACCESS_CODE
) {
674 if (access_type
& ACCESS_SUPER
) {
681 entry
= M68K_POINTER_BASE(next
) | M68K_ROOT_INDEX(address
);
683 next
= ldl_phys(cs
->as
, entry
);
684 if (!M68K_UDT_VALID(next
)) {
687 if (!(next
& M68K_DESC_USED
) && !debug
) {
688 stl_phys(cs
->as
, entry
, next
| M68K_DESC_USED
);
690 if (next
& M68K_DESC_WRITEPROT
) {
691 if (access_type
& ACCESS_PTEST
) {
692 env
->mmu
.mmusr
|= M68K_MMU_WP_040
;
694 *prot
&= ~PAGE_WRITE
;
695 if (access_type
& ACCESS_STORE
) {
701 entry
= M68K_POINTER_BASE(next
) | M68K_POINTER_INDEX(address
);
703 next
= ldl_phys(cs
->as
, entry
);
704 if (!M68K_UDT_VALID(next
)) {
707 if (!(next
& M68K_DESC_USED
) && !debug
) {
708 stl_phys(cs
->as
, entry
, next
| M68K_DESC_USED
);
710 if (next
& M68K_DESC_WRITEPROT
) {
711 if (access_type
& ACCESS_PTEST
) {
712 env
->mmu
.mmusr
|= M68K_MMU_WP_040
;
714 *prot
&= ~PAGE_WRITE
;
715 if (access_type
& ACCESS_STORE
) {
721 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
722 entry
= M68K_8K_PAGE_BASE(next
) | M68K_8K_PAGE_INDEX(address
);
724 entry
= M68K_4K_PAGE_BASE(next
) | M68K_4K_PAGE_INDEX(address
);
727 next
= ldl_phys(cs
->as
, entry
);
729 if (!M68K_PDT_VALID(next
)) {
732 if (M68K_PDT_INDIRECT(next
)) {
733 next
= ldl_phys(cs
->as
, M68K_INDIRECT_POINTER(next
));
735 if (access_type
& ACCESS_STORE
) {
736 if (next
& M68K_DESC_WRITEPROT
) {
737 if (!(next
& M68K_DESC_USED
) && !debug
) {
738 stl_phys(cs
->as
, entry
, next
| M68K_DESC_USED
);
740 } else if ((next
& (M68K_DESC_MODIFIED
| M68K_DESC_USED
)) !=
741 (M68K_DESC_MODIFIED
| M68K_DESC_USED
) && !debug
) {
742 stl_phys(cs
->as
, entry
,
743 next
| (M68K_DESC_MODIFIED
| M68K_DESC_USED
));
746 if (!(next
& M68K_DESC_USED
) && !debug
) {
747 stl_phys(cs
->as
, entry
, next
| M68K_DESC_USED
);
751 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
756 *page_size
= 1 << page_bits
;
757 page_mask
= ~(*page_size
- 1);
758 *physical
= next
& page_mask
;
760 if (access_type
& ACCESS_PTEST
) {
761 env
->mmu
.mmusr
|= next
& M68K_MMU_SR_MASK_040
;
762 env
->mmu
.mmusr
|= *physical
& 0xfffff000;
763 env
->mmu
.mmusr
|= M68K_MMU_R_040
;
766 if (next
& M68K_DESC_WRITEPROT
) {
767 *prot
&= ~PAGE_WRITE
;
768 if (access_type
& ACCESS_STORE
) {
772 if (next
& M68K_DESC_SUPERONLY
) {
773 if ((access_type
& ACCESS_SUPER
) == 0) {
781 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
783 M68kCPU
*cpu
= M68K_CPU(cs
);
784 CPUM68KState
*env
= &cpu
->env
;
788 target_ulong page_size
;
790 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
795 access_type
= ACCESS_DATA
| ACCESS_DEBUG
;
796 if (env
->sr
& SR_S
) {
797 access_type
|= ACCESS_SUPER
;
799 if (get_physical_address(env
, &phys_addr
, &prot
,
800 addr
, access_type
, &page_size
) != 0) {
806 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int size
, int rw
,
809 M68kCPU
*cpu
= M68K_CPU(cs
);
810 CPUM68KState
*env
= &cpu
->env
;
815 target_ulong page_size
;
817 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
819 tlb_set_page(cs
, address
& TARGET_PAGE_MASK
,
820 address
& TARGET_PAGE_MASK
,
821 PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
,
822 mmu_idx
, TARGET_PAGE_SIZE
);
827 access_type
= ACCESS_CODE
;
830 access_type
= ACCESS_DATA
;
832 access_type
|= ACCESS_STORE
;
836 if (mmu_idx
!= MMU_USER_IDX
) {
837 access_type
|= ACCESS_SUPER
;
840 ret
= get_physical_address(&cpu
->env
, &physical
, &prot
,
841 address
, access_type
, &page_size
);
843 address
&= TARGET_PAGE_MASK
;
844 physical
+= address
& (page_size
- 1);
845 tlb_set_page(cs
, address
, physical
,
846 prot
, mmu_idx
, TARGET_PAGE_SIZE
);
850 env
->mmu
.ssw
= M68K_ATC_040
;
853 env
->mmu
.ssw
|= M68K_BA_SIZE_BYTE
;
856 env
->mmu
.ssw
|= M68K_BA_SIZE_WORD
;
859 env
->mmu
.ssw
|= M68K_BA_SIZE_LONG
;
862 if (access_type
& ACCESS_SUPER
) {
863 env
->mmu
.ssw
|= M68K_TM_040_SUPER
;
865 if (access_type
& ACCESS_CODE
) {
866 env
->mmu
.ssw
|= M68K_TM_040_CODE
;
868 env
->mmu
.ssw
|= M68K_TM_040_DATA
;
870 if (!(access_type
& ACCESS_STORE
)) {
871 env
->mmu
.ssw
|= M68K_RW_040
;
873 env
->mmu
.ar
= address
;
874 cs
->exception_index
= EXCP_ACCESS
;
878 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
879 be handled by the interrupt controller. Real hardware only requests
880 the vector when the interrupt is acknowledged by the CPU. For
881 simplicitly we calculate it when the interrupt is signalled. */
882 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
884 CPUState
*cs
= CPU(cpu
);
885 CPUM68KState
*env
= &cpu
->env
;
887 env
->pending_level
= level
;
888 env
->pending_vector
= vector
;
890 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
892 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
898 uint32_t HELPER(bitrev
)(uint32_t x
)
900 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
901 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
902 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
906 uint32_t HELPER(ff1
)(uint32_t x
)
914 uint32_t HELPER(sats
)(uint32_t val
, uint32_t v
)
916 /* The result has the opposite sign to the original value. */
917 if ((int32_t)v
< 0) {
918 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
923 void cpu_m68k_set_sr(CPUM68KState
*env
, uint32_t sr
)
925 env
->sr
= sr
& 0xffe0;
926 cpu_m68k_set_ccr(env
, sr
);
930 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
932 cpu_m68k_set_sr(env
, val
);
936 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
937 take values, others take register numbers and manipulate the contents
939 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
942 env
->macc
[dest
] = env
->macc
[src
];
943 mask
= MACSR_PAV0
<< dest
;
944 if (env
->macsr
& (MACSR_PAV0
<< src
))
950 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
955 product
= (uint64_t)op1
* op2
;
956 res
= (product
<< 24) >> 24;
957 if (res
!= product
) {
958 env
->macsr
|= MACSR_V
;
959 if (env
->macsr
& MACSR_OMC
) {
960 /* Make sure the accumulate operation overflows. */
970 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
974 product
= (uint64_t)op1
* op2
;
975 if (product
& (0xffffffull
<< 40)) {
976 env
->macsr
|= MACSR_V
;
977 if (env
->macsr
& MACSR_OMC
) {
978 /* Make sure the accumulate operation overflows. */
981 product
&= ((1ull << 40) - 1);
987 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
992 product
= (uint64_t)op1
* op2
;
993 if (env
->macsr
& MACSR_RT
) {
994 remainder
= product
& 0xffffff;
996 if (remainder
> 0x800000)
998 else if (remainder
== 0x800000)
999 product
+= (product
& 1);
1006 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
1010 tmp
= env
->macc
[acc
];
1011 result
= ((tmp
<< 16) >> 16);
1012 if (result
!= tmp
) {
1013 env
->macsr
|= MACSR_V
;
1015 if (env
->macsr
& MACSR_V
) {
1016 env
->macsr
|= MACSR_PAV0
<< acc
;
1017 if (env
->macsr
& MACSR_OMC
) {
1018 /* The result is saturated to 32 bits, despite overflow occurring
1019 at 48 bits. Seems weird, but that's what the hardware docs
1021 result
= (result
>> 63) ^ 0x7fffffff;
1024 env
->macc
[acc
] = result
;
1027 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
1031 val
= env
->macc
[acc
];
1032 if (val
& (0xffffull
<< 48)) {
1033 env
->macsr
|= MACSR_V
;
1035 if (env
->macsr
& MACSR_V
) {
1036 env
->macsr
|= MACSR_PAV0
<< acc
;
1037 if (env
->macsr
& MACSR_OMC
) {
1038 if (val
> (1ull << 53))
1041 val
= (1ull << 48) - 1;
1043 val
&= ((1ull << 48) - 1);
1046 env
->macc
[acc
] = val
;
1049 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
1054 sum
= env
->macc
[acc
];
1055 result
= (sum
<< 16) >> 16;
1056 if (result
!= sum
) {
1057 env
->macsr
|= MACSR_V
;
1059 if (env
->macsr
& MACSR_V
) {
1060 env
->macsr
|= MACSR_PAV0
<< acc
;
1061 if (env
->macsr
& MACSR_OMC
) {
1062 result
= (result
>> 63) ^ 0x7fffffffffffll
;
1065 env
->macc
[acc
] = result
;
1068 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
1071 val
= env
->macc
[acc
];
1073 env
->macsr
|= MACSR_Z
;
1074 } else if (val
& (1ull << 47)) {
1075 env
->macsr
|= MACSR_N
;
1077 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
1078 env
->macsr
|= MACSR_V
;
1080 if (env
->macsr
& MACSR_FI
) {
1081 val
= ((int64_t)val
) >> 40;
1082 if (val
!= 0 && val
!= -1)
1083 env
->macsr
|= MACSR_EV
;
1084 } else if (env
->macsr
& MACSR_SU
) {
1085 val
= ((int64_t)val
) >> 32;
1086 if (val
!= 0 && val
!= -1)
1087 env
->macsr
|= MACSR_EV
;
1089 if ((val
>> 32) != 0)
1090 env
->macsr
|= MACSR_EV
;
1094 #define EXTSIGN(val, index) ( \
1095 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1098 #define COMPUTE_CCR(op, x, n, z, v, c) { \
1101 /* Everything in place. */ \
1108 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
1111 v = (res ^ src1) & ~(src1 ^ src2); \
1118 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
1121 v = (res ^ src1) & (src1 ^ src2); \
1128 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
1132 v = (res ^ src1) & (src1 ^ src2); \
1139 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
1143 uint32_t cpu_m68k_get_ccr(CPUM68KState
*env
)
1145 uint32_t x
, c
, n
, z
, v
;
1146 uint32_t res
, src1
, src2
;
1154 COMPUTE_CCR(env
->cc_op
, x
, n
, z
, v
, c
);
1160 return x
* CCF_X
+ n
* CCF_N
+ z
* CCF_Z
+ v
* CCF_V
+ c
* CCF_C
;
1163 uint32_t HELPER(get_ccr
)(CPUM68KState
*env
)
1165 return cpu_m68k_get_ccr(env
);
1168 void cpu_m68k_set_ccr(CPUM68KState
*env
, uint32_t ccr
)
1170 env
->cc_x
= (ccr
& CCF_X
? 1 : 0);
1171 env
->cc_n
= (ccr
& CCF_N
? -1 : 0);
1172 env
->cc_z
= (ccr
& CCF_Z
? 0 : 1);
1173 env
->cc_v
= (ccr
& CCF_V
? -1 : 0);
1174 env
->cc_c
= (ccr
& CCF_C
? 1 : 0);
1175 env
->cc_op
= CC_OP_FLAGS
;
1178 void HELPER(set_ccr
)(CPUM68KState
*env
, uint32_t ccr
)
1180 cpu_m68k_set_ccr(env
, ccr
);
1183 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
1185 uint32_t res
, src1
, src2
;
1187 COMPUTE_CCR(cc_op
, env
->cc_x
, env
->cc_n
, env
->cc_z
, env
->cc_v
, env
->cc_c
);
1188 env
->cc_op
= CC_OP_FLAGS
;
1191 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
1196 if (env
->macsr
& MACSR_SU
) {
1197 /* 16-bit rounding. */
1198 rem
= val
& 0xffffff;
1199 val
= (val
>> 24) & 0xffffu
;
1202 else if (rem
== 0x800000)
1204 } else if (env
->macsr
& MACSR_RT
) {
1205 /* 32-bit rounding. */
1210 else if (rem
== 0x80)
1216 if (env
->macsr
& MACSR_OMC
) {
1218 if (env
->macsr
& MACSR_SU
) {
1219 if (val
!= (uint16_t) val
) {
1220 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
1222 result
= val
& 0xffff;
1225 if (val
!= (uint32_t)val
) {
1226 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
1228 result
= (uint32_t)val
;
1232 /* No saturation. */
1233 if (env
->macsr
& MACSR_SU
) {
1234 result
= val
& 0xffff;
1236 result
= (uint32_t)val
;
1242 uint32_t HELPER(get_macs
)(uint64_t val
)
1244 if (val
== (int32_t)val
) {
1245 return (int32_t)val
;
1247 return (val
>> 61) ^ ~SIGNBIT
;
1251 uint32_t HELPER(get_macu
)(uint64_t val
)
1253 if ((val
>> 32) == 0) {
1254 return (uint32_t)val
;
1260 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
1263 val
= env
->macc
[acc
] & 0x00ff;
1264 val
|= (env
->macc
[acc
] >> 32) & 0xff00;
1265 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
1266 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
1270 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
1273 val
= (env
->macc
[acc
] >> 32) & 0xffff;
1274 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
1278 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1282 res
= env
->macc
[acc
] & 0xffffffff00ull
;
1283 tmp
= (int16_t)(val
& 0xff00);
1284 res
|= ((int64_t)tmp
) << 32;
1286 env
->macc
[acc
] = res
;
1287 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
1288 tmp
= (val
& 0xff000000);
1289 res
|= ((int64_t)tmp
) << 16;
1290 res
|= (val
>> 16) & 0xff;
1291 env
->macc
[acc
+ 1] = res
;
1294 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1298 res
= (uint32_t)env
->macc
[acc
];
1300 res
|= ((int64_t)tmp
) << 32;
1301 env
->macc
[acc
] = res
;
1302 res
= (uint32_t)env
->macc
[acc
+ 1];
1303 tmp
= val
& 0xffff0000;
1304 res
|= (int64_t)tmp
<< 16;
1305 env
->macc
[acc
+ 1] = res
;
1308 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1311 res
= (uint32_t)env
->macc
[acc
];
1312 res
|= ((uint64_t)(val
& 0xffff)) << 32;
1313 env
->macc
[acc
] = res
;
1314 res
= (uint32_t)env
->macc
[acc
+ 1];
1315 res
|= (uint64_t)(val
& 0xffff0000) << 16;
1316 env
->macc
[acc
+ 1] = res
;
1319 #if defined(CONFIG_SOFTMMU)
1320 void HELPER(ptest
)(CPUM68KState
*env
, uint32_t addr
, uint32_t is_read
)
1322 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
1323 CPUState
*cs
= CPU(cpu
);
1328 target_ulong page_size
;
1330 access_type
= ACCESS_PTEST
;
1332 access_type
|= ACCESS_SUPER
;
1334 if ((env
->dfc
& 3) == 2) {
1335 access_type
|= ACCESS_CODE
;
1338 access_type
|= ACCESS_STORE
;
1343 ret
= get_physical_address(env
, &physical
, &prot
, addr
,
1344 access_type
, &page_size
);
1346 addr
&= TARGET_PAGE_MASK
;
1347 physical
+= addr
& (page_size
- 1);
1348 tlb_set_page(cs
, addr
, physical
,
1349 prot
, access_type
& ACCESS_SUPER
?
1350 MMU_KERNEL_IDX
: MMU_USER_IDX
, page_size
);
1354 void HELPER(pflush
)(CPUM68KState
*env
, uint32_t addr
, uint32_t opmode
)
1356 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
1359 case 0: /* Flush page entry if not global */
1360 case 1: /* Flush page entry */
1361 tlb_flush_page(CPU(cpu
), addr
);
1363 case 2: /* Flush all except global entries */
1364 tlb_flush(CPU(cpu
));
1366 case 3: /* Flush all entries */
1367 tlb_flush(CPU(cpu
));
1372 void HELPER(reset
)(CPUM68KState
*env
)
1374 /* FIXME: reset all except CPU */