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 CPUM68KState
*cpu_m68k_init(const char *cpu_model
)
108 oc
= cpu_class_by_name(TYPE_M68K_CPU
, cpu_model
);
112 cpu
= M68K_CPU(object_new(object_class_get_name(oc
)));
120 env
->cpu_model_str
= cpu_model
;
122 register_m68k_insns(env
);
124 object_property_set_bool(OBJECT(cpu
), true, "realized", NULL
);
129 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
131 CPUM68KState
*env
= &cpu
->env
;
133 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
134 gdb_register_coprocessor(env
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
135 11, "cf-fp.xml", 18);
137 /* TODO: Add [E]MAC registers. */
140 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
147 #define HIGHBIT 0x80000000u
149 #define SET_NZ(x) do { \
152 else if ((int32_t)(x) < 0) \
156 #define SET_FLAGS_SUB(type, utype) do { \
157 SET_NZ((type)dest); \
159 if ((utype) tmp < (utype) src) \
161 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
180 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
184 SET_FLAGS_SUB(int32_t, uint32_t);
187 SET_FLAGS_SUB(int8_t, uint8_t);
190 SET_FLAGS_SUB(int16_t, uint16_t);
196 tmp
= dest
- src
- 1;
197 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
202 tmp
= dest
+ src
+ 1;
205 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
214 cpu_abort(env
, "Bad CC_OP %d", cc_op
);
216 env
->cc_op
= CC_OP_FLAGS
;
217 env
->cc_dest
= flags
;
220 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
223 case 0x02: /* CACR */
227 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
228 /* TODO: Implement Access Control Registers. */
230 case 0x801: /* VBR */
233 /* TODO: Implement control registers. */
235 cpu_abort(env
, "Unimplemented control register write 0x%x = 0x%x\n",
240 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
247 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
248 for (i
= 0; i
< 4; i
++) {
249 regval
= env
->macc
[i
];
250 exthigh
= regval
>> 40;
251 if (env
->macsr
& MACSR_FI
) {
256 extlow
= regval
>> 32;
258 if (env
->macsr
& MACSR_FI
) {
259 regval
= (((uint64_t)acc
) << 8) | extlow
;
260 regval
|= ((int64_t)exthigh
) << 40;
261 } else if (env
->macsr
& MACSR_SU
) {
262 regval
= acc
| (((int64_t)extlow
) << 32);
263 regval
|= ((int64_t)exthigh
) << 40;
265 regval
= acc
| (((uint64_t)extlow
) << 32);
266 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
268 env
->macc
[i
] = regval
;
274 void m68k_switch_sp(CPUM68KState
*env
)
278 env
->sp
[env
->current_sp
] = env
->aregs
[7];
279 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
280 ? M68K_SSP
: M68K_USP
;
281 env
->aregs
[7] = env
->sp
[new_sp
];
282 env
->current_sp
= new_sp
;
285 #if defined(CONFIG_USER_ONLY)
287 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
290 env
->exception_index
= EXCP_ACCESS
;
291 env
->mmu
.ar
= address
;
299 /* TODO: This will need fixing once the MMU is implemented. */
300 hwaddr
cpu_get_phys_page_debug(CPUM68KState
*env
, target_ulong addr
)
305 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
310 address
&= TARGET_PAGE_MASK
;
311 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
312 tlb_set_page(env
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
316 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
317 be handled by the interrupt controller. Real hardware only requests
318 the vector when the interrupt is acknowledged by the CPU. For
319 simplicitly we calculate it when the interrupt is signalled. */
320 void m68k_set_irq_level(CPUM68KState
*env
, int level
, uint8_t vector
)
322 env
->pending_level
= level
;
323 env
->pending_vector
= vector
;
325 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
327 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
332 uint32_t HELPER(bitrev
)(uint32_t x
)
334 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
335 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
336 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
340 uint32_t HELPER(ff1
)(uint32_t x
)
348 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
350 /* The result has the opposite sign to the original value. */
352 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
356 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
361 old_flags
= env
->cc_dest
;
363 env
->cc_x
= (op1
<= op2
);
364 env
->cc_op
= CC_OP_SUBX
;
365 res
= op1
- (op2
+ 1);
367 env
->cc_x
= (op1
< op2
);
368 env
->cc_op
= CC_OP_SUB
;
373 cpu_m68k_flush_flags(env
, env
->cc_op
);
375 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
379 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
384 old_flags
= env
->cc_dest
;
387 env
->cc_x
= (res
<= op2
);
388 env
->cc_op
= CC_OP_ADDX
;
391 env
->cc_x
= (res
< op2
);
392 env
->cc_op
= CC_OP_ADD
;
396 cpu_m68k_flush_flags(env
, env
->cc_op
);
398 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
402 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
407 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
409 env
->sr
= val
& 0xffff;
413 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
421 cf
= env
->cc_src
& CCF_C
;
422 } else if (shift
< 32) {
423 result
= val
<< shift
;
424 cf
= (val
>> (32 - shift
)) & 1;
425 } else if (shift
== 32) {
428 } else /* shift > 32 */ {
433 env
->cc_x
= (cf
!= 0);
434 env
->cc_dest
= result
;
438 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
446 cf
= env
->cc_src
& CCF_C
;
447 } else if (shift
< 32) {
448 result
= val
>> shift
;
449 cf
= (val
>> (shift
- 1)) & 1;
450 } else if (shift
== 32) {
453 } else /* shift > 32 */ {
458 env
->cc_x
= (cf
!= 0);
459 env
->cc_dest
= result
;
463 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
471 cf
= (env
->cc_src
& CCF_C
) != 0;
472 } else if (shift
< 32) {
473 result
= (int32_t)val
>> shift
;
474 cf
= (val
>> (shift
- 1)) & 1;
475 } else /* shift >= 32 */ {
476 result
= (int32_t)val
>> 31;
481 env
->cc_dest
= result
;
486 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
488 return float64_to_int32(val
, &env
->fp_status
);
491 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
493 return float64_to_float32(val
, &env
->fp_status
);
496 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
498 return int32_to_float64(val
, &env
->fp_status
);
501 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
503 return float32_to_float64(val
, &env
->fp_status
);
506 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
508 return float64_round_to_int(val
, &env
->fp_status
);
511 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
513 return float64_trunc_to_int(val
, &env
->fp_status
);
516 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
518 return float64_sqrt(val
, &env
->fp_status
);
521 float64
HELPER(abs_f64
)(float64 val
)
523 return float64_abs(val
);
526 float64
HELPER(chs_f64
)(float64 val
)
528 return float64_chs(val
);
531 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
533 return float64_add(a
, b
, &env
->fp_status
);
536 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
538 return float64_sub(a
, b
, &env
->fp_status
);
541 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
543 return float64_mul(a
, b
, &env
->fp_status
);
546 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
548 return float64_div(a
, b
, &env
->fp_status
);
551 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
553 /* ??? This may incorrectly raise exceptions. */
554 /* ??? Should flush denormals to zero. */
556 res
= float64_sub(a
, b
, &env
->fp_status
);
557 if (float64_is_quiet_nan(res
)) {
558 /* +/-inf compares equal against itself, but sub returns nan. */
559 if (!float64_is_quiet_nan(a
)
560 && !float64_is_quiet_nan(b
)) {
562 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
563 res
= float64_chs(res
);
569 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
571 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
575 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
576 take values, others take register numbers and manipulate the contents
578 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
581 env
->macc
[dest
] = env
->macc
[src
];
582 mask
= MACSR_PAV0
<< dest
;
583 if (env
->macsr
& (MACSR_PAV0
<< src
))
589 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
594 product
= (uint64_t)op1
* op2
;
595 res
= (product
<< 24) >> 24;
596 if (res
!= product
) {
597 env
->macsr
|= MACSR_V
;
598 if (env
->macsr
& MACSR_OMC
) {
599 /* Make sure the accumulate operation overflows. */
609 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
613 product
= (uint64_t)op1
* op2
;
614 if (product
& (0xffffffull
<< 40)) {
615 env
->macsr
|= MACSR_V
;
616 if (env
->macsr
& MACSR_OMC
) {
617 /* Make sure the accumulate operation overflows. */
620 product
&= ((1ull << 40) - 1);
626 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
631 product
= (uint64_t)op1
* op2
;
632 if (env
->macsr
& MACSR_RT
) {
633 remainder
= product
& 0xffffff;
635 if (remainder
> 0x800000)
637 else if (remainder
== 0x800000)
638 product
+= (product
& 1);
645 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
649 tmp
= env
->macc
[acc
];
650 result
= ((tmp
<< 16) >> 16);
652 env
->macsr
|= MACSR_V
;
654 if (env
->macsr
& MACSR_V
) {
655 env
->macsr
|= MACSR_PAV0
<< acc
;
656 if (env
->macsr
& MACSR_OMC
) {
657 /* The result is saturated to 32 bits, despite overflow occurring
658 at 48 bits. Seems weird, but that's what the hardware docs
660 result
= (result
>> 63) ^ 0x7fffffff;
663 env
->macc
[acc
] = result
;
666 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
670 val
= env
->macc
[acc
];
671 if (val
& (0xffffull
<< 48)) {
672 env
->macsr
|= MACSR_V
;
674 if (env
->macsr
& MACSR_V
) {
675 env
->macsr
|= MACSR_PAV0
<< acc
;
676 if (env
->macsr
& MACSR_OMC
) {
677 if (val
> (1ull << 53))
680 val
= (1ull << 48) - 1;
682 val
&= ((1ull << 48) - 1);
685 env
->macc
[acc
] = val
;
688 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
693 sum
= env
->macc
[acc
];
694 result
= (sum
<< 16) >> 16;
696 env
->macsr
|= MACSR_V
;
698 if (env
->macsr
& MACSR_V
) {
699 env
->macsr
|= MACSR_PAV0
<< acc
;
700 if (env
->macsr
& MACSR_OMC
) {
701 result
= (result
>> 63) ^ 0x7fffffffffffll
;
704 env
->macc
[acc
] = result
;
707 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
710 val
= env
->macc
[acc
];
712 env
->macsr
|= MACSR_Z
;
713 } else if (val
& (1ull << 47)) {
714 env
->macsr
|= MACSR_N
;
716 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
717 env
->macsr
|= MACSR_V
;
719 if (env
->macsr
& MACSR_FI
) {
720 val
= ((int64_t)val
) >> 40;
721 if (val
!= 0 && val
!= -1)
722 env
->macsr
|= MACSR_EV
;
723 } else if (env
->macsr
& MACSR_SU
) {
724 val
= ((int64_t)val
) >> 32;
725 if (val
!= 0 && val
!= -1)
726 env
->macsr
|= MACSR_EV
;
728 if ((val
>> 32) != 0)
729 env
->macsr
|= MACSR_EV
;
733 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
735 cpu_m68k_flush_flags(env
, cc_op
);
738 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
743 if (env
->macsr
& MACSR_SU
) {
744 /* 16-bit rounding. */
745 rem
= val
& 0xffffff;
746 val
= (val
>> 24) & 0xffffu
;
749 else if (rem
== 0x800000)
751 } else if (env
->macsr
& MACSR_RT
) {
752 /* 32-bit rounding. */
757 else if (rem
== 0x80)
763 if (env
->macsr
& MACSR_OMC
) {
765 if (env
->macsr
& MACSR_SU
) {
766 if (val
!= (uint16_t) val
) {
767 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
769 result
= val
& 0xffff;
772 if (val
!= (uint32_t)val
) {
773 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
775 result
= (uint32_t)val
;
780 if (env
->macsr
& MACSR_SU
) {
781 result
= val
& 0xffff;
783 result
= (uint32_t)val
;
789 uint32_t HELPER(get_macs
)(uint64_t val
)
791 if (val
== (int32_t)val
) {
794 return (val
>> 61) ^ ~SIGNBIT
;
798 uint32_t HELPER(get_macu
)(uint64_t val
)
800 if ((val
>> 32) == 0) {
801 return (uint32_t)val
;
807 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
810 val
= env
->macc
[acc
] & 0x00ff;
811 val
= (env
->macc
[acc
] >> 32) & 0xff00;
812 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
813 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
817 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
820 val
= (env
->macc
[acc
] >> 32) & 0xffff;
821 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
825 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
829 res
= env
->macc
[acc
] & 0xffffffff00ull
;
830 tmp
= (int16_t)(val
& 0xff00);
831 res
|= ((int64_t)tmp
) << 32;
833 env
->macc
[acc
] = res
;
834 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
835 tmp
= (val
& 0xff000000);
836 res
|= ((int64_t)tmp
) << 16;
837 res
|= (val
>> 16) & 0xff;
838 env
->macc
[acc
+ 1] = res
;
841 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
845 res
= (uint32_t)env
->macc
[acc
];
847 res
|= ((int64_t)tmp
) << 32;
848 env
->macc
[acc
] = res
;
849 res
= (uint32_t)env
->macc
[acc
+ 1];
850 tmp
= val
& 0xffff0000;
851 res
|= (int64_t)tmp
<< 16;
852 env
->macc
[acc
+ 1] = res
;
855 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
858 res
= (uint32_t)env
->macc
[acc
];
859 res
|= ((uint64_t)(val
& 0xffff)) << 32;
860 env
->macc
[acc
] = res
;
861 res
= (uint32_t)env
->macc
[acc
+ 1];
862 res
|= (uint64_t)(val
& 0xffff0000) << 16;
863 env
->macc
[acc
+ 1] = res
;