]> git.proxmox.com Git - qemu.git/blame - target-m68k/translate.c
Don't try to use "vt" output in nographic mode.
[qemu.git] / target-m68k / translate.c
CommitLineData
e6e5906b
PB
1/*
2 * m68k translation
3 *
0633879f 4 * Copyright (c) 2005-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
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <stdarg.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <inttypes.h>
26
27#include "config.h"
28#include "cpu.h"
29#include "exec-all.h"
30#include "disas.h"
31#include "m68k-qreg.h"
32
0633879f
PB
33//#define DEBUG_DISPATCH 1
34
e6e5906b
PB
35static inline void qemu_assert(int cond, const char *msg)
36{
37 if (!cond) {
38 fprintf (stderr, "badness: %s\n", msg);
39 abort();
40 }
41}
42
43/* internal defines */
44typedef struct DisasContext {
e6dbd3b3 45 CPUM68KState *env;
510ff0b7 46 target_ulong insn_pc; /* Start of the current instruction. */
e6e5906b
PB
47 target_ulong pc;
48 int is_jmp;
49 int cc_op;
0633879f 50 int user;
e6e5906b
PB
51 uint32_t fpcr;
52 struct TranslationBlock *tb;
53 int singlestep_enabled;
54} DisasContext;
55
56#define DISAS_JUMP_NEXT 4
57
0633879f
PB
58#if defined(CONFIG_USER_ONLY)
59#define IS_USER(s) 1
60#else
61#define IS_USER(s) s->user
62#endif
63
e6e5906b
PB
64/* XXX: move that elsewhere */
65/* ??? Fix exceptions. */
66static void *gen_throws_exception;
67#define gen_last_qop NULL
68
69static uint16_t *gen_opc_ptr;
70static uint32_t *gen_opparam_ptr;
71extern FILE *logfile;
72extern int loglevel;
73
74enum {
75#define DEF(s, n, copy_size) INDEX_op_ ## s,
76#include "opc.h"
77#undef DEF
78 NB_OPS,
79};
80
81#include "gen-op.h"
0633879f
PB
82
83#if defined(CONFIG_USER_ONLY)
84#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val)
85#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr)
86#else
87#define gen_st(s, name, addr, val) do { \
88 if (IS_USER(s)) \
89 gen_op_st##name##_user(addr, val); \
90 else \
91 gen_op_st##name##_kernel(addr, val); \
92 } while (0)
93#define gen_ld(s, name, val, addr) do { \
94 if (IS_USER(s)) \
95 gen_op_ld##name##_user(val, addr); \
96 else \
97 gen_op_ld##name##_kernel(val, addr); \
98 } while (0)
99#endif
100
e6e5906b
PB
101#include "op-hacks.h"
102
103#define OS_BYTE 0
104#define OS_WORD 1
105#define OS_LONG 2
106#define OS_SINGLE 4
107#define OS_DOUBLE 5
108
109#define DREG(insn, pos) (((insn >> pos) & 7) + QREG_D0)
110#define AREG(insn, pos) (((insn >> pos) & 7) + QREG_A0)
111#define FREG(insn, pos) (((insn >> pos) & 7) + QREG_F0)
112
e6e5906b
PB
113typedef void (*disas_proc)(DisasContext *, uint16_t);
114
0633879f
PB
115#ifdef DEBUG_DISPATCH
116#define DISAS_INSN(name) \
117 static void real_disas_##name (DisasContext *s, uint16_t insn); \
118 static void disas_##name (DisasContext *s, uint16_t insn) { \
119 if (logfile) fprintf(logfile, "Dispatch " #name "\n"); \
120 real_disas_##name(s, insn); } \
121 static void real_disas_##name (DisasContext *s, uint16_t insn)
122#else
e6e5906b
PB
123#define DISAS_INSN(name) \
124 static void disas_##name (DisasContext *s, uint16_t insn)
0633879f 125#endif
e6e5906b
PB
126
127/* Generate a load from the specified address. Narrow values are
128 sign extended to full register width. */
0633879f 129static inline int gen_load(DisasContext * s, int opsize, int addr, int sign)
e6e5906b
PB
130{
131 int tmp;
132 switch(opsize) {
133 case OS_BYTE:
134 tmp = gen_new_qreg(QMODE_I32);
135 if (sign)
0633879f 136 gen_ld(s, 8s32, tmp, addr);
e6e5906b 137 else
0633879f 138 gen_ld(s, 8u32, tmp, addr);
e6e5906b
PB
139 break;
140 case OS_WORD:
141 tmp = gen_new_qreg(QMODE_I32);
142 if (sign)
0633879f 143 gen_ld(s, 16s32, tmp, addr);
e6e5906b 144 else
0633879f 145 gen_ld(s, 16u32, tmp, addr);
e6e5906b
PB
146 break;
147 case OS_LONG:
148 tmp = gen_new_qreg(QMODE_I32);
0633879f 149 gen_ld(s, 32, tmp, addr);
e6e5906b
PB
150 break;
151 case OS_SINGLE:
152 tmp = gen_new_qreg(QMODE_F32);
0633879f 153 gen_ld(s, f32, tmp, addr);
e6e5906b
PB
154 break;
155 case OS_DOUBLE:
156 tmp = gen_new_qreg(QMODE_F64);
0633879f 157 gen_ld(s, f64, tmp, addr);
e6e5906b
PB
158 break;
159 default:
160 qemu_assert(0, "bad load size");
161 }
162 gen_throws_exception = gen_last_qop;
163 return tmp;
164}
165
166/* Generate a store. */
0633879f 167static inline void gen_store(DisasContext *s, int opsize, int addr, int val)
e6e5906b
PB
168{
169 switch(opsize) {
170 case OS_BYTE:
0633879f 171 gen_st(s, 8, addr, val);
e6e5906b
PB
172 break;
173 case OS_WORD:
0633879f 174 gen_st(s, 16, addr, val);
e6e5906b
PB
175 break;
176 case OS_LONG:
0633879f 177 gen_st(s, 32, addr, val);
e6e5906b
PB
178 break;
179 case OS_SINGLE:
0633879f 180 gen_st(s, f32, addr, val);
e6e5906b
PB
181 break;
182 case OS_DOUBLE:
0633879f 183 gen_st(s, f64, addr, val);
e6e5906b
PB
184 break;
185 default:
186 qemu_assert(0, "bad store size");
187 }
188 gen_throws_exception = gen_last_qop;
189}
190
191/* Generate an unsigned load if VAL is 0 a signed load if val is -1,
192 otherwise generate a store. */
0633879f 193static int gen_ldst(DisasContext *s, int opsize, int addr, int val)
e6e5906b
PB
194{
195 if (val > 0) {
0633879f 196 gen_store(s, opsize, addr, val);
e6e5906b
PB
197 return 0;
198 } else {
0633879f 199 return gen_load(s, opsize, addr, val != 0);
e6e5906b
PB
200 }
201}
202
e6dbd3b3
PB
203/* Read a 32-bit immediate constant. */
204static inline uint32_t read_im32(DisasContext *s)
205{
206 uint32_t im;
207 im = ((uint32_t)lduw_code(s->pc)) << 16;
208 s->pc += 2;
209 im |= lduw_code(s->pc);
210 s->pc += 2;
211 return im;
212}
213
214/* Calculate and address index. */
215static int gen_addr_index(uint16_t ext, int tmp)
216{
217 int add;
218 int scale;
219
220 add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
221 if ((ext & 0x800) == 0) {
222 gen_op_ext16s32(tmp, add);
223 add = tmp;
224 }
225 scale = (ext >> 9) & 3;
226 if (scale != 0) {
227 gen_op_shl32(tmp, add, gen_im32(scale));
228 add = tmp;
229 }
230 return add;
231}
232
e6e5906b
PB
233/* Handle a base + index + displacement effective addresss. A base of
234 -1 means pc-relative. */
235static int gen_lea_indexed(DisasContext *s, int opsize, int base)
236{
e6e5906b
PB
237 uint32_t offset;
238 uint16_t ext;
239 int add;
240 int tmp;
e6dbd3b3 241 uint32_t bd, od;
e6e5906b
PB
242
243 offset = s->pc;
0633879f 244 ext = lduw_code(s->pc);
e6e5906b 245 s->pc += 2;
e6dbd3b3
PB
246
247 if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
248 return -1;
249
250 if (ext & 0x100) {
251 /* full extension word format */
252 if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
253 return -1;
254
255 if ((ext & 0x30) > 0x10) {
256 /* base displacement */
257 if ((ext & 0x30) == 0x20) {
258 bd = (int16_t)lduw_code(s->pc);
259 s->pc += 2;
260 } else {
261 bd = read_im32(s);
262 }
263 } else {
264 bd = 0;
265 }
266 tmp = gen_new_qreg(QMODE_I32);
267 if ((ext & 0x44) == 0) {
268 /* pre-index */
269 add = gen_addr_index(ext, tmp);
270 } else {
271 add = QREG_NULL;
272 }
273 if ((ext & 0x80) == 0) {
274 /* base not suppressed */
275 if (base == -1) {
276 base = gen_im32(offset + bd);
277 bd = 0;
278 }
279 if (add) {
280 gen_op_add32(tmp, add, base);
281 add = tmp;
282 } else {
283 add = base;
284 }
285 }
286 if (add) {
287 if (bd != 0) {
288 gen_op_add32(tmp, add, gen_im32(bd));
289 add = tmp;
290 }
291 } else {
292 add = gen_im32(bd);
293 }
294 if ((ext & 3) != 0) {
295 /* memory indirect */
296 base = gen_load(s, OS_LONG, add, 0);
297 if ((ext & 0x44) == 4) {
298 add = gen_addr_index(ext, tmp);
299 gen_op_add32(tmp, add, base);
300 add = tmp;
301 } else {
302 add = base;
303 }
304 if ((ext & 3) > 1) {
305 /* outer displacement */
306 if ((ext & 3) == 2) {
307 od = (int16_t)lduw_code(s->pc);
308 s->pc += 2;
309 } else {
310 od = read_im32(s);
311 }
312 } else {
313 od = 0;
314 }
315 if (od != 0) {
2bc1abb7 316 gen_op_add32(tmp, add, gen_im32(od));
e6dbd3b3
PB
317 add = tmp;
318 }
319 }
e6e5906b 320 } else {
e6dbd3b3
PB
321 /* brief extension word format */
322 tmp = gen_new_qreg(QMODE_I32);
323 add = gen_addr_index(ext, tmp);
324 if (base != -1) {
325 gen_op_add32(tmp, add, base);
326 if ((int8_t)ext)
327 gen_op_add32(tmp, tmp, gen_im32((int8_t)ext));
328 } else {
329 gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext));
330 }
331 add = tmp;
e6e5906b 332 }
e6dbd3b3 333 return add;
e6e5906b
PB
334}
335
e6e5906b
PB
336/* Update the CPU env CC_OP state. */
337static inline void gen_flush_cc_op(DisasContext *s)
338{
339 if (s->cc_op != CC_OP_DYNAMIC)
340 gen_op_mov32(QREG_CC_OP, gen_im32(s->cc_op));
341}
342
343/* Evaluate all the CC flags. */
344static inline void gen_flush_flags(DisasContext *s)
345{
346 if (s->cc_op == CC_OP_FLAGS)
347 return;
348 gen_op_flush_flags(s->cc_op);
349 s->cc_op = CC_OP_FLAGS;
350}
351
352static inline int opsize_bytes(int opsize)
353{
354 switch (opsize) {
355 case OS_BYTE: return 1;
356 case OS_WORD: return 2;
357 case OS_LONG: return 4;
358 case OS_SINGLE: return 4;
359 case OS_DOUBLE: return 8;
360 default:
361 qemu_assert(0, "bad operand size");
362 }
363}
364
365/* Assign value to a register. If the width is less than the register width
366 only the low part of the register is set. */
367static void gen_partset_reg(int opsize, int reg, int val)
368{
369 int tmp;
370 switch (opsize) {
371 case OS_BYTE:
372 gen_op_and32(reg, reg, gen_im32(0xffffff00));
373 tmp = gen_new_qreg(QMODE_I32);
374 gen_op_and32(tmp, val, gen_im32(0xff));
375 gen_op_or32(reg, reg, tmp);
376 break;
377 case OS_WORD:
378 gen_op_and32(reg, reg, gen_im32(0xffff0000));
379 tmp = gen_new_qreg(QMODE_I32);
380 gen_op_and32(tmp, val, gen_im32(0xffff));
381 gen_op_or32(reg, reg, tmp);
382 break;
383 case OS_LONG:
384 gen_op_mov32(reg, val);
385 break;
386 case OS_SINGLE:
387 gen_op_pack_32_f32(reg, val);
388 break;
389 default:
390 qemu_assert(0, "Bad operand size");
391 break;
392 }
393}
394
395/* Sign or zero extend a value. */
396static inline int gen_extend(int val, int opsize, int sign)
397{
398 int tmp;
399
400 switch (opsize) {
401 case OS_BYTE:
402 tmp = gen_new_qreg(QMODE_I32);
403 if (sign)
404 gen_op_ext8s32(tmp, val);
405 else
406 gen_op_ext8u32(tmp, val);
407 break;
408 case OS_WORD:
409 tmp = gen_new_qreg(QMODE_I32);
410 if (sign)
411 gen_op_ext16s32(tmp, val);
412 else
413 gen_op_ext16u32(tmp, val);
414 break;
415 case OS_LONG:
416 tmp = val;
417 break;
418 case OS_SINGLE:
419 tmp = gen_new_qreg(QMODE_F32);
420 gen_op_pack_f32_32(tmp, val);
421 break;
422 default:
423 qemu_assert(0, "Bad operand size");
424 }
425 return tmp;
426}
427
428/* Generate code for an "effective address". Does not adjust the base
429 register for autoincrememnt addressing modes. */
430static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
431{
432 int reg;
433 int tmp;
434 uint16_t ext;
435 uint32_t offset;
436
437 reg = insn & 7;
438 switch ((insn >> 3) & 7) {
439 case 0: /* Data register direct. */
440 case 1: /* Address register direct. */
510ff0b7 441 return -1;
e6e5906b
PB
442 case 2: /* Indirect register */
443 case 3: /* Indirect postincrement. */
444 reg += QREG_A0;
445 return reg;
446 case 4: /* Indirect predecrememnt. */
447 reg += QREG_A0;
448 tmp = gen_new_qreg(QMODE_I32);
449 gen_op_sub32(tmp, reg, gen_im32(opsize_bytes(opsize)));
450 return tmp;
451 case 5: /* Indirect displacement. */
452 reg += QREG_A0;
453 tmp = gen_new_qreg(QMODE_I32);
0633879f 454 ext = lduw_code(s->pc);
e6e5906b
PB
455 s->pc += 2;
456 gen_op_add32(tmp, reg, gen_im32((int16_t)ext));
457 return tmp;
458 case 6: /* Indirect index + displacement. */
459 reg += QREG_A0;
460 return gen_lea_indexed(s, opsize, reg);
461 case 7: /* Other */
462 switch (reg) {
463 case 0: /* Absolute short. */
0633879f 464 offset = ldsw_code(s->pc);
e6e5906b
PB
465 s->pc += 2;
466 return gen_im32(offset);
467 case 1: /* Absolute long. */
468 offset = read_im32(s);
469 return gen_im32(offset);
470 case 2: /* pc displacement */
471 tmp = gen_new_qreg(QMODE_I32);
472 offset = s->pc;
0633879f 473 offset += ldsw_code(s->pc);
e6e5906b
PB
474 s->pc += 2;
475 return gen_im32(offset);
476 case 3: /* pc index+displacement. */
477 return gen_lea_indexed(s, opsize, -1);
478 case 4: /* Immediate. */
479 default:
510ff0b7 480 return -1;
e6e5906b
PB
481 }
482 }
483 /* Should never happen. */
484 return -1;
485}
486
487/* Helper function for gen_ea. Reuse the computed address between the
488 for read/write operands. */
489static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize,
490 int val, int *addrp)
491{
492 int tmp;
493
494 if (addrp && val > 0) {
495 tmp = *addrp;
496 } else {
497 tmp = gen_lea(s, insn, opsize);
510ff0b7
PB
498 if (tmp == -1)
499 return -1;
e6e5906b
PB
500 if (addrp)
501 *addrp = tmp;
502 }
0633879f 503 return gen_ldst(s, opsize, tmp, val);
e6e5906b
PB
504}
505
506/* Generate code to load/store a value ito/from an EA. If VAL > 0 this is
507 a write otherwise it is a read (0 == sign extend, -1 == zero extend).
508 ADDRP is non-null for readwrite operands. */
509static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
510 int *addrp)
511{
512 int reg;
513 int result;
514 uint32_t offset;
515
516 reg = insn & 7;
517 switch ((insn >> 3) & 7) {
518 case 0: /* Data register direct. */
519 reg += QREG_D0;
520 if (val > 0) {
521 gen_partset_reg(opsize, reg, val);
522 return 0;
523 } else {
524 return gen_extend(reg, opsize, val);
525 }
526 case 1: /* Address register direct. */
527 reg += QREG_A0;
528 if (val > 0) {
529 gen_op_mov32(reg, val);
530 return 0;
531 } else {
532 return gen_extend(reg, opsize, val);
533 }
534 case 2: /* Indirect register */
535 reg += QREG_A0;
0633879f 536 return gen_ldst(s, opsize, reg, val);
e6e5906b
PB
537 case 3: /* Indirect postincrement. */
538 reg += QREG_A0;
0633879f 539 result = gen_ldst(s, opsize, reg, val);
e6e5906b
PB
540 /* ??? This is not exception safe. The instruction may still
541 fault after this point. */
542 if (val > 0 || !addrp)
543 gen_op_add32(reg, reg, gen_im32(opsize_bytes(opsize)));
544 return result;
545 case 4: /* Indirect predecrememnt. */
546 {
547 int tmp;
548 if (addrp && val > 0) {
549 tmp = *addrp;
550 } else {
551 tmp = gen_lea(s, insn, opsize);
510ff0b7
PB
552 if (tmp == -1)
553 return -1;
e6e5906b
PB
554 if (addrp)
555 *addrp = tmp;
556 }
0633879f 557 result = gen_ldst(s, opsize, tmp, val);
e6e5906b
PB
558 /* ??? This is not exception safe. The instruction may still
559 fault after this point. */
560 if (val > 0 || !addrp) {
561 reg += QREG_A0;
562 gen_op_mov32(reg, tmp);
563 }
564 }
565 return result;
566 case 5: /* Indirect displacement. */
567 case 6: /* Indirect index + displacement. */
568 return gen_ea_once(s, insn, opsize, val, addrp);
569 case 7: /* Other */
570 switch (reg) {
571 case 0: /* Absolute short. */
572 case 1: /* Absolute long. */
573 case 2: /* pc displacement */
574 case 3: /* pc index+displacement. */
575 return gen_ea_once(s, insn, opsize, val, addrp);
576 case 4: /* Immediate. */
577 /* Sign extend values for consistency. */
578 switch (opsize) {
579 case OS_BYTE:
580 if (val)
0633879f 581 offset = ldsb_code(s->pc + 1);
e6e5906b 582 else
0633879f 583 offset = ldub_code(s->pc + 1);
e6e5906b
PB
584 s->pc += 2;
585 break;
586 case OS_WORD:
587 if (val)
0633879f 588 offset = ldsw_code(s->pc);
e6e5906b 589 else
0633879f 590 offset = lduw_code(s->pc);
e6e5906b
PB
591 s->pc += 2;
592 break;
593 case OS_LONG:
594 offset = read_im32(s);
595 break;
596 default:
597 qemu_assert(0, "Bad immediate operand");
598 }
599 return gen_im32(offset);
600 default:
510ff0b7 601 return -1;
e6e5906b
PB
602 }
603 }
604 /* Should never happen. */
605 return -1;
606}
607
608static void gen_logic_cc(DisasContext *s, int val)
609{
610 gen_op_logic_cc(val);
611 s->cc_op = CC_OP_LOGIC;
612}
613
614static void gen_jmpcc(DisasContext *s, int cond, int l1)
615{
616 int tmp;
617
618 gen_flush_flags(s);
619 switch (cond) {
620 case 0: /* T */
621 gen_op_jmp(l1);
622 break;
623 case 1: /* F */
624 break;
625 case 2: /* HI (!C && !Z) */
626 tmp = gen_new_qreg(QMODE_I32);
627 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z));
628 gen_op_jmp_z32(tmp, l1);
629 break;
630 case 3: /* LS (C || Z) */
631 tmp = gen_new_qreg(QMODE_I32);
632 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z));
633 gen_op_jmp_nz32(tmp, l1);
634 break;
635 case 4: /* CC (!C) */
636 tmp = gen_new_qreg(QMODE_I32);
637 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C));
638 gen_op_jmp_z32(tmp, l1);
639 break;
640 case 5: /* CS (C) */
641 tmp = gen_new_qreg(QMODE_I32);
642 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C));
643 gen_op_jmp_nz32(tmp, l1);
644 break;
645 case 6: /* NE (!Z) */
646 tmp = gen_new_qreg(QMODE_I32);
647 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
648 gen_op_jmp_z32(tmp, l1);
649 break;
650 case 7: /* EQ (Z) */
651 tmp = gen_new_qreg(QMODE_I32);
652 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
653 gen_op_jmp_nz32(tmp, l1);
654 break;
655 case 8: /* VC (!V) */
656 tmp = gen_new_qreg(QMODE_I32);
657 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
658 gen_op_jmp_z32(tmp, l1);
659 break;
660 case 9: /* VS (V) */
661 tmp = gen_new_qreg(QMODE_I32);
662 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
663 gen_op_jmp_nz32(tmp, l1);
664 break;
665 case 10: /* PL (!N) */
666 tmp = gen_new_qreg(QMODE_I32);
667 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N));
668 gen_op_jmp_z32(tmp, l1);
669 break;
670 case 11: /* MI (N) */
671 tmp = gen_new_qreg(QMODE_I32);
672 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N));
673 gen_op_jmp_nz32(tmp, l1);
674 break;
675 case 12: /* GE (!(N ^ V)) */
676 tmp = gen_new_qreg(QMODE_I32);
677 gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
678 gen_op_xor32(tmp, tmp, QREG_CC_DEST);
679 gen_op_and32(tmp, tmp, gen_im32(CCF_V));
680 gen_op_jmp_z32(tmp, l1);
681 break;
682 case 13: /* LT (N ^ V) */
683 tmp = gen_new_qreg(QMODE_I32);
684 gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
685 gen_op_xor32(tmp, tmp, QREG_CC_DEST);
686 gen_op_and32(tmp, tmp, gen_im32(CCF_V));
687 gen_op_jmp_nz32(tmp, l1);
688 break;
689 case 14: /* GT (!(Z || (N ^ V))) */
690 {
691 int l2;
692 l2 = gen_new_label();
693 tmp = gen_new_qreg(QMODE_I32);
694 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
695 gen_op_jmp_nz32(tmp, l2);
696 tmp = gen_new_qreg(QMODE_I32);
697 gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
698 gen_op_xor32(tmp, tmp, QREG_CC_DEST);
699 gen_op_and32(tmp, tmp, gen_im32(CCF_V));
700 gen_op_jmp_nz32(tmp, l2);
701 gen_op_jmp(l1);
702 gen_set_label(l2);
703 }
704 break;
705 case 15: /* LE (Z || (N ^ V)) */
706 tmp = gen_new_qreg(QMODE_I32);
707 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
708 gen_op_jmp_nz32(tmp, l1);
709 tmp = gen_new_qreg(QMODE_I32);
710 gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
711 gen_op_xor32(tmp, tmp, QREG_CC_DEST);
712 gen_op_and32(tmp, tmp, gen_im32(CCF_V));
713 gen_op_jmp_nz32(tmp, l1);
714 break;
715 default:
716 /* Should ever happen. */
717 abort();
718 }
719}
720
721DISAS_INSN(scc)
722{
723 int l1;
724 int cond;
725 int reg;
726
727 l1 = gen_new_label();
728 cond = (insn >> 8) & 0xf;
729 reg = DREG(insn, 0);
730 gen_op_and32(reg, reg, gen_im32(0xffffff00));
731 gen_jmpcc(s, cond ^ 1, l1);
732 gen_op_or32(reg, reg, gen_im32(0xff));
733 gen_set_label(l1);
734}
735
0633879f
PB
736/* Force a TB lookup after an instruction that changes the CPU state. */
737static void gen_lookup_tb(DisasContext *s)
738{
739 gen_flush_cc_op(s);
740 gen_op_mov32(QREG_PC, gen_im32(s->pc));
741 s->is_jmp = DISAS_UPDATE;
742}
743
e6e5906b
PB
744/* Generate a jump to to the address in qreg DEST. */
745static void gen_jmp(DisasContext *s, int dest)
746{
747 gen_flush_cc_op(s);
748 gen_op_mov32(QREG_PC, dest);
749 s->is_jmp = DISAS_JUMP;
750}
751
752static void gen_exception(DisasContext *s, uint32_t where, int nr)
753{
754 gen_flush_cc_op(s);
755 gen_jmp(s, gen_im32(where));
756 gen_op_raise_exception(nr);
757}
758
510ff0b7
PB
759static inline void gen_addr_fault(DisasContext *s)
760{
761 gen_exception(s, s->insn_pc, EXCP_ADDRESS);
762}
763
764#define SRC_EA(result, opsize, val, addrp) do { \
765 result = gen_ea(s, insn, opsize, val, addrp); \
766 if (result == -1) { \
767 gen_addr_fault(s); \
768 return; \
769 } \
770 } while (0)
771
772#define DEST_EA(insn, opsize, val, addrp) do { \
773 int ea_result = gen_ea(s, insn, opsize, val, addrp); \
774 if (ea_result == -1) { \
775 gen_addr_fault(s); \
776 return; \
777 } \
778 } while (0)
779
e6e5906b
PB
780/* Generate a jump to an immediate address. */
781static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
782{
783 TranslationBlock *tb;
784
785 tb = s->tb;
786 if (__builtin_expect (s->singlestep_enabled, 0)) {
787 gen_exception(s, dest, EXCP_DEBUG);
788 } else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
789 (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
790 gen_op_goto_tb(0, n, (long)tb);
791 gen_op_mov32(QREG_PC, gen_im32(dest));
792 gen_op_mov32(QREG_T0, gen_im32((long)tb + n));
793 gen_op_exit_tb();
794 } else {
795 gen_jmp(s, gen_im32(dest));
796 gen_op_mov32(QREG_T0, gen_im32(0));
797 gen_op_exit_tb();
798 }
799 s->is_jmp = DISAS_TB_JUMP;
800}
801
802DISAS_INSN(undef_mac)
803{
804 gen_exception(s, s->pc - 2, EXCP_LINEA);
805}
806
807DISAS_INSN(undef_fpu)
808{
809 gen_exception(s, s->pc - 2, EXCP_LINEF);
810}
811
812DISAS_INSN(undef)
813{
814 gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED);
815 cpu_abort(cpu_single_env, "Illegal instruction: %04x @ %08x",
816 insn, s->pc - 2);
817}
818
819DISAS_INSN(mulw)
820{
821 int reg;
822 int tmp;
823 int src;
824 int sign;
825
826 sign = (insn & 0x100) != 0;
827 reg = DREG(insn, 9);
828 tmp = gen_new_qreg(QMODE_I32);
829 if (sign)
830 gen_op_ext16s32(tmp, reg);
831 else
832 gen_op_ext16u32(tmp, reg);
510ff0b7 833 SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL);
e6e5906b
PB
834 gen_op_mul32(tmp, tmp, src);
835 gen_op_mov32(reg, tmp);
836 /* Unlike m68k, coldfire always clears the overflow bit. */
837 gen_logic_cc(s, tmp);
838}
839
840DISAS_INSN(divw)
841{
842 int reg;
843 int tmp;
844 int src;
845 int sign;
846
847 sign = (insn & 0x100) != 0;
848 reg = DREG(insn, 9);
849 if (sign) {
850 gen_op_ext16s32(QREG_DIV1, reg);
851 } else {
852 gen_op_ext16u32(QREG_DIV1, reg);
853 }
510ff0b7 854 SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL);
e6e5906b
PB
855 gen_op_mov32(QREG_DIV2, src);
856 if (sign) {
857 gen_op_divs(1);
858 } else {
859 gen_op_divu(1);
860 }
861
862 tmp = gen_new_qreg(QMODE_I32);
863 src = gen_new_qreg(QMODE_I32);
864 gen_op_ext16u32(tmp, QREG_DIV1);
865 gen_op_shl32(src, QREG_DIV2, gen_im32(16));
866 gen_op_or32(reg, tmp, src);
867 gen_op_flags_set();
868 s->cc_op = CC_OP_FLAGS;
869}
870
871DISAS_INSN(divl)
872{
873 int num;
874 int den;
875 int reg;
876 uint16_t ext;
877
0633879f 878 ext = lduw_code(s->pc);
e6e5906b
PB
879 s->pc += 2;
880 if (ext & 0x87f8) {
881 gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
882 return;
883 }
884 num = DREG(ext, 12);
885 reg = DREG(ext, 0);
886 gen_op_mov32(QREG_DIV1, num);
510ff0b7 887 SRC_EA(den, OS_LONG, 0, NULL);
e6e5906b
PB
888 gen_op_mov32(QREG_DIV2, den);
889 if (ext & 0x0800) {
2d37be61 890 gen_op_divs(2);
e6e5906b 891 } else {
2d37be61 892 gen_op_divu(2);
e6e5906b
PB
893 }
894 if (num == reg) {
895 /* div */
896 gen_op_mov32 (reg, QREG_DIV1);
897 } else {
898 /* rem */
899 gen_op_mov32 (reg, QREG_DIV2);
900 }
901 gen_op_flags_set();
902 s->cc_op = CC_OP_FLAGS;
903}
904
905DISAS_INSN(addsub)
906{
907 int reg;
908 int dest;
909 int src;
910 int tmp;
911 int addr;
912 int add;
913
914 add = (insn & 0x4000) != 0;
915 reg = DREG(insn, 9);
916 dest = gen_new_qreg(QMODE_I32);
917 if (insn & 0x100) {
510ff0b7 918 SRC_EA(tmp, OS_LONG, 0, &addr);
e6e5906b
PB
919 src = reg;
920 } else {
921 tmp = reg;
510ff0b7 922 SRC_EA(src, OS_LONG, 0, NULL);
e6e5906b
PB
923 }
924 if (add) {
925 gen_op_add32(dest, tmp, src);
926 gen_op_update_xflag_lt(dest, src);
927 s->cc_op = CC_OP_ADD;
928 } else {
929 gen_op_update_xflag_lt(tmp, src);
930 gen_op_sub32(dest, tmp, src);
931 s->cc_op = CC_OP_SUB;
932 }
933 gen_op_update_cc_add(dest, src);
934 if (insn & 0x100) {
510ff0b7 935 DEST_EA(insn, OS_LONG, dest, &addr);
e6e5906b
PB
936 } else {
937 gen_op_mov32(reg, dest);
938 }
939}
940
941
942/* Reverse the order of the bits in REG. */
943DISAS_INSN(bitrev)
944{
945 int val;
946 int tmp1;
947 int tmp2;
948 int reg;
949
950 val = gen_new_qreg(QMODE_I32);
951 tmp1 = gen_new_qreg(QMODE_I32);
952 tmp2 = gen_new_qreg(QMODE_I32);
953 reg = DREG(insn, 0);
954 gen_op_mov32(val, reg);
955 /* Reverse bits within each nibble. */
956 gen_op_shl32(tmp1, val, gen_im32(3));
957 gen_op_and32(tmp1, tmp1, gen_im32(0x88888888));
958 gen_op_shl32(tmp2, val, gen_im32(1));
959 gen_op_and32(tmp2, tmp2, gen_im32(0x44444444));
960 gen_op_or32(tmp1, tmp1, tmp2);
961 gen_op_shr32(tmp2, val, gen_im32(1));
962 gen_op_and32(tmp2, tmp2, gen_im32(0x22222222));
963 gen_op_or32(tmp1, tmp1, tmp2);
964 gen_op_shr32(tmp2, val, gen_im32(3));
965 gen_op_and32(tmp2, tmp2, gen_im32(0x11111111));
966 gen_op_or32(tmp1, tmp1, tmp2);
967 /* Reverse nibbles withing bytes. */
968 gen_op_shl32(val, tmp1, gen_im32(4));
969 gen_op_and32(val, val, gen_im32(0xf0f0f0f0));
970 gen_op_shr32(tmp2, tmp1, gen_im32(4));
971 gen_op_and32(tmp2, tmp2, gen_im32(0x0f0f0f0f));
972 gen_op_or32(val, val, tmp2);
973 /* Reverse bytes. */
974 gen_op_bswap32(reg, val);
975 gen_op_mov32(reg, val);
976}
977
978DISAS_INSN(bitop_reg)
979{
980 int opsize;
981 int op;
982 int src1;
983 int src2;
984 int tmp;
985 int addr;
986 int dest;
987
988 if ((insn & 0x38) != 0)
989 opsize = OS_BYTE;
990 else
991 opsize = OS_LONG;
992 op = (insn >> 6) & 3;
510ff0b7 993 SRC_EA(src1, opsize, 0, op ? &addr: NULL);
e6e5906b
PB
994 src2 = DREG(insn, 9);
995 dest = gen_new_qreg(QMODE_I32);
996
997 gen_flush_flags(s);
998 tmp = gen_new_qreg(QMODE_I32);
999 if (opsize == OS_BYTE)
1000 gen_op_and32(tmp, src2, gen_im32(7));
1001 else
1002 gen_op_and32(tmp, src2, gen_im32(31));
1003 src2 = tmp;
1004 tmp = gen_new_qreg(QMODE_I32);
1005 gen_op_shl32(tmp, gen_im32(1), src2);
1006
1007 gen_op_btest(src1, tmp);
1008 switch (op) {
1009 case 1: /* bchg */
1010 gen_op_xor32(dest, src1, tmp);
1011 break;
1012 case 2: /* bclr */
1013 gen_op_not32(tmp, tmp);
1014 gen_op_and32(dest, src1, tmp);
1015 break;
1016 case 3: /* bset */
1017 gen_op_or32(dest, src1, tmp);
1018 break;
1019 default: /* btst */
1020 break;
1021 }
1022 if (op)
510ff0b7 1023 DEST_EA(insn, opsize, dest, &addr);
e6e5906b
PB
1024}
1025
1026DISAS_INSN(sats)
1027{
1028 int reg;
1029 int tmp;
1030 int l1;
1031
1032 reg = DREG(insn, 0);
1033 tmp = gen_new_qreg(QMODE_I32);
1034 gen_flush_flags(s);
1035 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
1036 l1 = gen_new_label();
1037 gen_op_jmp_z32(tmp, l1);
1038 tmp = gen_new_qreg(QMODE_I32);
1039 gen_op_shr32(tmp, reg, gen_im32(31));
1040 gen_op_xor32(tmp, tmp, gen_im32(0x80000000));
1041 gen_op_mov32(reg, tmp);
1042 gen_set_label(l1);
1043 gen_logic_cc(s, tmp);
1044}
1045
0633879f 1046static void gen_push(DisasContext *s, int val)
e6e5906b
PB
1047{
1048 int tmp;
1049
1050 tmp = gen_new_qreg(QMODE_I32);
1051 gen_op_sub32(tmp, QREG_SP, gen_im32(4));
0633879f 1052 gen_store(s, OS_LONG, tmp, val);
e6e5906b
PB
1053 gen_op_mov32(QREG_SP, tmp);
1054}
1055
1056DISAS_INSN(movem)
1057{
1058 int addr;
1059 int i;
1060 uint16_t mask;
1061 int reg;
1062 int tmp;
1063 int is_load;
1064
0633879f 1065 mask = lduw_code(s->pc);
e6e5906b
PB
1066 s->pc += 2;
1067 tmp = gen_lea(s, insn, OS_LONG);
510ff0b7
PB
1068 if (tmp == -1) {
1069 gen_addr_fault(s);
1070 return;
1071 }
e6e5906b
PB
1072 addr = gen_new_qreg(QMODE_I32);
1073 gen_op_mov32(addr, tmp);
1074 is_load = ((insn & 0x0400) != 0);
1075 for (i = 0; i < 16; i++, mask >>= 1) {
1076 if (mask & 1) {
1077 if (i < 8)
1078 reg = DREG(i, 0);
1079 else
1080 reg = AREG(i, 0);
1081 if (is_load) {
0633879f 1082 tmp = gen_load(s, OS_LONG, addr, 0);
e6e5906b
PB
1083 gen_op_mov32(reg, tmp);
1084 } else {
0633879f 1085 gen_store(s, OS_LONG, addr, reg);
e6e5906b
PB
1086 }
1087 if (mask != 1)
1088 gen_op_add32(addr, addr, gen_im32(4));
1089 }
1090 }
1091}
1092
1093DISAS_INSN(bitop_im)
1094{
1095 int opsize;
1096 int op;
1097 int src1;
1098 uint32_t mask;
1099 int bitnum;
1100 int tmp;
1101 int addr;
1102 int dest;
1103
1104 if ((insn & 0x38) != 0)
1105 opsize = OS_BYTE;
1106 else
1107 opsize = OS_LONG;
1108 op = (insn >> 6) & 3;
1109
0633879f 1110 bitnum = lduw_code(s->pc);
e6e5906b
PB
1111 s->pc += 2;
1112 if (bitnum & 0xff00) {
1113 disas_undef(s, insn);
1114 return;
1115 }
1116
510ff0b7 1117 SRC_EA(src1, opsize, 0, op ? &addr: NULL);
e6e5906b
PB
1118
1119 gen_flush_flags(s);
1120 tmp = gen_new_qreg(QMODE_I32);
1121 if (opsize == OS_BYTE)
1122 bitnum &= 7;
1123 else
1124 bitnum &= 31;
1125 mask = 1 << bitnum;
1126
1127 gen_op_btest(src1, gen_im32(mask));
1128 if (op)
1129 dest = gen_new_qreg(QMODE_I32);
1130 else
1131 dest = -1;
1132
1133 switch (op) {
1134 case 1: /* bchg */
1135 gen_op_xor32(dest, src1, gen_im32(mask));
1136 break;
1137 case 2: /* bclr */
1138 gen_op_and32(dest, src1, gen_im32(~mask));
1139 break;
1140 case 3: /* bset */
1141 gen_op_or32(dest, src1, gen_im32(mask));
1142 break;
1143 default: /* btst */
1144 break;
1145 }
1146 if (op)
510ff0b7 1147 DEST_EA(insn, opsize, dest, &addr);
e6e5906b
PB
1148}
1149
1150DISAS_INSN(arith_im)
1151{
1152 int op;
1153 int src1;
1154 int dest;
1155 int src2;
1156 int addr;
1157
1158 op = (insn >> 9) & 7;
510ff0b7 1159 SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr);
e6e5906b
PB
1160 src2 = gen_im32(read_im32(s));
1161 dest = gen_new_qreg(QMODE_I32);
1162 switch (op) {
1163 case 0: /* ori */
1164 gen_op_or32(dest, src1, src2);
1165 gen_logic_cc(s, dest);
1166 break;
1167 case 1: /* andi */
1168 gen_op_and32(dest, src1, src2);
1169 gen_logic_cc(s, dest);
1170 break;
1171 case 2: /* subi */
1172 gen_op_mov32(dest, src1);
1173 gen_op_update_xflag_lt(dest, src2);
1174 gen_op_sub32(dest, dest, src2);
1175 gen_op_update_cc_add(dest, src2);
1176 s->cc_op = CC_OP_SUB;
1177 break;
1178 case 3: /* addi */
1179 gen_op_mov32(dest, src1);
1180 gen_op_add32(dest, dest, src2);
1181 gen_op_update_cc_add(dest, src2);
1182 gen_op_update_xflag_lt(dest, src2);
1183 s->cc_op = CC_OP_ADD;
1184 break;
1185 case 5: /* eori */
1186 gen_op_xor32(dest, src1, src2);
1187 gen_logic_cc(s, dest);
1188 break;
1189 case 6: /* cmpi */
1190 gen_op_mov32(dest, src1);
1191 gen_op_sub32(dest, dest, src2);
1192 gen_op_update_cc_add(dest, src2);
1193 s->cc_op = CC_OP_SUB;
1194 break;
1195 default:
1196 abort();
1197 }
1198 if (op != 6) {
510ff0b7 1199 DEST_EA(insn, OS_LONG, dest, &addr);
e6e5906b
PB
1200 }
1201}
1202
1203DISAS_INSN(byterev)
1204{
1205 int reg;
1206
1207 reg = DREG(insn, 0);
1208 gen_op_bswap32(reg, reg);
1209}
1210
1211DISAS_INSN(move)
1212{
1213 int src;
1214 int dest;
1215 int op;
1216 int opsize;
1217
1218 switch (insn >> 12) {
1219 case 1: /* move.b */
1220 opsize = OS_BYTE;
1221 break;
1222 case 2: /* move.l */
1223 opsize = OS_LONG;
1224 break;
1225 case 3: /* move.w */
1226 opsize = OS_WORD;
1227 break;
1228 default:
1229 abort();
1230 }
510ff0b7 1231 SRC_EA(src, opsize, -1, NULL);
e6e5906b
PB
1232 op = (insn >> 6) & 7;
1233 if (op == 1) {
1234 /* movea */
1235 /* The value will already have been sign extended. */
1236 dest = AREG(insn, 9);
1237 gen_op_mov32(dest, src);
1238 } else {
1239 /* normal move */
1240 uint16_t dest_ea;
1241 dest_ea = ((insn >> 9) & 7) | (op << 3);
510ff0b7 1242 DEST_EA(dest_ea, opsize, src, NULL);
e6e5906b
PB
1243 /* This will be correct because loads sign extend. */
1244 gen_logic_cc(s, src);
1245 }
1246}
1247
1248DISAS_INSN(negx)
1249{
1250 int reg;
1251 int dest;
1252 int tmp;
1253
1254 gen_flush_flags(s);
1255 reg = DREG(insn, 0);
1256 dest = gen_new_qreg(QMODE_I32);
1257 gen_op_mov32 (dest, gen_im32(0));
1258 gen_op_subx_cc(dest, reg);
1259 /* !Z is sticky. */
1260 tmp = gen_new_qreg(QMODE_I32);
1261 gen_op_mov32 (tmp, QREG_CC_DEST);
1262 gen_op_update_cc_add(dest, reg);
1263 gen_op_mov32(reg, dest);
1264 s->cc_op = CC_OP_DYNAMIC;
1265 gen_flush_flags(s);
1266 gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
1267 gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
1268 s->cc_op = CC_OP_FLAGS;
1269}
1270
1271DISAS_INSN(lea)
1272{
1273 int reg;
1274 int tmp;
1275
1276 reg = AREG(insn, 9);
1277 tmp = gen_lea(s, insn, OS_LONG);
510ff0b7
PB
1278 if (tmp == -1) {
1279 gen_addr_fault(s);
1280 return;
1281 }
e6e5906b
PB
1282 gen_op_mov32(reg, tmp);
1283}
1284
1285DISAS_INSN(clr)
1286{
1287 int opsize;
1288
1289 switch ((insn >> 6) & 3) {
1290 case 0: /* clr.b */
1291 opsize = OS_BYTE;
1292 break;
1293 case 1: /* clr.w */
1294 opsize = OS_WORD;
1295 break;
1296 case 2: /* clr.l */
1297 opsize = OS_LONG;
1298 break;
1299 default:
1300 abort();
1301 }
510ff0b7 1302 DEST_EA(insn, opsize, gen_im32(0), NULL);
e6e5906b
PB
1303 gen_logic_cc(s, gen_im32(0));
1304}
1305
0633879f 1306static int gen_get_ccr(DisasContext *s)
e6e5906b 1307{
e6e5906b
PB
1308 int dest;
1309
1310 gen_flush_flags(s);
1311 dest = gen_new_qreg(QMODE_I32);
1312 gen_op_get_xflag(dest);
1313 gen_op_shl32(dest, dest, gen_im32(4));
1314 gen_op_or32(dest, dest, QREG_CC_DEST);
0633879f
PB
1315 return dest;
1316}
1317
1318DISAS_INSN(move_from_ccr)
1319{
1320 int reg;
1321 int ccr;
1322
1323 ccr = gen_get_ccr(s);
e6e5906b 1324 reg = DREG(insn, 0);
0633879f 1325 gen_partset_reg(OS_WORD, reg, ccr);
e6e5906b
PB
1326}
1327
1328DISAS_INSN(neg)
1329{
1330 int reg;
1331 int src1;
1332
1333 reg = DREG(insn, 0);
1334 src1 = gen_new_qreg(QMODE_I32);
1335 gen_op_mov32(src1, reg);
1336 gen_op_neg32(reg, src1);
1337 s->cc_op = CC_OP_SUB;
1338 gen_op_update_cc_add(reg, src1);
1339 gen_op_update_xflag_lt(gen_im32(0), src1);
1340 s->cc_op = CC_OP_SUB;
1341}
1342
0633879f
PB
1343static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
1344{
1345 gen_op_logic_cc(gen_im32(val & 0xf));
1346 gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4));
1347 if (!ccr_only) {
20dcee94 1348 gen_op_set_sr(gen_im32(val & 0xff00));
0633879f
PB
1349 }
1350}
1351
1352static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only)
e6e5906b
PB
1353{
1354 int src1;
1355 int reg;
1356
1357 s->cc_op = CC_OP_FLAGS;
1358 if ((insn & 0x38) == 0)
1359 {
1360 src1 = gen_new_qreg(QMODE_I32);
1361 reg = DREG(insn, 0);
1362 gen_op_and32(src1, reg, gen_im32(0xf));
1363 gen_op_logic_cc(src1);
1364 gen_op_shr32(src1, reg, gen_im32(4));
1365 gen_op_and32(src1, src1, gen_im32(1));
1366 gen_op_update_xflag_tst(src1);
0633879f 1367 if (!ccr_only) {
20dcee94 1368 gen_op_set_sr(reg);
0633879f 1369 }
e6e5906b 1370 }
0633879f 1371 else if ((insn & 0x3f) == 0x3c)
e6e5906b 1372 {
0633879f
PB
1373 uint16_t val;
1374 val = lduw_code(s->pc);
e6e5906b 1375 s->pc += 2;
0633879f 1376 gen_set_sr_im(s, val, ccr_only);
e6e5906b
PB
1377 }
1378 else
1379 disas_undef(s, insn);
1380}
1381
0633879f
PB
1382DISAS_INSN(move_to_ccr)
1383{
1384 gen_set_sr(s, insn, 1);
1385}
1386
e6e5906b
PB
1387DISAS_INSN(not)
1388{
1389 int reg;
1390
1391 reg = DREG(insn, 0);
1392 gen_op_not32(reg, reg);
1393 gen_logic_cc(s, reg);
1394}
1395
1396DISAS_INSN(swap)
1397{
1398 int dest;
1399 int src1;
1400 int src2;
1401 int reg;
1402
1403 dest = gen_new_qreg(QMODE_I32);
1404 src1 = gen_new_qreg(QMODE_I32);
1405 src2 = gen_new_qreg(QMODE_I32);
1406 reg = DREG(insn, 0);
1407 gen_op_shl32(src1, reg, gen_im32(16));
1408 gen_op_shr32(src2, reg, gen_im32(16));
1409 gen_op_or32(dest, src1, src2);
1410 gen_op_mov32(reg, dest);
1411 gen_logic_cc(s, dest);
1412}
1413
1414DISAS_INSN(pea)
1415{
1416 int tmp;
1417
1418 tmp = gen_lea(s, insn, OS_LONG);
510ff0b7
PB
1419 if (tmp == -1) {
1420 gen_addr_fault(s);
1421 return;
1422 }
0633879f 1423 gen_push(s, tmp);
e6e5906b
PB
1424}
1425
1426DISAS_INSN(ext)
1427{
1428 int reg;
1429 int op;
1430 int tmp;
1431
1432 reg = DREG(insn, 0);
1433 op = (insn >> 6) & 7;
1434 tmp = gen_new_qreg(QMODE_I32);
1435 if (op == 3)
1436 gen_op_ext16s32(tmp, reg);
1437 else
1438 gen_op_ext8s32(tmp, reg);
1439 if (op == 2)
1440 gen_partset_reg(OS_WORD, reg, tmp);
1441 else
1442 gen_op_mov32(reg, tmp);
1443 gen_logic_cc(s, tmp);
1444}
1445
1446DISAS_INSN(tst)
1447{
1448 int opsize;
1449 int tmp;
1450
1451 switch ((insn >> 6) & 3) {
1452 case 0: /* tst.b */
1453 opsize = OS_BYTE;
1454 break;
1455 case 1: /* tst.w */
1456 opsize = OS_WORD;
1457 break;
1458 case 2: /* tst.l */
1459 opsize = OS_LONG;
1460 break;
1461 default:
1462 abort();
1463 }
510ff0b7 1464 SRC_EA(tmp, opsize, -1, NULL);
e6e5906b
PB
1465 gen_logic_cc(s, tmp);
1466}
1467
1468DISAS_INSN(pulse)
1469{
1470 /* Implemented as a NOP. */
1471}
1472
1473DISAS_INSN(illegal)
1474{
1475 gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
1476}
1477
1478/* ??? This should be atomic. */
1479DISAS_INSN(tas)
1480{
1481 int dest;
1482 int src1;
1483 int addr;
1484
1485 dest = gen_new_qreg(QMODE_I32);
510ff0b7 1486 SRC_EA(src1, OS_BYTE, -1, &addr);
e6e5906b
PB
1487 gen_logic_cc(s, src1);
1488 gen_op_or32(dest, src1, gen_im32(0x80));
510ff0b7 1489 DEST_EA(insn, OS_BYTE, dest, &addr);
e6e5906b
PB
1490}
1491
1492DISAS_INSN(mull)
1493{
1494 uint16_t ext;
1495 int reg;
1496 int src1;
1497 int dest;
1498
1499 /* The upper 32 bits of the product are discarded, so
1500 muls.l and mulu.l are functionally equivalent. */
0633879f 1501 ext = lduw_code(s->pc);
e6e5906b
PB
1502 s->pc += 2;
1503 if (ext & 0x87ff) {
1504 gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
1505 return;
1506 }
1507 reg = DREG(ext, 12);
510ff0b7 1508 SRC_EA(src1, OS_LONG, 0, NULL);
e6e5906b
PB
1509 dest = gen_new_qreg(QMODE_I32);
1510 gen_op_mul32(dest, src1, reg);
1511 gen_op_mov32(reg, dest);
1512 /* Unlike m68k, coldfire always clears the overflow bit. */
1513 gen_logic_cc(s, dest);
1514}
1515
1516DISAS_INSN(link)
1517{
1518 int16_t offset;
1519 int reg;
1520 int tmp;
1521
0633879f 1522 offset = ldsw_code(s->pc);
e6e5906b
PB
1523 s->pc += 2;
1524 reg = AREG(insn, 0);
1525 tmp = gen_new_qreg(QMODE_I32);
1526 gen_op_sub32(tmp, QREG_SP, gen_im32(4));
0633879f 1527 gen_store(s, OS_LONG, tmp, reg);
e6e5906b
PB
1528 if (reg != QREG_SP)
1529 gen_op_mov32(reg, tmp);
1530 gen_op_add32(QREG_SP, tmp, gen_im32(offset));
1531}
1532
1533DISAS_INSN(unlk)
1534{
1535 int src;
1536 int reg;
1537 int tmp;
1538
1539 src = gen_new_qreg(QMODE_I32);
1540 reg = AREG(insn, 0);
1541 gen_op_mov32(src, reg);
0633879f 1542 tmp = gen_load(s, OS_LONG, src, 0);
e6e5906b
PB
1543 gen_op_mov32(reg, tmp);
1544 gen_op_add32(QREG_SP, src, gen_im32(4));
1545}
1546
1547DISAS_INSN(nop)
1548{
1549}
1550
1551DISAS_INSN(rts)
1552{
1553 int tmp;
1554
0633879f 1555 tmp = gen_load(s, OS_LONG, QREG_SP, 0);
e6e5906b
PB
1556 gen_op_add32(QREG_SP, QREG_SP, gen_im32(4));
1557 gen_jmp(s, tmp);
1558}
1559
1560DISAS_INSN(jump)
1561{
1562 int tmp;
1563
1564 /* Load the target address first to ensure correct exception
1565 behavior. */
1566 tmp = gen_lea(s, insn, OS_LONG);
510ff0b7
PB
1567 if (tmp == -1) {
1568 gen_addr_fault(s);
1569 return;
1570 }
e6e5906b
PB
1571 if ((insn & 0x40) == 0) {
1572 /* jsr */
0633879f 1573 gen_push(s, gen_im32(s->pc));
e6e5906b
PB
1574 }
1575 gen_jmp(s, tmp);
1576}
1577
1578DISAS_INSN(addsubq)
1579{
1580 int src1;
1581 int src2;
1582 int dest;
1583 int val;
1584 int addr;
1585
510ff0b7 1586 SRC_EA(src1, OS_LONG, 0, &addr);
e6e5906b
PB
1587 val = (insn >> 9) & 7;
1588 if (val == 0)
1589 val = 8;
1590 src2 = gen_im32(val);
1591 dest = gen_new_qreg(QMODE_I32);
1592 gen_op_mov32(dest, src1);
1593 if ((insn & 0x38) == 0x08) {
1594 /* Don't update condition codes if the destination is an
1595 address register. */
1596 if (insn & 0x0100) {
1597 gen_op_sub32(dest, dest, src2);
1598 } else {
1599 gen_op_add32(dest, dest, src2);
1600 }
1601 } else {
1602 if (insn & 0x0100) {
1603 gen_op_update_xflag_lt(dest, src2);
1604 gen_op_sub32(dest, dest, src2);
1605 s->cc_op = CC_OP_SUB;
1606 } else {
1607 gen_op_add32(dest, dest, src2);
1608 gen_op_update_xflag_lt(dest, src2);
1609 s->cc_op = CC_OP_ADD;
1610 }
1611 gen_op_update_cc_add(dest, src2);
1612 }
510ff0b7 1613 DEST_EA(insn, OS_LONG, dest, &addr);
e6e5906b
PB
1614}
1615
1616DISAS_INSN(tpf)
1617{
1618 switch (insn & 7) {
1619 case 2: /* One extension word. */
1620 s->pc += 2;
1621 break;
1622 case 3: /* Two extension words. */
1623 s->pc += 4;
1624 break;
1625 case 4: /* No extension words. */
1626 break;
1627 default:
1628 disas_undef(s, insn);
1629 }
1630}
1631
1632DISAS_INSN(branch)
1633{
1634 int32_t offset;
1635 uint32_t base;
1636 int op;
1637 int l1;
1638
1639 base = s->pc;
1640 op = (insn >> 8) & 0xf;
1641 offset = (int8_t)insn;
1642 if (offset == 0) {
0633879f 1643 offset = ldsw_code(s->pc);
e6e5906b
PB
1644 s->pc += 2;
1645 } else if (offset == -1) {
1646 offset = read_im32(s);
1647 }
1648 if (op == 1) {
1649 /* bsr */
0633879f 1650 gen_push(s, gen_im32(s->pc));
e6e5906b
PB
1651 }
1652 gen_flush_cc_op(s);
1653 if (op > 1) {
1654 /* Bcc */
1655 l1 = gen_new_label();
1656 gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
1657 gen_jmp_tb(s, 1, base + offset);
1658 gen_set_label(l1);
1659 gen_jmp_tb(s, 0, s->pc);
1660 } else {
1661 /* Unconditional branch. */
1662 gen_jmp_tb(s, 0, base + offset);
1663 }
1664}
1665
1666DISAS_INSN(moveq)
1667{
1668 int tmp;
1669
1670 tmp = gen_im32((int8_t)insn);
1671 gen_op_mov32(DREG(insn, 9), tmp);
1672 gen_logic_cc(s, tmp);
1673}
1674
1675DISAS_INSN(mvzs)
1676{
1677 int opsize;
1678 int src;
1679 int reg;
1680
1681 if (insn & 0x40)
1682 opsize = OS_WORD;
1683 else
1684 opsize = OS_BYTE;
510ff0b7 1685 SRC_EA(src, opsize, (insn & 0x80) ? 0 : -1, NULL);
e6e5906b
PB
1686 reg = DREG(insn, 9);
1687 gen_op_mov32(reg, src);
1688 gen_logic_cc(s, src);
1689}
1690
1691DISAS_INSN(or)
1692{
1693 int reg;
1694 int dest;
1695 int src;
1696 int addr;
1697
1698 reg = DREG(insn, 9);
1699 dest = gen_new_qreg(QMODE_I32);
1700 if (insn & 0x100) {
510ff0b7 1701 SRC_EA(src, OS_LONG, 0, &addr);
e6e5906b 1702 gen_op_or32(dest, src, reg);
510ff0b7 1703 DEST_EA(insn, OS_LONG, dest, &addr);
e6e5906b 1704 } else {
510ff0b7 1705 SRC_EA(src, OS_LONG, 0, NULL);
e6e5906b
PB
1706 gen_op_or32(dest, src, reg);
1707 gen_op_mov32(reg, dest);
1708 }
1709 gen_logic_cc(s, dest);
1710}
1711
1712DISAS_INSN(suba)
1713{
1714 int src;
1715 int reg;
1716
510ff0b7 1717 SRC_EA(src, OS_LONG, 0, NULL);
e6e5906b
PB
1718 reg = AREG(insn, 9);
1719 gen_op_sub32(reg, reg, src);
1720}
1721
1722DISAS_INSN(subx)
1723{
1724 int reg;
1725 int src;
1726 int dest;
1727 int tmp;
1728
1729 gen_flush_flags(s);
1730 reg = DREG(insn, 9);
1731 src = DREG(insn, 0);
1732 dest = gen_new_qreg(QMODE_I32);
1733 gen_op_mov32 (dest, reg);
1734 gen_op_subx_cc(dest, src);
1735 /* !Z is sticky. */
1736 tmp = gen_new_qreg(QMODE_I32);
1737 gen_op_mov32 (tmp, QREG_CC_DEST);
1738 gen_op_update_cc_add(dest, src);
1739 gen_op_mov32(reg, dest);
1740 s->cc_op = CC_OP_DYNAMIC;
1741 gen_flush_flags(s);
1742 gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
1743 gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
1744 s->cc_op = CC_OP_FLAGS;
1745}
1746
1747DISAS_INSN(mov3q)
1748{
1749 int src;
1750 int val;
1751
1752 val = (insn >> 9) & 7;
1753 if (val == 0)
1754 val = -1;
1755 src = gen_im32(val);
1756 gen_logic_cc(s, src);
510ff0b7 1757 DEST_EA(insn, OS_LONG, src, NULL);
e6e5906b
PB
1758}
1759
1760DISAS_INSN(cmp)
1761{
1762 int op;
1763 int src;
1764 int reg;
1765 int dest;
1766 int opsize;
1767
1768 op = (insn >> 6) & 3;
1769 switch (op) {
1770 case 0: /* cmp.b */
1771 opsize = OS_BYTE;
1772 s->cc_op = CC_OP_CMPB;
1773 break;
1774 case 1: /* cmp.w */
1775 opsize = OS_WORD;
1776 s->cc_op = CC_OP_CMPW;
1777 break;
1778 case 2: /* cmp.l */
1779 opsize = OS_LONG;
1780 s->cc_op = CC_OP_SUB;
1781 break;
1782 default:
1783 abort();
1784 }
510ff0b7 1785 SRC_EA(src, opsize, -1, NULL);
e6e5906b
PB
1786 reg = DREG(insn, 9);
1787 dest = gen_new_qreg(QMODE_I32);
1788 gen_op_sub32(dest, reg, src);
1789 gen_op_update_cc_add(dest, src);
1790}
1791
1792DISAS_INSN(cmpa)
1793{
1794 int opsize;
1795 int src;
1796 int reg;
1797 int dest;
1798
1799 if (insn & 0x100) {
1800 opsize = OS_LONG;
1801 } else {
1802 opsize = OS_WORD;
1803 }
510ff0b7 1804 SRC_EA(src, opsize, -1, NULL);
e6e5906b
PB
1805 reg = AREG(insn, 9);
1806 dest = gen_new_qreg(QMODE_I32);
1807 gen_op_sub32(dest, reg, src);
1808 gen_op_update_cc_add(dest, src);
1809 s->cc_op = CC_OP_SUB;
1810}
1811
1812DISAS_INSN(eor)
1813{
1814 int src;
1815 int reg;
1816 int dest;
1817 int addr;
1818
510ff0b7 1819 SRC_EA(src, OS_LONG, 0, &addr);
e6e5906b
PB
1820 reg = DREG(insn, 9);
1821 dest = gen_new_qreg(QMODE_I32);
1822 gen_op_xor32(dest, src, reg);
1823 gen_logic_cc(s, dest);
510ff0b7 1824 DEST_EA(insn, OS_LONG, dest, &addr);
e6e5906b
PB
1825}
1826
1827DISAS_INSN(and)
1828{
1829 int src;
1830 int reg;
1831 int dest;
1832 int addr;
1833
1834 reg = DREG(insn, 9);
1835 dest = gen_new_qreg(QMODE_I32);
1836 if (insn & 0x100) {
510ff0b7 1837 SRC_EA(src, OS_LONG, 0, &addr);
e6e5906b 1838 gen_op_and32(dest, src, reg);
510ff0b7 1839 DEST_EA(insn, OS_LONG, dest, &addr);
e6e5906b 1840 } else {
510ff0b7 1841 SRC_EA(src, OS_LONG, 0, NULL);
e6e5906b
PB
1842 gen_op_and32(dest, src, reg);
1843 gen_op_mov32(reg, dest);
1844 }
1845 gen_logic_cc(s, dest);
1846}
1847
1848DISAS_INSN(adda)
1849{
1850 int src;
1851 int reg;
1852
510ff0b7 1853 SRC_EA(src, OS_LONG, 0, NULL);
e6e5906b
PB
1854 reg = AREG(insn, 9);
1855 gen_op_add32(reg, reg, src);
1856}
1857
1858DISAS_INSN(addx)
1859{
1860 int reg;
1861 int src;
1862 int dest;
1863 int tmp;
1864
1865 gen_flush_flags(s);
1866 reg = DREG(insn, 9);
1867 src = DREG(insn, 0);
1868 dest = gen_new_qreg(QMODE_I32);
1869 gen_op_mov32 (dest, reg);
1870 gen_op_addx_cc(dest, src);
1871 /* !Z is sticky. */
1872 tmp = gen_new_qreg(QMODE_I32);
1873 gen_op_mov32 (tmp, QREG_CC_DEST);
1874 gen_op_update_cc_add(dest, src);
1875 gen_op_mov32(reg, dest);
1876 s->cc_op = CC_OP_DYNAMIC;
1877 gen_flush_flags(s);
1878 gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
1879 gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
1880 s->cc_op = CC_OP_FLAGS;
1881}
1882
1883DISAS_INSN(shift_im)
1884{
1885 int reg;
1886 int tmp;
1887
1888 reg = DREG(insn, 0);
1889 tmp = (insn >> 9) & 7;
1890 if (tmp == 0)
1891 tmp = 8;
1892 if (insn & 0x100) {
1893 gen_op_shl_im_cc(reg, tmp);
1894 s->cc_op = CC_OP_SHL;
1895 } else {
1896 if (insn & 8) {
1897 gen_op_shr_im_cc(reg, tmp);
1898 s->cc_op = CC_OP_SHR;
1899 } else {
1900 gen_op_sar_im_cc(reg, tmp);
1901 s->cc_op = CC_OP_SAR;
1902 }
1903 }
1904}
1905
1906DISAS_INSN(shift_reg)
1907{
1908 int reg;
1909 int src;
1910 int tmp;
1911
1912 reg = DREG(insn, 0);
1913 src = DREG(insn, 9);
1914 tmp = gen_new_qreg(QMODE_I32);
1915 gen_op_and32(tmp, src, gen_im32(63));
1916 if (insn & 0x100) {
1917 gen_op_shl_cc(reg, tmp);
1918 s->cc_op = CC_OP_SHL;
1919 } else {
1920 if (insn & 8) {
1921 gen_op_shr_cc(reg, tmp);
1922 s->cc_op = CC_OP_SHR;
1923 } else {
1924 gen_op_sar_cc(reg, tmp);
1925 s->cc_op = CC_OP_SAR;
1926 }
1927 }
1928}
1929
1930DISAS_INSN(ff1)
1931{
821f7e76
PB
1932 int reg;
1933 reg = DREG(insn, 0);
1934 gen_logic_cc(s, reg);
1935 gen_op_ff1(reg, reg);
e6e5906b
PB
1936}
1937
0633879f
PB
1938static int gen_get_sr(DisasContext *s)
1939{
1940 int ccr;
1941 int sr;
1942
1943 ccr = gen_get_ccr(s);
1944 sr = gen_new_qreg(QMODE_I32);
1945 gen_op_and32(sr, QREG_SR, gen_im32(0xffe0));
1946 gen_op_or32(sr, sr, ccr);
1947 return sr;
1948}
1949
e6e5906b
PB
1950DISAS_INSN(strldsr)
1951{
1952 uint16_t ext;
1953 uint32_t addr;
1954
1955 addr = s->pc - 2;
0633879f 1956 ext = lduw_code(s->pc);
e6e5906b 1957 s->pc += 2;
0633879f 1958 if (ext != 0x46FC) {
e6e5906b 1959 gen_exception(s, addr, EXCP_UNSUPPORTED);
0633879f
PB
1960 return;
1961 }
1962 ext = lduw_code(s->pc);
1963 s->pc += 2;
1964 if (IS_USER(s) || (ext & SR_S) == 0) {
e6e5906b 1965 gen_exception(s, addr, EXCP_PRIVILEGE);
0633879f
PB
1966 return;
1967 }
1968 gen_push(s, gen_get_sr(s));
1969 gen_set_sr_im(s, ext, 0);
e6e5906b
PB
1970}
1971
1972DISAS_INSN(move_from_sr)
1973{
0633879f
PB
1974 int reg;
1975 int sr;
1976
1977 if (IS_USER(s)) {
1978 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1979 return;
1980 }
1981 sr = gen_get_sr(s);
1982 reg = DREG(insn, 0);
1983 gen_partset_reg(OS_WORD, reg, sr);
e6e5906b
PB
1984}
1985
1986DISAS_INSN(move_to_sr)
1987{
0633879f
PB
1988 if (IS_USER(s)) {
1989 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1990 return;
1991 }
1992 gen_set_sr(s, insn, 0);
1993 gen_lookup_tb(s);
e6e5906b
PB
1994}
1995
1996DISAS_INSN(move_from_usp)
1997{
0633879f
PB
1998 if (IS_USER(s)) {
1999 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2000 return;
2001 }
2002 /* TODO: Implement USP. */
2003 gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
e6e5906b
PB
2004}
2005
2006DISAS_INSN(move_to_usp)
2007{
0633879f
PB
2008 if (IS_USER(s)) {
2009 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2010 return;
2011 }
2012 /* TODO: Implement USP. */
2013 gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
e6e5906b
PB
2014}
2015
2016DISAS_INSN(halt)
2017{
0633879f
PB
2018 gen_jmp(s, gen_im32(s->pc));
2019 gen_op_halt();
e6e5906b
PB
2020}
2021
2022DISAS_INSN(stop)
2023{
0633879f
PB
2024 uint16_t ext;
2025
2026 if (IS_USER(s)) {
2027 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2028 return;
2029 }
2030
2031 ext = lduw_code(s->pc);
2032 s->pc += 2;
2033
2034 gen_set_sr_im(s, ext, 0);
a87295e8
PB
2035 gen_jmp(s, gen_im32(s->pc));
2036 gen_op_stop();
e6e5906b
PB
2037}
2038
2039DISAS_INSN(rte)
2040{
0633879f
PB
2041 if (IS_USER(s)) {
2042 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2043 return;
2044 }
2045 gen_exception(s, s->pc - 2, EXCP_RTE);
e6e5906b
PB
2046}
2047
2048DISAS_INSN(movec)
2049{
0633879f
PB
2050 uint16_t ext;
2051 int reg;
2052
2053 if (IS_USER(s)) {
2054 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2055 return;
2056 }
2057
2058 ext = lduw_code(s->pc);
2059 s->pc += 2;
2060
2061 if (ext & 0x8000) {
2062 reg = AREG(ext, 12);
2063 } else {
2064 reg = DREG(ext, 12);
2065 }
2066 gen_op_movec(gen_im32(ext & 0xfff), reg);
2067 gen_lookup_tb(s);
e6e5906b
PB
2068}
2069
2070DISAS_INSN(intouch)
2071{
0633879f
PB
2072 if (IS_USER(s)) {
2073 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2074 return;
2075 }
2076 /* ICache fetch. Implement as no-op. */
e6e5906b
PB
2077}
2078
2079DISAS_INSN(cpushl)
2080{
0633879f
PB
2081 if (IS_USER(s)) {
2082 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2083 return;
2084 }
2085 /* Cache push/invalidate. Implement as no-op. */
e6e5906b
PB
2086}
2087
2088DISAS_INSN(wddata)
2089{
2090 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2091}
2092
2093DISAS_INSN(wdebug)
2094{
0633879f
PB
2095 if (IS_USER(s)) {
2096 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2097 return;
2098 }
2099 /* TODO: Implement wdebug. */
2100 qemu_assert(0, "WDEBUG not implemented");
e6e5906b
PB
2101}
2102
2103DISAS_INSN(trap)
2104{
2105 gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf));
2106}
2107
2108/* ??? FP exceptions are not implemented. Most exceptions are deferred until
2109 immediately before the next FP instruction is executed. */
2110DISAS_INSN(fpu)
2111{
2112 uint16_t ext;
2113 int opmode;
2114 int src;
2115 int dest;
2116 int res;
2117 int round;
2118 int opsize;
2119
0633879f 2120 ext = lduw_code(s->pc);
e6e5906b
PB
2121 s->pc += 2;
2122 opmode = ext & 0x7f;
2123 switch ((ext >> 13) & 7) {
2124 case 0: case 2:
2125 break;
2126 case 1:
2127 goto undef;
2128 case 3: /* fmove out */
2129 src = FREG(ext, 7);
2130 /* fmove */
2131 /* ??? TODO: Proper behavior on overflow. */
2132 switch ((ext >> 10) & 7) {
2133 case 0:
2134 opsize = OS_LONG;
2135 res = gen_new_qreg(QMODE_I32);
2136 gen_op_f64_to_i32(res, src);
2137 break;
2138 case 1:
2139 opsize = OS_SINGLE;
2140 res = gen_new_qreg(QMODE_F32);
2141 gen_op_f64_to_f32(res, src);
2142 break;
2143 case 4:
2144 opsize = OS_WORD;
2145 res = gen_new_qreg(QMODE_I32);
2146 gen_op_f64_to_i32(res, src);
2147 break;
2148 case 5:
2149 opsize = OS_DOUBLE;
2150 res = src;
2151 break;
2152 case 6:
2153 opsize = OS_BYTE;
2154 res = gen_new_qreg(QMODE_I32);
2155 gen_op_f64_to_i32(res, src);
2156 break;
2157 default:
2158 goto undef;
2159 }
510ff0b7 2160 DEST_EA(insn, opsize, res, NULL);
e6e5906b
PB
2161 return;
2162 case 4: /* fmove to control register. */
2163 switch ((ext >> 10) & 7) {
2164 case 4: /* FPCR */
2165 /* Not implemented. Ignore writes. */
2166 break;
2167 case 1: /* FPIAR */
2168 case 2: /* FPSR */
2169 default:
2170 cpu_abort(NULL, "Unimplemented: fmove to control %d",
2171 (ext >> 10) & 7);
2172 }
2173 break;
2174 case 5: /* fmove from control register. */
2175 switch ((ext >> 10) & 7) {
2176 case 4: /* FPCR */
2177 /* Not implemented. Always return zero. */
2178 res = gen_im32(0);
2179 break;
2180 case 1: /* FPIAR */
2181 case 2: /* FPSR */
2182 default:
2183 cpu_abort(NULL, "Unimplemented: fmove from control %d",
2184 (ext >> 10) & 7);
2185 goto undef;
2186 }
510ff0b7 2187 DEST_EA(insn, OS_LONG, res, NULL);
e6e5906b
PB
2188 break;
2189 case 6: /* fmovem */
2190 case 7:
2191 {
2192 int addr;
2193 uint16_t mask;
2194 if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
2195 goto undef;
2196 src = gen_lea(s, insn, OS_LONG);
510ff0b7
PB
2197 if (src == -1) {
2198 gen_addr_fault(s);
2199 return;
2200 }
e6e5906b
PB
2201 addr = gen_new_qreg(QMODE_I32);
2202 gen_op_mov32(addr, src);
2203 mask = 0x80;
2204 dest = QREG_F0;
2205 while (mask) {
2206 if (ext & mask) {
2207 if (ext & (1 << 13)) {
2208 /* store */
0633879f 2209 gen_st(s, f64, addr, dest);
e6e5906b
PB
2210 } else {
2211 /* load */
0633879f 2212 gen_ld(s, f64, dest, addr);
e6e5906b
PB
2213 }
2214 if (ext & (mask - 1))
2215 gen_op_add32(addr, addr, gen_im32(8));
2216 }
2217 mask >>= 1;
2218 dest++;
2219 }
2220 }
2221 return;
2222 }
2223 if (ext & (1 << 14)) {
2224 int tmp;
2225
2226 /* Source effective address. */
2227 switch ((ext >> 10) & 7) {
2228 case 0: opsize = OS_LONG; break;
2229 case 1: opsize = OS_SINGLE; break;
2230 case 4: opsize = OS_WORD; break;
2231 case 5: opsize = OS_DOUBLE; break;
2232 case 6: opsize = OS_BYTE; break;
2233 default:
2234 goto undef;
2235 }
510ff0b7 2236 SRC_EA(tmp, opsize, -1, NULL);
e6e5906b
PB
2237 if (opsize == OS_DOUBLE) {
2238 src = tmp;
2239 } else {
2240 src = gen_new_qreg(QMODE_F64);
2241 switch (opsize) {
2242 case OS_LONG:
2243 case OS_WORD:
2244 case OS_BYTE:
2245 gen_op_i32_to_f64(src, tmp);
2246 break;
2247 case OS_SINGLE:
2248 gen_op_f32_to_f64(src, tmp);
2249 break;
2250 }
2251 }
2252 } else {
2253 /* Source register. */
2254 src = FREG(ext, 10);
2255 }
2256 dest = FREG(ext, 7);
2257 res = gen_new_qreg(QMODE_F64);
2258 if (opmode != 0x3a)
2259 gen_op_movf64(res, dest);
2260 round = 1;
2261 switch (opmode) {
2262 case 0: case 0x40: case 0x44: /* fmove */
2263 gen_op_movf64(res, src);
2264 break;
2265 case 1: /* fint */
2266 gen_op_iround_f64(res, src);
2267 round = 0;
2268 break;
2269 case 3: /* fintrz */
2270 gen_op_itrunc_f64(res, src);
2271 round = 0;
2272 break;
2273 case 4: case 0x41: case 0x45: /* fsqrt */
2274 gen_op_sqrtf64(res, src);
2275 break;
2276 case 0x18: case 0x58: case 0x5c: /* fabs */
2277 gen_op_absf64(res, src);
2278 break;
2279 case 0x1a: case 0x5a: case 0x5e: /* fneg */
2280 gen_op_chsf64(res, src);
2281 break;
2282 case 0x20: case 0x60: case 0x64: /* fdiv */
2283 gen_op_divf64(res, res, src);
2284 break;
2285 case 0x22: case 0x62: case 0x66: /* fadd */
2286 gen_op_addf64(res, res, src);
2287 break;
2288 case 0x23: case 0x63: case 0x67: /* fmul */
2289 gen_op_mulf64(res, res, src);
2290 break;
2291 case 0x28: case 0x68: case 0x6c: /* fsub */
2292 gen_op_subf64(res, res, src);
2293 break;
2294 case 0x38: /* fcmp */
2295 gen_op_sub_cmpf64(res, res, src);
2296 dest = 0;
2297 round = 0;
2298 break;
2299 case 0x3a: /* ftst */
2300 gen_op_movf64(res, src);
2301 dest = 0;
2302 round = 0;
2303 break;
2304 default:
2305 goto undef;
2306 }
2307 if (round) {
2308 if (opmode & 0x40) {
2309 if ((opmode & 0x4) != 0)
2310 round = 0;
2311 } else if ((s->fpcr & M68K_FPCR_PREC) == 0) {
2312 round = 0;
2313 }
2314 }
2315 if (round) {
2316 int tmp;
2317
2318 tmp = gen_new_qreg(QMODE_F32);
2319 gen_op_f64_to_f32(tmp, res);
2320 gen_op_f32_to_f64(res, tmp);
2321 }
2322 gen_op_fp_result(res);
2323 if (dest) {
2324 gen_op_movf64(dest, res);
2325 }
2326 return;
2327undef:
2328 s->pc -= 2;
2329 disas_undef_fpu(s, insn);
2330}
2331
2332DISAS_INSN(fbcc)
2333{
2334 uint32_t offset;
2335 uint32_t addr;
2336 int flag;
2337 int zero;
2338 int l1;
2339
2340 addr = s->pc;
0633879f 2341 offset = ldsw_code(s->pc);
e6e5906b
PB
2342 s->pc += 2;
2343 if (insn & (1 << 6)) {
0633879f 2344 offset = (offset << 16) | lduw_code(s->pc);
e6e5906b
PB
2345 s->pc += 2;
2346 }
2347
2348 l1 = gen_new_label();
2349 /* TODO: Raise BSUN exception. */
2350 flag = gen_new_qreg(QMODE_I32);
2351 zero = gen_new_qreg(QMODE_F64);
2352 gen_op_zerof64(zero);
2353 gen_op_compare_quietf64(flag, QREG_FP_RESULT, zero);
2354 /* Jump to l1 if condition is true. */
2355 switch (insn & 0xf) {
2356 case 0: /* f */
2357 break;
2358 case 1: /* eq (=0) */
2359 gen_op_jmp_z32(flag, l1);
2360 break;
2361 case 2: /* ogt (=1) */
2362 gen_op_sub32(flag, flag, gen_im32(1));
2363 gen_op_jmp_z32(flag, l1);
2364 break;
2365 case 3: /* oge (=0 or =1) */
2366 gen_op_jmp_z32(flag, l1);
2367 gen_op_sub32(flag, flag, gen_im32(1));
2368 gen_op_jmp_z32(flag, l1);
2369 break;
2370 case 4: /* olt (=-1) */
2371 gen_op_jmp_s32(flag, l1);
2372 break;
2373 case 5: /* ole (=-1 or =0) */
2374 gen_op_jmp_s32(flag, l1);
2375 gen_op_jmp_z32(flag, l1);
2376 break;
2377 case 6: /* ogl (=-1 or =1) */
2378 gen_op_jmp_s32(flag, l1);
2379 gen_op_sub32(flag, flag, gen_im32(1));
2380 gen_op_jmp_z32(flag, l1);
2381 break;
2382 case 7: /* or (=2) */
2383 gen_op_sub32(flag, flag, gen_im32(2));
2384 gen_op_jmp_z32(flag, l1);
2385 break;
2386 case 8: /* un (<2) */
2387 gen_op_sub32(flag, flag, gen_im32(2));
2388 gen_op_jmp_s32(flag, l1);
2389 break;
2390 case 9: /* ueq (=0 or =2) */
2391 gen_op_jmp_z32(flag, l1);
2392 gen_op_sub32(flag, flag, gen_im32(2));
2393 gen_op_jmp_z32(flag, l1);
2394 break;
2395 case 10: /* ugt (>0) */
2396 /* ??? Add jmp_gtu. */
2397 gen_op_sub32(flag, flag, gen_im32(1));
2398 gen_op_jmp_ns32(flag, l1);
2399 break;
2400 case 11: /* uge (>=0) */
2401 gen_op_jmp_ns32(flag, l1);
2402 break;
2403 case 12: /* ult (=-1 or =2) */
2404 gen_op_jmp_s32(flag, l1);
2405 gen_op_sub32(flag, flag, gen_im32(2));
2406 gen_op_jmp_z32(flag, l1);
2407 break;
2408 case 13: /* ule (!=1) */
2409 gen_op_sub32(flag, flag, gen_im32(1));
2410 gen_op_jmp_nz32(flag, l1);
2411 break;
2412 case 14: /* ne (!=0) */
2413 gen_op_jmp_nz32(flag, l1);
2414 break;
2415 case 15: /* t */
2416 gen_op_mov32(flag, gen_im32(1));
2417 break;
2418 }
2419 gen_jmp_tb(s, 0, s->pc);
2420 gen_set_label(l1);
2421 gen_jmp_tb(s, 1, addr + offset);
2422}
2423
0633879f
PB
2424DISAS_INSN(frestore)
2425{
2426 /* TODO: Implement frestore. */
2427 qemu_assert(0, "FRESTORE not implemented");
2428}
2429
2430DISAS_INSN(fsave)
2431{
2432 /* TODO: Implement fsave. */
2433 qemu_assert(0, "FSAVE not implemented");
2434}
2435
acf930aa
PB
2436static inline int gen_mac_extract_word(DisasContext *s, int val, int upper)
2437{
2438 int tmp = gen_new_qreg(QMODE_I32);
2439 if (s->env->macsr & MACSR_FI) {
2440 if (upper)
2441 gen_op_and32(tmp, val, gen_im32(0xffff0000));
2442 else
2443 gen_op_shl32(tmp, val, gen_im32(16));
2444 } else if (s->env->macsr & MACSR_SU) {
2445 if (upper)
2446 gen_op_sar32(tmp, val, gen_im32(16));
2447 else
2448 gen_op_ext16s32(tmp, val);
2449 } else {
2450 if (upper)
2451 gen_op_shr32(tmp, val, gen_im32(16));
2452 else
2453 gen_op_ext16u32(tmp, val);
2454 }
2455 return tmp;
2456}
2457
2458DISAS_INSN(mac)
2459{
2460 int rx;
2461 int ry;
2462 uint16_t ext;
2463 int acc;
2464 int l1;
2465 int tmp;
2466 int addr;
2467 int loadval;
2468 int dual;
2469 int saved_flags = -1;
2470
2471 ext = lduw_code(s->pc);
2472 s->pc += 2;
2473
2474 acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
2475 dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
d315c888
PB
2476 if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
2477 disas_undef(s, insn);
2478 return;
2479 }
acf930aa
PB
2480 if (insn & 0x30) {
2481 /* MAC with load. */
2482 tmp = gen_lea(s, insn, OS_LONG);
2483 addr = gen_new_qreg(QMODE_I32);
2484 gen_op_and32(addr, tmp, QREG_MAC_MASK);
2485 /* Load the value now to ensure correct exception behavior.
2486 Perform writeback after reading the MAC inputs. */
2487 loadval = gen_load(s, OS_LONG, addr, 0);
2488
2489 acc ^= 1;
2490 rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
2491 ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
2492 } else {
2493 loadval = addr = -1;
2494 rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
2495 ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
2496 }
2497
2498 gen_op_mac_clear_flags();
2499 l1 = -1;
2500 if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
2501 /* Skip the multiply if we know we will ignore it. */
2502 l1 = gen_new_label();
2503 tmp = gen_new_qreg(QMODE_I32);
2504 gen_op_and32(tmp, QREG_MACSR, gen_im32(1 << (acc + 8)));
2505 gen_op_jmp_nz32(tmp, l1);
2506 }
2507
2508 if ((ext & 0x0800) == 0) {
2509 /* Word. */
2510 rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
2511 ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
2512 }
2513 if (s->env->macsr & MACSR_FI) {
2514 gen_op_macmulf(rx, ry);
2515 } else {
2516 if (s->env->macsr & MACSR_SU)
2517 gen_op_macmuls(rx, ry);
2518 else
2519 gen_op_macmulu(rx, ry);
2520 switch ((ext >> 9) & 3) {
2521 case 1:
2522 gen_op_macshl();
2523 break;
2524 case 3:
2525 gen_op_macshr();
2526 break;
2527 }
2528 }
2529
2530 if (dual) {
2531 /* Save the overflow flag from the multiply. */
2532 saved_flags = gen_new_qreg(QMODE_I32);
2533 gen_op_mov32(saved_flags, QREG_MACSR);
2534 }
2535
2536 if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
2537 /* Skip the accumulate if the value is already saturated. */
2538 l1 = gen_new_label();
2539 tmp = gen_new_qreg(QMODE_I32);
2540 gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
2541 gen_op_jmp_nz32(tmp, l1);
2542 }
2543
2544 if (insn & 0x100)
2545 gen_op_macsub(acc);
2546 else
2547 gen_op_macadd(acc);
2548
2549 if (s->env->macsr & MACSR_FI)
2550 gen_op_macsatf(acc);
2551 else if (s->env->macsr & MACSR_SU)
2552 gen_op_macsats(acc);
2553 else
2554 gen_op_macsatu(acc);
2555
2556 if (l1 != -1)
2557 gen_set_label(l1);
2558
2559 if (dual) {
2560 /* Dual accumulate variant. */
2561 acc = (ext >> 2) & 3;
2562 /* Restore the overflow flag from the multiplier. */
2563 gen_op_mov32(QREG_MACSR, saved_flags);
2564 if ((s->env->macsr & MACSR_OMC) != 0) {
2565 /* Skip the accumulate if the value is already saturated. */
2566 l1 = gen_new_label();
2567 tmp = gen_new_qreg(QMODE_I32);
2568 gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
2569 gen_op_jmp_nz32(tmp, l1);
2570 }
2571 if (ext & 2)
2572 gen_op_macsub(acc);
2573 else
2574 gen_op_macadd(acc);
2575 if (s->env->macsr & MACSR_FI)
2576 gen_op_macsatf(acc);
2577 else if (s->env->macsr & MACSR_SU)
2578 gen_op_macsats(acc);
2579 else
2580 gen_op_macsatu(acc);
2581 if (l1 != -1)
2582 gen_set_label(l1);
2583 }
2584 gen_op_mac_set_flags(acc);
2585
2586 if (insn & 0x30) {
2587 int rw;
2588 rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
2589 gen_op_mov32(rw, loadval);
2590 /* FIXME: Should address writeback happen with the masked or
2591 unmasked value? */
2592 switch ((insn >> 3) & 7) {
2593 case 3: /* Post-increment. */
2594 gen_op_add32(AREG(insn, 0), addr, gen_im32(4));
2595 break;
2596 case 4: /* Pre-decrement. */
2597 gen_op_mov32(AREG(insn, 0), addr);
2598 }
2599 }
2600}
2601
2602DISAS_INSN(from_mac)
2603{
2604 int rx;
2605 int acc;
2606
2607 rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
2608 acc = (insn >> 9) & 3;
2609 if (s->env->macsr & MACSR_FI) {
2610 gen_op_get_macf(rx, acc);
2611 } else if ((s->env->macsr & MACSR_OMC) == 0) {
2612 gen_op_get_maci(rx, acc);
2613 } else if (s->env->macsr & MACSR_SU) {
2614 gen_op_get_macs(rx, acc);
2615 } else {
2616 gen_op_get_macu(rx, acc);
2617 }
2618 if (insn & 0x40)
2619 gen_op_clear_mac(acc);
2620}
2621
2622DISAS_INSN(move_mac)
2623{
2624 int src;
2625 int dest;
2626 src = insn & 3;
2627 dest = (insn >> 9) & 3;
2628 gen_op_move_mac(dest, src);
2629 gen_op_mac_clear_flags();
2630 gen_op_mac_set_flags(dest);
2631}
2632
2633DISAS_INSN(from_macsr)
2634{
2635 int reg;
2636
2637 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
2638 gen_op_mov32(reg, QREG_MACSR);
2639}
2640
2641DISAS_INSN(from_mask)
2642{
2643 int reg;
2644 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
2645 gen_op_mov32(reg, QREG_MAC_MASK);
2646}
2647
2648DISAS_INSN(from_mext)
2649{
2650 int reg;
2651 int acc;
2652 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
2653 acc = (insn & 0x400) ? 2 : 0;
2654 if (s->env->macsr & MACSR_FI)
2655 gen_op_get_mac_extf(reg, acc);
2656 else
2657 gen_op_get_mac_exti(reg, acc);
2658}
2659
2660DISAS_INSN(macsr_to_ccr)
2661{
2662 gen_op_mov32(QREG_CC_X, gen_im32(0));
2663 gen_op_and32(QREG_CC_DEST, QREG_MACSR, gen_im32(0xf));
2664 s->cc_op = CC_OP_FLAGS;
2665}
2666
2667DISAS_INSN(to_mac)
2668{
2669 int acc;
2670 int val;
2671 acc = (insn >>9) & 3;
2672 SRC_EA(val, OS_LONG, 0, NULL);
2673 if (s->env->macsr & MACSR_FI) {
2674 gen_op_set_macf(val, acc);
2675 } else if (s->env->macsr & MACSR_SU) {
2676 gen_op_set_macs(val, acc);
2677 } else {
2678 gen_op_set_macu(val, acc);
2679 }
2680 gen_op_mac_clear_flags();
2681 gen_op_mac_set_flags(acc);
2682}
2683
2684DISAS_INSN(to_macsr)
2685{
2686 int val;
2687 SRC_EA(val, OS_LONG, 0, NULL);
2688 gen_op_set_macsr(val);
2689 gen_lookup_tb(s);
2690}
2691
2692DISAS_INSN(to_mask)
2693{
2694 int val;
2695 SRC_EA(val, OS_LONG, 0, NULL);
2696 gen_op_or32(QREG_MAC_MASK, val, gen_im32(0xffff0000));
2697}
2698
2699DISAS_INSN(to_mext)
2700{
2701 int val;
2702 int acc;
2703 SRC_EA(val, OS_LONG, 0, NULL);
2704 acc = (insn & 0x400) ? 2 : 0;
2705 if (s->env->macsr & MACSR_FI)
2706 gen_op_set_mac_extf(val, acc);
2707 else if (s->env->macsr & MACSR_SU)
2708 gen_op_set_mac_exts(val, acc);
2709 else
2710 gen_op_set_mac_extu(val, acc);
2711}
2712
e6e5906b
PB
2713static disas_proc opcode_table[65536];
2714
2715static void
2716register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
2717{
2718 int i;
2719 int from;
2720 int to;
2721
2722 /* Sanity check. All set bits must be included in the mask. */
5fc4adf6
PB
2723 if (opcode & ~mask) {
2724 fprintf(stderr,
2725 "qemu internal error: bogus opcode definition %04x/%04x\n",
2726 opcode, mask);
e6e5906b 2727 abort();
5fc4adf6 2728 }
e6e5906b
PB
2729 /* This could probably be cleverer. For now just optimize the case where
2730 the top bits are known. */
2731 /* Find the first zero bit in the mask. */
2732 i = 0x8000;
2733 while ((i & mask) != 0)
2734 i >>= 1;
2735 /* Iterate over all combinations of this and lower bits. */
2736 if (i == 0)
2737 i = 1;
2738 else
2739 i <<= 1;
2740 from = opcode & ~(i - 1);
2741 to = from + i;
0633879f 2742 for (i = from; i < to; i++) {
e6e5906b
PB
2743 if ((i & mask) == opcode)
2744 opcode_table[i] = proc;
0633879f 2745 }
e6e5906b
PB
2746}
2747
2748/* Register m68k opcode handlers. Order is important.
2749 Later insn override earlier ones. */
0402f767 2750void register_m68k_insns (CPUM68KState *env)
e6e5906b 2751{
d315c888 2752#define INSN(name, opcode, mask, feature) do { \
0402f767 2753 if (m68k_feature(env, M68K_FEATURE_##feature)) \
d315c888
PB
2754 register_opcode(disas_##name, 0x##opcode, 0x##mask); \
2755 } while(0)
0402f767
PB
2756 INSN(undef, 0000, 0000, CF_ISA_A);
2757 INSN(arith_im, 0080, fff8, CF_ISA_A);
d315c888 2758 INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC);
0402f767
PB
2759 INSN(bitop_reg, 0100, f1c0, CF_ISA_A);
2760 INSN(bitop_reg, 0140, f1c0, CF_ISA_A);
2761 INSN(bitop_reg, 0180, f1c0, CF_ISA_A);
2762 INSN(bitop_reg, 01c0, f1c0, CF_ISA_A);
2763 INSN(arith_im, 0280, fff8, CF_ISA_A);
d315c888 2764 INSN(byterev, 02c0, fff8, CF_ISA_APLUSC);
0402f767 2765 INSN(arith_im, 0480, fff8, CF_ISA_A);
d315c888 2766 INSN(ff1, 04c0, fff8, CF_ISA_APLUSC);
0402f767
PB
2767 INSN(arith_im, 0680, fff8, CF_ISA_A);
2768 INSN(bitop_im, 0800, ffc0, CF_ISA_A);
2769 INSN(bitop_im, 0840, ffc0, CF_ISA_A);
2770 INSN(bitop_im, 0880, ffc0, CF_ISA_A);
2771 INSN(bitop_im, 08c0, ffc0, CF_ISA_A);
2772 INSN(arith_im, 0a80, fff8, CF_ISA_A);
2773 INSN(arith_im, 0c00, ff38, CF_ISA_A);
2774 INSN(move, 1000, f000, CF_ISA_A);
2775 INSN(move, 2000, f000, CF_ISA_A);
2776 INSN(move, 3000, f000, CF_ISA_A);
d315c888 2777 INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
0402f767
PB
2778 INSN(negx, 4080, fff8, CF_ISA_A);
2779 INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
2780 INSN(lea, 41c0, f1c0, CF_ISA_A);
2781 INSN(clr, 4200, ff00, CF_ISA_A);
2782 INSN(undef, 42c0, ffc0, CF_ISA_A);
2783 INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
2784 INSN(neg, 4480, fff8, CF_ISA_A);
2785 INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A);
2786 INSN(not, 4680, fff8, CF_ISA_A);
2787 INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
2788 INSN(pea, 4840, ffc0, CF_ISA_A);
2789 INSN(swap, 4840, fff8, CF_ISA_A);
2790 INSN(movem, 48c0, fbc0, CF_ISA_A);
2791 INSN(ext, 4880, fff8, CF_ISA_A);
2792 INSN(ext, 48c0, fff8, CF_ISA_A);
2793 INSN(ext, 49c0, fff8, CF_ISA_A);
2794 INSN(tst, 4a00, ff00, CF_ISA_A);
2795 INSN(tas, 4ac0, ffc0, CF_ISA_B);
2796 INSN(halt, 4ac8, ffff, CF_ISA_A);
2797 INSN(pulse, 4acc, ffff, CF_ISA_A);
2798 INSN(illegal, 4afc, ffff, CF_ISA_A);
2799 INSN(mull, 4c00, ffc0, CF_ISA_A);
2800 INSN(divl, 4c40, ffc0, CF_ISA_A);
2801 INSN(sats, 4c80, fff8, CF_ISA_B);
2802 INSN(trap, 4e40, fff0, CF_ISA_A);
2803 INSN(link, 4e50, fff8, CF_ISA_A);
2804 INSN(unlk, 4e58, fff8, CF_ISA_A);
20dcee94
PB
2805 INSN(move_to_usp, 4e60, fff8, USP);
2806 INSN(move_from_usp, 4e68, fff8, USP);
0402f767
PB
2807 INSN(nop, 4e71, ffff, CF_ISA_A);
2808 INSN(stop, 4e72, ffff, CF_ISA_A);
2809 INSN(rte, 4e73, ffff, CF_ISA_A);
2810 INSN(rts, 4e75, ffff, CF_ISA_A);
2811 INSN(movec, 4e7b, ffff, CF_ISA_A);
2812 INSN(jump, 4e80, ffc0, CF_ISA_A);
2813 INSN(jump, 4ec0, ffc0, CF_ISA_A);
2814 INSN(addsubq, 5180, f1c0, CF_ISA_A);
2815 INSN(scc, 50c0, f0f8, CF_ISA_A);
2816 INSN(addsubq, 5080, f1c0, CF_ISA_A);
2817 INSN(tpf, 51f8, fff8, CF_ISA_A);
d315c888
PB
2818
2819 /* Branch instructions. */
0402f767 2820 INSN(branch, 6000, f000, CF_ISA_A);
d315c888
PB
2821 /* Disable long branch instructions, then add back the ones we want. */
2822 INSN(undef, 60ff, f0ff, CF_ISA_A); /* All long branches. */
2823 INSN(branch, 60ff, f0ff, CF_ISA_B);
2824 INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */
2825 INSN(branch, 60ff, ffff, BRAL);
2826
0402f767
PB
2827 INSN(moveq, 7000, f100, CF_ISA_A);
2828 INSN(mvzs, 7100, f100, CF_ISA_B);
2829 INSN(or, 8000, f000, CF_ISA_A);
2830 INSN(divw, 80c0, f0c0, CF_ISA_A);
2831 INSN(addsub, 9000, f000, CF_ISA_A);
2832 INSN(subx, 9180, f1f8, CF_ISA_A);
2833 INSN(suba, 91c0, f1c0, CF_ISA_A);
acf930aa 2834
0402f767 2835 INSN(undef_mac, a000, f000, CF_ISA_A);
acf930aa
PB
2836 INSN(mac, a000, f100, CF_EMAC);
2837 INSN(from_mac, a180, f9b0, CF_EMAC);
2838 INSN(move_mac, a110, f9fc, CF_EMAC);
2839 INSN(from_macsr,a980, f9f0, CF_EMAC);
2840 INSN(from_mask, ad80, fff0, CF_EMAC);
2841 INSN(from_mext, ab80, fbf0, CF_EMAC);
2842 INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
2843 INSN(to_mac, a100, f9c0, CF_EMAC);
2844 INSN(to_macsr, a900, ffc0, CF_EMAC);
2845 INSN(to_mext, ab00, fbc0, CF_EMAC);
2846 INSN(to_mask, ad00, ffc0, CF_EMAC);
2847
0402f767
PB
2848 INSN(mov3q, a140, f1c0, CF_ISA_B);
2849 INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */
2850 INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */
2851 INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */
2852 INSN(cmp, b080, f1c0, CF_ISA_A);
2853 INSN(cmpa, b1c0, f1c0, CF_ISA_A);
2854 INSN(eor, b180, f1c0, CF_ISA_A);
2855 INSN(and, c000, f000, CF_ISA_A);
2856 INSN(mulw, c0c0, f0c0, CF_ISA_A);
2857 INSN(addsub, d000, f000, CF_ISA_A);
2858 INSN(addx, d180, f1f8, CF_ISA_A);
2859 INSN(adda, d1c0, f1c0, CF_ISA_A);
2860 INSN(shift_im, e080, f0f0, CF_ISA_A);
2861 INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
2862 INSN(undef_fpu, f000, f000, CF_ISA_A);
e6e5906b
PB
2863 INSN(fpu, f200, ffc0, CF_FPU);
2864 INSN(fbcc, f280, ffc0, CF_FPU);
0633879f
PB
2865 INSN(frestore, f340, ffc0, CF_FPU);
2866 INSN(fsave, f340, ffc0, CF_FPU);
0402f767
PB
2867 INSN(intouch, f340, ffc0, CF_ISA_A);
2868 INSN(cpushl, f428, ff38, CF_ISA_A);
2869 INSN(wddata, fb00, ff00, CF_ISA_A);
2870 INSN(wdebug, fbc0, ffc0, CF_ISA_A);
e6e5906b
PB
2871#undef INSN
2872}
2873
2874/* ??? Some of this implementation is not exception safe. We should always
2875 write back the result to memory before setting the condition codes. */
2876static void disas_m68k_insn(CPUState * env, DisasContext *s)
2877{
2878 uint16_t insn;
2879
0633879f 2880 insn = lduw_code(s->pc);
e6e5906b
PB
2881 s->pc += 2;
2882
2883 opcode_table[insn](s, insn);
2884}
2885
2886#if 0
2887/* Save the result of a floating point operation. */
2888static void expand_op_fp_result(qOP *qop)
2889{
2890 gen_op_movf64(QREG_FP_RESULT, qop->args[0]);
2891}
2892
2893/* Dummy op to indicate that the flags have been set. */
2894static void expand_op_flags_set(qOP *qop)
2895{
2896}
2897
2898/* Convert the confition codes into CC_OP_FLAGS format. */
2899static void expand_op_flush_flags(qOP *qop)
2900{
2901 int cc_opreg;
2902
2903 if (qop->args[0] == CC_OP_DYNAMIC)
2904 cc_opreg = QREG_CC_OP;
2905 else
2906 cc_opreg = gen_im32(qop->args[0]);
2907 gen_op_helper32(QREG_NULL, cc_opreg, HELPER_flush_flags);
2908}
2909
2910/* Set CC_DEST after a logical or direct flag setting operation. */
2911static void expand_op_logic_cc(qOP *qop)
2912{
2913 gen_op_mov32(QREG_CC_DEST, qop->args[0]);
2914}
2915
2916/* Set CC_SRC and CC_DEST after an arithmetic operation. */
2917static void expand_op_update_cc_add(qOP *qop)
2918{
2919 gen_op_mov32(QREG_CC_DEST, qop->args[0]);
2920 gen_op_mov32(QREG_CC_SRC, qop->args[1]);
2921}
2922
2923/* Update the X flag. */
2924static void expand_op_update_xflag(qOP *qop)
2925{
2926 int arg0;
2927 int arg1;
2928
2929 arg0 = qop->args[0];
2930 arg1 = qop->args[1];
2931 if (arg1 == QREG_NULL) {
2932 /* CC_X = arg0. */
2933 gen_op_mov32(QREG_CC_X, arg0);
2934 } else {
2935 /* CC_X = arg0 < (unsigned)arg1. */
2936 gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
2937 }
2938}
2939
2940/* Set arg0 to the contents of the X flag. */
2941static void expand_op_get_xflag(qOP *qop)
2942{
2943 gen_op_mov32(qop->args[0], QREG_CC_X);
2944}
2945
2946/* Expand a shift by immediate. The ISA only allows shifts by 1-8, so we
2947 already know the shift is within range. */
2948static inline void expand_shift_im(qOP *qop, int right, int arith)
2949{
2950 int val;
2951 int reg;
2952 int tmp;
2953 int im;
2954
2955 reg = qop->args[0];
2956 im = qop->args[1];
2957 tmp = gen_im32(im);
2958 val = gen_new_qreg(QMODE_I32);
2959 gen_op_mov32(val, reg);
2960 gen_op_mov32(QREG_CC_DEST, val);
2961 gen_op_mov32(QREG_CC_SRC, tmp);
2962 if (right) {
2963 if (arith) {
2964 gen_op_sar32(reg, val, tmp);
2965 } else {
2966 gen_op_shr32(reg, val, tmp);
2967 }
2968 if (im == 1)
2969 tmp = QREG_NULL;
2970 else
2971 tmp = gen_im32(im - 1);
2972 } else {
2973 gen_op_shl32(reg, val, tmp);
2974 tmp = gen_im32(32 - im);
2975 }
2976 if (tmp != QREG_NULL)
2977 gen_op_shr32(val, val, tmp);
2978 gen_op_and32(QREG_CC_X, val, gen_im32(1));
2979}
2980
2981static void expand_op_shl_im_cc(qOP *qop)
2982{
2983 expand_shift_im(qop, 0, 0);
2984}
2985
2986static void expand_op_shr_im_cc(qOP *qop)
2987{
2988 expand_shift_im(qop, 1, 0);
2989}
2990
2991static void expand_op_sar_im_cc(qOP *qop)
2992{
2993 expand_shift_im(qop, 1, 1);
2994}
2995
2996/* Expand a shift by register. */
2997/* ??? This gives incorrect answers for shifts by 0 or >= 32 */
2998static inline void expand_shift_reg(qOP *qop, int right, int arith)
2999{
3000 int val;
3001 int reg;
3002 int shift;
3003 int tmp;
3004
3005 reg = qop->args[0];
3006 shift = qop->args[1];
3007 val = gen_new_qreg(QMODE_I32);
3008 gen_op_mov32(val, reg);
3009 gen_op_mov32(QREG_CC_DEST, val);
3010 gen_op_mov32(QREG_CC_SRC, shift);
3011 tmp = gen_new_qreg(QMODE_I32);
3012 if (right) {
3013 if (arith) {
3014 gen_op_sar32(reg, val, shift);
3015 } else {
3016 gen_op_shr32(reg, val, shift);
3017 }
3018 gen_op_sub32(tmp, shift, gen_im32(1));
3019 } else {
3020 gen_op_shl32(reg, val, shift);
3021 gen_op_sub32(tmp, gen_im32(31), shift);
3022 }
3023 gen_op_shl32(val, val, tmp);
3024 gen_op_and32(QREG_CC_X, val, gen_im32(1));
3025}
3026
3027static void expand_op_shl_cc(qOP *qop)
3028{
3029 expand_shift_reg(qop, 0, 0);
3030}
3031
3032static void expand_op_shr_cc(qOP *qop)
3033{
3034 expand_shift_reg(qop, 1, 0);
3035}
3036
3037static void expand_op_sar_cc(qOP *qop)
3038{
3039 expand_shift_reg(qop, 1, 1);
3040}
3041
3042/* Set the Z flag to (arg0 & arg1) == 0. */
3043static void expand_op_btest(qOP *qop)
3044{
3045 int tmp;
3046 int l1;
3047
3048 l1 = gen_new_label();
3049 tmp = gen_new_qreg(QMODE_I32);
3050 gen_op_and32(tmp, qop->args[0], qop->args[1]);
3051 gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(~(uint32_t)CCF_Z));
3052 gen_op_jmp_nz32(tmp, l1);
3053 gen_op_or32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(CCF_Z));
3054 gen_op_label(l1);
3055}
3056
3057/* arg0 += arg1 + CC_X */
3058static void expand_op_addx_cc(qOP *qop)
3059{
3060 int arg0 = qop->args[0];
3061 int arg1 = qop->args[1];
3062 int l1, l2;
3063
3064 gen_op_add32 (arg0, arg0, arg1);
3065 l1 = gen_new_label();
3066 l2 = gen_new_label();
3067 gen_op_jmp_z32(QREG_CC_X, l1);
3068 gen_op_add32(arg0, arg0, gen_im32(1));
3069 gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADDX));
3070 gen_op_set_leu32(QREG_CC_X, arg0, arg1);
3071 gen_op_jmp(l2);
3072 gen_set_label(l1);
3073 gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADD));
3074 gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
3075 gen_set_label(l2);
3076}
3077
3078/* arg0 -= arg1 + CC_X */
3079static void expand_op_subx_cc(qOP *qop)
3080{
3081 int arg0 = qop->args[0];
3082 int arg1 = qop->args[1];
3083 int l1, l2;
3084
3085 l1 = gen_new_label();
3086 l2 = gen_new_label();
3087 gen_op_jmp_z32(QREG_CC_X, l1);
3088 gen_op_set_leu32(QREG_CC_X, arg0, arg1);
3089 gen_op_sub32(arg0, arg0, gen_im32(1));
3090 gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUBX));
3091 gen_op_jmp(l2);
3092 gen_set_label(l1);
3093 gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
3094 gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUB));
3095 gen_set_label(l2);
3096 gen_op_sub32 (arg0, arg0, arg1);
3097}
3098
3099/* Expand target specific ops to generic qops. */
3100static void expand_target_qops(void)
3101{
3102 qOP *qop;
3103 qOP *next;
3104 int c;
3105
3106 /* Copy the list of qops, expanding target specific ops as we go. */
3107 qop = gen_first_qop;
3108 gen_first_qop = NULL;
3109 gen_last_qop = NULL;
3110 for (; qop; qop = next) {
3111 c = qop->opcode;
3112 next = qop->next;
3113 if (c < FIRST_TARGET_OP) {
3114 qop->prev = gen_last_qop;
3115 qop->next = NULL;
3116 if (gen_last_qop)
3117 gen_last_qop->next = qop;
3118 else
3119 gen_first_qop = qop;
3120 gen_last_qop = qop;
3121 continue;
3122 }
3123 switch (c) {
3124#define DEF(name, nargs, barrier) \
3125 case INDEX_op_##name: \
3126 expand_op_##name(qop); \
3127 break;
3128#include "qop-target.def"
3129#undef DEF
3130 default:
3131 cpu_abort(NULL, "Unexpanded target qop");
3132 }
3133 }
3134}
3135
3136/* ??? Implement this. */
3137static void
3138optimize_flags(void)
3139{
3140}
3141#endif
3142
3143/* generate intermediate code for basic block 'tb'. */
820e00f2
TS
3144static inline int
3145gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
3146 int search_pc)
e6e5906b
PB
3147{
3148 DisasContext dc1, *dc = &dc1;
3149 uint16_t *gen_opc_end;
3150 int j, lj;
3151 target_ulong pc_start;
3152 int pc_offset;
3153 int last_cc_op;
3154
3155 /* generate intermediate code */
3156 pc_start = tb->pc;
3157
3158 dc->tb = tb;
3159
3160 gen_opc_ptr = gen_opc_buf;
3161 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3162 gen_opparam_ptr = gen_opparam_buf;
3163
e6dbd3b3 3164 dc->env = env;
e6e5906b
PB
3165 dc->is_jmp = DISAS_NEXT;
3166 dc->pc = pc_start;
3167 dc->cc_op = CC_OP_DYNAMIC;
3168 dc->singlestep_enabled = env->singlestep_enabled;
3169 dc->fpcr = env->fpcr;
0633879f 3170 dc->user = (env->sr & SR_S) == 0;
e6e5906b
PB
3171 nb_gen_labels = 0;
3172 lj = -1;
3173 do {
3174 free_qreg = 0;
3175 pc_offset = dc->pc - pc_start;
3176 gen_throws_exception = NULL;
3177 if (env->nb_breakpoints > 0) {
3178 for(j = 0; j < env->nb_breakpoints; j++) {
3179 if (env->breakpoints[j] == dc->pc) {
3180 gen_exception(dc, dc->pc, EXCP_DEBUG);
3181 dc->is_jmp = DISAS_JUMP;
3182 break;
3183 }
3184 }
3185 if (dc->is_jmp)
3186 break;
3187 }
3188 if (search_pc) {
3189 j = gen_opc_ptr - gen_opc_buf;
3190 if (lj < j) {
3191 lj++;
3192 while (lj < j)
3193 gen_opc_instr_start[lj++] = 0;
3194 }
3195 gen_opc_pc[lj] = dc->pc;
3196 gen_opc_instr_start[lj] = 1;
3197 }
3198 last_cc_op = dc->cc_op;
510ff0b7 3199 dc->insn_pc = dc->pc;
e6e5906b
PB
3200 disas_m68k_insn(env, dc);
3201 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
3202 !env->singlestep_enabled &&
3203 (pc_offset) < (TARGET_PAGE_SIZE - 32));
3204
3205 if (__builtin_expect(env->singlestep_enabled, 0)) {
3206 /* Make sure the pc is updated, and raise a debug exception. */
3207 if (!dc->is_jmp) {
3208 gen_flush_cc_op(dc);
3209 gen_op_mov32(QREG_PC, gen_im32((long)dc->pc));
3210 }
3211 gen_op_raise_exception(EXCP_DEBUG);
3212 } else {
3213 switch(dc->is_jmp) {
3214 case DISAS_NEXT:
3215 gen_flush_cc_op(dc);
3216 gen_jmp_tb(dc, 0, dc->pc);
3217 break;
3218 default:
3219 case DISAS_JUMP:
3220 case DISAS_UPDATE:
3221 gen_flush_cc_op(dc);
3222 /* indicate that the hash table must be used to find the next TB */
3223 gen_op_mov32(QREG_T0, gen_im32(0));
3224 gen_op_exit_tb();
3225 break;
3226 case DISAS_TB_JUMP:
3227 /* nothing more to generate */
3228 break;
3229 }
3230 }
3231 *gen_opc_ptr = INDEX_op_end;
3232
3233#ifdef DEBUG_DISAS
3234 if (loglevel & CPU_LOG_TB_IN_ASM) {
3235 fprintf(logfile, "----------------\n");
3236 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
3237 target_disas(logfile, pc_start, dc->pc - pc_start, 0);
3238 fprintf(logfile, "\n");
3239 if (loglevel & (CPU_LOG_TB_OP)) {
3240 fprintf(logfile, "OP:\n");
3241 dump_ops(gen_opc_buf, gen_opparam_buf);
3242 fprintf(logfile, "\n");
3243 }
3244 }
3245#endif
3246 if (search_pc) {
3247 j = gen_opc_ptr - gen_opc_buf;
3248 lj++;
3249 while (lj <= j)
3250 gen_opc_instr_start[lj++] = 0;
3251 tb->size = 0;
3252 } else {
3253 tb->size = dc->pc - pc_start;
3254 }
3255
3256 //optimize_flags();
3257 //expand_target_qops();
3258 return 0;
3259}
3260
3261int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
3262{
3263 return gen_intermediate_code_internal(env, tb, 0);
3264}
3265
3266int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
3267{
3268 return gen_intermediate_code_internal(env, tb, 1);
3269}
3270
0633879f
PB
3271void cpu_reset(CPUM68KState *env)
3272{
3273 memset(env, 0, offsetof(CPUM68KState, breakpoints));
3274#if !defined (CONFIG_USER_ONLY)
3275 env->sr = 0x2700;
3276#endif
20dcee94 3277 m68k_switch_sp(env);
0633879f
PB
3278 /* ??? FP regs should be initialized to NaN. */
3279 env->cc_op = CC_OP_FLAGS;
3280 /* TODO: We should set PC from the interrupt vector. */
3281 env->pc = 0;
3282 tlb_flush(env, 1);
3283}
3284
e6e5906b
PB
3285CPUM68KState *cpu_m68k_init(void)
3286{
3287 CPUM68KState *env;
3288
3289 env = malloc(sizeof(CPUM68KState));
3290 if (!env)
3291 return NULL;
3292 cpu_exec_init(env);
3293
0633879f 3294 cpu_reset(env);
e6e5906b
PB
3295 return env;
3296}
3297
3298void cpu_m68k_close(CPUM68KState *env)
3299{
3300 free(env);
3301}
3302
e6e5906b
PB
3303void cpu_dump_state(CPUState *env, FILE *f,
3304 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
3305 int flags)
3306{
3307 int i;
3308 uint16_t sr;
3309 CPU_DoubleU u;
3310 for (i = 0; i < 8; i++)
3311 {
3312 u.d = env->fregs[i];
3313 cpu_fprintf (f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n",
3314 i, env->dregs[i], i, env->aregs[i],
3315 i, u.l.upper, u.l.lower, u.d);
3316 }
3317 cpu_fprintf (f, "PC = %08x ", env->pc);
3318 sr = env->sr;
3319 cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & 0x10) ? 'X' : '-',
3320 (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-',
3321 (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-');
3322 cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result);
3323}
3324