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"
27 #include "fpu/softfloat.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
;
52 CPUListState
*s
= user_data
;
56 typename
= object_class_get_name(c
);
57 name
= g_strndup(typename
, strlen(typename
) - strlen("-" TYPE_M68K_CPU
));
58 (*s
->cpu_fprintf
)(s
->file
, "%s\n",
63 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
67 .cpu_fprintf
= cpu_fprintf
,
71 list
= object_class_get_list(TYPE_M68K_CPU
, false);
72 list
= g_slist_sort(list
, m68k_cpu_list_compare
);
73 g_slist_foreach(list
, m68k_cpu_list_entry
, &s
);
77 static int cf_fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
81 stfq_p(mem_buf
, floatx80_to_float64(env
->fregs
[n
].d
, &s
));
85 case 8: /* fpcontrol */
86 stl_be_p(mem_buf
, env
->fpcr
);
88 case 9: /* fpstatus */
89 stl_be_p(mem_buf
, env
->fpsr
);
91 case 10: /* fpiar, not implemented */
92 memset(mem_buf
, 0, 4);
98 static int cf_fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
102 env
->fregs
[n
].d
= float64_to_floatx80(ldfq_p(mem_buf
), &s
);
106 case 8: /* fpcontrol */
107 cpu_m68k_set_fpcr(env
, ldl_p(mem_buf
));
109 case 9: /* fpstatus */
110 env
->fpsr
= ldl_p(mem_buf
);
112 case 10: /* fpiar, not implemented */
118 static int m68k_fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
121 stw_be_p(mem_buf
, env
->fregs
[n
].l
.upper
);
122 memset(mem_buf
+ 2, 0, 2);
123 stq_be_p(mem_buf
+ 4, env
->fregs
[n
].l
.lower
);
127 case 8: /* fpcontrol */
128 stl_be_p(mem_buf
, env
->fpcr
);
130 case 9: /* fpstatus */
131 stl_be_p(mem_buf
, env
->fpsr
);
133 case 10: /* fpiar, not implemented */
134 memset(mem_buf
, 0, 4);
140 static int m68k_fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
143 env
->fregs
[n
].l
.upper
= lduw_be_p(mem_buf
);
144 env
->fregs
[n
].l
.lower
= ldq_be_p(mem_buf
+ 4);
148 case 8: /* fpcontrol */
149 cpu_m68k_set_fpcr(env
, ldl_p(mem_buf
));
151 case 9: /* fpstatus */
152 env
->fpsr
= ldl_p(mem_buf
);
154 case 10: /* fpiar, not implemented */
160 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
162 CPUState
*cs
= CPU(cpu
);
163 CPUM68KState
*env
= &cpu
->env
;
165 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
166 gdb_register_coprocessor(cs
, cf_fpu_gdb_get_reg
, cf_fpu_gdb_set_reg
,
167 11, "cf-fp.xml", 18);
168 } else if (m68k_feature(env
, M68K_FEATURE_FPU
)) {
169 gdb_register_coprocessor(cs
, m68k_fpu_gdb_get_reg
,
170 m68k_fpu_gdb_set_reg
, 11, "m68k-fp.xml", 18);
172 /* TODO: Add [E]MAC registers. */
175 void HELPER(cf_movec_to
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
177 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
188 /* TODO: Implement Access Control Registers. */
193 /* TODO: Implement control registers. */
196 "Unimplemented control register write 0x%x = 0x%x\n",
201 void HELPER(m68k_movec_to
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
203 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
226 env
->mmu
.mmusr
= val
;
235 env
->sp
[M68K_USP
] = val
;
238 env
->sp
[M68K_SSP
] = val
;
241 env
->sp
[M68K_ISP
] = val
;
243 /* MC68040/MC68LC040 */
245 env
->mmu
.ttr
[M68K_ITTR0
] = val
;
248 env
->mmu
.ttr
[M68K_ITTR1
] = val
;
251 env
->mmu
.ttr
[M68K_DTTR0
] = val
;
254 env
->mmu
.ttr
[M68K_DTTR1
] = val
;
257 cpu_abort(CPU(cpu
), "Unimplemented control register write 0x%x = 0x%x\n",
261 uint32_t HELPER(m68k_movec_from
)(CPUM68KState
*env
, uint32_t reg
)
263 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
280 return env
->mmu
.mmusr
;
284 return env
->sp
[M68K_USP
];
286 return env
->sp
[M68K_SSP
];
288 return env
->sp
[M68K_ISP
];
289 /* MC68040/MC68LC040 */
293 return env
->mmu
.ttr
[M68K_ITTR0
];
295 return env
->mmu
.ttr
[M68K_ITTR1
];
297 return env
->mmu
.ttr
[M68K_DTTR0
];
299 return env
->mmu
.ttr
[M68K_DTTR1
];
301 cpu_abort(CPU(cpu
), "Unimplemented control register read 0x%x\n",
305 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
312 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
313 for (i
= 0; i
< 4; i
++) {
314 regval
= env
->macc
[i
];
315 exthigh
= regval
>> 40;
316 if (env
->macsr
& MACSR_FI
) {
321 extlow
= regval
>> 32;
323 if (env
->macsr
& MACSR_FI
) {
324 regval
= (((uint64_t)acc
) << 8) | extlow
;
325 regval
|= ((int64_t)exthigh
) << 40;
326 } else if (env
->macsr
& MACSR_SU
) {
327 regval
= acc
| (((int64_t)extlow
) << 32);
328 regval
|= ((int64_t)exthigh
) << 40;
330 regval
= acc
| (((uint64_t)extlow
) << 32);
331 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
333 env
->macc
[i
] = regval
;
339 void m68k_switch_sp(CPUM68KState
*env
)
343 env
->sp
[env
->current_sp
] = env
->aregs
[7];
344 if (m68k_feature(env
, M68K_FEATURE_M68000
)) {
345 if (env
->sr
& SR_S
) {
346 if (env
->sr
& SR_M
) {
355 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
356 ? M68K_SSP
: M68K_USP
;
358 env
->aregs
[7] = env
->sp
[new_sp
];
359 env
->current_sp
= new_sp
;
362 #if defined(CONFIG_USER_ONLY)
364 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int size
, int rw
,
367 M68kCPU
*cpu
= M68K_CPU(cs
);
369 cs
->exception_index
= EXCP_ACCESS
;
370 cpu
->env
.mmu
.ar
= address
;
376 /* MMU: 68040 only */
378 static void print_address_zone(FILE *f
, fprintf_function cpu_fprintf
,
379 uint32_t logical
, uint32_t physical
,
380 uint32_t size
, int attr
)
382 cpu_fprintf(f
, "%08x - %08x -> %08x - %08x %c ",
383 logical
, logical
+ size
- 1,
384 physical
, physical
+ size
- 1,
385 attr
& 4 ? 'W' : '-');
388 cpu_fprintf(f
, "(%d KiB)\n", size
);
392 cpu_fprintf(f
, "(%d MiB)\n", size
);
395 cpu_fprintf(f
, "(%d GiB)\n", size
);
400 static void dump_address_map(FILE *f
, fprintf_function cpu_fprintf
,
401 CPUM68KState
*env
, uint32_t root_pointer
)
404 int tic_size
, tic_shift
;
406 uint32_t tia
, tib
, tic
;
407 uint32_t logical
= 0xffffffff, physical
= 0xffffffff;
408 uint32_t first_logical
= 0xffffffff, first_physical
= 0xffffffff;
409 uint32_t last_logical
, last_physical
;
411 int last_attr
= -1, attr
= -1;
412 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
413 CPUState
*cs
= CPU(cpu
);
415 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
419 tib_mask
= M68K_8K_PAGE_MASK
;
424 tib_mask
= M68K_4K_PAGE_MASK
;
426 for (i
= 0; i
< M68K_ROOT_POINTER_ENTRIES
; i
++) {
427 tia
= ldl_phys(cs
->as
, M68K_POINTER_BASE(root_pointer
) + i
* 4);
428 if (!M68K_UDT_VALID(tia
)) {
431 for (j
= 0; j
< M68K_ROOT_POINTER_ENTRIES
; j
++) {
432 tib
= ldl_phys(cs
->as
, M68K_POINTER_BASE(tia
) + j
* 4);
433 if (!M68K_UDT_VALID(tib
)) {
436 for (k
= 0; k
< tic_size
; k
++) {
437 tic
= ldl_phys(cs
->as
, (tib
& tib_mask
) + k
* 4);
438 if (!M68K_PDT_VALID(tic
)) {
441 if (M68K_PDT_INDIRECT(tic
)) {
442 tic
= ldl_phys(cs
->as
, M68K_INDIRECT_POINTER(tic
));
445 last_logical
= logical
;
446 logical
= (i
<< M68K_TTS_ROOT_SHIFT
) |
447 (j
<< M68K_TTS_POINTER_SHIFT
) |
450 last_physical
= physical
;
451 physical
= tic
& ~((1 << tic_shift
) - 1);
454 attr
= tic
& ((1 << tic_shift
) - 1);
456 if ((logical
!= (last_logical
+ (1 << tic_shift
))) ||
457 (physical
!= (last_physical
+ (1 << tic_shift
))) ||
458 (attr
& 4) != (last_attr
& 4)) {
460 if (first_logical
!= 0xffffffff) {
461 size
= last_logical
+ (1 << tic_shift
) -
463 print_address_zone(f
, cpu_fprintf
, first_logical
,
464 first_physical
, size
, last_attr
);
466 first_logical
= logical
;
467 first_physical
= physical
;
472 if (first_logical
!= logical
|| (attr
& 4) != (last_attr
& 4)) {
473 size
= logical
+ (1 << tic_shift
) - first_logical
;
474 print_address_zone(f
, cpu_fprintf
, first_logical
, first_physical
, size
,
479 #define DUMP_CACHEFLAGS(a) \
480 switch (a & M68K_DESC_CACHEMODE) { \
481 case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
482 cpu_fprintf(f, "T"); \
484 case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
485 cpu_fprintf(f, "C"); \
487 case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
488 cpu_fprintf(f, "S"); \
490 case M68K_DESC_CM_NCACHE: /* noncachable */ \
491 cpu_fprintf(f, "N"); \
495 static void dump_ttr(FILE *f
, fprintf_function cpu_fprintf
, uint32_t ttr
)
497 if ((ttr
& M68K_TTR_ENABLED
) == 0) {
498 cpu_fprintf(f
, "disabled\n");
501 cpu_fprintf(f
, "Base: 0x%08x Mask: 0x%08x Control: ",
502 ttr
& M68K_TTR_ADDR_BASE
,
503 (ttr
& M68K_TTR_ADDR_MASK
) << M68K_TTR_ADDR_MASK_SHIFT
);
504 switch (ttr
& M68K_TTR_SFIELD
) {
505 case M68K_TTR_SFIELD_USER
:
508 case M68K_TTR_SFIELD_SUPER
:
515 DUMP_CACHEFLAGS(ttr
);
516 if (ttr
& M68K_DESC_WRITEPROT
) {
521 cpu_fprintf(f
, " U: %d\n", (ttr
& M68K_DESC_USERATTR
) >>
522 M68K_DESC_USERATTR_SHIFT
);
525 void dump_mmu(FILE *f
, fprintf_function cpu_fprintf
, CPUM68KState
*env
)
527 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
528 cpu_fprintf(f
, "Translation disabled\n");
531 cpu_fprintf(f
, "Page Size: ");
532 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
533 cpu_fprintf(f
, "8kB\n");
535 cpu_fprintf(f
, "4kB\n");
538 cpu_fprintf(f
, "MMUSR: ");
539 if (env
->mmu
.mmusr
& M68K_MMU_B_040
) {
540 cpu_fprintf(f
, "BUS ERROR\n");
542 cpu_fprintf(f
, "Phy=%08x Flags: ", env
->mmu
.mmusr
& 0xfffff000);
543 /* flags found on the page descriptor */
544 if (env
->mmu
.mmusr
& M68K_MMU_G_040
) {
545 cpu_fprintf(f
, "G"); /* Global */
549 if (env
->mmu
.mmusr
& M68K_MMU_S_040
) {
550 cpu_fprintf(f
, "S"); /* Supervisor */
554 if (env
->mmu
.mmusr
& M68K_MMU_M_040
) {
555 cpu_fprintf(f
, "M"); /* Modified */
559 if (env
->mmu
.mmusr
& M68K_MMU_WP_040
) {
560 cpu_fprintf(f
, "W"); /* Write protect */
564 if (env
->mmu
.mmusr
& M68K_MMU_T_040
) {
565 cpu_fprintf(f
, "T"); /* Transparent */
569 if (env
->mmu
.mmusr
& M68K_MMU_R_040
) {
570 cpu_fprintf(f
, "R"); /* Resident */
574 cpu_fprintf(f
, " Cache: ");
575 DUMP_CACHEFLAGS(env
->mmu
.mmusr
);
576 cpu_fprintf(f
, " U: %d\n", (env
->mmu
.mmusr
>> 8) & 3);
577 cpu_fprintf(f
, "\n");
580 cpu_fprintf(f
, "ITTR0: ");
581 dump_ttr(f
, cpu_fprintf
, env
->mmu
.ttr
[M68K_ITTR0
]);
582 cpu_fprintf(f
, "ITTR1: ");
583 dump_ttr(f
, cpu_fprintf
, env
->mmu
.ttr
[M68K_ITTR1
]);
584 cpu_fprintf(f
, "DTTR0: ");
585 dump_ttr(f
, cpu_fprintf
, env
->mmu
.ttr
[M68K_DTTR0
]);
586 cpu_fprintf(f
, "DTTR1: ");
587 dump_ttr(f
, cpu_fprintf
, env
->mmu
.ttr
[M68K_DTTR1
]);
589 cpu_fprintf(f
, "SRP: 0x%08x\n", env
->mmu
.srp
);
590 dump_address_map(f
, cpu_fprintf
, env
, env
->mmu
.srp
);
592 cpu_fprintf(f
, "URP: 0x%08x\n", env
->mmu
.urp
);
593 dump_address_map(f
, cpu_fprintf
, env
, env
->mmu
.urp
);
596 static int check_TTR(uint32_t ttr
, int *prot
, target_ulong addr
,
601 /* check if transparent translation is enabled */
602 if ((ttr
& M68K_TTR_ENABLED
) == 0) {
606 /* check mode access */
607 switch (ttr
& M68K_TTR_SFIELD
) {
608 case M68K_TTR_SFIELD_USER
:
609 /* match only if user */
610 if ((access_type
& ACCESS_SUPER
) != 0) {
614 case M68K_TTR_SFIELD_SUPER
:
615 /* match only if supervisor */
616 if ((access_type
& ACCESS_SUPER
) == 0) {
621 /* all other values disable mode matching (FC2) */
625 /* check address matching */
627 base
= ttr
& M68K_TTR_ADDR_BASE
;
628 mask
= (ttr
& M68K_TTR_ADDR_MASK
) ^ M68K_TTR_ADDR_MASK
;
629 mask
<<= M68K_TTR_ADDR_MASK_SHIFT
;
631 if ((addr
& mask
) != (base
& mask
)) {
635 *prot
= PAGE_READ
| PAGE_EXEC
;
636 if ((ttr
& M68K_DESC_WRITEPROT
) == 0) {
643 static int get_physical_address(CPUM68KState
*env
, hwaddr
*physical
,
644 int *prot
, target_ulong address
,
645 int access_type
, target_ulong
*page_size
)
647 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
648 CPUState
*cs
= CPU(cpu
);
651 target_ulong page_mask
;
652 bool debug
= access_type
& ACCESS_DEBUG
;
656 /* Transparent Translation (physical = logical) */
657 for (i
= 0; i
< M68K_MAX_TTR
; i
++) {
658 if (check_TTR(env
->mmu
.TTR(access_type
, i
),
659 prot
, address
, access_type
)) {
660 if (access_type
& ACCESS_PTEST
) {
661 /* Transparent Translation Register bit */
662 env
->mmu
.mmusr
= M68K_MMU_T_040
| M68K_MMU_R_040
;
664 *physical
= address
& TARGET_PAGE_MASK
;
665 *page_size
= TARGET_PAGE_SIZE
;
670 /* Page Table Root Pointer */
671 *prot
= PAGE_READ
| PAGE_WRITE
;
672 if (access_type
& ACCESS_CODE
) {
675 if (access_type
& ACCESS_SUPER
) {
682 entry
= M68K_POINTER_BASE(next
) | M68K_ROOT_INDEX(address
);
684 next
= ldl_phys(cs
->as
, entry
);
685 if (!M68K_UDT_VALID(next
)) {
688 if (!(next
& M68K_DESC_USED
) && !debug
) {
689 stl_phys(cs
->as
, entry
, next
| M68K_DESC_USED
);
691 if (next
& M68K_DESC_WRITEPROT
) {
692 if (access_type
& ACCESS_PTEST
) {
693 env
->mmu
.mmusr
|= M68K_MMU_WP_040
;
695 *prot
&= ~PAGE_WRITE
;
696 if (access_type
& ACCESS_STORE
) {
702 entry
= M68K_POINTER_BASE(next
) | M68K_POINTER_INDEX(address
);
704 next
= ldl_phys(cs
->as
, entry
);
705 if (!M68K_UDT_VALID(next
)) {
708 if (!(next
& M68K_DESC_USED
) && !debug
) {
709 stl_phys(cs
->as
, entry
, next
| M68K_DESC_USED
);
711 if (next
& M68K_DESC_WRITEPROT
) {
712 if (access_type
& ACCESS_PTEST
) {
713 env
->mmu
.mmusr
|= M68K_MMU_WP_040
;
715 *prot
&= ~PAGE_WRITE
;
716 if (access_type
& ACCESS_STORE
) {
722 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
723 entry
= M68K_8K_PAGE_BASE(next
) | M68K_8K_PAGE_INDEX(address
);
725 entry
= M68K_4K_PAGE_BASE(next
) | M68K_4K_PAGE_INDEX(address
);
728 next
= ldl_phys(cs
->as
, entry
);
730 if (!M68K_PDT_VALID(next
)) {
733 if (M68K_PDT_INDIRECT(next
)) {
734 next
= ldl_phys(cs
->as
, M68K_INDIRECT_POINTER(next
));
736 if (access_type
& ACCESS_STORE
) {
737 if (next
& M68K_DESC_WRITEPROT
) {
738 if (!(next
& M68K_DESC_USED
) && !debug
) {
739 stl_phys(cs
->as
, entry
, next
| M68K_DESC_USED
);
741 } else if ((next
& (M68K_DESC_MODIFIED
| M68K_DESC_USED
)) !=
742 (M68K_DESC_MODIFIED
| M68K_DESC_USED
) && !debug
) {
743 stl_phys(cs
->as
, entry
,
744 next
| (M68K_DESC_MODIFIED
| M68K_DESC_USED
));
747 if (!(next
& M68K_DESC_USED
) && !debug
) {
748 stl_phys(cs
->as
, entry
, next
| M68K_DESC_USED
);
752 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
757 *page_size
= 1 << page_bits
;
758 page_mask
= ~(*page_size
- 1);
759 *physical
= next
& page_mask
;
761 if (access_type
& ACCESS_PTEST
) {
762 env
->mmu
.mmusr
|= next
& M68K_MMU_SR_MASK_040
;
763 env
->mmu
.mmusr
|= *physical
& 0xfffff000;
764 env
->mmu
.mmusr
|= M68K_MMU_R_040
;
767 if (next
& M68K_DESC_WRITEPROT
) {
768 *prot
&= ~PAGE_WRITE
;
769 if (access_type
& ACCESS_STORE
) {
773 if (next
& M68K_DESC_SUPERONLY
) {
774 if ((access_type
& ACCESS_SUPER
) == 0) {
782 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
784 M68kCPU
*cpu
= M68K_CPU(cs
);
785 CPUM68KState
*env
= &cpu
->env
;
789 target_ulong page_size
;
791 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
796 access_type
= ACCESS_DATA
| ACCESS_DEBUG
;
797 if (env
->sr
& SR_S
) {
798 access_type
|= ACCESS_SUPER
;
800 if (get_physical_address(env
, &phys_addr
, &prot
,
801 addr
, access_type
, &page_size
) != 0) {
807 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int size
, int rw
,
810 M68kCPU
*cpu
= M68K_CPU(cs
);
811 CPUM68KState
*env
= &cpu
->env
;
816 target_ulong page_size
;
818 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
820 tlb_set_page(cs
, address
& TARGET_PAGE_MASK
,
821 address
& TARGET_PAGE_MASK
,
822 PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
,
823 mmu_idx
, TARGET_PAGE_SIZE
);
828 access_type
= ACCESS_CODE
;
831 access_type
= ACCESS_DATA
;
833 access_type
|= ACCESS_STORE
;
837 if (mmu_idx
!= MMU_USER_IDX
) {
838 access_type
|= ACCESS_SUPER
;
841 ret
= get_physical_address(&cpu
->env
, &physical
, &prot
,
842 address
, access_type
, &page_size
);
844 address
&= TARGET_PAGE_MASK
;
845 physical
+= address
& (page_size
- 1);
846 tlb_set_page(cs
, address
, physical
,
847 prot
, mmu_idx
, TARGET_PAGE_SIZE
);
851 env
->mmu
.ssw
= M68K_ATC_040
;
854 env
->mmu
.ssw
|= M68K_BA_SIZE_BYTE
;
857 env
->mmu
.ssw
|= M68K_BA_SIZE_WORD
;
860 env
->mmu
.ssw
|= M68K_BA_SIZE_LONG
;
863 if (access_type
& ACCESS_SUPER
) {
864 env
->mmu
.ssw
|= M68K_TM_040_SUPER
;
866 if (access_type
& ACCESS_CODE
) {
867 env
->mmu
.ssw
|= M68K_TM_040_CODE
;
869 env
->mmu
.ssw
|= M68K_TM_040_DATA
;
871 if (!(access_type
& ACCESS_STORE
)) {
872 env
->mmu
.ssw
|= M68K_RW_040
;
874 env
->mmu
.ar
= address
;
875 cs
->exception_index
= EXCP_ACCESS
;
879 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
880 be handled by the interrupt controller. Real hardware only requests
881 the vector when the interrupt is acknowledged by the CPU. For
882 simplicitly we calculate it when the interrupt is signalled. */
883 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
885 CPUState
*cs
= CPU(cpu
);
886 CPUM68KState
*env
= &cpu
->env
;
888 env
->pending_level
= level
;
889 env
->pending_vector
= vector
;
891 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
893 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
899 uint32_t HELPER(bitrev
)(uint32_t x
)
901 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
902 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
903 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
907 uint32_t HELPER(ff1
)(uint32_t x
)
915 uint32_t HELPER(sats
)(uint32_t val
, uint32_t v
)
917 /* The result has the opposite sign to the original value. */
918 if ((int32_t)v
< 0) {
919 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
924 void cpu_m68k_set_sr(CPUM68KState
*env
, uint32_t sr
)
926 env
->sr
= sr
& 0xffe0;
927 cpu_m68k_set_ccr(env
, sr
);
931 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
933 cpu_m68k_set_sr(env
, val
);
937 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
938 take values, others take register numbers and manipulate the contents
940 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
943 env
->macc
[dest
] = env
->macc
[src
];
944 mask
= MACSR_PAV0
<< dest
;
945 if (env
->macsr
& (MACSR_PAV0
<< src
))
951 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
956 product
= (uint64_t)op1
* op2
;
957 res
= (product
<< 24) >> 24;
958 if (res
!= product
) {
959 env
->macsr
|= MACSR_V
;
960 if (env
->macsr
& MACSR_OMC
) {
961 /* Make sure the accumulate operation overflows. */
971 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
975 product
= (uint64_t)op1
* op2
;
976 if (product
& (0xffffffull
<< 40)) {
977 env
->macsr
|= MACSR_V
;
978 if (env
->macsr
& MACSR_OMC
) {
979 /* Make sure the accumulate operation overflows. */
982 product
&= ((1ull << 40) - 1);
988 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
993 product
= (uint64_t)op1
* op2
;
994 if (env
->macsr
& MACSR_RT
) {
995 remainder
= product
& 0xffffff;
997 if (remainder
> 0x800000)
999 else if (remainder
== 0x800000)
1000 product
+= (product
& 1);
1007 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
1011 tmp
= env
->macc
[acc
];
1012 result
= ((tmp
<< 16) >> 16);
1013 if (result
!= tmp
) {
1014 env
->macsr
|= MACSR_V
;
1016 if (env
->macsr
& MACSR_V
) {
1017 env
->macsr
|= MACSR_PAV0
<< acc
;
1018 if (env
->macsr
& MACSR_OMC
) {
1019 /* The result is saturated to 32 bits, despite overflow occurring
1020 at 48 bits. Seems weird, but that's what the hardware docs
1022 result
= (result
>> 63) ^ 0x7fffffff;
1025 env
->macc
[acc
] = result
;
1028 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
1032 val
= env
->macc
[acc
];
1033 if (val
& (0xffffull
<< 48)) {
1034 env
->macsr
|= MACSR_V
;
1036 if (env
->macsr
& MACSR_V
) {
1037 env
->macsr
|= MACSR_PAV0
<< acc
;
1038 if (env
->macsr
& MACSR_OMC
) {
1039 if (val
> (1ull << 53))
1042 val
= (1ull << 48) - 1;
1044 val
&= ((1ull << 48) - 1);
1047 env
->macc
[acc
] = val
;
1050 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
1055 sum
= env
->macc
[acc
];
1056 result
= (sum
<< 16) >> 16;
1057 if (result
!= sum
) {
1058 env
->macsr
|= MACSR_V
;
1060 if (env
->macsr
& MACSR_V
) {
1061 env
->macsr
|= MACSR_PAV0
<< acc
;
1062 if (env
->macsr
& MACSR_OMC
) {
1063 result
= (result
>> 63) ^ 0x7fffffffffffll
;
1066 env
->macc
[acc
] = result
;
1069 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
1072 val
= env
->macc
[acc
];
1074 env
->macsr
|= MACSR_Z
;
1075 } else if (val
& (1ull << 47)) {
1076 env
->macsr
|= MACSR_N
;
1078 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
1079 env
->macsr
|= MACSR_V
;
1081 if (env
->macsr
& MACSR_FI
) {
1082 val
= ((int64_t)val
) >> 40;
1083 if (val
!= 0 && val
!= -1)
1084 env
->macsr
|= MACSR_EV
;
1085 } else if (env
->macsr
& MACSR_SU
) {
1086 val
= ((int64_t)val
) >> 32;
1087 if (val
!= 0 && val
!= -1)
1088 env
->macsr
|= MACSR_EV
;
1090 if ((val
>> 32) != 0)
1091 env
->macsr
|= MACSR_EV
;
1095 #define EXTSIGN(val, index) ( \
1096 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1099 #define COMPUTE_CCR(op, x, n, z, v, c) { \
1102 /* Everything in place. */ \
1109 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
1112 v = (res ^ src1) & ~(src1 ^ src2); \
1119 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
1122 v = (res ^ src1) & (src1 ^ src2); \
1129 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
1133 v = (res ^ src1) & (src1 ^ src2); \
1140 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
1144 uint32_t cpu_m68k_get_ccr(CPUM68KState
*env
)
1146 uint32_t x
, c
, n
, z
, v
;
1147 uint32_t res
, src1
, src2
;
1155 COMPUTE_CCR(env
->cc_op
, x
, n
, z
, v
, c
);
1161 return x
* CCF_X
+ n
* CCF_N
+ z
* CCF_Z
+ v
* CCF_V
+ c
* CCF_C
;
1164 uint32_t HELPER(get_ccr
)(CPUM68KState
*env
)
1166 return cpu_m68k_get_ccr(env
);
1169 void cpu_m68k_set_ccr(CPUM68KState
*env
, uint32_t ccr
)
1171 env
->cc_x
= (ccr
& CCF_X
? 1 : 0);
1172 env
->cc_n
= (ccr
& CCF_N
? -1 : 0);
1173 env
->cc_z
= (ccr
& CCF_Z
? 0 : 1);
1174 env
->cc_v
= (ccr
& CCF_V
? -1 : 0);
1175 env
->cc_c
= (ccr
& CCF_C
? 1 : 0);
1176 env
->cc_op
= CC_OP_FLAGS
;
1179 void HELPER(set_ccr
)(CPUM68KState
*env
, uint32_t ccr
)
1181 cpu_m68k_set_ccr(env
, ccr
);
1184 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
1186 uint32_t res
, src1
, src2
;
1188 COMPUTE_CCR(cc_op
, env
->cc_x
, env
->cc_n
, env
->cc_z
, env
->cc_v
, env
->cc_c
);
1189 env
->cc_op
= CC_OP_FLAGS
;
1192 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
1197 if (env
->macsr
& MACSR_SU
) {
1198 /* 16-bit rounding. */
1199 rem
= val
& 0xffffff;
1200 val
= (val
>> 24) & 0xffffu
;
1203 else if (rem
== 0x800000)
1205 } else if (env
->macsr
& MACSR_RT
) {
1206 /* 32-bit rounding. */
1211 else if (rem
== 0x80)
1217 if (env
->macsr
& MACSR_OMC
) {
1219 if (env
->macsr
& MACSR_SU
) {
1220 if (val
!= (uint16_t) val
) {
1221 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
1223 result
= val
& 0xffff;
1226 if (val
!= (uint32_t)val
) {
1227 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
1229 result
= (uint32_t)val
;
1233 /* No saturation. */
1234 if (env
->macsr
& MACSR_SU
) {
1235 result
= val
& 0xffff;
1237 result
= (uint32_t)val
;
1243 uint32_t HELPER(get_macs
)(uint64_t val
)
1245 if (val
== (int32_t)val
) {
1246 return (int32_t)val
;
1248 return (val
>> 61) ^ ~SIGNBIT
;
1252 uint32_t HELPER(get_macu
)(uint64_t val
)
1254 if ((val
>> 32) == 0) {
1255 return (uint32_t)val
;
1261 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
1264 val
= env
->macc
[acc
] & 0x00ff;
1265 val
|= (env
->macc
[acc
] >> 32) & 0xff00;
1266 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
1267 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
1271 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
1274 val
= (env
->macc
[acc
] >> 32) & 0xffff;
1275 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
1279 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1283 res
= env
->macc
[acc
] & 0xffffffff00ull
;
1284 tmp
= (int16_t)(val
& 0xff00);
1285 res
|= ((int64_t)tmp
) << 32;
1287 env
->macc
[acc
] = res
;
1288 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
1289 tmp
= (val
& 0xff000000);
1290 res
|= ((int64_t)tmp
) << 16;
1291 res
|= (val
>> 16) & 0xff;
1292 env
->macc
[acc
+ 1] = res
;
1295 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1299 res
= (uint32_t)env
->macc
[acc
];
1301 res
|= ((int64_t)tmp
) << 32;
1302 env
->macc
[acc
] = res
;
1303 res
= (uint32_t)env
->macc
[acc
+ 1];
1304 tmp
= val
& 0xffff0000;
1305 res
|= (int64_t)tmp
<< 16;
1306 env
->macc
[acc
+ 1] = res
;
1309 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1312 res
= (uint32_t)env
->macc
[acc
];
1313 res
|= ((uint64_t)(val
& 0xffff)) << 32;
1314 env
->macc
[acc
] = res
;
1315 res
= (uint32_t)env
->macc
[acc
+ 1];
1316 res
|= (uint64_t)(val
& 0xffff0000) << 16;
1317 env
->macc
[acc
+ 1] = res
;
1320 #if defined(CONFIG_SOFTMMU)
1321 void HELPER(ptest
)(CPUM68KState
*env
, uint32_t addr
, uint32_t is_read
)
1323 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
1324 CPUState
*cs
= CPU(cpu
);
1329 target_ulong page_size
;
1331 access_type
= ACCESS_PTEST
;
1333 access_type
|= ACCESS_SUPER
;
1335 if ((env
->dfc
& 3) == 2) {
1336 access_type
|= ACCESS_CODE
;
1339 access_type
|= ACCESS_STORE
;
1344 ret
= get_physical_address(env
, &physical
, &prot
, addr
,
1345 access_type
, &page_size
);
1347 addr
&= TARGET_PAGE_MASK
;
1348 physical
+= addr
& (page_size
- 1);
1349 tlb_set_page(cs
, addr
, physical
,
1350 prot
, access_type
& ACCESS_SUPER
?
1351 MMU_KERNEL_IDX
: MMU_USER_IDX
, page_size
);
1355 void HELPER(pflush
)(CPUM68KState
*env
, uint32_t addr
, uint32_t opmode
)
1357 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
1360 case 0: /* Flush page entry if not global */
1361 case 1: /* Flush page entry */
1362 tlb_flush_page(CPU(cpu
), addr
);
1364 case 2: /* Flush all except global entries */
1365 tlb_flush(CPU(cpu
));
1367 case 3: /* Flush all entries */
1368 tlb_flush(CPU(cpu
));
1373 void HELPER(reset
)(CPUM68KState
*env
)
1375 /* FIXME: reset all except CPU */