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