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 typedef struct M68kCPUListState
{
29 fprintf_function cpu_fprintf
;
33 /* Sort alphabetically, except for "any". */
34 static gint
m68k_cpu_list_compare(gconstpointer a
, gconstpointer b
)
36 ObjectClass
*class_a
= (ObjectClass
*)a
;
37 ObjectClass
*class_b
= (ObjectClass
*)b
;
38 const char *name_a
, *name_b
;
40 name_a
= object_class_get_name(class_a
);
41 name_b
= object_class_get_name(class_b
);
42 if (strcmp(name_a
, "any") == 0) {
44 } else if (strcmp(name_b
, "any") == 0) {
47 return strcasecmp(name_a
, name_b
);
51 static void m68k_cpu_list_entry(gpointer data
, gpointer user_data
)
53 ObjectClass
*c
= data
;
54 M68kCPUListState
*s
= user_data
;
56 (*s
->cpu_fprintf
)(s
->file
, "%s\n",
57 object_class_get_name(c
));
60 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
62 M68kCPUListState s
= {
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
)
107 if (object_class_by_name(cpu_model
) == NULL
) {
110 cpu
= M68K_CPU(object_new(cpu_model
));
118 env
->cpu_model_str
= cpu_model
;
120 register_m68k_insns(env
);
121 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
122 gdb_register_coprocessor(env
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
123 11, "cf-fp.xml", 18);
125 /* TODO: Add [E]MAC registers. */
127 cpu_reset(ENV_GET_CPU(env
));
132 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
139 #define HIGHBIT 0x80000000u
141 #define SET_NZ(x) do { \
144 else if ((int32_t)(x) < 0) \
148 #define SET_FLAGS_SUB(type, utype) do { \
149 SET_NZ((type)dest); \
151 if ((utype) tmp < (utype) src) \
153 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
172 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
176 SET_FLAGS_SUB(int32_t, uint32_t);
179 SET_FLAGS_SUB(int8_t, uint8_t);
182 SET_FLAGS_SUB(int16_t, uint16_t);
188 tmp
= dest
- src
- 1;
189 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
194 tmp
= dest
+ src
+ 1;
197 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
206 cpu_abort(env
, "Bad CC_OP %d", cc_op
);
208 env
->cc_op
= CC_OP_FLAGS
;
209 env
->cc_dest
= flags
;
212 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
215 case 0x02: /* CACR */
219 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
220 /* TODO: Implement Access Control Registers. */
222 case 0x801: /* VBR */
225 /* TODO: Implement control registers. */
227 cpu_abort(env
, "Unimplemented control register write 0x%x = 0x%x\n",
232 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
239 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
240 for (i
= 0; i
< 4; i
++) {
241 regval
= env
->macc
[i
];
242 exthigh
= regval
>> 40;
243 if (env
->macsr
& MACSR_FI
) {
248 extlow
= regval
>> 32;
250 if (env
->macsr
& MACSR_FI
) {
251 regval
= (((uint64_t)acc
) << 8) | extlow
;
252 regval
|= ((int64_t)exthigh
) << 40;
253 } else if (env
->macsr
& MACSR_SU
) {
254 regval
= acc
| (((int64_t)extlow
) << 32);
255 regval
|= ((int64_t)exthigh
) << 40;
257 regval
= acc
| (((uint64_t)extlow
) << 32);
258 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
260 env
->macc
[i
] = regval
;
266 void m68k_switch_sp(CPUM68KState
*env
)
270 env
->sp
[env
->current_sp
] = env
->aregs
[7];
271 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
272 ? M68K_SSP
: M68K_USP
;
273 env
->aregs
[7] = env
->sp
[new_sp
];
274 env
->current_sp
= new_sp
;
277 #if defined(CONFIG_USER_ONLY)
279 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
282 env
->exception_index
= EXCP_ACCESS
;
283 env
->mmu
.ar
= address
;
291 /* TODO: This will need fixing once the MMU is implemented. */
292 hwaddr
cpu_get_phys_page_debug(CPUM68KState
*env
, target_ulong addr
)
297 int cpu_m68k_handle_mmu_fault (CPUM68KState
*env
, target_ulong address
, int rw
,
302 address
&= TARGET_PAGE_MASK
;
303 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
304 tlb_set_page(env
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
308 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
309 be handled by the interrupt controller. Real hardware only requests
310 the vector when the interrupt is acknowledged by the CPU. For
311 simplicitly we calculate it when the interrupt is signalled. */
312 void m68k_set_irq_level(CPUM68KState
*env
, int level
, uint8_t vector
)
314 env
->pending_level
= level
;
315 env
->pending_vector
= vector
;
317 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
319 cpu_reset_interrupt(env
, CPU_INTERRUPT_HARD
);
324 uint32_t HELPER(bitrev
)(uint32_t x
)
326 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
327 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
328 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
332 uint32_t HELPER(ff1
)(uint32_t x
)
340 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
342 /* The result has the opposite sign to the original value. */
344 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
348 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
353 old_flags
= env
->cc_dest
;
355 env
->cc_x
= (op1
<= op2
);
356 env
->cc_op
= CC_OP_SUBX
;
357 res
= op1
- (op2
+ 1);
359 env
->cc_x
= (op1
< op2
);
360 env
->cc_op
= CC_OP_SUB
;
365 cpu_m68k_flush_flags(env
, env
->cc_op
);
367 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
371 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
376 old_flags
= env
->cc_dest
;
379 env
->cc_x
= (res
<= op2
);
380 env
->cc_op
= CC_OP_ADDX
;
383 env
->cc_x
= (res
< op2
);
384 env
->cc_op
= CC_OP_ADD
;
388 cpu_m68k_flush_flags(env
, env
->cc_op
);
390 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
394 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
399 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
401 env
->sr
= val
& 0xffff;
405 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
413 cf
= env
->cc_src
& CCF_C
;
414 } else if (shift
< 32) {
415 result
= val
<< shift
;
416 cf
= (val
>> (32 - shift
)) & 1;
417 } else if (shift
== 32) {
420 } else /* shift > 32 */ {
425 env
->cc_x
= (cf
!= 0);
426 env
->cc_dest
= result
;
430 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
438 cf
= env
->cc_src
& CCF_C
;
439 } else if (shift
< 32) {
440 result
= val
>> shift
;
441 cf
= (val
>> (shift
- 1)) & 1;
442 } else if (shift
== 32) {
445 } else /* shift > 32 */ {
450 env
->cc_x
= (cf
!= 0);
451 env
->cc_dest
= result
;
455 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
463 cf
= (env
->cc_src
& CCF_C
) != 0;
464 } else if (shift
< 32) {
465 result
= (int32_t)val
>> shift
;
466 cf
= (val
>> (shift
- 1)) & 1;
467 } else /* shift >= 32 */ {
468 result
= (int32_t)val
>> 31;
473 env
->cc_dest
= result
;
478 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
480 return float64_to_int32(val
, &env
->fp_status
);
483 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
485 return float64_to_float32(val
, &env
->fp_status
);
488 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
490 return int32_to_float64(val
, &env
->fp_status
);
493 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
495 return float32_to_float64(val
, &env
->fp_status
);
498 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
500 return float64_round_to_int(val
, &env
->fp_status
);
503 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
505 return float64_trunc_to_int(val
, &env
->fp_status
);
508 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
510 return float64_sqrt(val
, &env
->fp_status
);
513 float64
HELPER(abs_f64
)(float64 val
)
515 return float64_abs(val
);
518 float64
HELPER(chs_f64
)(float64 val
)
520 return float64_chs(val
);
523 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
525 return float64_add(a
, b
, &env
->fp_status
);
528 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
530 return float64_sub(a
, b
, &env
->fp_status
);
533 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
535 return float64_mul(a
, b
, &env
->fp_status
);
538 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
540 return float64_div(a
, b
, &env
->fp_status
);
543 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
545 /* ??? This may incorrectly raise exceptions. */
546 /* ??? Should flush denormals to zero. */
548 res
= float64_sub(a
, b
, &env
->fp_status
);
549 if (float64_is_quiet_nan(res
)) {
550 /* +/-inf compares equal against itself, but sub returns nan. */
551 if (!float64_is_quiet_nan(a
)
552 && !float64_is_quiet_nan(b
)) {
554 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
555 res
= float64_chs(res
);
561 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
563 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
567 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
568 take values, others take register numbers and manipulate the contents
570 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
573 env
->macc
[dest
] = env
->macc
[src
];
574 mask
= MACSR_PAV0
<< dest
;
575 if (env
->macsr
& (MACSR_PAV0
<< src
))
581 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
586 product
= (uint64_t)op1
* op2
;
587 res
= (product
<< 24) >> 24;
588 if (res
!= product
) {
589 env
->macsr
|= MACSR_V
;
590 if (env
->macsr
& MACSR_OMC
) {
591 /* Make sure the accumulate operation overflows. */
601 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
605 product
= (uint64_t)op1
* op2
;
606 if (product
& (0xffffffull
<< 40)) {
607 env
->macsr
|= MACSR_V
;
608 if (env
->macsr
& MACSR_OMC
) {
609 /* Make sure the accumulate operation overflows. */
612 product
&= ((1ull << 40) - 1);
618 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
623 product
= (uint64_t)op1
* op2
;
624 if (env
->macsr
& MACSR_RT
) {
625 remainder
= product
& 0xffffff;
627 if (remainder
> 0x800000)
629 else if (remainder
== 0x800000)
630 product
+= (product
& 1);
637 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
641 tmp
= env
->macc
[acc
];
642 result
= ((tmp
<< 16) >> 16);
644 env
->macsr
|= MACSR_V
;
646 if (env
->macsr
& MACSR_V
) {
647 env
->macsr
|= MACSR_PAV0
<< acc
;
648 if (env
->macsr
& MACSR_OMC
) {
649 /* The result is saturated to 32 bits, despite overflow occurring
650 at 48 bits. Seems weird, but that's what the hardware docs
652 result
= (result
>> 63) ^ 0x7fffffff;
655 env
->macc
[acc
] = result
;
658 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
662 val
= env
->macc
[acc
];
663 if (val
& (0xffffull
<< 48)) {
664 env
->macsr
|= MACSR_V
;
666 if (env
->macsr
& MACSR_V
) {
667 env
->macsr
|= MACSR_PAV0
<< acc
;
668 if (env
->macsr
& MACSR_OMC
) {
669 if (val
> (1ull << 53))
672 val
= (1ull << 48) - 1;
674 val
&= ((1ull << 48) - 1);
677 env
->macc
[acc
] = val
;
680 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
685 sum
= env
->macc
[acc
];
686 result
= (sum
<< 16) >> 16;
688 env
->macsr
|= MACSR_V
;
690 if (env
->macsr
& MACSR_V
) {
691 env
->macsr
|= MACSR_PAV0
<< acc
;
692 if (env
->macsr
& MACSR_OMC
) {
693 result
= (result
>> 63) ^ 0x7fffffffffffll
;
696 env
->macc
[acc
] = result
;
699 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
702 val
= env
->macc
[acc
];
704 env
->macsr
|= MACSR_Z
;
705 } else if (val
& (1ull << 47)) {
706 env
->macsr
|= MACSR_N
;
708 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
709 env
->macsr
|= MACSR_V
;
711 if (env
->macsr
& MACSR_FI
) {
712 val
= ((int64_t)val
) >> 40;
713 if (val
!= 0 && val
!= -1)
714 env
->macsr
|= MACSR_EV
;
715 } else if (env
->macsr
& MACSR_SU
) {
716 val
= ((int64_t)val
) >> 32;
717 if (val
!= 0 && val
!= -1)
718 env
->macsr
|= MACSR_EV
;
720 if ((val
>> 32) != 0)
721 env
->macsr
|= MACSR_EV
;
725 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
727 cpu_m68k_flush_flags(env
, cc_op
);
730 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
735 if (env
->macsr
& MACSR_SU
) {
736 /* 16-bit rounding. */
737 rem
= val
& 0xffffff;
738 val
= (val
>> 24) & 0xffffu
;
741 else if (rem
== 0x800000)
743 } else if (env
->macsr
& MACSR_RT
) {
744 /* 32-bit rounding. */
749 else if (rem
== 0x80)
755 if (env
->macsr
& MACSR_OMC
) {
757 if (env
->macsr
& MACSR_SU
) {
758 if (val
!= (uint16_t) val
) {
759 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
761 result
= val
& 0xffff;
764 if (val
!= (uint32_t)val
) {
765 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
767 result
= (uint32_t)val
;
772 if (env
->macsr
& MACSR_SU
) {
773 result
= val
& 0xffff;
775 result
= (uint32_t)val
;
781 uint32_t HELPER(get_macs
)(uint64_t val
)
783 if (val
== (int32_t)val
) {
786 return (val
>> 61) ^ ~SIGNBIT
;
790 uint32_t HELPER(get_macu
)(uint64_t val
)
792 if ((val
>> 32) == 0) {
793 return (uint32_t)val
;
799 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
802 val
= env
->macc
[acc
] & 0x00ff;
803 val
= (env
->macc
[acc
] >> 32) & 0xff00;
804 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
805 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
809 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
812 val
= (env
->macc
[acc
] >> 32) & 0xffff;
813 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
817 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
821 res
= env
->macc
[acc
] & 0xffffffff00ull
;
822 tmp
= (int16_t)(val
& 0xff00);
823 res
|= ((int64_t)tmp
) << 32;
825 env
->macc
[acc
] = res
;
826 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
827 tmp
= (val
& 0xff000000);
828 res
|= ((int64_t)tmp
) << 16;
829 res
|= (val
>> 16) & 0xff;
830 env
->macc
[acc
+ 1] = res
;
833 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
837 res
= (uint32_t)env
->macc
[acc
];
839 res
|= ((int64_t)tmp
) << 32;
840 env
->macc
[acc
] = res
;
841 res
= (uint32_t)env
->macc
[acc
+ 1];
842 tmp
= val
& 0xffff0000;
843 res
|= (int64_t)tmp
<< 16;
844 env
->macc
[acc
+ 1] = res
;
847 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
850 res
= (uint32_t)env
->macc
[acc
];
851 res
|= ((uint64_t)(val
& 0xffff)) << 32;
852 env
->macc
[acc
] = res
;
853 res
= (uint32_t)env
->macc
[acc
+ 1];
854 res
|= (uint64_t)(val
& 0xffff0000) << 16;
855 env
->macc
[acc
+ 1] = res
;