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
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr 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 CPUState
*cs
= CPU(cpu
);
316 CPUM68KState
*env
= &cpu
->env
;
318 env
->pending_level
= level
;
319 env
->pending_vector
= vector
;
321 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
323 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
329 uint32_t HELPER(bitrev
)(uint32_t x
)
331 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
332 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
333 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
337 uint32_t HELPER(ff1
)(uint32_t x
)
345 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
347 /* The result has the opposite sign to the original value. */
349 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
353 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
358 old_flags
= env
->cc_dest
;
360 env
->cc_x
= (op1
<= op2
);
361 env
->cc_op
= CC_OP_SUBX
;
362 res
= op1
- (op2
+ 1);
364 env
->cc_x
= (op1
< op2
);
365 env
->cc_op
= CC_OP_SUB
;
370 cpu_m68k_flush_flags(env
, env
->cc_op
);
372 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
376 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
381 old_flags
= env
->cc_dest
;
384 env
->cc_x
= (res
<= op2
);
385 env
->cc_op
= CC_OP_ADDX
;
388 env
->cc_x
= (res
< op2
);
389 env
->cc_op
= CC_OP_ADD
;
393 cpu_m68k_flush_flags(env
, env
->cc_op
);
395 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
399 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
404 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
406 env
->sr
= val
& 0xffff;
410 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
418 cf
= env
->cc_src
& CCF_C
;
419 } else if (shift
< 32) {
420 result
= val
<< shift
;
421 cf
= (val
>> (32 - shift
)) & 1;
422 } else if (shift
== 32) {
425 } else /* shift > 32 */ {
430 env
->cc_x
= (cf
!= 0);
431 env
->cc_dest
= result
;
435 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
443 cf
= env
->cc_src
& CCF_C
;
444 } else if (shift
< 32) {
445 result
= val
>> shift
;
446 cf
= (val
>> (shift
- 1)) & 1;
447 } else if (shift
== 32) {
450 } else /* shift > 32 */ {
455 env
->cc_x
= (cf
!= 0);
456 env
->cc_dest
= result
;
460 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
468 cf
= (env
->cc_src
& CCF_C
) != 0;
469 } else if (shift
< 32) {
470 result
= (int32_t)val
>> shift
;
471 cf
= (val
>> (shift
- 1)) & 1;
472 } else /* shift >= 32 */ {
473 result
= (int32_t)val
>> 31;
478 env
->cc_dest
= result
;
483 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
485 return float64_to_int32(val
, &env
->fp_status
);
488 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
490 return float64_to_float32(val
, &env
->fp_status
);
493 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
495 return int32_to_float64(val
, &env
->fp_status
);
498 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
500 return float32_to_float64(val
, &env
->fp_status
);
503 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
505 return float64_round_to_int(val
, &env
->fp_status
);
508 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
510 return float64_trunc_to_int(val
, &env
->fp_status
);
513 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
515 return float64_sqrt(val
, &env
->fp_status
);
518 float64
HELPER(abs_f64
)(float64 val
)
520 return float64_abs(val
);
523 float64
HELPER(chs_f64
)(float64 val
)
525 return float64_chs(val
);
528 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
530 return float64_add(a
, b
, &env
->fp_status
);
533 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
535 return float64_sub(a
, b
, &env
->fp_status
);
538 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
540 return float64_mul(a
, b
, &env
->fp_status
);
543 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
545 return float64_div(a
, b
, &env
->fp_status
);
548 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
550 /* ??? This may incorrectly raise exceptions. */
551 /* ??? Should flush denormals to zero. */
553 res
= float64_sub(a
, b
, &env
->fp_status
);
554 if (float64_is_quiet_nan(res
)) {
555 /* +/-inf compares equal against itself, but sub returns nan. */
556 if (!float64_is_quiet_nan(a
)
557 && !float64_is_quiet_nan(b
)) {
559 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
560 res
= float64_chs(res
);
566 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
568 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
572 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
573 take values, others take register numbers and manipulate the contents
575 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
578 env
->macc
[dest
] = env
->macc
[src
];
579 mask
= MACSR_PAV0
<< dest
;
580 if (env
->macsr
& (MACSR_PAV0
<< src
))
586 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
591 product
= (uint64_t)op1
* op2
;
592 res
= (product
<< 24) >> 24;
593 if (res
!= product
) {
594 env
->macsr
|= MACSR_V
;
595 if (env
->macsr
& MACSR_OMC
) {
596 /* Make sure the accumulate operation overflows. */
606 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
610 product
= (uint64_t)op1
* op2
;
611 if (product
& (0xffffffull
<< 40)) {
612 env
->macsr
|= MACSR_V
;
613 if (env
->macsr
& MACSR_OMC
) {
614 /* Make sure the accumulate operation overflows. */
617 product
&= ((1ull << 40) - 1);
623 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
628 product
= (uint64_t)op1
* op2
;
629 if (env
->macsr
& MACSR_RT
) {
630 remainder
= product
& 0xffffff;
632 if (remainder
> 0x800000)
634 else if (remainder
== 0x800000)
635 product
+= (product
& 1);
642 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
646 tmp
= env
->macc
[acc
];
647 result
= ((tmp
<< 16) >> 16);
649 env
->macsr
|= MACSR_V
;
651 if (env
->macsr
& MACSR_V
) {
652 env
->macsr
|= MACSR_PAV0
<< acc
;
653 if (env
->macsr
& MACSR_OMC
) {
654 /* The result is saturated to 32 bits, despite overflow occurring
655 at 48 bits. Seems weird, but that's what the hardware docs
657 result
= (result
>> 63) ^ 0x7fffffff;
660 env
->macc
[acc
] = result
;
663 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
667 val
= env
->macc
[acc
];
668 if (val
& (0xffffull
<< 48)) {
669 env
->macsr
|= MACSR_V
;
671 if (env
->macsr
& MACSR_V
) {
672 env
->macsr
|= MACSR_PAV0
<< acc
;
673 if (env
->macsr
& MACSR_OMC
) {
674 if (val
> (1ull << 53))
677 val
= (1ull << 48) - 1;
679 val
&= ((1ull << 48) - 1);
682 env
->macc
[acc
] = val
;
685 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
690 sum
= env
->macc
[acc
];
691 result
= (sum
<< 16) >> 16;
693 env
->macsr
|= MACSR_V
;
695 if (env
->macsr
& MACSR_V
) {
696 env
->macsr
|= MACSR_PAV0
<< acc
;
697 if (env
->macsr
& MACSR_OMC
) {
698 result
= (result
>> 63) ^ 0x7fffffffffffll
;
701 env
->macc
[acc
] = result
;
704 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
707 val
= env
->macc
[acc
];
709 env
->macsr
|= MACSR_Z
;
710 } else if (val
& (1ull << 47)) {
711 env
->macsr
|= MACSR_N
;
713 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
714 env
->macsr
|= MACSR_V
;
716 if (env
->macsr
& MACSR_FI
) {
717 val
= ((int64_t)val
) >> 40;
718 if (val
!= 0 && val
!= -1)
719 env
->macsr
|= MACSR_EV
;
720 } else if (env
->macsr
& MACSR_SU
) {
721 val
= ((int64_t)val
) >> 32;
722 if (val
!= 0 && val
!= -1)
723 env
->macsr
|= MACSR_EV
;
725 if ((val
>> 32) != 0)
726 env
->macsr
|= MACSR_EV
;
730 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
732 cpu_m68k_flush_flags(env
, cc_op
);
735 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
740 if (env
->macsr
& MACSR_SU
) {
741 /* 16-bit rounding. */
742 rem
= val
& 0xffffff;
743 val
= (val
>> 24) & 0xffffu
;
746 else if (rem
== 0x800000)
748 } else if (env
->macsr
& MACSR_RT
) {
749 /* 32-bit rounding. */
754 else if (rem
== 0x80)
760 if (env
->macsr
& MACSR_OMC
) {
762 if (env
->macsr
& MACSR_SU
) {
763 if (val
!= (uint16_t) val
) {
764 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
766 result
= val
& 0xffff;
769 if (val
!= (uint32_t)val
) {
770 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
772 result
= (uint32_t)val
;
777 if (env
->macsr
& MACSR_SU
) {
778 result
= val
& 0xffff;
780 result
= (uint32_t)val
;
786 uint32_t HELPER(get_macs
)(uint64_t val
)
788 if (val
== (int32_t)val
) {
791 return (val
>> 61) ^ ~SIGNBIT
;
795 uint32_t HELPER(get_macu
)(uint64_t val
)
797 if ((val
>> 32) == 0) {
798 return (uint32_t)val
;
804 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
807 val
= env
->macc
[acc
] & 0x00ff;
808 val
= (env
->macc
[acc
] >> 32) & 0xff00;
809 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
810 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
814 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
817 val
= (env
->macc
[acc
] >> 32) & 0xffff;
818 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
822 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
826 res
= env
->macc
[acc
] & 0xffffffff00ull
;
827 tmp
= (int16_t)(val
& 0xff00);
828 res
|= ((int64_t)tmp
) << 32;
830 env
->macc
[acc
] = res
;
831 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
832 tmp
= (val
& 0xff000000);
833 res
|= ((int64_t)tmp
) << 16;
834 res
|= (val
>> 16) & 0xff;
835 env
->macc
[acc
+ 1] = res
;
838 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
842 res
= (uint32_t)env
->macc
[acc
];
844 res
|= ((int64_t)tmp
) << 32;
845 env
->macc
[acc
] = res
;
846 res
= (uint32_t)env
->macc
[acc
+ 1];
847 tmp
= val
& 0xffff0000;
848 res
|= (int64_t)tmp
<< 16;
849 env
->macc
[acc
+ 1] = res
;
852 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
855 res
= (uint32_t)env
->macc
[acc
];
856 res
|= ((uint64_t)(val
& 0xffff)) << 32;
857 env
->macc
[acc
] = res
;
858 res
= (uint32_t)env
->macc
[acc
+ 1];
859 res
|= (uint64_t)(val
& 0xffff0000) << 16;
860 env
->macc
[acc
+ 1] = res
;