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 cf_fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
80 stfq_p(mem_buf
, floatx80_to_float64(env
->fregs
[n
].d
, &s
));
84 case 8: /* fpcontrol */
85 stl_be_p(mem_buf
, env
->fpcr
);
87 case 9: /* fpstatus */
88 stl_be_p(mem_buf
, env
->fpsr
);
90 case 10: /* fpiar, not implemented */
91 memset(mem_buf
, 0, 4);
97 static int cf_fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
101 env
->fregs
[n
].d
= float64_to_floatx80(ldfq_p(mem_buf
), &s
);
105 case 8: /* fpcontrol */
106 cpu_m68k_set_fpcr(env
, ldl_p(mem_buf
));
108 case 9: /* fpstatus */
109 env
->fpsr
= ldl_p(mem_buf
);
111 case 10: /* fpiar, not implemented */
117 static int m68k_fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
120 stw_be_p(mem_buf
, env
->fregs
[n
].l
.upper
);
121 memset(mem_buf
+ 2, 0, 2);
122 stq_be_p(mem_buf
+ 4, env
->fregs
[n
].l
.lower
);
126 case 8: /* fpcontrol */
127 stl_be_p(mem_buf
, env
->fpcr
);
129 case 9: /* fpstatus */
130 stl_be_p(mem_buf
, env
->fpsr
);
132 case 10: /* fpiar, not implemented */
133 memset(mem_buf
, 0, 4);
139 static int m68k_fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
142 env
->fregs
[n
].l
.upper
= lduw_be_p(mem_buf
);
143 env
->fregs
[n
].l
.lower
= ldq_be_p(mem_buf
+ 4);
147 case 8: /* fpcontrol */
148 cpu_m68k_set_fpcr(env
, ldl_p(mem_buf
));
150 case 9: /* fpstatus */
151 env
->fpsr
= ldl_p(mem_buf
);
153 case 10: /* fpiar, not implemented */
159 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
161 CPUState
*cs
= CPU(cpu
);
162 CPUM68KState
*env
= &cpu
->env
;
164 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
165 gdb_register_coprocessor(cs
, cf_fpu_gdb_get_reg
, cf_fpu_gdb_set_reg
,
166 11, "cf-fp.xml", 18);
167 } else if (m68k_feature(env
, M68K_FEATURE_FPU
)) {
168 gdb_register_coprocessor(cs
, m68k_fpu_gdb_get_reg
,
169 m68k_fpu_gdb_set_reg
, 11, "m68k-fp.xml", 18);
171 /* TODO: Add [E]MAC registers. */
174 void HELPER(cf_movec_to
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
176 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
187 /* TODO: Implement Access Control Registers. */
192 /* TODO: Implement control registers. */
195 "Unimplemented control register write 0x%x = 0x%x\n",
200 void HELPER(m68k_movec_to
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
202 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
216 env
->sp
[M68K_USP
] = val
;
219 env
->sp
[M68K_SSP
] = val
;
222 env
->sp
[M68K_ISP
] = val
;
225 cpu_abort(CPU(cpu
), "Unimplemented control register write 0x%x = 0x%x\n",
229 uint32_t HELPER(m68k_movec_from
)(CPUM68KState
*env
, uint32_t reg
)
231 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
242 return env
->sp
[M68K_USP
];
244 return env
->sp
[M68K_SSP
];
246 return env
->sp
[M68K_ISP
];
248 cpu_abort(CPU(cpu
), "Unimplemented control register read 0x%x\n",
252 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
259 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
260 for (i
= 0; i
< 4; i
++) {
261 regval
= env
->macc
[i
];
262 exthigh
= regval
>> 40;
263 if (env
->macsr
& MACSR_FI
) {
268 extlow
= regval
>> 32;
270 if (env
->macsr
& MACSR_FI
) {
271 regval
= (((uint64_t)acc
) << 8) | extlow
;
272 regval
|= ((int64_t)exthigh
) << 40;
273 } else if (env
->macsr
& MACSR_SU
) {
274 regval
= acc
| (((int64_t)extlow
) << 32);
275 regval
|= ((int64_t)exthigh
) << 40;
277 regval
= acc
| (((uint64_t)extlow
) << 32);
278 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
280 env
->macc
[i
] = regval
;
286 void m68k_switch_sp(CPUM68KState
*env
)
290 env
->sp
[env
->current_sp
] = env
->aregs
[7];
291 if (m68k_feature(env
, M68K_FEATURE_M68000
)) {
292 if (env
->sr
& SR_S
) {
293 if (env
->sr
& SR_M
) {
302 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
303 ? M68K_SSP
: M68K_USP
;
305 env
->aregs
[7] = env
->sp
[new_sp
];
306 env
->current_sp
= new_sp
;
309 #if defined(CONFIG_USER_ONLY)
311 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
314 M68kCPU
*cpu
= M68K_CPU(cs
);
316 cs
->exception_index
= EXCP_ACCESS
;
317 cpu
->env
.mmu
.ar
= address
;
325 /* TODO: This will need fixing once the MMU is implemented. */
326 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
331 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
336 address
&= TARGET_PAGE_MASK
;
337 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
338 tlb_set_page(cs
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
342 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
343 be handled by the interrupt controller. Real hardware only requests
344 the vector when the interrupt is acknowledged by the CPU. For
345 simplicitly we calculate it when the interrupt is signalled. */
346 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
348 CPUState
*cs
= CPU(cpu
);
349 CPUM68KState
*env
= &cpu
->env
;
351 env
->pending_level
= level
;
352 env
->pending_vector
= vector
;
354 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
356 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
362 uint32_t HELPER(bitrev
)(uint32_t x
)
364 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
365 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
366 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
370 uint32_t HELPER(ff1
)(uint32_t x
)
378 uint32_t HELPER(sats
)(uint32_t val
, uint32_t v
)
380 /* The result has the opposite sign to the original value. */
381 if ((int32_t)v
< 0) {
382 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
387 void cpu_m68k_set_sr(CPUM68KState
*env
, uint32_t sr
)
389 env
->sr
= sr
& 0xffe0;
390 cpu_m68k_set_ccr(env
, sr
);
394 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
396 cpu_m68k_set_sr(env
, val
);
400 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
401 take values, others take register numbers and manipulate the contents
403 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
406 env
->macc
[dest
] = env
->macc
[src
];
407 mask
= MACSR_PAV0
<< dest
;
408 if (env
->macsr
& (MACSR_PAV0
<< src
))
414 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
419 product
= (uint64_t)op1
* op2
;
420 res
= (product
<< 24) >> 24;
421 if (res
!= product
) {
422 env
->macsr
|= MACSR_V
;
423 if (env
->macsr
& MACSR_OMC
) {
424 /* Make sure the accumulate operation overflows. */
434 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
438 product
= (uint64_t)op1
* op2
;
439 if (product
& (0xffffffull
<< 40)) {
440 env
->macsr
|= MACSR_V
;
441 if (env
->macsr
& MACSR_OMC
) {
442 /* Make sure the accumulate operation overflows. */
445 product
&= ((1ull << 40) - 1);
451 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
456 product
= (uint64_t)op1
* op2
;
457 if (env
->macsr
& MACSR_RT
) {
458 remainder
= product
& 0xffffff;
460 if (remainder
> 0x800000)
462 else if (remainder
== 0x800000)
463 product
+= (product
& 1);
470 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
474 tmp
= env
->macc
[acc
];
475 result
= ((tmp
<< 16) >> 16);
477 env
->macsr
|= MACSR_V
;
479 if (env
->macsr
& MACSR_V
) {
480 env
->macsr
|= MACSR_PAV0
<< acc
;
481 if (env
->macsr
& MACSR_OMC
) {
482 /* The result is saturated to 32 bits, despite overflow occurring
483 at 48 bits. Seems weird, but that's what the hardware docs
485 result
= (result
>> 63) ^ 0x7fffffff;
488 env
->macc
[acc
] = result
;
491 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
495 val
= env
->macc
[acc
];
496 if (val
& (0xffffull
<< 48)) {
497 env
->macsr
|= MACSR_V
;
499 if (env
->macsr
& MACSR_V
) {
500 env
->macsr
|= MACSR_PAV0
<< acc
;
501 if (env
->macsr
& MACSR_OMC
) {
502 if (val
> (1ull << 53))
505 val
= (1ull << 48) - 1;
507 val
&= ((1ull << 48) - 1);
510 env
->macc
[acc
] = val
;
513 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
518 sum
= env
->macc
[acc
];
519 result
= (sum
<< 16) >> 16;
521 env
->macsr
|= MACSR_V
;
523 if (env
->macsr
& MACSR_V
) {
524 env
->macsr
|= MACSR_PAV0
<< acc
;
525 if (env
->macsr
& MACSR_OMC
) {
526 result
= (result
>> 63) ^ 0x7fffffffffffll
;
529 env
->macc
[acc
] = result
;
532 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
535 val
= env
->macc
[acc
];
537 env
->macsr
|= MACSR_Z
;
538 } else if (val
& (1ull << 47)) {
539 env
->macsr
|= MACSR_N
;
541 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
542 env
->macsr
|= MACSR_V
;
544 if (env
->macsr
& MACSR_FI
) {
545 val
= ((int64_t)val
) >> 40;
546 if (val
!= 0 && val
!= -1)
547 env
->macsr
|= MACSR_EV
;
548 } else if (env
->macsr
& MACSR_SU
) {
549 val
= ((int64_t)val
) >> 32;
550 if (val
!= 0 && val
!= -1)
551 env
->macsr
|= MACSR_EV
;
553 if ((val
>> 32) != 0)
554 env
->macsr
|= MACSR_EV
;
558 #define EXTSIGN(val, index) ( \
559 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
562 #define COMPUTE_CCR(op, x, n, z, v, c) { \
565 /* Everything in place. */ \
572 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
575 v = (res ^ src1) & ~(src1 ^ src2); \
582 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
585 v = (res ^ src1) & (src1 ^ src2); \
592 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
596 v = (res ^ src1) & (src1 ^ src2); \
603 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
607 uint32_t cpu_m68k_get_ccr(CPUM68KState
*env
)
609 uint32_t x
, c
, n
, z
, v
;
610 uint32_t res
, src1
, src2
;
618 COMPUTE_CCR(env
->cc_op
, x
, n
, z
, v
, c
);
624 return x
* CCF_X
+ n
* CCF_N
+ z
* CCF_Z
+ v
* CCF_V
+ c
* CCF_C
;
627 uint32_t HELPER(get_ccr
)(CPUM68KState
*env
)
629 return cpu_m68k_get_ccr(env
);
632 void cpu_m68k_set_ccr(CPUM68KState
*env
, uint32_t ccr
)
634 env
->cc_x
= (ccr
& CCF_X
? 1 : 0);
635 env
->cc_n
= (ccr
& CCF_N
? -1 : 0);
636 env
->cc_z
= (ccr
& CCF_Z
? 0 : 1);
637 env
->cc_v
= (ccr
& CCF_V
? -1 : 0);
638 env
->cc_c
= (ccr
& CCF_C
? 1 : 0);
639 env
->cc_op
= CC_OP_FLAGS
;
642 void HELPER(set_ccr
)(CPUM68KState
*env
, uint32_t ccr
)
644 cpu_m68k_set_ccr(env
, ccr
);
647 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
649 uint32_t res
, src1
, src2
;
651 COMPUTE_CCR(cc_op
, env
->cc_x
, env
->cc_n
, env
->cc_z
, env
->cc_v
, env
->cc_c
);
652 env
->cc_op
= CC_OP_FLAGS
;
655 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
660 if (env
->macsr
& MACSR_SU
) {
661 /* 16-bit rounding. */
662 rem
= val
& 0xffffff;
663 val
= (val
>> 24) & 0xffffu
;
666 else if (rem
== 0x800000)
668 } else if (env
->macsr
& MACSR_RT
) {
669 /* 32-bit rounding. */
674 else if (rem
== 0x80)
680 if (env
->macsr
& MACSR_OMC
) {
682 if (env
->macsr
& MACSR_SU
) {
683 if (val
!= (uint16_t) val
) {
684 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
686 result
= val
& 0xffff;
689 if (val
!= (uint32_t)val
) {
690 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
692 result
= (uint32_t)val
;
697 if (env
->macsr
& MACSR_SU
) {
698 result
= val
& 0xffff;
700 result
= (uint32_t)val
;
706 uint32_t HELPER(get_macs
)(uint64_t val
)
708 if (val
== (int32_t)val
) {
711 return (val
>> 61) ^ ~SIGNBIT
;
715 uint32_t HELPER(get_macu
)(uint64_t val
)
717 if ((val
>> 32) == 0) {
718 return (uint32_t)val
;
724 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
727 val
= env
->macc
[acc
] & 0x00ff;
728 val
|= (env
->macc
[acc
] >> 32) & 0xff00;
729 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
730 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
734 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
737 val
= (env
->macc
[acc
] >> 32) & 0xffff;
738 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
742 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
746 res
= env
->macc
[acc
] & 0xffffffff00ull
;
747 tmp
= (int16_t)(val
& 0xff00);
748 res
|= ((int64_t)tmp
) << 32;
750 env
->macc
[acc
] = res
;
751 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
752 tmp
= (val
& 0xff000000);
753 res
|= ((int64_t)tmp
) << 16;
754 res
|= (val
>> 16) & 0xff;
755 env
->macc
[acc
+ 1] = res
;
758 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
762 res
= (uint32_t)env
->macc
[acc
];
764 res
|= ((int64_t)tmp
) << 32;
765 env
->macc
[acc
] = res
;
766 res
= (uint32_t)env
->macc
[acc
+ 1];
767 tmp
= val
& 0xffff0000;
768 res
|= (int64_t)tmp
<< 16;
769 env
->macc
[acc
+ 1] = res
;
772 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
775 res
= (uint32_t)env
->macc
[acc
];
776 res
|= ((uint64_t)(val
& 0xffff)) << 32;
777 env
->macc
[acc
] = res
;
778 res
= (uint32_t)env
->macc
[acc
+ 1];
779 res
|= (uint64_t)(val
& 0xffff0000) << 16;
780 env
->macc
[acc
+ 1] = res
;
783 #if defined(CONFIG_SOFTMMU)
784 void HELPER(reset
)(CPUM68KState
*env
)
786 /* FIXME: reset all except CPU */