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"
24 #include "exec/helper-proto.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
)));
114 register_m68k_insns(env
);
116 object_property_set_bool(OBJECT(cpu
), true, "realized", NULL
);
121 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
123 CPUState
*cs
= CPU(cpu
);
124 CPUM68KState
*env
= &cpu
->env
;
126 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
127 gdb_register_coprocessor(cs
, 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
)
135 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
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(CPU(cpu
), "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
)
216 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
219 case 0x02: /* CACR */
223 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
224 /* TODO: Implement Access Control Registers. */
226 case 0x801: /* VBR */
229 /* TODO: Implement control registers. */
231 cpu_abort(CPU(cpu
), "Unimplemented control register write 0x%x = 0x%x\n",
236 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
243 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
244 for (i
= 0; i
< 4; i
++) {
245 regval
= env
->macc
[i
];
246 exthigh
= regval
>> 40;
247 if (env
->macsr
& MACSR_FI
) {
252 extlow
= regval
>> 32;
254 if (env
->macsr
& MACSR_FI
) {
255 regval
= (((uint64_t)acc
) << 8) | extlow
;
256 regval
|= ((int64_t)exthigh
) << 40;
257 } else if (env
->macsr
& MACSR_SU
) {
258 regval
= acc
| (((int64_t)extlow
) << 32);
259 regval
|= ((int64_t)exthigh
) << 40;
261 regval
= acc
| (((uint64_t)extlow
) << 32);
262 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
264 env
->macc
[i
] = regval
;
270 void m68k_switch_sp(CPUM68KState
*env
)
274 env
->sp
[env
->current_sp
] = env
->aregs
[7];
275 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
276 ? M68K_SSP
: M68K_USP
;
277 env
->aregs
[7] = env
->sp
[new_sp
];
278 env
->current_sp
= new_sp
;
281 #if defined(CONFIG_USER_ONLY)
283 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
286 M68kCPU
*cpu
= M68K_CPU(cs
);
288 cs
->exception_index
= EXCP_ACCESS
;
289 cpu
->env
.mmu
.ar
= address
;
297 /* TODO: This will need fixing once the MMU is implemented. */
298 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
303 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
308 address
&= TARGET_PAGE_MASK
;
309 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
310 tlb_set_page(cs
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
314 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
315 be handled by the interrupt controller. Real hardware only requests
316 the vector when the interrupt is acknowledged by the CPU. For
317 simplicitly we calculate it when the interrupt is signalled. */
318 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
320 CPUState
*cs
= CPU(cpu
);
321 CPUM68KState
*env
= &cpu
->env
;
323 env
->pending_level
= level
;
324 env
->pending_vector
= vector
;
326 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
328 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
334 uint32_t HELPER(bitrev
)(uint32_t x
)
336 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
337 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
338 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
342 uint32_t HELPER(ff1
)(uint32_t x
)
350 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
352 /* The result has the opposite sign to the original value. */
354 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
358 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
363 old_flags
= env
->cc_dest
;
365 env
->cc_x
= (op1
<= op2
);
366 env
->cc_op
= CC_OP_SUBX
;
367 res
= op1
- (op2
+ 1);
369 env
->cc_x
= (op1
< op2
);
370 env
->cc_op
= CC_OP_SUB
;
375 cpu_m68k_flush_flags(env
, env
->cc_op
);
377 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
381 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
386 old_flags
= env
->cc_dest
;
389 env
->cc_x
= (res
<= op2
);
390 env
->cc_op
= CC_OP_ADDX
;
393 env
->cc_x
= (res
< op2
);
394 env
->cc_op
= CC_OP_ADD
;
398 cpu_m68k_flush_flags(env
, env
->cc_op
);
400 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
404 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
409 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
411 env
->sr
= val
& 0xffff;
415 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
423 cf
= env
->cc_src
& CCF_C
;
424 } else if (shift
< 32) {
425 result
= val
<< shift
;
426 cf
= (val
>> (32 - shift
)) & 1;
427 } else if (shift
== 32) {
430 } else /* shift > 32 */ {
435 env
->cc_x
= (cf
!= 0);
436 env
->cc_dest
= result
;
440 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
448 cf
= env
->cc_src
& CCF_C
;
449 } else if (shift
< 32) {
450 result
= val
>> shift
;
451 cf
= (val
>> (shift
- 1)) & 1;
452 } else if (shift
== 32) {
455 } else /* shift > 32 */ {
460 env
->cc_x
= (cf
!= 0);
461 env
->cc_dest
= result
;
465 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
473 cf
= (env
->cc_src
& CCF_C
) != 0;
474 } else if (shift
< 32) {
475 result
= (int32_t)val
>> shift
;
476 cf
= (val
>> (shift
- 1)) & 1;
477 } else /* shift >= 32 */ {
478 result
= (int32_t)val
>> 31;
483 env
->cc_dest
= result
;
488 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
490 return float64_to_int32(val
, &env
->fp_status
);
493 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
495 return float64_to_float32(val
, &env
->fp_status
);
498 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
500 return int32_to_float64(val
, &env
->fp_status
);
503 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
505 return float32_to_float64(val
, &env
->fp_status
);
508 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
510 return float64_round_to_int(val
, &env
->fp_status
);
513 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
515 return float64_trunc_to_int(val
, &env
->fp_status
);
518 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
520 return float64_sqrt(val
, &env
->fp_status
);
523 float64
HELPER(abs_f64
)(float64 val
)
525 return float64_abs(val
);
528 float64
HELPER(chs_f64
)(float64 val
)
530 return float64_chs(val
);
533 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
535 return float64_add(a
, b
, &env
->fp_status
);
538 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
540 return float64_sub(a
, b
, &env
->fp_status
);
543 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
545 return float64_mul(a
, b
, &env
->fp_status
);
548 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
550 return float64_div(a
, b
, &env
->fp_status
);
553 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
555 /* ??? This may incorrectly raise exceptions. */
556 /* ??? Should flush denormals to zero. */
558 res
= float64_sub(a
, b
, &env
->fp_status
);
559 if (float64_is_quiet_nan(res
)) {
560 /* +/-inf compares equal against itself, but sub returns nan. */
561 if (!float64_is_quiet_nan(a
)
562 && !float64_is_quiet_nan(b
)) {
564 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
565 res
= float64_chs(res
);
571 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
573 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
577 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
578 take values, others take register numbers and manipulate the contents
580 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
583 env
->macc
[dest
] = env
->macc
[src
];
584 mask
= MACSR_PAV0
<< dest
;
585 if (env
->macsr
& (MACSR_PAV0
<< src
))
591 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
596 product
= (uint64_t)op1
* op2
;
597 res
= (product
<< 24) >> 24;
598 if (res
!= product
) {
599 env
->macsr
|= MACSR_V
;
600 if (env
->macsr
& MACSR_OMC
) {
601 /* Make sure the accumulate operation overflows. */
611 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
615 product
= (uint64_t)op1
* op2
;
616 if (product
& (0xffffffull
<< 40)) {
617 env
->macsr
|= MACSR_V
;
618 if (env
->macsr
& MACSR_OMC
) {
619 /* Make sure the accumulate operation overflows. */
622 product
&= ((1ull << 40) - 1);
628 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
633 product
= (uint64_t)op1
* op2
;
634 if (env
->macsr
& MACSR_RT
) {
635 remainder
= product
& 0xffffff;
637 if (remainder
> 0x800000)
639 else if (remainder
== 0x800000)
640 product
+= (product
& 1);
647 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
651 tmp
= env
->macc
[acc
];
652 result
= ((tmp
<< 16) >> 16);
654 env
->macsr
|= MACSR_V
;
656 if (env
->macsr
& MACSR_V
) {
657 env
->macsr
|= MACSR_PAV0
<< acc
;
658 if (env
->macsr
& MACSR_OMC
) {
659 /* The result is saturated to 32 bits, despite overflow occurring
660 at 48 bits. Seems weird, but that's what the hardware docs
662 result
= (result
>> 63) ^ 0x7fffffff;
665 env
->macc
[acc
] = result
;
668 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
672 val
= env
->macc
[acc
];
673 if (val
& (0xffffull
<< 48)) {
674 env
->macsr
|= MACSR_V
;
676 if (env
->macsr
& MACSR_V
) {
677 env
->macsr
|= MACSR_PAV0
<< acc
;
678 if (env
->macsr
& MACSR_OMC
) {
679 if (val
> (1ull << 53))
682 val
= (1ull << 48) - 1;
684 val
&= ((1ull << 48) - 1);
687 env
->macc
[acc
] = val
;
690 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
695 sum
= env
->macc
[acc
];
696 result
= (sum
<< 16) >> 16;
698 env
->macsr
|= MACSR_V
;
700 if (env
->macsr
& MACSR_V
) {
701 env
->macsr
|= MACSR_PAV0
<< acc
;
702 if (env
->macsr
& MACSR_OMC
) {
703 result
= (result
>> 63) ^ 0x7fffffffffffll
;
706 env
->macc
[acc
] = result
;
709 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
712 val
= env
->macc
[acc
];
714 env
->macsr
|= MACSR_Z
;
715 } else if (val
& (1ull << 47)) {
716 env
->macsr
|= MACSR_N
;
718 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
719 env
->macsr
|= MACSR_V
;
721 if (env
->macsr
& MACSR_FI
) {
722 val
= ((int64_t)val
) >> 40;
723 if (val
!= 0 && val
!= -1)
724 env
->macsr
|= MACSR_EV
;
725 } else if (env
->macsr
& MACSR_SU
) {
726 val
= ((int64_t)val
) >> 32;
727 if (val
!= 0 && val
!= -1)
728 env
->macsr
|= MACSR_EV
;
730 if ((val
>> 32) != 0)
731 env
->macsr
|= MACSR_EV
;
735 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
737 cpu_m68k_flush_flags(env
, cc_op
);
740 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
745 if (env
->macsr
& MACSR_SU
) {
746 /* 16-bit rounding. */
747 rem
= val
& 0xffffff;
748 val
= (val
>> 24) & 0xffffu
;
751 else if (rem
== 0x800000)
753 } else if (env
->macsr
& MACSR_RT
) {
754 /* 32-bit rounding. */
759 else if (rem
== 0x80)
765 if (env
->macsr
& MACSR_OMC
) {
767 if (env
->macsr
& MACSR_SU
) {
768 if (val
!= (uint16_t) val
) {
769 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
771 result
= val
& 0xffff;
774 if (val
!= (uint32_t)val
) {
775 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
777 result
= (uint32_t)val
;
782 if (env
->macsr
& MACSR_SU
) {
783 result
= val
& 0xffff;
785 result
= (uint32_t)val
;
791 uint32_t HELPER(get_macs
)(uint64_t val
)
793 if (val
== (int32_t)val
) {
796 return (val
>> 61) ^ ~SIGNBIT
;
800 uint32_t HELPER(get_macu
)(uint64_t val
)
802 if ((val
>> 32) == 0) {
803 return (uint32_t)val
;
809 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
812 val
= env
->macc
[acc
] & 0x00ff;
813 val
= (env
->macc
[acc
] >> 32) & 0xff00;
814 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
815 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
819 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
822 val
= (env
->macc
[acc
] >> 32) & 0xffff;
823 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
827 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
831 res
= env
->macc
[acc
] & 0xffffffff00ull
;
832 tmp
= (int16_t)(val
& 0xff00);
833 res
|= ((int64_t)tmp
) << 32;
835 env
->macc
[acc
] = res
;
836 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
837 tmp
= (val
& 0xff000000);
838 res
|= ((int64_t)tmp
) << 16;
839 res
|= (val
>> 16) & 0xff;
840 env
->macc
[acc
+ 1] = res
;
843 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
847 res
= (uint32_t)env
->macc
[acc
];
849 res
|= ((int64_t)tmp
) << 32;
850 env
->macc
[acc
] = res
;
851 res
= (uint32_t)env
->macc
[acc
+ 1];
852 tmp
= val
& 0xffff0000;
853 res
|= (int64_t)tmp
<< 16;
854 env
->macc
[acc
+ 1] = res
;
857 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
860 res
= (uint32_t)env
->macc
[acc
];
861 res
|= ((uint64_t)(val
& 0xffff)) << 32;
862 env
->macc
[acc
] = res
;
863 res
= (uint32_t)env
->macc
[acc
+ 1];
864 res
|= (uint64_t)(val
& 0xffff0000) << 16;
865 env
->macc
[acc
+ 1] = res
;
868 void m68k_cpu_exec_enter(CPUState
*cs
)
870 M68kCPU
*cpu
= M68K_CPU(cs
);
871 CPUM68KState
*env
= &cpu
->env
;
873 env
->cc_op
= CC_OP_FLAGS
;
874 env
->cc_dest
= env
->sr
& 0xf;
875 env
->cc_x
= (env
->sr
>> 4) & 1;
878 void m68k_cpu_exec_exit(CPUState
*cs
)
880 M68kCPU
*cpu
= M68K_CPU(cs
);
881 CPUM68KState
*env
= &cpu
->env
;
883 cpu_m68k_flush_flags(env
, env
->cc_op
);
884 env
->cc_op
= CC_OP_FLAGS
;
885 env
->sr
= (env
->sr
& 0xffe0) | env
->cc_dest
| (env
->cc_x
<< 4);