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