]> Git Repo - qemu.git/blame - target/m68k/translate.c
target-m68k: Do not cpu_abort on undefined insns
[qemu.git] / target / m68k / translate.c
CommitLineData
e6e5906b
PB
1/*
2 * m68k translation
5fafdf24 3 *
0633879f 4 * Copyright (c) 2005-2007 CodeSourcery
e6e5906b
PB
5 * Written by Paul Brook
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
8167ee88 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
e6e5906b 19 */
e6e5906b 20
d8416665 21#include "qemu/osdep.h"
e6e5906b 22#include "cpu.h"
76cad711 23#include "disas/disas.h"
63c91552 24#include "exec/exec-all.h"
57fec1fe 25#include "tcg-op.h"
1de7afc9 26#include "qemu/log.h"
f08b6170 27#include "exec/cpu_ldst.h"
e1f3808e 28
2ef6175a
RH
29#include "exec/helper-proto.h"
30#include "exec/helper-gen.h"
e6e5906b 31
a7e30d84 32#include "trace-tcg.h"
508127e2 33#include "exec/log.h"
a7e30d84
LV
34
35
0633879f
PB
36//#define DEBUG_DISPATCH 1
37
815a6742 38/* Fake floating point. */
815a6742 39#define tcg_gen_mov_f64 tcg_gen_mov_i64
815a6742 40#define tcg_gen_qemu_ldf64 tcg_gen_qemu_ld64
815a6742 41#define tcg_gen_qemu_stf64 tcg_gen_qemu_st64
815a6742 42
e1f3808e 43#define DEFO32(name, offset) static TCGv QREG_##name;
a7812ae4
PB
44#define DEFO64(name, offset) static TCGv_i64 QREG_##name;
45#define DEFF64(name, offset) static TCGv_i64 QREG_##name;
e1f3808e
PB
46#include "qregs.def"
47#undef DEFO32
48#undef DEFO64
49#undef DEFF64
50
259186a7 51static TCGv_i32 cpu_halted;
27103424 52static TCGv_i32 cpu_exception_index;
259186a7 53
1bcea73e 54static TCGv_env cpu_env;
e1f3808e
PB
55
56static char cpu_reg_names[3*8*3 + 5*4];
57static TCGv cpu_dregs[8];
58static TCGv cpu_aregs[8];
a7812ae4
PB
59static TCGv_i64 cpu_fregs[8];
60static TCGv_i64 cpu_macc[4];
e1f3808e 61
8a1e52b6 62#define REG(insn, pos) (((insn) >> (pos)) & 7)
bcc098b0 63#define DREG(insn, pos) cpu_dregs[REG(insn, pos)]
8a1e52b6 64#define AREG(insn, pos) get_areg(s, REG(insn, pos))
bcc098b0 65#define FREG(insn, pos) cpu_fregs[REG(insn, pos)]
8a1e52b6
RH
66#define MACREG(acc) cpu_macc[acc]
67#define QREG_SP get_areg(s, 7)
e1f3808e
PB
68
69static TCGv NULL_QREG;
a7812ae4 70#define IS_NULL_QREG(t) (TCGV_EQUAL(t, NULL_QREG))
e1f3808e
PB
71/* Used to distinguish stores from bad addressing modes. */
72static TCGv store_dummy;
73
022c62cb 74#include "exec/gen-icount.h"
2e70f6ef 75
e1f3808e
PB
76void m68k_tcg_init(void)
77{
78 char *p;
79 int i;
80
e1ccc054 81 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
7c255043 82 tcg_ctx.tcg_env = cpu_env;
e1ccc054
RH
83
84#define DEFO32(name, offset) \
85 QREG_##name = tcg_global_mem_new_i32(cpu_env, \
86 offsetof(CPUM68KState, offset), #name);
87#define DEFO64(name, offset) \
88 QREG_##name = tcg_global_mem_new_i64(cpu_env, \
89 offsetof(CPUM68KState, offset), #name);
90#define DEFF64(name, offset) DEFO64(name, offset)
e1f3808e
PB
91#include "qregs.def"
92#undef DEFO32
93#undef DEFO64
94#undef DEFF64
95
e1ccc054 96 cpu_halted = tcg_global_mem_new_i32(cpu_env,
259186a7
AF
97 -offsetof(M68kCPU, env) +
98 offsetof(CPUState, halted), "HALTED");
e1ccc054 99 cpu_exception_index = tcg_global_mem_new_i32(cpu_env,
27103424
AF
100 -offsetof(M68kCPU, env) +
101 offsetof(CPUState, exception_index),
102 "EXCEPTION");
259186a7 103
e1f3808e
PB
104 p = cpu_reg_names;
105 for (i = 0; i < 8; i++) {
106 sprintf(p, "D%d", i);
e1ccc054 107 cpu_dregs[i] = tcg_global_mem_new(cpu_env,
e1f3808e
PB
108 offsetof(CPUM68KState, dregs[i]), p);
109 p += 3;
110 sprintf(p, "A%d", i);
e1ccc054 111 cpu_aregs[i] = tcg_global_mem_new(cpu_env,
e1f3808e
PB
112 offsetof(CPUM68KState, aregs[i]), p);
113 p += 3;
114 sprintf(p, "F%d", i);
e1ccc054 115 cpu_fregs[i] = tcg_global_mem_new_i64(cpu_env,
e1f3808e
PB
116 offsetof(CPUM68KState, fregs[i]), p);
117 p += 3;
118 }
119 for (i = 0; i < 4; i++) {
120 sprintf(p, "ACC%d", i);
e1ccc054 121 cpu_macc[i] = tcg_global_mem_new_i64(cpu_env,
e1f3808e
PB
122 offsetof(CPUM68KState, macc[i]), p);
123 p += 5;
124 }
125
e1ccc054
RH
126 NULL_QREG = tcg_global_mem_new(cpu_env, -4, "NULL");
127 store_dummy = tcg_global_mem_new(cpu_env, -8, "NULL");
e1f3808e
PB
128}
129
e6e5906b
PB
130/* internal defines */
131typedef struct DisasContext {
e6dbd3b3 132 CPUM68KState *env;
510ff0b7 133 target_ulong insn_pc; /* Start of the current instruction. */
e6e5906b
PB
134 target_ulong pc;
135 int is_jmp;
9fdb533f 136 CCOp cc_op; /* Current CC operation */
620c6cf6 137 int cc_op_synced;
0633879f 138 int user;
e6e5906b
PB
139 uint32_t fpcr;
140 struct TranslationBlock *tb;
141 int singlestep_enabled;
a7812ae4
PB
142 TCGv_i64 mactmp;
143 int done_mac;
8a1e52b6
RH
144 int writeback_mask;
145 TCGv writeback[8];
e6e5906b
PB
146} DisasContext;
147
8a1e52b6
RH
148static TCGv get_areg(DisasContext *s, unsigned regno)
149{
150 if (s->writeback_mask & (1 << regno)) {
151 return s->writeback[regno];
152 } else {
153 return cpu_aregs[regno];
154 }
155}
156
157static void delay_set_areg(DisasContext *s, unsigned regno,
158 TCGv val, bool give_temp)
159{
160 if (s->writeback_mask & (1 << regno)) {
161 if (give_temp) {
162 tcg_temp_free(s->writeback[regno]);
163 s->writeback[regno] = val;
164 } else {
165 tcg_gen_mov_i32(s->writeback[regno], val);
166 }
167 } else {
168 s->writeback_mask |= 1 << regno;
169 if (give_temp) {
170 s->writeback[regno] = val;
171 } else {
172 TCGv tmp = tcg_temp_new();
173 s->writeback[regno] = tmp;
174 tcg_gen_mov_i32(tmp, val);
175 }
176 }
177}
178
179static void do_writebacks(DisasContext *s)
180{
181 unsigned mask = s->writeback_mask;
182 if (mask) {
183 s->writeback_mask = 0;
184 do {
185 unsigned regno = ctz32(mask);
186 tcg_gen_mov_i32(cpu_aregs[regno], s->writeback[regno]);
187 tcg_temp_free(s->writeback[regno]);
188 mask &= mask - 1;
189 } while (mask);
190 }
191}
192
e6e5906b
PB
193#define DISAS_JUMP_NEXT 4
194
0633879f
PB
195#if defined(CONFIG_USER_ONLY)
196#define IS_USER(s) 1
197#else
198#define IS_USER(s) s->user
199#endif
200
e6e5906b
PB
201/* XXX: move that elsewhere */
202/* ??? Fix exceptions. */
203static void *gen_throws_exception;
204#define gen_last_qop NULL
205
d4d79bb1 206typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn);
e6e5906b 207
0633879f 208#ifdef DEBUG_DISPATCH
d4d79bb1
BS
209#define DISAS_INSN(name) \
210 static void real_disas_##name(CPUM68KState *env, DisasContext *s, \
211 uint16_t insn); \
212 static void disas_##name(CPUM68KState *env, DisasContext *s, \
213 uint16_t insn) \
214 { \
215 qemu_log("Dispatch " #name "\n"); \
a1ff1930 216 real_disas_##name(env, s, insn); \
d4d79bb1
BS
217 } \
218 static void real_disas_##name(CPUM68KState *env, DisasContext *s, \
219 uint16_t insn)
0633879f 220#else
d4d79bb1
BS
221#define DISAS_INSN(name) \
222 static void disas_##name(CPUM68KState *env, DisasContext *s, \
223 uint16_t insn)
0633879f 224#endif
e6e5906b 225
9fdb533f 226static const uint8_t cc_op_live[CC_OP_NB] = {
620c6cf6 227 [CC_OP_FLAGS] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
db3d7945
LV
228 [CC_OP_ADDB ... CC_OP_ADDL] = CCF_X | CCF_N | CCF_V,
229 [CC_OP_SUBB ... CC_OP_SUBL] = CCF_X | CCF_N | CCF_V,
230 [CC_OP_CMPB ... CC_OP_CMPL] = CCF_X | CCF_N | CCF_V,
620c6cf6 231 [CC_OP_LOGIC] = CCF_X | CCF_N
9fdb533f
LV
232};
233
234static void set_cc_op(DisasContext *s, CCOp op)
235{
620c6cf6 236 CCOp old_op = s->cc_op;
9fdb533f
LV
237 int dead;
238
620c6cf6 239 if (old_op == op) {
9fdb533f
LV
240 return;
241 }
620c6cf6
RH
242 s->cc_op = op;
243 s->cc_op_synced = 0;
9fdb533f 244
620c6cf6
RH
245 /* Discard CC computation that will no longer be used.
246 Note that X and N are never dead. */
247 dead = cc_op_live[old_op] & ~cc_op_live[op];
248 if (dead & CCF_C) {
249 tcg_gen_discard_i32(QREG_CC_C);
9fdb533f 250 }
620c6cf6
RH
251 if (dead & CCF_Z) {
252 tcg_gen_discard_i32(QREG_CC_Z);
9fdb533f 253 }
620c6cf6
RH
254 if (dead & CCF_V) {
255 tcg_gen_discard_i32(QREG_CC_V);
9fdb533f 256 }
9fdb533f
LV
257}
258
259/* Update the CPU env CC_OP state. */
620c6cf6 260static void update_cc_op(DisasContext *s)
9fdb533f 261{
620c6cf6
RH
262 if (!s->cc_op_synced) {
263 s->cc_op_synced = 1;
9fdb533f
LV
264 tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
265 }
266}
267
e6e5906b
PB
268/* Generate a load from the specified address. Narrow values are
269 sign extended to full register width. */
e1f3808e 270static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
e6e5906b 271{
e1f3808e
PB
272 TCGv tmp;
273 int index = IS_USER(s);
a7812ae4 274 tmp = tcg_temp_new_i32();
e6e5906b
PB
275 switch(opsize) {
276 case OS_BYTE:
e6e5906b 277 if (sign)
e1f3808e 278 tcg_gen_qemu_ld8s(tmp, addr, index);
e6e5906b 279 else
e1f3808e 280 tcg_gen_qemu_ld8u(tmp, addr, index);
e6e5906b
PB
281 break;
282 case OS_WORD:
e6e5906b 283 if (sign)
e1f3808e 284 tcg_gen_qemu_ld16s(tmp, addr, index);
e6e5906b 285 else
e1f3808e 286 tcg_gen_qemu_ld16u(tmp, addr, index);
e6e5906b
PB
287 break;
288 case OS_LONG:
e6e5906b 289 case OS_SINGLE:
a7812ae4 290 tcg_gen_qemu_ld32u(tmp, addr, index);
e6e5906b
PB
291 break;
292 default:
7372c2b9 293 g_assert_not_reached();
e6e5906b
PB
294 }
295 gen_throws_exception = gen_last_qop;
296 return tmp;
297}
298
a7812ae4
PB
299static inline TCGv_i64 gen_load64(DisasContext * s, TCGv addr)
300{
301 TCGv_i64 tmp;
302 int index = IS_USER(s);
a7812ae4
PB
303 tmp = tcg_temp_new_i64();
304 tcg_gen_qemu_ldf64(tmp, addr, index);
305 gen_throws_exception = gen_last_qop;
306 return tmp;
307}
308
e6e5906b 309/* Generate a store. */
e1f3808e 310static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
e6e5906b 311{
e1f3808e 312 int index = IS_USER(s);
e6e5906b
PB
313 switch(opsize) {
314 case OS_BYTE:
e1f3808e 315 tcg_gen_qemu_st8(val, addr, index);
e6e5906b
PB
316 break;
317 case OS_WORD:
e1f3808e 318 tcg_gen_qemu_st16(val, addr, index);
e6e5906b
PB
319 break;
320 case OS_LONG:
e6e5906b 321 case OS_SINGLE:
a7812ae4 322 tcg_gen_qemu_st32(val, addr, index);
e6e5906b
PB
323 break;
324 default:
7372c2b9 325 g_assert_not_reached();
e6e5906b
PB
326 }
327 gen_throws_exception = gen_last_qop;
328}
329
a7812ae4
PB
330static inline void gen_store64(DisasContext *s, TCGv addr, TCGv_i64 val)
331{
332 int index = IS_USER(s);
a7812ae4
PB
333 tcg_gen_qemu_stf64(val, addr, index);
334 gen_throws_exception = gen_last_qop;
335}
336
e1f3808e
PB
337typedef enum {
338 EA_STORE,
339 EA_LOADU,
340 EA_LOADS
341} ea_what;
342
e6e5906b
PB
343/* Generate an unsigned load if VAL is 0 a signed load if val is -1,
344 otherwise generate a store. */
e1f3808e
PB
345static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
346 ea_what what)
e6e5906b 347{
e1f3808e 348 if (what == EA_STORE) {
0633879f 349 gen_store(s, opsize, addr, val);
e1f3808e 350 return store_dummy;
e6e5906b 351 } else {
e1f3808e 352 return gen_load(s, opsize, addr, what == EA_LOADS);
e6e5906b
PB
353 }
354}
355
28b68cd7
LV
356/* Read a 16-bit immediate constant */
357static inline uint16_t read_im16(CPUM68KState *env, DisasContext *s)
358{
359 uint16_t im;
360 im = cpu_lduw_code(env, s->pc);
361 s->pc += 2;
362 return im;
363}
364
365/* Read an 8-bit immediate constant */
366static inline uint8_t read_im8(CPUM68KState *env, DisasContext *s)
367{
368 return read_im16(env, s);
369}
370
e6dbd3b3 371/* Read a 32-bit immediate constant. */
d4d79bb1 372static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s)
e6dbd3b3
PB
373{
374 uint32_t im;
28b68cd7
LV
375 im = read_im16(env, s) << 16;
376 im |= 0xffff & read_im16(env, s);
e6dbd3b3
PB
377 return im;
378}
379
380/* Calculate and address index. */
8a1e52b6 381static TCGv gen_addr_index(DisasContext *s, uint16_t ext, TCGv tmp)
e6dbd3b3 382{
e1f3808e 383 TCGv add;
e6dbd3b3
PB
384 int scale;
385
386 add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
387 if ((ext & 0x800) == 0) {
e1f3808e 388 tcg_gen_ext16s_i32(tmp, add);
e6dbd3b3
PB
389 add = tmp;
390 }
391 scale = (ext >> 9) & 3;
392 if (scale != 0) {
e1f3808e 393 tcg_gen_shli_i32(tmp, add, scale);
e6dbd3b3
PB
394 add = tmp;
395 }
396 return add;
397}
398
e1f3808e
PB
399/* Handle a base + index + displacement effective addresss.
400 A NULL_QREG base means pc-relative. */
a4356126 401static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
e6e5906b 402{
e6e5906b
PB
403 uint32_t offset;
404 uint16_t ext;
e1f3808e
PB
405 TCGv add;
406 TCGv tmp;
e6dbd3b3 407 uint32_t bd, od;
e6e5906b
PB
408
409 offset = s->pc;
28b68cd7 410 ext = read_im16(env, s);
e6dbd3b3
PB
411
412 if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
e1f3808e 413 return NULL_QREG;
e6dbd3b3 414
d8633620
LV
415 if (m68k_feature(s->env, M68K_FEATURE_M68000) &&
416 !m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX)) {
417 ext &= ~(3 << 9);
418 }
419
e6dbd3b3
PB
420 if (ext & 0x100) {
421 /* full extension word format */
422 if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
e1f3808e 423 return NULL_QREG;
e6dbd3b3
PB
424
425 if ((ext & 0x30) > 0x10) {
426 /* base displacement */
427 if ((ext & 0x30) == 0x20) {
28b68cd7 428 bd = (int16_t)read_im16(env, s);
e6dbd3b3 429 } else {
d4d79bb1 430 bd = read_im32(env, s);
e6dbd3b3
PB
431 }
432 } else {
433 bd = 0;
434 }
a7812ae4 435 tmp = tcg_temp_new();
e6dbd3b3
PB
436 if ((ext & 0x44) == 0) {
437 /* pre-index */
8a1e52b6 438 add = gen_addr_index(s, ext, tmp);
e6dbd3b3 439 } else {
e1f3808e 440 add = NULL_QREG;
e6dbd3b3
PB
441 }
442 if ((ext & 0x80) == 0) {
443 /* base not suppressed */
e1f3808e 444 if (IS_NULL_QREG(base)) {
351326a6 445 base = tcg_const_i32(offset + bd);
e6dbd3b3
PB
446 bd = 0;
447 }
e1f3808e
PB
448 if (!IS_NULL_QREG(add)) {
449 tcg_gen_add_i32(tmp, add, base);
e6dbd3b3
PB
450 add = tmp;
451 } else {
452 add = base;
453 }
454 }
e1f3808e 455 if (!IS_NULL_QREG(add)) {
e6dbd3b3 456 if (bd != 0) {
e1f3808e 457 tcg_gen_addi_i32(tmp, add, bd);
e6dbd3b3
PB
458 add = tmp;
459 }
460 } else {
351326a6 461 add = tcg_const_i32(bd);
e6dbd3b3
PB
462 }
463 if ((ext & 3) != 0) {
464 /* memory indirect */
465 base = gen_load(s, OS_LONG, add, 0);
466 if ((ext & 0x44) == 4) {
8a1e52b6 467 add = gen_addr_index(s, ext, tmp);
e1f3808e 468 tcg_gen_add_i32(tmp, add, base);
e6dbd3b3
PB
469 add = tmp;
470 } else {
471 add = base;
472 }
473 if ((ext & 3) > 1) {
474 /* outer displacement */
475 if ((ext & 3) == 2) {
28b68cd7 476 od = (int16_t)read_im16(env, s);
e6dbd3b3 477 } else {
d4d79bb1 478 od = read_im32(env, s);
e6dbd3b3
PB
479 }
480 } else {
481 od = 0;
482 }
483 if (od != 0) {
e1f3808e 484 tcg_gen_addi_i32(tmp, add, od);
e6dbd3b3
PB
485 add = tmp;
486 }
487 }
e6e5906b 488 } else {
e6dbd3b3 489 /* brief extension word format */
a7812ae4 490 tmp = tcg_temp_new();
8a1e52b6 491 add = gen_addr_index(s, ext, tmp);
e1f3808e
PB
492 if (!IS_NULL_QREG(base)) {
493 tcg_gen_add_i32(tmp, add, base);
e6dbd3b3 494 if ((int8_t)ext)
e1f3808e 495 tcg_gen_addi_i32(tmp, tmp, (int8_t)ext);
e6dbd3b3 496 } else {
e1f3808e 497 tcg_gen_addi_i32(tmp, add, offset + (int8_t)ext);
e6dbd3b3
PB
498 }
499 add = tmp;
e6e5906b 500 }
e6dbd3b3 501 return add;
e6e5906b
PB
502}
503
db3d7945
LV
504/* Sign or zero extend a value. */
505
506static inline void gen_ext(TCGv res, TCGv val, int opsize, int sign)
507{
508 switch (opsize) {
509 case OS_BYTE:
510 if (sign) {
511 tcg_gen_ext8s_i32(res, val);
512 } else {
513 tcg_gen_ext8u_i32(res, val);
514 }
515 break;
516 case OS_WORD:
517 if (sign) {
518 tcg_gen_ext16s_i32(res, val);
519 } else {
520 tcg_gen_ext16u_i32(res, val);
521 }
522 break;
523 case OS_LONG:
524 tcg_gen_mov_i32(res, val);
525 break;
526 default:
527 g_assert_not_reached();
528 }
529}
530
e6e5906b 531/* Evaluate all the CC flags. */
9fdb533f 532
620c6cf6 533static void gen_flush_flags(DisasContext *s)
e6e5906b 534{
36f0399d 535 TCGv t0, t1;
620c6cf6
RH
536
537 switch (s->cc_op) {
538 case CC_OP_FLAGS:
e6e5906b 539 return;
36f0399d 540
db3d7945
LV
541 case CC_OP_ADDB:
542 case CC_OP_ADDW:
543 case CC_OP_ADDL:
36f0399d
RH
544 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
545 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
546 /* Compute signed overflow for addition. */
547 t0 = tcg_temp_new();
548 t1 = tcg_temp_new();
549 tcg_gen_sub_i32(t0, QREG_CC_N, QREG_CC_V);
db3d7945 550 gen_ext(t0, t0, s->cc_op - CC_OP_ADDB, 1);
36f0399d
RH
551 tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V);
552 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
553 tcg_temp_free(t0);
554 tcg_gen_andc_i32(QREG_CC_V, t1, QREG_CC_V);
555 tcg_temp_free(t1);
556 break;
557
db3d7945
LV
558 case CC_OP_SUBB:
559 case CC_OP_SUBW:
560 case CC_OP_SUBL:
36f0399d
RH
561 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
562 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
563 /* Compute signed overflow for subtraction. */
564 t0 = tcg_temp_new();
565 t1 = tcg_temp_new();
566 tcg_gen_add_i32(t0, QREG_CC_N, QREG_CC_V);
db3d7945 567 gen_ext(t0, t0, s->cc_op - CC_OP_SUBB, 1);
36f0399d
RH
568 tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V);
569 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
570 tcg_temp_free(t0);
571 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t1);
572 tcg_temp_free(t1);
573 break;
574
db3d7945
LV
575 case CC_OP_CMPB:
576 case CC_OP_CMPW:
577 case CC_OP_CMPL:
36f0399d
RH
578 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_C, QREG_CC_N, QREG_CC_V);
579 tcg_gen_sub_i32(QREG_CC_Z, QREG_CC_N, QREG_CC_V);
db3d7945 580 gen_ext(QREG_CC_Z, QREG_CC_Z, s->cc_op - CC_OP_CMPB, 1);
36f0399d
RH
581 /* Compute signed overflow for subtraction. */
582 t0 = tcg_temp_new();
583 tcg_gen_xor_i32(t0, QREG_CC_Z, QREG_CC_N);
584 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, QREG_CC_N);
585 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t0);
586 tcg_temp_free(t0);
587 tcg_gen_mov_i32(QREG_CC_N, QREG_CC_Z);
588 break;
589
590 case CC_OP_LOGIC:
591 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
592 tcg_gen_movi_i32(QREG_CC_C, 0);
593 tcg_gen_movi_i32(QREG_CC_V, 0);
594 break;
595
620c6cf6
RH
596 case CC_OP_DYNAMIC:
597 gen_helper_flush_flags(cpu_env, QREG_CC_OP);
598 break;
36f0399d 599
620c6cf6 600 default:
36f0399d
RH
601 t0 = tcg_const_i32(s->cc_op);
602 gen_helper_flush_flags(cpu_env, t0);
603 tcg_temp_free(t0);
620c6cf6
RH
604 break;
605 }
606
607 /* Note that flush_flags also assigned to env->cc_op. */
608 s->cc_op = CC_OP_FLAGS;
609 s->cc_op_synced = 1;
610}
611
db3d7945 612static inline TCGv gen_extend(TCGv val, int opsize, int sign)
620c6cf6
RH
613{
614 TCGv tmp;
615
616 if (opsize == OS_LONG) {
617 tmp = val;
618 } else {
619 tmp = tcg_temp_new();
620 gen_ext(tmp, val, opsize, sign);
621 }
622
623 return tmp;
624}
5dbb6784
LV
625
626static void gen_logic_cc(DisasContext *s, TCGv val, int opsize)
e1f3808e 627{
620c6cf6
RH
628 gen_ext(QREG_CC_N, val, opsize, 1);
629 set_cc_op(s, CC_OP_LOGIC);
e1f3808e
PB
630}
631
ff99b952
LV
632static void gen_update_cc_cmp(DisasContext *s, TCGv dest, TCGv src, int opsize)
633{
634 tcg_gen_mov_i32(QREG_CC_N, dest);
635 tcg_gen_mov_i32(QREG_CC_V, src);
636 set_cc_op(s, CC_OP_CMPB + opsize);
637}
638
db3d7945 639static void gen_update_cc_add(TCGv dest, TCGv src, int opsize)
e1f3808e 640{
db3d7945 641 gen_ext(QREG_CC_N, dest, opsize, 1);
620c6cf6 642 tcg_gen_mov_i32(QREG_CC_V, src);
e1f3808e
PB
643}
644
e6e5906b
PB
645static inline int opsize_bytes(int opsize)
646{
647 switch (opsize) {
648 case OS_BYTE: return 1;
649 case OS_WORD: return 2;
650 case OS_LONG: return 4;
651 case OS_SINGLE: return 4;
652 case OS_DOUBLE: return 8;
7ef25cdd
LV
653 case OS_EXTENDED: return 12;
654 case OS_PACKED: return 12;
655 default:
656 g_assert_not_reached();
657 }
658}
659
660static inline int insn_opsize(int insn)
661{
662 switch ((insn >> 6) & 3) {
663 case 0: return OS_BYTE;
664 case 1: return OS_WORD;
665 case 2: return OS_LONG;
e6e5906b 666 default:
7372c2b9 667 g_assert_not_reached();
e6e5906b
PB
668 }
669}
670
671/* Assign value to a register. If the width is less than the register width
672 only the low part of the register is set. */
e1f3808e 673static void gen_partset_reg(int opsize, TCGv reg, TCGv val)
e6e5906b 674{
e1f3808e 675 TCGv tmp;
e6e5906b
PB
676 switch (opsize) {
677 case OS_BYTE:
e1f3808e 678 tcg_gen_andi_i32(reg, reg, 0xffffff00);
a7812ae4 679 tmp = tcg_temp_new();
e1f3808e
PB
680 tcg_gen_ext8u_i32(tmp, val);
681 tcg_gen_or_i32(reg, reg, tmp);
e6e5906b
PB
682 break;
683 case OS_WORD:
e1f3808e 684 tcg_gen_andi_i32(reg, reg, 0xffff0000);
a7812ae4 685 tmp = tcg_temp_new();
e1f3808e
PB
686 tcg_gen_ext16u_i32(tmp, val);
687 tcg_gen_or_i32(reg, reg, tmp);
e6e5906b
PB
688 break;
689 case OS_LONG:
e6e5906b 690 case OS_SINGLE:
a7812ae4 691 tcg_gen_mov_i32(reg, val);
e6e5906b
PB
692 break;
693 default:
7372c2b9 694 g_assert_not_reached();
e6e5906b
PB
695 }
696}
697
e6e5906b 698/* Generate code for an "effective address". Does not adjust the base
1addc7c5 699 register for autoincrement addressing modes. */
f84aab26
RH
700static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
701 int mode, int reg0, int opsize)
e6e5906b 702{
e1f3808e
PB
703 TCGv reg;
704 TCGv tmp;
e6e5906b
PB
705 uint16_t ext;
706 uint32_t offset;
707
f84aab26 708 switch (mode) {
e6e5906b
PB
709 case 0: /* Data register direct. */
710 case 1: /* Address register direct. */
e1f3808e 711 return NULL_QREG;
e6e5906b
PB
712 case 2: /* Indirect register */
713 case 3: /* Indirect postincrement. */
f84aab26 714 return get_areg(s, reg0);
e6e5906b 715 case 4: /* Indirect predecrememnt. */
f84aab26 716 reg = get_areg(s, reg0);
a7812ae4 717 tmp = tcg_temp_new();
e1f3808e 718 tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize));
e6e5906b
PB
719 return tmp;
720 case 5: /* Indirect displacement. */
f84aab26 721 reg = get_areg(s, reg0);
a7812ae4 722 tmp = tcg_temp_new();
28b68cd7 723 ext = read_im16(env, s);
e1f3808e 724 tcg_gen_addi_i32(tmp, reg, (int16_t)ext);
e6e5906b
PB
725 return tmp;
726 case 6: /* Indirect index + displacement. */
f84aab26 727 reg = get_areg(s, reg0);
a4356126 728 return gen_lea_indexed(env, s, reg);
e6e5906b 729 case 7: /* Other */
f84aab26 730 switch (reg0) {
e6e5906b 731 case 0: /* Absolute short. */
28b68cd7 732 offset = (int16_t)read_im16(env, s);
351326a6 733 return tcg_const_i32(offset);
e6e5906b 734 case 1: /* Absolute long. */
d4d79bb1 735 offset = read_im32(env, s);
351326a6 736 return tcg_const_i32(offset);
e6e5906b 737 case 2: /* pc displacement */
e6e5906b 738 offset = s->pc;
28b68cd7 739 offset += (int16_t)read_im16(env, s);
351326a6 740 return tcg_const_i32(offset);
e6e5906b 741 case 3: /* pc index+displacement. */
a4356126 742 return gen_lea_indexed(env, s, NULL_QREG);
e6e5906b
PB
743 case 4: /* Immediate. */
744 default:
e1f3808e 745 return NULL_QREG;
e6e5906b
PB
746 }
747 }
748 /* Should never happen. */
e1f3808e 749 return NULL_QREG;
e6e5906b
PB
750}
751
f84aab26
RH
752static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn,
753 int opsize)
e6e5906b 754{
f84aab26
RH
755 int mode = extract32(insn, 3, 3);
756 int reg0 = REG(insn, 0);
757 return gen_lea_mode(env, s, mode, reg0, opsize);
e6e5906b
PB
758}
759
f84aab26 760/* Generate code to load/store a value from/into an EA. If WHAT > 0 this is
e6e5906b
PB
761 a write otherwise it is a read (0 == sign extend, -1 == zero extend).
762 ADDRP is non-null for readwrite operands. */
f84aab26
RH
763static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0,
764 int opsize, TCGv val, TCGv *addrp, ea_what what)
e6e5906b 765{
f84aab26
RH
766 TCGv reg, tmp, result;
767 int32_t offset;
e6e5906b 768
f84aab26 769 switch (mode) {
e6e5906b 770 case 0: /* Data register direct. */
f84aab26 771 reg = cpu_dregs[reg0];
e1f3808e 772 if (what == EA_STORE) {
e6e5906b 773 gen_partset_reg(opsize, reg, val);
e1f3808e 774 return store_dummy;
e6e5906b 775 } else {
e1f3808e 776 return gen_extend(reg, opsize, what == EA_LOADS);
e6e5906b
PB
777 }
778 case 1: /* Address register direct. */
f84aab26 779 reg = get_areg(s, reg0);
e1f3808e
PB
780 if (what == EA_STORE) {
781 tcg_gen_mov_i32(reg, val);
782 return store_dummy;
e6e5906b 783 } else {
e1f3808e 784 return gen_extend(reg, opsize, what == EA_LOADS);
e6e5906b
PB
785 }
786 case 2: /* Indirect register */
f84aab26 787 reg = get_areg(s, reg0);
e1f3808e 788 return gen_ldst(s, opsize, reg, val, what);
e6e5906b 789 case 3: /* Indirect postincrement. */
f84aab26 790 reg = get_areg(s, reg0);
e1f3808e 791 result = gen_ldst(s, opsize, reg, val, what);
8a1e52b6
RH
792 if (what == EA_STORE || !addrp) {
793 TCGv tmp = tcg_temp_new();
794 tcg_gen_addi_i32(tmp, reg, opsize_bytes(opsize));
f84aab26 795 delay_set_areg(s, reg0, tmp, true);
8a1e52b6 796 }
e6e5906b
PB
797 return result;
798 case 4: /* Indirect predecrememnt. */
f84aab26
RH
799 if (addrp && what == EA_STORE) {
800 tmp = *addrp;
801 } else {
802 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
803 if (IS_NULL_QREG(tmp)) {
804 return tmp;
e6e5906b 805 }
f84aab26
RH
806 if (addrp) {
807 *addrp = tmp;
e6e5906b
PB
808 }
809 }
f84aab26
RH
810 result = gen_ldst(s, opsize, tmp, val, what);
811 if (what == EA_STORE || !addrp) {
812 delay_set_areg(s, reg0, tmp, false);
813 }
e6e5906b
PB
814 return result;
815 case 5: /* Indirect displacement. */
816 case 6: /* Indirect index + displacement. */
f84aab26
RH
817 do_indirect:
818 if (addrp && what == EA_STORE) {
819 tmp = *addrp;
820 } else {
821 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
822 if (IS_NULL_QREG(tmp)) {
823 return tmp;
824 }
825 if (addrp) {
826 *addrp = tmp;
827 }
828 }
829 return gen_ldst(s, opsize, tmp, val, what);
e6e5906b 830 case 7: /* Other */
f84aab26 831 switch (reg0) {
e6e5906b
PB
832 case 0: /* Absolute short. */
833 case 1: /* Absolute long. */
834 case 2: /* pc displacement */
835 case 3: /* pc index+displacement. */
f84aab26 836 goto do_indirect;
e6e5906b
PB
837 case 4: /* Immediate. */
838 /* Sign extend values for consistency. */
839 switch (opsize) {
840 case OS_BYTE:
31871141 841 if (what == EA_LOADS) {
28b68cd7 842 offset = (int8_t)read_im8(env, s);
31871141 843 } else {
28b68cd7 844 offset = read_im8(env, s);
31871141 845 }
e6e5906b
PB
846 break;
847 case OS_WORD:
31871141 848 if (what == EA_LOADS) {
28b68cd7 849 offset = (int16_t)read_im16(env, s);
31871141 850 } else {
28b68cd7 851 offset = read_im16(env, s);
31871141 852 }
e6e5906b
PB
853 break;
854 case OS_LONG:
d4d79bb1 855 offset = read_im32(env, s);
e6e5906b
PB
856 break;
857 default:
7372c2b9 858 g_assert_not_reached();
e6e5906b 859 }
e1f3808e 860 return tcg_const_i32(offset);
e6e5906b 861 default:
e1f3808e 862 return NULL_QREG;
e6e5906b
PB
863 }
864 }
865 /* Should never happen. */
e1f3808e 866 return NULL_QREG;
e6e5906b
PB
867}
868
f84aab26
RH
869static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn,
870 int opsize, TCGv val, TCGv *addrp, ea_what what)
871{
872 int mode = extract32(insn, 3, 3);
873 int reg0 = REG(insn, 0);
874 return gen_ea_mode(env, s, mode, reg0, opsize, val, addrp, what);
875}
876
6a432295
RH
877typedef struct {
878 TCGCond tcond;
879 bool g1;
880 bool g2;
881 TCGv v1;
882 TCGv v2;
883} DisasCompare;
884
885static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond)
e6e5906b 886{
620c6cf6
RH
887 TCGv tmp, tmp2;
888 TCGCond tcond;
9d896621 889 CCOp op = s->cc_op;
e6e5906b 890
9d896621 891 /* The CC_OP_CMP form can handle most normal comparisons directly. */
db3d7945 892 if (op == CC_OP_CMPB || op == CC_OP_CMPW || op == CC_OP_CMPL) {
9d896621
RH
893 c->g1 = c->g2 = 1;
894 c->v1 = QREG_CC_N;
895 c->v2 = QREG_CC_V;
896 switch (cond) {
897 case 2: /* HI */
898 case 3: /* LS */
899 tcond = TCG_COND_LEU;
900 goto done;
901 case 4: /* CC */
902 case 5: /* CS */
903 tcond = TCG_COND_LTU;
904 goto done;
905 case 6: /* NE */
906 case 7: /* EQ */
907 tcond = TCG_COND_EQ;
908 goto done;
909 case 10: /* PL */
910 case 11: /* MI */
911 c->g1 = c->g2 = 0;
912 c->v2 = tcg_const_i32(0);
913 c->v1 = tmp = tcg_temp_new();
914 tcg_gen_sub_i32(tmp, QREG_CC_N, QREG_CC_V);
db3d7945 915 gen_ext(tmp, tmp, op - CC_OP_CMPB, 1);
9d896621
RH
916 /* fallthru */
917 case 12: /* GE */
918 case 13: /* LT */
919 tcond = TCG_COND_LT;
920 goto done;
921 case 14: /* GT */
922 case 15: /* LE */
923 tcond = TCG_COND_LE;
924 goto done;
925 }
926 }
6a432295
RH
927
928 c->g1 = 1;
929 c->g2 = 0;
930 c->v2 = tcg_const_i32(0);
931
e6e5906b
PB
932 switch (cond) {
933 case 0: /* T */
e6e5906b 934 case 1: /* F */
6a432295
RH
935 c->v1 = c->v2;
936 tcond = TCG_COND_NEVER;
9d896621
RH
937 goto done;
938 case 14: /* GT (!(Z || (N ^ V))) */
939 case 15: /* LE (Z || (N ^ V)) */
940 /* Logic operations clear V, which simplifies LE to (Z || N),
941 and since Z and N are co-located, this becomes a normal
942 comparison vs N. */
943 if (op == CC_OP_LOGIC) {
944 c->v1 = QREG_CC_N;
945 tcond = TCG_COND_LE;
946 goto done;
947 }
6a432295 948 break;
9d896621
RH
949 case 12: /* GE (!(N ^ V)) */
950 case 13: /* LT (N ^ V) */
951 /* Logic operations clear V, which simplifies this to N. */
952 if (op != CC_OP_LOGIC) {
953 break;
954 }
955 /* fallthru */
956 case 10: /* PL (!N) */
957 case 11: /* MI (N) */
958 /* Several cases represent N normally. */
db3d7945
LV
959 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
960 op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
961 op == CC_OP_LOGIC) {
9d896621
RH
962 c->v1 = QREG_CC_N;
963 tcond = TCG_COND_LT;
964 goto done;
965 }
966 break;
967 case 6: /* NE (!Z) */
968 case 7: /* EQ (Z) */
969 /* Some cases fold Z into N. */
db3d7945
LV
970 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
971 op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
972 op == CC_OP_LOGIC) {
9d896621
RH
973 tcond = TCG_COND_EQ;
974 c->v1 = QREG_CC_N;
975 goto done;
976 }
977 break;
978 case 4: /* CC (!C) */
979 case 5: /* CS (C) */
980 /* Some cases fold C into X. */
db3d7945
LV
981 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
982 op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL) {
9d896621
RH
983 tcond = TCG_COND_NE;
984 c->v1 = QREG_CC_X;
985 goto done;
986 }
987 /* fallthru */
988 case 8: /* VC (!V) */
989 case 9: /* VS (V) */
990 /* Logic operations clear V and C. */
991 if (op == CC_OP_LOGIC) {
992 tcond = TCG_COND_NEVER;
993 c->v1 = c->v2;
994 goto done;
995 }
996 break;
997 }
998
999 /* Otherwise, flush flag state to CC_OP_FLAGS. */
1000 gen_flush_flags(s);
1001
1002 switch (cond) {
1003 case 0: /* T */
1004 case 1: /* F */
1005 default:
1006 /* Invalid, or handled above. */
1007 abort();
620c6cf6 1008 case 2: /* HI (!C && !Z) -> !(C || Z)*/
e6e5906b 1009 case 3: /* LS (C || Z) */
6a432295
RH
1010 c->v1 = tmp = tcg_temp_new();
1011 c->g1 = 0;
1012 tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
620c6cf6 1013 tcg_gen_or_i32(tmp, tmp, QREG_CC_C);
6a432295 1014 tcond = TCG_COND_NE;
e6e5906b
PB
1015 break;
1016 case 4: /* CC (!C) */
e6e5906b 1017 case 5: /* CS (C) */
6a432295
RH
1018 c->v1 = QREG_CC_C;
1019 tcond = TCG_COND_NE;
e6e5906b
PB
1020 break;
1021 case 6: /* NE (!Z) */
e6e5906b 1022 case 7: /* EQ (Z) */
6a432295
RH
1023 c->v1 = QREG_CC_Z;
1024 tcond = TCG_COND_EQ;
e6e5906b
PB
1025 break;
1026 case 8: /* VC (!V) */
e6e5906b 1027 case 9: /* VS (V) */
6a432295
RH
1028 c->v1 = QREG_CC_V;
1029 tcond = TCG_COND_LT;
e6e5906b
PB
1030 break;
1031 case 10: /* PL (!N) */
e6e5906b 1032 case 11: /* MI (N) */
6a432295
RH
1033 c->v1 = QREG_CC_N;
1034 tcond = TCG_COND_LT;
e6e5906b
PB
1035 break;
1036 case 12: /* GE (!(N ^ V)) */
e6e5906b 1037 case 13: /* LT (N ^ V) */
6a432295
RH
1038 c->v1 = tmp = tcg_temp_new();
1039 c->g1 = 0;
620c6cf6 1040 tcg_gen_xor_i32(tmp, QREG_CC_N, QREG_CC_V);
6a432295 1041 tcond = TCG_COND_LT;
e6e5906b
PB
1042 break;
1043 case 14: /* GT (!(Z || (N ^ V))) */
e6e5906b 1044 case 15: /* LE (Z || (N ^ V)) */
6a432295
RH
1045 c->v1 = tmp = tcg_temp_new();
1046 c->g1 = 0;
1047 tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
620c6cf6
RH
1048 tcg_gen_neg_i32(tmp, tmp);
1049 tmp2 = tcg_temp_new();
1050 tcg_gen_xor_i32(tmp2, QREG_CC_N, QREG_CC_V);
1051 tcg_gen_or_i32(tmp, tmp, tmp2);
6a432295
RH
1052 tcg_temp_free(tmp2);
1053 tcond = TCG_COND_LT;
e6e5906b 1054 break;
e6e5906b 1055 }
9d896621
RH
1056
1057 done:
6a432295
RH
1058 if ((cond & 1) == 0) {
1059 tcond = tcg_invert_cond(tcond);
1060 }
1061 c->tcond = tcond;
1062}
1063
1064static void free_cond(DisasCompare *c)
1065{
1066 if (!c->g1) {
1067 tcg_temp_free(c->v1);
1068 }
1069 if (!c->g2) {
1070 tcg_temp_free(c->v2);
1071 }
1072}
1073
1074static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1)
1075{
1076 DisasCompare c;
1077
1078 gen_cc_cond(&c, s, cond);
1079 update_cc_op(s);
1080 tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
1081 free_cond(&c);
e6e5906b
PB
1082}
1083
0633879f
PB
1084/* Force a TB lookup after an instruction that changes the CPU state. */
1085static void gen_lookup_tb(DisasContext *s)
1086{
9fdb533f 1087 update_cc_op(s);
e1f3808e 1088 tcg_gen_movi_i32(QREG_PC, s->pc);
0633879f
PB
1089 s->is_jmp = DISAS_UPDATE;
1090}
1091
e1f3808e
PB
1092/* Generate a jump to an immediate address. */
1093static void gen_jmp_im(DisasContext *s, uint32_t dest)
1094{
9fdb533f 1095 update_cc_op(s);
e1f3808e
PB
1096 tcg_gen_movi_i32(QREG_PC, dest);
1097 s->is_jmp = DISAS_JUMP;
1098}
1099
1100/* Generate a jump to the address in qreg DEST. */
1101static void gen_jmp(DisasContext *s, TCGv dest)
e6e5906b 1102{
9fdb533f 1103 update_cc_op(s);
e1f3808e 1104 tcg_gen_mov_i32(QREG_PC, dest);
e6e5906b
PB
1105 s->is_jmp = DISAS_JUMP;
1106}
1107
1108static void gen_exception(DisasContext *s, uint32_t where, int nr)
1109{
9fdb533f 1110 update_cc_op(s);
e1f3808e 1111 gen_jmp_im(s, where);
31871141 1112 gen_helper_raise_exception(cpu_env, tcg_const_i32(nr));
e6e5906b
PB
1113}
1114
510ff0b7
PB
1115static inline void gen_addr_fault(DisasContext *s)
1116{
1117 gen_exception(s, s->insn_pc, EXCP_ADDRESS);
1118}
1119
d4d79bb1
BS
1120#define SRC_EA(env, result, opsize, op_sign, addrp) do { \
1121 result = gen_ea(env, s, insn, opsize, NULL_QREG, addrp, \
1122 op_sign ? EA_LOADS : EA_LOADU); \
1123 if (IS_NULL_QREG(result)) { \
1124 gen_addr_fault(s); \
1125 return; \
1126 } \
510ff0b7
PB
1127 } while (0)
1128
d4d79bb1
BS
1129#define DEST_EA(env, insn, opsize, val, addrp) do { \
1130 TCGv ea_result = gen_ea(env, s, insn, opsize, val, addrp, EA_STORE); \
1131 if (IS_NULL_QREG(ea_result)) { \
1132 gen_addr_fault(s); \
1133 return; \
1134 } \
510ff0b7
PB
1135 } while (0)
1136
90aa39a1
SF
1137static inline bool use_goto_tb(DisasContext *s, uint32_t dest)
1138{
1139#ifndef CONFIG_USER_ONLY
1140 return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
1141 (s->insn_pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
1142#else
1143 return true;
1144#endif
1145}
1146
e6e5906b
PB
1147/* Generate a jump to an immediate address. */
1148static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
1149{
551bd27f 1150 if (unlikely(s->singlestep_enabled)) {
e6e5906b 1151 gen_exception(s, dest, EXCP_DEBUG);
90aa39a1 1152 } else if (use_goto_tb(s, dest)) {
57fec1fe 1153 tcg_gen_goto_tb(n);
e1f3808e 1154 tcg_gen_movi_i32(QREG_PC, dest);
90aa39a1 1155 tcg_gen_exit_tb((uintptr_t)s->tb + n);
e6e5906b 1156 } else {
e1f3808e 1157 gen_jmp_im(s, dest);
57fec1fe 1158 tcg_gen_exit_tb(0);
e6e5906b
PB
1159 }
1160 s->is_jmp = DISAS_TB_JUMP;
1161}
1162
d5a3cf33
LV
1163DISAS_INSN(scc)
1164{
1165 DisasCompare c;
1166 int cond;
1167 TCGv tmp;
1168
1169 cond = (insn >> 8) & 0xf;
1170 gen_cc_cond(&c, s, cond);
1171
1172 tmp = tcg_temp_new();
1173 tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2);
1174 free_cond(&c);
1175
1176 tcg_gen_neg_i32(tmp, tmp);
1177 DEST_EA(env, insn, OS_BYTE, tmp, NULL);
1178 tcg_temp_free(tmp);
1179}
1180
beff27ab
LV
1181DISAS_INSN(dbcc)
1182{
1183 TCGLabel *l1;
1184 TCGv reg;
1185 TCGv tmp;
1186 int16_t offset;
1187 uint32_t base;
1188
1189 reg = DREG(insn, 0);
1190 base = s->pc;
1191 offset = (int16_t)read_im16(env, s);
1192 l1 = gen_new_label();
1193 gen_jmpcc(s, (insn >> 8) & 0xf, l1);
1194
1195 tmp = tcg_temp_new();
1196 tcg_gen_ext16s_i32(tmp, reg);
1197 tcg_gen_addi_i32(tmp, tmp, -1);
1198 gen_partset_reg(OS_WORD, reg, tmp);
1199 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1);
1200 gen_jmp_tb(s, 1, base + offset);
1201 gen_set_label(l1);
1202 gen_jmp_tb(s, 0, s->pc);
1203}
1204
e6e5906b
PB
1205DISAS_INSN(undef_mac)
1206{
1207 gen_exception(s, s->pc - 2, EXCP_LINEA);
1208}
1209
1210DISAS_INSN(undef_fpu)
1211{
1212 gen_exception(s, s->pc - 2, EXCP_LINEF);
1213}
1214
1215DISAS_INSN(undef)
1216{
72d2e4b6
RH
1217 /* ??? This is both instructions that are as yet unimplemented
1218 for the 680x0 series, as well as those that are implemented
1219 but actually illegal for CPU32 or pre-68020. */
1220 qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x",
1221 insn, s->pc - 2);
e6e5906b 1222 gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED);
e6e5906b
PB
1223}
1224
1225DISAS_INSN(mulw)
1226{
e1f3808e
PB
1227 TCGv reg;
1228 TCGv tmp;
1229 TCGv src;
e6e5906b
PB
1230 int sign;
1231
1232 sign = (insn & 0x100) != 0;
1233 reg = DREG(insn, 9);
a7812ae4 1234 tmp = tcg_temp_new();
e6e5906b 1235 if (sign)
e1f3808e 1236 tcg_gen_ext16s_i32(tmp, reg);
e6e5906b 1237 else
e1f3808e 1238 tcg_gen_ext16u_i32(tmp, reg);
d4d79bb1 1239 SRC_EA(env, src, OS_WORD, sign, NULL);
e1f3808e
PB
1240 tcg_gen_mul_i32(tmp, tmp, src);
1241 tcg_gen_mov_i32(reg, tmp);
4a18cd44 1242 gen_logic_cc(s, tmp, OS_LONG);
e6e5906b
PB
1243}
1244
1245DISAS_INSN(divw)
1246{
e6e5906b 1247 int sign;
0ccb9c1d
LV
1248 TCGv src;
1249 TCGv destr;
1250
1251 /* divX.w <EA>,Dn 32/16 -> 16r:16q */
e6e5906b
PB
1252
1253 sign = (insn & 0x100) != 0;
0ccb9c1d
LV
1254
1255 /* dest.l / src.w */
1256
d4d79bb1 1257 SRC_EA(env, src, OS_WORD, sign, NULL);
0ccb9c1d 1258 destr = tcg_const_i32(REG(insn, 9));
e6e5906b 1259 if (sign) {
0ccb9c1d 1260 gen_helper_divsw(cpu_env, destr, src);
e6e5906b 1261 } else {
0ccb9c1d 1262 gen_helper_divuw(cpu_env, destr, src);
e6e5906b 1263 }
0ccb9c1d 1264 tcg_temp_free(destr);
620c6cf6 1265
9fdb533f 1266 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1267}
1268
1269DISAS_INSN(divl)
1270{
0ccb9c1d
LV
1271 TCGv num, reg, den;
1272 int sign;
e6e5906b
PB
1273 uint16_t ext;
1274
28b68cd7 1275 ext = read_im16(env, s);
0ccb9c1d
LV
1276
1277 sign = (ext & 0x0800) != 0;
1278
1279 if (ext & 0x400) {
1280 if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
1281 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
1282 return;
1283 }
1284
1285 /* divX.l <EA>, Dr:Dq 64/32 -> 32r:32q */
1286
1287 SRC_EA(env, den, OS_LONG, 0, NULL);
1288 num = tcg_const_i32(REG(ext, 12));
1289 reg = tcg_const_i32(REG(ext, 0));
1290 if (sign) {
1291 gen_helper_divsll(cpu_env, num, reg, den);
1292 } else {
1293 gen_helper_divull(cpu_env, num, reg, den);
1294 }
1295 tcg_temp_free(reg);
1296 tcg_temp_free(num);
1297 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1298 return;
1299 }
0ccb9c1d
LV
1300
1301 /* divX.l <EA>, Dq 32/32 -> 32q */
1302 /* divXl.l <EA>, Dr:Dq 32/32 -> 32r:32q */
1303
d4d79bb1 1304 SRC_EA(env, den, OS_LONG, 0, NULL);
0ccb9c1d
LV
1305 num = tcg_const_i32(REG(ext, 12));
1306 reg = tcg_const_i32(REG(ext, 0));
1307 if (sign) {
1308 gen_helper_divsl(cpu_env, num, reg, den);
e6e5906b 1309 } else {
0ccb9c1d 1310 gen_helper_divul(cpu_env, num, reg, den);
e6e5906b 1311 }
0ccb9c1d
LV
1312 tcg_temp_free(reg);
1313 tcg_temp_free(num);
1314
9fdb533f 1315 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1316}
1317
fb5543d8
LV
1318static void bcd_add(TCGv dest, TCGv src)
1319{
1320 TCGv t0, t1;
1321
1322 /* dest10 = dest10 + src10 + X
1323 *
1324 * t1 = src
1325 * t2 = t1 + 0x066
1326 * t3 = t2 + dest + X
1327 * t4 = t2 ^ dest
1328 * t5 = t3 ^ t4
1329 * t6 = ~t5 & 0x110
1330 * t7 = (t6 >> 2) | (t6 >> 3)
1331 * return t3 - t7
1332 */
1333
1334 /* t1 = (src + 0x066) + dest + X
1335 * = result with some possible exceding 0x6
1336 */
1337
1338 t0 = tcg_const_i32(0x066);
1339 tcg_gen_add_i32(t0, t0, src);
1340
1341 t1 = tcg_temp_new();
1342 tcg_gen_add_i32(t1, t0, dest);
1343 tcg_gen_add_i32(t1, t1, QREG_CC_X);
1344
1345 /* we will remove exceding 0x6 where there is no carry */
1346
1347 /* t0 = (src + 0x0066) ^ dest
1348 * = t1 without carries
1349 */
1350
1351 tcg_gen_xor_i32(t0, t0, dest);
1352
1353 /* extract the carries
1354 * t0 = t0 ^ t1
1355 * = only the carries
1356 */
1357
1358 tcg_gen_xor_i32(t0, t0, t1);
1359
1360 /* generate 0x1 where there is no carry
1361 * and for each 0x10, generate a 0x6
1362 */
1363
1364 tcg_gen_shri_i32(t0, t0, 3);
1365 tcg_gen_not_i32(t0, t0);
1366 tcg_gen_andi_i32(t0, t0, 0x22);
1367 tcg_gen_add_i32(dest, t0, t0);
1368 tcg_gen_add_i32(dest, dest, t0);
1369 tcg_temp_free(t0);
1370
1371 /* remove the exceding 0x6
1372 * for digits that have not generated a carry
1373 */
1374
1375 tcg_gen_sub_i32(dest, t1, dest);
1376 tcg_temp_free(t1);
1377}
1378
1379static void bcd_sub(TCGv dest, TCGv src)
1380{
1381 TCGv t0, t1, t2;
1382
1383 /* dest10 = dest10 - src10 - X
1384 * = bcd_add(dest + 1 - X, 0x199 - src)
1385 */
1386
1387 /* t0 = 0x066 + (0x199 - src) */
1388
1389 t0 = tcg_temp_new();
1390 tcg_gen_subfi_i32(t0, 0x1ff, src);
1391
1392 /* t1 = t0 + dest + 1 - X*/
1393
1394 t1 = tcg_temp_new();
1395 tcg_gen_add_i32(t1, t0, dest);
1396 tcg_gen_addi_i32(t1, t1, 1);
1397 tcg_gen_sub_i32(t1, t1, QREG_CC_X);
1398
1399 /* t2 = t0 ^ dest */
1400
1401 t2 = tcg_temp_new();
1402 tcg_gen_xor_i32(t2, t0, dest);
1403
1404 /* t0 = t1 ^ t2 */
1405
1406 tcg_gen_xor_i32(t0, t1, t2);
1407
1408 /* t2 = ~t0 & 0x110
1409 * t0 = (t2 >> 2) | (t2 >> 3)
1410 *
1411 * to fit on 8bit operands, changed in:
1412 *
1413 * t2 = ~(t0 >> 3) & 0x22
1414 * t0 = t2 + t2
1415 * t0 = t0 + t2
1416 */
1417
1418 tcg_gen_shri_i32(t2, t0, 3);
1419 tcg_gen_not_i32(t2, t2);
1420 tcg_gen_andi_i32(t2, t2, 0x22);
1421 tcg_gen_add_i32(t0, t2, t2);
1422 tcg_gen_add_i32(t0, t0, t2);
1423 tcg_temp_free(t2);
1424
1425 /* return t1 - t0 */
1426
1427 tcg_gen_sub_i32(dest, t1, t0);
1428 tcg_temp_free(t0);
1429 tcg_temp_free(t1);
1430}
1431
1432static void bcd_flags(TCGv val)
1433{
1434 tcg_gen_andi_i32(QREG_CC_C, val, 0x0ff);
1435 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_C);
1436
1437 tcg_gen_shri_i32(QREG_CC_C, val, 8);
1438 tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
1439
1440 tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
1441}
1442
1443DISAS_INSN(abcd_reg)
1444{
1445 TCGv src;
1446 TCGv dest;
1447
1448 gen_flush_flags(s); /* !Z is sticky */
1449
1450 src = gen_extend(DREG(insn, 0), OS_BYTE, 0);
1451 dest = gen_extend(DREG(insn, 9), OS_BYTE, 0);
1452 bcd_add(dest, src);
1453 gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1454
1455 bcd_flags(dest);
1456}
1457
1458DISAS_INSN(abcd_mem)
1459{
1460 TCGv src, dest, addr;
1461
1462 gen_flush_flags(s); /* !Z is sticky */
1463
1464 /* Indirect pre-decrement load (mode 4) */
1465
1466 src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
1467 NULL_QREG, NULL, EA_LOADU);
1468 dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
1469 NULL_QREG, &addr, EA_LOADU);
1470
1471 bcd_add(dest, src);
1472
1473 gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr, EA_STORE);
1474
1475 bcd_flags(dest);
1476}
1477
1478DISAS_INSN(sbcd_reg)
1479{
1480 TCGv src, dest;
1481
1482 gen_flush_flags(s); /* !Z is sticky */
1483
1484 src = gen_extend(DREG(insn, 0), OS_BYTE, 0);
1485 dest = gen_extend(DREG(insn, 9), OS_BYTE, 0);
1486
1487 bcd_sub(dest, src);
1488
1489 gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1490
1491 bcd_flags(dest);
1492}
1493
1494DISAS_INSN(sbcd_mem)
1495{
1496 TCGv src, dest, addr;
1497
1498 gen_flush_flags(s); /* !Z is sticky */
1499
1500 /* Indirect pre-decrement load (mode 4) */
1501
1502 src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
1503 NULL_QREG, NULL, EA_LOADU);
1504 dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
1505 NULL_QREG, &addr, EA_LOADU);
1506
1507 bcd_sub(dest, src);
1508
1509 gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr, EA_STORE);
1510
1511 bcd_flags(dest);
1512}
1513
1514DISAS_INSN(nbcd)
1515{
1516 TCGv src, dest;
1517 TCGv addr;
1518
1519 gen_flush_flags(s); /* !Z is sticky */
1520
1521 SRC_EA(env, src, OS_BYTE, 0, &addr);
1522
1523 dest = tcg_const_i32(0);
1524 bcd_sub(dest, src);
1525
1526 DEST_EA(env, insn, OS_BYTE, dest, &addr);
1527
1528 bcd_flags(dest);
1529
1530 tcg_temp_free(dest);
1531}
1532
e6e5906b
PB
1533DISAS_INSN(addsub)
1534{
e1f3808e
PB
1535 TCGv reg;
1536 TCGv dest;
1537 TCGv src;
1538 TCGv tmp;
1539 TCGv addr;
e6e5906b 1540 int add;
8a370c6c 1541 int opsize;
e6e5906b
PB
1542
1543 add = (insn & 0x4000) != 0;
8a370c6c
LV
1544 opsize = insn_opsize(insn);
1545 reg = gen_extend(DREG(insn, 9), opsize, 1);
a7812ae4 1546 dest = tcg_temp_new();
e6e5906b 1547 if (insn & 0x100) {
8a370c6c 1548 SRC_EA(env, tmp, opsize, 1, &addr);
e6e5906b
PB
1549 src = reg;
1550 } else {
1551 tmp = reg;
8a370c6c 1552 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b
PB
1553 }
1554 if (add) {
e1f3808e 1555 tcg_gen_add_i32(dest, tmp, src);
f9083519 1556 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src);
8a370c6c 1557 set_cc_op(s, CC_OP_ADDB + opsize);
e6e5906b 1558 } else {
f9083519 1559 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src);
e1f3808e 1560 tcg_gen_sub_i32(dest, tmp, src);
8a370c6c 1561 set_cc_op(s, CC_OP_SUBB + opsize);
e6e5906b 1562 }
8a370c6c 1563 gen_update_cc_add(dest, src, opsize);
e6e5906b 1564 if (insn & 0x100) {
8a370c6c 1565 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 1566 } else {
8a370c6c 1567 gen_partset_reg(opsize, DREG(insn, 9), dest);
e6e5906b 1568 }
8a370c6c 1569 tcg_temp_free(dest);
e6e5906b
PB
1570}
1571
e6e5906b
PB
1572/* Reverse the order of the bits in REG. */
1573DISAS_INSN(bitrev)
1574{
e1f3808e 1575 TCGv reg;
e6e5906b 1576 reg = DREG(insn, 0);
e1f3808e 1577 gen_helper_bitrev(reg, reg);
e6e5906b
PB
1578}
1579
1580DISAS_INSN(bitop_reg)
1581{
1582 int opsize;
1583 int op;
e1f3808e
PB
1584 TCGv src1;
1585 TCGv src2;
1586 TCGv tmp;
1587 TCGv addr;
1588 TCGv dest;
e6e5906b
PB
1589
1590 if ((insn & 0x38) != 0)
1591 opsize = OS_BYTE;
1592 else
1593 opsize = OS_LONG;
1594 op = (insn >> 6) & 3;
d4d79bb1 1595 SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
e6e5906b 1596
3c980d2e
LV
1597 gen_flush_flags(s);
1598 src2 = tcg_temp_new();
e6e5906b 1599 if (opsize == OS_BYTE)
3c980d2e 1600 tcg_gen_andi_i32(src2, DREG(insn, 9), 7);
e6e5906b 1601 else
3c980d2e 1602 tcg_gen_andi_i32(src2, DREG(insn, 9), 31);
620c6cf6 1603
3c980d2e
LV
1604 tmp = tcg_const_i32(1);
1605 tcg_gen_shl_i32(tmp, tmp, src2);
1606 tcg_temp_free(src2);
620c6cf6 1607
3c980d2e 1608 tcg_gen_and_i32(QREG_CC_Z, src1, tmp);
620c6cf6 1609
3c980d2e 1610 dest = tcg_temp_new();
e6e5906b
PB
1611 switch (op) {
1612 case 1: /* bchg */
3c980d2e 1613 tcg_gen_xor_i32(dest, src1, tmp);
e6e5906b
PB
1614 break;
1615 case 2: /* bclr */
3c980d2e 1616 tcg_gen_andc_i32(dest, src1, tmp);
e6e5906b
PB
1617 break;
1618 case 3: /* bset */
3c980d2e 1619 tcg_gen_or_i32(dest, src1, tmp);
e6e5906b
PB
1620 break;
1621 default: /* btst */
1622 break;
1623 }
3c980d2e 1624 tcg_temp_free(tmp);
620c6cf6 1625 if (op) {
d4d79bb1 1626 DEST_EA(env, insn, opsize, dest, &addr);
620c6cf6
RH
1627 }
1628 tcg_temp_free(dest);
e6e5906b
PB
1629}
1630
1631DISAS_INSN(sats)
1632{
e1f3808e 1633 TCGv reg;
e6e5906b 1634 reg = DREG(insn, 0);
e6e5906b 1635 gen_flush_flags(s);
620c6cf6 1636 gen_helper_sats(reg, reg, QREG_CC_V);
5dbb6784 1637 gen_logic_cc(s, reg, OS_LONG);
e6e5906b
PB
1638}
1639
e1f3808e 1640static void gen_push(DisasContext *s, TCGv val)
e6e5906b 1641{
e1f3808e 1642 TCGv tmp;
e6e5906b 1643
a7812ae4 1644 tmp = tcg_temp_new();
e1f3808e 1645 tcg_gen_subi_i32(tmp, QREG_SP, 4);
0633879f 1646 gen_store(s, OS_LONG, tmp, val);
e1f3808e 1647 tcg_gen_mov_i32(QREG_SP, tmp);
e6e5906b
PB
1648}
1649
7b542eb9
LV
1650static TCGv mreg(int reg)
1651{
1652 if (reg < 8) {
1653 /* Dx */
1654 return cpu_dregs[reg];
1655 }
1656 /* Ax */
1657 return cpu_aregs[reg & 7];
1658}
1659
e6e5906b
PB
1660DISAS_INSN(movem)
1661{
7b542eb9
LV
1662 TCGv addr, incr, tmp, r[16];
1663 int is_load = (insn & 0x0400) != 0;
1664 int opsize = (insn & 0x40) != 0 ? OS_LONG : OS_WORD;
1665 uint16_t mask = read_im16(env, s);
1666 int mode = extract32(insn, 3, 3);
1667 int reg0 = REG(insn, 0);
e6e5906b 1668 int i;
e6e5906b 1669
7b542eb9
LV
1670 tmp = cpu_aregs[reg0];
1671
1672 switch (mode) {
1673 case 0: /* data register direct */
1674 case 1: /* addr register direct */
1675 do_addr_fault:
510ff0b7
PB
1676 gen_addr_fault(s);
1677 return;
7b542eb9
LV
1678
1679 case 2: /* indirect */
1680 break;
1681
1682 case 3: /* indirect post-increment */
1683 if (!is_load) {
1684 /* post-increment is not allowed */
1685 goto do_addr_fault;
1686 }
1687 break;
1688
1689 case 4: /* indirect pre-decrement */
1690 if (is_load) {
1691 /* pre-decrement is not allowed */
1692 goto do_addr_fault;
1693 }
1694 /* We want a bare copy of the address reg, without any pre-decrement
1695 adjustment, as gen_lea would provide. */
1696 break;
1697
1698 default:
1699 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
1700 if (IS_NULL_QREG(tmp)) {
1701 goto do_addr_fault;
1702 }
1703 break;
510ff0b7 1704 }
7b542eb9 1705
a7812ae4 1706 addr = tcg_temp_new();
e1f3808e 1707 tcg_gen_mov_i32(addr, tmp);
7b542eb9
LV
1708 incr = tcg_const_i32(opsize_bytes(opsize));
1709
1710 if (is_load) {
1711 /* memory to register */
1712 for (i = 0; i < 16; i++) {
1713 if (mask & (1 << i)) {
1714 r[i] = gen_load(s, opsize, addr, 1);
1715 tcg_gen_add_i32(addr, addr, incr);
1716 }
1717 }
1718 for (i = 0; i < 16; i++) {
1719 if (mask & (1 << i)) {
1720 tcg_gen_mov_i32(mreg(i), r[i]);
1721 tcg_temp_free(r[i]);
1722 }
1723 }
1724 if (mode == 3) {
1725 /* post-increment: movem (An)+,X */
1726 tcg_gen_mov_i32(cpu_aregs[reg0], addr);
1727 }
1728 } else {
1729 /* register to memory */
1730 if (mode == 4) {
1731 /* pre-decrement: movem X,-(An) */
1732 for (i = 15; i >= 0; i--) {
1733 if ((mask << i) & 0x8000) {
1734 tcg_gen_sub_i32(addr, addr, incr);
1735 if (reg0 + 8 == i &&
1736 m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) {
1737 /* M68020+: if the addressing register is the
1738 * register moved to memory, the value written
1739 * is the initial value decremented by the size of
1740 * the operation, regardless of how many actual
1741 * stores have been performed until this point.
1742 * M68000/M68010: the value is the initial value.
1743 */
1744 tmp = tcg_temp_new();
1745 tcg_gen_sub_i32(tmp, cpu_aregs[reg0], incr);
1746 gen_store(s, opsize, addr, tmp);
1747 tcg_temp_free(tmp);
1748 } else {
1749 gen_store(s, opsize, addr, mreg(i));
1750 }
1751 }
1752 }
1753 tcg_gen_mov_i32(cpu_aregs[reg0], addr);
1754 } else {
1755 for (i = 0; i < 16; i++) {
1756 if (mask & (1 << i)) {
1757 gen_store(s, opsize, addr, mreg(i));
1758 tcg_gen_add_i32(addr, addr, incr);
1759 }
e6e5906b 1760 }
e6e5906b
PB
1761 }
1762 }
7b542eb9
LV
1763
1764 tcg_temp_free(incr);
1765 tcg_temp_free(addr);
e6e5906b
PB
1766}
1767
1768DISAS_INSN(bitop_im)
1769{
1770 int opsize;
1771 int op;
e1f3808e 1772 TCGv src1;
e6e5906b
PB
1773 uint32_t mask;
1774 int bitnum;
e1f3808e
PB
1775 TCGv tmp;
1776 TCGv addr;
e6e5906b
PB
1777
1778 if ((insn & 0x38) != 0)
1779 opsize = OS_BYTE;
1780 else
1781 opsize = OS_LONG;
1782 op = (insn >> 6) & 3;
1783
28b68cd7 1784 bitnum = read_im16(env, s);
e6e5906b 1785 if (bitnum & 0xff00) {
d4d79bb1 1786 disas_undef(env, s, insn);
e6e5906b
PB
1787 return;
1788 }
1789
d4d79bb1 1790 SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
e6e5906b 1791
3c980d2e 1792 gen_flush_flags(s);
e6e5906b
PB
1793 if (opsize == OS_BYTE)
1794 bitnum &= 7;
1795 else
1796 bitnum &= 31;
1797 mask = 1 << bitnum;
1798
3c980d2e 1799 tcg_gen_andi_i32(QREG_CC_Z, src1, mask);
620c6cf6 1800
e1f3808e 1801 if (op) {
620c6cf6 1802 tmp = tcg_temp_new();
e1f3808e
PB
1803 switch (op) {
1804 case 1: /* bchg */
1805 tcg_gen_xori_i32(tmp, src1, mask);
1806 break;
1807 case 2: /* bclr */
1808 tcg_gen_andi_i32(tmp, src1, ~mask);
1809 break;
1810 case 3: /* bset */
1811 tcg_gen_ori_i32(tmp, src1, mask);
1812 break;
1813 default: /* btst */
1814 break;
1815 }
d4d79bb1 1816 DEST_EA(env, insn, opsize, tmp, &addr);
620c6cf6 1817 tcg_temp_free(tmp);
e6e5906b 1818 }
e6e5906b 1819}
620c6cf6 1820
e6e5906b
PB
1821DISAS_INSN(arith_im)
1822{
1823 int op;
92c62548 1824 TCGv im;
e1f3808e
PB
1825 TCGv src1;
1826 TCGv dest;
1827 TCGv addr;
92c62548 1828 int opsize;
e6e5906b
PB
1829
1830 op = (insn >> 9) & 7;
92c62548
LV
1831 opsize = insn_opsize(insn);
1832 switch (opsize) {
1833 case OS_BYTE:
1834 im = tcg_const_i32((int8_t)read_im8(env, s));
1835 break;
1836 case OS_WORD:
1837 im = tcg_const_i32((int16_t)read_im16(env, s));
1838 break;
1839 case OS_LONG:
1840 im = tcg_const_i32(read_im32(env, s));
1841 break;
1842 default:
1843 abort();
1844 }
1845 SRC_EA(env, src1, opsize, 1, (op == 6) ? NULL : &addr);
a7812ae4 1846 dest = tcg_temp_new();
e6e5906b
PB
1847 switch (op) {
1848 case 0: /* ori */
92c62548
LV
1849 tcg_gen_or_i32(dest, src1, im);
1850 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
1851 break;
1852 case 1: /* andi */
92c62548
LV
1853 tcg_gen_and_i32(dest, src1, im);
1854 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
1855 break;
1856 case 2: /* subi */
92c62548
LV
1857 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, src1, im);
1858 tcg_gen_sub_i32(dest, src1, im);
1859 gen_update_cc_add(dest, im, opsize);
1860 set_cc_op(s, CC_OP_SUBB + opsize);
e6e5906b
PB
1861 break;
1862 case 3: /* addi */
92c62548
LV
1863 tcg_gen_add_i32(dest, src1, im);
1864 gen_update_cc_add(dest, im, opsize);
1865 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, im);
1866 set_cc_op(s, CC_OP_ADDB + opsize);
e6e5906b
PB
1867 break;
1868 case 5: /* eori */
92c62548
LV
1869 tcg_gen_xor_i32(dest, src1, im);
1870 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
1871 break;
1872 case 6: /* cmpi */
92c62548 1873 gen_update_cc_cmp(s, src1, im, opsize);
e6e5906b
PB
1874 break;
1875 default:
1876 abort();
1877 }
92c62548 1878 tcg_temp_free(im);
e6e5906b 1879 if (op != 6) {
92c62548 1880 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 1881 }
92c62548 1882 tcg_temp_free(dest);
e6e5906b
PB
1883}
1884
14f94406
LV
1885DISAS_INSN(cas)
1886{
1887 int opsize;
1888 TCGv addr;
1889 uint16_t ext;
1890 TCGv load;
1891 TCGv cmp;
1892 TCGMemOp opc;
1893
1894 switch ((insn >> 9) & 3) {
1895 case 1:
1896 opsize = OS_BYTE;
1897 opc = MO_SB;
1898 break;
1899 case 2:
1900 opsize = OS_WORD;
1901 opc = MO_TESW;
1902 break;
1903 case 3:
1904 opsize = OS_LONG;
1905 opc = MO_TESL;
1906 break;
1907 default:
1908 g_assert_not_reached();
1909 }
1910 opc |= MO_ALIGN;
1911
1912 ext = read_im16(env, s);
1913
1914 /* cas Dc,Du,<EA> */
1915
1916 addr = gen_lea(env, s, insn, opsize);
1917 if (IS_NULL_QREG(addr)) {
1918 gen_addr_fault(s);
1919 return;
1920 }
1921
1922 cmp = gen_extend(DREG(ext, 0), opsize, 1);
1923
1924 /* if <EA> == Dc then
1925 * <EA> = Du
1926 * Dc = <EA> (because <EA> == Dc)
1927 * else
1928 * Dc = <EA>
1929 */
1930
1931 load = tcg_temp_new();
1932 tcg_gen_atomic_cmpxchg_i32(load, addr, cmp, DREG(ext, 6),
1933 IS_USER(s), opc);
1934 /* update flags before setting cmp to load */
1935 gen_update_cc_cmp(s, load, cmp, opsize);
1936 gen_partset_reg(opsize, DREG(ext, 0), load);
1937
1938 tcg_temp_free(load);
1939}
1940
1941DISAS_INSN(cas2w)
1942{
1943 uint16_t ext1, ext2;
1944 TCGv addr1, addr2;
1945 TCGv regs;
1946
1947 /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
1948
1949 ext1 = read_im16(env, s);
1950
1951 if (ext1 & 0x8000) {
1952 /* Address Register */
1953 addr1 = AREG(ext1, 12);
1954 } else {
1955 /* Data Register */
1956 addr1 = DREG(ext1, 12);
1957 }
1958
1959 ext2 = read_im16(env, s);
1960 if (ext2 & 0x8000) {
1961 /* Address Register */
1962 addr2 = AREG(ext2, 12);
1963 } else {
1964 /* Data Register */
1965 addr2 = DREG(ext2, 12);
1966 }
1967
1968 /* if (R1) == Dc1 && (R2) == Dc2 then
1969 * (R1) = Du1
1970 * (R2) = Du2
1971 * else
1972 * Dc1 = (R1)
1973 * Dc2 = (R2)
1974 */
1975
1976 regs = tcg_const_i32(REG(ext2, 6) |
1977 (REG(ext1, 6) << 3) |
1978 (REG(ext2, 0) << 6) |
1979 (REG(ext1, 0) << 9));
1980 gen_helper_cas2w(cpu_env, regs, addr1, addr2);
1981 tcg_temp_free(regs);
1982
1983 /* Note that cas2w also assigned to env->cc_op. */
1984 s->cc_op = CC_OP_CMPW;
1985 s->cc_op_synced = 1;
1986}
1987
1988DISAS_INSN(cas2l)
1989{
1990 uint16_t ext1, ext2;
1991 TCGv addr1, addr2, regs;
1992
1993 /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
1994
1995 ext1 = read_im16(env, s);
1996
1997 if (ext1 & 0x8000) {
1998 /* Address Register */
1999 addr1 = AREG(ext1, 12);
2000 } else {
2001 /* Data Register */
2002 addr1 = DREG(ext1, 12);
2003 }
2004
2005 ext2 = read_im16(env, s);
2006 if (ext2 & 0x8000) {
2007 /* Address Register */
2008 addr2 = AREG(ext2, 12);
2009 } else {
2010 /* Data Register */
2011 addr2 = DREG(ext2, 12);
2012 }
2013
2014 /* if (R1) == Dc1 && (R2) == Dc2 then
2015 * (R1) = Du1
2016 * (R2) = Du2
2017 * else
2018 * Dc1 = (R1)
2019 * Dc2 = (R2)
2020 */
2021
2022 regs = tcg_const_i32(REG(ext2, 6) |
2023 (REG(ext1, 6) << 3) |
2024 (REG(ext2, 0) << 6) |
2025 (REG(ext1, 0) << 9));
2026 gen_helper_cas2l(cpu_env, regs, addr1, addr2);
2027 tcg_temp_free(regs);
2028
2029 /* Note that cas2l also assigned to env->cc_op. */
2030 s->cc_op = CC_OP_CMPL;
2031 s->cc_op_synced = 1;
2032}
2033
e6e5906b
PB
2034DISAS_INSN(byterev)
2035{
e1f3808e 2036 TCGv reg;
e6e5906b
PB
2037
2038 reg = DREG(insn, 0);
66896cb8 2039 tcg_gen_bswap32_i32(reg, reg);
e6e5906b
PB
2040}
2041
2042DISAS_INSN(move)
2043{
e1f3808e
PB
2044 TCGv src;
2045 TCGv dest;
e6e5906b
PB
2046 int op;
2047 int opsize;
2048
2049 switch (insn >> 12) {
2050 case 1: /* move.b */
2051 opsize = OS_BYTE;
2052 break;
2053 case 2: /* move.l */
2054 opsize = OS_LONG;
2055 break;
2056 case 3: /* move.w */
2057 opsize = OS_WORD;
2058 break;
2059 default:
2060 abort();
2061 }
d4d79bb1 2062 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b
PB
2063 op = (insn >> 6) & 7;
2064 if (op == 1) {
2065 /* movea */
2066 /* The value will already have been sign extended. */
2067 dest = AREG(insn, 9);
e1f3808e 2068 tcg_gen_mov_i32(dest, src);
e6e5906b
PB
2069 } else {
2070 /* normal move */
2071 uint16_t dest_ea;
2072 dest_ea = ((insn >> 9) & 7) | (op << 3);
d4d79bb1 2073 DEST_EA(env, dest_ea, opsize, src, NULL);
e6e5906b 2074 /* This will be correct because loads sign extend. */
5dbb6784 2075 gen_logic_cc(s, src, opsize);
e6e5906b
PB
2076 }
2077}
2078
2079DISAS_INSN(negx)
2080{
a665a820
RH
2081 TCGv z;
2082 TCGv src;
2083 TCGv addr;
2084 int opsize;
e6e5906b 2085
a665a820
RH
2086 opsize = insn_opsize(insn);
2087 SRC_EA(env, src, opsize, 1, &addr);
2088
2089 gen_flush_flags(s); /* compute old Z */
2090
2091 /* Perform substract with borrow.
2092 * (X, N) = -(src + X);
2093 */
2094
2095 z = tcg_const_i32(0);
2096 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z);
2097 tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X);
2098 tcg_temp_free(z);
2099 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2100
2101 tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
2102
2103 /* Compute signed-overflow for negation. The normal formula for
2104 * subtraction is (res ^ src) & (src ^ dest), but with dest==0
2105 * this simplies to res & src.
2106 */
2107
2108 tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, src);
2109
2110 /* Copy the rest of the results into place. */
2111 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2112 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2113
2114 set_cc_op(s, CC_OP_FLAGS);
2115
2116 /* result is in QREG_CC_N */
2117
2118 DEST_EA(env, insn, opsize, QREG_CC_N, &addr);
e6e5906b
PB
2119}
2120
2121DISAS_INSN(lea)
2122{
e1f3808e
PB
2123 TCGv reg;
2124 TCGv tmp;
e6e5906b
PB
2125
2126 reg = AREG(insn, 9);
d4d79bb1 2127 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 2128 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
2129 gen_addr_fault(s);
2130 return;
2131 }
e1f3808e 2132 tcg_gen_mov_i32(reg, tmp);
e6e5906b
PB
2133}
2134
2135DISAS_INSN(clr)
2136{
2137 int opsize;
2138
7ef25cdd 2139 opsize = insn_opsize(insn);
d4d79bb1 2140 DEST_EA(env, insn, opsize, tcg_const_i32(0), NULL);
5dbb6784 2141 gen_logic_cc(s, tcg_const_i32(0), opsize);
e6e5906b
PB
2142}
2143
e1f3808e 2144static TCGv gen_get_ccr(DisasContext *s)
e6e5906b 2145{
e1f3808e 2146 TCGv dest;
e6e5906b
PB
2147
2148 gen_flush_flags(s);
620c6cf6 2149 update_cc_op(s);
a7812ae4 2150 dest = tcg_temp_new();
620c6cf6 2151 gen_helper_get_ccr(dest, cpu_env);
0633879f
PB
2152 return dest;
2153}
2154
2155DISAS_INSN(move_from_ccr)
2156{
e1f3808e 2157 TCGv ccr;
0633879f
PB
2158
2159 ccr = gen_get_ccr(s);
7c0eb318 2160 DEST_EA(env, insn, OS_WORD, ccr, NULL);
e6e5906b
PB
2161}
2162
2163DISAS_INSN(neg)
2164{
e1f3808e 2165 TCGv src1;
227de713
LV
2166 TCGv dest;
2167 TCGv addr;
2168 int opsize;
e6e5906b 2169
227de713
LV
2170 opsize = insn_opsize(insn);
2171 SRC_EA(env, src1, opsize, 1, &addr);
2172 dest = tcg_temp_new();
2173 tcg_gen_neg_i32(dest, src1);
2174 set_cc_op(s, CC_OP_SUBB + opsize);
2175 gen_update_cc_add(dest, src1, opsize);
2176 tcg_gen_setcondi_i32(TCG_COND_NE, QREG_CC_X, dest, 0);
2177 DEST_EA(env, insn, opsize, dest, &addr);
2178 tcg_temp_free(dest);
e6e5906b
PB
2179}
2180
0633879f
PB
2181static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
2182{
620c6cf6
RH
2183 if (ccr_only) {
2184 tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0);
2185 tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0);
2186 tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1);
2187 tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0);
2188 tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0);
2189 } else {
2190 gen_helper_set_sr(cpu_env, tcg_const_i32(val));
0633879f 2191 }
9fdb533f 2192 set_cc_op(s, CC_OP_FLAGS);
0633879f
PB
2193}
2194
620c6cf6
RH
2195static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn,
2196 int ccr_only)
e6e5906b 2197{
620c6cf6
RH
2198 if ((insn & 0x38) == 0) {
2199 if (ccr_only) {
2200 gen_helper_set_ccr(cpu_env, DREG(insn, 0));
2201 } else {
2202 gen_helper_set_sr(cpu_env, DREG(insn, 0));
2203 }
2204 set_cc_op(s, CC_OP_FLAGS);
2205 } else if ((insn & 0x3f) == 0x3c) {
2206 uint16_t val;
2207 val = read_im16(env, s);
2208 gen_set_sr_im(s, val, ccr_only);
2209 } else {
2210 disas_undef(env, s, insn);
7c0eb318
LV
2211 }
2212}
e6e5906b 2213
7c0eb318 2214
0633879f
PB
2215DISAS_INSN(move_to_ccr)
2216{
620c6cf6 2217 gen_set_sr(env, s, insn, 1);
0633879f
PB
2218}
2219
e6e5906b
PB
2220DISAS_INSN(not)
2221{
ea4f2a84
LV
2222 TCGv src1;
2223 TCGv dest;
2224 TCGv addr;
2225 int opsize;
e6e5906b 2226
ea4f2a84
LV
2227 opsize = insn_opsize(insn);
2228 SRC_EA(env, src1, opsize, 1, &addr);
2229 dest = tcg_temp_new();
2230 tcg_gen_not_i32(dest, src1);
2231 DEST_EA(env, insn, opsize, dest, &addr);
2232 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
2233}
2234
2235DISAS_INSN(swap)
2236{
e1f3808e
PB
2237 TCGv src1;
2238 TCGv src2;
2239 TCGv reg;
e6e5906b 2240
a7812ae4
PB
2241 src1 = tcg_temp_new();
2242 src2 = tcg_temp_new();
e6e5906b 2243 reg = DREG(insn, 0);
e1f3808e
PB
2244 tcg_gen_shli_i32(src1, reg, 16);
2245 tcg_gen_shri_i32(src2, reg, 16);
2246 tcg_gen_or_i32(reg, src1, src2);
5dbb6784 2247 gen_logic_cc(s, reg, OS_LONG);
e6e5906b
PB
2248}
2249
71600eda
LV
2250DISAS_INSN(bkpt)
2251{
2252 gen_exception(s, s->pc - 2, EXCP_DEBUG);
2253}
2254
e6e5906b
PB
2255DISAS_INSN(pea)
2256{
e1f3808e 2257 TCGv tmp;
e6e5906b 2258
d4d79bb1 2259 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 2260 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
2261 gen_addr_fault(s);
2262 return;
2263 }
0633879f 2264 gen_push(s, tmp);
e6e5906b
PB
2265}
2266
2267DISAS_INSN(ext)
2268{
e6e5906b 2269 int op;
e1f3808e
PB
2270 TCGv reg;
2271 TCGv tmp;
e6e5906b
PB
2272
2273 reg = DREG(insn, 0);
2274 op = (insn >> 6) & 7;
a7812ae4 2275 tmp = tcg_temp_new();
e6e5906b 2276 if (op == 3)
e1f3808e 2277 tcg_gen_ext16s_i32(tmp, reg);
e6e5906b 2278 else
e1f3808e 2279 tcg_gen_ext8s_i32(tmp, reg);
e6e5906b
PB
2280 if (op == 2)
2281 gen_partset_reg(OS_WORD, reg, tmp);
2282 else
e1f3808e 2283 tcg_gen_mov_i32(reg, tmp);
5dbb6784 2284 gen_logic_cc(s, tmp, OS_LONG);
e6e5906b
PB
2285}
2286
2287DISAS_INSN(tst)
2288{
2289 int opsize;
e1f3808e 2290 TCGv tmp;
e6e5906b 2291
7ef25cdd 2292 opsize = insn_opsize(insn);
d4d79bb1 2293 SRC_EA(env, tmp, opsize, 1, NULL);
5dbb6784 2294 gen_logic_cc(s, tmp, opsize);
e6e5906b
PB
2295}
2296
2297DISAS_INSN(pulse)
2298{
2299 /* Implemented as a NOP. */
2300}
2301
2302DISAS_INSN(illegal)
2303{
2304 gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
2305}
2306
2307/* ??? This should be atomic. */
2308DISAS_INSN(tas)
2309{
e1f3808e
PB
2310 TCGv dest;
2311 TCGv src1;
2312 TCGv addr;
e6e5906b 2313
a7812ae4 2314 dest = tcg_temp_new();
d4d79bb1 2315 SRC_EA(env, src1, OS_BYTE, 1, &addr);
5dbb6784 2316 gen_logic_cc(s, src1, OS_BYTE);
e1f3808e 2317 tcg_gen_ori_i32(dest, src1, 0x80);
d4d79bb1 2318 DEST_EA(env, insn, OS_BYTE, dest, &addr);
e6e5906b
PB
2319}
2320
2321DISAS_INSN(mull)
2322{
2323 uint16_t ext;
e1f3808e 2324 TCGv src1;
8be95def 2325 int sign;
e6e5906b 2326
28b68cd7 2327 ext = read_im16(env, s);
8be95def
LV
2328
2329 sign = ext & 0x800;
2330
2331 if (ext & 0x400) {
2332 if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
2333 gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
2334 return;
2335 }
2336
2337 SRC_EA(env, src1, OS_LONG, 0, NULL);
2338
2339 if (sign) {
2340 tcg_gen_muls2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
2341 } else {
2342 tcg_gen_mulu2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
2343 }
2344 /* if Dl == Dh, 68040 returns low word */
2345 tcg_gen_mov_i32(DREG(ext, 0), QREG_CC_N);
2346 tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_Z);
2347 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N);
2348
2349 tcg_gen_movi_i32(QREG_CC_V, 0);
2350 tcg_gen_movi_i32(QREG_CC_C, 0);
2351
2352 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
2353 return;
2354 }
d4d79bb1 2355 SRC_EA(env, src1, OS_LONG, 0, NULL);
8be95def
LV
2356 if (m68k_feature(s->env, M68K_FEATURE_M68000)) {
2357 tcg_gen_movi_i32(QREG_CC_C, 0);
2358 if (sign) {
2359 tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
2360 /* QREG_CC_V is -(QREG_CC_V != (QREG_CC_N >> 31)) */
2361 tcg_gen_sari_i32(QREG_CC_Z, QREG_CC_N, 31);
2362 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_Z);
2363 } else {
2364 tcg_gen_mulu2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
2365 /* QREG_CC_V is -(QREG_CC_V != 0), use QREG_CC_C as 0 */
2366 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_C);
2367 }
2368 tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V);
2369 tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_N);
2370
2371 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
2372
2373 set_cc_op(s, CC_OP_FLAGS);
2374 } else {
2375 /* The upper 32 bits of the product are discarded, so
2376 muls.l and mulu.l are functionally equivalent. */
2377 tcg_gen_mul_i32(DREG(ext, 12), src1, DREG(ext, 12));
2378 gen_logic_cc(s, DREG(ext, 12), OS_LONG);
2379 }
e6e5906b
PB
2380}
2381
c630e436 2382static void gen_link(DisasContext *s, uint16_t insn, int32_t offset)
e6e5906b 2383{
e1f3808e
PB
2384 TCGv reg;
2385 TCGv tmp;
e6e5906b 2386
e6e5906b 2387 reg = AREG(insn, 0);
a7812ae4 2388 tmp = tcg_temp_new();
e1f3808e 2389 tcg_gen_subi_i32(tmp, QREG_SP, 4);
0633879f 2390 gen_store(s, OS_LONG, tmp, reg);
c630e436 2391 if ((insn & 7) != 7) {
e1f3808e 2392 tcg_gen_mov_i32(reg, tmp);
c630e436 2393 }
e1f3808e 2394 tcg_gen_addi_i32(QREG_SP, tmp, offset);
c630e436
LV
2395 tcg_temp_free(tmp);
2396}
2397
2398DISAS_INSN(link)
2399{
2400 int16_t offset;
2401
2402 offset = read_im16(env, s);
2403 gen_link(s, insn, offset);
2404}
2405
2406DISAS_INSN(linkl)
2407{
2408 int32_t offset;
2409
2410 offset = read_im32(env, s);
2411 gen_link(s, insn, offset);
e6e5906b
PB
2412}
2413
2414DISAS_INSN(unlk)
2415{
e1f3808e
PB
2416 TCGv src;
2417 TCGv reg;
2418 TCGv tmp;
e6e5906b 2419
a7812ae4 2420 src = tcg_temp_new();
e6e5906b 2421 reg = AREG(insn, 0);
e1f3808e 2422 tcg_gen_mov_i32(src, reg);
0633879f 2423 tmp = gen_load(s, OS_LONG, src, 0);
e1f3808e
PB
2424 tcg_gen_mov_i32(reg, tmp);
2425 tcg_gen_addi_i32(QREG_SP, src, 4);
e6e5906b
PB
2426}
2427
2428DISAS_INSN(nop)
2429{
2430}
2431
2432DISAS_INSN(rts)
2433{
e1f3808e 2434 TCGv tmp;
e6e5906b 2435
0633879f 2436 tmp = gen_load(s, OS_LONG, QREG_SP, 0);
e1f3808e 2437 tcg_gen_addi_i32(QREG_SP, QREG_SP, 4);
e6e5906b
PB
2438 gen_jmp(s, tmp);
2439}
2440
2441DISAS_INSN(jump)
2442{
e1f3808e 2443 TCGv tmp;
e6e5906b
PB
2444
2445 /* Load the target address first to ensure correct exception
2446 behavior. */
d4d79bb1 2447 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 2448 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
2449 gen_addr_fault(s);
2450 return;
2451 }
e6e5906b
PB
2452 if ((insn & 0x40) == 0) {
2453 /* jsr */
351326a6 2454 gen_push(s, tcg_const_i32(s->pc));
e6e5906b
PB
2455 }
2456 gen_jmp(s, tmp);
2457}
2458
2459DISAS_INSN(addsubq)
2460{
8a370c6c 2461 TCGv src;
e1f3808e 2462 TCGv dest;
8a370c6c
LV
2463 TCGv val;
2464 int imm;
e1f3808e 2465 TCGv addr;
8a370c6c 2466 int opsize;
e6e5906b 2467
8a370c6c
LV
2468 if ((insn & 070) == 010) {
2469 /* Operation on address register is always long. */
2470 opsize = OS_LONG;
2471 } else {
2472 opsize = insn_opsize(insn);
2473 }
2474 SRC_EA(env, src, opsize, 1, &addr);
2475 imm = (insn >> 9) & 7;
2476 if (imm == 0) {
2477 imm = 8;
2478 }
2479 val = tcg_const_i32(imm);
a7812ae4 2480 dest = tcg_temp_new();
8a370c6c 2481 tcg_gen_mov_i32(dest, src);
e6e5906b
PB
2482 if ((insn & 0x38) == 0x08) {
2483 /* Don't update condition codes if the destination is an
2484 address register. */
2485 if (insn & 0x0100) {
8a370c6c 2486 tcg_gen_sub_i32(dest, dest, val);
e6e5906b 2487 } else {
8a370c6c 2488 tcg_gen_add_i32(dest, dest, val);
e6e5906b
PB
2489 }
2490 } else {
2491 if (insn & 0x0100) {
8a370c6c
LV
2492 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2493 tcg_gen_sub_i32(dest, dest, val);
2494 set_cc_op(s, CC_OP_SUBB + opsize);
e6e5906b 2495 } else {
8a370c6c
LV
2496 tcg_gen_add_i32(dest, dest, val);
2497 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2498 set_cc_op(s, CC_OP_ADDB + opsize);
e6e5906b 2499 }
8a370c6c 2500 gen_update_cc_add(dest, val, opsize);
e6e5906b 2501 }
8a370c6c 2502 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b
PB
2503}
2504
2505DISAS_INSN(tpf)
2506{
2507 switch (insn & 7) {
2508 case 2: /* One extension word. */
2509 s->pc += 2;
2510 break;
2511 case 3: /* Two extension words. */
2512 s->pc += 4;
2513 break;
2514 case 4: /* No extension words. */
2515 break;
2516 default:
d4d79bb1 2517 disas_undef(env, s, insn);
e6e5906b
PB
2518 }
2519}
2520
2521DISAS_INSN(branch)
2522{
2523 int32_t offset;
2524 uint32_t base;
2525 int op;
42a268c2 2526 TCGLabel *l1;
3b46e624 2527
e6e5906b
PB
2528 base = s->pc;
2529 op = (insn >> 8) & 0xf;
2530 offset = (int8_t)insn;
2531 if (offset == 0) {
28b68cd7 2532 offset = (int16_t)read_im16(env, s);
e6e5906b 2533 } else if (offset == -1) {
d4d79bb1 2534 offset = read_im32(env, s);
e6e5906b
PB
2535 }
2536 if (op == 1) {
2537 /* bsr */
351326a6 2538 gen_push(s, tcg_const_i32(s->pc));
e6e5906b 2539 }
e6e5906b
PB
2540 if (op > 1) {
2541 /* Bcc */
2542 l1 = gen_new_label();
2543 gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
2544 gen_jmp_tb(s, 1, base + offset);
2545 gen_set_label(l1);
2546 gen_jmp_tb(s, 0, s->pc);
2547 } else {
2548 /* Unconditional branch. */
2549 gen_jmp_tb(s, 0, base + offset);
2550 }
2551}
2552
2553DISAS_INSN(moveq)
2554{
e1f3808e 2555 uint32_t val;
e6e5906b 2556
e1f3808e
PB
2557 val = (int8_t)insn;
2558 tcg_gen_movi_i32(DREG(insn, 9), val);
5dbb6784 2559 gen_logic_cc(s, tcg_const_i32(val), OS_LONG);
e6e5906b
PB
2560}
2561
2562DISAS_INSN(mvzs)
2563{
2564 int opsize;
e1f3808e
PB
2565 TCGv src;
2566 TCGv reg;
e6e5906b
PB
2567
2568 if (insn & 0x40)
2569 opsize = OS_WORD;
2570 else
2571 opsize = OS_BYTE;
d4d79bb1 2572 SRC_EA(env, src, opsize, (insn & 0x80) == 0, NULL);
e6e5906b 2573 reg = DREG(insn, 9);
e1f3808e 2574 tcg_gen_mov_i32(reg, src);
5dbb6784 2575 gen_logic_cc(s, src, opsize);
e6e5906b
PB
2576}
2577
2578DISAS_INSN(or)
2579{
e1f3808e
PB
2580 TCGv reg;
2581 TCGv dest;
2582 TCGv src;
2583 TCGv addr;
020a4659 2584 int opsize;
e6e5906b 2585
020a4659
LV
2586 opsize = insn_opsize(insn);
2587 reg = gen_extend(DREG(insn, 9), opsize, 0);
a7812ae4 2588 dest = tcg_temp_new();
e6e5906b 2589 if (insn & 0x100) {
020a4659 2590 SRC_EA(env, src, opsize, 0, &addr);
e1f3808e 2591 tcg_gen_or_i32(dest, src, reg);
020a4659 2592 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 2593 } else {
020a4659 2594 SRC_EA(env, src, opsize, 0, NULL);
e1f3808e 2595 tcg_gen_or_i32(dest, src, reg);
020a4659 2596 gen_partset_reg(opsize, DREG(insn, 9), dest);
e6e5906b 2597 }
020a4659 2598 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
2599}
2600
2601DISAS_INSN(suba)
2602{
e1f3808e
PB
2603 TCGv src;
2604 TCGv reg;
e6e5906b 2605
415f4b62 2606 SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
e6e5906b 2607 reg = AREG(insn, 9);
e1f3808e 2608 tcg_gen_sub_i32(reg, reg, src);
e6e5906b
PB
2609}
2610
a665a820 2611static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
e6e5906b 2612{
a665a820
RH
2613 TCGv tmp;
2614
2615 gen_flush_flags(s); /* compute old Z */
2616
2617 /* Perform substract with borrow.
2618 * (X, N) = dest - (src + X);
2619 */
2620
2621 tmp = tcg_const_i32(0);
2622 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, tmp, QREG_CC_X, tmp);
2623 tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, dest, tmp, QREG_CC_N, QREG_CC_X);
2624 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2625 tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
2626
2627 /* Compute signed-overflow for substract. */
2628
2629 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, dest);
2630 tcg_gen_xor_i32(tmp, dest, src);
2631 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, tmp);
2632 tcg_temp_free(tmp);
2633
2634 /* Copy the rest of the results into place. */
2635 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2636 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2637
2638 set_cc_op(s, CC_OP_FLAGS);
2639
2640 /* result is in QREG_CC_N */
2641}
2642
2643DISAS_INSN(subx_reg)
2644{
2645 TCGv dest;
e1f3808e 2646 TCGv src;
a665a820 2647 int opsize;
e6e5906b 2648
a665a820
RH
2649 opsize = insn_opsize(insn);
2650
2651 src = gen_extend(DREG(insn, 0), opsize, 1);
2652 dest = gen_extend(DREG(insn, 9), opsize, 1);
2653
2654 gen_subx(s, src, dest, opsize);
2655
2656 gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
2657}
2658
2659DISAS_INSN(subx_mem)
2660{
2661 TCGv src;
2662 TCGv addr_src;
2663 TCGv dest;
2664 TCGv addr_dest;
2665 int opsize;
2666
2667 opsize = insn_opsize(insn);
2668
2669 addr_src = AREG(insn, 0);
2670 tcg_gen_subi_i32(addr_src, addr_src, opsize);
2671 src = gen_load(s, opsize, addr_src, 1);
2672
2673 addr_dest = AREG(insn, 9);
2674 tcg_gen_subi_i32(addr_dest, addr_dest, opsize);
2675 dest = gen_load(s, opsize, addr_dest, 1);
2676
2677 gen_subx(s, src, dest, opsize);
2678
2679 gen_store(s, opsize, addr_dest, QREG_CC_N);
e6e5906b
PB
2680}
2681
2682DISAS_INSN(mov3q)
2683{
e1f3808e 2684 TCGv src;
e6e5906b
PB
2685 int val;
2686
2687 val = (insn >> 9) & 7;
2688 if (val == 0)
2689 val = -1;
351326a6 2690 src = tcg_const_i32(val);
5dbb6784 2691 gen_logic_cc(s, src, OS_LONG);
d4d79bb1 2692 DEST_EA(env, insn, OS_LONG, src, NULL);
e6e5906b
PB
2693}
2694
2695DISAS_INSN(cmp)
2696{
e1f3808e
PB
2697 TCGv src;
2698 TCGv reg;
e6e5906b
PB
2699 int opsize;
2700
5dbb6784 2701 opsize = insn_opsize(insn);
ff99b952
LV
2702 SRC_EA(env, src, opsize, 1, NULL);
2703 reg = gen_extend(DREG(insn, 9), opsize, 1);
2704 gen_update_cc_cmp(s, reg, src, opsize);
e6e5906b
PB
2705}
2706
2707DISAS_INSN(cmpa)
2708{
2709 int opsize;
e1f3808e
PB
2710 TCGv src;
2711 TCGv reg;
e6e5906b
PB
2712
2713 if (insn & 0x100) {
2714 opsize = OS_LONG;
2715 } else {
2716 opsize = OS_WORD;
2717 }
d4d79bb1 2718 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b 2719 reg = AREG(insn, 9);
5436c29d 2720 gen_update_cc_cmp(s, reg, src, OS_LONG);
e6e5906b
PB
2721}
2722
817af1c7
LV
2723DISAS_INSN(cmpm)
2724{
2725 int opsize = insn_opsize(insn);
2726 TCGv src, dst;
2727
2728 /* Post-increment load (mode 3) from Ay. */
2729 src = gen_ea_mode(env, s, 3, REG(insn, 0), opsize,
2730 NULL_QREG, NULL, EA_LOADS);
2731 /* Post-increment load (mode 3) from Ax. */
2732 dst = gen_ea_mode(env, s, 3, REG(insn, 9), opsize,
2733 NULL_QREG, NULL, EA_LOADS);
2734
2735 gen_update_cc_cmp(s, dst, src, opsize);
2736}
2737
e6e5906b
PB
2738DISAS_INSN(eor)
2739{
e1f3808e 2740 TCGv src;
e1f3808e
PB
2741 TCGv dest;
2742 TCGv addr;
eec37aec 2743 int opsize;
e6e5906b 2744
eec37aec
LV
2745 opsize = insn_opsize(insn);
2746
2747 SRC_EA(env, src, opsize, 0, &addr);
a7812ae4 2748 dest = tcg_temp_new();
eec37aec
LV
2749 tcg_gen_xor_i32(dest, src, DREG(insn, 9));
2750 gen_logic_cc(s, dest, opsize);
2751 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b
PB
2752}
2753
29cf437d
LV
2754static void do_exg(TCGv reg1, TCGv reg2)
2755{
2756 TCGv temp = tcg_temp_new();
2757 tcg_gen_mov_i32(temp, reg1);
2758 tcg_gen_mov_i32(reg1, reg2);
2759 tcg_gen_mov_i32(reg2, temp);
2760 tcg_temp_free(temp);
2761}
2762
c090c97d 2763DISAS_INSN(exg_dd)
29cf437d
LV
2764{
2765 /* exchange Dx and Dy */
2766 do_exg(DREG(insn, 9), DREG(insn, 0));
2767}
2768
c090c97d 2769DISAS_INSN(exg_aa)
29cf437d
LV
2770{
2771 /* exchange Ax and Ay */
2772 do_exg(AREG(insn, 9), AREG(insn, 0));
2773}
2774
2775DISAS_INSN(exg_da)
2776{
2777 /* exchange Dx and Ay */
2778 do_exg(DREG(insn, 9), AREG(insn, 0));
2779}
2780
e6e5906b
PB
2781DISAS_INSN(and)
2782{
e1f3808e
PB
2783 TCGv src;
2784 TCGv reg;
2785 TCGv dest;
2786 TCGv addr;
52dc23c5 2787 int opsize;
e6e5906b 2788
a7812ae4 2789 dest = tcg_temp_new();
52dc23c5
LV
2790
2791 opsize = insn_opsize(insn);
2792 reg = DREG(insn, 9);
e6e5906b 2793 if (insn & 0x100) {
52dc23c5 2794 SRC_EA(env, src, opsize, 0, &addr);
e1f3808e 2795 tcg_gen_and_i32(dest, src, reg);
52dc23c5 2796 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 2797 } else {
52dc23c5 2798 SRC_EA(env, src, opsize, 0, NULL);
e1f3808e 2799 tcg_gen_and_i32(dest, src, reg);
52dc23c5 2800 gen_partset_reg(opsize, reg, dest);
e6e5906b 2801 }
52dc23c5
LV
2802 tcg_temp_free(dest);
2803 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
2804}
2805
2806DISAS_INSN(adda)
2807{
e1f3808e
PB
2808 TCGv src;
2809 TCGv reg;
e6e5906b 2810
415f4b62 2811 SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
e6e5906b 2812 reg = AREG(insn, 9);
e1f3808e 2813 tcg_gen_add_i32(reg, reg, src);
e6e5906b
PB
2814}
2815
a665a820 2816static inline void gen_addx(DisasContext *s, TCGv src, TCGv dest, int opsize)
e6e5906b 2817{
a665a820
RH
2818 TCGv tmp;
2819
2820 gen_flush_flags(s); /* compute old Z */
2821
2822 /* Perform addition with carry.
2823 * (X, N) = src + dest + X;
2824 */
2825
2826 tmp = tcg_const_i32(0);
2827 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_X, tmp, dest, tmp);
2828 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, tmp);
2829 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2830
2831 /* Compute signed-overflow for addition. */
2832
2833 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
2834 tcg_gen_xor_i32(tmp, dest, src);
2835 tcg_gen_andc_i32(QREG_CC_V, QREG_CC_V, tmp);
2836 tcg_temp_free(tmp);
2837
2838 /* Copy the rest of the results into place. */
2839 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2840 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2841
2842 set_cc_op(s, CC_OP_FLAGS);
2843
2844 /* result is in QREG_CC_N */
2845}
2846
2847DISAS_INSN(addx_reg)
2848{
2849 TCGv dest;
e1f3808e 2850 TCGv src;
a665a820 2851 int opsize;
e6e5906b 2852
a665a820
RH
2853 opsize = insn_opsize(insn);
2854
2855 dest = gen_extend(DREG(insn, 9), opsize, 1);
2856 src = gen_extend(DREG(insn, 0), opsize, 1);
2857
2858 gen_addx(s, src, dest, opsize);
2859
2860 gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
2861}
2862
2863DISAS_INSN(addx_mem)
2864{
2865 TCGv src;
2866 TCGv addr_src;
2867 TCGv dest;
2868 TCGv addr_dest;
2869 int opsize;
2870
2871 opsize = insn_opsize(insn);
2872
2873 addr_src = AREG(insn, 0);
2874 tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
2875 src = gen_load(s, opsize, addr_src, 1);
2876
2877 addr_dest = AREG(insn, 9);
2878 tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
2879 dest = gen_load(s, opsize, addr_dest, 1);
2880
2881 gen_addx(s, src, dest, opsize);
2882
2883 gen_store(s, opsize, addr_dest, QREG_CC_N);
e6e5906b
PB
2884}
2885
e1f3808e 2886/* TODO: This could be implemented without helper functions. */
e6e5906b
PB
2887DISAS_INSN(shift_im)
2888{
e1f3808e 2889 TCGv reg;
e6e5906b 2890 int tmp;
e1f3808e 2891 TCGv shift;
e6e5906b 2892
620c6cf6
RH
2893 set_cc_op(s, CC_OP_FLAGS);
2894
e6e5906b
PB
2895 reg = DREG(insn, 0);
2896 tmp = (insn >> 9) & 7;
2897 if (tmp == 0)
e1f3808e 2898 tmp = 8;
351326a6 2899 shift = tcg_const_i32(tmp);
e1f3808e 2900 /* No need to flush flags becuse we know we will set C flag. */
e6e5906b 2901 if (insn & 0x100) {
e1f3808e 2902 gen_helper_shl_cc(reg, cpu_env, reg, shift);
e6e5906b
PB
2903 } else {
2904 if (insn & 8) {
e1f3808e 2905 gen_helper_shr_cc(reg, cpu_env, reg, shift);
e6e5906b 2906 } else {
e1f3808e 2907 gen_helper_sar_cc(reg, cpu_env, reg, shift);
e6e5906b
PB
2908 }
2909 }
2910}
2911
2912DISAS_INSN(shift_reg)
2913{
e1f3808e
PB
2914 TCGv reg;
2915 TCGv shift;
e6e5906b
PB
2916
2917 reg = DREG(insn, 0);
e1f3808e 2918 shift = DREG(insn, 9);
e6e5906b 2919 if (insn & 0x100) {
e1f3808e 2920 gen_helper_shl_cc(reg, cpu_env, reg, shift);
e6e5906b
PB
2921 } else {
2922 if (insn & 8) {
e1f3808e 2923 gen_helper_shr_cc(reg, cpu_env, reg, shift);
e6e5906b 2924 } else {
e1f3808e 2925 gen_helper_sar_cc(reg, cpu_env, reg, shift);
e6e5906b
PB
2926 }
2927 }
620c6cf6 2928 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
2929}
2930
2931DISAS_INSN(ff1)
2932{
e1f3808e 2933 TCGv reg;
821f7e76 2934 reg = DREG(insn, 0);
5dbb6784 2935 gen_logic_cc(s, reg, OS_LONG);
e1f3808e 2936 gen_helper_ff1(reg, reg);
e6e5906b
PB
2937}
2938
e1f3808e 2939static TCGv gen_get_sr(DisasContext *s)
0633879f 2940{
e1f3808e
PB
2941 TCGv ccr;
2942 TCGv sr;
0633879f
PB
2943
2944 ccr = gen_get_ccr(s);
a7812ae4 2945 sr = tcg_temp_new();
e1f3808e
PB
2946 tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
2947 tcg_gen_or_i32(sr, sr, ccr);
0633879f
PB
2948 return sr;
2949}
2950
e6e5906b
PB
2951DISAS_INSN(strldsr)
2952{
2953 uint16_t ext;
2954 uint32_t addr;
2955
2956 addr = s->pc - 2;
28b68cd7 2957 ext = read_im16(env, s);
0633879f 2958 if (ext != 0x46FC) {
e6e5906b 2959 gen_exception(s, addr, EXCP_UNSUPPORTED);
0633879f
PB
2960 return;
2961 }
28b68cd7 2962 ext = read_im16(env, s);
0633879f 2963 if (IS_USER(s) || (ext & SR_S) == 0) {
e6e5906b 2964 gen_exception(s, addr, EXCP_PRIVILEGE);
0633879f
PB
2965 return;
2966 }
2967 gen_push(s, gen_get_sr(s));
2968 gen_set_sr_im(s, ext, 0);
e6e5906b
PB
2969}
2970
2971DISAS_INSN(move_from_sr)
2972{
e1f3808e 2973 TCGv sr;
0633879f 2974
7c0eb318 2975 if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) {
0633879f
PB
2976 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2977 return;
2978 }
2979 sr = gen_get_sr(s);
7c0eb318 2980 DEST_EA(env, insn, OS_WORD, sr, NULL);
e6e5906b
PB
2981}
2982
2983DISAS_INSN(move_to_sr)
2984{
0633879f
PB
2985 if (IS_USER(s)) {
2986 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2987 return;
2988 }
620c6cf6 2989 gen_set_sr(env, s, insn, 0);
0633879f 2990 gen_lookup_tb(s);
e6e5906b
PB
2991}
2992
2993DISAS_INSN(move_from_usp)
2994{
0633879f
PB
2995 if (IS_USER(s)) {
2996 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2997 return;
2998 }
2a8327e8
GU
2999 tcg_gen_ld_i32(AREG(insn, 0), cpu_env,
3000 offsetof(CPUM68KState, sp[M68K_USP]));
e6e5906b
PB
3001}
3002
3003DISAS_INSN(move_to_usp)
3004{
0633879f
PB
3005 if (IS_USER(s)) {
3006 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
3007 return;
3008 }
2a8327e8
GU
3009 tcg_gen_st_i32(AREG(insn, 0), cpu_env,
3010 offsetof(CPUM68KState, sp[M68K_USP]));
e6e5906b
PB
3011}
3012
3013DISAS_INSN(halt)
3014{
e1f3808e 3015 gen_exception(s, s->pc, EXCP_HALT_INSN);
e6e5906b
PB
3016}
3017
3018DISAS_INSN(stop)
3019{
0633879f
PB
3020 uint16_t ext;
3021
3022 if (IS_USER(s)) {
3023 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
3024 return;
3025 }
3026
28b68cd7 3027 ext = read_im16(env, s);
0633879f
PB
3028
3029 gen_set_sr_im(s, ext, 0);
259186a7 3030 tcg_gen_movi_i32(cpu_halted, 1);
e1f3808e 3031 gen_exception(s, s->pc, EXCP_HLT);
e6e5906b
PB
3032}
3033
3034DISAS_INSN(rte)
3035{
0633879f
PB
3036 if (IS_USER(s)) {
3037 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
3038 return;
3039 }
3040 gen_exception(s, s->pc - 2, EXCP_RTE);
e6e5906b
PB
3041}
3042
3043DISAS_INSN(movec)
3044{
0633879f 3045 uint16_t ext;
e1f3808e 3046 TCGv reg;
0633879f
PB
3047
3048 if (IS_USER(s)) {
3049 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
3050 return;
3051 }
3052
28b68cd7 3053 ext = read_im16(env, s);
0633879f
PB
3054
3055 if (ext & 0x8000) {
3056 reg = AREG(ext, 12);
3057 } else {
3058 reg = DREG(ext, 12);
3059 }
e1f3808e 3060 gen_helper_movec(cpu_env, tcg_const_i32(ext & 0xfff), reg);
0633879f 3061 gen_lookup_tb(s);
e6e5906b
PB
3062}
3063
3064DISAS_INSN(intouch)
3065{
0633879f
PB
3066 if (IS_USER(s)) {
3067 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
3068 return;
3069 }
3070 /* ICache fetch. Implement as no-op. */
e6e5906b
PB
3071}
3072
3073DISAS_INSN(cpushl)
3074{
0633879f
PB
3075 if (IS_USER(s)) {
3076 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
3077 return;
3078 }
3079 /* Cache push/invalidate. Implement as no-op. */
e6e5906b
PB
3080}
3081
3082DISAS_INSN(wddata)
3083{
3084 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
3085}
3086
3087DISAS_INSN(wdebug)
3088{
a47dddd7
AF
3089 M68kCPU *cpu = m68k_env_get_cpu(env);
3090
0633879f
PB
3091 if (IS_USER(s)) {
3092 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
3093 return;
3094 }
3095 /* TODO: Implement wdebug. */
a47dddd7 3096 cpu_abort(CPU(cpu), "WDEBUG not implemented");
e6e5906b
PB
3097}
3098
3099DISAS_INSN(trap)
3100{
3101 gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf));
3102}
3103
3104/* ??? FP exceptions are not implemented. Most exceptions are deferred until
3105 immediately before the next FP instruction is executed. */
3106DISAS_INSN(fpu)
3107{
3108 uint16_t ext;
a7812ae4 3109 int32_t offset;
e6e5906b 3110 int opmode;
a7812ae4
PB
3111 TCGv_i64 src;
3112 TCGv_i64 dest;
3113 TCGv_i64 res;
3114 TCGv tmp32;
e6e5906b 3115 int round;
a7812ae4 3116 int set_dest;
e6e5906b
PB
3117 int opsize;
3118
28b68cd7 3119 ext = read_im16(env, s);
e6e5906b
PB
3120 opmode = ext & 0x7f;
3121 switch ((ext >> 13) & 7) {
3122 case 0: case 2:
3123 break;
3124 case 1:
3125 goto undef;
3126 case 3: /* fmove out */
3127 src = FREG(ext, 7);
a7812ae4 3128 tmp32 = tcg_temp_new_i32();
e6e5906b
PB
3129 /* fmove */
3130 /* ??? TODO: Proper behavior on overflow. */
3131 switch ((ext >> 10) & 7) {
3132 case 0:
3133 opsize = OS_LONG;
a7812ae4 3134 gen_helper_f64_to_i32(tmp32, cpu_env, src);
e6e5906b
PB
3135 break;
3136 case 1:
3137 opsize = OS_SINGLE;
a7812ae4 3138 gen_helper_f64_to_f32(tmp32, cpu_env, src);
e6e5906b
PB
3139 break;
3140 case 4:
3141 opsize = OS_WORD;
a7812ae4 3142 gen_helper_f64_to_i32(tmp32, cpu_env, src);
e6e5906b 3143 break;
a7812ae4
PB
3144 case 5: /* OS_DOUBLE */
3145 tcg_gen_mov_i32(tmp32, AREG(insn, 0));
c59b97aa 3146 switch ((insn >> 3) & 7) {
a7812ae4
PB
3147 case 2:
3148 case 3:
243ee8f7 3149 break;
a7812ae4
PB
3150 case 4:
3151 tcg_gen_addi_i32(tmp32, tmp32, -8);
3152 break;
3153 case 5:
d4d79bb1 3154 offset = cpu_ldsw_code(env, s->pc);
a7812ae4
PB
3155 s->pc += 2;
3156 tcg_gen_addi_i32(tmp32, tmp32, offset);
3157 break;
3158 default:
3159 goto undef;
3160 }
3161 gen_store64(s, tmp32, src);
c59b97aa 3162 switch ((insn >> 3) & 7) {
a7812ae4
PB
3163 case 3:
3164 tcg_gen_addi_i32(tmp32, tmp32, 8);
3165 tcg_gen_mov_i32(AREG(insn, 0), tmp32);
3166 break;
3167 case 4:
3168 tcg_gen_mov_i32(AREG(insn, 0), tmp32);
3169 break;
3170 }
3171 tcg_temp_free_i32(tmp32);
3172 return;
e6e5906b
PB
3173 case 6:
3174 opsize = OS_BYTE;
a7812ae4 3175 gen_helper_f64_to_i32(tmp32, cpu_env, src);
e6e5906b
PB
3176 break;
3177 default:
3178 goto undef;
3179 }
d4d79bb1 3180 DEST_EA(env, insn, opsize, tmp32, NULL);
a7812ae4 3181 tcg_temp_free_i32(tmp32);
e6e5906b
PB
3182 return;
3183 case 4: /* fmove to control register. */
3184 switch ((ext >> 10) & 7) {
3185 case 4: /* FPCR */
3186 /* Not implemented. Ignore writes. */
3187 break;
3188 case 1: /* FPIAR */
3189 case 2: /* FPSR */
3190 default:
3191 cpu_abort(NULL, "Unimplemented: fmove to control %d",
3192 (ext >> 10) & 7);
3193 }
3194 break;
3195 case 5: /* fmove from control register. */
3196 switch ((ext >> 10) & 7) {
3197 case 4: /* FPCR */
3198 /* Not implemented. Always return zero. */
351326a6 3199 tmp32 = tcg_const_i32(0);
e6e5906b
PB
3200 break;
3201 case 1: /* FPIAR */
3202 case 2: /* FPSR */
3203 default:
3204 cpu_abort(NULL, "Unimplemented: fmove from control %d",
3205 (ext >> 10) & 7);
3206 goto undef;
3207 }
d4d79bb1 3208 DEST_EA(env, insn, OS_LONG, tmp32, NULL);
e6e5906b 3209 break;
5fafdf24 3210 case 6: /* fmovem */
e6e5906b
PB
3211 case 7:
3212 {
e1f3808e
PB
3213 TCGv addr;
3214 uint16_t mask;
3215 int i;
3216 if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
3217 goto undef;
d4d79bb1 3218 tmp32 = gen_lea(env, s, insn, OS_LONG);
a7812ae4 3219 if (IS_NULL_QREG(tmp32)) {
e1f3808e
PB
3220 gen_addr_fault(s);
3221 return;
3222 }
a7812ae4
PB
3223 addr = tcg_temp_new_i32();
3224 tcg_gen_mov_i32(addr, tmp32);
e1f3808e
PB
3225 mask = 0x80;
3226 for (i = 0; i < 8; i++) {
3227 if (ext & mask) {
e1f3808e
PB
3228 dest = FREG(i, 0);
3229 if (ext & (1 << 13)) {
3230 /* store */
3231 tcg_gen_qemu_stf64(dest, addr, IS_USER(s));
3232 } else {
3233 /* load */
3234 tcg_gen_qemu_ldf64(dest, addr, IS_USER(s));
3235 }
3236 if (ext & (mask - 1))
3237 tcg_gen_addi_i32(addr, addr, 8);
e6e5906b 3238 }
e1f3808e 3239 mask >>= 1;
e6e5906b 3240 }
18307f26 3241 tcg_temp_free_i32(addr);
e6e5906b
PB
3242 }
3243 return;
3244 }
3245 if (ext & (1 << 14)) {
e6e5906b
PB
3246 /* Source effective address. */
3247 switch ((ext >> 10) & 7) {
3248 case 0: opsize = OS_LONG; break;
3249 case 1: opsize = OS_SINGLE; break;
3250 case 4: opsize = OS_WORD; break;
3251 case 5: opsize = OS_DOUBLE; break;
3252 case 6: opsize = OS_BYTE; break;
3253 default:
3254 goto undef;
3255 }
e6e5906b 3256 if (opsize == OS_DOUBLE) {
a7812ae4
PB
3257 tmp32 = tcg_temp_new_i32();
3258 tcg_gen_mov_i32(tmp32, AREG(insn, 0));
c59b97aa 3259 switch ((insn >> 3) & 7) {
a7812ae4
PB
3260 case 2:
3261 case 3:
243ee8f7 3262 break;
a7812ae4
PB
3263 case 4:
3264 tcg_gen_addi_i32(tmp32, tmp32, -8);
3265 break;
3266 case 5:
d4d79bb1 3267 offset = cpu_ldsw_code(env, s->pc);
a7812ae4
PB
3268 s->pc += 2;
3269 tcg_gen_addi_i32(tmp32, tmp32, offset);
3270 break;
3271 case 7:
d4d79bb1 3272 offset = cpu_ldsw_code(env, s->pc);
a7812ae4
PB
3273 offset += s->pc - 2;
3274 s->pc += 2;
3275 tcg_gen_addi_i32(tmp32, tmp32, offset);
3276 break;
3277 default:
3278 goto undef;
3279 }
3280 src = gen_load64(s, tmp32);
c59b97aa 3281 switch ((insn >> 3) & 7) {
a7812ae4
PB
3282 case 3:
3283 tcg_gen_addi_i32(tmp32, tmp32, 8);
3284 tcg_gen_mov_i32(AREG(insn, 0), tmp32);
3285 break;
3286 case 4:
3287 tcg_gen_mov_i32(AREG(insn, 0), tmp32);
3288 break;
3289 }
3290 tcg_temp_free_i32(tmp32);
e6e5906b 3291 } else {
d4d79bb1 3292 SRC_EA(env, tmp32, opsize, 1, NULL);
a7812ae4 3293 src = tcg_temp_new_i64();
e6e5906b
PB
3294 switch (opsize) {
3295 case OS_LONG:
3296 case OS_WORD:
3297 case OS_BYTE:
a7812ae4 3298 gen_helper_i32_to_f64(src, cpu_env, tmp32);
e6e5906b
PB
3299 break;
3300 case OS_SINGLE:
a7812ae4 3301 gen_helper_f32_to_f64(src, cpu_env, tmp32);
e6e5906b
PB
3302 break;
3303 }
3304 }
3305 } else {
3306 /* Source register. */
3307 src = FREG(ext, 10);
3308 }
3309 dest = FREG(ext, 7);
a7812ae4 3310 res = tcg_temp_new_i64();
e6e5906b 3311 if (opmode != 0x3a)
e1f3808e 3312 tcg_gen_mov_f64(res, dest);
e6e5906b 3313 round = 1;
a7812ae4 3314 set_dest = 1;
e6e5906b
PB
3315 switch (opmode) {
3316 case 0: case 0x40: case 0x44: /* fmove */
e1f3808e 3317 tcg_gen_mov_f64(res, src);
e6e5906b
PB
3318 break;
3319 case 1: /* fint */
e1f3808e 3320 gen_helper_iround_f64(res, cpu_env, src);
e6e5906b
PB
3321 round = 0;
3322 break;
3323 case 3: /* fintrz */
e1f3808e 3324 gen_helper_itrunc_f64(res, cpu_env, src);
e6e5906b
PB
3325 round = 0;
3326 break;
3327 case 4: case 0x41: case 0x45: /* fsqrt */
e1f3808e 3328 gen_helper_sqrt_f64(res, cpu_env, src);
e6e5906b
PB
3329 break;
3330 case 0x18: case 0x58: case 0x5c: /* fabs */
e1f3808e 3331 gen_helper_abs_f64(res, src);
e6e5906b
PB
3332 break;
3333 case 0x1a: case 0x5a: case 0x5e: /* fneg */
e1f3808e 3334 gen_helper_chs_f64(res, src);
e6e5906b
PB
3335 break;
3336 case 0x20: case 0x60: case 0x64: /* fdiv */
e1f3808e 3337 gen_helper_div_f64(res, cpu_env, res, src);
e6e5906b
PB
3338 break;
3339 case 0x22: case 0x62: case 0x66: /* fadd */
e1f3808e 3340 gen_helper_add_f64(res, cpu_env, res, src);
e6e5906b
PB
3341 break;
3342 case 0x23: case 0x63: case 0x67: /* fmul */
e1f3808e 3343 gen_helper_mul_f64(res, cpu_env, res, src);
e6e5906b
PB
3344 break;
3345 case 0x28: case 0x68: case 0x6c: /* fsub */
e1f3808e 3346 gen_helper_sub_f64(res, cpu_env, res, src);
e6e5906b
PB
3347 break;
3348 case 0x38: /* fcmp */
e1f3808e 3349 gen_helper_sub_cmp_f64(res, cpu_env, res, src);
a7812ae4 3350 set_dest = 0;
e6e5906b
PB
3351 round = 0;
3352 break;
3353 case 0x3a: /* ftst */
e1f3808e 3354 tcg_gen_mov_f64(res, src);
a7812ae4 3355 set_dest = 0;
e6e5906b
PB
3356 round = 0;
3357 break;
3358 default:
3359 goto undef;
3360 }
a7812ae4
PB
3361 if (ext & (1 << 14)) {
3362 tcg_temp_free_i64(src);
3363 }
e6e5906b
PB
3364 if (round) {
3365 if (opmode & 0x40) {
3366 if ((opmode & 0x4) != 0)
3367 round = 0;
3368 } else if ((s->fpcr & M68K_FPCR_PREC) == 0) {
3369 round = 0;
3370 }
3371 }
3372 if (round) {
a7812ae4 3373 TCGv tmp = tcg_temp_new_i32();
e1f3808e
PB
3374 gen_helper_f64_to_f32(tmp, cpu_env, res);
3375 gen_helper_f32_to_f64(res, cpu_env, tmp);
a7812ae4 3376 tcg_temp_free_i32(tmp);
5fafdf24 3377 }
e1f3808e 3378 tcg_gen_mov_f64(QREG_FP_RESULT, res);
a7812ae4 3379 if (set_dest) {
e1f3808e 3380 tcg_gen_mov_f64(dest, res);
e6e5906b 3381 }
a7812ae4 3382 tcg_temp_free_i64(res);
e6e5906b
PB
3383 return;
3384undef:
a7812ae4 3385 /* FIXME: Is this right for offset addressing modes? */
e6e5906b 3386 s->pc -= 2;
d4d79bb1 3387 disas_undef_fpu(env, s, insn);
e6e5906b
PB
3388}
3389
3390DISAS_INSN(fbcc)
3391{
3392 uint32_t offset;
3393 uint32_t addr;
e1f3808e 3394 TCGv flag;
42a268c2 3395 TCGLabel *l1;
e6e5906b
PB
3396
3397 addr = s->pc;
d4d79bb1 3398 offset = cpu_ldsw_code(env, s->pc);
e6e5906b
PB
3399 s->pc += 2;
3400 if (insn & (1 << 6)) {
28b68cd7 3401 offset = (offset << 16) | read_im16(env, s);
e6e5906b
PB
3402 }
3403
3404 l1 = gen_new_label();
3405 /* TODO: Raise BSUN exception. */
a7812ae4 3406 flag = tcg_temp_new();
e1f3808e 3407 gen_helper_compare_f64(flag, cpu_env, QREG_FP_RESULT);
e6e5906b
PB
3408 /* Jump to l1 if condition is true. */
3409 switch (insn & 0xf) {
3410 case 0: /* f */
3411 break;
3412 case 1: /* eq (=0) */
e1f3808e 3413 tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3414 break;
3415 case 2: /* ogt (=1) */
e1f3808e 3416 tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(1), l1);
e6e5906b
PB
3417 break;
3418 case 3: /* oge (=0 or =1) */
e1f3808e 3419 tcg_gen_brcond_i32(TCG_COND_LEU, flag, tcg_const_i32(1), l1);
e6e5906b
PB
3420 break;
3421 case 4: /* olt (=-1) */
e1f3808e 3422 tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3423 break;
3424 case 5: /* ole (=-1 or =0) */
e1f3808e 3425 tcg_gen_brcond_i32(TCG_COND_LE, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3426 break;
3427 case 6: /* ogl (=-1 or =1) */
e1f3808e
PB
3428 tcg_gen_andi_i32(flag, flag, 1);
3429 tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3430 break;
3431 case 7: /* or (=2) */
e1f3808e 3432 tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(2), l1);
e6e5906b
PB
3433 break;
3434 case 8: /* un (<2) */
e1f3808e 3435 tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(2), l1);
e6e5906b
PB
3436 break;
3437 case 9: /* ueq (=0 or =2) */
e1f3808e
PB
3438 tcg_gen_andi_i32(flag, flag, 1);
3439 tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3440 break;
3441 case 10: /* ugt (>0) */
e1f3808e 3442 tcg_gen_brcond_i32(TCG_COND_GT, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3443 break;
3444 case 11: /* uge (>=0) */
e1f3808e 3445 tcg_gen_brcond_i32(TCG_COND_GE, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3446 break;
3447 case 12: /* ult (=-1 or =2) */
e1f3808e 3448 tcg_gen_brcond_i32(TCG_COND_GEU, flag, tcg_const_i32(2), l1);
e6e5906b
PB
3449 break;
3450 case 13: /* ule (!=1) */
e1f3808e 3451 tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(1), l1);
e6e5906b
PB
3452 break;
3453 case 14: /* ne (!=0) */
e1f3808e 3454 tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3455 break;
3456 case 15: /* t */
e1f3808e 3457 tcg_gen_br(l1);
e6e5906b
PB
3458 break;
3459 }
3460 gen_jmp_tb(s, 0, s->pc);
3461 gen_set_label(l1);
3462 gen_jmp_tb(s, 1, addr + offset);
3463}
3464
0633879f
PB
3465DISAS_INSN(frestore)
3466{
a47dddd7
AF
3467 M68kCPU *cpu = m68k_env_get_cpu(env);
3468
0633879f 3469 /* TODO: Implement frestore. */
a47dddd7 3470 cpu_abort(CPU(cpu), "FRESTORE not implemented");
0633879f
PB
3471}
3472
3473DISAS_INSN(fsave)
3474{
a47dddd7
AF
3475 M68kCPU *cpu = m68k_env_get_cpu(env);
3476
0633879f 3477 /* TODO: Implement fsave. */
a47dddd7 3478 cpu_abort(CPU(cpu), "FSAVE not implemented");
0633879f
PB
3479}
3480
e1f3808e 3481static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
acf930aa 3482{
a7812ae4 3483 TCGv tmp = tcg_temp_new();
acf930aa
PB
3484 if (s->env->macsr & MACSR_FI) {
3485 if (upper)
e1f3808e 3486 tcg_gen_andi_i32(tmp, val, 0xffff0000);
acf930aa 3487 else
e1f3808e 3488 tcg_gen_shli_i32(tmp, val, 16);
acf930aa
PB
3489 } else if (s->env->macsr & MACSR_SU) {
3490 if (upper)
e1f3808e 3491 tcg_gen_sari_i32(tmp, val, 16);
acf930aa 3492 else
e1f3808e 3493 tcg_gen_ext16s_i32(tmp, val);
acf930aa
PB
3494 } else {
3495 if (upper)
e1f3808e 3496 tcg_gen_shri_i32(tmp, val, 16);
acf930aa 3497 else
e1f3808e 3498 tcg_gen_ext16u_i32(tmp, val);
acf930aa
PB
3499 }
3500 return tmp;
3501}
3502
e1f3808e
PB
3503static void gen_mac_clear_flags(void)
3504{
3505 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR,
3506 ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV));
3507}
3508
acf930aa
PB
3509DISAS_INSN(mac)
3510{
e1f3808e
PB
3511 TCGv rx;
3512 TCGv ry;
acf930aa
PB
3513 uint16_t ext;
3514 int acc;
e1f3808e
PB
3515 TCGv tmp;
3516 TCGv addr;
3517 TCGv loadval;
acf930aa 3518 int dual;
e1f3808e
PB
3519 TCGv saved_flags;
3520
a7812ae4
PB
3521 if (!s->done_mac) {
3522 s->mactmp = tcg_temp_new_i64();
3523 s->done_mac = 1;
3524 }
acf930aa 3525
28b68cd7 3526 ext = read_im16(env, s);
acf930aa
PB
3527
3528 acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
3529 dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
d315c888 3530 if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
d4d79bb1 3531 disas_undef(env, s, insn);
d315c888
PB
3532 return;
3533 }
acf930aa
PB
3534 if (insn & 0x30) {
3535 /* MAC with load. */
d4d79bb1 3536 tmp = gen_lea(env, s, insn, OS_LONG);
a7812ae4 3537 addr = tcg_temp_new();
e1f3808e 3538 tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK);
acf930aa
PB
3539 /* Load the value now to ensure correct exception behavior.
3540 Perform writeback after reading the MAC inputs. */
3541 loadval = gen_load(s, OS_LONG, addr, 0);
3542
3543 acc ^= 1;
3544 rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
3545 ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
3546 } else {
e1f3808e 3547 loadval = addr = NULL_QREG;
acf930aa
PB
3548 rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
3549 ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
3550 }
3551
e1f3808e
PB
3552 gen_mac_clear_flags();
3553#if 0
acf930aa 3554 l1 = -1;
e1f3808e 3555 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3556 if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
3557 /* Skip the multiply if we know we will ignore it. */
3558 l1 = gen_new_label();
a7812ae4 3559 tmp = tcg_temp_new();
e1f3808e 3560 tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8));
acf930aa
PB
3561 gen_op_jmp_nz32(tmp, l1);
3562 }
e1f3808e 3563#endif
acf930aa
PB
3564
3565 if ((ext & 0x0800) == 0) {
3566 /* Word. */
3567 rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
3568 ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
3569 }
3570 if (s->env->macsr & MACSR_FI) {
e1f3808e 3571 gen_helper_macmulf(s->mactmp, cpu_env, rx, ry);
acf930aa
PB
3572 } else {
3573 if (s->env->macsr & MACSR_SU)
e1f3808e 3574 gen_helper_macmuls(s->mactmp, cpu_env, rx, ry);
acf930aa 3575 else
e1f3808e 3576 gen_helper_macmulu(s->mactmp, cpu_env, rx, ry);
acf930aa
PB
3577 switch ((ext >> 9) & 3) {
3578 case 1:
e1f3808e 3579 tcg_gen_shli_i64(s->mactmp, s->mactmp, 1);
acf930aa
PB
3580 break;
3581 case 3:
e1f3808e 3582 tcg_gen_shri_i64(s->mactmp, s->mactmp, 1);
acf930aa
PB
3583 break;
3584 }
3585 }
3586
3587 if (dual) {
3588 /* Save the overflow flag from the multiply. */
a7812ae4 3589 saved_flags = tcg_temp_new();
e1f3808e
PB
3590 tcg_gen_mov_i32(saved_flags, QREG_MACSR);
3591 } else {
3592 saved_flags = NULL_QREG;
acf930aa
PB
3593 }
3594
e1f3808e
PB
3595#if 0
3596 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3597 if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
3598 /* Skip the accumulate if the value is already saturated. */
3599 l1 = gen_new_label();
a7812ae4 3600 tmp = tcg_temp_new();
351326a6 3601 gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
acf930aa
PB
3602 gen_op_jmp_nz32(tmp, l1);
3603 }
e1f3808e 3604#endif
acf930aa
PB
3605
3606 if (insn & 0x100)
e1f3808e 3607 tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 3608 else
e1f3808e 3609 tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa
PB
3610
3611 if (s->env->macsr & MACSR_FI)
e1f3808e 3612 gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
acf930aa 3613 else if (s->env->macsr & MACSR_SU)
e1f3808e 3614 gen_helper_macsats(cpu_env, tcg_const_i32(acc));
acf930aa 3615 else
e1f3808e 3616 gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
acf930aa 3617
e1f3808e
PB
3618#if 0
3619 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3620 if (l1 != -1)
3621 gen_set_label(l1);
e1f3808e 3622#endif
acf930aa
PB
3623
3624 if (dual) {
3625 /* Dual accumulate variant. */
3626 acc = (ext >> 2) & 3;
3627 /* Restore the overflow flag from the multiplier. */
e1f3808e
PB
3628 tcg_gen_mov_i32(QREG_MACSR, saved_flags);
3629#if 0
3630 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3631 if ((s->env->macsr & MACSR_OMC) != 0) {
3632 /* Skip the accumulate if the value is already saturated. */
3633 l1 = gen_new_label();
a7812ae4 3634 tmp = tcg_temp_new();
351326a6 3635 gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
acf930aa
PB
3636 gen_op_jmp_nz32(tmp, l1);
3637 }
e1f3808e 3638#endif
acf930aa 3639 if (ext & 2)
e1f3808e 3640 tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 3641 else
e1f3808e 3642 tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 3643 if (s->env->macsr & MACSR_FI)
e1f3808e 3644 gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
acf930aa 3645 else if (s->env->macsr & MACSR_SU)
e1f3808e 3646 gen_helper_macsats(cpu_env, tcg_const_i32(acc));
acf930aa 3647 else
e1f3808e
PB
3648 gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
3649#if 0
3650 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3651 if (l1 != -1)
3652 gen_set_label(l1);
e1f3808e 3653#endif
acf930aa 3654 }
e1f3808e 3655 gen_helper_mac_set_flags(cpu_env, tcg_const_i32(acc));
acf930aa
PB
3656
3657 if (insn & 0x30) {
e1f3808e 3658 TCGv rw;
acf930aa 3659 rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
e1f3808e 3660 tcg_gen_mov_i32(rw, loadval);
acf930aa
PB
3661 /* FIXME: Should address writeback happen with the masked or
3662 unmasked value? */
3663 switch ((insn >> 3) & 7) {
3664 case 3: /* Post-increment. */
e1f3808e 3665 tcg_gen_addi_i32(AREG(insn, 0), addr, 4);
acf930aa
PB
3666 break;
3667 case 4: /* Pre-decrement. */
e1f3808e 3668 tcg_gen_mov_i32(AREG(insn, 0), addr);
acf930aa
PB
3669 }
3670 }
3671}
3672
3673DISAS_INSN(from_mac)
3674{
e1f3808e 3675 TCGv rx;
a7812ae4 3676 TCGv_i64 acc;
e1f3808e 3677 int accnum;
acf930aa
PB
3678
3679 rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e
PB
3680 accnum = (insn >> 9) & 3;
3681 acc = MACREG(accnum);
acf930aa 3682 if (s->env->macsr & MACSR_FI) {
a7812ae4 3683 gen_helper_get_macf(rx, cpu_env, acc);
acf930aa 3684 } else if ((s->env->macsr & MACSR_OMC) == 0) {
ecc7b3aa 3685 tcg_gen_extrl_i64_i32(rx, acc);
acf930aa 3686 } else if (s->env->macsr & MACSR_SU) {
e1f3808e 3687 gen_helper_get_macs(rx, acc);
acf930aa 3688 } else {
e1f3808e
PB
3689 gen_helper_get_macu(rx, acc);
3690 }
3691 if (insn & 0x40) {
3692 tcg_gen_movi_i64(acc, 0);
3693 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
acf930aa 3694 }
acf930aa
PB
3695}
3696
3697DISAS_INSN(move_mac)
3698{
e1f3808e 3699 /* FIXME: This can be done without a helper. */
acf930aa 3700 int src;
e1f3808e 3701 TCGv dest;
acf930aa 3702 src = insn & 3;
e1f3808e
PB
3703 dest = tcg_const_i32((insn >> 9) & 3);
3704 gen_helper_mac_move(cpu_env, dest, tcg_const_i32(src));
3705 gen_mac_clear_flags();
3706 gen_helper_mac_set_flags(cpu_env, dest);
acf930aa
PB
3707}
3708
3709DISAS_INSN(from_macsr)
3710{
e1f3808e 3711 TCGv reg;
acf930aa
PB
3712
3713 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 3714 tcg_gen_mov_i32(reg, QREG_MACSR);
acf930aa
PB
3715}
3716
3717DISAS_INSN(from_mask)
3718{
e1f3808e 3719 TCGv reg;
acf930aa 3720 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 3721 tcg_gen_mov_i32(reg, QREG_MAC_MASK);
acf930aa
PB
3722}
3723
3724DISAS_INSN(from_mext)
3725{
e1f3808e
PB
3726 TCGv reg;
3727 TCGv acc;
acf930aa 3728 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 3729 acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
acf930aa 3730 if (s->env->macsr & MACSR_FI)
e1f3808e 3731 gen_helper_get_mac_extf(reg, cpu_env, acc);
acf930aa 3732 else
e1f3808e 3733 gen_helper_get_mac_exti(reg, cpu_env, acc);
acf930aa
PB
3734}
3735
3736DISAS_INSN(macsr_to_ccr)
3737{
620c6cf6
RH
3738 TCGv tmp = tcg_temp_new();
3739 tcg_gen_andi_i32(tmp, QREG_MACSR, 0xf);
3740 gen_helper_set_sr(cpu_env, tmp);
3741 tcg_temp_free(tmp);
9fdb533f 3742 set_cc_op(s, CC_OP_FLAGS);
acf930aa
PB
3743}
3744
3745DISAS_INSN(to_mac)
3746{
a7812ae4 3747 TCGv_i64 acc;
e1f3808e
PB
3748 TCGv val;
3749 int accnum;
3750 accnum = (insn >> 9) & 3;
3751 acc = MACREG(accnum);
d4d79bb1 3752 SRC_EA(env, val, OS_LONG, 0, NULL);
acf930aa 3753 if (s->env->macsr & MACSR_FI) {
e1f3808e
PB
3754 tcg_gen_ext_i32_i64(acc, val);
3755 tcg_gen_shli_i64(acc, acc, 8);
acf930aa 3756 } else if (s->env->macsr & MACSR_SU) {
e1f3808e 3757 tcg_gen_ext_i32_i64(acc, val);
acf930aa 3758 } else {
e1f3808e 3759 tcg_gen_extu_i32_i64(acc, val);
acf930aa 3760 }
e1f3808e
PB
3761 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
3762 gen_mac_clear_flags();
3763 gen_helper_mac_set_flags(cpu_env, tcg_const_i32(accnum));
acf930aa
PB
3764}
3765
3766DISAS_INSN(to_macsr)
3767{
e1f3808e 3768 TCGv val;
d4d79bb1 3769 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 3770 gen_helper_set_macsr(cpu_env, val);
acf930aa
PB
3771 gen_lookup_tb(s);
3772}
3773
3774DISAS_INSN(to_mask)
3775{
e1f3808e 3776 TCGv val;
d4d79bb1 3777 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 3778 tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000);
acf930aa
PB
3779}
3780
3781DISAS_INSN(to_mext)
3782{
e1f3808e
PB
3783 TCGv val;
3784 TCGv acc;
d4d79bb1 3785 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 3786 acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
acf930aa 3787 if (s->env->macsr & MACSR_FI)
e1f3808e 3788 gen_helper_set_mac_extf(cpu_env, val, acc);
acf930aa 3789 else if (s->env->macsr & MACSR_SU)
e1f3808e 3790 gen_helper_set_mac_exts(cpu_env, val, acc);
acf930aa 3791 else
e1f3808e 3792 gen_helper_set_mac_extu(cpu_env, val, acc);
acf930aa
PB
3793}
3794
e6e5906b
PB
3795static disas_proc opcode_table[65536];
3796
3797static void
3798register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
3799{
3800 int i;
3801 int from;
3802 int to;
3803
3804 /* Sanity check. All set bits must be included in the mask. */
5fc4adf6
PB
3805 if (opcode & ~mask) {
3806 fprintf(stderr,
3807 "qemu internal error: bogus opcode definition %04x/%04x\n",
3808 opcode, mask);
e6e5906b 3809 abort();
5fc4adf6 3810 }
e6e5906b
PB
3811 /* This could probably be cleverer. For now just optimize the case where
3812 the top bits are known. */
3813 /* Find the first zero bit in the mask. */
3814 i = 0x8000;
3815 while ((i & mask) != 0)
3816 i >>= 1;
3817 /* Iterate over all combinations of this and lower bits. */
3818 if (i == 0)
3819 i = 1;
3820 else
3821 i <<= 1;
3822 from = opcode & ~(i - 1);
3823 to = from + i;
0633879f 3824 for (i = from; i < to; i++) {
e6e5906b
PB
3825 if ((i & mask) == opcode)
3826 opcode_table[i] = proc;
0633879f 3827 }
e6e5906b
PB
3828}
3829
3830/* Register m68k opcode handlers. Order is important.
3831 Later insn override earlier ones. */
0402f767 3832void register_m68k_insns (CPUM68KState *env)
e6e5906b 3833{
b2085257
JPAG
3834 /* Build the opcode table only once to avoid
3835 multithreading issues. */
3836 if (opcode_table[0] != NULL) {
3837 return;
3838 }
f076803b
LV
3839
3840 /* use BASE() for instruction available
3841 * for CF_ISA_A and M68000.
3842 */
3843#define BASE(name, opcode, mask) \
3844 register_opcode(disas_##name, 0x##opcode, 0x##mask)
d315c888 3845#define INSN(name, opcode, mask, feature) do { \
0402f767 3846 if (m68k_feature(env, M68K_FEATURE_##feature)) \
f076803b 3847 BASE(name, opcode, mask); \
d315c888 3848 } while(0)
f076803b 3849 BASE(undef, 0000, 0000);
0402f767 3850 INSN(arith_im, 0080, fff8, CF_ISA_A);
f076803b
LV
3851 INSN(arith_im, 0000, ff00, M68000);
3852 INSN(undef, 00c0, ffc0, M68000);
d315c888 3853 INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC);
f076803b
LV
3854 BASE(bitop_reg, 0100, f1c0);
3855 BASE(bitop_reg, 0140, f1c0);
3856 BASE(bitop_reg, 0180, f1c0);
3857 BASE(bitop_reg, 01c0, f1c0);
0402f767 3858 INSN(arith_im, 0280, fff8, CF_ISA_A);
f076803b
LV
3859 INSN(arith_im, 0200, ff00, M68000);
3860 INSN(undef, 02c0, ffc0, M68000);
d315c888 3861 INSN(byterev, 02c0, fff8, CF_ISA_APLUSC);
0402f767 3862 INSN(arith_im, 0480, fff8, CF_ISA_A);
f076803b
LV
3863 INSN(arith_im, 0400, ff00, M68000);
3864 INSN(undef, 04c0, ffc0, M68000);
3865 INSN(arith_im, 0600, ff00, M68000);
3866 INSN(undef, 06c0, ffc0, M68000);
d315c888 3867 INSN(ff1, 04c0, fff8, CF_ISA_APLUSC);
0402f767 3868 INSN(arith_im, 0680, fff8, CF_ISA_A);
0402f767 3869 INSN(arith_im, 0c00, ff38, CF_ISA_A);
f076803b
LV
3870 INSN(arith_im, 0c00, ff00, M68000);
3871 BASE(bitop_im, 0800, ffc0);
3872 BASE(bitop_im, 0840, ffc0);
3873 BASE(bitop_im, 0880, ffc0);
3874 BASE(bitop_im, 08c0, ffc0);
3875 INSN(arith_im, 0a80, fff8, CF_ISA_A);
3876 INSN(arith_im, 0a00, ff00, M68000);
14f94406
LV
3877 INSN(cas, 0ac0, ffc0, CAS);
3878 INSN(cas, 0cc0, ffc0, CAS);
3879 INSN(cas, 0ec0, ffc0, CAS);
3880 INSN(cas2w, 0cfc, ffff, CAS);
3881 INSN(cas2l, 0efc, ffff, CAS);
f076803b
LV
3882 BASE(move, 1000, f000);
3883 BASE(move, 2000, f000);
3884 BASE(move, 3000, f000);
d315c888 3885 INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
0402f767 3886 INSN(negx, 4080, fff8, CF_ISA_A);
a665a820
RH
3887 INSN(negx, 4000, ff00, M68000);
3888 INSN(undef, 40c0, ffc0, M68000);
0402f767 3889 INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
f076803b
LV
3890 INSN(move_from_sr, 40c0, ffc0, M68000);
3891 BASE(lea, 41c0, f1c0);
3892 BASE(clr, 4200, ff00);
3893 BASE(undef, 42c0, ffc0);
0402f767 3894 INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
7c0eb318 3895 INSN(move_from_ccr, 42c0, ffc0, M68000);
0402f767 3896 INSN(neg, 4480, fff8, CF_ISA_A);
f076803b
LV
3897 INSN(neg, 4400, ff00, M68000);
3898 INSN(undef, 44c0, ffc0, M68000);
3899 BASE(move_to_ccr, 44c0, ffc0);
0402f767 3900 INSN(not, 4680, fff8, CF_ISA_A);
f076803b
LV
3901 INSN(not, 4600, ff00, M68000);
3902 INSN(undef, 46c0, ffc0, M68000);
0402f767 3903 INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
fb5543d8 3904 INSN(nbcd, 4800, ffc0, M68000);
c630e436 3905 INSN(linkl, 4808, fff8, M68000);
f076803b
LV
3906 BASE(pea, 4840, ffc0);
3907 BASE(swap, 4840, fff8);
71600eda 3908 INSN(bkpt, 4848, fff8, BKPT);
7b542eb9
LV
3909 INSN(movem, 48d0, fbf8, CF_ISA_A);
3910 INSN(movem, 48e8, fbf8, CF_ISA_A);
3911 INSN(movem, 4880, fb80, M68000);
f076803b
LV
3912 BASE(ext, 4880, fff8);
3913 BASE(ext, 48c0, fff8);
3914 BASE(ext, 49c0, fff8);
3915 BASE(tst, 4a00, ff00);
0402f767 3916 INSN(tas, 4ac0, ffc0, CF_ISA_B);
f076803b 3917 INSN(tas, 4ac0, ffc0, M68000);
0402f767
PB
3918 INSN(halt, 4ac8, ffff, CF_ISA_A);
3919 INSN(pulse, 4acc, ffff, CF_ISA_A);
f076803b 3920 BASE(illegal, 4afc, ffff);
0402f767 3921 INSN(mull, 4c00, ffc0, CF_ISA_A);
f076803b 3922 INSN(mull, 4c00, ffc0, LONG_MULDIV);
0402f767 3923 INSN(divl, 4c40, ffc0, CF_ISA_A);
f076803b 3924 INSN(divl, 4c40, ffc0, LONG_MULDIV);
0402f767 3925 INSN(sats, 4c80, fff8, CF_ISA_B);
f076803b
LV
3926 BASE(trap, 4e40, fff0);
3927 BASE(link, 4e50, fff8);
3928 BASE(unlk, 4e58, fff8);
20dcee94
PB
3929 INSN(move_to_usp, 4e60, fff8, USP);
3930 INSN(move_from_usp, 4e68, fff8, USP);
f076803b
LV
3931 BASE(nop, 4e71, ffff);
3932 BASE(stop, 4e72, ffff);
3933 BASE(rte, 4e73, ffff);
3934 BASE(rts, 4e75, ffff);
0402f767 3935 INSN(movec, 4e7b, ffff, CF_ISA_A);
f076803b 3936 BASE(jump, 4e80, ffc0);
8a370c6c 3937 BASE(jump, 4ec0, ffc0);
f076803b 3938 INSN(addsubq, 5000, f080, M68000);
8a370c6c 3939 BASE(addsubq, 5080, f0c0);
d5a3cf33
LV
3940 INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */
3941 INSN(scc, 50c0, f0c0, M68000); /* Scc.B <EA> */
beff27ab 3942 INSN(dbcc, 50c8, f0f8, M68000);
0402f767 3943 INSN(tpf, 51f8, fff8, CF_ISA_A);
d315c888
PB
3944
3945 /* Branch instructions. */
f076803b 3946 BASE(branch, 6000, f000);
d315c888 3947 /* Disable long branch instructions, then add back the ones we want. */
f076803b 3948 BASE(undef, 60ff, f0ff); /* All long branches. */
d315c888
PB
3949 INSN(branch, 60ff, f0ff, CF_ISA_B);
3950 INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */
3951 INSN(branch, 60ff, ffff, BRAL);
f076803b 3952 INSN(branch, 60ff, f0ff, BCCL);
d315c888 3953
f076803b 3954 BASE(moveq, 7000, f100);
0402f767 3955 INSN(mvzs, 7100, f100, CF_ISA_B);
f076803b
LV
3956 BASE(or, 8000, f000);
3957 BASE(divw, 80c0, f0c0);
fb5543d8
LV
3958 INSN(sbcd_reg, 8100, f1f8, M68000);
3959 INSN(sbcd_mem, 8108, f1f8, M68000);
f076803b 3960 BASE(addsub, 9000, f000);
a665a820
RH
3961 INSN(undef, 90c0, f0c0, CF_ISA_A);
3962 INSN(subx_reg, 9180, f1f8, CF_ISA_A);
3963 INSN(subx_reg, 9100, f138, M68000);
3964 INSN(subx_mem, 9108, f138, M68000);
0402f767 3965 INSN(suba, 91c0, f1c0, CF_ISA_A);
415f4b62 3966 INSN(suba, 90c0, f0c0, M68000);
acf930aa 3967
f076803b 3968 BASE(undef_mac, a000, f000);
acf930aa
PB
3969 INSN(mac, a000, f100, CF_EMAC);
3970 INSN(from_mac, a180, f9b0, CF_EMAC);
3971 INSN(move_mac, a110, f9fc, CF_EMAC);
3972 INSN(from_macsr,a980, f9f0, CF_EMAC);
3973 INSN(from_mask, ad80, fff0, CF_EMAC);
3974 INSN(from_mext, ab80, fbf0, CF_EMAC);
3975 INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
3976 INSN(to_mac, a100, f9c0, CF_EMAC);
3977 INSN(to_macsr, a900, ffc0, CF_EMAC);
3978 INSN(to_mext, ab00, fbc0, CF_EMAC);
3979 INSN(to_mask, ad00, ffc0, CF_EMAC);
3980
0402f767
PB
3981 INSN(mov3q, a140, f1c0, CF_ISA_B);
3982 INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */
3983 INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */
3984 INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */
3985 INSN(cmp, b080, f1c0, CF_ISA_A);
3986 INSN(cmpa, b1c0, f1c0, CF_ISA_A);
f076803b
LV
3987 INSN(cmp, b000, f100, M68000);
3988 INSN(eor, b100, f100, M68000);
817af1c7 3989 INSN(cmpm, b108, f138, M68000);
f076803b 3990 INSN(cmpa, b0c0, f0c0, M68000);
0402f767 3991 INSN(eor, b180, f1c0, CF_ISA_A);
f076803b 3992 BASE(and, c000, f000);
29cf437d
LV
3993 INSN(exg_dd, c140, f1f8, M68000);
3994 INSN(exg_aa, c148, f1f8, M68000);
3995 INSN(exg_da, c188, f1f8, M68000);
f076803b 3996 BASE(mulw, c0c0, f0c0);
fb5543d8
LV
3997 INSN(abcd_reg, c100, f1f8, M68000);
3998 INSN(abcd_mem, c108, f1f8, M68000);
f076803b 3999 BASE(addsub, d000, f000);
a665a820
RH
4000 INSN(undef, d0c0, f0c0, CF_ISA_A);
4001 INSN(addx_reg, d180, f1f8, CF_ISA_A);
4002 INSN(addx_reg, d100, f138, M68000);
4003 INSN(addx_mem, d108, f138, M68000);
0402f767 4004 INSN(adda, d1c0, f1c0, CF_ISA_A);
f076803b 4005 INSN(adda, d0c0, f0c0, M68000);
0402f767
PB
4006 INSN(shift_im, e080, f0f0, CF_ISA_A);
4007 INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
4008 INSN(undef_fpu, f000, f000, CF_ISA_A);
e6e5906b
PB
4009 INSN(fpu, f200, ffc0, CF_FPU);
4010 INSN(fbcc, f280, ffc0, CF_FPU);
0633879f
PB
4011 INSN(frestore, f340, ffc0, CF_FPU);
4012 INSN(fsave, f340, ffc0, CF_FPU);
0402f767
PB
4013 INSN(intouch, f340, ffc0, CF_ISA_A);
4014 INSN(cpushl, f428, ff38, CF_ISA_A);
4015 INSN(wddata, fb00, ff00, CF_ISA_A);
4016 INSN(wdebug, fbc0, ffc0, CF_ISA_A);
e6e5906b
PB
4017#undef INSN
4018}
4019
4020/* ??? Some of this implementation is not exception safe. We should always
4021 write back the result to memory before setting the condition codes. */
2b3e3cfe 4022static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
e6e5906b 4023{
8a1e52b6 4024 uint16_t insn = read_im16(env, s);
d4d79bb1 4025 opcode_table[insn](env, s, insn);
8a1e52b6 4026 do_writebacks(s);
e6e5906b
PB
4027}
4028
e6e5906b 4029/* generate intermediate code for basic block 'tb'. */
4e5e1215 4030void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
e6e5906b 4031{
4e5e1215 4032 M68kCPU *cpu = m68k_env_get_cpu(env);
ed2803da 4033 CPUState *cs = CPU(cpu);
e6e5906b 4034 DisasContext dc1, *dc = &dc1;
e6e5906b
PB
4035 target_ulong pc_start;
4036 int pc_offset;
2e70f6ef
PB
4037 int num_insns;
4038 int max_insns;
e6e5906b
PB
4039
4040 /* generate intermediate code */
4041 pc_start = tb->pc;
3b46e624 4042
e6e5906b
PB
4043 dc->tb = tb;
4044
e6dbd3b3 4045 dc->env = env;
e6e5906b
PB
4046 dc->is_jmp = DISAS_NEXT;
4047 dc->pc = pc_start;
4048 dc->cc_op = CC_OP_DYNAMIC;
620c6cf6 4049 dc->cc_op_synced = 1;
ed2803da 4050 dc->singlestep_enabled = cs->singlestep_enabled;
e6e5906b 4051 dc->fpcr = env->fpcr;
0633879f 4052 dc->user = (env->sr & SR_S) == 0;
a7812ae4 4053 dc->done_mac = 0;
8a1e52b6 4054 dc->writeback_mask = 0;
2e70f6ef
PB
4055 num_insns = 0;
4056 max_insns = tb->cflags & CF_COUNT_MASK;
190ce7fb 4057 if (max_insns == 0) {
2e70f6ef 4058 max_insns = CF_COUNT_MASK;
190ce7fb
RH
4059 }
4060 if (max_insns > TCG_MAX_INSNS) {
4061 max_insns = TCG_MAX_INSNS;
4062 }
2e70f6ef 4063
cd42d5b2 4064 gen_tb_start(tb);
e6e5906b 4065 do {
e6e5906b
PB
4066 pc_offset = dc->pc - pc_start;
4067 gen_throws_exception = NULL;
20a8856e 4068 tcg_gen_insn_start(dc->pc, dc->cc_op);
959082fc 4069 num_insns++;
667b8e29 4070
b933066a
RH
4071 if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
4072 gen_exception(dc, dc->pc, EXCP_DEBUG);
4073 dc->is_jmp = DISAS_JUMP;
522a0d4e
RH
4074 /* The address covered by the breakpoint must be included in
4075 [tb->pc, tb->pc + tb->size) in order to for it to be
4076 properly cleared -- thus we increment the PC here so that
4077 the logic setting tb->size below does the right thing. */
4078 dc->pc += 2;
b933066a
RH
4079 break;
4080 }
4081
959082fc 4082 if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
2e70f6ef 4083 gen_io_start();
667b8e29
RH
4084 }
4085
510ff0b7 4086 dc->insn_pc = dc->pc;
e6e5906b 4087 disas_m68k_insn(env, dc);
fe700adb 4088 } while (!dc->is_jmp && !tcg_op_buf_full() &&
ed2803da 4089 !cs->singlestep_enabled &&
1b530a6d 4090 !singlestep &&
2e70f6ef
PB
4091 (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
4092 num_insns < max_insns);
e6e5906b 4093
2e70f6ef
PB
4094 if (tb->cflags & CF_LAST_IO)
4095 gen_io_end();
ed2803da 4096 if (unlikely(cs->singlestep_enabled)) {
e6e5906b
PB
4097 /* Make sure the pc is updated, and raise a debug exception. */
4098 if (!dc->is_jmp) {
9fdb533f 4099 update_cc_op(dc);
e1f3808e 4100 tcg_gen_movi_i32(QREG_PC, dc->pc);
e6e5906b 4101 }
31871141 4102 gen_helper_raise_exception(cpu_env, tcg_const_i32(EXCP_DEBUG));
e6e5906b
PB
4103 } else {
4104 switch(dc->is_jmp) {
4105 case DISAS_NEXT:
9fdb533f 4106 update_cc_op(dc);
e6e5906b
PB
4107 gen_jmp_tb(dc, 0, dc->pc);
4108 break;
4109 default:
4110 case DISAS_JUMP:
4111 case DISAS_UPDATE:
9fdb533f 4112 update_cc_op(dc);
e6e5906b 4113 /* indicate that the hash table must be used to find the next TB */
57fec1fe 4114 tcg_gen_exit_tb(0);
e6e5906b
PB
4115 break;
4116 case DISAS_TB_JUMP:
4117 /* nothing more to generate */
4118 break;
4119 }
4120 }
806f352d 4121 gen_tb_end(tb, num_insns);
e6e5906b
PB
4122
4123#ifdef DEBUG_DISAS
4910e6e4
RH
4124 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
4125 && qemu_log_in_addr_range(pc_start)) {
1ee73216 4126 qemu_log_lock();
93fcfe39
AL
4127 qemu_log("----------------\n");
4128 qemu_log("IN: %s\n", lookup_symbol(pc_start));
d49190c4 4129 log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
93fcfe39 4130 qemu_log("\n");
1ee73216 4131 qemu_log_unlock();
e6e5906b
PB
4132 }
4133#endif
4e5e1215
RH
4134 tb->size = dc->pc - pc_start;
4135 tb->icount = num_insns;
e6e5906b
PB
4136}
4137
878096ee
AF
4138void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
4139 int flags)
e6e5906b 4140{
878096ee
AF
4141 M68kCPU *cpu = M68K_CPU(cs);
4142 CPUM68KState *env = &cpu->env;
e6e5906b
PB
4143 int i;
4144 uint16_t sr;
4145 CPU_DoubleU u;
4146 for (i = 0; i < 8; i++)
4147 {
4148 u.d = env->fregs[i];
8e394cca
RH
4149 cpu_fprintf(f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n",
4150 i, env->dregs[i], i, env->aregs[i],
4151 i, u.l.upper, u.l.lower, *(double *)&u.d);
e6e5906b
PB
4152 }
4153 cpu_fprintf (f, "PC = %08x ", env->pc);
99c51448 4154 sr = env->sr | cpu_m68k_get_ccr(env);
8e394cca
RH
4155 cpu_fprintf(f, "SR = %04x %c%c%c%c%c ", sr, (sr & CCF_X) ? 'X' : '-',
4156 (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-',
4157 (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-');
8fc7cc58 4158 cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result);
e6e5906b
PB
4159}
4160
bad729e2
RH
4161void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb,
4162 target_ulong *data)
d2856f1a 4163{
20a8856e 4164 int cc_op = data[1];
bad729e2 4165 env->pc = data[0];
20a8856e
LV
4166 if (cc_op != CC_OP_DYNAMIC) {
4167 env->cc_op = cc_op;
4168 }
d2856f1a 4169}
This page took 1.512521 seconds and 4 git commands to generate.