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/>.
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
)
102 if (object_class_by_name(cpu_model
) == NULL
) {
105 cpu
= M68K_CPU(object_new(cpu_model
));
113 env
->cpu_model_str
= cpu_model
;
115 register_m68k_insns(env
);
116 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
117 gdb_register_coprocessor(env
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
118 11, "cf-fp.xml", 18);
120 /* TODO: Add [E]MAC registers. */
122 cpu_reset(ENV_GET_CPU(env
));
127 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
134 #define HIGHBIT 0x80000000u
136 #define SET_NZ(x) do { \
139 else if ((int32_t)(x) < 0) \
143 #define SET_FLAGS_SUB(type, utype) do { \
144 SET_NZ((type)dest); \
146 if ((utype) tmp < (utype) src) \
148 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
167 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
171 SET_FLAGS_SUB(int32_t, uint32_t);
174 SET_FLAGS_SUB(int8_t, uint8_t);
177 SET_FLAGS_SUB(int16_t, uint16_t);
183 tmp
= dest
- src
- 1;
184 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
189 tmp
= dest
+ src
+ 1;
192 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
201 cpu_abort(env
, "Bad CC_OP %d", cc_op
);
203 env
->cc_op
= CC_OP_FLAGS
;
204 env
->cc_dest
= flags
;
207 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
210 case 0x02: /* CACR */
214 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
215 /* TODO: Implement Access Control Registers. */
217 case 0x801: /* VBR */
220 /* TODO: Implement control registers. */
222 cpu_abort(env
, "Unimplemented control register write 0x%x = 0x%x\n",
227 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
234 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
235 for (i
= 0; i
< 4; i
++) {
236 regval
= env
->macc
[i
];
237 exthigh
= regval
>> 40;
238 if (env
->macsr
& MACSR_FI
) {
243 extlow
= regval
>> 32;
245 if (env
->macsr
& MACSR_FI
) {
246 regval
= (((uint64_t)acc
) << 8) | extlow
;
247 regval
|= ((int64_t)exthigh
) << 40;
248 } else if (env
->macsr
& MACSR_SU
) {
249 regval
= acc
| (((int64_t)extlow
) << 32);
250 regval
|= ((int64_t)exthigh
) << 40;
252 regval
= acc
| (((uint64_t)extlow
) << 32);
253 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
255 env
->macc
[i
] = regval
;
261 void m68k_switch_sp(CPUM68KState
*env
)
265 env
->sp
[env
->current_sp
] = env
->aregs
[7];
266 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
267 ? M68K_SSP
: M68K_USP
;
268 env
->aregs
[7] = env
->sp
[new_sp
];
269 env
->current_sp
= new_sp
;
272 #if defined(CONFIG_USER_ONLY)
274 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
277 env
->exception_index
= EXCP_ACCESS
;
278 env
->mmu
.ar
= address
;
286 /* TODO: This will need fixing once the MMU is implemented. */
287 hwaddr
cpu_get_phys_page_debug(CPUM68KState
*env
, target_ulong addr
)
292 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
297 address
&= TARGET_PAGE_MASK
;
298 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
299 tlb_set_page(env
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
303 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
304 be handled by the interrupt controller. Real hardware only requests
305 the vector when the interrupt is acknowledged by the CPU. For
306 simplicitly we calculate it when the interrupt is signalled. */
307 void m68k_set_irq_level(CPUM68KState
*env
, int level
, uint8_t vector
)
309 env
->pending_level
= level
;
310 env
->pending_vector
= vector
;
312 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
314 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
319 uint32_t HELPER(bitrev
)(uint32_t x
)
321 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
322 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
323 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
327 uint32_t HELPER(ff1
)(uint32_t x
)
335 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
337 /* The result has the opposite sign to the original value. */
339 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
343 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
348 old_flags
= env
->cc_dest
;
350 env
->cc_x
= (op1
<= op2
);
351 env
->cc_op
= CC_OP_SUBX
;
352 res
= op1
- (op2
+ 1);
354 env
->cc_x
= (op1
< op2
);
355 env
->cc_op
= CC_OP_SUB
;
360 cpu_m68k_flush_flags(env
, env
->cc_op
);
362 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
366 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
371 old_flags
= env
->cc_dest
;
374 env
->cc_x
= (res
<= op2
);
375 env
->cc_op
= CC_OP_ADDX
;
378 env
->cc_x
= (res
< op2
);
379 env
->cc_op
= CC_OP_ADD
;
383 cpu_m68k_flush_flags(env
, env
->cc_op
);
385 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
389 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
394 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
396 env
->sr
= val
& 0xffff;
400 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
408 cf
= env
->cc_src
& CCF_C
;
409 } else if (shift
< 32) {
410 result
= val
<< shift
;
411 cf
= (val
>> (32 - shift
)) & 1;
412 } else if (shift
== 32) {
415 } else /* shift > 32 */ {
420 env
->cc_x
= (cf
!= 0);
421 env
->cc_dest
= result
;
425 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
433 cf
= env
->cc_src
& CCF_C
;
434 } else if (shift
< 32) {
435 result
= val
>> shift
;
436 cf
= (val
>> (shift
- 1)) & 1;
437 } else if (shift
== 32) {
440 } else /* shift > 32 */ {
445 env
->cc_x
= (cf
!= 0);
446 env
->cc_dest
= result
;
450 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
458 cf
= (env
->cc_src
& CCF_C
) != 0;
459 } else if (shift
< 32) {
460 result
= (int32_t)val
>> shift
;
461 cf
= (val
>> (shift
- 1)) & 1;
462 } else /* shift >= 32 */ {
463 result
= (int32_t)val
>> 31;
468 env
->cc_dest
= result
;
473 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
475 return float64_to_int32(val
, &env
->fp_status
);
478 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
480 return float64_to_float32(val
, &env
->fp_status
);
483 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
485 return int32_to_float64(val
, &env
->fp_status
);
488 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
490 return float32_to_float64(val
, &env
->fp_status
);
493 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
495 return float64_round_to_int(val
, &env
->fp_status
);
498 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
500 return float64_trunc_to_int(val
, &env
->fp_status
);
503 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
505 return float64_sqrt(val
, &env
->fp_status
);
508 float64
HELPER(abs_f64
)(float64 val
)
510 return float64_abs(val
);
513 float64
HELPER(chs_f64
)(float64 val
)
515 return float64_chs(val
);
518 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
520 return float64_add(a
, b
, &env
->fp_status
);
523 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
525 return float64_sub(a
, b
, &env
->fp_status
);
528 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
530 return float64_mul(a
, b
, &env
->fp_status
);
533 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
535 return float64_div(a
, b
, &env
->fp_status
);
538 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
540 /* ??? This may incorrectly raise exceptions. */
541 /* ??? Should flush denormals to zero. */
543 res
= float64_sub(a
, b
, &env
->fp_status
);
544 if (float64_is_quiet_nan(res
)) {
545 /* +/-inf compares equal against itself, but sub returns nan. */
546 if (!float64_is_quiet_nan(a
)
547 && !float64_is_quiet_nan(b
)) {
549 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
550 res
= float64_chs(res
);
556 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
558 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
562 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
563 take values, others take register numbers and manipulate the contents
565 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
568 env
->macc
[dest
] = env
->macc
[src
];
569 mask
= MACSR_PAV0
<< dest
;
570 if (env
->macsr
& (MACSR_PAV0
<< src
))
576 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
581 product
= (uint64_t)op1
* op2
;
582 res
= (product
<< 24) >> 24;
583 if (res
!= product
) {
584 env
->macsr
|= MACSR_V
;
585 if (env
->macsr
& MACSR_OMC
) {
586 /* Make sure the accumulate operation overflows. */
596 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
600 product
= (uint64_t)op1
* op2
;
601 if (product
& (0xffffffull
<< 40)) {
602 env
->macsr
|= MACSR_V
;
603 if (env
->macsr
& MACSR_OMC
) {
604 /* Make sure the accumulate operation overflows. */
607 product
&= ((1ull << 40) - 1);
613 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
618 product
= (uint64_t)op1
* op2
;
619 if (env
->macsr
& MACSR_RT
) {
620 remainder
= product
& 0xffffff;
622 if (remainder
> 0x800000)
624 else if (remainder
== 0x800000)
625 product
+= (product
& 1);
632 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
636 tmp
= env
->macc
[acc
];
637 result
= ((tmp
<< 16) >> 16);
639 env
->macsr
|= MACSR_V
;
641 if (env
->macsr
& MACSR_V
) {
642 env
->macsr
|= MACSR_PAV0
<< acc
;
643 if (env
->macsr
& MACSR_OMC
) {
644 /* The result is saturated to 32 bits, despite overflow occurring
645 at 48 bits. Seems weird, but that's what the hardware docs
647 result
= (result
>> 63) ^ 0x7fffffff;
650 env
->macc
[acc
] = result
;
653 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
657 val
= env
->macc
[acc
];
658 if (val
& (0xffffull
<< 48)) {
659 env
->macsr
|= MACSR_V
;
661 if (env
->macsr
& MACSR_V
) {
662 env
->macsr
|= MACSR_PAV0
<< acc
;
663 if (env
->macsr
& MACSR_OMC
) {
664 if (val
> (1ull << 53))
667 val
= (1ull << 48) - 1;
669 val
&= ((1ull << 48) - 1);
672 env
->macc
[acc
] = val
;
675 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
680 sum
= env
->macc
[acc
];
681 result
= (sum
<< 16) >> 16;
683 env
->macsr
|= MACSR_V
;
685 if (env
->macsr
& MACSR_V
) {
686 env
->macsr
|= MACSR_PAV0
<< acc
;
687 if (env
->macsr
& MACSR_OMC
) {
688 result
= (result
>> 63) ^ 0x7fffffffffffll
;
691 env
->macc
[acc
] = result
;
694 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
697 val
= env
->macc
[acc
];
699 env
->macsr
|= MACSR_Z
;
700 } else if (val
& (1ull << 47)) {
701 env
->macsr
|= MACSR_N
;
703 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
704 env
->macsr
|= MACSR_V
;
706 if (env
->macsr
& MACSR_FI
) {
707 val
= ((int64_t)val
) >> 40;
708 if (val
!= 0 && val
!= -1)
709 env
->macsr
|= MACSR_EV
;
710 } else if (env
->macsr
& MACSR_SU
) {
711 val
= ((int64_t)val
) >> 32;
712 if (val
!= 0 && val
!= -1)
713 env
->macsr
|= MACSR_EV
;
715 if ((val
>> 32) != 0)
716 env
->macsr
|= MACSR_EV
;
720 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
722 cpu_m68k_flush_flags(env
, cc_op
);
725 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
730 if (env
->macsr
& MACSR_SU
) {
731 /* 16-bit rounding. */
732 rem
= val
& 0xffffff;
733 val
= (val
>> 24) & 0xffffu
;
736 else if (rem
== 0x800000)
738 } else if (env
->macsr
& MACSR_RT
) {
739 /* 32-bit rounding. */
744 else if (rem
== 0x80)
750 if (env
->macsr
& MACSR_OMC
) {
752 if (env
->macsr
& MACSR_SU
) {
753 if (val
!= (uint16_t) val
) {
754 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
756 result
= val
& 0xffff;
759 if (val
!= (uint32_t)val
) {
760 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
762 result
= (uint32_t)val
;
767 if (env
->macsr
& MACSR_SU
) {
768 result
= val
& 0xffff;
770 result
= (uint32_t)val
;
776 uint32_t HELPER(get_macs
)(uint64_t val
)
778 if (val
== (int32_t)val
) {
781 return (val
>> 61) ^ ~SIGNBIT
;
785 uint32_t HELPER(get_macu
)(uint64_t val
)
787 if ((val
>> 32) == 0) {
788 return (uint32_t)val
;
794 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
797 val
= env
->macc
[acc
] & 0x00ff;
798 val
= (env
->macc
[acc
] >> 32) & 0xff00;
799 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
800 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
804 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
807 val
= (env
->macc
[acc
] >> 32) & 0xffff;
808 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
812 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
816 res
= env
->macc
[acc
] & 0xffffffff00ull
;
817 tmp
= (int16_t)(val
& 0xff00);
818 res
|= ((int64_t)tmp
) << 32;
820 env
->macc
[acc
] = res
;
821 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
822 tmp
= (val
& 0xff000000);
823 res
|= ((int64_t)tmp
) << 16;
824 res
|= (val
>> 16) & 0xff;
825 env
->macc
[acc
+ 1] = res
;
828 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
832 res
= (uint32_t)env
->macc
[acc
];
834 res
|= ((int64_t)tmp
) << 32;
835 env
->macc
[acc
] = res
;
836 res
= (uint32_t)env
->macc
[acc
+ 1];
837 tmp
= val
& 0xffff0000;
838 res
|= (int64_t)tmp
<< 16;
839 env
->macc
[acc
+ 1] = res
;
842 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
845 res
= (uint32_t)env
->macc
[acc
];
846 res
|= ((uint64_t)(val
& 0xffff)) << 32;
847 env
->macc
[acc
] = res
;
848 res
= (uint32_t)env
->macc
[acc
+ 1];
849 res
|= (uint64_t)(val
& 0xffff0000) << 16;
850 env
->macc
[acc
+ 1] = res
;