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