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