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 M68kCPU
*cpu_m68k_init(const char *cpu_model
)
165 oc
= cpu_class_by_name(TYPE_M68K_CPU
, cpu_model
);
169 cpu
= M68K_CPU(object_new(object_class_get_name(oc
)));
172 register_m68k_insns(env
);
174 object_property_set_bool(OBJECT(cpu
), true, "realized", NULL
);
179 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
181 CPUState
*cs
= CPU(cpu
);
182 CPUM68KState
*env
= &cpu
->env
;
184 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
185 gdb_register_coprocessor(cs
, cf_fpu_gdb_get_reg
, cf_fpu_gdb_set_reg
,
186 11, "cf-fp.xml", 18);
187 } else if (m68k_feature(env
, M68K_FEATURE_FPU
)) {
188 gdb_register_coprocessor(cs
, m68k_fpu_gdb_get_reg
,
189 m68k_fpu_gdb_set_reg
, 11, "m68k-fp.xml", 18);
191 /* TODO: Add [E]MAC registers. */
194 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
196 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
199 case 0x02: /* CACR */
203 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
204 /* TODO: Implement Access Control Registers. */
206 case 0x801: /* VBR */
209 /* TODO: Implement control registers. */
211 cpu_abort(CPU(cpu
), "Unimplemented control register write 0x%x = 0x%x\n",
216 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
223 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
224 for (i
= 0; i
< 4; i
++) {
225 regval
= env
->macc
[i
];
226 exthigh
= regval
>> 40;
227 if (env
->macsr
& MACSR_FI
) {
232 extlow
= regval
>> 32;
234 if (env
->macsr
& MACSR_FI
) {
235 regval
= (((uint64_t)acc
) << 8) | extlow
;
236 regval
|= ((int64_t)exthigh
) << 40;
237 } else if (env
->macsr
& MACSR_SU
) {
238 regval
= acc
| (((int64_t)extlow
) << 32);
239 regval
|= ((int64_t)exthigh
) << 40;
241 regval
= acc
| (((uint64_t)extlow
) << 32);
242 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
244 env
->macc
[i
] = regval
;
250 void m68k_switch_sp(CPUM68KState
*env
)
254 env
->sp
[env
->current_sp
] = env
->aregs
[7];
255 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
256 ? M68K_SSP
: M68K_USP
;
257 env
->aregs
[7] = env
->sp
[new_sp
];
258 env
->current_sp
= new_sp
;
261 #if defined(CONFIG_USER_ONLY)
263 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
266 M68kCPU
*cpu
= M68K_CPU(cs
);
268 cs
->exception_index
= EXCP_ACCESS
;
269 cpu
->env
.mmu
.ar
= address
;
277 /* TODO: This will need fixing once the MMU is implemented. */
278 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
283 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
288 address
&= TARGET_PAGE_MASK
;
289 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
290 tlb_set_page(cs
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
294 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
295 be handled by the interrupt controller. Real hardware only requests
296 the vector when the interrupt is acknowledged by the CPU. For
297 simplicitly we calculate it when the interrupt is signalled. */
298 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
300 CPUState
*cs
= CPU(cpu
);
301 CPUM68KState
*env
= &cpu
->env
;
303 env
->pending_level
= level
;
304 env
->pending_vector
= vector
;
306 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
308 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
314 uint32_t HELPER(bitrev
)(uint32_t x
)
316 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
317 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
318 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
322 uint32_t HELPER(ff1
)(uint32_t x
)
330 uint32_t HELPER(sats
)(uint32_t val
, uint32_t v
)
332 /* The result has the opposite sign to the original value. */
333 if ((int32_t)v
< 0) {
334 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
339 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
341 env
->sr
= val
& 0xffe0;
342 cpu_m68k_set_ccr(env
, val
);
348 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
349 take values, others take register numbers and manipulate the contents
351 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
354 env
->macc
[dest
] = env
->macc
[src
];
355 mask
= MACSR_PAV0
<< dest
;
356 if (env
->macsr
& (MACSR_PAV0
<< src
))
362 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
367 product
= (uint64_t)op1
* op2
;
368 res
= (product
<< 24) >> 24;
369 if (res
!= product
) {
370 env
->macsr
|= MACSR_V
;
371 if (env
->macsr
& MACSR_OMC
) {
372 /* Make sure the accumulate operation overflows. */
382 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
386 product
= (uint64_t)op1
* op2
;
387 if (product
& (0xffffffull
<< 40)) {
388 env
->macsr
|= MACSR_V
;
389 if (env
->macsr
& MACSR_OMC
) {
390 /* Make sure the accumulate operation overflows. */
393 product
&= ((1ull << 40) - 1);
399 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
404 product
= (uint64_t)op1
* op2
;
405 if (env
->macsr
& MACSR_RT
) {
406 remainder
= product
& 0xffffff;
408 if (remainder
> 0x800000)
410 else if (remainder
== 0x800000)
411 product
+= (product
& 1);
418 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
422 tmp
= env
->macc
[acc
];
423 result
= ((tmp
<< 16) >> 16);
425 env
->macsr
|= MACSR_V
;
427 if (env
->macsr
& MACSR_V
) {
428 env
->macsr
|= MACSR_PAV0
<< acc
;
429 if (env
->macsr
& MACSR_OMC
) {
430 /* The result is saturated to 32 bits, despite overflow occurring
431 at 48 bits. Seems weird, but that's what the hardware docs
433 result
= (result
>> 63) ^ 0x7fffffff;
436 env
->macc
[acc
] = result
;
439 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
443 val
= env
->macc
[acc
];
444 if (val
& (0xffffull
<< 48)) {
445 env
->macsr
|= MACSR_V
;
447 if (env
->macsr
& MACSR_V
) {
448 env
->macsr
|= MACSR_PAV0
<< acc
;
449 if (env
->macsr
& MACSR_OMC
) {
450 if (val
> (1ull << 53))
453 val
= (1ull << 48) - 1;
455 val
&= ((1ull << 48) - 1);
458 env
->macc
[acc
] = val
;
461 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
466 sum
= env
->macc
[acc
];
467 result
= (sum
<< 16) >> 16;
469 env
->macsr
|= MACSR_V
;
471 if (env
->macsr
& MACSR_V
) {
472 env
->macsr
|= MACSR_PAV0
<< acc
;
473 if (env
->macsr
& MACSR_OMC
) {
474 result
= (result
>> 63) ^ 0x7fffffffffffll
;
477 env
->macc
[acc
] = result
;
480 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
483 val
= env
->macc
[acc
];
485 env
->macsr
|= MACSR_Z
;
486 } else if (val
& (1ull << 47)) {
487 env
->macsr
|= MACSR_N
;
489 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
490 env
->macsr
|= MACSR_V
;
492 if (env
->macsr
& MACSR_FI
) {
493 val
= ((int64_t)val
) >> 40;
494 if (val
!= 0 && val
!= -1)
495 env
->macsr
|= MACSR_EV
;
496 } else if (env
->macsr
& MACSR_SU
) {
497 val
= ((int64_t)val
) >> 32;
498 if (val
!= 0 && val
!= -1)
499 env
->macsr
|= MACSR_EV
;
501 if ((val
>> 32) != 0)
502 env
->macsr
|= MACSR_EV
;
506 #define EXTSIGN(val, index) ( \
507 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
510 #define COMPUTE_CCR(op, x, n, z, v, c) { \
513 /* Everything in place. */ \
520 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
523 v = (res ^ src1) & ~(src1 ^ src2); \
530 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
533 v = (res ^ src1) & (src1 ^ src2); \
540 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
544 v = (res ^ src1) & (src1 ^ src2); \
551 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
555 uint32_t cpu_m68k_get_ccr(CPUM68KState
*env
)
557 uint32_t x
, c
, n
, z
, v
;
558 uint32_t res
, src1
, src2
;
566 COMPUTE_CCR(env
->cc_op
, x
, n
, z
, v
, c
);
572 return x
* CCF_X
+ n
* CCF_N
+ z
* CCF_Z
+ v
* CCF_V
+ c
* CCF_C
;
575 uint32_t HELPER(get_ccr
)(CPUM68KState
*env
)
577 return cpu_m68k_get_ccr(env
);
580 void cpu_m68k_set_ccr(CPUM68KState
*env
, uint32_t ccr
)
582 env
->cc_x
= (ccr
& CCF_X
? 1 : 0);
583 env
->cc_n
= (ccr
& CCF_N
? -1 : 0);
584 env
->cc_z
= (ccr
& CCF_Z
? 0 : 1);
585 env
->cc_v
= (ccr
& CCF_V
? -1 : 0);
586 env
->cc_c
= (ccr
& CCF_C
? 1 : 0);
587 env
->cc_op
= CC_OP_FLAGS
;
590 void HELPER(set_ccr
)(CPUM68KState
*env
, uint32_t ccr
)
592 cpu_m68k_set_ccr(env
, ccr
);
595 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
597 uint32_t res
, src1
, src2
;
599 COMPUTE_CCR(cc_op
, env
->cc_x
, env
->cc_n
, env
->cc_z
, env
->cc_v
, env
->cc_c
);
600 env
->cc_op
= CC_OP_FLAGS
;
603 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
608 if (env
->macsr
& MACSR_SU
) {
609 /* 16-bit rounding. */
610 rem
= val
& 0xffffff;
611 val
= (val
>> 24) & 0xffffu
;
614 else if (rem
== 0x800000)
616 } else if (env
->macsr
& MACSR_RT
) {
617 /* 32-bit rounding. */
622 else if (rem
== 0x80)
628 if (env
->macsr
& MACSR_OMC
) {
630 if (env
->macsr
& MACSR_SU
) {
631 if (val
!= (uint16_t) val
) {
632 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
634 result
= val
& 0xffff;
637 if (val
!= (uint32_t)val
) {
638 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
640 result
= (uint32_t)val
;
645 if (env
->macsr
& MACSR_SU
) {
646 result
= val
& 0xffff;
648 result
= (uint32_t)val
;
654 uint32_t HELPER(get_macs
)(uint64_t val
)
656 if (val
== (int32_t)val
) {
659 return (val
>> 61) ^ ~SIGNBIT
;
663 uint32_t HELPER(get_macu
)(uint64_t val
)
665 if ((val
>> 32) == 0) {
666 return (uint32_t)val
;
672 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
675 val
= env
->macc
[acc
] & 0x00ff;
676 val
|= (env
->macc
[acc
] >> 32) & 0xff00;
677 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
678 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
682 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
685 val
= (env
->macc
[acc
] >> 32) & 0xffff;
686 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
690 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
694 res
= env
->macc
[acc
] & 0xffffffff00ull
;
695 tmp
= (int16_t)(val
& 0xff00);
696 res
|= ((int64_t)tmp
) << 32;
698 env
->macc
[acc
] = res
;
699 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
700 tmp
= (val
& 0xff000000);
701 res
|= ((int64_t)tmp
) << 16;
702 res
|= (val
>> 16) & 0xff;
703 env
->macc
[acc
+ 1] = res
;
706 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
710 res
= (uint32_t)env
->macc
[acc
];
712 res
|= ((int64_t)tmp
) << 32;
713 env
->macc
[acc
] = res
;
714 res
= (uint32_t)env
->macc
[acc
+ 1];
715 tmp
= val
& 0xffff0000;
716 res
|= (int64_t)tmp
<< 16;
717 env
->macc
[acc
+ 1] = res
;
720 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
723 res
= (uint32_t)env
->macc
[acc
];
724 res
|= ((uint64_t)(val
& 0xffff)) << 32;
725 env
->macc
[acc
] = res
;
726 res
= (uint32_t)env
->macc
[acc
+ 1];
727 res
|= (uint64_t)(val
& 0xffff0000) << 16;
728 env
->macc
[acc
+ 1] = res
;