blob: 674c8e6f071d86d557d5bc957098ba27902133b1 [file] [log] [blame]
pbrooke6e59062006-10-22 00:18:54 +00001/*
2 * m68k op helpers
ths5fafdf22007-09-16 21:08:06 +00003 *
pbrook06338792007-05-23 19:58:11 +00004 * Copyright (c) 2006-2007 CodeSourcery
pbrooke6e59062006-10-22 00:18:54 +00005 * 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
Blue Swirl8167ee82009-07-16 20:47:01 +000018 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
pbrooke6e59062006-10-22 00:18:54 +000019 */
20
21#include <stdio.h>
pbrook0402f762007-05-26 16:52:21 +000022#include <string.h>
pbrooke6e59062006-10-22 00:18:54 +000023
24#include "config.h"
25#include "cpu.h"
aurel32ca10f862008-04-11 21:35:42 +000026#include "qemu-common.h"
pbrook56aebc82008-10-11 17:55:29 +000027#include "gdbstub.h"
pbrooke6e59062006-10-22 00:18:54 +000028
pbrooke1f38082008-05-24 22:29:16 +000029#include "helpers.h"
30
31#define SIGNBIT (1u << 31)
32
pbrook0402f762007-05-26 16:52:21 +000033enum m68k_cpuid {
34 M68K_CPUID_M5206,
pbrook20dcee92007-06-03 11:13:39 +000035 M68K_CPUID_M5208,
pbrook0402f762007-05-26 16:52:21 +000036 M68K_CPUID_CFV4E,
37 M68K_CPUID_ANY,
38};
39
Anthony Liguoric227f092009-10-01 16:12:16 -050040typedef struct m68k_def_t m68k_def_t;
bellardaaed9092007-11-10 15:15:54 +000041
Anthony Liguoric227f092009-10-01 16:12:16 -050042struct m68k_def_t {
pbrook0402f762007-05-26 16:52:21 +000043 const char * name;
44 enum m68k_cpuid id;
45};
46
Anthony Liguoric227f092009-10-01 16:12:16 -050047static m68k_def_t m68k_cpu_defs[] = {
ths5fafdf22007-09-16 21:08:06 +000048 {"m5206", M68K_CPUID_M5206},
49 {"m5208", M68K_CPUID_M5208},
pbrook0402f762007-05-26 16:52:21 +000050 {"cfv4e", M68K_CPUID_CFV4E},
51 {"any", M68K_CPUID_ANY},
ths5fafdf22007-09-16 21:08:06 +000052 {NULL, 0},
pbrook0402f762007-05-26 16:52:21 +000053};
54
Stefan Weil9a78eea2010-10-22 23:03:33 +020055void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
Laurent Vivier009a4352009-05-09 22:21:39 +020056{
57 unsigned int i;
58
59 for (i = 0; m68k_cpu_defs[i].name; i++) {
60 (*cpu_fprintf)(f, "%s\n", m68k_cpu_defs[i].name);
61 }
62}
63
pbrook56aebc82008-10-11 17:55:29 +000064static int fpu_gdb_get_reg(CPUState *env, uint8_t *mem_buf, int n)
65{
66 if (n < 8) {
67 stfq_p(mem_buf, env->fregs[n]);
68 return 8;
69 }
70 if (n < 11) {
71 /* FP control registers (not implemented) */
72 memset(mem_buf, 0, 4);
73 return 4;
74 }
75 return 0;
76}
77
78static int fpu_gdb_set_reg(CPUState *env, uint8_t *mem_buf, int n)
79{
80 if (n < 8) {
81 env->fregs[n] = ldfq_p(mem_buf);
82 return 8;
83 }
84 if (n < 11) {
85 /* FP control registers (not implemented) */
86 return 4;
87 }
88 return 0;
89}
90
pbrook0402f762007-05-26 16:52:21 +000091static void m68k_set_feature(CPUM68KState *env, int feature)
92{
93 env->features |= (1u << feature);
94}
95
bellardaaed9092007-11-10 15:15:54 +000096static int cpu_m68k_set_model(CPUM68KState *env, const char *name)
pbrook0402f762007-05-26 16:52:21 +000097{
Anthony Liguoric227f092009-10-01 16:12:16 -050098 m68k_def_t *def;
pbrook0402f762007-05-26 16:52:21 +000099
100 for (def = m68k_cpu_defs; def->name; def++) {
101 if (strcmp(def->name, name) == 0)
102 break;
103 }
104 if (!def->name)
bellardaaed9092007-11-10 15:15:54 +0000105 return -1;
pbrook0402f762007-05-26 16:52:21 +0000106
107 switch (def->id) {
108 case M68K_CPUID_M5206:
109 m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
110 break;
pbrook20dcee92007-06-03 11:13:39 +0000111 case M68K_CPUID_M5208:
112 m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
pbrookd315c882007-06-03 12:35:08 +0000113 m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
114 m68k_set_feature(env, M68K_FEATURE_BRAL);
pbrook20dcee92007-06-03 11:13:39 +0000115 m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
116 m68k_set_feature(env, M68K_FEATURE_USP);
117 break;
pbrook0402f762007-05-26 16:52:21 +0000118 case M68K_CPUID_CFV4E:
119 m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
120 m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
pbrookd315c882007-06-03 12:35:08 +0000121 m68k_set_feature(env, M68K_FEATURE_BRAL);
pbrook0402f762007-05-26 16:52:21 +0000122 m68k_set_feature(env, M68K_FEATURE_CF_FPU);
pbrook0402f762007-05-26 16:52:21 +0000123 m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
pbrook20dcee92007-06-03 11:13:39 +0000124 m68k_set_feature(env, M68K_FEATURE_USP);
pbrook0402f762007-05-26 16:52:21 +0000125 break;
126 case M68K_CPUID_ANY:
127 m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
128 m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
pbrookd315c882007-06-03 12:35:08 +0000129 m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
130 m68k_set_feature(env, M68K_FEATURE_BRAL);
pbrook0402f762007-05-26 16:52:21 +0000131 m68k_set_feature(env, M68K_FEATURE_CF_FPU);
pbrookacf930a2007-05-29 14:57:59 +0000132 /* MAC and EMAC are mututally exclusive, so pick EMAC.
133 It's mostly backwards compatible. */
pbrook0402f762007-05-26 16:52:21 +0000134 m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
pbrookd315c882007-06-03 12:35:08 +0000135 m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B);
pbrook20dcee92007-06-03 11:13:39 +0000136 m68k_set_feature(env, M68K_FEATURE_USP);
pbrook0402f762007-05-26 16:52:21 +0000137 m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
pbrookd315c882007-06-03 12:35:08 +0000138 m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
pbrook0402f762007-05-26 16:52:21 +0000139 break;
140 }
141
142 register_m68k_insns(env);
pbrook56aebc82008-10-11 17:55:29 +0000143 if (m68k_feature (env, M68K_FEATURE_CF_FPU)) {
144 gdb_register_coprocessor(env, fpu_gdb_get_reg, fpu_gdb_set_reg,
145 11, "cf-fp.xml", 18);
146 }
147 /* TODO: Add [E]MAC registers. */
bellard4f6cf9e2007-11-12 23:12:17 +0000148 return 0;
bellardaaed9092007-11-10 15:15:54 +0000149}
pbrook0402f762007-05-26 16:52:21 +0000150
bellardaaed9092007-11-10 15:15:54 +0000151void cpu_reset(CPUM68KState *env)
152{
aliguorieca1bdf2009-01-26 19:54:31 +0000153 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
154 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
155 log_cpu_state(env, 0);
156 }
157
bellardaaed9092007-11-10 15:15:54 +0000158 memset(env, 0, offsetof(CPUM68KState, breakpoints));
159#if !defined (CONFIG_USER_ONLY)
160 env->sr = 0x2700;
161#endif
162 m68k_switch_sp(env);
163 /* ??? FP regs should be initialized to NaN. */
164 env->cc_op = CC_OP_FLAGS;
165 /* TODO: We should set PC from the interrupt vector. */
166 env->pc = 0;
167 tlb_flush(env, 1);
168}
169
170CPUM68KState *cpu_m68k_init(const char *cpu_model)
171{
172 CPUM68KState *env;
pbrooke1f38082008-05-24 22:29:16 +0000173 static int inited;
bellardaaed9092007-11-10 15:15:54 +0000174
Anthony Liguori7267c092011-08-20 22:09:37 -0500175 env = g_malloc0(sizeof(CPUM68KState));
bellardaaed9092007-11-10 15:15:54 +0000176 cpu_exec_init(env);
pbrooke1f38082008-05-24 22:29:16 +0000177 if (!inited) {
178 inited = 1;
179 m68k_tcg_init();
180 }
bellardaaed9092007-11-10 15:15:54 +0000181
ths01ba9812007-12-09 02:22:57 +0000182 env->cpu_model_str = cpu_model;
183
bellardaaed9092007-11-10 15:15:54 +0000184 if (cpu_m68k_set_model(env, cpu_model) < 0) {
185 cpu_m68k_close(env);
186 return NULL;
187 }
ths01ba9812007-12-09 02:22:57 +0000188
bellardaaed9092007-11-10 15:15:54 +0000189 cpu_reset(env);
aliguori0bf46a42009-04-24 18:03:41 +0000190 qemu_init_vcpu(env);
bellardaaed9092007-11-10 15:15:54 +0000191 return env;
192}
193
194void cpu_m68k_close(CPUM68KState *env)
195{
Anthony Liguori7267c092011-08-20 22:09:37 -0500196 g_free(env);
pbrook0402f762007-05-26 16:52:21 +0000197}
198
pbrooke6e59062006-10-22 00:18:54 +0000199void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
200{
201 int flags;
202 uint32_t src;
203 uint32_t dest;
204 uint32_t tmp;
205
206#define HIGHBIT 0x80000000u
207
208#define SET_NZ(x) do { \
209 if ((x) == 0) \
210 flags |= CCF_Z; \
211 else if ((int32_t)(x) < 0) \
212 flags |= CCF_N; \
213 } while (0)
214
215#define SET_FLAGS_SUB(type, utype) do { \
216 SET_NZ((type)dest); \
217 tmp = dest + src; \
218 if ((utype) tmp < (utype) src) \
219 flags |= CCF_C; \
220 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
221 flags |= CCF_V; \
222 } while (0)
223
224 flags = 0;
225 src = env->cc_src;
226 dest = env->cc_dest;
227 switch (cc_op) {
228 case CC_OP_FLAGS:
229 flags = dest;
230 break;
231 case CC_OP_LOGIC:
232 SET_NZ(dest);
233 break;
234 case CC_OP_ADD:
235 SET_NZ(dest);
236 if (dest < src)
237 flags |= CCF_C;
238 tmp = dest - src;
239 if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
240 flags |= CCF_V;
241 break;
242 case CC_OP_SUB:
243 SET_FLAGS_SUB(int32_t, uint32_t);
244 break;
245 case CC_OP_CMPB:
246 SET_FLAGS_SUB(int8_t, uint8_t);
247 break;
248 case CC_OP_CMPW:
249 SET_FLAGS_SUB(int16_t, uint16_t);
250 break;
251 case CC_OP_ADDX:
252 SET_NZ(dest);
253 if (dest <= src)
254 flags |= CCF_C;
255 tmp = dest - src - 1;
256 if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
257 flags |= CCF_V;
258 break;
259 case CC_OP_SUBX:
260 SET_NZ(dest);
261 tmp = dest + src + 1;
262 if (tmp <= src)
263 flags |= CCF_C;
264 if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
265 flags |= CCF_V;
266 break;
pbrooke1f38082008-05-24 22:29:16 +0000267 case CC_OP_SHIFT:
268 SET_NZ(dest);
269 if (src)
pbrooke6e59062006-10-22 00:18:54 +0000270 flags |= CCF_C;
271 break;
272 default:
273 cpu_abort(env, "Bad CC_OP %d", cc_op);
274 }
275 env->cc_op = CC_OP_FLAGS;
276 env->cc_dest = flags;
277}
278
pbrooke1f38082008-05-24 22:29:16 +0000279void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
pbrook06338792007-05-23 19:58:11 +0000280{
281 switch (reg) {
282 case 0x02: /* CACR */
pbrook20dcee92007-06-03 11:13:39 +0000283 env->cacr = val;
284 m68k_switch_sp(env);
285 break;
286 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
287 /* TODO: Implement Access Control Registers. */
pbrook06338792007-05-23 19:58:11 +0000288 break;
289 case 0x801: /* VBR */
290 env->vbr = val;
291 break;
292 /* TODO: Implement control registers. */
293 default:
294 cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
295 reg, val);
296 }
297}
298
pbrooke1f38082008-05-24 22:29:16 +0000299void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
pbrookacf930a2007-05-29 14:57:59 +0000300{
301 uint32_t acc;
302 int8_t exthigh;
303 uint8_t extlow;
304 uint64_t regval;
305 int i;
306 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
307 for (i = 0; i < 4; i++) {
308 regval = env->macc[i];
309 exthigh = regval >> 40;
310 if (env->macsr & MACSR_FI) {
311 acc = regval >> 8;
312 extlow = regval;
313 } else {
314 acc = regval;
315 extlow = regval >> 32;
316 }
317 if (env->macsr & MACSR_FI) {
318 regval = (((uint64_t)acc) << 8) | extlow;
319 regval |= ((int64_t)exthigh) << 40;
320 } else if (env->macsr & MACSR_SU) {
321 regval = acc | (((int64_t)extlow) << 32);
322 regval |= ((int64_t)exthigh) << 40;
323 } else {
324 regval = acc | (((uint64_t)extlow) << 32);
325 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
326 }
327 env->macc[i] = regval;
328 }
329 }
330 env->macsr = val;
331}
332
pbrook20dcee92007-06-03 11:13:39 +0000333void m68k_switch_sp(CPUM68KState *env)
334{
335 int new_sp;
336
337 env->sp[env->current_sp] = env->aregs[7];
338 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
339 ? M68K_SSP : M68K_USP;
340 env->aregs[7] = env->sp[new_sp];
341 env->current_sp = new_sp;
342}
343
ths5fafdf22007-09-16 21:08:06 +0000344#if defined(CONFIG_USER_ONLY)
pbrook06338792007-05-23 19:58:11 +0000345
346int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
Blue Swirl97b348e2011-08-01 16:12:17 +0000347 int mmu_idx)
pbrook06338792007-05-23 19:58:11 +0000348{
349 env->exception_index = EXCP_ACCESS;
350 env->mmu.ar = address;
351 return 1;
352}
353
354#else
355
Paul Brook4fcc5622010-03-01 03:46:18 +0000356/* MMU */
357
358/* TODO: This will need fixing once the MMU is implemented. */
359target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
360{
361 return addr;
362}
363
pbrook06338792007-05-23 19:58:11 +0000364int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
Blue Swirl97b348e2011-08-01 16:12:17 +0000365 int mmu_idx)
pbrook06338792007-05-23 19:58:11 +0000366{
367 int prot;
368
369 address &= TARGET_PAGE_MASK;
Paul Brookd4c430a2010-03-17 02:14:28 +0000370 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
371 tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
372 return 0;
pbrook06338792007-05-23 19:58:11 +0000373}
374
375/* Notify CPU of a pending interrupt. Prioritization and vectoring should
376 be handled by the interrupt controller. Real hardware only requests
377 the vector when the interrupt is acknowledged by the CPU. For
378 simplicitly we calculate it when the interrupt is signalled. */
379void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
380{
381 env->pending_level = level;
382 env->pending_vector = vector;
383 if (level)
384 cpu_interrupt(env, CPU_INTERRUPT_HARD);
385 else
386 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
387}
388
389#endif
pbrooke1f38082008-05-24 22:29:16 +0000390
391uint32_t HELPER(bitrev)(uint32_t x)
392{
393 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
394 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
395 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
396 return bswap32(x);
397}
398
399uint32_t HELPER(ff1)(uint32_t x)
400{
401 int n;
402 for (n = 32; x; n--)
403 x >>= 1;
404 return n;
405}
406
407uint32_t HELPER(sats)(uint32_t val, uint32_t ccr)
408{
409 /* The result has the opposite sign to the original value. */
410 if (ccr & CCF_V)
411 val = (((int32_t)val) >> 31) ^ SIGNBIT;
412 return val;
413}
414
415uint32_t HELPER(subx_cc)(CPUState *env, uint32_t op1, uint32_t op2)
416{
417 uint32_t res;
418 uint32_t old_flags;
419
420 old_flags = env->cc_dest;
421 if (env->cc_x) {
422 env->cc_x = (op1 <= op2);
423 env->cc_op = CC_OP_SUBX;
424 res = op1 - (op2 + 1);
425 } else {
426 env->cc_x = (op1 < op2);
427 env->cc_op = CC_OP_SUB;
428 res = op1 - op2;
429 }
430 env->cc_dest = res;
431 env->cc_src = op2;
432 cpu_m68k_flush_flags(env, env->cc_op);
433 /* !Z is sticky. */
434 env->cc_dest &= (old_flags | ~CCF_Z);
435 return res;
436}
437
438uint32_t HELPER(addx_cc)(CPUState *env, uint32_t op1, uint32_t op2)
439{
440 uint32_t res;
441 uint32_t old_flags;
442
443 old_flags = env->cc_dest;
444 if (env->cc_x) {
445 res = op1 + op2 + 1;
446 env->cc_x = (res <= op2);
447 env->cc_op = CC_OP_ADDX;
448 } else {
449 res = op1 + op2;
450 env->cc_x = (res < op2);
451 env->cc_op = CC_OP_ADD;
452 }
453 env->cc_dest = res;
454 env->cc_src = op2;
455 cpu_m68k_flush_flags(env, env->cc_op);
456 /* !Z is sticky. */
457 env->cc_dest &= (old_flags | ~CCF_Z);
458 return res;
459}
460
461uint32_t HELPER(xflag_lt)(uint32_t a, uint32_t b)
462{
463 return a < b;
464}
465
pbrooke1f38082008-05-24 22:29:16 +0000466void HELPER(set_sr)(CPUState *env, uint32_t val)
467{
468 env->sr = val & 0xffff;
469 m68k_switch_sp(env);
470}
471
472uint32_t HELPER(shl_cc)(CPUState *env, uint32_t val, uint32_t shift)
473{
474 uint32_t result;
475 uint32_t cf;
476
477 shift &= 63;
478 if (shift == 0) {
479 result = val;
480 cf = env->cc_src & CCF_C;
481 } else if (shift < 32) {
482 result = val << shift;
483 cf = (val >> (32 - shift)) & 1;
484 } else if (shift == 32) {
485 result = 0;
486 cf = val & 1;
487 } else /* shift > 32 */ {
488 result = 0;
489 cf = 0;
490 }
491 env->cc_src = cf;
492 env->cc_x = (cf != 0);
493 env->cc_dest = result;
494 return result;
495}
496
497uint32_t HELPER(shr_cc)(CPUState *env, uint32_t val, uint32_t shift)
498{
499 uint32_t result;
500 uint32_t cf;
501
502 shift &= 63;
503 if (shift == 0) {
504 result = val;
505 cf = env->cc_src & CCF_C;
506 } else if (shift < 32) {
507 result = val >> shift;
508 cf = (val >> (shift - 1)) & 1;
509 } else if (shift == 32) {
510 result = 0;
511 cf = val >> 31;
512 } else /* shift > 32 */ {
513 result = 0;
514 cf = 0;
515 }
516 env->cc_src = cf;
517 env->cc_x = (cf != 0);
518 env->cc_dest = result;
519 return result;
520}
521
522uint32_t HELPER(sar_cc)(CPUState *env, uint32_t val, uint32_t shift)
523{
524 uint32_t result;
525 uint32_t cf;
526
527 shift &= 63;
528 if (shift == 0) {
529 result = val;
530 cf = (env->cc_src & CCF_C) != 0;
531 } else if (shift < 32) {
532 result = (int32_t)val >> shift;
533 cf = (val >> (shift - 1)) & 1;
534 } else /* shift >= 32 */ {
535 result = (int32_t)val >> 31;
536 cf = val >> 31;
537 }
538 env->cc_src = cf;
539 env->cc_x = cf;
540 env->cc_dest = result;
541 return result;
542}
543
544/* FPU helpers. */
545uint32_t HELPER(f64_to_i32)(CPUState *env, float64 val)
546{
547 return float64_to_int32(val, &env->fp_status);
548}
549
550float32 HELPER(f64_to_f32)(CPUState *env, float64 val)
551{
552 return float64_to_float32(val, &env->fp_status);
553}
554
555float64 HELPER(i32_to_f64)(CPUState *env, uint32_t val)
556{
557 return int32_to_float64(val, &env->fp_status);
558}
559
560float64 HELPER(f32_to_f64)(CPUState *env, float32 val)
561{
562 return float32_to_float64(val, &env->fp_status);
563}
564
565float64 HELPER(iround_f64)(CPUState *env, float64 val)
566{
567 return float64_round_to_int(val, &env->fp_status);
568}
569
570float64 HELPER(itrunc_f64)(CPUState *env, float64 val)
571{
572 return float64_trunc_to_int(val, &env->fp_status);
573}
574
575float64 HELPER(sqrt_f64)(CPUState *env, float64 val)
576{
577 return float64_sqrt(val, &env->fp_status);
578}
579
580float64 HELPER(abs_f64)(float64 val)
581{
582 return float64_abs(val);
583}
584
585float64 HELPER(chs_f64)(float64 val)
586{
587 return float64_chs(val);
588}
589
590float64 HELPER(add_f64)(CPUState *env, float64 a, float64 b)
591{
592 return float64_add(a, b, &env->fp_status);
593}
594
595float64 HELPER(sub_f64)(CPUState *env, float64 a, float64 b)
596{
597 return float64_sub(a, b, &env->fp_status);
598}
599
600float64 HELPER(mul_f64)(CPUState *env, float64 a, float64 b)
601{
602 return float64_mul(a, b, &env->fp_status);
603}
604
605float64 HELPER(div_f64)(CPUState *env, float64 a, float64 b)
606{
607 return float64_div(a, b, &env->fp_status);
608}
609
610float64 HELPER(sub_cmp_f64)(CPUState *env, float64 a, float64 b)
611{
612 /* ??? This may incorrectly raise exceptions. */
613 /* ??? Should flush denormals to zero. */
614 float64 res;
615 res = float64_sub(a, b, &env->fp_status);
Peter Maydell18569872010-12-17 15:56:06 +0000616 if (float64_is_quiet_nan(res)) {
pbrooke1f38082008-05-24 22:29:16 +0000617 /* +/-inf compares equal against itself, but sub returns nan. */
Peter Maydell18569872010-12-17 15:56:06 +0000618 if (!float64_is_quiet_nan(a)
619 && !float64_is_quiet_nan(b)) {
pbrooke1f38082008-05-24 22:29:16 +0000620 res = float64_zero;
621 if (float64_lt_quiet(a, res, &env->fp_status))
622 res = float64_chs(res);
623 }
624 }
625 return res;
626}
627
628uint32_t HELPER(compare_f64)(CPUState *env, float64 val)
629{
630 return float64_compare_quiet(val, float64_zero, &env->fp_status);
631}
632
633/* MAC unit. */
634/* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
635 take values, others take register numbers and manipulate the contents
636 in-place. */
637void HELPER(mac_move)(CPUState *env, uint32_t dest, uint32_t src)
638{
639 uint32_t mask;
640 env->macc[dest] = env->macc[src];
641 mask = MACSR_PAV0 << dest;
642 if (env->macsr & (MACSR_PAV0 << src))
643 env->macsr |= mask;
644 else
645 env->macsr &= ~mask;
646}
647
648uint64_t HELPER(macmuls)(CPUState *env, uint32_t op1, uint32_t op2)
649{
650 int64_t product;
651 int64_t res;
652
653 product = (uint64_t)op1 * op2;
654 res = (product << 24) >> 24;
655 if (res != product) {
656 env->macsr |= MACSR_V;
657 if (env->macsr & MACSR_OMC) {
658 /* Make sure the accumulate operation overflows. */
659 if (product < 0)
660 res = ~(1ll << 50);
661 else
662 res = 1ll << 50;
663 }
664 }
665 return res;
666}
667
668uint64_t HELPER(macmulu)(CPUState *env, uint32_t op1, uint32_t op2)
669{
670 uint64_t product;
671
672 product = (uint64_t)op1 * op2;
673 if (product & (0xffffffull << 40)) {
674 env->macsr |= MACSR_V;
675 if (env->macsr & MACSR_OMC) {
676 /* Make sure the accumulate operation overflows. */
677 product = 1ll << 50;
678 } else {
679 product &= ((1ull << 40) - 1);
680 }
681 }
682 return product;
683}
684
685uint64_t HELPER(macmulf)(CPUState *env, uint32_t op1, uint32_t op2)
686{
687 uint64_t product;
688 uint32_t remainder;
689
690 product = (uint64_t)op1 * op2;
691 if (env->macsr & MACSR_RT) {
692 remainder = product & 0xffffff;
693 product >>= 24;
694 if (remainder > 0x800000)
695 product++;
696 else if (remainder == 0x800000)
697 product += (product & 1);
698 } else {
699 product >>= 24;
700 }
701 return product;
702}
703
704void HELPER(macsats)(CPUState *env, uint32_t acc)
705{
706 int64_t tmp;
707 int64_t result;
708 tmp = env->macc[acc];
709 result = ((tmp << 16) >> 16);
710 if (result != tmp) {
711 env->macsr |= MACSR_V;
712 }
713 if (env->macsr & MACSR_V) {
714 env->macsr |= MACSR_PAV0 << acc;
715 if (env->macsr & MACSR_OMC) {
Stefan Weila1c72732011-04-28 17:20:38 +0200716 /* The result is saturated to 32 bits, despite overflow occurring
pbrooke1f38082008-05-24 22:29:16 +0000717 at 48 bits. Seems weird, but that's what the hardware docs
718 say. */
719 result = (result >> 63) ^ 0x7fffffff;
720 }
721 }
722 env->macc[acc] = result;
723}
724
725void HELPER(macsatu)(CPUState *env, uint32_t acc)
726{
727 uint64_t val;
728
729 val = env->macc[acc];
730 if (val & (0xffffull << 48)) {
731 env->macsr |= MACSR_V;
732 }
733 if (env->macsr & MACSR_V) {
734 env->macsr |= MACSR_PAV0 << acc;
735 if (env->macsr & MACSR_OMC) {
736 if (val > (1ull << 53))
737 val = 0;
738 else
739 val = (1ull << 48) - 1;
740 } else {
741 val &= ((1ull << 48) - 1);
742 }
743 }
744 env->macc[acc] = val;
745}
746
747void HELPER(macsatf)(CPUState *env, uint32_t acc)
748{
749 int64_t sum;
750 int64_t result;
751
752 sum = env->macc[acc];
753 result = (sum << 16) >> 16;
754 if (result != sum) {
755 env->macsr |= MACSR_V;
756 }
757 if (env->macsr & MACSR_V) {
758 env->macsr |= MACSR_PAV0 << acc;
759 if (env->macsr & MACSR_OMC) {
760 result = (result >> 63) ^ 0x7fffffffffffll;
761 }
762 }
763 env->macc[acc] = result;
764}
765
766void HELPER(mac_set_flags)(CPUState *env, uint32_t acc)
767{
768 uint64_t val;
769 val = env->macc[acc];
Blue Swirlc4162572010-04-23 19:22:22 +0000770 if (val == 0) {
pbrooke1f38082008-05-24 22:29:16 +0000771 env->macsr |= MACSR_Z;
Blue Swirlc4162572010-04-23 19:22:22 +0000772 } else if (val & (1ull << 47)) {
pbrooke1f38082008-05-24 22:29:16 +0000773 env->macsr |= MACSR_N;
Blue Swirlc4162572010-04-23 19:22:22 +0000774 }
pbrooke1f38082008-05-24 22:29:16 +0000775 if (env->macsr & (MACSR_PAV0 << acc)) {
776 env->macsr |= MACSR_V;
777 }
778 if (env->macsr & MACSR_FI) {
779 val = ((int64_t)val) >> 40;
780 if (val != 0 && val != -1)
781 env->macsr |= MACSR_EV;
782 } else if (env->macsr & MACSR_SU) {
783 val = ((int64_t)val) >> 32;
784 if (val != 0 && val != -1)
785 env->macsr |= MACSR_EV;
786 } else {
787 if ((val >> 32) != 0)
788 env->macsr |= MACSR_EV;
789 }
790}
791
792void HELPER(flush_flags)(CPUState *env, uint32_t cc_op)
793{
794 cpu_m68k_flush_flags(env, cc_op);
795}
796
797uint32_t HELPER(get_macf)(CPUState *env, uint64_t val)
798{
799 int rem;
800 uint32_t result;
801
802 if (env->macsr & MACSR_SU) {
803 /* 16-bit rounding. */
804 rem = val & 0xffffff;
805 val = (val >> 24) & 0xffffu;
806 if (rem > 0x800000)
807 val++;
808 else if (rem == 0x800000)
809 val += (val & 1);
810 } else if (env->macsr & MACSR_RT) {
811 /* 32-bit rounding. */
812 rem = val & 0xff;
813 val >>= 8;
814 if (rem > 0x80)
815 val++;
816 else if (rem == 0x80)
817 val += (val & 1);
818 } else {
819 /* No rounding. */
820 val >>= 8;
821 }
822 if (env->macsr & MACSR_OMC) {
823 /* Saturate. */
824 if (env->macsr & MACSR_SU) {
825 if (val != (uint16_t) val) {
826 result = ((val >> 63) ^ 0x7fff) & 0xffff;
827 } else {
828 result = val & 0xffff;
829 }
830 } else {
831 if (val != (uint32_t)val) {
832 result = ((uint32_t)(val >> 63) & 0x7fffffff);
833 } else {
834 result = (uint32_t)val;
835 }
836 }
837 } else {
838 /* No saturation. */
839 if (env->macsr & MACSR_SU) {
840 result = val & 0xffff;
841 } else {
842 result = (uint32_t)val;
843 }
844 }
845 return result;
846}
847
848uint32_t HELPER(get_macs)(uint64_t val)
849{
850 if (val == (int32_t)val) {
851 return (int32_t)val;
852 } else {
853 return (val >> 61) ^ ~SIGNBIT;
854 }
855}
856
857uint32_t HELPER(get_macu)(uint64_t val)
858{
859 if ((val >> 32) == 0) {
860 return (uint32_t)val;
861 } else {
862 return 0xffffffffu;
863 }
864}
865
866uint32_t HELPER(get_mac_extf)(CPUState *env, uint32_t acc)
867{
868 uint32_t val;
869 val = env->macc[acc] & 0x00ff;
870 val = (env->macc[acc] >> 32) & 0xff00;
871 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
872 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
873 return val;
874}
875
876uint32_t HELPER(get_mac_exti)(CPUState *env, uint32_t acc)
877{
878 uint32_t val;
879 val = (env->macc[acc] >> 32) & 0xffff;
880 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
881 return val;
882}
883
884void HELPER(set_mac_extf)(CPUState *env, uint32_t val, uint32_t acc)
885{
886 int64_t res;
887 int32_t tmp;
888 res = env->macc[acc] & 0xffffffff00ull;
889 tmp = (int16_t)(val & 0xff00);
890 res |= ((int64_t)tmp) << 32;
891 res |= val & 0xff;
892 env->macc[acc] = res;
893 res = env->macc[acc + 1] & 0xffffffff00ull;
894 tmp = (val & 0xff000000);
895 res |= ((int64_t)tmp) << 16;
896 res |= (val >> 16) & 0xff;
897 env->macc[acc + 1] = res;
898}
899
900void HELPER(set_mac_exts)(CPUState *env, uint32_t val, uint32_t acc)
901{
902 int64_t res;
903 int32_t tmp;
904 res = (uint32_t)env->macc[acc];
905 tmp = (int16_t)val;
906 res |= ((int64_t)tmp) << 32;
907 env->macc[acc] = res;
908 res = (uint32_t)env->macc[acc + 1];
909 tmp = val & 0xffff0000;
910 res |= (int64_t)tmp << 16;
911 env->macc[acc + 1] = res;
912}
913
914void HELPER(set_mac_extu)(CPUState *env, uint32_t val, uint32_t acc)
915{
916 uint64_t res;
917 res = (uint32_t)env->macc[acc];
918 res |= ((uint64_t)(val & 0xffff)) << 32;
919 env->macc[acc] = res;
920 res = (uint32_t)env->macc[acc + 1];
921 res |= (uint64_t)(val & 0xffff0000) << 16;
922 env->macc[acc + 1] = res;
923}