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/>.
22 #include "exec/gdbstub.h"
26 #define SIGNBIT (1u << 31)
28 /* Sort alphabetically, except for "any". */
29 static gint
m68k_cpu_list_compare(gconstpointer a
, gconstpointer b
)
31 ObjectClass
*class_a
= (ObjectClass
*)a
;
32 ObjectClass
*class_b
= (ObjectClass
*)b
;
33 const char *name_a
, *name_b
;
35 name_a
= object_class_get_name(class_a
);
36 name_b
= object_class_get_name(class_b
);
37 if (strcmp(name_a
, "any-" TYPE_M68K_CPU
) == 0) {
39 } else if (strcmp(name_b
, "any-" TYPE_M68K_CPU
) == 0) {
42 return strcasecmp(name_a
, name_b
);
46 static void m68k_cpu_list_entry(gpointer data
, gpointer user_data
)
48 ObjectClass
*c
= data
;
49 CPUListState
*s
= user_data
;
53 typename
= object_class_get_name(c
);
54 name
= g_strndup(typename
, strlen(typename
) - strlen("-" TYPE_M68K_CPU
));
55 (*s
->cpu_fprintf
)(s
->file
, "%s\n",
60 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
64 .cpu_fprintf
= cpu_fprintf
,
68 list
= object_class_get_list(TYPE_M68K_CPU
, false);
69 list
= g_slist_sort(list
, m68k_cpu_list_compare
);
70 g_slist_foreach(list
, m68k_cpu_list_entry
, &s
);
74 static int fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
77 stfq_p(mem_buf
, env
->fregs
[n
]);
81 /* FP control registers (not implemented) */
82 memset(mem_buf
, 0, 4);
88 static int fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
91 env
->fregs
[n
] = ldfq_p(mem_buf
);
95 /* FP control registers (not implemented) */
101 M68kCPU
*cpu_m68k_init(const char *cpu_model
)
107 oc
= cpu_class_by_name(TYPE_M68K_CPU
, cpu_model
);
111 cpu
= M68K_CPU(object_new(object_class_get_name(oc
)));
113 env
->cpu_model_str
= cpu_model
;
115 register_m68k_insns(env
);
117 object_property_set_bool(OBJECT(cpu
), true, "realized", NULL
);
122 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
124 CPUM68KState
*env
= &cpu
->env
;
126 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
127 gdb_register_coprocessor(env
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
128 11, "cf-fp.xml", 18);
130 /* TODO: Add [E]MAC registers. */
133 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
140 #define HIGHBIT 0x80000000u
142 #define SET_NZ(x) do { \
145 else if ((int32_t)(x) < 0) \
149 #define SET_FLAGS_SUB(type, utype) do { \
150 SET_NZ((type)dest); \
152 if ((utype) tmp < (utype) src) \
154 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
173 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
177 SET_FLAGS_SUB(int32_t, uint32_t);
180 SET_FLAGS_SUB(int8_t, uint8_t);
183 SET_FLAGS_SUB(int16_t, uint16_t);
189 tmp
= dest
- src
- 1;
190 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
195 tmp
= dest
+ src
+ 1;
198 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
207 cpu_abort(env
, "Bad CC_OP %d", cc_op
);
209 env
->cc_op
= CC_OP_FLAGS
;
210 env
->cc_dest
= flags
;
213 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
216 case 0x02: /* CACR */
220 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
221 /* TODO: Implement Access Control Registers. */
223 case 0x801: /* VBR */
226 /* TODO: Implement control registers. */
228 cpu_abort(env
, "Unimplemented control register write 0x%x = 0x%x\n",
233 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
240 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
241 for (i
= 0; i
< 4; i
++) {
242 regval
= env
->macc
[i
];
243 exthigh
= regval
>> 40;
244 if (env
->macsr
& MACSR_FI
) {
249 extlow
= regval
>> 32;
251 if (env
->macsr
& MACSR_FI
) {
252 regval
= (((uint64_t)acc
) << 8) | extlow
;
253 regval
|= ((int64_t)exthigh
) << 40;
254 } else if (env
->macsr
& MACSR_SU
) {
255 regval
= acc
| (((int64_t)extlow
) << 32);
256 regval
|= ((int64_t)exthigh
) << 40;
258 regval
= acc
| (((uint64_t)extlow
) << 32);
259 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
261 env
->macc
[i
] = regval
;
267 void m68k_switch_sp(CPUM68KState
*env
)
271 env
->sp
[env
->current_sp
] = env
->aregs
[7];
272 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
273 ? M68K_SSP
: M68K_USP
;
274 env
->aregs
[7] = env
->sp
[new_sp
];
275 env
->current_sp
= new_sp
;
278 #if defined(CONFIG_USER_ONLY)
280 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
283 env
->exception_index
= EXCP_ACCESS
;
284 env
->mmu
.ar
= address
;
292 /* TODO: This will need fixing once the MMU is implemented. */
293 hwaddr
cpu_get_phys_page_debug(CPUM68KState
*env
, target_ulong addr
)
298 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
303 address
&= TARGET_PAGE_MASK
;
304 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
305 tlb_set_page(env
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
309 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
310 be handled by the interrupt controller. Real hardware only requests
311 the vector when the interrupt is acknowledged by the CPU. For
312 simplicitly we calculate it when the interrupt is signalled. */
313 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
315 CPUM68KState
*env
= &cpu
->env
;
317 env
->pending_level
= level
;
318 env
->pending_vector
= vector
;
320 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
322 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
327 uint32_t HELPER(bitrev
)(uint32_t x
)
329 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
330 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
331 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
335 uint32_t HELPER(ff1
)(uint32_t x
)
343 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
345 /* The result has the opposite sign to the original value. */
347 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
351 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
356 old_flags
= env
->cc_dest
;
358 env
->cc_x
= (op1
<= op2
);
359 env
->cc_op
= CC_OP_SUBX
;
360 res
= op1
- (op2
+ 1);
362 env
->cc_x
= (op1
< op2
);
363 env
->cc_op
= CC_OP_SUB
;
368 cpu_m68k_flush_flags(env
, env
->cc_op
);
370 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
374 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
379 old_flags
= env
->cc_dest
;
382 env
->cc_x
= (res
<= op2
);
383 env
->cc_op
= CC_OP_ADDX
;
386 env
->cc_x
= (res
< op2
);
387 env
->cc_op
= CC_OP_ADD
;
391 cpu_m68k_flush_flags(env
, env
->cc_op
);
393 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
397 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
402 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
404 env
->sr
= val
& 0xffff;
408 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
416 cf
= env
->cc_src
& CCF_C
;
417 } else if (shift
< 32) {
418 result
= val
<< shift
;
419 cf
= (val
>> (32 - shift
)) & 1;
420 } else if (shift
== 32) {
423 } else /* shift > 32 */ {
428 env
->cc_x
= (cf
!= 0);
429 env
->cc_dest
= result
;
433 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
441 cf
= env
->cc_src
& CCF_C
;
442 } else if (shift
< 32) {
443 result
= val
>> shift
;
444 cf
= (val
>> (shift
- 1)) & 1;
445 } else if (shift
== 32) {
448 } else /* shift > 32 */ {
453 env
->cc_x
= (cf
!= 0);
454 env
->cc_dest
= result
;
458 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
466 cf
= (env
->cc_src
& CCF_C
) != 0;
467 } else if (shift
< 32) {
468 result
= (int32_t)val
>> shift
;
469 cf
= (val
>> (shift
- 1)) & 1;
470 } else /* shift >= 32 */ {
471 result
= (int32_t)val
>> 31;
476 env
->cc_dest
= result
;
481 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
483 return float64_to_int32(val
, &env
->fp_status
);
486 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
488 return float64_to_float32(val
, &env
->fp_status
);
491 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
493 return int32_to_float64(val
, &env
->fp_status
);
496 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
498 return float32_to_float64(val
, &env
->fp_status
);
501 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
503 return float64_round_to_int(val
, &env
->fp_status
);
506 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
508 return float64_trunc_to_int(val
, &env
->fp_status
);
511 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
513 return float64_sqrt(val
, &env
->fp_status
);
516 float64
HELPER(abs_f64
)(float64 val
)
518 return float64_abs(val
);
521 float64
HELPER(chs_f64
)(float64 val
)
523 return float64_chs(val
);
526 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
528 return float64_add(a
, b
, &env
->fp_status
);
531 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
533 return float64_sub(a
, b
, &env
->fp_status
);
536 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
538 return float64_mul(a
, b
, &env
->fp_status
);
541 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
543 return float64_div(a
, b
, &env
->fp_status
);
546 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
548 /* ??? This may incorrectly raise exceptions. */
549 /* ??? Should flush denormals to zero. */
551 res
= float64_sub(a
, b
, &env
->fp_status
);
552 if (float64_is_quiet_nan(res
)) {
553 /* +/-inf compares equal against itself, but sub returns nan. */
554 if (!float64_is_quiet_nan(a
)
555 && !float64_is_quiet_nan(b
)) {
557 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
558 res
= float64_chs(res
);
564 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
566 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
570 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
571 take values, others take register numbers and manipulate the contents
573 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
576 env
->macc
[dest
] = env
->macc
[src
];
577 mask
= MACSR_PAV0
<< dest
;
578 if (env
->macsr
& (MACSR_PAV0
<< src
))
584 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
589 product
= (uint64_t)op1
* op2
;
590 res
= (product
<< 24) >> 24;
591 if (res
!= product
) {
592 env
->macsr
|= MACSR_V
;
593 if (env
->macsr
& MACSR_OMC
) {
594 /* Make sure the accumulate operation overflows. */
604 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
608 product
= (uint64_t)op1
* op2
;
609 if (product
& (0xffffffull
<< 40)) {
610 env
->macsr
|= MACSR_V
;
611 if (env
->macsr
& MACSR_OMC
) {
612 /* Make sure the accumulate operation overflows. */
615 product
&= ((1ull << 40) - 1);
621 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
626 product
= (uint64_t)op1
* op2
;
627 if (env
->macsr
& MACSR_RT
) {
628 remainder
= product
& 0xffffff;
630 if (remainder
> 0x800000)
632 else if (remainder
== 0x800000)
633 product
+= (product
& 1);
640 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
644 tmp
= env
->macc
[acc
];
645 result
= ((tmp
<< 16) >> 16);
647 env
->macsr
|= MACSR_V
;
649 if (env
->macsr
& MACSR_V
) {
650 env
->macsr
|= MACSR_PAV0
<< acc
;
651 if (env
->macsr
& MACSR_OMC
) {
652 /* The result is saturated to 32 bits, despite overflow occurring
653 at 48 bits. Seems weird, but that's what the hardware docs
655 result
= (result
>> 63) ^ 0x7fffffff;
658 env
->macc
[acc
] = result
;
661 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
665 val
= env
->macc
[acc
];
666 if (val
& (0xffffull
<< 48)) {
667 env
->macsr
|= MACSR_V
;
669 if (env
->macsr
& MACSR_V
) {
670 env
->macsr
|= MACSR_PAV0
<< acc
;
671 if (env
->macsr
& MACSR_OMC
) {
672 if (val
> (1ull << 53))
675 val
= (1ull << 48) - 1;
677 val
&= ((1ull << 48) - 1);
680 env
->macc
[acc
] = val
;
683 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
688 sum
= env
->macc
[acc
];
689 result
= (sum
<< 16) >> 16;
691 env
->macsr
|= MACSR_V
;
693 if (env
->macsr
& MACSR_V
) {
694 env
->macsr
|= MACSR_PAV0
<< acc
;
695 if (env
->macsr
& MACSR_OMC
) {
696 result
= (result
>> 63) ^ 0x7fffffffffffll
;
699 env
->macc
[acc
] = result
;
702 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
705 val
= env
->macc
[acc
];
707 env
->macsr
|= MACSR_Z
;
708 } else if (val
& (1ull << 47)) {
709 env
->macsr
|= MACSR_N
;
711 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
712 env
->macsr
|= MACSR_V
;
714 if (env
->macsr
& MACSR_FI
) {
715 val
= ((int64_t)val
) >> 40;
716 if (val
!= 0 && val
!= -1)
717 env
->macsr
|= MACSR_EV
;
718 } else if (env
->macsr
& MACSR_SU
) {
719 val
= ((int64_t)val
) >> 32;
720 if (val
!= 0 && val
!= -1)
721 env
->macsr
|= MACSR_EV
;
723 if ((val
>> 32) != 0)
724 env
->macsr
|= MACSR_EV
;
728 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
730 cpu_m68k_flush_flags(env
, cc_op
);
733 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
738 if (env
->macsr
& MACSR_SU
) {
739 /* 16-bit rounding. */
740 rem
= val
& 0xffffff;
741 val
= (val
>> 24) & 0xffffu
;
744 else if (rem
== 0x800000)
746 } else if (env
->macsr
& MACSR_RT
) {
747 /* 32-bit rounding. */
752 else if (rem
== 0x80)
758 if (env
->macsr
& MACSR_OMC
) {
760 if (env
->macsr
& MACSR_SU
) {
761 if (val
!= (uint16_t) val
) {
762 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
764 result
= val
& 0xffff;
767 if (val
!= (uint32_t)val
) {
768 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
770 result
= (uint32_t)val
;
775 if (env
->macsr
& MACSR_SU
) {
776 result
= val
& 0xffff;
778 result
= (uint32_t)val
;
784 uint32_t HELPER(get_macs
)(uint64_t val
)
786 if (val
== (int32_t)val
) {
789 return (val
>> 61) ^ ~SIGNBIT
;
793 uint32_t HELPER(get_macu
)(uint64_t val
)
795 if ((val
>> 32) == 0) {
796 return (uint32_t)val
;
802 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
805 val
= env
->macc
[acc
] & 0x00ff;
806 val
= (env
->macc
[acc
] >> 32) & 0xff00;
807 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
808 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
812 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
815 val
= (env
->macc
[acc
] >> 32) & 0xffff;
816 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
820 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
824 res
= env
->macc
[acc
] & 0xffffffff00ull
;
825 tmp
= (int16_t)(val
& 0xff00);
826 res
|= ((int64_t)tmp
) << 32;
828 env
->macc
[acc
] = res
;
829 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
830 tmp
= (val
& 0xff000000);
831 res
|= ((int64_t)tmp
) << 16;
832 res
|= (val
>> 16) & 0xff;
833 env
->macc
[acc
+ 1] = res
;
836 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
840 res
= (uint32_t)env
->macc
[acc
];
842 res
|= ((int64_t)tmp
) << 32;
843 env
->macc
[acc
] = res
;
844 res
= (uint32_t)env
->macc
[acc
+ 1];
845 tmp
= val
& 0xffff0000;
846 res
|= (int64_t)tmp
<< 16;
847 env
->macc
[acc
+ 1] = res
;
850 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
853 res
= (uint32_t)env
->macc
[acc
];
854 res
|= ((uint64_t)(val
& 0xffff)) << 32;
855 env
->macc
[acc
] = res
;
856 res
= (uint32_t)env
->macc
[acc
+ 1];
857 res
|= (uint64_t)(val
& 0xffff0000) << 16;
858 env
->macc
[acc
+ 1] = res
;