qapi: drop the sentinel in enum array
[qemu/armbru.git] / target / m68k / helper.c
blobcaae29100cabad31e60c9ca0bed143386e1b1259
1 /*
2 * m68k op helpers
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"
22 #include "cpu.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) {
40 return 1;
41 } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
42 return -1;
43 } else {
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;
52 const char *typename;
53 char *name;
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",
58 name);
59 g_free(name);
62 void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
64 CPUListState s = {
65 .file = f,
66 .cpu_fprintf = cpu_fprintf,
68 GSList *list;
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);
73 g_slist_free(list);
76 static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
78 if (n < 8) {
79 float_status s;
80 stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
81 return 8;
83 switch (n) {
84 case 8: /* fpcontrol */
85 stl_be_p(mem_buf, env->fpcr);
86 return 4;
87 case 9: /* fpstatus */
88 stl_be_p(mem_buf, env->fpsr);
89 return 4;
90 case 10: /* fpiar, not implemented */
91 memset(mem_buf, 0, 4);
92 return 4;
94 return 0;
97 static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
99 if (n < 8) {
100 float_status s;
101 env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
102 return 8;
104 switch (n) {
105 case 8: /* fpcontrol */
106 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
107 return 4;
108 case 9: /* fpstatus */
109 env->fpsr = ldl_p(mem_buf);
110 return 4;
111 case 10: /* fpiar, not implemented */
112 return 4;
114 return 0;
117 static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
119 if (n < 8) {
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);
123 return 12;
125 switch (n) {
126 case 8: /* fpcontrol */
127 stl_be_p(mem_buf, env->fpcr);
128 return 4;
129 case 9: /* fpstatus */
130 stl_be_p(mem_buf, env->fpsr);
131 return 4;
132 case 10: /* fpiar, not implemented */
133 memset(mem_buf, 0, 4);
134 return 4;
136 return 0;
139 static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
141 if (n < 8) {
142 env->fregs[n].l.upper = lduw_be_p(mem_buf);
143 env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
144 return 12;
146 switch (n) {
147 case 8: /* fpcontrol */
148 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
149 return 4;
150 case 9: /* fpstatus */
151 env->fpsr = ldl_p(mem_buf);
152 return 4;
153 case 10: /* fpiar, not implemented */
154 return 4;
156 return 0;
159 M68kCPU *cpu_m68k_init(const char *cpu_model)
161 M68kCPU *cpu;
162 CPUM68KState *env;
163 ObjectClass *oc;
165 oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model);
166 if (oc == NULL) {
167 return NULL;
169 cpu = M68K_CPU(object_new(object_class_get_name(oc)));
170 env = &cpu->env;
172 register_m68k_insns(env);
174 object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
176 return cpu;
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);
198 switch (reg) {
199 case 0x02: /* CACR */
200 env->cacr = val;
201 m68k_switch_sp(env);
202 break;
203 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
204 /* TODO: Implement Access Control Registers. */
205 break;
206 case 0x801: /* VBR */
207 env->vbr = val;
208 break;
209 /* TODO: Implement control registers. */
210 default:
211 cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
212 reg, val);
216 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
218 uint32_t acc;
219 int8_t exthigh;
220 uint8_t extlow;
221 uint64_t regval;
222 int i;
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) {
228 acc = regval >> 8;
229 extlow = regval;
230 } else {
231 acc = regval;
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;
240 } else {
241 regval = acc | (((uint64_t)extlow) << 32);
242 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
244 env->macc[i] = regval;
247 env->macsr = val;
250 void m68k_switch_sp(CPUM68KState *env)
252 int new_sp;
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,
264 int mmu_idx)
266 M68kCPU *cpu = M68K_CPU(cs);
268 cs->exception_index = EXCP_ACCESS;
269 cpu->env.mmu.ar = address;
270 return 1;
273 #else
275 /* MMU */
277 /* TODO: This will need fixing once the MMU is implemented. */
278 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
280 return addr;
283 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
284 int mmu_idx)
286 int prot;
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);
291 return 0;
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;
305 if (level) {
306 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
307 } else {
308 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
312 #endif
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);
319 return bswap32(x);
322 uint32_t HELPER(ff1)(uint32_t x)
324 int n;
325 for (n = 32; x; n--)
326 x >>= 1;
327 return n;
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;
336 return val;
339 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
341 env->sr = val & 0xffe0;
342 cpu_m68k_set_ccr(env, val);
343 m68k_switch_sp(env);
347 /* MAC unit. */
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
350 in-place. */
351 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
353 uint32_t mask;
354 env->macc[dest] = env->macc[src];
355 mask = MACSR_PAV0 << dest;
356 if (env->macsr & (MACSR_PAV0 << src))
357 env->macsr |= mask;
358 else
359 env->macsr &= ~mask;
362 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
364 int64_t product;
365 int64_t res;
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. */
373 if (product < 0)
374 res = ~(1ll << 50);
375 else
376 res = 1ll << 50;
379 return res;
382 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
384 uint64_t product;
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. */
391 product = 1ll << 50;
392 } else {
393 product &= ((1ull << 40) - 1);
396 return product;
399 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
401 uint64_t product;
402 uint32_t remainder;
404 product = (uint64_t)op1 * op2;
405 if (env->macsr & MACSR_RT) {
406 remainder = product & 0xffffff;
407 product >>= 24;
408 if (remainder > 0x800000)
409 product++;
410 else if (remainder == 0x800000)
411 product += (product & 1);
412 } else {
413 product >>= 24;
415 return product;
418 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
420 int64_t tmp;
421 int64_t result;
422 tmp = env->macc[acc];
423 result = ((tmp << 16) >> 16);
424 if (result != tmp) {
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
432 say. */
433 result = (result >> 63) ^ 0x7fffffff;
436 env->macc[acc] = result;
439 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
441 uint64_t val;
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))
451 val = 0;
452 else
453 val = (1ull << 48) - 1;
454 } else {
455 val &= ((1ull << 48) - 1);
458 env->macc[acc] = val;
461 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
463 int64_t sum;
464 int64_t result;
466 sum = env->macc[acc];
467 result = (sum << 16) >> 16;
468 if (result != sum) {
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)
482 uint64_t val;
483 val = env->macc[acc];
484 if (val == 0) {
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;
500 } else {
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) { \
511 switch (op) { \
512 case CC_OP_FLAGS: \
513 /* Everything in place. */ \
514 break; \
515 case CC_OP_ADDB: \
516 case CC_OP_ADDW: \
517 case CC_OP_ADDL: \
518 res = n; \
519 src2 = v; \
520 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
521 c = x; \
522 z = n; \
523 v = (res ^ src1) & ~(src1 ^ src2); \
524 break; \
525 case CC_OP_SUBB: \
526 case CC_OP_SUBW: \
527 case CC_OP_SUBL: \
528 res = n; \
529 src2 = v; \
530 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
531 c = x; \
532 z = n; \
533 v = (res ^ src1) & (src1 ^ src2); \
534 break; \
535 case CC_OP_CMPB: \
536 case CC_OP_CMPW: \
537 case CC_OP_CMPL: \
538 src1 = n; \
539 src2 = v; \
540 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
541 n = res; \
542 z = res; \
543 c = src1 < src2; \
544 v = (res ^ src1) & (src1 ^ src2); \
545 break; \
546 case CC_OP_LOGIC: \
547 c = v = 0; \
548 z = n; \
549 break; \
550 default: \
551 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
553 } while (0)
555 uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
557 uint32_t x, c, n, z, v;
558 uint32_t res, src1, src2;
560 x = env->cc_x;
561 n = env->cc_n;
562 z = env->cc_z;
563 v = env->cc_v;
564 c = env->cc_c;
566 COMPUTE_CCR(env->cc_op, x, n, z, v, c);
568 n = n >> 31;
569 z = (z == 0);
570 v = v >> 31;
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)
605 int rem;
606 uint32_t result;
608 if (env->macsr & MACSR_SU) {
609 /* 16-bit rounding. */
610 rem = val & 0xffffff;
611 val = (val >> 24) & 0xffffu;
612 if (rem > 0x800000)
613 val++;
614 else if (rem == 0x800000)
615 val += (val & 1);
616 } else if (env->macsr & MACSR_RT) {
617 /* 32-bit rounding. */
618 rem = val & 0xff;
619 val >>= 8;
620 if (rem > 0x80)
621 val++;
622 else if (rem == 0x80)
623 val += (val & 1);
624 } else {
625 /* No rounding. */
626 val >>= 8;
628 if (env->macsr & MACSR_OMC) {
629 /* Saturate. */
630 if (env->macsr & MACSR_SU) {
631 if (val != (uint16_t) val) {
632 result = ((val >> 63) ^ 0x7fff) & 0xffff;
633 } else {
634 result = val & 0xffff;
636 } else {
637 if (val != (uint32_t)val) {
638 result = ((uint32_t)(val >> 63) & 0x7fffffff);
639 } else {
640 result = (uint32_t)val;
643 } else {
644 /* No saturation. */
645 if (env->macsr & MACSR_SU) {
646 result = val & 0xffff;
647 } else {
648 result = (uint32_t)val;
651 return result;
654 uint32_t HELPER(get_macs)(uint64_t val)
656 if (val == (int32_t)val) {
657 return (int32_t)val;
658 } else {
659 return (val >> 61) ^ ~SIGNBIT;
663 uint32_t HELPER(get_macu)(uint64_t val)
665 if ((val >> 32) == 0) {
666 return (uint32_t)val;
667 } else {
668 return 0xffffffffu;
672 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
674 uint32_t val;
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;
679 return val;
682 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
684 uint32_t val;
685 val = (env->macc[acc] >> 32) & 0xffff;
686 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
687 return val;
690 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
692 int64_t res;
693 int32_t tmp;
694 res = env->macc[acc] & 0xffffffff00ull;
695 tmp = (int16_t)(val & 0xff00);
696 res |= ((int64_t)tmp) << 32;
697 res |= val & 0xff;
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)
708 int64_t res;
709 int32_t tmp;
710 res = (uint32_t)env->macc[acc];
711 tmp = (int16_t)val;
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)
722 uint64_t res;
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;