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