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