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(CPUM68KState
*env
, int level
, uint8_t vector
)
315 env
->pending_level
= level
;
316 env
->pending_vector
= vector
;
318 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
320 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
325 uint32_t HELPER(bitrev
)(uint32_t x
)
327 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
328 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
329 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
333 uint32_t HELPER(ff1
)(uint32_t x
)
341 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
343 /* The result has the opposite sign to the original value. */
345 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
349 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
354 old_flags
= env
->cc_dest
;
356 env
->cc_x
= (op1
<= op2
);
357 env
->cc_op
= CC_OP_SUBX
;
358 res
= op1
- (op2
+ 1);
360 env
->cc_x
= (op1
< op2
);
361 env
->cc_op
= CC_OP_SUB
;
366 cpu_m68k_flush_flags(env
, env
->cc_op
);
368 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
372 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
377 old_flags
= env
->cc_dest
;
380 env
->cc_x
= (res
<= op2
);
381 env
->cc_op
= CC_OP_ADDX
;
384 env
->cc_x
= (res
< op2
);
385 env
->cc_op
= CC_OP_ADD
;
389 cpu_m68k_flush_flags(env
, env
->cc_op
);
391 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
395 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
400 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
402 env
->sr
= val
& 0xffff;
406 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
414 cf
= env
->cc_src
& CCF_C
;
415 } else if (shift
< 32) {
416 result
= val
<< shift
;
417 cf
= (val
>> (32 - shift
)) & 1;
418 } else if (shift
== 32) {
421 } else /* shift > 32 */ {
426 env
->cc_x
= (cf
!= 0);
427 env
->cc_dest
= result
;
431 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
439 cf
= env
->cc_src
& CCF_C
;
440 } else if (shift
< 32) {
441 result
= val
>> shift
;
442 cf
= (val
>> (shift
- 1)) & 1;
443 } else if (shift
== 32) {
446 } else /* shift > 32 */ {
451 env
->cc_x
= (cf
!= 0);
452 env
->cc_dest
= result
;
456 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
464 cf
= (env
->cc_src
& CCF_C
) != 0;
465 } else if (shift
< 32) {
466 result
= (int32_t)val
>> shift
;
467 cf
= (val
>> (shift
- 1)) & 1;
468 } else /* shift >= 32 */ {
469 result
= (int32_t)val
>> 31;
474 env
->cc_dest
= result
;
479 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
481 return float64_to_int32(val
, &env
->fp_status
);
484 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
486 return float64_to_float32(val
, &env
->fp_status
);
489 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
491 return int32_to_float64(val
, &env
->fp_status
);
494 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
496 return float32_to_float64(val
, &env
->fp_status
);
499 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
501 return float64_round_to_int(val
, &env
->fp_status
);
504 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
506 return float64_trunc_to_int(val
, &env
->fp_status
);
509 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
511 return float64_sqrt(val
, &env
->fp_status
);
514 float64
HELPER(abs_f64
)(float64 val
)
516 return float64_abs(val
);
519 float64
HELPER(chs_f64
)(float64 val
)
521 return float64_chs(val
);
524 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
526 return float64_add(a
, b
, &env
->fp_status
);
529 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
531 return float64_sub(a
, b
, &env
->fp_status
);
534 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
536 return float64_mul(a
, b
, &env
->fp_status
);
539 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
541 return float64_div(a
, b
, &env
->fp_status
);
544 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
546 /* ??? This may incorrectly raise exceptions. */
547 /* ??? Should flush denormals to zero. */
549 res
= float64_sub(a
, b
, &env
->fp_status
);
550 if (float64_is_quiet_nan(res
)) {
551 /* +/-inf compares equal against itself, but sub returns nan. */
552 if (!float64_is_quiet_nan(a
)
553 && !float64_is_quiet_nan(b
)) {
555 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
556 res
= float64_chs(res
);
562 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
564 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
568 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
569 take values, others take register numbers and manipulate the contents
571 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
574 env
->macc
[dest
] = env
->macc
[src
];
575 mask
= MACSR_PAV0
<< dest
;
576 if (env
->macsr
& (MACSR_PAV0
<< src
))
582 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
587 product
= (uint64_t)op1
* op2
;
588 res
= (product
<< 24) >> 24;
589 if (res
!= product
) {
590 env
->macsr
|= MACSR_V
;
591 if (env
->macsr
& MACSR_OMC
) {
592 /* Make sure the accumulate operation overflows. */
602 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
606 product
= (uint64_t)op1
* op2
;
607 if (product
& (0xffffffull
<< 40)) {
608 env
->macsr
|= MACSR_V
;
609 if (env
->macsr
& MACSR_OMC
) {
610 /* Make sure the accumulate operation overflows. */
613 product
&= ((1ull << 40) - 1);
619 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
624 product
= (uint64_t)op1
* op2
;
625 if (env
->macsr
& MACSR_RT
) {
626 remainder
= product
& 0xffffff;
628 if (remainder
> 0x800000)
630 else if (remainder
== 0x800000)
631 product
+= (product
& 1);
638 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
642 tmp
= env
->macc
[acc
];
643 result
= ((tmp
<< 16) >> 16);
645 env
->macsr
|= MACSR_V
;
647 if (env
->macsr
& MACSR_V
) {
648 env
->macsr
|= MACSR_PAV0
<< acc
;
649 if (env
->macsr
& MACSR_OMC
) {
650 /* The result is saturated to 32 bits, despite overflow occurring
651 at 48 bits. Seems weird, but that's what the hardware docs
653 result
= (result
>> 63) ^ 0x7fffffff;
656 env
->macc
[acc
] = result
;
659 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
663 val
= env
->macc
[acc
];
664 if (val
& (0xffffull
<< 48)) {
665 env
->macsr
|= MACSR_V
;
667 if (env
->macsr
& MACSR_V
) {
668 env
->macsr
|= MACSR_PAV0
<< acc
;
669 if (env
->macsr
& MACSR_OMC
) {
670 if (val
> (1ull << 53))
673 val
= (1ull << 48) - 1;
675 val
&= ((1ull << 48) - 1);
678 env
->macc
[acc
] = val
;
681 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
686 sum
= env
->macc
[acc
];
687 result
= (sum
<< 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 result
= (result
>> 63) ^ 0x7fffffffffffll
;
697 env
->macc
[acc
] = result
;
700 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
703 val
= env
->macc
[acc
];
705 env
->macsr
|= MACSR_Z
;
706 } else if (val
& (1ull << 47)) {
707 env
->macsr
|= MACSR_N
;
709 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
710 env
->macsr
|= MACSR_V
;
712 if (env
->macsr
& MACSR_FI
) {
713 val
= ((int64_t)val
) >> 40;
714 if (val
!= 0 && val
!= -1)
715 env
->macsr
|= MACSR_EV
;
716 } else if (env
->macsr
& MACSR_SU
) {
717 val
= ((int64_t)val
) >> 32;
718 if (val
!= 0 && val
!= -1)
719 env
->macsr
|= MACSR_EV
;
721 if ((val
>> 32) != 0)
722 env
->macsr
|= MACSR_EV
;
726 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
728 cpu_m68k_flush_flags(env
, cc_op
);
731 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
736 if (env
->macsr
& MACSR_SU
) {
737 /* 16-bit rounding. */
738 rem
= val
& 0xffffff;
739 val
= (val
>> 24) & 0xffffu
;
742 else if (rem
== 0x800000)
744 } else if (env
->macsr
& MACSR_RT
) {
745 /* 32-bit rounding. */
750 else if (rem
== 0x80)
756 if (env
->macsr
& MACSR_OMC
) {
758 if (env
->macsr
& MACSR_SU
) {
759 if (val
!= (uint16_t) val
) {
760 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
762 result
= val
& 0xffff;
765 if (val
!= (uint32_t)val
) {
766 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
768 result
= (uint32_t)val
;
773 if (env
->macsr
& MACSR_SU
) {
774 result
= val
& 0xffff;
776 result
= (uint32_t)val
;
782 uint32_t HELPER(get_macs
)(uint64_t val
)
784 if (val
== (int32_t)val
) {
787 return (val
>> 61) ^ ~SIGNBIT
;
791 uint32_t HELPER(get_macu
)(uint64_t val
)
793 if ((val
>> 32) == 0) {
794 return (uint32_t)val
;
800 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
803 val
= env
->macc
[acc
] & 0x00ff;
804 val
= (env
->macc
[acc
] >> 32) & 0xff00;
805 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
806 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
810 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
813 val
= (env
->macc
[acc
] >> 32) & 0xffff;
814 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
818 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
822 res
= env
->macc
[acc
] & 0xffffffff00ull
;
823 tmp
= (int16_t)(val
& 0xff00);
824 res
|= ((int64_t)tmp
) << 32;
826 env
->macc
[acc
] = res
;
827 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
828 tmp
= (val
& 0xff000000);
829 res
|= ((int64_t)tmp
) << 16;
830 res
|= (val
>> 16) & 0xff;
831 env
->macc
[acc
+ 1] = res
;
834 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
838 res
= (uint32_t)env
->macc
[acc
];
840 res
|= ((int64_t)tmp
) << 32;
841 env
->macc
[acc
] = res
;
842 res
= (uint32_t)env
->macc
[acc
+ 1];
843 tmp
= val
& 0xffff0000;
844 res
|= (int64_t)tmp
<< 16;
845 env
->macc
[acc
+ 1] = res
;
848 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
851 res
= (uint32_t)env
->macc
[acc
];
852 res
|= ((uint64_t)(val
& 0xffff)) << 32;
853 env
->macc
[acc
] = res
;
854 res
= (uint32_t)env
->macc
[acc
+ 1];
855 res
|= (uint64_t)(val
& 0xffff0000) << 16;
856 env
->macc
[acc
+ 1] = res
;