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