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