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") == 0) {
39 } else if (strcmp(name_b
, "any") == 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
;
51 (*s
->cpu_fprintf
)(s
->file
, "%s\n",
52 object_class_get_name(c
));
55 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
59 .cpu_fprintf
= cpu_fprintf
,
63 list
= object_class_get_list(TYPE_M68K_CPU
, false);
64 list
= g_slist_sort(list
, m68k_cpu_list_compare
);
65 g_slist_foreach(list
, m68k_cpu_list_entry
, &s
);
69 static int fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
72 stfq_p(mem_buf
, env
->fregs
[n
]);
76 /* FP control registers (not implemented) */
77 memset(mem_buf
, 0, 4);
83 static int fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
86 env
->fregs
[n
] = ldfq_p(mem_buf
);
90 /* FP control registers (not implemented) */
96 CPUM68KState
*cpu_m68k_init(const char *cpu_model
)
103 oc
= cpu_class_by_name(TYPE_M68K_CPU
, cpu_model
);
107 cpu
= M68K_CPU(object_new(object_class_get_name(oc
)));
115 env
->cpu_model_str
= cpu_model
;
117 register_m68k_insns(env
);
118 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
119 gdb_register_coprocessor(env
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
120 11, "cf-fp.xml", 18);
122 /* TODO: Add [E]MAC registers. */
124 cpu_reset(ENV_GET_CPU(env
));
129 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
136 #define HIGHBIT 0x80000000u
138 #define SET_NZ(x) do { \
141 else if ((int32_t)(x) < 0) \
145 #define SET_FLAGS_SUB(type, utype) do { \
146 SET_NZ((type)dest); \
148 if ((utype) tmp < (utype) src) \
150 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
169 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
173 SET_FLAGS_SUB(int32_t, uint32_t);
176 SET_FLAGS_SUB(int8_t, uint8_t);
179 SET_FLAGS_SUB(int16_t, uint16_t);
185 tmp
= dest
- src
- 1;
186 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
191 tmp
= dest
+ src
+ 1;
194 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
203 cpu_abort(env
, "Bad CC_OP %d", cc_op
);
205 env
->cc_op
= CC_OP_FLAGS
;
206 env
->cc_dest
= flags
;
209 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
212 case 0x02: /* CACR */
216 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
217 /* TODO: Implement Access Control Registers. */
219 case 0x801: /* VBR */
222 /* TODO: Implement control registers. */
224 cpu_abort(env
, "Unimplemented control register write 0x%x = 0x%x\n",
229 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
236 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
237 for (i
= 0; i
< 4; i
++) {
238 regval
= env
->macc
[i
];
239 exthigh
= regval
>> 40;
240 if (env
->macsr
& MACSR_FI
) {
245 extlow
= regval
>> 32;
247 if (env
->macsr
& MACSR_FI
) {
248 regval
= (((uint64_t)acc
) << 8) | extlow
;
249 regval
|= ((int64_t)exthigh
) << 40;
250 } else if (env
->macsr
& MACSR_SU
) {
251 regval
= acc
| (((int64_t)extlow
) << 32);
252 regval
|= ((int64_t)exthigh
) << 40;
254 regval
= acc
| (((uint64_t)extlow
) << 32);
255 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
257 env
->macc
[i
] = regval
;
263 void m68k_switch_sp(CPUM68KState
*env
)
267 env
->sp
[env
->current_sp
] = env
->aregs
[7];
268 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
269 ? M68K_SSP
: M68K_USP
;
270 env
->aregs
[7] = env
->sp
[new_sp
];
271 env
->current_sp
= new_sp
;
274 #if defined(CONFIG_USER_ONLY)
276 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
279 env
->exception_index
= EXCP_ACCESS
;
280 env
->mmu
.ar
= address
;
288 /* TODO: This will need fixing once the MMU is implemented. */
289 hwaddr
cpu_get_phys_page_debug(CPUM68KState
*env
, target_ulong addr
)
294 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
299 address
&= TARGET_PAGE_MASK
;
300 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
301 tlb_set_page(env
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
305 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
306 be handled by the interrupt controller. Real hardware only requests
307 the vector when the interrupt is acknowledged by the CPU. For
308 simplicitly we calculate it when the interrupt is signalled. */
309 void m68k_set_irq_level(CPUM68KState
*env
, int level
, uint8_t vector
)
311 env
->pending_level
= level
;
312 env
->pending_vector
= vector
;
314 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
316 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
321 uint32_t HELPER(bitrev
)(uint32_t x
)
323 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
324 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
325 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
329 uint32_t HELPER(ff1
)(uint32_t x
)
337 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
339 /* The result has the opposite sign to the original value. */
341 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
345 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
350 old_flags
= env
->cc_dest
;
352 env
->cc_x
= (op1
<= op2
);
353 env
->cc_op
= CC_OP_SUBX
;
354 res
= op1
- (op2
+ 1);
356 env
->cc_x
= (op1
< op2
);
357 env
->cc_op
= CC_OP_SUB
;
362 cpu_m68k_flush_flags(env
, env
->cc_op
);
364 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
368 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
373 old_flags
= env
->cc_dest
;
376 env
->cc_x
= (res
<= op2
);
377 env
->cc_op
= CC_OP_ADDX
;
380 env
->cc_x
= (res
< op2
);
381 env
->cc_op
= CC_OP_ADD
;
385 cpu_m68k_flush_flags(env
, env
->cc_op
);
387 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
391 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
396 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
398 env
->sr
= val
& 0xffff;
402 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
410 cf
= env
->cc_src
& CCF_C
;
411 } else if (shift
< 32) {
412 result
= val
<< shift
;
413 cf
= (val
>> (32 - shift
)) & 1;
414 } else if (shift
== 32) {
417 } else /* shift > 32 */ {
422 env
->cc_x
= (cf
!= 0);
423 env
->cc_dest
= result
;
427 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
435 cf
= env
->cc_src
& CCF_C
;
436 } else if (shift
< 32) {
437 result
= val
>> shift
;
438 cf
= (val
>> (shift
- 1)) & 1;
439 } else if (shift
== 32) {
442 } else /* shift > 32 */ {
447 env
->cc_x
= (cf
!= 0);
448 env
->cc_dest
= result
;
452 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
460 cf
= (env
->cc_src
& CCF_C
) != 0;
461 } else if (shift
< 32) {
462 result
= (int32_t)val
>> shift
;
463 cf
= (val
>> (shift
- 1)) & 1;
464 } else /* shift >= 32 */ {
465 result
= (int32_t)val
>> 31;
470 env
->cc_dest
= result
;
475 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
477 return float64_to_int32(val
, &env
->fp_status
);
480 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
482 return float64_to_float32(val
, &env
->fp_status
);
485 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
487 return int32_to_float64(val
, &env
->fp_status
);
490 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
492 return float32_to_float64(val
, &env
->fp_status
);
495 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
497 return float64_round_to_int(val
, &env
->fp_status
);
500 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
502 return float64_trunc_to_int(val
, &env
->fp_status
);
505 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
507 return float64_sqrt(val
, &env
->fp_status
);
510 float64
HELPER(abs_f64
)(float64 val
)
512 return float64_abs(val
);
515 float64
HELPER(chs_f64
)(float64 val
)
517 return float64_chs(val
);
520 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
522 return float64_add(a
, b
, &env
->fp_status
);
525 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
527 return float64_sub(a
, b
, &env
->fp_status
);
530 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
532 return float64_mul(a
, b
, &env
->fp_status
);
535 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
537 return float64_div(a
, b
, &env
->fp_status
);
540 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
542 /* ??? This may incorrectly raise exceptions. */
543 /* ??? Should flush denormals to zero. */
545 res
= float64_sub(a
, b
, &env
->fp_status
);
546 if (float64_is_quiet_nan(res
)) {
547 /* +/-inf compares equal against itself, but sub returns nan. */
548 if (!float64_is_quiet_nan(a
)
549 && !float64_is_quiet_nan(b
)) {
551 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
552 res
= float64_chs(res
);
558 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
560 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
564 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
565 take values, others take register numbers and manipulate the contents
567 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
570 env
->macc
[dest
] = env
->macc
[src
];
571 mask
= MACSR_PAV0
<< dest
;
572 if (env
->macsr
& (MACSR_PAV0
<< src
))
578 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
583 product
= (uint64_t)op1
* op2
;
584 res
= (product
<< 24) >> 24;
585 if (res
!= product
) {
586 env
->macsr
|= MACSR_V
;
587 if (env
->macsr
& MACSR_OMC
) {
588 /* Make sure the accumulate operation overflows. */
598 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
602 product
= (uint64_t)op1
* op2
;
603 if (product
& (0xffffffull
<< 40)) {
604 env
->macsr
|= MACSR_V
;
605 if (env
->macsr
& MACSR_OMC
) {
606 /* Make sure the accumulate operation overflows. */
609 product
&= ((1ull << 40) - 1);
615 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
620 product
= (uint64_t)op1
* op2
;
621 if (env
->macsr
& MACSR_RT
) {
622 remainder
= product
& 0xffffff;
624 if (remainder
> 0x800000)
626 else if (remainder
== 0x800000)
627 product
+= (product
& 1);
634 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
638 tmp
= env
->macc
[acc
];
639 result
= ((tmp
<< 16) >> 16);
641 env
->macsr
|= MACSR_V
;
643 if (env
->macsr
& MACSR_V
) {
644 env
->macsr
|= MACSR_PAV0
<< acc
;
645 if (env
->macsr
& MACSR_OMC
) {
646 /* The result is saturated to 32 bits, despite overflow occurring
647 at 48 bits. Seems weird, but that's what the hardware docs
649 result
= (result
>> 63) ^ 0x7fffffff;
652 env
->macc
[acc
] = result
;
655 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
659 val
= env
->macc
[acc
];
660 if (val
& (0xffffull
<< 48)) {
661 env
->macsr
|= MACSR_V
;
663 if (env
->macsr
& MACSR_V
) {
664 env
->macsr
|= MACSR_PAV0
<< acc
;
665 if (env
->macsr
& MACSR_OMC
) {
666 if (val
> (1ull << 53))
669 val
= (1ull << 48) - 1;
671 val
&= ((1ull << 48) - 1);
674 env
->macc
[acc
] = val
;
677 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
682 sum
= env
->macc
[acc
];
683 result
= (sum
<< 16) >> 16;
685 env
->macsr
|= MACSR_V
;
687 if (env
->macsr
& MACSR_V
) {
688 env
->macsr
|= MACSR_PAV0
<< acc
;
689 if (env
->macsr
& MACSR_OMC
) {
690 result
= (result
>> 63) ^ 0x7fffffffffffll
;
693 env
->macc
[acc
] = result
;
696 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
699 val
= env
->macc
[acc
];
701 env
->macsr
|= MACSR_Z
;
702 } else if (val
& (1ull << 47)) {
703 env
->macsr
|= MACSR_N
;
705 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
706 env
->macsr
|= MACSR_V
;
708 if (env
->macsr
& MACSR_FI
) {
709 val
= ((int64_t)val
) >> 40;
710 if (val
!= 0 && val
!= -1)
711 env
->macsr
|= MACSR_EV
;
712 } else if (env
->macsr
& MACSR_SU
) {
713 val
= ((int64_t)val
) >> 32;
714 if (val
!= 0 && val
!= -1)
715 env
->macsr
|= MACSR_EV
;
717 if ((val
>> 32) != 0)
718 env
->macsr
|= MACSR_EV
;
722 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
724 cpu_m68k_flush_flags(env
, cc_op
);
727 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
732 if (env
->macsr
& MACSR_SU
) {
733 /* 16-bit rounding. */
734 rem
= val
& 0xffffff;
735 val
= (val
>> 24) & 0xffffu
;
738 else if (rem
== 0x800000)
740 } else if (env
->macsr
& MACSR_RT
) {
741 /* 32-bit rounding. */
746 else if (rem
== 0x80)
752 if (env
->macsr
& MACSR_OMC
) {
754 if (env
->macsr
& MACSR_SU
) {
755 if (val
!= (uint16_t) val
) {
756 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
758 result
= val
& 0xffff;
761 if (val
!= (uint32_t)val
) {
762 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
764 result
= (uint32_t)val
;
769 if (env
->macsr
& MACSR_SU
) {
770 result
= val
& 0xffff;
772 result
= (uint32_t)val
;
778 uint32_t HELPER(get_macs
)(uint64_t val
)
780 if (val
== (int32_t)val
) {
783 return (val
>> 61) ^ ~SIGNBIT
;
787 uint32_t HELPER(get_macu
)(uint64_t val
)
789 if ((val
>> 32) == 0) {
790 return (uint32_t)val
;
796 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
799 val
= env
->macc
[acc
] & 0x00ff;
800 val
= (env
->macc
[acc
] >> 32) & 0xff00;
801 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
802 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
806 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
809 val
= (env
->macc
[acc
] >> 32) & 0xffff;
810 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
814 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
818 res
= env
->macc
[acc
] & 0xffffffff00ull
;
819 tmp
= (int16_t)(val
& 0xff00);
820 res
|= ((int64_t)tmp
) << 32;
822 env
->macc
[acc
] = res
;
823 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
824 tmp
= (val
& 0xff000000);
825 res
|= ((int64_t)tmp
) << 16;
826 res
|= (val
>> 16) & 0xff;
827 env
->macc
[acc
+ 1] = res
;
830 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
834 res
= (uint32_t)env
->macc
[acc
];
836 res
|= ((int64_t)tmp
) << 32;
837 env
->macc
[acc
] = res
;
838 res
= (uint32_t)env
->macc
[acc
+ 1];
839 tmp
= val
& 0xffff0000;
840 res
|= (int64_t)tmp
<< 16;
841 env
->macc
[acc
+ 1] = res
;
844 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
847 res
= (uint32_t)env
->macc
[acc
];
848 res
|= ((uint64_t)(val
& 0xffff)) << 32;
849 env
->macc
[acc
] = res
;
850 res
= (uint32_t)env
->macc
[acc
+ 1];
851 res
|= (uint64_t)(val
& 0xffff0000) << 16;
852 env
->macc
[acc
+ 1] = res
;