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(CPUM68KState
*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(CPUM68KState
*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_state_reset(CPUM68KState
*env
)
148 cpu_reset(ENV_GET_CPU(env
));
151 CPUM68KState
*cpu_m68k_init(const char *cpu_model
)
157 cpu
= M68K_CPU(object_new(TYPE_M68K_CPU
));
165 env
->cpu_model_str
= cpu_model
;
167 if (cpu_m68k_set_model(env
, cpu_model
) < 0) {
168 object_delete(OBJECT(cpu
));
172 cpu_reset(ENV_GET_CPU(env
));
177 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
184 #define HIGHBIT 0x80000000u
186 #define SET_NZ(x) do { \
189 else if ((int32_t)(x) < 0) \
193 #define SET_FLAGS_SUB(type, utype) do { \
194 SET_NZ((type)dest); \
196 if ((utype) tmp < (utype) src) \
198 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
217 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
221 SET_FLAGS_SUB(int32_t, uint32_t);
224 SET_FLAGS_SUB(int8_t, uint8_t);
227 SET_FLAGS_SUB(int16_t, uint16_t);
233 tmp
= dest
- src
- 1;
234 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
239 tmp
= dest
+ src
+ 1;
242 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
251 cpu_abort(env
, "Bad CC_OP %d", cc_op
);
253 env
->cc_op
= CC_OP_FLAGS
;
254 env
->cc_dest
= flags
;
257 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
260 case 0x02: /* CACR */
264 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
265 /* TODO: Implement Access Control Registers. */
267 case 0x801: /* VBR */
270 /* TODO: Implement control registers. */
272 cpu_abort(env
, "Unimplemented control register write 0x%x = 0x%x\n",
277 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
284 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
285 for (i
= 0; i
< 4; i
++) {
286 regval
= env
->macc
[i
];
287 exthigh
= regval
>> 40;
288 if (env
->macsr
& MACSR_FI
) {
293 extlow
= regval
>> 32;
295 if (env
->macsr
& MACSR_FI
) {
296 regval
= (((uint64_t)acc
) << 8) | extlow
;
297 regval
|= ((int64_t)exthigh
) << 40;
298 } else if (env
->macsr
& MACSR_SU
) {
299 regval
= acc
| (((int64_t)extlow
) << 32);
300 regval
|= ((int64_t)exthigh
) << 40;
302 regval
= acc
| (((uint64_t)extlow
) << 32);
303 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
305 env
->macc
[i
] = regval
;
311 void m68k_switch_sp(CPUM68KState
*env
)
315 env
->sp
[env
->current_sp
] = env
->aregs
[7];
316 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
317 ? M68K_SSP
: M68K_USP
;
318 env
->aregs
[7] = env
->sp
[new_sp
];
319 env
->current_sp
= new_sp
;
322 #if defined(CONFIG_USER_ONLY)
324 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
327 env
->exception_index
= EXCP_ACCESS
;
328 env
->mmu
.ar
= address
;
336 /* TODO: This will need fixing once the MMU is implemented. */
337 target_phys_addr_t
cpu_get_phys_page_debug(CPUM68KState
*env
, target_ulong addr
)
342 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
347 address
&= TARGET_PAGE_MASK
;
348 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
349 tlb_set_page(env
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
353 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
354 be handled by the interrupt controller. Real hardware only requests
355 the vector when the interrupt is acknowledged by the CPU. For
356 simplicitly we calculate it when the interrupt is signalled. */
357 void m68k_set_irq_level(CPUM68KState
*env
, int level
, uint8_t vector
)
359 env
->pending_level
= level
;
360 env
->pending_vector
= vector
;
362 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
364 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
369 uint32_t HELPER(bitrev
)(uint32_t x
)
371 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
372 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
373 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
377 uint32_t HELPER(ff1
)(uint32_t x
)
385 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
387 /* The result has the opposite sign to the original value. */
389 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
393 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
398 old_flags
= env
->cc_dest
;
400 env
->cc_x
= (op1
<= op2
);
401 env
->cc_op
= CC_OP_SUBX
;
402 res
= op1
- (op2
+ 1);
404 env
->cc_x
= (op1
< op2
);
405 env
->cc_op
= CC_OP_SUB
;
410 cpu_m68k_flush_flags(env
, env
->cc_op
);
412 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
416 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
421 old_flags
= env
->cc_dest
;
424 env
->cc_x
= (res
<= op2
);
425 env
->cc_op
= CC_OP_ADDX
;
428 env
->cc_x
= (res
< op2
);
429 env
->cc_op
= CC_OP_ADD
;
433 cpu_m68k_flush_flags(env
, env
->cc_op
);
435 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
439 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
444 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
446 env
->sr
= val
& 0xffff;
450 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
458 cf
= env
->cc_src
& CCF_C
;
459 } else if (shift
< 32) {
460 result
= val
<< shift
;
461 cf
= (val
>> (32 - shift
)) & 1;
462 } else if (shift
== 32) {
465 } else /* shift > 32 */ {
470 env
->cc_x
= (cf
!= 0);
471 env
->cc_dest
= result
;
475 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
483 cf
= env
->cc_src
& CCF_C
;
484 } else if (shift
< 32) {
485 result
= val
>> shift
;
486 cf
= (val
>> (shift
- 1)) & 1;
487 } else if (shift
== 32) {
490 } else /* shift > 32 */ {
495 env
->cc_x
= (cf
!= 0);
496 env
->cc_dest
= result
;
500 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
508 cf
= (env
->cc_src
& CCF_C
) != 0;
509 } else if (shift
< 32) {
510 result
= (int32_t)val
>> shift
;
511 cf
= (val
>> (shift
- 1)) & 1;
512 } else /* shift >= 32 */ {
513 result
= (int32_t)val
>> 31;
518 env
->cc_dest
= result
;
523 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
525 return float64_to_int32(val
, &env
->fp_status
);
528 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
530 return float64_to_float32(val
, &env
->fp_status
);
533 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
535 return int32_to_float64(val
, &env
->fp_status
);
538 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
540 return float32_to_float64(val
, &env
->fp_status
);
543 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
545 return float64_round_to_int(val
, &env
->fp_status
);
548 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
550 return float64_trunc_to_int(val
, &env
->fp_status
);
553 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
555 return float64_sqrt(val
, &env
->fp_status
);
558 float64
HELPER(abs_f64
)(float64 val
)
560 return float64_abs(val
);
563 float64
HELPER(chs_f64
)(float64 val
)
565 return float64_chs(val
);
568 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
570 return float64_add(a
, b
, &env
->fp_status
);
573 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
575 return float64_sub(a
, b
, &env
->fp_status
);
578 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
580 return float64_mul(a
, b
, &env
->fp_status
);
583 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
585 return float64_div(a
, b
, &env
->fp_status
);
588 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
590 /* ??? This may incorrectly raise exceptions. */
591 /* ??? Should flush denormals to zero. */
593 res
= float64_sub(a
, b
, &env
->fp_status
);
594 if (float64_is_quiet_nan(res
)) {
595 /* +/-inf compares equal against itself, but sub returns nan. */
596 if (!float64_is_quiet_nan(a
)
597 && !float64_is_quiet_nan(b
)) {
599 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
600 res
= float64_chs(res
);
606 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
608 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
612 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
613 take values, others take register numbers and manipulate the contents
615 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
618 env
->macc
[dest
] = env
->macc
[src
];
619 mask
= MACSR_PAV0
<< dest
;
620 if (env
->macsr
& (MACSR_PAV0
<< src
))
626 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
631 product
= (uint64_t)op1
* op2
;
632 res
= (product
<< 24) >> 24;
633 if (res
!= product
) {
634 env
->macsr
|= MACSR_V
;
635 if (env
->macsr
& MACSR_OMC
) {
636 /* Make sure the accumulate operation overflows. */
646 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
650 product
= (uint64_t)op1
* op2
;
651 if (product
& (0xffffffull
<< 40)) {
652 env
->macsr
|= MACSR_V
;
653 if (env
->macsr
& MACSR_OMC
) {
654 /* Make sure the accumulate operation overflows. */
657 product
&= ((1ull << 40) - 1);
663 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
668 product
= (uint64_t)op1
* op2
;
669 if (env
->macsr
& MACSR_RT
) {
670 remainder
= product
& 0xffffff;
672 if (remainder
> 0x800000)
674 else if (remainder
== 0x800000)
675 product
+= (product
& 1);
682 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
686 tmp
= env
->macc
[acc
];
687 result
= ((tmp
<< 16) >> 16);
689 env
->macsr
|= MACSR_V
;
691 if (env
->macsr
& MACSR_V
) {
692 env
->macsr
|= MACSR_PAV0
<< acc
;
693 if (env
->macsr
& MACSR_OMC
) {
694 /* The result is saturated to 32 bits, despite overflow occurring
695 at 48 bits. Seems weird, but that's what the hardware docs
697 result
= (result
>> 63) ^ 0x7fffffff;
700 env
->macc
[acc
] = result
;
703 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
707 val
= env
->macc
[acc
];
708 if (val
& (0xffffull
<< 48)) {
709 env
->macsr
|= MACSR_V
;
711 if (env
->macsr
& MACSR_V
) {
712 env
->macsr
|= MACSR_PAV0
<< acc
;
713 if (env
->macsr
& MACSR_OMC
) {
714 if (val
> (1ull << 53))
717 val
= (1ull << 48) - 1;
719 val
&= ((1ull << 48) - 1);
722 env
->macc
[acc
] = val
;
725 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
730 sum
= env
->macc
[acc
];
731 result
= (sum
<< 16) >> 16;
733 env
->macsr
|= MACSR_V
;
735 if (env
->macsr
& MACSR_V
) {
736 env
->macsr
|= MACSR_PAV0
<< acc
;
737 if (env
->macsr
& MACSR_OMC
) {
738 result
= (result
>> 63) ^ 0x7fffffffffffll
;
741 env
->macc
[acc
] = result
;
744 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
747 val
= env
->macc
[acc
];
749 env
->macsr
|= MACSR_Z
;
750 } else if (val
& (1ull << 47)) {
751 env
->macsr
|= MACSR_N
;
753 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
754 env
->macsr
|= MACSR_V
;
756 if (env
->macsr
& MACSR_FI
) {
757 val
= ((int64_t)val
) >> 40;
758 if (val
!= 0 && val
!= -1)
759 env
->macsr
|= MACSR_EV
;
760 } else if (env
->macsr
& MACSR_SU
) {
761 val
= ((int64_t)val
) >> 32;
762 if (val
!= 0 && val
!= -1)
763 env
->macsr
|= MACSR_EV
;
765 if ((val
>> 32) != 0)
766 env
->macsr
|= MACSR_EV
;
770 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
772 cpu_m68k_flush_flags(env
, cc_op
);
775 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
780 if (env
->macsr
& MACSR_SU
) {
781 /* 16-bit rounding. */
782 rem
= val
& 0xffffff;
783 val
= (val
>> 24) & 0xffffu
;
786 else if (rem
== 0x800000)
788 } else if (env
->macsr
& MACSR_RT
) {
789 /* 32-bit rounding. */
794 else if (rem
== 0x80)
800 if (env
->macsr
& MACSR_OMC
) {
802 if (env
->macsr
& MACSR_SU
) {
803 if (val
!= (uint16_t) val
) {
804 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
806 result
= val
& 0xffff;
809 if (val
!= (uint32_t)val
) {
810 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
812 result
= (uint32_t)val
;
817 if (env
->macsr
& MACSR_SU
) {
818 result
= val
& 0xffff;
820 result
= (uint32_t)val
;
826 uint32_t HELPER(get_macs
)(uint64_t val
)
828 if (val
== (int32_t)val
) {
831 return (val
>> 61) ^ ~SIGNBIT
;
835 uint32_t HELPER(get_macu
)(uint64_t val
)
837 if ((val
>> 32) == 0) {
838 return (uint32_t)val
;
844 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
847 val
= env
->macc
[acc
] & 0x00ff;
848 val
= (env
->macc
[acc
] >> 32) & 0xff00;
849 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
850 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
854 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
857 val
= (env
->macc
[acc
] >> 32) & 0xffff;
858 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
862 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
866 res
= env
->macc
[acc
] & 0xffffffff00ull
;
867 tmp
= (int16_t)(val
& 0xff00);
868 res
|= ((int64_t)tmp
) << 32;
870 env
->macc
[acc
] = res
;
871 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
872 tmp
= (val
& 0xff000000);
873 res
|= ((int64_t)tmp
) << 16;
874 res
|= (val
>> 16) & 0xff;
875 env
->macc
[acc
+ 1] = res
;
878 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
882 res
= (uint32_t)env
->macc
[acc
];
884 res
|= ((int64_t)tmp
) << 32;
885 env
->macc
[acc
] = res
;
886 res
= (uint32_t)env
->macc
[acc
+ 1];
887 tmp
= val
& 0xffff0000;
888 res
|= (int64_t)tmp
<< 16;
889 env
->macc
[acc
+ 1] = res
;
892 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
895 res
= (uint32_t)env
->macc
[acc
];
896 res
|= ((uint64_t)(val
& 0xffff)) << 32;
897 env
->macc
[acc
] = res
;
898 res
= (uint32_t)env
->macc
[acc
+ 1];
899 res
|= (uint64_t)(val
& 0xffff0000) << 16;
900 env
->macc
[acc
+ 1] = res
;