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/page-protection.h"
25 #include "exec/gdbstub.h"
26 #include "exec/helper-proto.h"
27 #include "gdbstub/helpers.h"
28 #include "fpu/softfloat.h"
29 #include "qemu/qemu-print.h"
31 #define SIGNBIT (1u << 31)
33 static int cf_fpu_gdb_get_reg(CPUState
*cs
, GByteArray
*mem_buf
, int n
)
35 M68kCPU
*cpu
= M68K_CPU(cs
);
36 CPUM68KState
*env
= &cpu
->env
;
40 return gdb_get_reg64(mem_buf
, floatx80_to_float64(env
->fregs
[n
].d
, &s
));
43 case 8: /* fpcontrol */
44 return gdb_get_reg32(mem_buf
, env
->fpcr
);
45 case 9: /* fpstatus */
46 return gdb_get_reg32(mem_buf
, env
->fpsr
);
47 case 10: /* fpiar, not implemented */
48 return gdb_get_reg32(mem_buf
, 0);
53 static int cf_fpu_gdb_set_reg(CPUState
*cs
, uint8_t *mem_buf
, int n
)
55 M68kCPU
*cpu
= M68K_CPU(cs
);
56 CPUM68KState
*env
= &cpu
->env
;
60 env
->fregs
[n
].d
= float64_to_floatx80(ldq_be_p(mem_buf
), &s
);
64 case 8: /* fpcontrol */
65 cpu_m68k_set_fpcr(env
, ldl_be_p(mem_buf
));
67 case 9: /* fpstatus */
68 env
->fpsr
= ldl_be_p(mem_buf
);
70 case 10: /* fpiar, not implemented */
76 static int m68k_fpu_gdb_get_reg(CPUState
*cs
, GByteArray
*mem_buf
, int n
)
78 M68kCPU
*cpu
= M68K_CPU(cs
);
79 CPUM68KState
*env
= &cpu
->env
;
82 int len
= gdb_get_reg16(mem_buf
, env
->fregs
[n
].l
.upper
);
83 len
+= gdb_get_reg16(mem_buf
, 0);
84 len
+= gdb_get_reg64(mem_buf
, env
->fregs
[n
].l
.lower
);
88 case 8: /* fpcontrol */
89 return gdb_get_reg32(mem_buf
, env
->fpcr
);
90 case 9: /* fpstatus */
91 return gdb_get_reg32(mem_buf
, cpu_m68k_get_fpsr(env
));
92 case 10: /* fpiar, not implemented */
93 return gdb_get_reg32(mem_buf
, 0);
98 static int m68k_fpu_gdb_set_reg(CPUState
*cs
, uint8_t *mem_buf
, int n
)
100 M68kCPU
*cpu
= M68K_CPU(cs
);
101 CPUM68KState
*env
= &cpu
->env
;
104 env
->fregs
[n
].l
.upper
= lduw_be_p(mem_buf
);
105 env
->fregs
[n
].l
.lower
= ldq_be_p(mem_buf
+ 4);
109 case 8: /* fpcontrol */
110 cpu_m68k_set_fpcr(env
, ldl_be_p(mem_buf
));
112 case 9: /* fpstatus */
113 cpu_m68k_set_fpsr(env
, ldl_be_p(mem_buf
));
115 case 10: /* fpiar, not implemented */
121 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
123 CPUState
*cs
= CPU(cpu
);
124 CPUM68KState
*env
= &cpu
->env
;
126 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
127 gdb_register_coprocessor(cs
, cf_fpu_gdb_get_reg
, cf_fpu_gdb_set_reg
,
128 gdb_find_static_feature("cf-fp.xml"), 18);
129 } else if (m68k_feature(env
, M68K_FEATURE_FPU
)) {
130 gdb_register_coprocessor(cs
, m68k_fpu_gdb_get_reg
, m68k_fpu_gdb_set_reg
,
131 gdb_find_static_feature("m68k-fp.xml"), 18);
133 /* TODO: Add [E]MAC registers. */
136 void HELPER(cf_movec_to
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
147 /* TODO: Implement Access Control Registers. */
152 /* TODO: Implement control registers. */
154 cpu_abort(env_cpu(env
),
155 "Unimplemented control register write 0x%x = 0x%x\n",
160 static void raise_exception_ra(CPUM68KState
*env
, int tt
, uintptr_t raddr
)
162 CPUState
*cs
= env_cpu(env
);
164 cs
->exception_index
= tt
;
165 cpu_loop_exit_restore(cs
, raddr
);
168 void HELPER(m68k_movec_to
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
185 if (m68k_feature(env
, M68K_FEATURE_M68020
)) {
186 env
->cacr
= val
& 0x0000000f;
187 } else if (m68k_feature(env
, M68K_FEATURE_M68030
)) {
188 env
->cacr
= val
& 0x00003f1f;
189 } else if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
190 env
->cacr
= val
& 0x80008000;
191 } else if (m68k_feature(env
, M68K_FEATURE_M68060
)) {
192 env
->cacr
= val
& 0xf8e0e000;
200 if (m68k_feature(env
, M68K_FEATURE_M68040
)
201 || m68k_feature(env
, M68K_FEATURE_M68060
)) {
208 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
209 env
->mmu
.mmusr
= val
;
215 if (m68k_feature(env
, M68K_FEATURE_M68040
)
216 || m68k_feature(env
, M68K_FEATURE_M68060
)) {
223 if (m68k_feature(env
, M68K_FEATURE_M68040
)
224 || m68k_feature(env
, M68K_FEATURE_M68060
)) {
231 env
->sp
[M68K_USP
] = val
;
235 if (m68k_feature(env
, M68K_FEATURE_M68020
)
236 || m68k_feature(env
, M68K_FEATURE_M68030
)
237 || m68k_feature(env
, M68K_FEATURE_M68040
)) {
238 env
->sp
[M68K_SSP
] = val
;
244 if (m68k_feature(env
, M68K_FEATURE_M68020
)
245 || m68k_feature(env
, M68K_FEATURE_M68030
)
246 || m68k_feature(env
, M68K_FEATURE_M68040
)) {
247 env
->sp
[M68K_ISP
] = val
;
251 /* MC68040/MC68LC040 */
252 case M68K_CR_ITT0
: /* MC68EC040 only: M68K_CR_IACR0 */
253 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
254 env
->mmu
.ttr
[M68K_ITTR0
] = val
;
258 /* MC68040/MC68LC040 */
259 case M68K_CR_ITT1
: /* MC68EC040 only: M68K_CR_IACR1 */
260 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
261 env
->mmu
.ttr
[M68K_ITTR1
] = val
;
265 /* MC68040/MC68LC040 */
266 case M68K_CR_DTT0
: /* MC68EC040 only: M68K_CR_DACR0 */
267 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
268 env
->mmu
.ttr
[M68K_DTTR0
] = val
;
272 /* MC68040/MC68LC040 */
273 case M68K_CR_DTT1
: /* MC68EC040 only: M68K_CR_DACR1 */
274 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
275 env
->mmu
.ttr
[M68K_DTTR1
] = val
;
279 /* Unimplemented Registers */
283 cpu_abort(env_cpu(env
),
284 "Unimplemented control register write 0x%x = 0x%x\n",
288 /* Invalid control registers will generate an exception. */
289 raise_exception_ra(env
, EXCP_ILLEGAL
, 0);
293 uint32_t HELPER(m68k_movec_from
)(CPUM68KState
*env
, uint32_t reg
)
307 if (m68k_feature(env
, M68K_FEATURE_M68020
)
308 || m68k_feature(env
, M68K_FEATURE_M68030
)
309 || m68k_feature(env
, M68K_FEATURE_M68040
)
310 || m68k_feature(env
, M68K_FEATURE_M68060
)) {
316 if (m68k_feature(env
, M68K_FEATURE_M68040
)
317 || m68k_feature(env
, M68K_FEATURE_M68060
)) {
323 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
324 return env
->mmu
.mmusr
;
329 if (m68k_feature(env
, M68K_FEATURE_M68040
)
330 || m68k_feature(env
, M68K_FEATURE_M68060
)) {
334 /* MC68040/MC68LC040 */
336 if (m68k_feature(env
, M68K_FEATURE_M68040
)
337 || m68k_feature(env
, M68K_FEATURE_M68060
)) {
343 return env
->sp
[M68K_USP
];
346 if (m68k_feature(env
, M68K_FEATURE_M68020
)
347 || m68k_feature(env
, M68K_FEATURE_M68030
)
348 || m68k_feature(env
, M68K_FEATURE_M68040
)) {
349 return env
->sp
[M68K_SSP
];
354 if (m68k_feature(env
, M68K_FEATURE_M68020
)
355 || m68k_feature(env
, M68K_FEATURE_M68030
)
356 || m68k_feature(env
, M68K_FEATURE_M68040
)) {
357 return env
->sp
[M68K_ISP
];
360 /* MC68040/MC68LC040 */
361 case M68K_CR_ITT0
: /* MC68EC040 only: M68K_CR_IACR0 */
362 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
363 return env
->mmu
.ttr
[M68K_ITTR0
];
366 /* MC68040/MC68LC040 */
367 case M68K_CR_ITT1
: /* MC68EC040 only: M68K_CR_IACR1 */
368 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
369 return env
->mmu
.ttr
[M68K_ITTR1
];
372 /* MC68040/MC68LC040 */
373 case M68K_CR_DTT0
: /* MC68EC040 only: M68K_CR_DACR0 */
374 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
375 return env
->mmu
.ttr
[M68K_DTTR0
];
378 /* MC68040/MC68LC040 */
379 case M68K_CR_DTT1
: /* MC68EC040 only: M68K_CR_DACR1 */
380 if (m68k_feature(env
, M68K_FEATURE_M68040
)) {
381 return env
->mmu
.ttr
[M68K_DTTR1
];
384 /* Unimplemented Registers */
388 cpu_abort(env_cpu(env
), "Unimplemented control register read 0x%x\n",
392 /* Invalid control registers will generate an exception. */
393 raise_exception_ra(env
, EXCP_ILLEGAL
, 0);
398 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
405 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
406 for (i
= 0; i
< 4; i
++) {
407 regval
= env
->macc
[i
];
408 exthigh
= regval
>> 40;
409 if (env
->macsr
& MACSR_FI
) {
414 extlow
= regval
>> 32;
416 if (env
->macsr
& MACSR_FI
) {
417 regval
= (((uint64_t)acc
) << 8) | extlow
;
418 regval
|= ((int64_t)exthigh
) << 40;
419 } else if (env
->macsr
& MACSR_SU
) {
420 regval
= acc
| (((int64_t)extlow
) << 32);
421 regval
|= ((int64_t)exthigh
) << 40;
423 regval
= acc
| (((uint64_t)extlow
) << 32);
424 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
426 env
->macc
[i
] = regval
;
432 void m68k_switch_sp(CPUM68KState
*env
)
436 env
->sp
[env
->current_sp
] = env
->aregs
[7];
437 if (m68k_feature(env
, M68K_FEATURE_M68K
)) {
438 if (env
->sr
& SR_S
) {
439 /* SR:Master-Mode bit unimplemented then ISP is not available */
440 if (!m68k_feature(env
, M68K_FEATURE_MSP
) || env
->sr
& SR_M
) {
449 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
450 ? M68K_SSP
: M68K_USP
;
452 env
->aregs
[7] = env
->sp
[new_sp
];
453 env
->current_sp
= new_sp
;
456 #if !defined(CONFIG_USER_ONLY)
457 /* MMU: 68040 only */
459 static void print_address_zone(uint32_t logical
, uint32_t physical
,
460 uint32_t size
, int attr
)
462 qemu_printf("%08x - %08x -> %08x - %08x %c ",
463 logical
, logical
+ size
- 1,
464 physical
, physical
+ size
- 1,
465 attr
& 4 ? 'W' : '-');
468 qemu_printf("(%d KiB)\n", size
);
472 qemu_printf("(%d MiB)\n", size
);
475 qemu_printf("(%d GiB)\n", size
);
480 static void dump_address_map(CPUM68KState
*env
, uint32_t root_pointer
)
482 int tic_size
, tic_shift
;
484 uint32_t tia
, tib
, tic
;
485 uint32_t logical
= 0xffffffff, physical
= 0xffffffff;
486 uint32_t first_logical
= 0xffffffff, first_physical
= 0xffffffff;
487 uint32_t last_logical
, last_physical
;
489 int last_attr
= -1, attr
= -1;
490 CPUState
*cs
= env_cpu(env
);
493 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
497 tib_mask
= M68K_8K_PAGE_MASK
;
502 tib_mask
= M68K_4K_PAGE_MASK
;
504 for (unsigned i
= 0; i
< M68K_ROOT_POINTER_ENTRIES
; i
++) {
505 tia
= address_space_ldl(cs
->as
, M68K_POINTER_BASE(root_pointer
) + i
* 4,
506 MEMTXATTRS_UNSPECIFIED
, &txres
);
507 if (txres
!= MEMTX_OK
|| !M68K_UDT_VALID(tia
)) {
510 for (unsigned j
= 0; j
< M68K_ROOT_POINTER_ENTRIES
; j
++) {
511 tib
= address_space_ldl(cs
->as
, M68K_POINTER_BASE(tia
) + j
* 4,
512 MEMTXATTRS_UNSPECIFIED
, &txres
);
513 if (txres
!= MEMTX_OK
|| !M68K_UDT_VALID(tib
)) {
516 for (unsigned k
= 0; k
< tic_size
; k
++) {
517 tic
= address_space_ldl(cs
->as
, (tib
& tib_mask
) + k
* 4,
518 MEMTXATTRS_UNSPECIFIED
, &txres
);
519 if (txres
!= MEMTX_OK
|| !M68K_PDT_VALID(tic
)) {
522 if (M68K_PDT_INDIRECT(tic
)) {
523 tic
= address_space_ldl(cs
->as
, M68K_INDIRECT_POINTER(tic
),
524 MEMTXATTRS_UNSPECIFIED
, &txres
);
525 if (txres
!= MEMTX_OK
) {
530 last_logical
= logical
;
531 logical
= (i
<< M68K_TTS_ROOT_SHIFT
) |
532 (j
<< M68K_TTS_POINTER_SHIFT
) |
535 last_physical
= physical
;
536 physical
= tic
& ~((1 << tic_shift
) - 1);
539 attr
= tic
& ((1 << tic_shift
) - 1);
541 if ((logical
!= (last_logical
+ (1 << tic_shift
))) ||
542 (physical
!= (last_physical
+ (1 << tic_shift
))) ||
543 (attr
& 4) != (last_attr
& 4)) {
545 if (first_logical
!= 0xffffffff) {
546 size
= last_logical
+ (1 << tic_shift
) -
548 print_address_zone(first_logical
,
549 first_physical
, size
, last_attr
);
551 first_logical
= logical
;
552 first_physical
= physical
;
557 if (first_logical
!= logical
|| (attr
& 4) != (last_attr
& 4)) {
558 size
= logical
+ (1 << tic_shift
) - first_logical
;
559 print_address_zone(first_logical
, first_physical
, size
, last_attr
);
563 #define DUMP_CACHEFLAGS(a) \
564 switch (a & M68K_DESC_CACHEMODE) { \
565 case M68K_DESC_CM_WRTHRU: /* cacheable, write-through */ \
568 case M68K_DESC_CM_COPYBK: /* cacheable, copyback */ \
571 case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
574 case M68K_DESC_CM_NCACHE: /* noncachable */ \
579 static void dump_ttr(uint32_t ttr
)
581 if ((ttr
& M68K_TTR_ENABLED
) == 0) {
582 qemu_printf("disabled\n");
585 qemu_printf("Base: 0x%08x Mask: 0x%08x Control: ",
586 ttr
& M68K_TTR_ADDR_BASE
,
587 (ttr
& M68K_TTR_ADDR_MASK
) << M68K_TTR_ADDR_MASK_SHIFT
);
588 switch (ttr
& M68K_TTR_SFIELD
) {
589 case M68K_TTR_SFIELD_USER
:
592 case M68K_TTR_SFIELD_SUPER
:
599 DUMP_CACHEFLAGS(ttr
);
600 if (ttr
& M68K_DESC_WRITEPROT
) {
605 qemu_printf(" U: %d\n", (ttr
& M68K_DESC_USERATTR
) >>
606 M68K_DESC_USERATTR_SHIFT
);
609 void dump_mmu(CPUM68KState
*env
)
611 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
612 qemu_printf("Translation disabled\n");
615 qemu_printf("Page Size: ");
616 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
617 qemu_printf("8kB\n");
619 qemu_printf("4kB\n");
622 qemu_printf("MMUSR: ");
623 if (env
->mmu
.mmusr
& M68K_MMU_B_040
) {
624 qemu_printf("BUS ERROR\n");
626 qemu_printf("Phy=%08x Flags: ", env
->mmu
.mmusr
& 0xfffff000);
627 /* flags found on the page descriptor */
628 if (env
->mmu
.mmusr
& M68K_MMU_G_040
) {
629 qemu_printf("G"); /* Global */
633 if (env
->mmu
.mmusr
& M68K_MMU_S_040
) {
634 qemu_printf("S"); /* Supervisor */
638 if (env
->mmu
.mmusr
& M68K_MMU_M_040
) {
639 qemu_printf("M"); /* Modified */
643 if (env
->mmu
.mmusr
& M68K_MMU_WP_040
) {
644 qemu_printf("W"); /* Write protect */
648 if (env
->mmu
.mmusr
& M68K_MMU_T_040
) {
649 qemu_printf("T"); /* Transparent */
653 if (env
->mmu
.mmusr
& M68K_MMU_R_040
) {
654 qemu_printf("R"); /* Resident */
658 qemu_printf(" Cache: ");
659 DUMP_CACHEFLAGS(env
->mmu
.mmusr
);
660 qemu_printf(" U: %d\n", (env
->mmu
.mmusr
>> 8) & 3);
664 qemu_printf("ITTR0: ");
665 dump_ttr(env
->mmu
.ttr
[M68K_ITTR0
]);
666 qemu_printf("ITTR1: ");
667 dump_ttr(env
->mmu
.ttr
[M68K_ITTR1
]);
668 qemu_printf("DTTR0: ");
669 dump_ttr(env
->mmu
.ttr
[M68K_DTTR0
]);
670 qemu_printf("DTTR1: ");
671 dump_ttr(env
->mmu
.ttr
[M68K_DTTR1
]);
673 qemu_printf("SRP: 0x%08x\n", env
->mmu
.srp
);
674 dump_address_map(env
, env
->mmu
.srp
);
676 qemu_printf("URP: 0x%08x\n", env
->mmu
.urp
);
677 dump_address_map(env
, env
->mmu
.urp
);
680 static int check_TTR(uint32_t ttr
, int *prot
, target_ulong addr
,
685 /* check if transparent translation is enabled */
686 if ((ttr
& M68K_TTR_ENABLED
) == 0) {
690 /* check mode access */
691 switch (ttr
& M68K_TTR_SFIELD
) {
692 case M68K_TTR_SFIELD_USER
:
693 /* match only if user */
694 if ((access_type
& ACCESS_SUPER
) != 0) {
698 case M68K_TTR_SFIELD_SUPER
:
699 /* match only if supervisor */
700 if ((access_type
& ACCESS_SUPER
) == 0) {
705 /* all other values disable mode matching (FC2) */
709 /* check address matching */
711 base
= ttr
& M68K_TTR_ADDR_BASE
;
712 mask
= (ttr
& M68K_TTR_ADDR_MASK
) ^ M68K_TTR_ADDR_MASK
;
713 mask
<<= M68K_TTR_ADDR_MASK_SHIFT
;
715 if ((addr
& mask
) != (base
& mask
)) {
719 *prot
= PAGE_READ
| PAGE_EXEC
;
720 if ((ttr
& M68K_DESC_WRITEPROT
) == 0) {
727 static int get_physical_address(CPUM68KState
*env
, hwaddr
*physical
,
728 int *prot
, target_ulong address
,
729 int access_type
, target_ulong
*page_size
)
731 CPUState
*cs
= env_cpu(env
);
734 target_ulong page_mask
;
735 bool debug
= access_type
& ACCESS_DEBUG
;
740 /* Transparent Translation (physical = logical) */
741 for (i
= 0; i
< M68K_MAX_TTR
; i
++) {
742 if (check_TTR(env
->mmu
.TTR(access_type
, i
),
743 prot
, address
, access_type
)) {
744 if (access_type
& ACCESS_PTEST
) {
745 /* Transparent Translation Register bit */
746 env
->mmu
.mmusr
= M68K_MMU_T_040
| M68K_MMU_R_040
;
749 *page_size
= TARGET_PAGE_SIZE
;
754 /* Page Table Root Pointer */
755 *prot
= PAGE_READ
| PAGE_WRITE
;
756 if (access_type
& ACCESS_CODE
) {
759 if (access_type
& ACCESS_SUPER
) {
766 entry
= M68K_POINTER_BASE(next
) | M68K_ROOT_INDEX(address
);
768 next
= address_space_ldl(cs
->as
, entry
, MEMTXATTRS_UNSPECIFIED
, &txres
);
769 if (txres
!= MEMTX_OK
) {
772 if (!M68K_UDT_VALID(next
)) {
775 if (!(next
& M68K_DESC_USED
) && !debug
) {
776 address_space_stl(cs
->as
, entry
, next
| M68K_DESC_USED
,
777 MEMTXATTRS_UNSPECIFIED
, &txres
);
778 if (txres
!= MEMTX_OK
) {
782 if (next
& M68K_DESC_WRITEPROT
) {
783 if (access_type
& ACCESS_PTEST
) {
784 env
->mmu
.mmusr
|= M68K_MMU_WP_040
;
786 *prot
&= ~PAGE_WRITE
;
787 if (access_type
& ACCESS_STORE
) {
793 entry
= M68K_POINTER_BASE(next
) | M68K_POINTER_INDEX(address
);
795 next
= address_space_ldl(cs
->as
, entry
, MEMTXATTRS_UNSPECIFIED
, &txres
);
796 if (txres
!= MEMTX_OK
) {
799 if (!M68K_UDT_VALID(next
)) {
802 if (!(next
& M68K_DESC_USED
) && !debug
) {
803 address_space_stl(cs
->as
, entry
, next
| M68K_DESC_USED
,
804 MEMTXATTRS_UNSPECIFIED
, &txres
);
805 if (txres
!= MEMTX_OK
) {
809 if (next
& M68K_DESC_WRITEPROT
) {
810 if (access_type
& ACCESS_PTEST
) {
811 env
->mmu
.mmusr
|= M68K_MMU_WP_040
;
813 *prot
&= ~PAGE_WRITE
;
814 if (access_type
& ACCESS_STORE
) {
820 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
821 entry
= M68K_8K_PAGE_BASE(next
) | M68K_8K_PAGE_INDEX(address
);
823 entry
= M68K_4K_PAGE_BASE(next
) | M68K_4K_PAGE_INDEX(address
);
826 next
= address_space_ldl(cs
->as
, entry
, MEMTXATTRS_UNSPECIFIED
, &txres
);
827 if (txres
!= MEMTX_OK
) {
831 if (!M68K_PDT_VALID(next
)) {
834 if (M68K_PDT_INDIRECT(next
)) {
835 next
= address_space_ldl(cs
->as
, M68K_INDIRECT_POINTER(next
),
836 MEMTXATTRS_UNSPECIFIED
, &txres
);
837 if (txres
!= MEMTX_OK
) {
841 if (access_type
& ACCESS_STORE
) {
842 if (next
& M68K_DESC_WRITEPROT
) {
843 if (!(next
& M68K_DESC_USED
) && !debug
) {
844 address_space_stl(cs
->as
, entry
, next
| M68K_DESC_USED
,
845 MEMTXATTRS_UNSPECIFIED
, &txres
);
846 if (txres
!= MEMTX_OK
) {
850 } else if ((next
& (M68K_DESC_MODIFIED
| M68K_DESC_USED
)) !=
851 (M68K_DESC_MODIFIED
| M68K_DESC_USED
) && !debug
) {
852 address_space_stl(cs
->as
, entry
,
853 next
| (M68K_DESC_MODIFIED
| M68K_DESC_USED
),
854 MEMTXATTRS_UNSPECIFIED
, &txres
);
855 if (txres
!= MEMTX_OK
) {
860 if (!(next
& M68K_DESC_USED
) && !debug
) {
861 address_space_stl(cs
->as
, entry
, next
| M68K_DESC_USED
,
862 MEMTXATTRS_UNSPECIFIED
, &txres
);
863 if (txres
!= MEMTX_OK
) {
869 if (env
->mmu
.tcr
& M68K_TCR_PAGE_8K
) {
874 *page_size
= 1 << page_bits
;
875 page_mask
= ~(*page_size
- 1);
876 *physical
= (next
& page_mask
) + (address
& (*page_size
- 1));
878 if (access_type
& ACCESS_PTEST
) {
879 env
->mmu
.mmusr
|= next
& M68K_MMU_SR_MASK_040
;
880 env
->mmu
.mmusr
|= *physical
& 0xfffff000;
881 env
->mmu
.mmusr
|= M68K_MMU_R_040
;
884 if (next
& M68K_DESC_WRITEPROT
) {
885 *prot
&= ~PAGE_WRITE
;
886 if (access_type
& ACCESS_STORE
) {
890 if (next
& M68K_DESC_SUPERONLY
) {
891 if ((access_type
& ACCESS_SUPER
) == 0) {
900 * A page table load/store failed. TODO: we should really raise a
901 * suitable guest fault here if this is not a debug access.
902 * For now just return that the translation failed.
907 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
909 CPUM68KState
*env
= cpu_env(cs
);
913 target_ulong page_size
;
915 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
920 access_type
= ACCESS_DATA
| ACCESS_DEBUG
;
921 if (env
->sr
& SR_S
) {
922 access_type
|= ACCESS_SUPER
;
925 if (get_physical_address(env
, &phys_addr
, &prot
,
926 addr
, access_type
, &page_size
) != 0) {
934 * Notify CPU of a pending interrupt. Prioritization and vectoring should
935 * be handled by the interrupt controller. Real hardware only requests
936 * the vector when the interrupt is acknowledged by the CPU. For
937 * simplicity we calculate it when the interrupt is signalled.
939 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
941 CPUState
*cs
= CPU(cpu
);
942 CPUM68KState
*env
= &cpu
->env
;
944 env
->pending_level
= level
;
945 env
->pending_vector
= vector
;
947 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
949 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
953 bool m68k_cpu_tlb_fill(CPUState
*cs
, vaddr address
, int size
,
954 MMUAccessType qemu_access_type
, int mmu_idx
,
955 bool probe
, uintptr_t retaddr
)
957 CPUM68KState
*env
= cpu_env(cs
);
962 target_ulong page_size
;
964 if ((env
->mmu
.tcr
& M68K_TCR_ENABLED
) == 0) {
966 tlb_set_page(cs
, address
& TARGET_PAGE_MASK
,
967 address
& TARGET_PAGE_MASK
,
968 PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
,
969 mmu_idx
, TARGET_PAGE_SIZE
);
973 if (qemu_access_type
== MMU_INST_FETCH
) {
974 access_type
= ACCESS_CODE
;
976 access_type
= ACCESS_DATA
;
977 if (qemu_access_type
== MMU_DATA_STORE
) {
978 access_type
|= ACCESS_STORE
;
981 if (mmu_idx
!= MMU_USER_IDX
) {
982 access_type
|= ACCESS_SUPER
;
985 ret
= get_physical_address(env
, &physical
, &prot
,
986 address
, access_type
, &page_size
);
987 if (likely(ret
== 0)) {
988 tlb_set_page(cs
, address
& TARGET_PAGE_MASK
,
989 physical
& TARGET_PAGE_MASK
, prot
, mmu_idx
, page_size
);
998 env
->mmu
.ssw
= M68K_ATC_040
;
1001 env
->mmu
.ssw
|= M68K_BA_SIZE_BYTE
;
1004 env
->mmu
.ssw
|= M68K_BA_SIZE_WORD
;
1007 env
->mmu
.ssw
|= M68K_BA_SIZE_LONG
;
1010 if (access_type
& ACCESS_SUPER
) {
1011 env
->mmu
.ssw
|= M68K_TM_040_SUPER
;
1013 if (access_type
& ACCESS_CODE
) {
1014 env
->mmu
.ssw
|= M68K_TM_040_CODE
;
1016 env
->mmu
.ssw
|= M68K_TM_040_DATA
;
1018 if (!(access_type
& ACCESS_STORE
)) {
1019 env
->mmu
.ssw
|= M68K_RW_040
;
1022 cs
->exception_index
= EXCP_ACCESS
;
1023 env
->mmu
.ar
= address
;
1024 cpu_loop_exit_restore(cs
, retaddr
);
1026 #endif /* !CONFIG_USER_ONLY */
1028 uint32_t HELPER(bitrev
)(uint32_t x
)
1030 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
1031 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
1032 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
1036 uint32_t HELPER(ff1
)(uint32_t x
)
1039 for (n
= 32; x
; n
--)
1044 uint32_t HELPER(sats
)(uint32_t val
, uint32_t v
)
1046 /* The result has the opposite sign to the original value. */
1047 if ((int32_t)v
< 0) {
1048 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
1053 void cpu_m68k_set_sr(CPUM68KState
*env
, uint32_t sr
)
1055 env
->sr
= sr
& 0xffe0;
1056 cpu_m68k_set_ccr(env
, sr
);
1057 m68k_switch_sp(env
);
1060 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
1062 cpu_m68k_set_sr(env
, val
);
1067 * FIXME: The MAC unit implementation is a bit of a mess. Some helpers
1068 * take values, others take register numbers and manipulate the contents
1071 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
1074 env
->macc
[dest
] = env
->macc
[src
];
1075 mask
= MACSR_PAV0
<< dest
;
1076 if (env
->macsr
& (MACSR_PAV0
<< src
))
1079 env
->macsr
&= ~mask
;
1082 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
1087 product
= (uint64_t)op1
* op2
;
1088 res
= (product
<< 24) >> 24;
1089 if (res
!= product
) {
1090 env
->macsr
|= MACSR_V
;
1091 if (env
->macsr
& MACSR_OMC
) {
1092 /* Make sure the accumulate operation overflows. */
1102 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
1106 product
= (uint64_t)op1
* op2
;
1107 if (product
& (0xffffffull
<< 40)) {
1108 env
->macsr
|= MACSR_V
;
1109 if (env
->macsr
& MACSR_OMC
) {
1110 /* Make sure the accumulate operation overflows. */
1111 product
= 1ll << 50;
1113 product
&= ((1ull << 40) - 1);
1119 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
1124 product
= (uint64_t)op1
* op2
;
1125 if (env
->macsr
& MACSR_RT
) {
1126 remainder
= product
& 0xffffff;
1128 if (remainder
> 0x800000)
1130 else if (remainder
== 0x800000)
1131 product
+= (product
& 1);
1138 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
1142 tmp
= env
->macc
[acc
];
1143 result
= ((tmp
<< 16) >> 16);
1144 if (result
!= tmp
) {
1145 env
->macsr
|= MACSR_V
;
1147 if (env
->macsr
& MACSR_V
) {
1148 env
->macsr
|= MACSR_PAV0
<< acc
;
1149 if (env
->macsr
& MACSR_OMC
) {
1151 * The result is saturated to 32 bits, despite overflow occurring
1152 * at 48 bits. Seems weird, but that's what the hardware docs
1155 result
= (result
>> 63) ^ 0x7fffffff;
1158 env
->macc
[acc
] = result
;
1161 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
1165 val
= env
->macc
[acc
];
1166 if (val
& (0xffffull
<< 48)) {
1167 env
->macsr
|= MACSR_V
;
1169 if (env
->macsr
& MACSR_V
) {
1170 env
->macsr
|= MACSR_PAV0
<< acc
;
1171 if (env
->macsr
& MACSR_OMC
) {
1172 if (val
> (1ull << 53))
1175 val
= (1ull << 48) - 1;
1177 val
&= ((1ull << 48) - 1);
1180 env
->macc
[acc
] = val
;
1183 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
1188 sum
= env
->macc
[acc
];
1189 result
= (sum
<< 16) >> 16;
1190 if (result
!= sum
) {
1191 env
->macsr
|= MACSR_V
;
1193 if (env
->macsr
& MACSR_V
) {
1194 env
->macsr
|= MACSR_PAV0
<< acc
;
1195 if (env
->macsr
& MACSR_OMC
) {
1196 result
= (result
>> 63) ^ 0x7fffffffffffll
;
1199 env
->macc
[acc
] = result
;
1202 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
1205 val
= env
->macc
[acc
];
1207 env
->macsr
|= MACSR_Z
;
1208 } else if (val
& (1ull << 47)) {
1209 env
->macsr
|= MACSR_N
;
1211 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
1212 env
->macsr
|= MACSR_V
;
1214 if (env
->macsr
& MACSR_FI
) {
1215 val
= ((int64_t)val
) >> 40;
1216 if (val
!= 0 && val
!= -1)
1217 env
->macsr
|= MACSR_EV
;
1218 } else if (env
->macsr
& MACSR_SU
) {
1219 val
= ((int64_t)val
) >> 32;
1220 if (val
!= 0 && val
!= -1)
1221 env
->macsr
|= MACSR_EV
;
1223 if ((val
>> 32) != 0)
1224 env
->macsr
|= MACSR_EV
;
1228 #define EXTSIGN(val, index) ( \
1229 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1232 #define COMPUTE_CCR(op, x, n, z, v, c) { \
1235 /* Everything in place. */ \
1242 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
1245 v = (res ^ src1) & ~(src1 ^ src2); \
1252 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
1255 v = (res ^ src1) & (src1 ^ src2); \
1262 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
1266 v = (res ^ src1) & (src1 ^ src2); \
1273 cpu_abort(env_cpu(env), "Bad CC_OP %d", op); \
1277 uint32_t cpu_m68k_get_ccr(CPUM68KState
*env
)
1279 uint32_t x
, c
, n
, z
, v
;
1280 uint32_t res
, src1
, src2
;
1288 COMPUTE_CCR(env
->cc_op
, x
, n
, z
, v
, c
);
1294 return x
* CCF_X
+ n
* CCF_N
+ z
* CCF_Z
+ v
* CCF_V
+ c
* CCF_C
;
1297 uint32_t HELPER(get_ccr
)(CPUM68KState
*env
)
1299 return cpu_m68k_get_ccr(env
);
1302 void cpu_m68k_set_ccr(CPUM68KState
*env
, uint32_t ccr
)
1304 env
->cc_x
= (ccr
& CCF_X
? 1 : 0);
1305 env
->cc_n
= (ccr
& CCF_N
? -1 : 0);
1306 env
->cc_z
= (ccr
& CCF_Z
? 0 : 1);
1307 env
->cc_v
= (ccr
& CCF_V
? -1 : 0);
1308 env
->cc_c
= (ccr
& CCF_C
? 1 : 0);
1309 env
->cc_op
= CC_OP_FLAGS
;
1312 void HELPER(set_ccr
)(CPUM68KState
*env
, uint32_t ccr
)
1314 cpu_m68k_set_ccr(env
, ccr
);
1317 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
1319 uint32_t res
, src1
, src2
;
1321 COMPUTE_CCR(cc_op
, env
->cc_x
, env
->cc_n
, env
->cc_z
, env
->cc_v
, env
->cc_c
);
1322 env
->cc_op
= CC_OP_FLAGS
;
1325 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
1330 if (env
->macsr
& MACSR_SU
) {
1331 /* 16-bit rounding. */
1332 rem
= val
& 0xffffff;
1333 val
= (val
>> 24) & 0xffffu
;
1336 else if (rem
== 0x800000)
1338 } else if (env
->macsr
& MACSR_RT
) {
1339 /* 32-bit rounding. */
1344 else if (rem
== 0x80)
1350 if (env
->macsr
& MACSR_OMC
) {
1352 if (env
->macsr
& MACSR_SU
) {
1353 if (val
!= (uint16_t) val
) {
1354 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
1356 result
= val
& 0xffff;
1359 if (val
!= (uint32_t)val
) {
1360 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
1362 result
= (uint32_t)val
;
1366 /* No saturation. */
1367 if (env
->macsr
& MACSR_SU
) {
1368 result
= val
& 0xffff;
1370 result
= (uint32_t)val
;
1376 uint32_t HELPER(get_macs
)(uint64_t val
)
1378 if (val
== (int32_t)val
) {
1379 return (int32_t)val
;
1381 return (val
>> 61) ^ ~SIGNBIT
;
1385 uint32_t HELPER(get_macu
)(uint64_t val
)
1387 if ((val
>> 32) == 0) {
1388 return (uint32_t)val
;
1394 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
1397 val
= env
->macc
[acc
] & 0x00ff;
1398 val
|= (env
->macc
[acc
] >> 32) & 0xff00;
1399 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
1400 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
1404 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
1407 val
= (env
->macc
[acc
] >> 32) & 0xffff;
1408 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
1412 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1416 res
= env
->macc
[acc
] & 0xffffffff00ull
;
1417 tmp
= (int16_t)(val
& 0xff00);
1418 res
|= ((int64_t)tmp
) << 32;
1420 env
->macc
[acc
] = res
;
1421 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
1422 tmp
= (val
& 0xff000000);
1423 res
|= ((int64_t)tmp
) << 16;
1424 res
|= (val
>> 16) & 0xff;
1425 env
->macc
[acc
+ 1] = res
;
1428 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1432 res
= (uint32_t)env
->macc
[acc
];
1434 res
|= ((int64_t)tmp
) << 32;
1435 env
->macc
[acc
] = res
;
1436 res
= (uint32_t)env
->macc
[acc
+ 1];
1437 tmp
= val
& 0xffff0000;
1438 res
|= (int64_t)tmp
<< 16;
1439 env
->macc
[acc
+ 1] = res
;
1442 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
1445 res
= (uint32_t)env
->macc
[acc
];
1446 res
|= ((uint64_t)(val
& 0xffff)) << 32;
1447 env
->macc
[acc
] = res
;
1448 res
= (uint32_t)env
->macc
[acc
+ 1];
1449 res
|= (uint64_t)(val
& 0xffff0000) << 16;
1450 env
->macc
[acc
+ 1] = res
;
1453 #if !defined(CONFIG_USER_ONLY)
1454 void HELPER(ptest
)(CPUM68KState
*env
, uint32_t addr
, uint32_t is_read
)
1460 target_ulong page_size
;
1462 access_type
= ACCESS_PTEST
;
1464 access_type
|= ACCESS_SUPER
;
1466 if ((env
->dfc
& 3) == 2) {
1467 access_type
|= ACCESS_CODE
;
1470 access_type
|= ACCESS_STORE
;
1475 ret
= get_physical_address(env
, &physical
, &prot
, addr
,
1476 access_type
, &page_size
);
1478 tlb_set_page(env_cpu(env
), addr
& TARGET_PAGE_MASK
,
1479 physical
& TARGET_PAGE_MASK
,
1480 prot
, access_type
& ACCESS_SUPER
?
1481 MMU_KERNEL_IDX
: MMU_USER_IDX
, page_size
);
1485 void HELPER(pflush
)(CPUM68KState
*env
, uint32_t addr
, uint32_t opmode
)
1487 CPUState
*cs
= env_cpu(env
);
1490 case 0: /* Flush page entry if not global */
1491 case 1: /* Flush page entry */
1492 tlb_flush_page(cs
, addr
);
1494 case 2: /* Flush all except global entries */
1497 case 3: /* Flush all entries */
1503 void HELPER(reset
)(CPUM68KState
*env
)
1505 /* FIXME: reset all except CPU */
1507 #endif /* !CONFIG_USER_ONLY */