io: get rid of bounce buffering in websock write path
[qemu/ar7.git] / target / m68k / helper.c
blob7e50ff587145bd68dc9bac5fe717fd266aed3b01
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 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(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
176 M68kCPU *cpu = m68k_env_get_cpu(env);
178 switch (reg) {
179 case 0x02: /* CACR */
180 env->cacr = val;
181 m68k_switch_sp(env);
182 break;
183 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
184 /* TODO: Implement Access Control Registers. */
185 break;
186 case 0x801: /* VBR */
187 env->vbr = val;
188 break;
189 /* TODO: Implement control registers. */
190 default:
191 cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
192 reg, val);
196 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
198 uint32_t acc;
199 int8_t exthigh;
200 uint8_t extlow;
201 uint64_t regval;
202 int i;
203 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
204 for (i = 0; i < 4; i++) {
205 regval = env->macc[i];
206 exthigh = regval >> 40;
207 if (env->macsr & MACSR_FI) {
208 acc = regval >> 8;
209 extlow = regval;
210 } else {
211 acc = regval;
212 extlow = regval >> 32;
214 if (env->macsr & MACSR_FI) {
215 regval = (((uint64_t)acc) << 8) | extlow;
216 regval |= ((int64_t)exthigh) << 40;
217 } else if (env->macsr & MACSR_SU) {
218 regval = acc | (((int64_t)extlow) << 32);
219 regval |= ((int64_t)exthigh) << 40;
220 } else {
221 regval = acc | (((uint64_t)extlow) << 32);
222 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
224 env->macc[i] = regval;
227 env->macsr = val;
230 void m68k_switch_sp(CPUM68KState *env)
232 int new_sp;
234 env->sp[env->current_sp] = env->aregs[7];
235 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
236 ? M68K_SSP : M68K_USP;
237 env->aregs[7] = env->sp[new_sp];
238 env->current_sp = new_sp;
241 #if defined(CONFIG_USER_ONLY)
243 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
244 int mmu_idx)
246 M68kCPU *cpu = M68K_CPU(cs);
248 cs->exception_index = EXCP_ACCESS;
249 cpu->env.mmu.ar = address;
250 return 1;
253 #else
255 /* MMU */
257 /* TODO: This will need fixing once the MMU is implemented. */
258 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
260 return addr;
263 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
264 int mmu_idx)
266 int prot;
268 address &= TARGET_PAGE_MASK;
269 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
270 tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
271 return 0;
274 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
275 be handled by the interrupt controller. Real hardware only requests
276 the vector when the interrupt is acknowledged by the CPU. For
277 simplicitly we calculate it when the interrupt is signalled. */
278 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
280 CPUState *cs = CPU(cpu);
281 CPUM68KState *env = &cpu->env;
283 env->pending_level = level;
284 env->pending_vector = vector;
285 if (level) {
286 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
287 } else {
288 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
292 #endif
294 uint32_t HELPER(bitrev)(uint32_t x)
296 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
297 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
298 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
299 return bswap32(x);
302 uint32_t HELPER(ff1)(uint32_t x)
304 int n;
305 for (n = 32; x; n--)
306 x >>= 1;
307 return n;
310 uint32_t HELPER(sats)(uint32_t val, uint32_t v)
312 /* The result has the opposite sign to the original value. */
313 if ((int32_t)v < 0) {
314 val = (((int32_t)val) >> 31) ^ SIGNBIT;
316 return val;
319 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
321 env->sr = val & 0xffe0;
322 cpu_m68k_set_ccr(env, val);
323 m68k_switch_sp(env);
327 /* MAC unit. */
328 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
329 take values, others take register numbers and manipulate the contents
330 in-place. */
331 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
333 uint32_t mask;
334 env->macc[dest] = env->macc[src];
335 mask = MACSR_PAV0 << dest;
336 if (env->macsr & (MACSR_PAV0 << src))
337 env->macsr |= mask;
338 else
339 env->macsr &= ~mask;
342 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
344 int64_t product;
345 int64_t res;
347 product = (uint64_t)op1 * op2;
348 res = (product << 24) >> 24;
349 if (res != product) {
350 env->macsr |= MACSR_V;
351 if (env->macsr & MACSR_OMC) {
352 /* Make sure the accumulate operation overflows. */
353 if (product < 0)
354 res = ~(1ll << 50);
355 else
356 res = 1ll << 50;
359 return res;
362 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
364 uint64_t product;
366 product = (uint64_t)op1 * op2;
367 if (product & (0xffffffull << 40)) {
368 env->macsr |= MACSR_V;
369 if (env->macsr & MACSR_OMC) {
370 /* Make sure the accumulate operation overflows. */
371 product = 1ll << 50;
372 } else {
373 product &= ((1ull << 40) - 1);
376 return product;
379 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
381 uint64_t product;
382 uint32_t remainder;
384 product = (uint64_t)op1 * op2;
385 if (env->macsr & MACSR_RT) {
386 remainder = product & 0xffffff;
387 product >>= 24;
388 if (remainder > 0x800000)
389 product++;
390 else if (remainder == 0x800000)
391 product += (product & 1);
392 } else {
393 product >>= 24;
395 return product;
398 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
400 int64_t tmp;
401 int64_t result;
402 tmp = env->macc[acc];
403 result = ((tmp << 16) >> 16);
404 if (result != tmp) {
405 env->macsr |= MACSR_V;
407 if (env->macsr & MACSR_V) {
408 env->macsr |= MACSR_PAV0 << acc;
409 if (env->macsr & MACSR_OMC) {
410 /* The result is saturated to 32 bits, despite overflow occurring
411 at 48 bits. Seems weird, but that's what the hardware docs
412 say. */
413 result = (result >> 63) ^ 0x7fffffff;
416 env->macc[acc] = result;
419 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
421 uint64_t val;
423 val = env->macc[acc];
424 if (val & (0xffffull << 48)) {
425 env->macsr |= MACSR_V;
427 if (env->macsr & MACSR_V) {
428 env->macsr |= MACSR_PAV0 << acc;
429 if (env->macsr & MACSR_OMC) {
430 if (val > (1ull << 53))
431 val = 0;
432 else
433 val = (1ull << 48) - 1;
434 } else {
435 val &= ((1ull << 48) - 1);
438 env->macc[acc] = val;
441 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
443 int64_t sum;
444 int64_t result;
446 sum = env->macc[acc];
447 result = (sum << 16) >> 16;
448 if (result != sum) {
449 env->macsr |= MACSR_V;
451 if (env->macsr & MACSR_V) {
452 env->macsr |= MACSR_PAV0 << acc;
453 if (env->macsr & MACSR_OMC) {
454 result = (result >> 63) ^ 0x7fffffffffffll;
457 env->macc[acc] = result;
460 void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
462 uint64_t val;
463 val = env->macc[acc];
464 if (val == 0) {
465 env->macsr |= MACSR_Z;
466 } else if (val & (1ull << 47)) {
467 env->macsr |= MACSR_N;
469 if (env->macsr & (MACSR_PAV0 << acc)) {
470 env->macsr |= MACSR_V;
472 if (env->macsr & MACSR_FI) {
473 val = ((int64_t)val) >> 40;
474 if (val != 0 && val != -1)
475 env->macsr |= MACSR_EV;
476 } else if (env->macsr & MACSR_SU) {
477 val = ((int64_t)val) >> 32;
478 if (val != 0 && val != -1)
479 env->macsr |= MACSR_EV;
480 } else {
481 if ((val >> 32) != 0)
482 env->macsr |= MACSR_EV;
486 #define EXTSIGN(val, index) ( \
487 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
490 #define COMPUTE_CCR(op, x, n, z, v, c) { \
491 switch (op) { \
492 case CC_OP_FLAGS: \
493 /* Everything in place. */ \
494 break; \
495 case CC_OP_ADDB: \
496 case CC_OP_ADDW: \
497 case CC_OP_ADDL: \
498 res = n; \
499 src2 = v; \
500 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
501 c = x; \
502 z = n; \
503 v = (res ^ src1) & ~(src1 ^ src2); \
504 break; \
505 case CC_OP_SUBB: \
506 case CC_OP_SUBW: \
507 case CC_OP_SUBL: \
508 res = n; \
509 src2 = v; \
510 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
511 c = x; \
512 z = n; \
513 v = (res ^ src1) & (src1 ^ src2); \
514 break; \
515 case CC_OP_CMPB: \
516 case CC_OP_CMPW: \
517 case CC_OP_CMPL: \
518 src1 = n; \
519 src2 = v; \
520 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
521 n = res; \
522 z = res; \
523 c = src1 < src2; \
524 v = (res ^ src1) & (src1 ^ src2); \
525 break; \
526 case CC_OP_LOGIC: \
527 c = v = 0; \
528 z = n; \
529 break; \
530 default: \
531 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
533 } while (0)
535 uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
537 uint32_t x, c, n, z, v;
538 uint32_t res, src1, src2;
540 x = env->cc_x;
541 n = env->cc_n;
542 z = env->cc_z;
543 v = env->cc_v;
544 c = env->cc_c;
546 COMPUTE_CCR(env->cc_op, x, n, z, v, c);
548 n = n >> 31;
549 z = (z == 0);
550 v = v >> 31;
552 return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
555 uint32_t HELPER(get_ccr)(CPUM68KState *env)
557 return cpu_m68k_get_ccr(env);
560 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
562 env->cc_x = (ccr & CCF_X ? 1 : 0);
563 env->cc_n = (ccr & CCF_N ? -1 : 0);
564 env->cc_z = (ccr & CCF_Z ? 0 : 1);
565 env->cc_v = (ccr & CCF_V ? -1 : 0);
566 env->cc_c = (ccr & CCF_C ? 1 : 0);
567 env->cc_op = CC_OP_FLAGS;
570 void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
572 cpu_m68k_set_ccr(env, ccr);
575 void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
577 uint32_t res, src1, src2;
579 COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
580 env->cc_op = CC_OP_FLAGS;
583 uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
585 int rem;
586 uint32_t result;
588 if (env->macsr & MACSR_SU) {
589 /* 16-bit rounding. */
590 rem = val & 0xffffff;
591 val = (val >> 24) & 0xffffu;
592 if (rem > 0x800000)
593 val++;
594 else if (rem == 0x800000)
595 val += (val & 1);
596 } else if (env->macsr & MACSR_RT) {
597 /* 32-bit rounding. */
598 rem = val & 0xff;
599 val >>= 8;
600 if (rem > 0x80)
601 val++;
602 else if (rem == 0x80)
603 val += (val & 1);
604 } else {
605 /* No rounding. */
606 val >>= 8;
608 if (env->macsr & MACSR_OMC) {
609 /* Saturate. */
610 if (env->macsr & MACSR_SU) {
611 if (val != (uint16_t) val) {
612 result = ((val >> 63) ^ 0x7fff) & 0xffff;
613 } else {
614 result = val & 0xffff;
616 } else {
617 if (val != (uint32_t)val) {
618 result = ((uint32_t)(val >> 63) & 0x7fffffff);
619 } else {
620 result = (uint32_t)val;
623 } else {
624 /* No saturation. */
625 if (env->macsr & MACSR_SU) {
626 result = val & 0xffff;
627 } else {
628 result = (uint32_t)val;
631 return result;
634 uint32_t HELPER(get_macs)(uint64_t val)
636 if (val == (int32_t)val) {
637 return (int32_t)val;
638 } else {
639 return (val >> 61) ^ ~SIGNBIT;
643 uint32_t HELPER(get_macu)(uint64_t val)
645 if ((val >> 32) == 0) {
646 return (uint32_t)val;
647 } else {
648 return 0xffffffffu;
652 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
654 uint32_t val;
655 val = env->macc[acc] & 0x00ff;
656 val |= (env->macc[acc] >> 32) & 0xff00;
657 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
658 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
659 return val;
662 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
664 uint32_t val;
665 val = (env->macc[acc] >> 32) & 0xffff;
666 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
667 return val;
670 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
672 int64_t res;
673 int32_t tmp;
674 res = env->macc[acc] & 0xffffffff00ull;
675 tmp = (int16_t)(val & 0xff00);
676 res |= ((int64_t)tmp) << 32;
677 res |= val & 0xff;
678 env->macc[acc] = res;
679 res = env->macc[acc + 1] & 0xffffffff00ull;
680 tmp = (val & 0xff000000);
681 res |= ((int64_t)tmp) << 16;
682 res |= (val >> 16) & 0xff;
683 env->macc[acc + 1] = res;
686 void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
688 int64_t res;
689 int32_t tmp;
690 res = (uint32_t)env->macc[acc];
691 tmp = (int16_t)val;
692 res |= ((int64_t)tmp) << 32;
693 env->macc[acc] = res;
694 res = (uint32_t)env->macc[acc + 1];
695 tmp = val & 0xffff0000;
696 res |= (int64_t)tmp << 16;
697 env->macc[acc + 1] = res;
700 void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
702 uint64_t res;
703 res = (uint32_t)env->macc[acc];
704 res |= ((uint64_t)(val & 0xffff)) << 32;
705 env->macc[acc] = res;
706 res = (uint32_t)env->macc[acc + 1];
707 res |= (uint64_t)(val & 0xffff0000) << 16;
708 env->macc[acc + 1] = res;