]> git.proxmox.com Git - qemu.git/blob - target-m68k/helper.c
target-m68k: Introduce QOM realizefn for M68kCPU
[qemu.git] / target-m68k / helper.c
1 /*
2 * m68k op helpers
3 *
4 * Copyright (c) 2006-2007 CodeSourcery
5 * Written by Paul Brook
6 *
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.
11 *
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.
16 *
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/>.
19 */
20
21 #include "cpu.h"
22 #include "exec/gdbstub.h"
23
24 #include "helpers.h"
25
26 #define SIGNBIT (1u << 31)
27
28 /* Sort alphabetically, except for "any". */
29 static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b)
30 {
31 ObjectClass *class_a = (ObjectClass *)a;
32 ObjectClass *class_b = (ObjectClass *)b;
33 const char *name_a, *name_b;
34
35 name_a = object_class_get_name(class_a);
36 name_b = object_class_get_name(class_b);
37 if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) {
38 return 1;
39 } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
40 return -1;
41 } else {
42 return strcasecmp(name_a, name_b);
43 }
44 }
45
46 static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
47 {
48 ObjectClass *c = data;
49 CPUListState *s = user_data;
50 const char *typename;
51 char *name;
52
53 typename = object_class_get_name(c);
54 name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
55 (*s->cpu_fprintf)(s->file, "%s\n",
56 name);
57 g_free(name);
58 }
59
60 void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
61 {
62 CPUListState s = {
63 .file = f,
64 .cpu_fprintf = cpu_fprintf,
65 };
66 GSList *list;
67
68 list = object_class_get_list(TYPE_M68K_CPU, false);
69 list = g_slist_sort(list, m68k_cpu_list_compare);
70 g_slist_foreach(list, m68k_cpu_list_entry, &s);
71 g_slist_free(list);
72 }
73
74 static int fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
75 {
76 if (n < 8) {
77 stfq_p(mem_buf, env->fregs[n]);
78 return 8;
79 }
80 if (n < 11) {
81 /* FP control registers (not implemented) */
82 memset(mem_buf, 0, 4);
83 return 4;
84 }
85 return 0;
86 }
87
88 static int fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
89 {
90 if (n < 8) {
91 env->fregs[n] = ldfq_p(mem_buf);
92 return 8;
93 }
94 if (n < 11) {
95 /* FP control registers (not implemented) */
96 return 4;
97 }
98 return 0;
99 }
100
101 CPUM68KState *cpu_m68k_init(const char *cpu_model)
102 {
103 M68kCPU *cpu;
104 CPUM68KState *env;
105 ObjectClass *oc;
106 static int inited;
107
108 oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model);
109 if (oc == NULL) {
110 return NULL;
111 }
112 cpu = M68K_CPU(object_new(object_class_get_name(oc)));
113 env = &cpu->env;
114
115 if (!inited) {
116 inited = 1;
117 m68k_tcg_init();
118 }
119
120 env->cpu_model_str = cpu_model;
121
122 register_m68k_insns(env);
123
124 object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
125
126 return env;
127 }
128
129 void m68k_cpu_init_gdb(M68kCPU *cpu)
130 {
131 CPUM68KState *env = &cpu->env;
132
133 if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
134 gdb_register_coprocessor(env, fpu_gdb_get_reg, fpu_gdb_set_reg,
135 11, "cf-fp.xml", 18);
136 }
137 /* TODO: Add [E]MAC registers. */
138 }
139
140 void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
141 {
142 int flags;
143 uint32_t src;
144 uint32_t dest;
145 uint32_t tmp;
146
147 #define HIGHBIT 0x80000000u
148
149 #define SET_NZ(x) do { \
150 if ((x) == 0) \
151 flags |= CCF_Z; \
152 else if ((int32_t)(x) < 0) \
153 flags |= CCF_N; \
154 } while (0)
155
156 #define SET_FLAGS_SUB(type, utype) do { \
157 SET_NZ((type)dest); \
158 tmp = dest + src; \
159 if ((utype) tmp < (utype) src) \
160 flags |= CCF_C; \
161 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
162 flags |= CCF_V; \
163 } while (0)
164
165 flags = 0;
166 src = env->cc_src;
167 dest = env->cc_dest;
168 switch (cc_op) {
169 case CC_OP_FLAGS:
170 flags = dest;
171 break;
172 case CC_OP_LOGIC:
173 SET_NZ(dest);
174 break;
175 case CC_OP_ADD:
176 SET_NZ(dest);
177 if (dest < src)
178 flags |= CCF_C;
179 tmp = dest - src;
180 if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
181 flags |= CCF_V;
182 break;
183 case CC_OP_SUB:
184 SET_FLAGS_SUB(int32_t, uint32_t);
185 break;
186 case CC_OP_CMPB:
187 SET_FLAGS_SUB(int8_t, uint8_t);
188 break;
189 case CC_OP_CMPW:
190 SET_FLAGS_SUB(int16_t, uint16_t);
191 break;
192 case CC_OP_ADDX:
193 SET_NZ(dest);
194 if (dest <= src)
195 flags |= CCF_C;
196 tmp = dest - src - 1;
197 if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
198 flags |= CCF_V;
199 break;
200 case CC_OP_SUBX:
201 SET_NZ(dest);
202 tmp = dest + src + 1;
203 if (tmp <= src)
204 flags |= CCF_C;
205 if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
206 flags |= CCF_V;
207 break;
208 case CC_OP_SHIFT:
209 SET_NZ(dest);
210 if (src)
211 flags |= CCF_C;
212 break;
213 default:
214 cpu_abort(env, "Bad CC_OP %d", cc_op);
215 }
216 env->cc_op = CC_OP_FLAGS;
217 env->cc_dest = flags;
218 }
219
220 void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
221 {
222 switch (reg) {
223 case 0x02: /* CACR */
224 env->cacr = val;
225 m68k_switch_sp(env);
226 break;
227 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
228 /* TODO: Implement Access Control Registers. */
229 break;
230 case 0x801: /* VBR */
231 env->vbr = val;
232 break;
233 /* TODO: Implement control registers. */
234 default:
235 cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
236 reg, val);
237 }
238 }
239
240 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
241 {
242 uint32_t acc;
243 int8_t exthigh;
244 uint8_t extlow;
245 uint64_t regval;
246 int i;
247 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
248 for (i = 0; i < 4; i++) {
249 regval = env->macc[i];
250 exthigh = regval >> 40;
251 if (env->macsr & MACSR_FI) {
252 acc = regval >> 8;
253 extlow = regval;
254 } else {
255 acc = regval;
256 extlow = regval >> 32;
257 }
258 if (env->macsr & MACSR_FI) {
259 regval = (((uint64_t)acc) << 8) | extlow;
260 regval |= ((int64_t)exthigh) << 40;
261 } else if (env->macsr & MACSR_SU) {
262 regval = acc | (((int64_t)extlow) << 32);
263 regval |= ((int64_t)exthigh) << 40;
264 } else {
265 regval = acc | (((uint64_t)extlow) << 32);
266 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
267 }
268 env->macc[i] = regval;
269 }
270 }
271 env->macsr = val;
272 }
273
274 void m68k_switch_sp(CPUM68KState *env)
275 {
276 int new_sp;
277
278 env->sp[env->current_sp] = env->aregs[7];
279 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
280 ? M68K_SSP : M68K_USP;
281 env->aregs[7] = env->sp[new_sp];
282 env->current_sp = new_sp;
283 }
284
285 #if defined(CONFIG_USER_ONLY)
286
287 int cpu_m68k_handle_mmu_fault (CPUM68KState *env, target_ulong address, int rw,
288 int mmu_idx)
289 {
290 env->exception_index = EXCP_ACCESS;
291 env->mmu.ar = address;
292 return 1;
293 }
294
295 #else
296
297 /* MMU */
298
299 /* TODO: This will need fixing once the MMU is implemented. */
300 hwaddr cpu_get_phys_page_debug(CPUM68KState *env, target_ulong addr)
301 {
302 return addr;
303 }
304
305 int cpu_m68k_handle_mmu_fault (CPUM68KState *env, target_ulong address, int rw,
306 int mmu_idx)
307 {
308 int prot;
309
310 address &= TARGET_PAGE_MASK;
311 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
312 tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
313 return 0;
314 }
315
316 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
317 be handled by the interrupt controller. Real hardware only requests
318 the vector when the interrupt is acknowledged by the CPU. For
319 simplicitly we calculate it when the interrupt is signalled. */
320 void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
321 {
322 env->pending_level = level;
323 env->pending_vector = vector;
324 if (level)
325 cpu_interrupt(env, CPU_INTERRUPT_HARD);
326 else
327 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
328 }
329
330 #endif
331
332 uint32_t HELPER(bitrev)(uint32_t x)
333 {
334 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
335 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
336 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
337 return bswap32(x);
338 }
339
340 uint32_t HELPER(ff1)(uint32_t x)
341 {
342 int n;
343 for (n = 32; x; n--)
344 x >>= 1;
345 return n;
346 }
347
348 uint32_t HELPER(sats)(uint32_t val, uint32_t ccr)
349 {
350 /* The result has the opposite sign to the original value. */
351 if (ccr & CCF_V)
352 val = (((int32_t)val) >> 31) ^ SIGNBIT;
353 return val;
354 }
355
356 uint32_t HELPER(subx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2)
357 {
358 uint32_t res;
359 uint32_t old_flags;
360
361 old_flags = env->cc_dest;
362 if (env->cc_x) {
363 env->cc_x = (op1 <= op2);
364 env->cc_op = CC_OP_SUBX;
365 res = op1 - (op2 + 1);
366 } else {
367 env->cc_x = (op1 < op2);
368 env->cc_op = CC_OP_SUB;
369 res = op1 - op2;
370 }
371 env->cc_dest = res;
372 env->cc_src = op2;
373 cpu_m68k_flush_flags(env, env->cc_op);
374 /* !Z is sticky. */
375 env->cc_dest &= (old_flags | ~CCF_Z);
376 return res;
377 }
378
379 uint32_t HELPER(addx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2)
380 {
381 uint32_t res;
382 uint32_t old_flags;
383
384 old_flags = env->cc_dest;
385 if (env->cc_x) {
386 res = op1 + op2 + 1;
387 env->cc_x = (res <= op2);
388 env->cc_op = CC_OP_ADDX;
389 } else {
390 res = op1 + op2;
391 env->cc_x = (res < op2);
392 env->cc_op = CC_OP_ADD;
393 }
394 env->cc_dest = res;
395 env->cc_src = op2;
396 cpu_m68k_flush_flags(env, env->cc_op);
397 /* !Z is sticky. */
398 env->cc_dest &= (old_flags | ~CCF_Z);
399 return res;
400 }
401
402 uint32_t HELPER(xflag_lt)(uint32_t a, uint32_t b)
403 {
404 return a < b;
405 }
406
407 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
408 {
409 env->sr = val & 0xffff;
410 m68k_switch_sp(env);
411 }
412
413 uint32_t HELPER(shl_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
414 {
415 uint32_t result;
416 uint32_t cf;
417
418 shift &= 63;
419 if (shift == 0) {
420 result = val;
421 cf = env->cc_src & CCF_C;
422 } else if (shift < 32) {
423 result = val << shift;
424 cf = (val >> (32 - shift)) & 1;
425 } else if (shift == 32) {
426 result = 0;
427 cf = val & 1;
428 } else /* shift > 32 */ {
429 result = 0;
430 cf = 0;
431 }
432 env->cc_src = cf;
433 env->cc_x = (cf != 0);
434 env->cc_dest = result;
435 return result;
436 }
437
438 uint32_t HELPER(shr_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
439 {
440 uint32_t result;
441 uint32_t cf;
442
443 shift &= 63;
444 if (shift == 0) {
445 result = val;
446 cf = env->cc_src & CCF_C;
447 } else if (shift < 32) {
448 result = val >> shift;
449 cf = (val >> (shift - 1)) & 1;
450 } else if (shift == 32) {
451 result = 0;
452 cf = val >> 31;
453 } else /* shift > 32 */ {
454 result = 0;
455 cf = 0;
456 }
457 env->cc_src = cf;
458 env->cc_x = (cf != 0);
459 env->cc_dest = result;
460 return result;
461 }
462
463 uint32_t HELPER(sar_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
464 {
465 uint32_t result;
466 uint32_t cf;
467
468 shift &= 63;
469 if (shift == 0) {
470 result = val;
471 cf = (env->cc_src & CCF_C) != 0;
472 } else if (shift < 32) {
473 result = (int32_t)val >> shift;
474 cf = (val >> (shift - 1)) & 1;
475 } else /* shift >= 32 */ {
476 result = (int32_t)val >> 31;
477 cf = val >> 31;
478 }
479 env->cc_src = cf;
480 env->cc_x = cf;
481 env->cc_dest = result;
482 return result;
483 }
484
485 /* FPU helpers. */
486 uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val)
487 {
488 return float64_to_int32(val, &env->fp_status);
489 }
490
491 float32 HELPER(f64_to_f32)(CPUM68KState *env, float64 val)
492 {
493 return float64_to_float32(val, &env->fp_status);
494 }
495
496 float64 HELPER(i32_to_f64)(CPUM68KState *env, uint32_t val)
497 {
498 return int32_to_float64(val, &env->fp_status);
499 }
500
501 float64 HELPER(f32_to_f64)(CPUM68KState *env, float32 val)
502 {
503 return float32_to_float64(val, &env->fp_status);
504 }
505
506 float64 HELPER(iround_f64)(CPUM68KState *env, float64 val)
507 {
508 return float64_round_to_int(val, &env->fp_status);
509 }
510
511 float64 HELPER(itrunc_f64)(CPUM68KState *env, float64 val)
512 {
513 return float64_trunc_to_int(val, &env->fp_status);
514 }
515
516 float64 HELPER(sqrt_f64)(CPUM68KState *env, float64 val)
517 {
518 return float64_sqrt(val, &env->fp_status);
519 }
520
521 float64 HELPER(abs_f64)(float64 val)
522 {
523 return float64_abs(val);
524 }
525
526 float64 HELPER(chs_f64)(float64 val)
527 {
528 return float64_chs(val);
529 }
530
531 float64 HELPER(add_f64)(CPUM68KState *env, float64 a, float64 b)
532 {
533 return float64_add(a, b, &env->fp_status);
534 }
535
536 float64 HELPER(sub_f64)(CPUM68KState *env, float64 a, float64 b)
537 {
538 return float64_sub(a, b, &env->fp_status);
539 }
540
541 float64 HELPER(mul_f64)(CPUM68KState *env, float64 a, float64 b)
542 {
543 return float64_mul(a, b, &env->fp_status);
544 }
545
546 float64 HELPER(div_f64)(CPUM68KState *env, float64 a, float64 b)
547 {
548 return float64_div(a, b, &env->fp_status);
549 }
550
551 float64 HELPER(sub_cmp_f64)(CPUM68KState *env, float64 a, float64 b)
552 {
553 /* ??? This may incorrectly raise exceptions. */
554 /* ??? Should flush denormals to zero. */
555 float64 res;
556 res = float64_sub(a, b, &env->fp_status);
557 if (float64_is_quiet_nan(res)) {
558 /* +/-inf compares equal against itself, but sub returns nan. */
559 if (!float64_is_quiet_nan(a)
560 && !float64_is_quiet_nan(b)) {
561 res = float64_zero;
562 if (float64_lt_quiet(a, res, &env->fp_status))
563 res = float64_chs(res);
564 }
565 }
566 return res;
567 }
568
569 uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
570 {
571 return float64_compare_quiet(val, float64_zero, &env->fp_status);
572 }
573
574 /* MAC unit. */
575 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
576 take values, others take register numbers and manipulate the contents
577 in-place. */
578 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
579 {
580 uint32_t mask;
581 env->macc[dest] = env->macc[src];
582 mask = MACSR_PAV0 << dest;
583 if (env->macsr & (MACSR_PAV0 << src))
584 env->macsr |= mask;
585 else
586 env->macsr &= ~mask;
587 }
588
589 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
590 {
591 int64_t product;
592 int64_t res;
593
594 product = (uint64_t)op1 * op2;
595 res = (product << 24) >> 24;
596 if (res != product) {
597 env->macsr |= MACSR_V;
598 if (env->macsr & MACSR_OMC) {
599 /* Make sure the accumulate operation overflows. */
600 if (product < 0)
601 res = ~(1ll << 50);
602 else
603 res = 1ll << 50;
604 }
605 }
606 return res;
607 }
608
609 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
610 {
611 uint64_t product;
612
613 product = (uint64_t)op1 * op2;
614 if (product & (0xffffffull << 40)) {
615 env->macsr |= MACSR_V;
616 if (env->macsr & MACSR_OMC) {
617 /* Make sure the accumulate operation overflows. */
618 product = 1ll << 50;
619 } else {
620 product &= ((1ull << 40) - 1);
621 }
622 }
623 return product;
624 }
625
626 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
627 {
628 uint64_t product;
629 uint32_t remainder;
630
631 product = (uint64_t)op1 * op2;
632 if (env->macsr & MACSR_RT) {
633 remainder = product & 0xffffff;
634 product >>= 24;
635 if (remainder > 0x800000)
636 product++;
637 else if (remainder == 0x800000)
638 product += (product & 1);
639 } else {
640 product >>= 24;
641 }
642 return product;
643 }
644
645 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
646 {
647 int64_t tmp;
648 int64_t result;
649 tmp = env->macc[acc];
650 result = ((tmp << 16) >> 16);
651 if (result != tmp) {
652 env->macsr |= MACSR_V;
653 }
654 if (env->macsr & MACSR_V) {
655 env->macsr |= MACSR_PAV0 << acc;
656 if (env->macsr & MACSR_OMC) {
657 /* The result is saturated to 32 bits, despite overflow occurring
658 at 48 bits. Seems weird, but that's what the hardware docs
659 say. */
660 result = (result >> 63) ^ 0x7fffffff;
661 }
662 }
663 env->macc[acc] = result;
664 }
665
666 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
667 {
668 uint64_t val;
669
670 val = env->macc[acc];
671 if (val & (0xffffull << 48)) {
672 env->macsr |= MACSR_V;
673 }
674 if (env->macsr & MACSR_V) {
675 env->macsr |= MACSR_PAV0 << acc;
676 if (env->macsr & MACSR_OMC) {
677 if (val > (1ull << 53))
678 val = 0;
679 else
680 val = (1ull << 48) - 1;
681 } else {
682 val &= ((1ull << 48) - 1);
683 }
684 }
685 env->macc[acc] = val;
686 }
687
688 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
689 {
690 int64_t sum;
691 int64_t result;
692
693 sum = env->macc[acc];
694 result = (sum << 16) >> 16;
695 if (result != sum) {
696 env->macsr |= MACSR_V;
697 }
698 if (env->macsr & MACSR_V) {
699 env->macsr |= MACSR_PAV0 << acc;
700 if (env->macsr & MACSR_OMC) {
701 result = (result >> 63) ^ 0x7fffffffffffll;
702 }
703 }
704 env->macc[acc] = result;
705 }
706
707 void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
708 {
709 uint64_t val;
710 val = env->macc[acc];
711 if (val == 0) {
712 env->macsr |= MACSR_Z;
713 } else if (val & (1ull << 47)) {
714 env->macsr |= MACSR_N;
715 }
716 if (env->macsr & (MACSR_PAV0 << acc)) {
717 env->macsr |= MACSR_V;
718 }
719 if (env->macsr & MACSR_FI) {
720 val = ((int64_t)val) >> 40;
721 if (val != 0 && val != -1)
722 env->macsr |= MACSR_EV;
723 } else if (env->macsr & MACSR_SU) {
724 val = ((int64_t)val) >> 32;
725 if (val != 0 && val != -1)
726 env->macsr |= MACSR_EV;
727 } else {
728 if ((val >> 32) != 0)
729 env->macsr |= MACSR_EV;
730 }
731 }
732
733 void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
734 {
735 cpu_m68k_flush_flags(env, cc_op);
736 }
737
738 uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
739 {
740 int rem;
741 uint32_t result;
742
743 if (env->macsr & MACSR_SU) {
744 /* 16-bit rounding. */
745 rem = val & 0xffffff;
746 val = (val >> 24) & 0xffffu;
747 if (rem > 0x800000)
748 val++;
749 else if (rem == 0x800000)
750 val += (val & 1);
751 } else if (env->macsr & MACSR_RT) {
752 /* 32-bit rounding. */
753 rem = val & 0xff;
754 val >>= 8;
755 if (rem > 0x80)
756 val++;
757 else if (rem == 0x80)
758 val += (val & 1);
759 } else {
760 /* No rounding. */
761 val >>= 8;
762 }
763 if (env->macsr & MACSR_OMC) {
764 /* Saturate. */
765 if (env->macsr & MACSR_SU) {
766 if (val != (uint16_t) val) {
767 result = ((val >> 63) ^ 0x7fff) & 0xffff;
768 } else {
769 result = val & 0xffff;
770 }
771 } else {
772 if (val != (uint32_t)val) {
773 result = ((uint32_t)(val >> 63) & 0x7fffffff);
774 } else {
775 result = (uint32_t)val;
776 }
777 }
778 } else {
779 /* No saturation. */
780 if (env->macsr & MACSR_SU) {
781 result = val & 0xffff;
782 } else {
783 result = (uint32_t)val;
784 }
785 }
786 return result;
787 }
788
789 uint32_t HELPER(get_macs)(uint64_t val)
790 {
791 if (val == (int32_t)val) {
792 return (int32_t)val;
793 } else {
794 return (val >> 61) ^ ~SIGNBIT;
795 }
796 }
797
798 uint32_t HELPER(get_macu)(uint64_t val)
799 {
800 if ((val >> 32) == 0) {
801 return (uint32_t)val;
802 } else {
803 return 0xffffffffu;
804 }
805 }
806
807 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
808 {
809 uint32_t val;
810 val = env->macc[acc] & 0x00ff;
811 val = (env->macc[acc] >> 32) & 0xff00;
812 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
813 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
814 return val;
815 }
816
817 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
818 {
819 uint32_t val;
820 val = (env->macc[acc] >> 32) & 0xffff;
821 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
822 return val;
823 }
824
825 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
826 {
827 int64_t res;
828 int32_t tmp;
829 res = env->macc[acc] & 0xffffffff00ull;
830 tmp = (int16_t)(val & 0xff00);
831 res |= ((int64_t)tmp) << 32;
832 res |= val & 0xff;
833 env->macc[acc] = res;
834 res = env->macc[acc + 1] & 0xffffffff00ull;
835 tmp = (val & 0xff000000);
836 res |= ((int64_t)tmp) << 16;
837 res |= (val >> 16) & 0xff;
838 env->macc[acc + 1] = res;
839 }
840
841 void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
842 {
843 int64_t res;
844 int32_t tmp;
845 res = (uint32_t)env->macc[acc];
846 tmp = (int16_t)val;
847 res |= ((int64_t)tmp) << 32;
848 env->macc[acc] = res;
849 res = (uint32_t)env->macc[acc + 1];
850 tmp = val & 0xffff0000;
851 res |= (int64_t)tmp << 16;
852 env->macc[acc + 1] = res;
853 }
854
855 void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
856 {
857 uint64_t res;
858 res = (uint32_t)env->macc[acc];
859 res |= ((uint64_t)(val & 0xffff)) << 32;
860 env->macc[acc] = res;
861 res = (uint32_t)env->macc[acc + 1];
862 res |= (uint64_t)(val & 0xffff0000) << 16;
863 env->macc[acc + 1] = res;
864 }