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/>.
21 #include "qemu/osdep.h"
23 #include "exec/gdbstub.h"
25 #include "exec/helper-proto.h"
27 #define SIGNBIT (1u << 31)
29 /* Sort alphabetically, except for "any". */
30 static gint
m68k_cpu_list_compare(gconstpointer a
, gconstpointer b
)
32 ObjectClass
*class_a
= (ObjectClass
*)a
;
33 ObjectClass
*class_b
= (ObjectClass
*)b
;
34 const char *name_a
, *name_b
;
36 name_a
= object_class_get_name(class_a
);
37 name_b
= object_class_get_name(class_b
);
38 if (strcmp(name_a
, "any-" TYPE_M68K_CPU
) == 0) {
40 } else if (strcmp(name_b
, "any-" TYPE_M68K_CPU
) == 0) {
43 return strcasecmp(name_a
, name_b
);
47 static void m68k_cpu_list_entry(gpointer data
, gpointer user_data
)
49 ObjectClass
*c
= data
;
50 CPUListState
*s
= user_data
;
54 typename
= object_class_get_name(c
);
55 name
= g_strndup(typename
, strlen(typename
) - strlen("-" TYPE_M68K_CPU
));
56 (*s
->cpu_fprintf
)(s
->file
, "%s\n",
61 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
65 .cpu_fprintf
= cpu_fprintf
,
69 list
= object_class_get_list(TYPE_M68K_CPU
, false);
70 list
= g_slist_sort(list
, m68k_cpu_list_compare
);
71 g_slist_foreach(list
, m68k_cpu_list_entry
, &s
);
75 static int fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
78 stfq_p(mem_buf
, env
->fregs
[n
]);
82 /* FP control registers (not implemented) */
83 memset(mem_buf
, 0, 4);
89 static int fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
92 env
->fregs
[n
] = ldfq_p(mem_buf
);
96 /* FP control registers (not implemented) */
102 M68kCPU
*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
)));
115 register_m68k_insns(env
);
117 object_property_set_bool(OBJECT(cpu
), true, "realized", NULL
);
122 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
124 CPUState
*cs
= CPU(cpu
);
125 CPUM68KState
*env
= &cpu
->env
;
127 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
128 gdb_register_coprocessor(cs
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
129 11, "cf-fp.xml", 18);
131 /* TODO: Add [E]MAC registers. */
134 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
136 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
142 #define HIGHBIT 0x80000000u
144 #define SET_NZ(x) do { \
147 else if ((int32_t)(x) < 0) \
151 #define SET_FLAGS_SUB(type, utype) do { \
152 SET_NZ((type)dest); \
154 if ((utype) tmp < (utype) src) \
156 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
175 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
179 SET_FLAGS_SUB(int32_t, uint32_t);
182 SET_FLAGS_SUB(int8_t, uint8_t);
185 SET_FLAGS_SUB(int16_t, uint16_t);
191 tmp
= dest
- src
- 1;
192 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
197 tmp
= dest
+ src
+ 1;
200 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
209 cpu_abort(CPU(cpu
), "Bad CC_OP %d", cc_op
);
211 env
->cc_op
= CC_OP_FLAGS
;
212 env
->cc_dest
= flags
;
215 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
217 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
220 case 0x02: /* CACR */
224 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
225 /* TODO: Implement Access Control Registers. */
227 case 0x801: /* VBR */
230 /* TODO: Implement control registers. */
232 cpu_abort(CPU(cpu
), "Unimplemented control register write 0x%x = 0x%x\n",
237 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
244 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
245 for (i
= 0; i
< 4; i
++) {
246 regval
= env
->macc
[i
];
247 exthigh
= regval
>> 40;
248 if (env
->macsr
& MACSR_FI
) {
253 extlow
= regval
>> 32;
255 if (env
->macsr
& MACSR_FI
) {
256 regval
= (((uint64_t)acc
) << 8) | extlow
;
257 regval
|= ((int64_t)exthigh
) << 40;
258 } else if (env
->macsr
& MACSR_SU
) {
259 regval
= acc
| (((int64_t)extlow
) << 32);
260 regval
|= ((int64_t)exthigh
) << 40;
262 regval
= acc
| (((uint64_t)extlow
) << 32);
263 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
265 env
->macc
[i
] = regval
;
271 void m68k_switch_sp(CPUM68KState
*env
)
275 env
->sp
[env
->current_sp
] = env
->aregs
[7];
276 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
277 ? M68K_SSP
: M68K_USP
;
278 env
->aregs
[7] = env
->sp
[new_sp
];
279 env
->current_sp
= new_sp
;
282 #if defined(CONFIG_USER_ONLY)
284 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
287 M68kCPU
*cpu
= M68K_CPU(cs
);
289 cs
->exception_index
= EXCP_ACCESS
;
290 cpu
->env
.mmu
.ar
= address
;
298 /* TODO: This will need fixing once the MMU is implemented. */
299 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
304 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
309 address
&= TARGET_PAGE_MASK
;
310 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
311 tlb_set_page(cs
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
315 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
316 be handled by the interrupt controller. Real hardware only requests
317 the vector when the interrupt is acknowledged by the CPU. For
318 simplicitly we calculate it when the interrupt is signalled. */
319 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
321 CPUState
*cs
= CPU(cpu
);
322 CPUM68KState
*env
= &cpu
->env
;
324 env
->pending_level
= level
;
325 env
->pending_vector
= vector
;
327 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
329 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
335 uint32_t HELPER(bitrev
)(uint32_t x
)
337 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
338 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
339 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
343 uint32_t HELPER(ff1
)(uint32_t x
)
351 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
353 /* The result has the opposite sign to the original value. */
355 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
359 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
364 old_flags
= env
->cc_dest
;
366 env
->cc_x
= (op1
<= op2
);
367 env
->cc_op
= CC_OP_SUBX
;
368 res
= op1
- (op2
+ 1);
370 env
->cc_x
= (op1
< op2
);
371 env
->cc_op
= CC_OP_SUB
;
376 cpu_m68k_flush_flags(env
, env
->cc_op
);
378 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
382 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
387 old_flags
= env
->cc_dest
;
390 env
->cc_x
= (res
<= op2
);
391 env
->cc_op
= CC_OP_ADDX
;
394 env
->cc_x
= (res
< op2
);
395 env
->cc_op
= CC_OP_ADD
;
399 cpu_m68k_flush_flags(env
, env
->cc_op
);
401 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
405 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
410 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
412 env
->sr
= val
& 0xffff;
416 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
424 cf
= env
->cc_src
& CCF_C
;
425 } else if (shift
< 32) {
426 result
= val
<< shift
;
427 cf
= (val
>> (32 - shift
)) & 1;
428 } else if (shift
== 32) {
431 } else /* shift > 32 */ {
436 env
->cc_x
= (cf
!= 0);
437 env
->cc_dest
= result
;
441 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
449 cf
= env
->cc_src
& CCF_C
;
450 } else if (shift
< 32) {
451 result
= val
>> shift
;
452 cf
= (val
>> (shift
- 1)) & 1;
453 } else if (shift
== 32) {
456 } else /* shift > 32 */ {
461 env
->cc_x
= (cf
!= 0);
462 env
->cc_dest
= result
;
466 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
474 cf
= (env
->cc_src
& CCF_C
) != 0;
475 } else if (shift
< 32) {
476 result
= (int32_t)val
>> shift
;
477 cf
= (val
>> (shift
- 1)) & 1;
478 } else /* shift >= 32 */ {
479 result
= (int32_t)val
>> 31;
484 env
->cc_dest
= result
;
489 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
491 return float64_to_int32(val
, &env
->fp_status
);
494 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
496 return float64_to_float32(val
, &env
->fp_status
);
499 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
501 return int32_to_float64(val
, &env
->fp_status
);
504 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
506 return float32_to_float64(val
, &env
->fp_status
);
509 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
511 return float64_round_to_int(val
, &env
->fp_status
);
514 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
516 return float64_trunc_to_int(val
, &env
->fp_status
);
519 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
521 return float64_sqrt(val
, &env
->fp_status
);
524 float64
HELPER(abs_f64
)(float64 val
)
526 return float64_abs(val
);
529 float64
HELPER(chs_f64
)(float64 val
)
531 return float64_chs(val
);
534 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
536 return float64_add(a
, b
, &env
->fp_status
);
539 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
541 return float64_sub(a
, b
, &env
->fp_status
);
544 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
546 return float64_mul(a
, b
, &env
->fp_status
);
549 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
551 return float64_div(a
, b
, &env
->fp_status
);
554 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
556 /* ??? This may incorrectly raise exceptions. */
557 /* ??? Should flush denormals to zero. */
559 res
= float64_sub(a
, b
, &env
->fp_status
);
560 if (float64_is_quiet_nan(res
)) {
561 /* +/-inf compares equal against itself, but sub returns nan. */
562 if (!float64_is_quiet_nan(a
)
563 && !float64_is_quiet_nan(b
)) {
565 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
566 res
= float64_chs(res
);
572 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
574 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
578 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
579 take values, others take register numbers and manipulate the contents
581 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
584 env
->macc
[dest
] = env
->macc
[src
];
585 mask
= MACSR_PAV0
<< dest
;
586 if (env
->macsr
& (MACSR_PAV0
<< src
))
592 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
597 product
= (uint64_t)op1
* op2
;
598 res
= (product
<< 24) >> 24;
599 if (res
!= product
) {
600 env
->macsr
|= MACSR_V
;
601 if (env
->macsr
& MACSR_OMC
) {
602 /* Make sure the accumulate operation overflows. */
612 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
616 product
= (uint64_t)op1
* op2
;
617 if (product
& (0xffffffull
<< 40)) {
618 env
->macsr
|= MACSR_V
;
619 if (env
->macsr
& MACSR_OMC
) {
620 /* Make sure the accumulate operation overflows. */
623 product
&= ((1ull << 40) - 1);
629 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
634 product
= (uint64_t)op1
* op2
;
635 if (env
->macsr
& MACSR_RT
) {
636 remainder
= product
& 0xffffff;
638 if (remainder
> 0x800000)
640 else if (remainder
== 0x800000)
641 product
+= (product
& 1);
648 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
652 tmp
= env
->macc
[acc
];
653 result
= ((tmp
<< 16) >> 16);
655 env
->macsr
|= MACSR_V
;
657 if (env
->macsr
& MACSR_V
) {
658 env
->macsr
|= MACSR_PAV0
<< acc
;
659 if (env
->macsr
& MACSR_OMC
) {
660 /* The result is saturated to 32 bits, despite overflow occurring
661 at 48 bits. Seems weird, but that's what the hardware docs
663 result
= (result
>> 63) ^ 0x7fffffff;
666 env
->macc
[acc
] = result
;
669 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
673 val
= env
->macc
[acc
];
674 if (val
& (0xffffull
<< 48)) {
675 env
->macsr
|= MACSR_V
;
677 if (env
->macsr
& MACSR_V
) {
678 env
->macsr
|= MACSR_PAV0
<< acc
;
679 if (env
->macsr
& MACSR_OMC
) {
680 if (val
> (1ull << 53))
683 val
= (1ull << 48) - 1;
685 val
&= ((1ull << 48) - 1);
688 env
->macc
[acc
] = val
;
691 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
696 sum
= env
->macc
[acc
];
697 result
= (sum
<< 16) >> 16;
699 env
->macsr
|= MACSR_V
;
701 if (env
->macsr
& MACSR_V
) {
702 env
->macsr
|= MACSR_PAV0
<< acc
;
703 if (env
->macsr
& MACSR_OMC
) {
704 result
= (result
>> 63) ^ 0x7fffffffffffll
;
707 env
->macc
[acc
] = result
;
710 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
713 val
= env
->macc
[acc
];
715 env
->macsr
|= MACSR_Z
;
716 } else if (val
& (1ull << 47)) {
717 env
->macsr
|= MACSR_N
;
719 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
720 env
->macsr
|= MACSR_V
;
722 if (env
->macsr
& MACSR_FI
) {
723 val
= ((int64_t)val
) >> 40;
724 if (val
!= 0 && val
!= -1)
725 env
->macsr
|= MACSR_EV
;
726 } else if (env
->macsr
& MACSR_SU
) {
727 val
= ((int64_t)val
) >> 32;
728 if (val
!= 0 && val
!= -1)
729 env
->macsr
|= MACSR_EV
;
731 if ((val
>> 32) != 0)
732 env
->macsr
|= MACSR_EV
;
736 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
738 cpu_m68k_flush_flags(env
, cc_op
);
741 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
746 if (env
->macsr
& MACSR_SU
) {
747 /* 16-bit rounding. */
748 rem
= val
& 0xffffff;
749 val
= (val
>> 24) & 0xffffu
;
752 else if (rem
== 0x800000)
754 } else if (env
->macsr
& MACSR_RT
) {
755 /* 32-bit rounding. */
760 else if (rem
== 0x80)
766 if (env
->macsr
& MACSR_OMC
) {
768 if (env
->macsr
& MACSR_SU
) {
769 if (val
!= (uint16_t) val
) {
770 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
772 result
= val
& 0xffff;
775 if (val
!= (uint32_t)val
) {
776 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
778 result
= (uint32_t)val
;
783 if (env
->macsr
& MACSR_SU
) {
784 result
= val
& 0xffff;
786 result
= (uint32_t)val
;
792 uint32_t HELPER(get_macs
)(uint64_t val
)
794 if (val
== (int32_t)val
) {
797 return (val
>> 61) ^ ~SIGNBIT
;
801 uint32_t HELPER(get_macu
)(uint64_t val
)
803 if ((val
>> 32) == 0) {
804 return (uint32_t)val
;
810 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
813 val
= env
->macc
[acc
] & 0x00ff;
814 val
= (env
->macc
[acc
] >> 32) & 0xff00;
815 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
816 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
820 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
823 val
= (env
->macc
[acc
] >> 32) & 0xffff;
824 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
828 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
832 res
= env
->macc
[acc
] & 0xffffffff00ull
;
833 tmp
= (int16_t)(val
& 0xff00);
834 res
|= ((int64_t)tmp
) << 32;
836 env
->macc
[acc
] = res
;
837 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
838 tmp
= (val
& 0xff000000);
839 res
|= ((int64_t)tmp
) << 16;
840 res
|= (val
>> 16) & 0xff;
841 env
->macc
[acc
+ 1] = res
;
844 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
848 res
= (uint32_t)env
->macc
[acc
];
850 res
|= ((int64_t)tmp
) << 32;
851 env
->macc
[acc
] = res
;
852 res
= (uint32_t)env
->macc
[acc
+ 1];
853 tmp
= val
& 0xffff0000;
854 res
|= (int64_t)tmp
<< 16;
855 env
->macc
[acc
+ 1] = res
;
858 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
861 res
= (uint32_t)env
->macc
[acc
];
862 res
|= ((uint64_t)(val
& 0xffff)) << 32;
863 env
->macc
[acc
] = res
;
864 res
= (uint32_t)env
->macc
[acc
+ 1];
865 res
|= (uint64_t)(val
& 0xffff0000) << 16;
866 env
->macc
[acc
+ 1] = res
;
869 void m68k_cpu_exec_enter(CPUState
*cs
)
871 M68kCPU
*cpu
= M68K_CPU(cs
);
872 CPUM68KState
*env
= &cpu
->env
;
874 env
->cc_op
= CC_OP_FLAGS
;
875 env
->cc_dest
= env
->sr
& 0xf;
876 env
->cc_x
= (env
->sr
>> 4) & 1;
879 void m68k_cpu_exec_exit(CPUState
*cs
)
881 M68kCPU
*cpu
= M68K_CPU(cs
);
882 CPUM68KState
*env
= &cpu
->env
;
884 cpu_m68k_flush_flags(env
, env
->cc_op
);
885 env
->cc_op
= CC_OP_FLAGS
;
886 env
->sr
= (env
->sr
& 0xffe0) | env
->cc_dest
| (env
->cc_x
<< 4);