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