blob: a8f6d9d6a626094bff9ebcb49537014136106fb9 [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
Peter Maydelld8416662016-01-26 18:17:23 +000021#include "qemu/osdep.h"
pbrooke6e59062006-10-22 00:18:54 +000022#include "cpu.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010023#include "exec/gdbstub.h"
pbrooke6e59062006-10-22 00:18:54 +000024
Richard Henderson2ef61752014-04-07 22:31:41 -070025#include "exec/helper-proto.h"
pbrooke1f38082008-05-24 22:29:16 +000026
27#define SIGNBIT (1u << 31)
28
Andreas Färber11150912012-04-15 03:30:10 +020029/* Sort alphabetically, except for "any". */
30static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b)
31{
32 ObjectClass *class_a = (ObjectClass *)a;
33 ObjectClass *class_b = (ObjectClass *)b;
34 const char *name_a, *name_b;
bellardaaed9092007-11-10 15:15:54 +000035
Andreas Färber11150912012-04-15 03:30:10 +020036 name_a = object_class_get_name(class_a);
37 name_b = object_class_get_name(class_b);
Andreas Färber7a9f8122013-01-27 20:16:17 +010038 if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) {
Andreas Färber11150912012-04-15 03:30:10 +020039 return 1;
Andreas Färber7a9f8122013-01-27 20:16:17 +010040 } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
Andreas Färber11150912012-04-15 03:30:10 +020041 return -1;
42 } else {
43 return strcasecmp(name_a, name_b);
44 }
45}
pbrook0402f762007-05-26 16:52:21 +000046
Andreas Färber11150912012-04-15 03:30:10 +020047static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
48{
49 ObjectClass *c = data;
Andreas Färber92a31362012-12-16 02:17:02 +010050 CPUListState *s = user_data;
Andreas Färber7a9f8122013-01-27 20:16:17 +010051 const char *typename;
52 char *name;
Andreas Färber11150912012-04-15 03:30:10 +020053
Andreas Färber7a9f8122013-01-27 20:16:17 +010054 typename = object_class_get_name(c);
55 name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
Andreas Färber11150912012-04-15 03:30:10 +020056 (*s->cpu_fprintf)(s->file, "%s\n",
Andreas Färber7a9f8122013-01-27 20:16:17 +010057 name);
58 g_free(name);
Andreas Färber11150912012-04-15 03:30:10 +020059}
pbrook0402f762007-05-26 16:52:21 +000060
Stefan Weil9a78eea2010-10-22 23:03:33 +020061void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
Laurent Vivier009a4352009-05-09 22:21:39 +020062{
Andreas Färber92a31362012-12-16 02:17:02 +010063 CPUListState s = {
Andreas Färber11150912012-04-15 03:30:10 +020064 .file = f,
65 .cpu_fprintf = cpu_fprintf,
66 };
67 GSList *list;
Laurent Vivier009a4352009-05-09 22:21:39 +020068
Andreas Färber11150912012-04-15 03:30:10 +020069 list = object_class_get_list(TYPE_M68K_CPU, false);
70 list = g_slist_sort(list, m68k_cpu_list_compare);
71 g_slist_foreach(list, m68k_cpu_list_entry, &s);
72 g_slist_free(list);
Laurent Vivier009a4352009-05-09 22:21:39 +020073}
74
Andreas Färber2b3e3cf2012-03-14 01:38:22 +010075static int fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
pbrook56aebc82008-10-11 17:55:29 +000076{
77 if (n < 8) {
78 stfq_p(mem_buf, env->fregs[n]);
79 return 8;
80 }
81 if (n < 11) {
82 /* FP control registers (not implemented) */
83 memset(mem_buf, 0, 4);
84 return 4;
85 }
86 return 0;
87}
88
Andreas Färber2b3e3cf2012-03-14 01:38:22 +010089static int fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
pbrook56aebc82008-10-11 17:55:29 +000090{
91 if (n < 8) {
92 env->fregs[n] = ldfq_p(mem_buf);
93 return 8;
94 }
95 if (n < 11) {
96 /* FP control registers (not implemented) */
97 return 4;
98 }
99 return 0;
100}
101
Andreas Färberc7937d92013-01-18 14:03:58 +0100102M68kCPU *cpu_m68k_init(const char *cpu_model)
bellardaaed9092007-11-10 15:15:54 +0000103{
Andreas Färberb9e7a232012-04-15 00:35:50 +0200104 M68kCPU *cpu;
bellardaaed9092007-11-10 15:15:54 +0000105 CPUM68KState *env;
Andreas Färberbc5b2da2013-01-21 17:50:15 +0100106 ObjectClass *oc;
bellardaaed9092007-11-10 15:15:54 +0000107
Andreas Färberbc5b2da2013-01-21 17:50:15 +0100108 oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model);
109 if (oc == NULL) {
Andreas Färber11150912012-04-15 03:30:10 +0200110 return NULL;
111 }
Andreas Färberbc5b2da2013-01-21 17:50:15 +0100112 cpu = M68K_CPU(object_new(object_class_get_name(oc)));
Andreas Färberb9e7a232012-04-15 00:35:50 +0200113 env = &cpu->env;
ths01ba9812007-12-09 02:22:57 +0000114
Andreas Färber11150912012-04-15 03:30:10 +0200115 register_m68k_insns(env);
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100116
117 object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
118
Andreas Färberc7937d92013-01-18 14:03:58 +0100119 return cpu;
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100120}
121
122void m68k_cpu_init_gdb(M68kCPU *cpu)
123{
Andreas Färber22169d42013-06-28 21:27:39 +0200124 CPUState *cs = CPU(cpu);
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100125 CPUM68KState *env = &cpu->env;
126
Andreas Färber11150912012-04-15 03:30:10 +0200127 if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
Andreas Färber22169d42013-06-28 21:27:39 +0200128 gdb_register_coprocessor(cs, fpu_gdb_get_reg, fpu_gdb_set_reg,
Andreas Färber11150912012-04-15 03:30:10 +0200129 11, "cf-fp.xml", 18);
bellardaaed9092007-11-10 15:15:54 +0000130 }
Andreas Färber11150912012-04-15 03:30:10 +0200131 /* TODO: Add [E]MAC registers. */
bellardaaed9092007-11-10 15:15:54 +0000132}
133
pbrooke6e59062006-10-22 00:18:54 +0000134void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
135{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200136 M68kCPU *cpu = m68k_env_get_cpu(env);
pbrooke6e59062006-10-22 00:18:54 +0000137 int flags;
138 uint32_t src;
139 uint32_t dest;
140 uint32_t tmp;
141
142#define HIGHBIT 0x80000000u
143
144#define SET_NZ(x) do { \
145 if ((x) == 0) \
146 flags |= CCF_Z; \
147 else if ((int32_t)(x) < 0) \
148 flags |= CCF_N; \
149 } while (0)
150
151#define SET_FLAGS_SUB(type, utype) do { \
152 SET_NZ((type)dest); \
153 tmp = dest + src; \
154 if ((utype) tmp < (utype) src) \
155 flags |= CCF_C; \
156 if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
157 flags |= CCF_V; \
158 } while (0)
159
160 flags = 0;
161 src = env->cc_src;
162 dest = env->cc_dest;
163 switch (cc_op) {
164 case CC_OP_FLAGS:
165 flags = dest;
166 break;
167 case CC_OP_LOGIC:
168 SET_NZ(dest);
169 break;
170 case CC_OP_ADD:
171 SET_NZ(dest);
172 if (dest < src)
173 flags |= CCF_C;
174 tmp = dest - src;
175 if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
176 flags |= CCF_V;
177 break;
178 case CC_OP_SUB:
179 SET_FLAGS_SUB(int32_t, uint32_t);
180 break;
181 case CC_OP_CMPB:
182 SET_FLAGS_SUB(int8_t, uint8_t);
183 break;
184 case CC_OP_CMPW:
185 SET_FLAGS_SUB(int16_t, uint16_t);
186 break;
187 case CC_OP_ADDX:
188 SET_NZ(dest);
189 if (dest <= src)
190 flags |= CCF_C;
191 tmp = dest - src - 1;
192 if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
193 flags |= CCF_V;
194 break;
195 case CC_OP_SUBX:
196 SET_NZ(dest);
197 tmp = dest + src + 1;
198 if (tmp <= src)
199 flags |= CCF_C;
200 if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
201 flags |= CCF_V;
202 break;
pbrooke1f38082008-05-24 22:29:16 +0000203 case CC_OP_SHIFT:
204 SET_NZ(dest);
205 if (src)
pbrooke6e59062006-10-22 00:18:54 +0000206 flags |= CCF_C;
207 break;
208 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200209 cpu_abort(CPU(cpu), "Bad CC_OP %d", cc_op);
pbrooke6e59062006-10-22 00:18:54 +0000210 }
211 env->cc_op = CC_OP_FLAGS;
212 env->cc_dest = flags;
213}
214
pbrooke1f38082008-05-24 22:29:16 +0000215void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
pbrook06338792007-05-23 19:58:11 +0000216{
Andreas Färbera47dddd2013-09-03 17:38:47 +0200217 M68kCPU *cpu = m68k_env_get_cpu(env);
218
pbrook06338792007-05-23 19:58:11 +0000219 switch (reg) {
220 case 0x02: /* CACR */
pbrook20dcee92007-06-03 11:13:39 +0000221 env->cacr = val;
222 m68k_switch_sp(env);
223 break;
224 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
225 /* TODO: Implement Access Control Registers. */
pbrook06338792007-05-23 19:58:11 +0000226 break;
227 case 0x801: /* VBR */
228 env->vbr = val;
229 break;
230 /* TODO: Implement control registers. */
231 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200232 cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
pbrook06338792007-05-23 19:58:11 +0000233 reg, val);
234 }
235}
236
pbrooke1f38082008-05-24 22:29:16 +0000237void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
pbrookacf930a2007-05-29 14:57:59 +0000238{
239 uint32_t acc;
240 int8_t exthigh;
241 uint8_t extlow;
242 uint64_t regval;
243 int i;
244 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
245 for (i = 0; i < 4; i++) {
246 regval = env->macc[i];
247 exthigh = regval >> 40;
248 if (env->macsr & MACSR_FI) {
249 acc = regval >> 8;
250 extlow = regval;
251 } else {
252 acc = regval;
253 extlow = regval >> 32;
254 }
255 if (env->macsr & MACSR_FI) {
256 regval = (((uint64_t)acc) << 8) | extlow;
257 regval |= ((int64_t)exthigh) << 40;
258 } else if (env->macsr & MACSR_SU) {
259 regval = acc | (((int64_t)extlow) << 32);
260 regval |= ((int64_t)exthigh) << 40;
261 } else {
262 regval = acc | (((uint64_t)extlow) << 32);
263 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
264 }
265 env->macc[i] = regval;
266 }
267 }
268 env->macsr = val;
269}
270
pbrook20dcee92007-06-03 11:13:39 +0000271void m68k_switch_sp(CPUM68KState *env)
272{
273 int new_sp;
274
275 env->sp[env->current_sp] = env->aregs[7];
276 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
277 ? M68K_SSP : M68K_USP;
278 env->aregs[7] = env->sp[new_sp];
279 env->current_sp = new_sp;
280}
281
ths5fafdf22007-09-16 21:08:06 +0000282#if defined(CONFIG_USER_ONLY)
pbrook06338792007-05-23 19:58:11 +0000283
Andreas Färber75104542013-08-26 03:01:33 +0200284int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
285 int mmu_idx)
pbrook06338792007-05-23 19:58:11 +0000286{
Andreas Färber75104542013-08-26 03:01:33 +0200287 M68kCPU *cpu = M68K_CPU(cs);
288
Andreas Färber27103422013-08-26 08:31:06 +0200289 cs->exception_index = EXCP_ACCESS;
Andreas Färber75104542013-08-26 03:01:33 +0200290 cpu->env.mmu.ar = address;
pbrook06338792007-05-23 19:58:11 +0000291 return 1;
292}
293
294#else
295
Paul Brook4fcc5622010-03-01 03:46:18 +0000296/* MMU */
297
298/* TODO: This will need fixing once the MMU is implemented. */
Andreas Färber00b941e2013-06-29 18:55:54 +0200299hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
Paul Brook4fcc5622010-03-01 03:46:18 +0000300{
301 return addr;
302}
303
Andreas Färber75104542013-08-26 03:01:33 +0200304int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
305 int mmu_idx)
pbrook06338792007-05-23 19:58:11 +0000306{
307 int prot;
308
309 address &= TARGET_PAGE_MASK;
Paul Brookd4c430a2010-03-17 02:14:28 +0000310 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
Andreas Färber0c591eb2013-09-03 13:59:37 +0200311 tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
Paul Brookd4c430a2010-03-17 02:14:28 +0000312 return 0;
pbrook06338792007-05-23 19:58:11 +0000313}
314
315/* Notify CPU of a pending interrupt. Prioritization and vectoring should
316 be handled by the interrupt controller. Real hardware only requests
317 the vector when the interrupt is acknowledged by the CPU. For
318 simplicitly we calculate it when the interrupt is signalled. */
Andreas Färbercb3fb382013-01-18 14:20:52 +0100319void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
pbrook06338792007-05-23 19:58:11 +0000320{
Andreas Färberd8ed8872013-01-17 22:30:20 +0100321 CPUState *cs = CPU(cpu);
Andreas Färbercb3fb382013-01-18 14:20:52 +0100322 CPUM68KState *env = &cpu->env;
323
pbrook06338792007-05-23 19:58:11 +0000324 env->pending_level = level;
325 env->pending_vector = vector;
Andreas Färberd8ed8872013-01-17 22:30:20 +0100326 if (level) {
Andreas Färberc3affe52013-01-18 15:03:43 +0100327 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
Andreas Färberd8ed8872013-01-17 22:30:20 +0100328 } else {
329 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
330 }
pbrook06338792007-05-23 19:58:11 +0000331}
332
333#endif
pbrooke1f38082008-05-24 22:29:16 +0000334
335uint32_t HELPER(bitrev)(uint32_t x)
336{
337 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
338 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
339 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
340 return bswap32(x);
341}
342
343uint32_t HELPER(ff1)(uint32_t x)
344{
345 int n;
346 for (n = 32; x; n--)
347 x >>= 1;
348 return n;
349}
350
351uint32_t HELPER(sats)(uint32_t val, uint32_t ccr)
352{
353 /* The result has the opposite sign to the original value. */
354 if (ccr & CCF_V)
355 val = (((int32_t)val) >> 31) ^ SIGNBIT;
356 return val;
357}
358
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100359uint32_t HELPER(subx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2)
pbrooke1f38082008-05-24 22:29:16 +0000360{
361 uint32_t res;
362 uint32_t old_flags;
363
364 old_flags = env->cc_dest;
365 if (env->cc_x) {
366 env->cc_x = (op1 <= op2);
367 env->cc_op = CC_OP_SUBX;
368 res = op1 - (op2 + 1);
369 } else {
370 env->cc_x = (op1 < op2);
371 env->cc_op = CC_OP_SUB;
372 res = op1 - op2;
373 }
374 env->cc_dest = res;
375 env->cc_src = op2;
376 cpu_m68k_flush_flags(env, env->cc_op);
377 /* !Z is sticky. */
378 env->cc_dest &= (old_flags | ~CCF_Z);
379 return res;
380}
381
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100382uint32_t HELPER(addx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2)
pbrooke1f38082008-05-24 22:29:16 +0000383{
384 uint32_t res;
385 uint32_t old_flags;
386
387 old_flags = env->cc_dest;
388 if (env->cc_x) {
389 res = op1 + op2 + 1;
390 env->cc_x = (res <= op2);
391 env->cc_op = CC_OP_ADDX;
392 } else {
393 res = op1 + op2;
394 env->cc_x = (res < op2);
395 env->cc_op = CC_OP_ADD;
396 }
397 env->cc_dest = res;
398 env->cc_src = op2;
399 cpu_m68k_flush_flags(env, env->cc_op);
400 /* !Z is sticky. */
401 env->cc_dest &= (old_flags | ~CCF_Z);
402 return res;
403}
404
405uint32_t HELPER(xflag_lt)(uint32_t a, uint32_t b)
406{
407 return a < b;
408}
409
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100410void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
pbrooke1f38082008-05-24 22:29:16 +0000411{
412 env->sr = val & 0xffff;
413 m68k_switch_sp(env);
414}
415
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100416uint32_t HELPER(shl_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
pbrooke1f38082008-05-24 22:29:16 +0000417{
418 uint32_t result;
419 uint32_t cf;
420
421 shift &= 63;
422 if (shift == 0) {
423 result = val;
424 cf = env->cc_src & CCF_C;
425 } else if (shift < 32) {
426 result = val << shift;
427 cf = (val >> (32 - shift)) & 1;
428 } else if (shift == 32) {
429 result = 0;
430 cf = val & 1;
431 } else /* shift > 32 */ {
432 result = 0;
433 cf = 0;
434 }
435 env->cc_src = cf;
436 env->cc_x = (cf != 0);
437 env->cc_dest = result;
438 return result;
439}
440
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100441uint32_t HELPER(shr_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
pbrooke1f38082008-05-24 22:29:16 +0000442{
443 uint32_t result;
444 uint32_t cf;
445
446 shift &= 63;
447 if (shift == 0) {
448 result = val;
449 cf = env->cc_src & CCF_C;
450 } else if (shift < 32) {
451 result = val >> shift;
452 cf = (val >> (shift - 1)) & 1;
453 } else if (shift == 32) {
454 result = 0;
455 cf = val >> 31;
456 } else /* shift > 32 */ {
457 result = 0;
458 cf = 0;
459 }
460 env->cc_src = cf;
461 env->cc_x = (cf != 0);
462 env->cc_dest = result;
463 return result;
464}
465
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100466uint32_t HELPER(sar_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
pbrooke1f38082008-05-24 22:29:16 +0000467{
468 uint32_t result;
469 uint32_t cf;
470
471 shift &= 63;
472 if (shift == 0) {
473 result = val;
474 cf = (env->cc_src & CCF_C) != 0;
475 } else if (shift < 32) {
476 result = (int32_t)val >> shift;
477 cf = (val >> (shift - 1)) & 1;
478 } else /* shift >= 32 */ {
479 result = (int32_t)val >> 31;
480 cf = val >> 31;
481 }
482 env->cc_src = cf;
483 env->cc_x = cf;
484 env->cc_dest = result;
485 return result;
486}
487
488/* FPU helpers. */
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100489uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val)
pbrooke1f38082008-05-24 22:29:16 +0000490{
491 return float64_to_int32(val, &env->fp_status);
492}
493
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100494float32 HELPER(f64_to_f32)(CPUM68KState *env, float64 val)
pbrooke1f38082008-05-24 22:29:16 +0000495{
496 return float64_to_float32(val, &env->fp_status);
497}
498
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100499float64 HELPER(i32_to_f64)(CPUM68KState *env, uint32_t val)
pbrooke1f38082008-05-24 22:29:16 +0000500{
501 return int32_to_float64(val, &env->fp_status);
502}
503
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100504float64 HELPER(f32_to_f64)(CPUM68KState *env, float32 val)
pbrooke1f38082008-05-24 22:29:16 +0000505{
506 return float32_to_float64(val, &env->fp_status);
507}
508
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100509float64 HELPER(iround_f64)(CPUM68KState *env, float64 val)
pbrooke1f38082008-05-24 22:29:16 +0000510{
511 return float64_round_to_int(val, &env->fp_status);
512}
513
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100514float64 HELPER(itrunc_f64)(CPUM68KState *env, float64 val)
pbrooke1f38082008-05-24 22:29:16 +0000515{
516 return float64_trunc_to_int(val, &env->fp_status);
517}
518
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100519float64 HELPER(sqrt_f64)(CPUM68KState *env, float64 val)
pbrooke1f38082008-05-24 22:29:16 +0000520{
521 return float64_sqrt(val, &env->fp_status);
522}
523
524float64 HELPER(abs_f64)(float64 val)
525{
526 return float64_abs(val);
527}
528
529float64 HELPER(chs_f64)(float64 val)
530{
531 return float64_chs(val);
532}
533
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100534float64 HELPER(add_f64)(CPUM68KState *env, float64 a, float64 b)
pbrooke1f38082008-05-24 22:29:16 +0000535{
536 return float64_add(a, b, &env->fp_status);
537}
538
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100539float64 HELPER(sub_f64)(CPUM68KState *env, float64 a, float64 b)
pbrooke1f38082008-05-24 22:29:16 +0000540{
541 return float64_sub(a, b, &env->fp_status);
542}
543
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100544float64 HELPER(mul_f64)(CPUM68KState *env, float64 a, float64 b)
pbrooke1f38082008-05-24 22:29:16 +0000545{
546 return float64_mul(a, b, &env->fp_status);
547}
548
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100549float64 HELPER(div_f64)(CPUM68KState *env, float64 a, float64 b)
pbrooke1f38082008-05-24 22:29:16 +0000550{
551 return float64_div(a, b, &env->fp_status);
552}
553
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100554float64 HELPER(sub_cmp_f64)(CPUM68KState *env, float64 a, float64 b)
pbrooke1f38082008-05-24 22:29:16 +0000555{
556 /* ??? This may incorrectly raise exceptions. */
557 /* ??? Should flush denormals to zero. */
558 float64 res;
559 res = float64_sub(a, b, &env->fp_status);
Peter Maydell18569872010-12-17 15:56:06 +0000560 if (float64_is_quiet_nan(res)) {
pbrooke1f38082008-05-24 22:29:16 +0000561 /* +/-inf compares equal against itself, but sub returns nan. */
Peter Maydell18569872010-12-17 15:56:06 +0000562 if (!float64_is_quiet_nan(a)
563 && !float64_is_quiet_nan(b)) {
pbrooke1f38082008-05-24 22:29:16 +0000564 res = float64_zero;
565 if (float64_lt_quiet(a, res, &env->fp_status))
566 res = float64_chs(res);
567 }
568 }
569 return res;
570}
571
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100572uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
pbrooke1f38082008-05-24 22:29:16 +0000573{
574 return float64_compare_quiet(val, float64_zero, &env->fp_status);
575}
576
577/* MAC unit. */
578/* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
579 take values, others take register numbers and manipulate the contents
580 in-place. */
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100581void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
pbrooke1f38082008-05-24 22:29:16 +0000582{
583 uint32_t mask;
584 env->macc[dest] = env->macc[src];
585 mask = MACSR_PAV0 << dest;
586 if (env->macsr & (MACSR_PAV0 << src))
587 env->macsr |= mask;
588 else
589 env->macsr &= ~mask;
590}
591
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100592uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
pbrooke1f38082008-05-24 22:29:16 +0000593{
594 int64_t product;
595 int64_t res;
596
597 product = (uint64_t)op1 * op2;
598 res = (product << 24) >> 24;
599 if (res != product) {
600 env->macsr |= MACSR_V;
601 if (env->macsr & MACSR_OMC) {
602 /* Make sure the accumulate operation overflows. */
603 if (product < 0)
604 res = ~(1ll << 50);
605 else
606 res = 1ll << 50;
607 }
608 }
609 return res;
610}
611
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100612uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
pbrooke1f38082008-05-24 22:29:16 +0000613{
614 uint64_t product;
615
616 product = (uint64_t)op1 * op2;
617 if (product & (0xffffffull << 40)) {
618 env->macsr |= MACSR_V;
619 if (env->macsr & MACSR_OMC) {
620 /* Make sure the accumulate operation overflows. */
621 product = 1ll << 50;
622 } else {
623 product &= ((1ull << 40) - 1);
624 }
625 }
626 return product;
627}
628
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100629uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
pbrooke1f38082008-05-24 22:29:16 +0000630{
631 uint64_t product;
632 uint32_t remainder;
633
634 product = (uint64_t)op1 * op2;
635 if (env->macsr & MACSR_RT) {
636 remainder = product & 0xffffff;
637 product >>= 24;
638 if (remainder > 0x800000)
639 product++;
640 else if (remainder == 0x800000)
641 product += (product & 1);
642 } else {
643 product >>= 24;
644 }
645 return product;
646}
647
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100648void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000649{
650 int64_t tmp;
651 int64_t result;
652 tmp = env->macc[acc];
653 result = ((tmp << 16) >> 16);
654 if (result != tmp) {
655 env->macsr |= MACSR_V;
656 }
657 if (env->macsr & MACSR_V) {
658 env->macsr |= MACSR_PAV0 << acc;
659 if (env->macsr & MACSR_OMC) {
Stefan Weila1c72732011-04-28 17:20:38 +0200660 /* The result is saturated to 32 bits, despite overflow occurring
pbrooke1f38082008-05-24 22:29:16 +0000661 at 48 bits. Seems weird, but that's what the hardware docs
662 say. */
663 result = (result >> 63) ^ 0x7fffffff;
664 }
665 }
666 env->macc[acc] = result;
667}
668
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100669void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000670{
671 uint64_t val;
672
673 val = env->macc[acc];
674 if (val & (0xffffull << 48)) {
675 env->macsr |= MACSR_V;
676 }
677 if (env->macsr & MACSR_V) {
678 env->macsr |= MACSR_PAV0 << acc;
679 if (env->macsr & MACSR_OMC) {
680 if (val > (1ull << 53))
681 val = 0;
682 else
683 val = (1ull << 48) - 1;
684 } else {
685 val &= ((1ull << 48) - 1);
686 }
687 }
688 env->macc[acc] = val;
689}
690
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100691void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000692{
693 int64_t sum;
694 int64_t result;
695
696 sum = env->macc[acc];
697 result = (sum << 16) >> 16;
698 if (result != sum) {
699 env->macsr |= MACSR_V;
700 }
701 if (env->macsr & MACSR_V) {
702 env->macsr |= MACSR_PAV0 << acc;
703 if (env->macsr & MACSR_OMC) {
704 result = (result >> 63) ^ 0x7fffffffffffll;
705 }
706 }
707 env->macc[acc] = result;
708}
709
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100710void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000711{
712 uint64_t val;
713 val = env->macc[acc];
Blue Swirlc4162572010-04-23 19:22:22 +0000714 if (val == 0) {
pbrooke1f38082008-05-24 22:29:16 +0000715 env->macsr |= MACSR_Z;
Blue Swirlc4162572010-04-23 19:22:22 +0000716 } else if (val & (1ull << 47)) {
pbrooke1f38082008-05-24 22:29:16 +0000717 env->macsr |= MACSR_N;
Blue Swirlc4162572010-04-23 19:22:22 +0000718 }
pbrooke1f38082008-05-24 22:29:16 +0000719 if (env->macsr & (MACSR_PAV0 << acc)) {
720 env->macsr |= MACSR_V;
721 }
722 if (env->macsr & MACSR_FI) {
723 val = ((int64_t)val) >> 40;
724 if (val != 0 && val != -1)
725 env->macsr |= MACSR_EV;
726 } else if (env->macsr & MACSR_SU) {
727 val = ((int64_t)val) >> 32;
728 if (val != 0 && val != -1)
729 env->macsr |= MACSR_EV;
730 } else {
731 if ((val >> 32) != 0)
732 env->macsr |= MACSR_EV;
733 }
734}
735
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100736void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
pbrooke1f38082008-05-24 22:29:16 +0000737{
738 cpu_m68k_flush_flags(env, cc_op);
739}
740
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100741uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
pbrooke1f38082008-05-24 22:29:16 +0000742{
743 int rem;
744 uint32_t result;
745
746 if (env->macsr & MACSR_SU) {
747 /* 16-bit rounding. */
748 rem = val & 0xffffff;
749 val = (val >> 24) & 0xffffu;
750 if (rem > 0x800000)
751 val++;
752 else if (rem == 0x800000)
753 val += (val & 1);
754 } else if (env->macsr & MACSR_RT) {
755 /* 32-bit rounding. */
756 rem = val & 0xff;
757 val >>= 8;
758 if (rem > 0x80)
759 val++;
760 else if (rem == 0x80)
761 val += (val & 1);
762 } else {
763 /* No rounding. */
764 val >>= 8;
765 }
766 if (env->macsr & MACSR_OMC) {
767 /* Saturate. */
768 if (env->macsr & MACSR_SU) {
769 if (val != (uint16_t) val) {
770 result = ((val >> 63) ^ 0x7fff) & 0xffff;
771 } else {
772 result = val & 0xffff;
773 }
774 } else {
775 if (val != (uint32_t)val) {
776 result = ((uint32_t)(val >> 63) & 0x7fffffff);
777 } else {
778 result = (uint32_t)val;
779 }
780 }
781 } else {
782 /* No saturation. */
783 if (env->macsr & MACSR_SU) {
784 result = val & 0xffff;
785 } else {
786 result = (uint32_t)val;
787 }
788 }
789 return result;
790}
791
792uint32_t HELPER(get_macs)(uint64_t val)
793{
794 if (val == (int32_t)val) {
795 return (int32_t)val;
796 } else {
797 return (val >> 61) ^ ~SIGNBIT;
798 }
799}
800
801uint32_t HELPER(get_macu)(uint64_t val)
802{
803 if ((val >> 32) == 0) {
804 return (uint32_t)val;
805 } else {
806 return 0xffffffffu;
807 }
808}
809
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100810uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000811{
812 uint32_t val;
813 val = env->macc[acc] & 0x00ff;
814 val = (env->macc[acc] >> 32) & 0xff00;
815 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
816 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
817 return val;
818}
819
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100820uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000821{
822 uint32_t val;
823 val = (env->macc[acc] >> 32) & 0xffff;
824 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
825 return val;
826}
827
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100828void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000829{
830 int64_t res;
831 int32_t tmp;
832 res = env->macc[acc] & 0xffffffff00ull;
833 tmp = (int16_t)(val & 0xff00);
834 res |= ((int64_t)tmp) << 32;
835 res |= val & 0xff;
836 env->macc[acc] = res;
837 res = env->macc[acc + 1] & 0xffffffff00ull;
838 tmp = (val & 0xff000000);
839 res |= ((int64_t)tmp) << 16;
840 res |= (val >> 16) & 0xff;
841 env->macc[acc + 1] = res;
842}
843
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100844void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000845{
846 int64_t res;
847 int32_t tmp;
848 res = (uint32_t)env->macc[acc];
849 tmp = (int16_t)val;
850 res |= ((int64_t)tmp) << 32;
851 env->macc[acc] = res;
852 res = (uint32_t)env->macc[acc + 1];
853 tmp = val & 0xffff0000;
854 res |= (int64_t)tmp << 16;
855 env->macc[acc + 1] = res;
856}
857
Andreas Färber2b3e3cf2012-03-14 01:38:22 +0100858void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
pbrooke1f38082008-05-24 22:29:16 +0000859{
860 uint64_t res;
861 res = (uint32_t)env->macc[acc];
862 res |= ((uint64_t)(val & 0xffff)) << 32;
863 env->macc[acc] = res;
864 res = (uint32_t)env->macc[acc + 1];
865 res |= (uint64_t)(val & 0xffff0000) << 16;
866 env->macc[acc + 1] = res;
867}
Richard Henderson00f3fd62014-09-13 09:45:15 -0700868
869void m68k_cpu_exec_enter(CPUState *cs)
870{
871 M68kCPU *cpu = M68K_CPU(cs);
872 CPUM68KState *env = &cpu->env;
873
874 env->cc_op = CC_OP_FLAGS;
875 env->cc_dest = env->sr & 0xf;
876 env->cc_x = (env->sr >> 4) & 1;
877}
878
879void m68k_cpu_exec_exit(CPUState *cs)
880{
881 M68kCPU *cpu = M68K_CPU(cs);
882 CPUM68KState *env = &cpu->env;
883
884 cpu_m68k_flush_flags(env, env->cc_op);
885 env->cc_op = CC_OP_FLAGS;
886 env->sr = (env->sr & 0xffe0) | env->cc_dest | (env->cc_x << 4);
887}