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