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
);
123 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
124 gdb_register_coprocessor(env
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
125 11, "cf-fp.xml", 18);
127 /* TODO: Add [E]MAC registers. */
129 cpu_reset(ENV_GET_CPU(env
));
134 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
141 #define HIGHBIT 0x80000000u
143 #define SET_NZ(x) do { \
146 else if ((int32_t)(x) < 0) \
150 #define SET_FLAGS_SUB(type, utype) do { \
151 SET_NZ((type)dest); \
153 if ((utype) tmp < (utype) src) \
155 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
174 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
178 SET_FLAGS_SUB(int32_t, uint32_t);
181 SET_FLAGS_SUB(int8_t, uint8_t);
184 SET_FLAGS_SUB(int16_t, uint16_t);
190 tmp
= dest
- src
- 1;
191 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
196 tmp
= dest
+ src
+ 1;
199 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
208 cpu_abort(env
, "Bad CC_OP %d", cc_op
);
210 env
->cc_op
= CC_OP_FLAGS
;
211 env
->cc_dest
= flags
;
214 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
217 case 0x02: /* CACR */
221 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
222 /* TODO: Implement Access Control Registers. */
224 case 0x801: /* VBR */
227 /* TODO: Implement control registers. */
229 cpu_abort(env
, "Unimplemented control register write 0x%x = 0x%x\n",
234 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
241 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
242 for (i
= 0; i
< 4; i
++) {
243 regval
= env
->macc
[i
];
244 exthigh
= regval
>> 40;
245 if (env
->macsr
& MACSR_FI
) {
250 extlow
= regval
>> 32;
252 if (env
->macsr
& MACSR_FI
) {
253 regval
= (((uint64_t)acc
) << 8) | extlow
;
254 regval
|= ((int64_t)exthigh
) << 40;
255 } else if (env
->macsr
& MACSR_SU
) {
256 regval
= acc
| (((int64_t)extlow
) << 32);
257 regval
|= ((int64_t)exthigh
) << 40;
259 regval
= acc
| (((uint64_t)extlow
) << 32);
260 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
262 env
->macc
[i
] = regval
;
268 void m68k_switch_sp(CPUM68KState
*env
)
272 env
->sp
[env
->current_sp
] = env
->aregs
[7];
273 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
274 ? M68K_SSP
: M68K_USP
;
275 env
->aregs
[7] = env
->sp
[new_sp
];
276 env
->current_sp
= new_sp
;
279 #if defined(CONFIG_USER_ONLY)
281 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
284 env
->exception_index
= EXCP_ACCESS
;
285 env
->mmu
.ar
= address
;
293 /* TODO: This will need fixing once the MMU is implemented. */
294 hwaddr
cpu_get_phys_page_debug(CPUM68KState
*env
, target_ulong addr
)
299 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
304 address
&= TARGET_PAGE_MASK
;
305 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
306 tlb_set_page(env
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
310 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
311 be handled by the interrupt controller. Real hardware only requests
312 the vector when the interrupt is acknowledged by the CPU. For
313 simplicitly we calculate it when the interrupt is signalled. */
314 void m68k_set_irq_level(CPUM68KState
*env
, int level
, uint8_t vector
)
316 env
->pending_level
= level
;
317 env
->pending_vector
= vector
;
319 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
321 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
326 uint32_t HELPER(bitrev
)(uint32_t x
)
328 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
329 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
330 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
334 uint32_t HELPER(ff1
)(uint32_t x
)
342 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
344 /* The result has the opposite sign to the original value. */
346 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
350 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
355 old_flags
= env
->cc_dest
;
357 env
->cc_x
= (op1
<= op2
);
358 env
->cc_op
= CC_OP_SUBX
;
359 res
= op1
- (op2
+ 1);
361 env
->cc_x
= (op1
< op2
);
362 env
->cc_op
= CC_OP_SUB
;
367 cpu_m68k_flush_flags(env
, env
->cc_op
);
369 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
373 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
378 old_flags
= env
->cc_dest
;
381 env
->cc_x
= (res
<= op2
);
382 env
->cc_op
= CC_OP_ADDX
;
385 env
->cc_x
= (res
< op2
);
386 env
->cc_op
= CC_OP_ADD
;
390 cpu_m68k_flush_flags(env
, env
->cc_op
);
392 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
396 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
401 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
403 env
->sr
= val
& 0xffff;
407 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
415 cf
= env
->cc_src
& CCF_C
;
416 } else if (shift
< 32) {
417 result
= val
<< shift
;
418 cf
= (val
>> (32 - shift
)) & 1;
419 } else if (shift
== 32) {
422 } else /* shift > 32 */ {
427 env
->cc_x
= (cf
!= 0);
428 env
->cc_dest
= result
;
432 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
440 cf
= env
->cc_src
& CCF_C
;
441 } else if (shift
< 32) {
442 result
= val
>> shift
;
443 cf
= (val
>> (shift
- 1)) & 1;
444 } else if (shift
== 32) {
447 } else /* shift > 32 */ {
452 env
->cc_x
= (cf
!= 0);
453 env
->cc_dest
= result
;
457 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
465 cf
= (env
->cc_src
& CCF_C
) != 0;
466 } else if (shift
< 32) {
467 result
= (int32_t)val
>> shift
;
468 cf
= (val
>> (shift
- 1)) & 1;
469 } else /* shift >= 32 */ {
470 result
= (int32_t)val
>> 31;
475 env
->cc_dest
= result
;
480 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
482 return float64_to_int32(val
, &env
->fp_status
);
485 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
487 return float64_to_float32(val
, &env
->fp_status
);
490 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
492 return int32_to_float64(val
, &env
->fp_status
);
495 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
497 return float32_to_float64(val
, &env
->fp_status
);
500 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
502 return float64_round_to_int(val
, &env
->fp_status
);
505 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
507 return float64_trunc_to_int(val
, &env
->fp_status
);
510 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
512 return float64_sqrt(val
, &env
->fp_status
);
515 float64
HELPER(abs_f64
)(float64 val
)
517 return float64_abs(val
);
520 float64
HELPER(chs_f64
)(float64 val
)
522 return float64_chs(val
);
525 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
527 return float64_add(a
, b
, &env
->fp_status
);
530 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
532 return float64_sub(a
, b
, &env
->fp_status
);
535 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
537 return float64_mul(a
, b
, &env
->fp_status
);
540 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
542 return float64_div(a
, b
, &env
->fp_status
);
545 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
547 /* ??? This may incorrectly raise exceptions. */
548 /* ??? Should flush denormals to zero. */
550 res
= float64_sub(a
, b
, &env
->fp_status
);
551 if (float64_is_quiet_nan(res
)) {
552 /* +/-inf compares equal against itself, but sub returns nan. */
553 if (!float64_is_quiet_nan(a
)
554 && !float64_is_quiet_nan(b
)) {
556 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
557 res
= float64_chs(res
);
563 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
565 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
569 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
570 take values, others take register numbers and manipulate the contents
572 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
575 env
->macc
[dest
] = env
->macc
[src
];
576 mask
= MACSR_PAV0
<< dest
;
577 if (env
->macsr
& (MACSR_PAV0
<< src
))
583 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
588 product
= (uint64_t)op1
* op2
;
589 res
= (product
<< 24) >> 24;
590 if (res
!= product
) {
591 env
->macsr
|= MACSR_V
;
592 if (env
->macsr
& MACSR_OMC
) {
593 /* Make sure the accumulate operation overflows. */
603 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
607 product
= (uint64_t)op1
* op2
;
608 if (product
& (0xffffffull
<< 40)) {
609 env
->macsr
|= MACSR_V
;
610 if (env
->macsr
& MACSR_OMC
) {
611 /* Make sure the accumulate operation overflows. */
614 product
&= ((1ull << 40) - 1);
620 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
625 product
= (uint64_t)op1
* op2
;
626 if (env
->macsr
& MACSR_RT
) {
627 remainder
= product
& 0xffffff;
629 if (remainder
> 0x800000)
631 else if (remainder
== 0x800000)
632 product
+= (product
& 1);
639 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
643 tmp
= env
->macc
[acc
];
644 result
= ((tmp
<< 16) >> 16);
646 env
->macsr
|= MACSR_V
;
648 if (env
->macsr
& MACSR_V
) {
649 env
->macsr
|= MACSR_PAV0
<< acc
;
650 if (env
->macsr
& MACSR_OMC
) {
651 /* The result is saturated to 32 bits, despite overflow occurring
652 at 48 bits. Seems weird, but that's what the hardware docs
654 result
= (result
>> 63) ^ 0x7fffffff;
657 env
->macc
[acc
] = result
;
660 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
664 val
= env
->macc
[acc
];
665 if (val
& (0xffffull
<< 48)) {
666 env
->macsr
|= MACSR_V
;
668 if (env
->macsr
& MACSR_V
) {
669 env
->macsr
|= MACSR_PAV0
<< acc
;
670 if (env
->macsr
& MACSR_OMC
) {
671 if (val
> (1ull << 53))
674 val
= (1ull << 48) - 1;
676 val
&= ((1ull << 48) - 1);
679 env
->macc
[acc
] = val
;
682 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
687 sum
= env
->macc
[acc
];
688 result
= (sum
<< 16) >> 16;
690 env
->macsr
|= MACSR_V
;
692 if (env
->macsr
& MACSR_V
) {
693 env
->macsr
|= MACSR_PAV0
<< acc
;
694 if (env
->macsr
& MACSR_OMC
) {
695 result
= (result
>> 63) ^ 0x7fffffffffffll
;
698 env
->macc
[acc
] = result
;
701 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
704 val
= env
->macc
[acc
];
706 env
->macsr
|= MACSR_Z
;
707 } else if (val
& (1ull << 47)) {
708 env
->macsr
|= MACSR_N
;
710 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
711 env
->macsr
|= MACSR_V
;
713 if (env
->macsr
& MACSR_FI
) {
714 val
= ((int64_t)val
) >> 40;
715 if (val
!= 0 && val
!= -1)
716 env
->macsr
|= MACSR_EV
;
717 } else if (env
->macsr
& MACSR_SU
) {
718 val
= ((int64_t)val
) >> 32;
719 if (val
!= 0 && val
!= -1)
720 env
->macsr
|= MACSR_EV
;
722 if ((val
>> 32) != 0)
723 env
->macsr
|= MACSR_EV
;
727 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
729 cpu_m68k_flush_flags(env
, cc_op
);
732 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
737 if (env
->macsr
& MACSR_SU
) {
738 /* 16-bit rounding. */
739 rem
= val
& 0xffffff;
740 val
= (val
>> 24) & 0xffffu
;
743 else if (rem
== 0x800000)
745 } else if (env
->macsr
& MACSR_RT
) {
746 /* 32-bit rounding. */
751 else if (rem
== 0x80)
757 if (env
->macsr
& MACSR_OMC
) {
759 if (env
->macsr
& MACSR_SU
) {
760 if (val
!= (uint16_t) val
) {
761 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
763 result
= val
& 0xffff;
766 if (val
!= (uint32_t)val
) {
767 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
769 result
= (uint32_t)val
;
774 if (env
->macsr
& MACSR_SU
) {
775 result
= val
& 0xffff;
777 result
= (uint32_t)val
;
783 uint32_t HELPER(get_macs
)(uint64_t val
)
785 if (val
== (int32_t)val
) {
788 return (val
>> 61) ^ ~SIGNBIT
;
792 uint32_t HELPER(get_macu
)(uint64_t val
)
794 if ((val
>> 32) == 0) {
795 return (uint32_t)val
;
801 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
804 val
= env
->macc
[acc
] & 0x00ff;
805 val
= (env
->macc
[acc
] >> 32) & 0xff00;
806 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
807 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
811 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
814 val
= (env
->macc
[acc
] >> 32) & 0xffff;
815 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
819 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
823 res
= env
->macc
[acc
] & 0xffffffff00ull
;
824 tmp
= (int16_t)(val
& 0xff00);
825 res
|= ((int64_t)tmp
) << 32;
827 env
->macc
[acc
] = res
;
828 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
829 tmp
= (val
& 0xff000000);
830 res
|= ((int64_t)tmp
) << 16;
831 res
|= (val
>> 16) & 0xff;
832 env
->macc
[acc
+ 1] = res
;
835 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
839 res
= (uint32_t)env
->macc
[acc
];
841 res
|= ((int64_t)tmp
) << 32;
842 env
->macc
[acc
] = res
;
843 res
= (uint32_t)env
->macc
[acc
+ 1];
844 tmp
= val
& 0xffff0000;
845 res
|= (int64_t)tmp
<< 16;
846 env
->macc
[acc
+ 1] = res
;
849 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
852 res
= (uint32_t)env
->macc
[acc
];
853 res
|= ((uint64_t)(val
& 0xffff)) << 32;
854 env
->macc
[acc
] = res
;
855 res
= (uint32_t)env
->macc
[acc
+ 1];
856 res
|= (uint64_t)(val
& 0xffff0000) << 16;
857 env
->macc
[acc
+ 1] = res
;