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 /* FP control registers (not implemented) */
85 memset(mem_buf, 0, 4);
91 static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
95 env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
99 /* FP control registers (not implemented) */
105 static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
108 stw_be_p(mem_buf, env->fregs[n].l.upper);
109 memset(mem_buf + 2, 0, 2);
110 stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
114 case 8: /* fpcontrol */
115 stl_be_p(mem_buf, env->fpcr);
117 case 9: /* fpstatus */
118 stl_be_p(mem_buf, env->fpsr);
120 case 10: /* fpiar, not implemented */
121 memset(mem_buf, 0, 4);
127 static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
130 env->fregs[n].l.upper = lduw_be_p(mem_buf);
131 env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
135 case 8: /* fpcontrol */
136 env->fpcr = ldl_p(mem_buf);
138 case 9: /* fpstatus */
139 env->fpsr = ldl_p(mem_buf);
141 case 10: /* fpiar, not implemented */
147 M68kCPU *cpu_m68k_init(const char *cpu_model)
153 oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model);
157 cpu = M68K_CPU(object_new(object_class_get_name(oc)));
160 register_m68k_insns(env);
162 object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
167 void m68k_cpu_init_gdb(M68kCPU *cpu)
169 CPUState *cs = CPU(cpu);
170 CPUM68KState *env = &cpu->env;
172 if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
173 gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
174 11, "cf-fp.xml", 18);
175 } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
176 gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
177 m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
179 /* TODO: Add [E]MAC registers. */
182 void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
184 M68kCPU *cpu = m68k_env_get_cpu(env);
187 case 0x02: /* CACR */
191 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
192 /* TODO: Implement Access Control Registers. */
194 case 0x801: /* VBR */
197 /* TODO: Implement control registers. */
199 cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
204 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
211 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
212 for (i = 0; i < 4; i++) {
213 regval = env->macc[i];
214 exthigh = regval >> 40;
215 if (env->macsr & MACSR_FI) {
220 extlow = regval >> 32;
222 if (env->macsr & MACSR_FI) {
223 regval = (((uint64_t)acc) << 8) | extlow;
224 regval |= ((int64_t)exthigh) << 40;
225 } else if (env->macsr & MACSR_SU) {
226 regval = acc | (((int64_t)extlow) << 32);
227 regval |= ((int64_t)exthigh) << 40;
229 regval = acc | (((uint64_t)extlow) << 32);
230 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
232 env->macc[i] = regval;
238 void m68k_switch_sp(CPUM68KState *env)
242 env->sp[env->current_sp] = env->aregs[7];
243 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
244 ? M68K_SSP : M68K_USP;
245 env->aregs[7] = env->sp[new_sp];
246 env->current_sp = new_sp;
249 #if defined(CONFIG_USER_ONLY)
251 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
254 M68kCPU *cpu = M68K_CPU(cs);
256 cs->exception_index = EXCP_ACCESS;
257 cpu->env.mmu.ar = address;
265 /* TODO: This will need fixing once the MMU is implemented. */
266 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
271 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
276 address &= TARGET_PAGE_MASK;
277 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
278 tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
282 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
283 be handled by the interrupt controller. Real hardware only requests
284 the vector when the interrupt is acknowledged by the CPU. For
285 simplicitly we calculate it when the interrupt is signalled. */
286 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
288 CPUState *cs = CPU(cpu);
289 CPUM68KState *env = &cpu->env;
291 env->pending_level = level;
292 env->pending_vector = vector;
294 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
296 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
302 uint32_t HELPER(bitrev)(uint32_t x)
304 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
305 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
306 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
310 uint32_t HELPER(ff1)(uint32_t x)
318 uint32_t HELPER(sats)(uint32_t val, uint32_t v)
320 /* The result has the opposite sign to the original value. */
321 if ((int32_t)v < 0) {
322 val = (((int32_t)val) >> 31) ^ SIGNBIT;
327 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
329 env->sr = val & 0xffe0;
330 cpu_m68k_set_ccr(env, val);
336 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
337 take values, others take register numbers and manipulate the contents
339 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
342 env->macc[dest] = env->macc[src];
343 mask = MACSR_PAV0 << dest;
344 if (env->macsr & (MACSR_PAV0 << src))
350 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
355 product = (uint64_t)op1 * op2;
356 res = (product << 24) >> 24;
357 if (res != product) {
358 env->macsr |= MACSR_V;
359 if (env->macsr & MACSR_OMC) {
360 /* Make sure the accumulate operation overflows. */
370 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
374 product = (uint64_t)op1 * op2;
375 if (product & (0xffffffull << 40)) {
376 env->macsr |= MACSR_V;
377 if (env->macsr & MACSR_OMC) {
378 /* Make sure the accumulate operation overflows. */
381 product &= ((1ull << 40) - 1);
387 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
392 product = (uint64_t)op1 * op2;
393 if (env->macsr & MACSR_RT) {
394 remainder = product & 0xffffff;
396 if (remainder > 0x800000)
398 else if (remainder == 0x800000)
399 product += (product & 1);
406 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
410 tmp = env->macc[acc];
411 result = ((tmp << 16) >> 16);
413 env->macsr |= MACSR_V;
415 if (env->macsr & MACSR_V) {
416 env->macsr |= MACSR_PAV0 << acc;
417 if (env->macsr & MACSR_OMC) {
418 /* The result is saturated to 32 bits, despite overflow occurring
419 at 48 bits. Seems weird, but that's what the hardware docs
421 result = (result >> 63) ^ 0x7fffffff;
424 env->macc[acc] = result;
427 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
431 val = env->macc[acc];
432 if (val & (0xffffull << 48)) {
433 env->macsr |= MACSR_V;
435 if (env->macsr & MACSR_V) {
436 env->macsr |= MACSR_PAV0 << acc;
437 if (env->macsr & MACSR_OMC) {
438 if (val > (1ull << 53))
441 val = (1ull << 48) - 1;
443 val &= ((1ull << 48) - 1);
446 env->macc[acc] = val;
449 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
454 sum = env->macc[acc];
455 result = (sum << 16) >> 16;
457 env->macsr |= MACSR_V;
459 if (env->macsr & MACSR_V) {
460 env->macsr |= MACSR_PAV0 << acc;
461 if (env->macsr & MACSR_OMC) {
462 result = (result >> 63) ^ 0x7fffffffffffll;
465 env->macc[acc] = result;
468 void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
471 val = env->macc[acc];
473 env->macsr |= MACSR_Z;
474 } else if (val & (1ull << 47)) {
475 env->macsr |= MACSR_N;
477 if (env->macsr & (MACSR_PAV0 << acc)) {
478 env->macsr |= MACSR_V;
480 if (env->macsr & MACSR_FI) {
481 val = ((int64_t)val) >> 40;
482 if (val != 0 && val != -1)
483 env->macsr |= MACSR_EV;
484 } else if (env->macsr & MACSR_SU) {
485 val = ((int64_t)val) >> 32;
486 if (val != 0 && val != -1)
487 env->macsr |= MACSR_EV;
489 if ((val >> 32) != 0)
490 env->macsr |= MACSR_EV;
494 #define EXTSIGN(val, index) ( \
495 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
498 #define COMPUTE_CCR(op, x, n, z, v, c) { \
501 /* Everything in place. */ \
508 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
511 v = (res ^ src1) & ~(src1 ^ src2); \
518 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
521 v = (res ^ src1) & (src1 ^ src2); \
528 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
532 v = (res ^ src1) & (src1 ^ src2); \
539 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
543 uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
545 uint32_t x, c, n, z, v;
546 uint32_t res, src1, src2;
554 COMPUTE_CCR(env->cc_op, x, n, z, v, c);
560 return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
563 uint32_t HELPER(get_ccr)(CPUM68KState *env)
565 return cpu_m68k_get_ccr(env);
568 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
570 env->cc_x = (ccr & CCF_X ? 1 : 0);
571 env->cc_n = (ccr & CCF_N ? -1 : 0);
572 env->cc_z = (ccr & CCF_Z ? 0 : 1);
573 env->cc_v = (ccr & CCF_V ? -1 : 0);
574 env->cc_c = (ccr & CCF_C ? 1 : 0);
575 env->cc_op = CC_OP_FLAGS;
578 void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
580 cpu_m68k_set_ccr(env, ccr);
583 void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
585 uint32_t res, src1, src2;
587 COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
588 env->cc_op = CC_OP_FLAGS;
591 uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
596 if (env->macsr & MACSR_SU) {
597 /* 16-bit rounding. */
598 rem = val & 0xffffff;
599 val = (val >> 24) & 0xffffu;
602 else if (rem == 0x800000)
604 } else if (env->macsr & MACSR_RT) {
605 /* 32-bit rounding. */
610 else if (rem == 0x80)
616 if (env->macsr & MACSR_OMC) {
618 if (env->macsr & MACSR_SU) {
619 if (val != (uint16_t) val) {
620 result = ((val >> 63) ^ 0x7fff) & 0xffff;
622 result = val & 0xffff;
625 if (val != (uint32_t)val) {
626 result = ((uint32_t)(val >> 63) & 0x7fffffff);
628 result = (uint32_t)val;
633 if (env->macsr & MACSR_SU) {
634 result = val & 0xffff;
636 result = (uint32_t)val;
642 uint32_t HELPER(get_macs)(uint64_t val)
644 if (val == (int32_t)val) {
647 return (val >> 61) ^ ~SIGNBIT;
651 uint32_t HELPER(get_macu)(uint64_t val)
653 if ((val >> 32) == 0) {
654 return (uint32_t)val;
660 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
663 val = env->macc[acc] & 0x00ff;
664 val |= (env->macc[acc] >> 32) & 0xff00;
665 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
666 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
670 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
673 val = (env->macc[acc] >> 32) & 0xffff;
674 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
678 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
682 res = env->macc[acc] & 0xffffffff00ull;
683 tmp = (int16_t)(val & 0xff00);
684 res |= ((int64_t)tmp) << 32;
686 env->macc[acc] = res;
687 res = env->macc[acc + 1] & 0xffffffff00ull;
688 tmp = (val & 0xff000000);
689 res |= ((int64_t)tmp) << 16;
690 res |= (val >> 16) & 0xff;
691 env->macc[acc + 1] = res;
694 void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
698 res = (uint32_t)env->macc[acc];
700 res |= ((int64_t)tmp) << 32;
701 env->macc[acc] = res;
702 res = (uint32_t)env->macc[acc + 1];
703 tmp = val & 0xffff0000;
704 res |= (int64_t)tmp << 16;
705 env->macc[acc + 1] = res;
708 void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
711 res = (uint32_t)env->macc[acc];
712 res |= ((uint64_t)(val & 0xffff)) << 32;
713 env->macc[acc] = res;
714 res = (uint32_t)env->macc[acc + 1];
715 res |= (uint64_t)(val & 0xffff0000) << 16;
716 env->macc[acc + 1] = res;