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/exec-all.h"
24 #include "exec/gdbstub.h"
26 #include "exec/helper-proto.h"
28 #define SIGNBIT (1u << 31)
30 /* Sort alphabetically, except for "any". */
31 static gint
m68k_cpu_list_compare(gconstpointer a
, gconstpointer b
)
33 ObjectClass
*class_a
= (ObjectClass
*)a
;
34 ObjectClass
*class_b
= (ObjectClass
*)b
;
35 const char *name_a
, *name_b
;
37 name_a
= object_class_get_name(class_a
);
38 name_b
= object_class_get_name(class_b
);
39 if (strcmp(name_a
, "any-" TYPE_M68K_CPU
) == 0) {
41 } else if (strcmp(name_b
, "any-" TYPE_M68K_CPU
) == 0) {
44 return strcasecmp(name_a
, name_b
);
48 static void m68k_cpu_list_entry(gpointer data
, gpointer user_data
)
50 ObjectClass
*c
= data
;
51 CPUListState
*s
= user_data
;
55 typename
= object_class_get_name(c
);
56 name
= g_strndup(typename
, strlen(typename
) - strlen("-" TYPE_M68K_CPU
));
57 (*s
->cpu_fprintf
)(s
->file
, "%s\n",
62 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
66 .cpu_fprintf
= cpu_fprintf
,
70 list
= object_class_get_list(TYPE_M68K_CPU
, false);
71 list
= g_slist_sort(list
, m68k_cpu_list_compare
);
72 g_slist_foreach(list
, m68k_cpu_list_entry
, &s
);
76 static int fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
79 stfq_p(mem_buf
, env
->fregs
[n
]);
83 /* FP control registers (not implemented) */
84 memset(mem_buf
, 0, 4);
90 static int fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
93 env
->fregs
[n
] = ldfq_p(mem_buf
);
97 /* FP control registers (not implemented) */
103 M68kCPU
*cpu_m68k_init(const char *cpu_model
)
109 oc
= cpu_class_by_name(TYPE_M68K_CPU
, cpu_model
);
113 cpu
= M68K_CPU(object_new(object_class_get_name(oc
)));
116 register_m68k_insns(env
);
118 object_property_set_bool(OBJECT(cpu
), true, "realized", NULL
);
123 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
125 CPUState
*cs
= CPU(cpu
);
126 CPUM68KState
*env
= &cpu
->env
;
128 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
129 gdb_register_coprocessor(cs
, fpu_gdb_get_reg
, fpu_gdb_set_reg
,
130 11, "cf-fp.xml", 18);
132 /* TODO: Add [E]MAC registers. */
135 void cpu_m68k_flush_flags(CPUM68KState
*env
, int cc_op
)
137 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
143 #define HIGHBIT 0x80000000u
145 #define SET_NZ(x) do { \
148 else if ((int32_t)(x) < 0) \
152 #define SET_FLAGS_SUB(type, utype) do { \
153 SET_NZ((type)dest); \
155 if ((utype) tmp < (utype) src) \
157 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
176 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
180 SET_FLAGS_SUB(int32_t, uint32_t);
183 SET_FLAGS_SUB(int8_t, uint8_t);
186 SET_FLAGS_SUB(int16_t, uint16_t);
192 tmp
= dest
- src
- 1;
193 if (HIGHBIT
& (src
^ dest
) & ~(tmp
^ src
))
198 tmp
= dest
+ src
+ 1;
201 if (HIGHBIT
& (tmp
^ dest
) & (tmp
^ src
))
210 cpu_abort(CPU(cpu
), "Bad CC_OP %d", cc_op
);
212 env
->cc_op
= CC_OP_FLAGS
;
213 env
->cc_dest
= flags
;
216 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
218 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
221 case 0x02: /* CACR */
225 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
226 /* TODO: Implement Access Control Registers. */
228 case 0x801: /* VBR */
231 /* TODO: Implement control registers. */
233 cpu_abort(CPU(cpu
), "Unimplemented control register write 0x%x = 0x%x\n",
238 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
245 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
246 for (i
= 0; i
< 4; i
++) {
247 regval
= env
->macc
[i
];
248 exthigh
= regval
>> 40;
249 if (env
->macsr
& MACSR_FI
) {
254 extlow
= regval
>> 32;
256 if (env
->macsr
& MACSR_FI
) {
257 regval
= (((uint64_t)acc
) << 8) | extlow
;
258 regval
|= ((int64_t)exthigh
) << 40;
259 } else if (env
->macsr
& MACSR_SU
) {
260 regval
= acc
| (((int64_t)extlow
) << 32);
261 regval
|= ((int64_t)exthigh
) << 40;
263 regval
= acc
| (((uint64_t)extlow
) << 32);
264 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
266 env
->macc
[i
] = regval
;
272 void m68k_switch_sp(CPUM68KState
*env
)
276 env
->sp
[env
->current_sp
] = env
->aregs
[7];
277 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
278 ? M68K_SSP
: M68K_USP
;
279 env
->aregs
[7] = env
->sp
[new_sp
];
280 env
->current_sp
= new_sp
;
283 #if defined(CONFIG_USER_ONLY)
285 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
288 M68kCPU
*cpu
= M68K_CPU(cs
);
290 cs
->exception_index
= EXCP_ACCESS
;
291 cpu
->env
.mmu
.ar
= address
;
299 /* TODO: This will need fixing once the MMU is implemented. */
300 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
305 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
310 address
&= TARGET_PAGE_MASK
;
311 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
312 tlb_set_page(cs
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
316 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
317 be handled by the interrupt controller. Real hardware only requests
318 the vector when the interrupt is acknowledged by the CPU. For
319 simplicitly we calculate it when the interrupt is signalled. */
320 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
322 CPUState
*cs
= CPU(cpu
);
323 CPUM68KState
*env
= &cpu
->env
;
325 env
->pending_level
= level
;
326 env
->pending_vector
= vector
;
328 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
330 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
336 uint32_t HELPER(bitrev
)(uint32_t x
)
338 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
339 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
340 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
344 uint32_t HELPER(ff1
)(uint32_t x
)
352 uint32_t HELPER(sats
)(uint32_t val
, uint32_t ccr
)
354 /* The result has the opposite sign to the original value. */
356 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
360 uint32_t HELPER(subx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
365 old_flags
= env
->cc_dest
;
367 env
->cc_x
= (op1
<= op2
);
368 env
->cc_op
= CC_OP_SUBX
;
369 res
= op1
- (op2
+ 1);
371 env
->cc_x
= (op1
< op2
);
372 env
->cc_op
= CC_OP_SUB
;
377 cpu_m68k_flush_flags(env
, env
->cc_op
);
379 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
383 uint32_t HELPER(addx_cc
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
388 old_flags
= env
->cc_dest
;
391 env
->cc_x
= (res
<= op2
);
392 env
->cc_op
= CC_OP_ADDX
;
395 env
->cc_x
= (res
< op2
);
396 env
->cc_op
= CC_OP_ADD
;
400 cpu_m68k_flush_flags(env
, env
->cc_op
);
402 env
->cc_dest
&= (old_flags
| ~CCF_Z
);
406 uint32_t HELPER(xflag_lt
)(uint32_t a
, uint32_t b
)
411 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
413 env
->sr
= val
& 0xffff;
417 uint32_t HELPER(shl_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
425 cf
= env
->cc_src
& CCF_C
;
426 } else if (shift
< 32) {
427 result
= val
<< shift
;
428 cf
= (val
>> (32 - shift
)) & 1;
429 } else if (shift
== 32) {
432 } else /* shift > 32 */ {
437 env
->cc_x
= (cf
!= 0);
438 env
->cc_dest
= result
;
442 uint32_t HELPER(shr_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
450 cf
= env
->cc_src
& CCF_C
;
451 } else if (shift
< 32) {
452 result
= val
>> shift
;
453 cf
= (val
>> (shift
- 1)) & 1;
454 } else if (shift
== 32) {
457 } else /* shift > 32 */ {
462 env
->cc_x
= (cf
!= 0);
463 env
->cc_dest
= result
;
467 uint32_t HELPER(sar_cc
)(CPUM68KState
*env
, uint32_t val
, uint32_t shift
)
475 cf
= (env
->cc_src
& CCF_C
) != 0;
476 } else if (shift
< 32) {
477 result
= (int32_t)val
>> shift
;
478 cf
= (val
>> (shift
- 1)) & 1;
479 } else /* shift >= 32 */ {
480 result
= (int32_t)val
>> 31;
485 env
->cc_dest
= result
;
490 uint32_t HELPER(f64_to_i32
)(CPUM68KState
*env
, float64 val
)
492 return float64_to_int32(val
, &env
->fp_status
);
495 float32
HELPER(f64_to_f32
)(CPUM68KState
*env
, float64 val
)
497 return float64_to_float32(val
, &env
->fp_status
);
500 float64
HELPER(i32_to_f64
)(CPUM68KState
*env
, uint32_t val
)
502 return int32_to_float64(val
, &env
->fp_status
);
505 float64
HELPER(f32_to_f64
)(CPUM68KState
*env
, float32 val
)
507 return float32_to_float64(val
, &env
->fp_status
);
510 float64
HELPER(iround_f64
)(CPUM68KState
*env
, float64 val
)
512 return float64_round_to_int(val
, &env
->fp_status
);
515 float64
HELPER(itrunc_f64
)(CPUM68KState
*env
, float64 val
)
517 return float64_trunc_to_int(val
, &env
->fp_status
);
520 float64
HELPER(sqrt_f64
)(CPUM68KState
*env
, float64 val
)
522 return float64_sqrt(val
, &env
->fp_status
);
525 float64
HELPER(abs_f64
)(float64 val
)
527 return float64_abs(val
);
530 float64
HELPER(chs_f64
)(float64 val
)
532 return float64_chs(val
);
535 float64
HELPER(add_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
537 return float64_add(a
, b
, &env
->fp_status
);
540 float64
HELPER(sub_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
542 return float64_sub(a
, b
, &env
->fp_status
);
545 float64
HELPER(mul_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
547 return float64_mul(a
, b
, &env
->fp_status
);
550 float64
HELPER(div_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
552 return float64_div(a
, b
, &env
->fp_status
);
555 float64
HELPER(sub_cmp_f64
)(CPUM68KState
*env
, float64 a
, float64 b
)
557 /* ??? This may incorrectly raise exceptions. */
558 /* ??? Should flush denormals to zero. */
560 res
= float64_sub(a
, b
, &env
->fp_status
);
561 if (float64_is_quiet_nan(res
, &env
->fp_status
)) {
562 /* +/-inf compares equal against itself, but sub returns nan. */
563 if (!float64_is_quiet_nan(a
, &env
->fp_status
)
564 && !float64_is_quiet_nan(b
, &env
->fp_status
)) {
566 if (float64_lt_quiet(a
, res
, &env
->fp_status
))
567 res
= float64_chs(res
);
573 uint32_t HELPER(compare_f64
)(CPUM68KState
*env
, float64 val
)
575 return float64_compare_quiet(val
, float64_zero
, &env
->fp_status
);
579 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
580 take values, others take register numbers and manipulate the contents
582 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
585 env
->macc
[dest
] = env
->macc
[src
];
586 mask
= MACSR_PAV0
<< dest
;
587 if (env
->macsr
& (MACSR_PAV0
<< src
))
593 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
598 product
= (uint64_t)op1
* op2
;
599 res
= (product
<< 24) >> 24;
600 if (res
!= product
) {
601 env
->macsr
|= MACSR_V
;
602 if (env
->macsr
& MACSR_OMC
) {
603 /* Make sure the accumulate operation overflows. */
613 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
617 product
= (uint64_t)op1
* op2
;
618 if (product
& (0xffffffull
<< 40)) {
619 env
->macsr
|= MACSR_V
;
620 if (env
->macsr
& MACSR_OMC
) {
621 /* Make sure the accumulate operation overflows. */
624 product
&= ((1ull << 40) - 1);
630 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
635 product
= (uint64_t)op1
* op2
;
636 if (env
->macsr
& MACSR_RT
) {
637 remainder
= product
& 0xffffff;
639 if (remainder
> 0x800000)
641 else if (remainder
== 0x800000)
642 product
+= (product
& 1);
649 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
653 tmp
= env
->macc
[acc
];
654 result
= ((tmp
<< 16) >> 16);
656 env
->macsr
|= MACSR_V
;
658 if (env
->macsr
& MACSR_V
) {
659 env
->macsr
|= MACSR_PAV0
<< acc
;
660 if (env
->macsr
& MACSR_OMC
) {
661 /* The result is saturated to 32 bits, despite overflow occurring
662 at 48 bits. Seems weird, but that's what the hardware docs
664 result
= (result
>> 63) ^ 0x7fffffff;
667 env
->macc
[acc
] = result
;
670 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
674 val
= env
->macc
[acc
];
675 if (val
& (0xffffull
<< 48)) {
676 env
->macsr
|= MACSR_V
;
678 if (env
->macsr
& MACSR_V
) {
679 env
->macsr
|= MACSR_PAV0
<< acc
;
680 if (env
->macsr
& MACSR_OMC
) {
681 if (val
> (1ull << 53))
684 val
= (1ull << 48) - 1;
686 val
&= ((1ull << 48) - 1);
689 env
->macc
[acc
] = val
;
692 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
697 sum
= env
->macc
[acc
];
698 result
= (sum
<< 16) >> 16;
700 env
->macsr
|= MACSR_V
;
702 if (env
->macsr
& MACSR_V
) {
703 env
->macsr
|= MACSR_PAV0
<< acc
;
704 if (env
->macsr
& MACSR_OMC
) {
705 result
= (result
>> 63) ^ 0x7fffffffffffll
;
708 env
->macc
[acc
] = result
;
711 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
714 val
= env
->macc
[acc
];
716 env
->macsr
|= MACSR_Z
;
717 } else if (val
& (1ull << 47)) {
718 env
->macsr
|= MACSR_N
;
720 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
721 env
->macsr
|= MACSR_V
;
723 if (env
->macsr
& MACSR_FI
) {
724 val
= ((int64_t)val
) >> 40;
725 if (val
!= 0 && val
!= -1)
726 env
->macsr
|= MACSR_EV
;
727 } else if (env
->macsr
& MACSR_SU
) {
728 val
= ((int64_t)val
) >> 32;
729 if (val
!= 0 && val
!= -1)
730 env
->macsr
|= MACSR_EV
;
732 if ((val
>> 32) != 0)
733 env
->macsr
|= MACSR_EV
;
737 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
739 cpu_m68k_flush_flags(env
, cc_op
);
742 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
747 if (env
->macsr
& MACSR_SU
) {
748 /* 16-bit rounding. */
749 rem
= val
& 0xffffff;
750 val
= (val
>> 24) & 0xffffu
;
753 else if (rem
== 0x800000)
755 } else if (env
->macsr
& MACSR_RT
) {
756 /* 32-bit rounding. */
761 else if (rem
== 0x80)
767 if (env
->macsr
& MACSR_OMC
) {
769 if (env
->macsr
& MACSR_SU
) {
770 if (val
!= (uint16_t) val
) {
771 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
773 result
= val
& 0xffff;
776 if (val
!= (uint32_t)val
) {
777 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
779 result
= (uint32_t)val
;
784 if (env
->macsr
& MACSR_SU
) {
785 result
= val
& 0xffff;
787 result
= (uint32_t)val
;
793 uint32_t HELPER(get_macs
)(uint64_t val
)
795 if (val
== (int32_t)val
) {
798 return (val
>> 61) ^ ~SIGNBIT
;
802 uint32_t HELPER(get_macu
)(uint64_t val
)
804 if ((val
>> 32) == 0) {
805 return (uint32_t)val
;
811 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
814 val
= env
->macc
[acc
] & 0x00ff;
815 val
|= (env
->macc
[acc
] >> 32) & 0xff00;
816 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
817 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
821 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
824 val
= (env
->macc
[acc
] >> 32) & 0xffff;
825 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
829 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
833 res
= env
->macc
[acc
] & 0xffffffff00ull
;
834 tmp
= (int16_t)(val
& 0xff00);
835 res
|= ((int64_t)tmp
) << 32;
837 env
->macc
[acc
] = res
;
838 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
839 tmp
= (val
& 0xff000000);
840 res
|= ((int64_t)tmp
) << 16;
841 res
|= (val
>> 16) & 0xff;
842 env
->macc
[acc
+ 1] = res
;
845 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
849 res
= (uint32_t)env
->macc
[acc
];
851 res
|= ((int64_t)tmp
) << 32;
852 env
->macc
[acc
] = res
;
853 res
= (uint32_t)env
->macc
[acc
+ 1];
854 tmp
= val
& 0xffff0000;
855 res
|= (int64_t)tmp
<< 16;
856 env
->macc
[acc
+ 1] = res
;
859 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
862 res
= (uint32_t)env
->macc
[acc
];
863 res
|= ((uint64_t)(val
& 0xffff)) << 32;
864 env
->macc
[acc
] = res
;
865 res
= (uint32_t)env
->macc
[acc
+ 1];
866 res
|= (uint64_t)(val
& 0xffff0000) << 16;
867 env
->macc
[acc
+ 1] = res
;
870 void m68k_cpu_exec_enter(CPUState
*cs
)
872 M68kCPU
*cpu
= M68K_CPU(cs
);
873 CPUM68KState
*env
= &cpu
->env
;
875 env
->cc_op
= CC_OP_FLAGS
;
876 env
->cc_dest
= env
->sr
& 0xf;
877 env
->cc_x
= (env
->sr
>> 4) & 1;
880 void m68k_cpu_exec_exit(CPUState
*cs
)
882 M68kCPU
*cpu
= M68K_CPU(cs
);
883 CPUM68KState
*env
= &cpu
->env
;
885 cpu_m68k_flush_flags(env
, env
->cc_op
);
886 env
->cc_op
= CC_OP_FLAGS
;
887 env
->sr
= (env
->sr
& 0xffe0) | env
->cc_dest
| (env
->cc_x
<< 4);