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/>.
26 #define SIGNBIT (1u << 31)
35 typedef struct m68k_def_t m68k_def_t
;
42 static m68k_def_t m68k_cpu_defs
[] = {
43 {"m5206", M68K_CPUID_M5206
},
44 {"m5208", M68K_CPUID_M5208
},
45 {"cfv4e", M68K_CPUID_CFV4E
},
46 {"any", M68K_CPUID_ANY
},
50 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
54 for (i
= 0; m68k_cpu_defs
[i
].name
; i
++) {
55 (*cpu_fprintf
)(f
, "%s\n", m68k_cpu_defs
[i
].name
);
59 static int fpu_gdb_get_reg(CPUState
*env
, uint8_t *mem_buf
, int n
)
62 stfq_p(mem_buf
, env
->fregs
[n
]);
66 /* FP control registers (not implemented) */
67 memset(mem_buf
, 0, 4);
73 static int fpu_gdb_set_reg(CPUState
*env
, uint8_t *mem_buf
, int n
)
76 env
->fregs
[n
] = ldfq_p(mem_buf
);
80 /* FP control registers (not implemented) */
86 static void m68k_set_feature(CPUM68KState
*env
, int feature
)
88 env
->features
|= (1u << feature
);
91 static int cpu_m68k_set_model(CPUM68KState
*env
, const char *name
)
95 for (def
= m68k_cpu_defs
; def
->name
; def
++) {
96 if (strcmp(def
->name
, name
) == 0)
103 case M68K_CPUID_M5206
:
104 m68k_set_feature(env
, M68K_FEATURE_CF_ISA_A
);
106 case M68K_CPUID_M5208
:
107 m68k_set_feature(env
, M68K_FEATURE_CF_ISA_A
);
108 m68k_set_feature(env
, M68K_FEATURE_CF_ISA_APLUSC
);
109 m68k_set_feature(env
, M68K_FEATURE_BRAL
);
110 m68k_set_feature(env
, M68K_FEATURE_CF_EMAC
);
111 m68k_set_feature(env
, M68K_FEATURE_USP
);
113 case M68K_CPUID_CFV4E
:
114 m68k_set_feature(env
, M68K_FEATURE_CF_ISA_A
);
115 m68k_set_feature(env
, M68K_FEATURE_CF_ISA_B
);
116 m68k_set_feature(env
, M68K_FEATURE_BRAL
);
117 m68k_set_feature(env
, M68K_FEATURE_CF_FPU
);
118 m68k_set_feature(env
, M68K_FEATURE_CF_EMAC
);
119 m68k_set_feature(env
, M68K_FEATURE_USP
);
122 m68k_set_feature(env
, M68K_FEATURE_CF_ISA_A
);
123 m68k_set_feature(env
, M68K_FEATURE_CF_ISA_B
);
124 m68k_set_feature(env
, M68K_FEATURE_CF_ISA_APLUSC
);
125 m68k_set_feature(env
, M68K_FEATURE_BRAL
);
126 m68k_set_feature(env
, M68K_FEATURE_CF_FPU
);
127 /* MAC and EMAC are mututally exclusive, so pick EMAC.
128 It's mostly backwards compatible. */
129 m68k_set_feature(env
, M68K_FEATURE_CF_EMAC
);
130 m68k_set_feature(env
, M68K_FEATURE_CF_EMAC_B
);
131 m68k_set_feature(env
, M68K_FEATURE_USP
);
132 m68k_set_feature(env
, M68K_FEATURE_EXT_FULL
);
133 m68k_set_feature(env
, M68K_FEATURE_WORD_INDEX
);
137 register_m68k_insns(env
);
138 if (m68k_feature (env
, M68K_FEATURE_CF_FPU
)) {
139 gdb_register_coprocessor(env
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
140 11, "cf-fp.xml", 18);
142 /* TODO: Add [E]MAC registers. */
146 void cpu_reset(CPUM68KState
*env
)
148 if (qemu_loglevel_mask(CPU_LOG_RESET
)) {
149 qemu_log("CPU Reset (CPU %d)\n", env
->cpu_index
);
150 log_cpu_state(env
, 0);
153 memset(env
, 0, offsetof(CPUM68KState
, breakpoints
));
154 #if !defined (CONFIG_USER_ONLY)
158 /* ??? FP regs should be initialized to NaN. */
159 env
->cc_op
= CC_OP_FLAGS
;
160 /* TODO: We should set PC from the interrupt vector. */
165 CPUM68KState
*cpu_m68k_init(const char *cpu_model
)
170 env
= g_malloc0(sizeof(CPUM68KState
));
177 env
->cpu_model_str
= cpu_model
;
179 if (cpu_m68k_set_model(env
, cpu_model
) < 0) {
189 void cpu_m68k_close(CPUM68KState
*env
)
194 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
201 #define HIGHBIT 0x80000000u
203 #define SET_NZ(x) do { \
206 else if ((int32_t)(x) < 0) \
210 #define SET_FLAGS_SUB(type, utype) do { \
211 SET_NZ((type)dest); \
213 if ((utype) tmp < (utype) src) \
215 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
234 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
238 SET_FLAGS_SUB(int32_t, uint32_t);
241 SET_FLAGS_SUB(int8_t, uint8_t);
244 SET_FLAGS_SUB(int16_t, uint16_t);
250 tmp
= dest
- src
- 1;
251 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
256 tmp
= dest
+ src
+ 1;
259 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
268 cpu_abort(env
, "Bad CC_OP %d", cc_op
);
270 env
->cc_op
= CC_OP_FLAGS
;
271 env
->cc_dest
= flags
;
274 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
277 case 0x02: /* CACR */
281 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
282 /* TODO: Implement Access Control Registers. */
284 case 0x801: /* VBR */
287 /* TODO: Implement control registers. */
289 cpu_abort(env
, "Unimplemented control register write 0x%x = 0x%x\n",
294 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
301 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
302 for (i
= 0; i
< 4; i
++) {
303 regval
= env
->macc
[i
];
304 exthigh
= regval
>> 40;
305 if (env
->macsr
& MACSR_FI
) {
310 extlow
= regval
>> 32;
312 if (env
->macsr
& MACSR_FI
) {
313 regval
= (((uint64_t)acc
) << 8) | extlow
;
314 regval
|= ((int64_t)exthigh
) << 40;
315 } else if (env
->macsr
& MACSR_SU
) {
316 regval
= acc
| (((int64_t)extlow
) << 32);
317 regval
|= ((int64_t)exthigh
) << 40;
319 regval
= acc
| (((uint64_t)extlow
) << 32);
320 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
322 env
->macc
[i
] = regval
;
328 void m68k_switch_sp(CPUM68KState
*env
)
332 env
->sp
[env
->current_sp
] = env
->aregs
[7];
333 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
334 ? M68K_SSP
: M68K_USP
;
335 env
->aregs
[7] = env
->sp
[new_sp
];
336 env
->current_sp
= new_sp
;
339 #if defined(CONFIG_USER_ONLY)
341 int cpu_m68k_handle_mmu_fault (CPUState
*env
, target_ulong address
, int rw
,
344 env
->exception_index
= EXCP_ACCESS
;
345 env
->mmu
.ar
= address
;
353 /* TODO: This will need fixing once the MMU is implemented. */
354 target_phys_addr_t
cpu_get_phys_page_debug(CPUState
*env
, target_ulong addr
)
359 int cpu_m68k_handle_mmu_fault (CPUState
*env
, target_ulong address
, int rw
,
364 address
&= TARGET_PAGE_MASK
;
365 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
366 tlb_set_page(env
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
370 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
371 be handled by the interrupt controller. Real hardware only requests
372 the vector when the interrupt is acknowledged by the CPU. For
373 simplicitly we calculate it when the interrupt is signalled. */
374 void m68k_set_irq_level(CPUM68KState
*env
, int level
, uint8_t vector
)
376 env
->pending_level
= level
;
377 env
->pending_vector
= vector
;
379 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
381 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
386 uint32_t HELPER(bitrev
)(uint32_t x
)
388 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
389 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
390 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
394 uint32_t HELPER(ff1
)(uint32_t x
)
402 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
404 /* The result has the opposite sign to the original value. */
406 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
410 uint32_t HELPER(subx_cc
)(CPUState
*env
, uint32_t op1
, uint32_t op2
)
415 old_flags
= env
->cc_dest
;
417 env
->cc_x
= (op1
<= op2
);
418 env
->cc_op
= CC_OP_SUBX
;
419 res
= op1
- (op2
+ 1);
421 env
->cc_x
= (op1
< op2
);
422 env
->cc_op
= CC_OP_SUB
;
427 cpu_m68k_flush_flags(env
, env
->cc_op
);
429 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
433 uint32_t HELPER(addx_cc
)(CPUState
*env
, uint32_t op1
, uint32_t op2
)
438 old_flags
= env
->cc_dest
;
441 env
->cc_x
= (res
<= op2
);
442 env
->cc_op
= CC_OP_ADDX
;
445 env
->cc_x
= (res
< op2
);
446 env
->cc_op
= CC_OP_ADD
;
450 cpu_m68k_flush_flags(env
, env
->cc_op
);
452 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
456 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
461 void HELPER(set_sr
)(CPUState
*env
, uint32_t val
)
463 env
->sr
= val
& 0xffff;
467 uint32_t HELPER(shl_cc
)(CPUState
*env
, uint32_t val
, uint32_t shift
)
475 cf
= env
->cc_src
& CCF_C
;
476 } else if (shift
< 32) {
477 result
= val
<< shift
;
478 cf
= (val
>> (32 - shift
)) & 1;
479 } else if (shift
== 32) {
482 } else /* shift > 32 */ {
487 env
->cc_x
= (cf
!= 0);
488 env
->cc_dest
= result
;
492 uint32_t HELPER(shr_cc
)(CPUState
*env
, uint32_t val
, uint32_t shift
)
500 cf
= env
->cc_src
& CCF_C
;
501 } else if (shift
< 32) {
502 result
= val
>> shift
;
503 cf
= (val
>> (shift
- 1)) & 1;
504 } else if (shift
== 32) {
507 } else /* shift > 32 */ {
512 env
->cc_x
= (cf
!= 0);
513 env
->cc_dest
= result
;
517 uint32_t HELPER(sar_cc
)(CPUState
*env
, uint32_t val
, uint32_t shift
)
525 cf
= (env
->cc_src
& CCF_C
) != 0;
526 } else if (shift
< 32) {
527 result
= (int32_t)val
>> shift
;
528 cf
= (val
>> (shift
- 1)) & 1;
529 } else /* shift >= 32 */ {
530 result
= (int32_t)val
>> 31;
535 env
->cc_dest
= result
;
540 uint32_t HELPER(f64_to_i32
)(CPUState
*env
, float64 val
)
542 return float64_to_int32(val
, &env
->fp_status
);
545 float32
HELPER(f64_to_f32
)(CPUState
*env
, float64 val
)
547 return float64_to_float32(val
, &env
->fp_status
);
550 float64
HELPER(i32_to_f64
)(CPUState
*env
, uint32_t val
)
552 return int32_to_float64(val
, &env
->fp_status
);
555 float64
HELPER(f32_to_f64
)(CPUState
*env
, float32 val
)
557 return float32_to_float64(val
, &env
->fp_status
);
560 float64
HELPER(iround_f64
)(CPUState
*env
, float64 val
)
562 return float64_round_to_int(val
, &env
->fp_status
);
565 float64
HELPER(itrunc_f64
)(CPUState
*env
, float64 val
)
567 return float64_trunc_to_int(val
, &env
->fp_status
);
570 float64
HELPER(sqrt_f64
)(CPUState
*env
, float64 val
)
572 return float64_sqrt(val
, &env
->fp_status
);
575 float64
HELPER(abs_f64
)(float64 val
)
577 return float64_abs(val
);
580 float64
HELPER(chs_f64
)(float64 val
)
582 return float64_chs(val
);
585 float64
HELPER(add_f64
)(CPUState
*env
, float64 a
, float64 b
)
587 return float64_add(a
, b
, &env
->fp_status
);
590 float64
HELPER(sub_f64
)(CPUState
*env
, float64 a
, float64 b
)
592 return float64_sub(a
, b
, &env
->fp_status
);
595 float64
HELPER(mul_f64
)(CPUState
*env
, float64 a
, float64 b
)
597 return float64_mul(a
, b
, &env
->fp_status
);
600 float64
HELPER(div_f64
)(CPUState
*env
, float64 a
, float64 b
)
602 return float64_div(a
, b
, &env
->fp_status
);
605 float64
HELPER(sub_cmp_f64
)(CPUState
*env
, float64 a
, float64 b
)
607 /* ??? This may incorrectly raise exceptions. */
608 /* ??? Should flush denormals to zero. */
610 res
= float64_sub(a
, b
, &env
->fp_status
);
611 if (float64_is_quiet_nan(res
)) {
612 /* +/-inf compares equal against itself, but sub returns nan. */
613 if (!float64_is_quiet_nan(a
)
614 && !float64_is_quiet_nan(b
)) {
616 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
617 res
= float64_chs(res
);
623 uint32_t HELPER(compare_f64
)(CPUState
*env
, float64 val
)
625 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
629 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
630 take values, others take register numbers and manipulate the contents
632 void HELPER(mac_move
)(CPUState
*env
, uint32_t dest
, uint32_t src
)
635 env
->macc
[dest
] = env
->macc
[src
];
636 mask
= MACSR_PAV0
<< dest
;
637 if (env
->macsr
& (MACSR_PAV0
<< src
))
643 uint64_t HELPER(macmuls
)(CPUState
*env
, uint32_t op1
, uint32_t op2
)
648 product
= (uint64_t)op1
* op2
;
649 res
= (product
<< 24) >> 24;
650 if (res
!= product
) {
651 env
->macsr
|= MACSR_V
;
652 if (env
->macsr
& MACSR_OMC
) {
653 /* Make sure the accumulate operation overflows. */
663 uint64_t HELPER(macmulu
)(CPUState
*env
, uint32_t op1
, uint32_t op2
)
667 product
= (uint64_t)op1
* op2
;
668 if (product
& (0xffffffull
<< 40)) {
669 env
->macsr
|= MACSR_V
;
670 if (env
->macsr
& MACSR_OMC
) {
671 /* Make sure the accumulate operation overflows. */
674 product
&= ((1ull << 40) - 1);
680 uint64_t HELPER(macmulf
)(CPUState
*env
, uint32_t op1
, uint32_t op2
)
685 product
= (uint64_t)op1
* op2
;
686 if (env
->macsr
& MACSR_RT
) {
687 remainder
= product
& 0xffffff;
689 if (remainder
> 0x800000)
691 else if (remainder
== 0x800000)
692 product
+= (product
& 1);
699 void HELPER(macsats
)(CPUState
*env
, uint32_t acc
)
703 tmp
= env
->macc
[acc
];
704 result
= ((tmp
<< 16) >> 16);
706 env
->macsr
|= MACSR_V
;
708 if (env
->macsr
& MACSR_V
) {
709 env
->macsr
|= MACSR_PAV0
<< acc
;
710 if (env
->macsr
& MACSR_OMC
) {
711 /* The result is saturated to 32 bits, despite overflow occurring
712 at 48 bits. Seems weird, but that's what the hardware docs
714 result
= (result
>> 63) ^ 0x7fffffff;
717 env
->macc
[acc
] = result
;
720 void HELPER(macsatu
)(CPUState
*env
, uint32_t acc
)
724 val
= env
->macc
[acc
];
725 if (val
& (0xffffull
<< 48)) {
726 env
->macsr
|= MACSR_V
;
728 if (env
->macsr
& MACSR_V
) {
729 env
->macsr
|= MACSR_PAV0
<< acc
;
730 if (env
->macsr
& MACSR_OMC
) {
731 if (val
> (1ull << 53))
734 val
= (1ull << 48) - 1;
736 val
&= ((1ull << 48) - 1);
739 env
->macc
[acc
] = val
;
742 void HELPER(macsatf
)(CPUState
*env
, uint32_t acc
)
747 sum
= env
->macc
[acc
];
748 result
= (sum
<< 16) >> 16;
750 env
->macsr
|= MACSR_V
;
752 if (env
->macsr
& MACSR_V
) {
753 env
->macsr
|= MACSR_PAV0
<< acc
;
754 if (env
->macsr
& MACSR_OMC
) {
755 result
= (result
>> 63) ^ 0x7fffffffffffll
;
758 env
->macc
[acc
] = result
;
761 void HELPER(mac_set_flags
)(CPUState
*env
, uint32_t acc
)
764 val
= env
->macc
[acc
];
766 env
->macsr
|= MACSR_Z
;
767 } else if (val
& (1ull << 47)) {
768 env
->macsr
|= MACSR_N
;
770 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
771 env
->macsr
|= MACSR_V
;
773 if (env
->macsr
& MACSR_FI
) {
774 val
= ((int64_t)val
) >> 40;
775 if (val
!= 0 && val
!= -1)
776 env
->macsr
|= MACSR_EV
;
777 } else if (env
->macsr
& MACSR_SU
) {
778 val
= ((int64_t)val
) >> 32;
779 if (val
!= 0 && val
!= -1)
780 env
->macsr
|= MACSR_EV
;
782 if ((val
>> 32) != 0)
783 env
->macsr
|= MACSR_EV
;
787 void HELPER(flush_flags
)(CPUState
*env
, uint32_t cc_op
)
789 cpu_m68k_flush_flags(env
, cc_op
);
792 uint32_t HELPER(get_macf
)(CPUState
*env
, uint64_t val
)
797 if (env
->macsr
& MACSR_SU
) {
798 /* 16-bit rounding. */
799 rem
= val
& 0xffffff;
800 val
= (val
>> 24) & 0xffffu
;
803 else if (rem
== 0x800000)
805 } else if (env
->macsr
& MACSR_RT
) {
806 /* 32-bit rounding. */
811 else if (rem
== 0x80)
817 if (env
->macsr
& MACSR_OMC
) {
819 if (env
->macsr
& MACSR_SU
) {
820 if (val
!= (uint16_t) val
) {
821 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
823 result
= val
& 0xffff;
826 if (val
!= (uint32_t)val
) {
827 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
829 result
= (uint32_t)val
;
834 if (env
->macsr
& MACSR_SU
) {
835 result
= val
& 0xffff;
837 result
= (uint32_t)val
;
843 uint32_t HELPER(get_macs
)(uint64_t val
)
845 if (val
== (int32_t)val
) {
848 return (val
>> 61) ^ ~SIGNBIT
;
852 uint32_t HELPER(get_macu
)(uint64_t val
)
854 if ((val
>> 32) == 0) {
855 return (uint32_t)val
;
861 uint32_t HELPER(get_mac_extf
)(CPUState
*env
, uint32_t acc
)
864 val
= env
->macc
[acc
] & 0x00ff;
865 val
= (env
->macc
[acc
] >> 32) & 0xff00;
866 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
867 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
871 uint32_t HELPER(get_mac_exti
)(CPUState
*env
, uint32_t acc
)
874 val
= (env
->macc
[acc
] >> 32) & 0xffff;
875 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
879 void HELPER(set_mac_extf
)(CPUState
*env
, uint32_t val
, uint32_t acc
)
883 res
= env
->macc
[acc
] & 0xffffffff00ull
;
884 tmp
= (int16_t)(val
& 0xff00);
885 res
|= ((int64_t)tmp
) << 32;
887 env
->macc
[acc
] = res
;
888 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
889 tmp
= (val
& 0xff000000);
890 res
|= ((int64_t)tmp
) << 16;
891 res
|= (val
>> 16) & 0xff;
892 env
->macc
[acc
+ 1] = res
;
895 void HELPER(set_mac_exts
)(CPUState
*env
, uint32_t val
, uint32_t acc
)
899 res
= (uint32_t)env
->macc
[acc
];
901 res
|= ((int64_t)tmp
) << 32;
902 env
->macc
[acc
] = res
;
903 res
= (uint32_t)env
->macc
[acc
+ 1];
904 tmp
= val
& 0xffff0000;
905 res
|= (int64_t)tmp
<< 16;
906 env
->macc
[acc
+ 1] = res
;
909 void HELPER(set_mac_extu
)(CPUState
*env
, uint32_t val
, uint32_t acc
)
912 res
= (uint32_t)env
->macc
[acc
];
913 res
|= ((uint64_t)(val
& 0xffff)) << 32;
914 env
->macc
[acc
] = res
;
915 res
= (uint32_t)env
->macc
[acc
+ 1];
916 res
|= (uint64_t)(val
& 0xffff0000) << 16;
917 env
->macc
[acc
+ 1] = res
;