]> git.proxmox.com Git - mirror_qemu.git/blame - target/m68k/translate.c
target-m68k: add abcd/sbcd/nbcd
[mirror_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{
a47dddd7
AF
1217 M68kCPU *cpu = m68k_env_get_cpu(env);
1218
e6e5906b 1219 gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED);
a47dddd7 1220 cpu_abort(CPU(cpu), "Illegal instruction: %04x @ %08x", insn, s->pc - 2);
e6e5906b
PB
1221}
1222
1223DISAS_INSN(mulw)
1224{
e1f3808e
PB
1225 TCGv reg;
1226 TCGv tmp;
1227 TCGv src;
e6e5906b
PB
1228 int sign;
1229
1230 sign = (insn & 0x100) != 0;
1231 reg = DREG(insn, 9);
a7812ae4 1232 tmp = tcg_temp_new();
e6e5906b 1233 if (sign)
e1f3808e 1234 tcg_gen_ext16s_i32(tmp, reg);
e6e5906b 1235 else
e1f3808e 1236 tcg_gen_ext16u_i32(tmp, reg);
d4d79bb1 1237 SRC_EA(env, src, OS_WORD, sign, NULL);
e1f3808e
PB
1238 tcg_gen_mul_i32(tmp, tmp, src);
1239 tcg_gen_mov_i32(reg, tmp);
4a18cd44 1240 gen_logic_cc(s, tmp, OS_LONG);
e6e5906b
PB
1241}
1242
1243DISAS_INSN(divw)
1244{
e6e5906b 1245 int sign;
0ccb9c1d
LV
1246 TCGv src;
1247 TCGv destr;
1248
1249 /* divX.w <EA>,Dn 32/16 -> 16r:16q */
e6e5906b
PB
1250
1251 sign = (insn & 0x100) != 0;
0ccb9c1d
LV
1252
1253 /* dest.l / src.w */
1254
d4d79bb1 1255 SRC_EA(env, src, OS_WORD, sign, NULL);
0ccb9c1d 1256 destr = tcg_const_i32(REG(insn, 9));
e6e5906b 1257 if (sign) {
0ccb9c1d 1258 gen_helper_divsw(cpu_env, destr, src);
e6e5906b 1259 } else {
0ccb9c1d 1260 gen_helper_divuw(cpu_env, destr, src);
e6e5906b 1261 }
0ccb9c1d 1262 tcg_temp_free(destr);
620c6cf6 1263
9fdb533f 1264 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1265}
1266
1267DISAS_INSN(divl)
1268{
0ccb9c1d
LV
1269 TCGv num, reg, den;
1270 int sign;
e6e5906b
PB
1271 uint16_t ext;
1272
28b68cd7 1273 ext = read_im16(env, s);
0ccb9c1d
LV
1274
1275 sign = (ext & 0x0800) != 0;
1276
1277 if (ext & 0x400) {
1278 if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
1279 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
1280 return;
1281 }
1282
1283 /* divX.l <EA>, Dr:Dq 64/32 -> 32r:32q */
1284
1285 SRC_EA(env, den, OS_LONG, 0, NULL);
1286 num = tcg_const_i32(REG(ext, 12));
1287 reg = tcg_const_i32(REG(ext, 0));
1288 if (sign) {
1289 gen_helper_divsll(cpu_env, num, reg, den);
1290 } else {
1291 gen_helper_divull(cpu_env, num, reg, den);
1292 }
1293 tcg_temp_free(reg);
1294 tcg_temp_free(num);
1295 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1296 return;
1297 }
0ccb9c1d
LV
1298
1299 /* divX.l <EA>, Dq 32/32 -> 32q */
1300 /* divXl.l <EA>, Dr:Dq 32/32 -> 32r:32q */
1301
d4d79bb1 1302 SRC_EA(env, den, OS_LONG, 0, NULL);
0ccb9c1d
LV
1303 num = tcg_const_i32(REG(ext, 12));
1304 reg = tcg_const_i32(REG(ext, 0));
1305 if (sign) {
1306 gen_helper_divsl(cpu_env, num, reg, den);
e6e5906b 1307 } else {
0ccb9c1d 1308 gen_helper_divul(cpu_env, num, reg, den);
e6e5906b 1309 }
0ccb9c1d
LV
1310 tcg_temp_free(reg);
1311 tcg_temp_free(num);
1312
9fdb533f 1313 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1314}
1315
fb5543d8
LV
1316static void bcd_add(TCGv dest, TCGv src)
1317{
1318 TCGv t0, t1;
1319
1320 /* dest10 = dest10 + src10 + X
1321 *
1322 * t1 = src
1323 * t2 = t1 + 0x066
1324 * t3 = t2 + dest + X
1325 * t4 = t2 ^ dest
1326 * t5 = t3 ^ t4
1327 * t6 = ~t5 & 0x110
1328 * t7 = (t6 >> 2) | (t6 >> 3)
1329 * return t3 - t7
1330 */
1331
1332 /* t1 = (src + 0x066) + dest + X
1333 * = result with some possible exceding 0x6
1334 */
1335
1336 t0 = tcg_const_i32(0x066);
1337 tcg_gen_add_i32(t0, t0, src);
1338
1339 t1 = tcg_temp_new();
1340 tcg_gen_add_i32(t1, t0, dest);
1341 tcg_gen_add_i32(t1, t1, QREG_CC_X);
1342
1343 /* we will remove exceding 0x6 where there is no carry */
1344
1345 /* t0 = (src + 0x0066) ^ dest
1346 * = t1 without carries
1347 */
1348
1349 tcg_gen_xor_i32(t0, t0, dest);
1350
1351 /* extract the carries
1352 * t0 = t0 ^ t1
1353 * = only the carries
1354 */
1355
1356 tcg_gen_xor_i32(t0, t0, t1);
1357
1358 /* generate 0x1 where there is no carry
1359 * and for each 0x10, generate a 0x6
1360 */
1361
1362 tcg_gen_shri_i32(t0, t0, 3);
1363 tcg_gen_not_i32(t0, t0);
1364 tcg_gen_andi_i32(t0, t0, 0x22);
1365 tcg_gen_add_i32(dest, t0, t0);
1366 tcg_gen_add_i32(dest, dest, t0);
1367 tcg_temp_free(t0);
1368
1369 /* remove the exceding 0x6
1370 * for digits that have not generated a carry
1371 */
1372
1373 tcg_gen_sub_i32(dest, t1, dest);
1374 tcg_temp_free(t1);
1375}
1376
1377static void bcd_sub(TCGv dest, TCGv src)
1378{
1379 TCGv t0, t1, t2;
1380
1381 /* dest10 = dest10 - src10 - X
1382 * = bcd_add(dest + 1 - X, 0x199 - src)
1383 */
1384
1385 /* t0 = 0x066 + (0x199 - src) */
1386
1387 t0 = tcg_temp_new();
1388 tcg_gen_subfi_i32(t0, 0x1ff, src);
1389
1390 /* t1 = t0 + dest + 1 - X*/
1391
1392 t1 = tcg_temp_new();
1393 tcg_gen_add_i32(t1, t0, dest);
1394 tcg_gen_addi_i32(t1, t1, 1);
1395 tcg_gen_sub_i32(t1, t1, QREG_CC_X);
1396
1397 /* t2 = t0 ^ dest */
1398
1399 t2 = tcg_temp_new();
1400 tcg_gen_xor_i32(t2, t0, dest);
1401
1402 /* t0 = t1 ^ t2 */
1403
1404 tcg_gen_xor_i32(t0, t1, t2);
1405
1406 /* t2 = ~t0 & 0x110
1407 * t0 = (t2 >> 2) | (t2 >> 3)
1408 *
1409 * to fit on 8bit operands, changed in:
1410 *
1411 * t2 = ~(t0 >> 3) & 0x22
1412 * t0 = t2 + t2
1413 * t0 = t0 + t2
1414 */
1415
1416 tcg_gen_shri_i32(t2, t0, 3);
1417 tcg_gen_not_i32(t2, t2);
1418 tcg_gen_andi_i32(t2, t2, 0x22);
1419 tcg_gen_add_i32(t0, t2, t2);
1420 tcg_gen_add_i32(t0, t0, t2);
1421 tcg_temp_free(t2);
1422
1423 /* return t1 - t0 */
1424
1425 tcg_gen_sub_i32(dest, t1, t0);
1426 tcg_temp_free(t0);
1427 tcg_temp_free(t1);
1428}
1429
1430static void bcd_flags(TCGv val)
1431{
1432 tcg_gen_andi_i32(QREG_CC_C, val, 0x0ff);
1433 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_C);
1434
1435 tcg_gen_shri_i32(QREG_CC_C, val, 8);
1436 tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
1437
1438 tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
1439}
1440
1441DISAS_INSN(abcd_reg)
1442{
1443 TCGv src;
1444 TCGv dest;
1445
1446 gen_flush_flags(s); /* !Z is sticky */
1447
1448 src = gen_extend(DREG(insn, 0), OS_BYTE, 0);
1449 dest = gen_extend(DREG(insn, 9), OS_BYTE, 0);
1450 bcd_add(dest, src);
1451 gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1452
1453 bcd_flags(dest);
1454}
1455
1456DISAS_INSN(abcd_mem)
1457{
1458 TCGv src, dest, addr;
1459
1460 gen_flush_flags(s); /* !Z is sticky */
1461
1462 /* Indirect pre-decrement load (mode 4) */
1463
1464 src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
1465 NULL_QREG, NULL, EA_LOADU);
1466 dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
1467 NULL_QREG, &addr, EA_LOADU);
1468
1469 bcd_add(dest, src);
1470
1471 gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr, EA_STORE);
1472
1473 bcd_flags(dest);
1474}
1475
1476DISAS_INSN(sbcd_reg)
1477{
1478 TCGv src, dest;
1479
1480 gen_flush_flags(s); /* !Z is sticky */
1481
1482 src = gen_extend(DREG(insn, 0), OS_BYTE, 0);
1483 dest = gen_extend(DREG(insn, 9), OS_BYTE, 0);
1484
1485 bcd_sub(dest, src);
1486
1487 gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1488
1489 bcd_flags(dest);
1490}
1491
1492DISAS_INSN(sbcd_mem)
1493{
1494 TCGv src, dest, addr;
1495
1496 gen_flush_flags(s); /* !Z is sticky */
1497
1498 /* Indirect pre-decrement load (mode 4) */
1499
1500 src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
1501 NULL_QREG, NULL, EA_LOADU);
1502 dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
1503 NULL_QREG, &addr, EA_LOADU);
1504
1505 bcd_sub(dest, src);
1506
1507 gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr, EA_STORE);
1508
1509 bcd_flags(dest);
1510}
1511
1512DISAS_INSN(nbcd)
1513{
1514 TCGv src, dest;
1515 TCGv addr;
1516
1517 gen_flush_flags(s); /* !Z is sticky */
1518
1519 SRC_EA(env, src, OS_BYTE, 0, &addr);
1520
1521 dest = tcg_const_i32(0);
1522 bcd_sub(dest, src);
1523
1524 DEST_EA(env, insn, OS_BYTE, dest, &addr);
1525
1526 bcd_flags(dest);
1527
1528 tcg_temp_free(dest);
1529}
1530
e6e5906b
PB
1531DISAS_INSN(addsub)
1532{
e1f3808e
PB
1533 TCGv reg;
1534 TCGv dest;
1535 TCGv src;
1536 TCGv tmp;
1537 TCGv addr;
e6e5906b 1538 int add;
8a370c6c 1539 int opsize;
e6e5906b
PB
1540
1541 add = (insn & 0x4000) != 0;
8a370c6c
LV
1542 opsize = insn_opsize(insn);
1543 reg = gen_extend(DREG(insn, 9), opsize, 1);
a7812ae4 1544 dest = tcg_temp_new();
e6e5906b 1545 if (insn & 0x100) {
8a370c6c 1546 SRC_EA(env, tmp, opsize, 1, &addr);
e6e5906b
PB
1547 src = reg;
1548 } else {
1549 tmp = reg;
8a370c6c 1550 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b
PB
1551 }
1552 if (add) {
e1f3808e 1553 tcg_gen_add_i32(dest, tmp, src);
f9083519 1554 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src);
8a370c6c 1555 set_cc_op(s, CC_OP_ADDB + opsize);
e6e5906b 1556 } else {
f9083519 1557 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src);
e1f3808e 1558 tcg_gen_sub_i32(dest, tmp, src);
8a370c6c 1559 set_cc_op(s, CC_OP_SUBB + opsize);
e6e5906b 1560 }
8a370c6c 1561 gen_update_cc_add(dest, src, opsize);
e6e5906b 1562 if (insn & 0x100) {
8a370c6c 1563 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 1564 } else {
8a370c6c 1565 gen_partset_reg(opsize, DREG(insn, 9), dest);
e6e5906b 1566 }
8a370c6c 1567 tcg_temp_free(dest);
e6e5906b
PB
1568}
1569
e6e5906b
PB
1570/* Reverse the order of the bits in REG. */
1571DISAS_INSN(bitrev)
1572{
e1f3808e 1573 TCGv reg;
e6e5906b 1574 reg = DREG(insn, 0);
e1f3808e 1575 gen_helper_bitrev(reg, reg);
e6e5906b
PB
1576}
1577
1578DISAS_INSN(bitop_reg)
1579{
1580 int opsize;
1581 int op;
e1f3808e
PB
1582 TCGv src1;
1583 TCGv src2;
1584 TCGv tmp;
1585 TCGv addr;
1586 TCGv dest;
e6e5906b
PB
1587
1588 if ((insn & 0x38) != 0)
1589 opsize = OS_BYTE;
1590 else
1591 opsize = OS_LONG;
1592 op = (insn >> 6) & 3;
d4d79bb1 1593 SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
e6e5906b 1594
3c980d2e
LV
1595 gen_flush_flags(s);
1596 src2 = tcg_temp_new();
e6e5906b 1597 if (opsize == OS_BYTE)
3c980d2e 1598 tcg_gen_andi_i32(src2, DREG(insn, 9), 7);
e6e5906b 1599 else
3c980d2e 1600 tcg_gen_andi_i32(src2, DREG(insn, 9), 31);
620c6cf6 1601
3c980d2e
LV
1602 tmp = tcg_const_i32(1);
1603 tcg_gen_shl_i32(tmp, tmp, src2);
1604 tcg_temp_free(src2);
620c6cf6 1605
3c980d2e 1606 tcg_gen_and_i32(QREG_CC_Z, src1, tmp);
620c6cf6 1607
3c980d2e 1608 dest = tcg_temp_new();
e6e5906b
PB
1609 switch (op) {
1610 case 1: /* bchg */
3c980d2e 1611 tcg_gen_xor_i32(dest, src1, tmp);
e6e5906b
PB
1612 break;
1613 case 2: /* bclr */
3c980d2e 1614 tcg_gen_andc_i32(dest, src1, tmp);
e6e5906b
PB
1615 break;
1616 case 3: /* bset */
3c980d2e 1617 tcg_gen_or_i32(dest, src1, tmp);
e6e5906b
PB
1618 break;
1619 default: /* btst */
1620 break;
1621 }
3c980d2e 1622 tcg_temp_free(tmp);
620c6cf6 1623 if (op) {
d4d79bb1 1624 DEST_EA(env, insn, opsize, dest, &addr);
620c6cf6
RH
1625 }
1626 tcg_temp_free(dest);
e6e5906b
PB
1627}
1628
1629DISAS_INSN(sats)
1630{
e1f3808e 1631 TCGv reg;
e6e5906b 1632 reg = DREG(insn, 0);
e6e5906b 1633 gen_flush_flags(s);
620c6cf6 1634 gen_helper_sats(reg, reg, QREG_CC_V);
5dbb6784 1635 gen_logic_cc(s, reg, OS_LONG);
e6e5906b
PB
1636}
1637
e1f3808e 1638static void gen_push(DisasContext *s, TCGv val)
e6e5906b 1639{
e1f3808e 1640 TCGv tmp;
e6e5906b 1641
a7812ae4 1642 tmp = tcg_temp_new();
e1f3808e 1643 tcg_gen_subi_i32(tmp, QREG_SP, 4);
0633879f 1644 gen_store(s, OS_LONG, tmp, val);
e1f3808e 1645 tcg_gen_mov_i32(QREG_SP, tmp);
e6e5906b
PB
1646}
1647
1648DISAS_INSN(movem)
1649{
e1f3808e 1650 TCGv addr;
e6e5906b
PB
1651 int i;
1652 uint16_t mask;
e1f3808e
PB
1653 TCGv reg;
1654 TCGv tmp;
e6e5906b
PB
1655 int is_load;
1656
28b68cd7 1657 mask = read_im16(env, s);
d4d79bb1 1658 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 1659 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
1660 gen_addr_fault(s);
1661 return;
1662 }
a7812ae4 1663 addr = tcg_temp_new();
e1f3808e 1664 tcg_gen_mov_i32(addr, tmp);
e6e5906b
PB
1665 is_load = ((insn & 0x0400) != 0);
1666 for (i = 0; i < 16; i++, mask >>= 1) {
1667 if (mask & 1) {
1668 if (i < 8)
1669 reg = DREG(i, 0);
1670 else
1671 reg = AREG(i, 0);
1672 if (is_load) {
0633879f 1673 tmp = gen_load(s, OS_LONG, addr, 0);
e1f3808e 1674 tcg_gen_mov_i32(reg, tmp);
e6e5906b 1675 } else {
0633879f 1676 gen_store(s, OS_LONG, addr, reg);
e6e5906b
PB
1677 }
1678 if (mask != 1)
e1f3808e 1679 tcg_gen_addi_i32(addr, addr, 4);
e6e5906b
PB
1680 }
1681 }
1682}
1683
1684DISAS_INSN(bitop_im)
1685{
1686 int opsize;
1687 int op;
e1f3808e 1688 TCGv src1;
e6e5906b
PB
1689 uint32_t mask;
1690 int bitnum;
e1f3808e
PB
1691 TCGv tmp;
1692 TCGv addr;
e6e5906b
PB
1693
1694 if ((insn & 0x38) != 0)
1695 opsize = OS_BYTE;
1696 else
1697 opsize = OS_LONG;
1698 op = (insn >> 6) & 3;
1699
28b68cd7 1700 bitnum = read_im16(env, s);
e6e5906b 1701 if (bitnum & 0xff00) {
d4d79bb1 1702 disas_undef(env, s, insn);
e6e5906b
PB
1703 return;
1704 }
1705
d4d79bb1 1706 SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
e6e5906b 1707
3c980d2e 1708 gen_flush_flags(s);
e6e5906b
PB
1709 if (opsize == OS_BYTE)
1710 bitnum &= 7;
1711 else
1712 bitnum &= 31;
1713 mask = 1 << bitnum;
1714
3c980d2e 1715 tcg_gen_andi_i32(QREG_CC_Z, src1, mask);
620c6cf6 1716
e1f3808e 1717 if (op) {
620c6cf6 1718 tmp = tcg_temp_new();
e1f3808e
PB
1719 switch (op) {
1720 case 1: /* bchg */
1721 tcg_gen_xori_i32(tmp, src1, mask);
1722 break;
1723 case 2: /* bclr */
1724 tcg_gen_andi_i32(tmp, src1, ~mask);
1725 break;
1726 case 3: /* bset */
1727 tcg_gen_ori_i32(tmp, src1, mask);
1728 break;
1729 default: /* btst */
1730 break;
1731 }
d4d79bb1 1732 DEST_EA(env, insn, opsize, tmp, &addr);
620c6cf6 1733 tcg_temp_free(tmp);
e6e5906b 1734 }
e6e5906b 1735}
620c6cf6 1736
e6e5906b
PB
1737DISAS_INSN(arith_im)
1738{
1739 int op;
92c62548 1740 TCGv im;
e1f3808e
PB
1741 TCGv src1;
1742 TCGv dest;
1743 TCGv addr;
92c62548 1744 int opsize;
e6e5906b
PB
1745
1746 op = (insn >> 9) & 7;
92c62548
LV
1747 opsize = insn_opsize(insn);
1748 switch (opsize) {
1749 case OS_BYTE:
1750 im = tcg_const_i32((int8_t)read_im8(env, s));
1751 break;
1752 case OS_WORD:
1753 im = tcg_const_i32((int16_t)read_im16(env, s));
1754 break;
1755 case OS_LONG:
1756 im = tcg_const_i32(read_im32(env, s));
1757 break;
1758 default:
1759 abort();
1760 }
1761 SRC_EA(env, src1, opsize, 1, (op == 6) ? NULL : &addr);
a7812ae4 1762 dest = tcg_temp_new();
e6e5906b
PB
1763 switch (op) {
1764 case 0: /* ori */
92c62548
LV
1765 tcg_gen_or_i32(dest, src1, im);
1766 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
1767 break;
1768 case 1: /* andi */
92c62548
LV
1769 tcg_gen_and_i32(dest, src1, im);
1770 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
1771 break;
1772 case 2: /* subi */
92c62548
LV
1773 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, src1, im);
1774 tcg_gen_sub_i32(dest, src1, im);
1775 gen_update_cc_add(dest, im, opsize);
1776 set_cc_op(s, CC_OP_SUBB + opsize);
e6e5906b
PB
1777 break;
1778 case 3: /* addi */
92c62548
LV
1779 tcg_gen_add_i32(dest, src1, im);
1780 gen_update_cc_add(dest, im, opsize);
1781 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, im);
1782 set_cc_op(s, CC_OP_ADDB + opsize);
e6e5906b
PB
1783 break;
1784 case 5: /* eori */
92c62548
LV
1785 tcg_gen_xor_i32(dest, src1, im);
1786 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
1787 break;
1788 case 6: /* cmpi */
92c62548 1789 gen_update_cc_cmp(s, src1, im, opsize);
e6e5906b
PB
1790 break;
1791 default:
1792 abort();
1793 }
92c62548 1794 tcg_temp_free(im);
e6e5906b 1795 if (op != 6) {
92c62548 1796 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 1797 }
92c62548 1798 tcg_temp_free(dest);
e6e5906b
PB
1799}
1800
1801DISAS_INSN(byterev)
1802{
e1f3808e 1803 TCGv reg;
e6e5906b
PB
1804
1805 reg = DREG(insn, 0);
66896cb8 1806 tcg_gen_bswap32_i32(reg, reg);
e6e5906b
PB
1807}
1808
1809DISAS_INSN(move)
1810{
e1f3808e
PB
1811 TCGv src;
1812 TCGv dest;
e6e5906b
PB
1813 int op;
1814 int opsize;
1815
1816 switch (insn >> 12) {
1817 case 1: /* move.b */
1818 opsize = OS_BYTE;
1819 break;
1820 case 2: /* move.l */
1821 opsize = OS_LONG;
1822 break;
1823 case 3: /* move.w */
1824 opsize = OS_WORD;
1825 break;
1826 default:
1827 abort();
1828 }
d4d79bb1 1829 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b
PB
1830 op = (insn >> 6) & 7;
1831 if (op == 1) {
1832 /* movea */
1833 /* The value will already have been sign extended. */
1834 dest = AREG(insn, 9);
e1f3808e 1835 tcg_gen_mov_i32(dest, src);
e6e5906b
PB
1836 } else {
1837 /* normal move */
1838 uint16_t dest_ea;
1839 dest_ea = ((insn >> 9) & 7) | (op << 3);
d4d79bb1 1840 DEST_EA(env, dest_ea, opsize, src, NULL);
e6e5906b 1841 /* This will be correct because loads sign extend. */
5dbb6784 1842 gen_logic_cc(s, src, opsize);
e6e5906b
PB
1843 }
1844}
1845
1846DISAS_INSN(negx)
1847{
a665a820
RH
1848 TCGv z;
1849 TCGv src;
1850 TCGv addr;
1851 int opsize;
e6e5906b 1852
a665a820
RH
1853 opsize = insn_opsize(insn);
1854 SRC_EA(env, src, opsize, 1, &addr);
1855
1856 gen_flush_flags(s); /* compute old Z */
1857
1858 /* Perform substract with borrow.
1859 * (X, N) = -(src + X);
1860 */
1861
1862 z = tcg_const_i32(0);
1863 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z);
1864 tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X);
1865 tcg_temp_free(z);
1866 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
1867
1868 tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
1869
1870 /* Compute signed-overflow for negation. The normal formula for
1871 * subtraction is (res ^ src) & (src ^ dest), but with dest==0
1872 * this simplies to res & src.
1873 */
1874
1875 tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, src);
1876
1877 /* Copy the rest of the results into place. */
1878 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
1879 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
1880
1881 set_cc_op(s, CC_OP_FLAGS);
1882
1883 /* result is in QREG_CC_N */
1884
1885 DEST_EA(env, insn, opsize, QREG_CC_N, &addr);
e6e5906b
PB
1886}
1887
1888DISAS_INSN(lea)
1889{
e1f3808e
PB
1890 TCGv reg;
1891 TCGv tmp;
e6e5906b
PB
1892
1893 reg = AREG(insn, 9);
d4d79bb1 1894 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 1895 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
1896 gen_addr_fault(s);
1897 return;
1898 }
e1f3808e 1899 tcg_gen_mov_i32(reg, tmp);
e6e5906b
PB
1900}
1901
1902DISAS_INSN(clr)
1903{
1904 int opsize;
1905
7ef25cdd 1906 opsize = insn_opsize(insn);
d4d79bb1 1907 DEST_EA(env, insn, opsize, tcg_const_i32(0), NULL);
5dbb6784 1908 gen_logic_cc(s, tcg_const_i32(0), opsize);
e6e5906b
PB
1909}
1910
e1f3808e 1911static TCGv gen_get_ccr(DisasContext *s)
e6e5906b 1912{
e1f3808e 1913 TCGv dest;
e6e5906b
PB
1914
1915 gen_flush_flags(s);
620c6cf6 1916 update_cc_op(s);
a7812ae4 1917 dest = tcg_temp_new();
620c6cf6 1918 gen_helper_get_ccr(dest, cpu_env);
0633879f
PB
1919 return dest;
1920}
1921
1922DISAS_INSN(move_from_ccr)
1923{
e1f3808e 1924 TCGv ccr;
0633879f
PB
1925
1926 ccr = gen_get_ccr(s);
7c0eb318 1927 DEST_EA(env, insn, OS_WORD, ccr, NULL);
e6e5906b
PB
1928}
1929
1930DISAS_INSN(neg)
1931{
e1f3808e 1932 TCGv src1;
227de713
LV
1933 TCGv dest;
1934 TCGv addr;
1935 int opsize;
e6e5906b 1936
227de713
LV
1937 opsize = insn_opsize(insn);
1938 SRC_EA(env, src1, opsize, 1, &addr);
1939 dest = tcg_temp_new();
1940 tcg_gen_neg_i32(dest, src1);
1941 set_cc_op(s, CC_OP_SUBB + opsize);
1942 gen_update_cc_add(dest, src1, opsize);
1943 tcg_gen_setcondi_i32(TCG_COND_NE, QREG_CC_X, dest, 0);
1944 DEST_EA(env, insn, opsize, dest, &addr);
1945 tcg_temp_free(dest);
e6e5906b
PB
1946}
1947
0633879f
PB
1948static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
1949{
620c6cf6
RH
1950 if (ccr_only) {
1951 tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0);
1952 tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0);
1953 tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1);
1954 tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0);
1955 tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0);
1956 } else {
1957 gen_helper_set_sr(cpu_env, tcg_const_i32(val));
0633879f 1958 }
9fdb533f 1959 set_cc_op(s, CC_OP_FLAGS);
0633879f
PB
1960}
1961
620c6cf6
RH
1962static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn,
1963 int ccr_only)
e6e5906b 1964{
620c6cf6
RH
1965 if ((insn & 0x38) == 0) {
1966 if (ccr_only) {
1967 gen_helper_set_ccr(cpu_env, DREG(insn, 0));
1968 } else {
1969 gen_helper_set_sr(cpu_env, DREG(insn, 0));
1970 }
1971 set_cc_op(s, CC_OP_FLAGS);
1972 } else if ((insn & 0x3f) == 0x3c) {
1973 uint16_t val;
1974 val = read_im16(env, s);
1975 gen_set_sr_im(s, val, ccr_only);
1976 } else {
1977 disas_undef(env, s, insn);
7c0eb318
LV
1978 }
1979}
e6e5906b 1980
7c0eb318 1981
0633879f
PB
1982DISAS_INSN(move_to_ccr)
1983{
620c6cf6 1984 gen_set_sr(env, s, insn, 1);
0633879f
PB
1985}
1986
e6e5906b
PB
1987DISAS_INSN(not)
1988{
ea4f2a84
LV
1989 TCGv src1;
1990 TCGv dest;
1991 TCGv addr;
1992 int opsize;
e6e5906b 1993
ea4f2a84
LV
1994 opsize = insn_opsize(insn);
1995 SRC_EA(env, src1, opsize, 1, &addr);
1996 dest = tcg_temp_new();
1997 tcg_gen_not_i32(dest, src1);
1998 DEST_EA(env, insn, opsize, dest, &addr);
1999 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
2000}
2001
2002DISAS_INSN(swap)
2003{
e1f3808e
PB
2004 TCGv src1;
2005 TCGv src2;
2006 TCGv reg;
e6e5906b 2007
a7812ae4
PB
2008 src1 = tcg_temp_new();
2009 src2 = tcg_temp_new();
e6e5906b 2010 reg = DREG(insn, 0);
e1f3808e
PB
2011 tcg_gen_shli_i32(src1, reg, 16);
2012 tcg_gen_shri_i32(src2, reg, 16);
2013 tcg_gen_or_i32(reg, src1, src2);
5dbb6784 2014 gen_logic_cc(s, reg, OS_LONG);
e6e5906b
PB
2015}
2016
71600eda
LV
2017DISAS_INSN(bkpt)
2018{
2019 gen_exception(s, s->pc - 2, EXCP_DEBUG);
2020}
2021
e6e5906b
PB
2022DISAS_INSN(pea)
2023{
e1f3808e 2024 TCGv tmp;
e6e5906b 2025
d4d79bb1 2026 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 2027 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
2028 gen_addr_fault(s);
2029 return;
2030 }
0633879f 2031 gen_push(s, tmp);
e6e5906b
PB
2032}
2033
2034DISAS_INSN(ext)
2035{
e6e5906b 2036 int op;
e1f3808e
PB
2037 TCGv reg;
2038 TCGv tmp;
e6e5906b
PB
2039
2040 reg = DREG(insn, 0);
2041 op = (insn >> 6) & 7;
a7812ae4 2042 tmp = tcg_temp_new();
e6e5906b 2043 if (op == 3)
e1f3808e 2044 tcg_gen_ext16s_i32(tmp, reg);
e6e5906b 2045 else
e1f3808e 2046 tcg_gen_ext8s_i32(tmp, reg);
e6e5906b
PB
2047 if (op == 2)
2048 gen_partset_reg(OS_WORD, reg, tmp);
2049 else
e1f3808e 2050 tcg_gen_mov_i32(reg, tmp);
5dbb6784 2051 gen_logic_cc(s, tmp, OS_LONG);
e6e5906b
PB
2052}
2053
2054DISAS_INSN(tst)
2055{
2056 int opsize;
e1f3808e 2057 TCGv tmp;
e6e5906b 2058
7ef25cdd 2059 opsize = insn_opsize(insn);
d4d79bb1 2060 SRC_EA(env, tmp, opsize, 1, NULL);
5dbb6784 2061 gen_logic_cc(s, tmp, opsize);
e6e5906b
PB
2062}
2063
2064DISAS_INSN(pulse)
2065{
2066 /* Implemented as a NOP. */
2067}
2068
2069DISAS_INSN(illegal)
2070{
2071 gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
2072}
2073
2074/* ??? This should be atomic. */
2075DISAS_INSN(tas)
2076{
e1f3808e
PB
2077 TCGv dest;
2078 TCGv src1;
2079 TCGv addr;
e6e5906b 2080
a7812ae4 2081 dest = tcg_temp_new();
d4d79bb1 2082 SRC_EA(env, src1, OS_BYTE, 1, &addr);
5dbb6784 2083 gen_logic_cc(s, src1, OS_BYTE);
e1f3808e 2084 tcg_gen_ori_i32(dest, src1, 0x80);
d4d79bb1 2085 DEST_EA(env, insn, OS_BYTE, dest, &addr);
e6e5906b
PB
2086}
2087
2088DISAS_INSN(mull)
2089{
2090 uint16_t ext;
e1f3808e 2091 TCGv src1;
8be95def 2092 int sign;
e6e5906b 2093
28b68cd7 2094 ext = read_im16(env, s);
8be95def
LV
2095
2096 sign = ext & 0x800;
2097
2098 if (ext & 0x400) {
2099 if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
2100 gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
2101 return;
2102 }
2103
2104 SRC_EA(env, src1, OS_LONG, 0, NULL);
2105
2106 if (sign) {
2107 tcg_gen_muls2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
2108 } else {
2109 tcg_gen_mulu2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
2110 }
2111 /* if Dl == Dh, 68040 returns low word */
2112 tcg_gen_mov_i32(DREG(ext, 0), QREG_CC_N);
2113 tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_Z);
2114 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N);
2115
2116 tcg_gen_movi_i32(QREG_CC_V, 0);
2117 tcg_gen_movi_i32(QREG_CC_C, 0);
2118
2119 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
2120 return;
2121 }
d4d79bb1 2122 SRC_EA(env, src1, OS_LONG, 0, NULL);
8be95def
LV
2123 if (m68k_feature(s->env, M68K_FEATURE_M68000)) {
2124 tcg_gen_movi_i32(QREG_CC_C, 0);
2125 if (sign) {
2126 tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
2127 /* QREG_CC_V is -(QREG_CC_V != (QREG_CC_N >> 31)) */
2128 tcg_gen_sari_i32(QREG_CC_Z, QREG_CC_N, 31);
2129 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_Z);
2130 } else {
2131 tcg_gen_mulu2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
2132 /* QREG_CC_V is -(QREG_CC_V != 0), use QREG_CC_C as 0 */
2133 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_C);
2134 }
2135 tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V);
2136 tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_N);
2137
2138 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
2139
2140 set_cc_op(s, CC_OP_FLAGS);
2141 } else {
2142 /* The upper 32 bits of the product are discarded, so
2143 muls.l and mulu.l are functionally equivalent. */
2144 tcg_gen_mul_i32(DREG(ext, 12), src1, DREG(ext, 12));
2145 gen_logic_cc(s, DREG(ext, 12), OS_LONG);
2146 }
e6e5906b
PB
2147}
2148
c630e436 2149static void gen_link(DisasContext *s, uint16_t insn, int32_t offset)
e6e5906b 2150{
e1f3808e
PB
2151 TCGv reg;
2152 TCGv tmp;
e6e5906b 2153
e6e5906b 2154 reg = AREG(insn, 0);
a7812ae4 2155 tmp = tcg_temp_new();
e1f3808e 2156 tcg_gen_subi_i32(tmp, QREG_SP, 4);
0633879f 2157 gen_store(s, OS_LONG, tmp, reg);
c630e436 2158 if ((insn & 7) != 7) {
e1f3808e 2159 tcg_gen_mov_i32(reg, tmp);
c630e436 2160 }
e1f3808e 2161 tcg_gen_addi_i32(QREG_SP, tmp, offset);
c630e436
LV
2162 tcg_temp_free(tmp);
2163}
2164
2165DISAS_INSN(link)
2166{
2167 int16_t offset;
2168
2169 offset = read_im16(env, s);
2170 gen_link(s, insn, offset);
2171}
2172
2173DISAS_INSN(linkl)
2174{
2175 int32_t offset;
2176
2177 offset = read_im32(env, s);
2178 gen_link(s, insn, offset);
e6e5906b
PB
2179}
2180
2181DISAS_INSN(unlk)
2182{
e1f3808e
PB
2183 TCGv src;
2184 TCGv reg;
2185 TCGv tmp;
e6e5906b 2186
a7812ae4 2187 src = tcg_temp_new();
e6e5906b 2188 reg = AREG(insn, 0);
e1f3808e 2189 tcg_gen_mov_i32(src, reg);
0633879f 2190 tmp = gen_load(s, OS_LONG, src, 0);
e1f3808e
PB
2191 tcg_gen_mov_i32(reg, tmp);
2192 tcg_gen_addi_i32(QREG_SP, src, 4);
e6e5906b
PB
2193}
2194
2195DISAS_INSN(nop)
2196{
2197}
2198
2199DISAS_INSN(rts)
2200{
e1f3808e 2201 TCGv tmp;
e6e5906b 2202
0633879f 2203 tmp = gen_load(s, OS_LONG, QREG_SP, 0);
e1f3808e 2204 tcg_gen_addi_i32(QREG_SP, QREG_SP, 4);
e6e5906b
PB
2205 gen_jmp(s, tmp);
2206}
2207
2208DISAS_INSN(jump)
2209{
e1f3808e 2210 TCGv tmp;
e6e5906b
PB
2211
2212 /* Load the target address first to ensure correct exception
2213 behavior. */
d4d79bb1 2214 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 2215 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
2216 gen_addr_fault(s);
2217 return;
2218 }
e6e5906b
PB
2219 if ((insn & 0x40) == 0) {
2220 /* jsr */
351326a6 2221 gen_push(s, tcg_const_i32(s->pc));
e6e5906b
PB
2222 }
2223 gen_jmp(s, tmp);
2224}
2225
2226DISAS_INSN(addsubq)
2227{
8a370c6c 2228 TCGv src;
e1f3808e 2229 TCGv dest;
8a370c6c
LV
2230 TCGv val;
2231 int imm;
e1f3808e 2232 TCGv addr;
8a370c6c 2233 int opsize;
e6e5906b 2234
8a370c6c
LV
2235 if ((insn & 070) == 010) {
2236 /* Operation on address register is always long. */
2237 opsize = OS_LONG;
2238 } else {
2239 opsize = insn_opsize(insn);
2240 }
2241 SRC_EA(env, src, opsize, 1, &addr);
2242 imm = (insn >> 9) & 7;
2243 if (imm == 0) {
2244 imm = 8;
2245 }
2246 val = tcg_const_i32(imm);
a7812ae4 2247 dest = tcg_temp_new();
8a370c6c 2248 tcg_gen_mov_i32(dest, src);
e6e5906b
PB
2249 if ((insn & 0x38) == 0x08) {
2250 /* Don't update condition codes if the destination is an
2251 address register. */
2252 if (insn & 0x0100) {
8a370c6c 2253 tcg_gen_sub_i32(dest, dest, val);
e6e5906b 2254 } else {
8a370c6c 2255 tcg_gen_add_i32(dest, dest, val);
e6e5906b
PB
2256 }
2257 } else {
2258 if (insn & 0x0100) {
8a370c6c
LV
2259 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2260 tcg_gen_sub_i32(dest, dest, val);
2261 set_cc_op(s, CC_OP_SUBB + opsize);
e6e5906b 2262 } else {
8a370c6c
LV
2263 tcg_gen_add_i32(dest, dest, val);
2264 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2265 set_cc_op(s, CC_OP_ADDB + opsize);
e6e5906b 2266 }
8a370c6c 2267 gen_update_cc_add(dest, val, opsize);
e6e5906b 2268 }
8a370c6c 2269 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b
PB
2270}
2271
2272DISAS_INSN(tpf)
2273{
2274 switch (insn & 7) {
2275 case 2: /* One extension word. */
2276 s->pc += 2;
2277 break;
2278 case 3: /* Two extension words. */
2279 s->pc += 4;
2280 break;
2281 case 4: /* No extension words. */
2282 break;
2283 default:
d4d79bb1 2284 disas_undef(env, s, insn);
e6e5906b
PB
2285 }
2286}
2287
2288DISAS_INSN(branch)
2289{
2290 int32_t offset;
2291 uint32_t base;
2292 int op;
42a268c2 2293 TCGLabel *l1;
3b46e624 2294
e6e5906b
PB
2295 base = s->pc;
2296 op = (insn >> 8) & 0xf;
2297 offset = (int8_t)insn;
2298 if (offset == 0) {
28b68cd7 2299 offset = (int16_t)read_im16(env, s);
e6e5906b 2300 } else if (offset == -1) {
d4d79bb1 2301 offset = read_im32(env, s);
e6e5906b
PB
2302 }
2303 if (op == 1) {
2304 /* bsr */
351326a6 2305 gen_push(s, tcg_const_i32(s->pc));
e6e5906b 2306 }
e6e5906b
PB
2307 if (op > 1) {
2308 /* Bcc */
2309 l1 = gen_new_label();
2310 gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
2311 gen_jmp_tb(s, 1, base + offset);
2312 gen_set_label(l1);
2313 gen_jmp_tb(s, 0, s->pc);
2314 } else {
2315 /* Unconditional branch. */
2316 gen_jmp_tb(s, 0, base + offset);
2317 }
2318}
2319
2320DISAS_INSN(moveq)
2321{
e1f3808e 2322 uint32_t val;
e6e5906b 2323
e1f3808e
PB
2324 val = (int8_t)insn;
2325 tcg_gen_movi_i32(DREG(insn, 9), val);
5dbb6784 2326 gen_logic_cc(s, tcg_const_i32(val), OS_LONG);
e6e5906b
PB
2327}
2328
2329DISAS_INSN(mvzs)
2330{
2331 int opsize;
e1f3808e
PB
2332 TCGv src;
2333 TCGv reg;
e6e5906b
PB
2334
2335 if (insn & 0x40)
2336 opsize = OS_WORD;
2337 else
2338 opsize = OS_BYTE;
d4d79bb1 2339 SRC_EA(env, src, opsize, (insn & 0x80) == 0, NULL);
e6e5906b 2340 reg = DREG(insn, 9);
e1f3808e 2341 tcg_gen_mov_i32(reg, src);
5dbb6784 2342 gen_logic_cc(s, src, opsize);
e6e5906b
PB
2343}
2344
2345DISAS_INSN(or)
2346{
e1f3808e
PB
2347 TCGv reg;
2348 TCGv dest;
2349 TCGv src;
2350 TCGv addr;
020a4659 2351 int opsize;
e6e5906b 2352
020a4659
LV
2353 opsize = insn_opsize(insn);
2354 reg = gen_extend(DREG(insn, 9), opsize, 0);
a7812ae4 2355 dest = tcg_temp_new();
e6e5906b 2356 if (insn & 0x100) {
020a4659 2357 SRC_EA(env, src, opsize, 0, &addr);
e1f3808e 2358 tcg_gen_or_i32(dest, src, reg);
020a4659 2359 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 2360 } else {
020a4659 2361 SRC_EA(env, src, opsize, 0, NULL);
e1f3808e 2362 tcg_gen_or_i32(dest, src, reg);
020a4659 2363 gen_partset_reg(opsize, DREG(insn, 9), dest);
e6e5906b 2364 }
020a4659 2365 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
2366}
2367
2368DISAS_INSN(suba)
2369{
e1f3808e
PB
2370 TCGv src;
2371 TCGv reg;
e6e5906b 2372
415f4b62 2373 SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
e6e5906b 2374 reg = AREG(insn, 9);
e1f3808e 2375 tcg_gen_sub_i32(reg, reg, src);
e6e5906b
PB
2376}
2377
a665a820 2378static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
e6e5906b 2379{
a665a820
RH
2380 TCGv tmp;
2381
2382 gen_flush_flags(s); /* compute old Z */
2383
2384 /* Perform substract with borrow.
2385 * (X, N) = dest - (src + X);
2386 */
2387
2388 tmp = tcg_const_i32(0);
2389 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, tmp, QREG_CC_X, tmp);
2390 tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, dest, tmp, QREG_CC_N, QREG_CC_X);
2391 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2392 tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
2393
2394 /* Compute signed-overflow for substract. */
2395
2396 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, dest);
2397 tcg_gen_xor_i32(tmp, dest, src);
2398 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, tmp);
2399 tcg_temp_free(tmp);
2400
2401 /* Copy the rest of the results into place. */
2402 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2403 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2404
2405 set_cc_op(s, CC_OP_FLAGS);
2406
2407 /* result is in QREG_CC_N */
2408}
2409
2410DISAS_INSN(subx_reg)
2411{
2412 TCGv dest;
e1f3808e 2413 TCGv src;
a665a820 2414 int opsize;
e6e5906b 2415
a665a820
RH
2416 opsize = insn_opsize(insn);
2417
2418 src = gen_extend(DREG(insn, 0), opsize, 1);
2419 dest = gen_extend(DREG(insn, 9), opsize, 1);
2420
2421 gen_subx(s, src, dest, opsize);
2422
2423 gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
2424}
2425
2426DISAS_INSN(subx_mem)
2427{
2428 TCGv src;
2429 TCGv addr_src;
2430 TCGv dest;
2431 TCGv addr_dest;
2432 int opsize;
2433
2434 opsize = insn_opsize(insn);
2435
2436 addr_src = AREG(insn, 0);
2437 tcg_gen_subi_i32(addr_src, addr_src, opsize);
2438 src = gen_load(s, opsize, addr_src, 1);
2439
2440 addr_dest = AREG(insn, 9);
2441 tcg_gen_subi_i32(addr_dest, addr_dest, opsize);
2442 dest = gen_load(s, opsize, addr_dest, 1);
2443
2444 gen_subx(s, src, dest, opsize);
2445
2446 gen_store(s, opsize, addr_dest, QREG_CC_N);
e6e5906b
PB
2447}
2448
2449DISAS_INSN(mov3q)
2450{
e1f3808e 2451 TCGv src;
e6e5906b
PB
2452 int val;
2453
2454 val = (insn >> 9) & 7;
2455 if (val == 0)
2456 val = -1;
351326a6 2457 src = tcg_const_i32(val);
5dbb6784 2458 gen_logic_cc(s, src, OS_LONG);
d4d79bb1 2459 DEST_EA(env, insn, OS_LONG, src, NULL);
e6e5906b
PB
2460}
2461
2462DISAS_INSN(cmp)
2463{
e1f3808e
PB
2464 TCGv src;
2465 TCGv reg;
e6e5906b
PB
2466 int opsize;
2467
5dbb6784 2468 opsize = insn_opsize(insn);
ff99b952
LV
2469 SRC_EA(env, src, opsize, 1, NULL);
2470 reg = gen_extend(DREG(insn, 9), opsize, 1);
2471 gen_update_cc_cmp(s, reg, src, opsize);
e6e5906b
PB
2472}
2473
2474DISAS_INSN(cmpa)
2475{
2476 int opsize;
e1f3808e
PB
2477 TCGv src;
2478 TCGv reg;
e6e5906b
PB
2479
2480 if (insn & 0x100) {
2481 opsize = OS_LONG;
2482 } else {
2483 opsize = OS_WORD;
2484 }
d4d79bb1 2485 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b 2486 reg = AREG(insn, 9);
5436c29d 2487 gen_update_cc_cmp(s, reg, src, OS_LONG);
e6e5906b
PB
2488}
2489
817af1c7
LV
2490DISAS_INSN(cmpm)
2491{
2492 int opsize = insn_opsize(insn);
2493 TCGv src, dst;
2494
2495 /* Post-increment load (mode 3) from Ay. */
2496 src = gen_ea_mode(env, s, 3, REG(insn, 0), opsize,
2497 NULL_QREG, NULL, EA_LOADS);
2498 /* Post-increment load (mode 3) from Ax. */
2499 dst = gen_ea_mode(env, s, 3, REG(insn, 9), opsize,
2500 NULL_QREG, NULL, EA_LOADS);
2501
2502 gen_update_cc_cmp(s, dst, src, opsize);
2503}
2504
e6e5906b
PB
2505DISAS_INSN(eor)
2506{
e1f3808e 2507 TCGv src;
e1f3808e
PB
2508 TCGv dest;
2509 TCGv addr;
eec37aec 2510 int opsize;
e6e5906b 2511
eec37aec
LV
2512 opsize = insn_opsize(insn);
2513
2514 SRC_EA(env, src, opsize, 0, &addr);
a7812ae4 2515 dest = tcg_temp_new();
eec37aec
LV
2516 tcg_gen_xor_i32(dest, src, DREG(insn, 9));
2517 gen_logic_cc(s, dest, opsize);
2518 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b
PB
2519}
2520
29cf437d
LV
2521static void do_exg(TCGv reg1, TCGv reg2)
2522{
2523 TCGv temp = tcg_temp_new();
2524 tcg_gen_mov_i32(temp, reg1);
2525 tcg_gen_mov_i32(reg1, reg2);
2526 tcg_gen_mov_i32(reg2, temp);
2527 tcg_temp_free(temp);
2528}
2529
c090c97d 2530DISAS_INSN(exg_dd)
29cf437d
LV
2531{
2532 /* exchange Dx and Dy */
2533 do_exg(DREG(insn, 9), DREG(insn, 0));
2534}
2535
c090c97d 2536DISAS_INSN(exg_aa)
29cf437d
LV
2537{
2538 /* exchange Ax and Ay */
2539 do_exg(AREG(insn, 9), AREG(insn, 0));
2540}
2541
2542DISAS_INSN(exg_da)
2543{
2544 /* exchange Dx and Ay */
2545 do_exg(DREG(insn, 9), AREG(insn, 0));
2546}
2547
e6e5906b
PB
2548DISAS_INSN(and)
2549{
e1f3808e
PB
2550 TCGv src;
2551 TCGv reg;
2552 TCGv dest;
2553 TCGv addr;
52dc23c5 2554 int opsize;
e6e5906b 2555
a7812ae4 2556 dest = tcg_temp_new();
52dc23c5
LV
2557
2558 opsize = insn_opsize(insn);
2559 reg = DREG(insn, 9);
e6e5906b 2560 if (insn & 0x100) {
52dc23c5 2561 SRC_EA(env, src, opsize, 0, &addr);
e1f3808e 2562 tcg_gen_and_i32(dest, src, reg);
52dc23c5 2563 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 2564 } else {
52dc23c5 2565 SRC_EA(env, src, opsize, 0, NULL);
e1f3808e 2566 tcg_gen_and_i32(dest, src, reg);
52dc23c5 2567 gen_partset_reg(opsize, reg, dest);
e6e5906b 2568 }
52dc23c5
LV
2569 tcg_temp_free(dest);
2570 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
2571}
2572
2573DISAS_INSN(adda)
2574{
e1f3808e
PB
2575 TCGv src;
2576 TCGv reg;
e6e5906b 2577
415f4b62 2578 SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
e6e5906b 2579 reg = AREG(insn, 9);
e1f3808e 2580 tcg_gen_add_i32(reg, reg, src);
e6e5906b
PB
2581}
2582
a665a820 2583static inline void gen_addx(DisasContext *s, TCGv src, TCGv dest, int opsize)
e6e5906b 2584{
a665a820
RH
2585 TCGv tmp;
2586
2587 gen_flush_flags(s); /* compute old Z */
2588
2589 /* Perform addition with carry.
2590 * (X, N) = src + dest + X;
2591 */
2592
2593 tmp = tcg_const_i32(0);
2594 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_X, tmp, dest, tmp);
2595 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, tmp);
2596 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2597
2598 /* Compute signed-overflow for addition. */
2599
2600 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
2601 tcg_gen_xor_i32(tmp, dest, src);
2602 tcg_gen_andc_i32(QREG_CC_V, QREG_CC_V, tmp);
2603 tcg_temp_free(tmp);
2604
2605 /* Copy the rest of the results into place. */
2606 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2607 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2608
2609 set_cc_op(s, CC_OP_FLAGS);
2610
2611 /* result is in QREG_CC_N */
2612}
2613
2614DISAS_INSN(addx_reg)
2615{
2616 TCGv dest;
e1f3808e 2617 TCGv src;
a665a820 2618 int opsize;
e6e5906b 2619
a665a820
RH
2620 opsize = insn_opsize(insn);
2621
2622 dest = gen_extend(DREG(insn, 9), opsize, 1);
2623 src = gen_extend(DREG(insn, 0), opsize, 1);
2624
2625 gen_addx(s, src, dest, opsize);
2626
2627 gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
2628}
2629
2630DISAS_INSN(addx_mem)
2631{
2632 TCGv src;
2633 TCGv addr_src;
2634 TCGv dest;
2635 TCGv addr_dest;
2636 int opsize;
2637
2638 opsize = insn_opsize(insn);
2639
2640 addr_src = AREG(insn, 0);
2641 tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
2642 src = gen_load(s, opsize, addr_src, 1);
2643
2644 addr_dest = AREG(insn, 9);
2645 tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
2646 dest = gen_load(s, opsize, addr_dest, 1);
2647
2648 gen_addx(s, src, dest, opsize);
2649
2650 gen_store(s, opsize, addr_dest, QREG_CC_N);
e6e5906b
PB
2651}
2652
e1f3808e 2653/* TODO: This could be implemented without helper functions. */
e6e5906b
PB
2654DISAS_INSN(shift_im)
2655{
e1f3808e 2656 TCGv reg;
e6e5906b 2657 int tmp;
e1f3808e 2658 TCGv shift;
e6e5906b 2659
620c6cf6
RH
2660 set_cc_op(s, CC_OP_FLAGS);
2661
e6e5906b
PB
2662 reg = DREG(insn, 0);
2663 tmp = (insn >> 9) & 7;
2664 if (tmp == 0)
e1f3808e 2665 tmp = 8;
351326a6 2666 shift = tcg_const_i32(tmp);
e1f3808e 2667 /* No need to flush flags becuse we know we will set C flag. */
e6e5906b 2668 if (insn & 0x100) {
e1f3808e 2669 gen_helper_shl_cc(reg, cpu_env, reg, shift);
e6e5906b
PB
2670 } else {
2671 if (insn & 8) {
e1f3808e 2672 gen_helper_shr_cc(reg, cpu_env, reg, shift);
e6e5906b 2673 } else {
e1f3808e 2674 gen_helper_sar_cc(reg, cpu_env, reg, shift);
e6e5906b
PB
2675 }
2676 }
2677}
2678
2679DISAS_INSN(shift_reg)
2680{
e1f3808e
PB
2681 TCGv reg;
2682 TCGv shift;
e6e5906b
PB
2683
2684 reg = DREG(insn, 0);
e1f3808e 2685 shift = DREG(insn, 9);
e6e5906b 2686 if (insn & 0x100) {
e1f3808e 2687 gen_helper_shl_cc(reg, cpu_env, reg, shift);
e6e5906b
PB
2688 } else {
2689 if (insn & 8) {
e1f3808e 2690 gen_helper_shr_cc(reg, cpu_env, reg, shift);
e6e5906b 2691 } else {
e1f3808e 2692 gen_helper_sar_cc(reg, cpu_env, reg, shift);
e6e5906b
PB
2693 }
2694 }
620c6cf6 2695 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
2696}
2697
2698DISAS_INSN(ff1)
2699{
e1f3808e 2700 TCGv reg;
821f7e76 2701 reg = DREG(insn, 0);
5dbb6784 2702 gen_logic_cc(s, reg, OS_LONG);
e1f3808e 2703 gen_helper_ff1(reg, reg);
e6e5906b
PB
2704}
2705
e1f3808e 2706static TCGv gen_get_sr(DisasContext *s)
0633879f 2707{
e1f3808e
PB
2708 TCGv ccr;
2709 TCGv sr;
0633879f
PB
2710
2711 ccr = gen_get_ccr(s);
a7812ae4 2712 sr = tcg_temp_new();
e1f3808e
PB
2713 tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
2714 tcg_gen_or_i32(sr, sr, ccr);
0633879f
PB
2715 return sr;
2716}
2717
e6e5906b
PB
2718DISAS_INSN(strldsr)
2719{
2720 uint16_t ext;
2721 uint32_t addr;
2722
2723 addr = s->pc - 2;
28b68cd7 2724 ext = read_im16(env, s);
0633879f 2725 if (ext != 0x46FC) {
e6e5906b 2726 gen_exception(s, addr, EXCP_UNSUPPORTED);
0633879f
PB
2727 return;
2728 }
28b68cd7 2729 ext = read_im16(env, s);
0633879f 2730 if (IS_USER(s) || (ext & SR_S) == 0) {
e6e5906b 2731 gen_exception(s, addr, EXCP_PRIVILEGE);
0633879f
PB
2732 return;
2733 }
2734 gen_push(s, gen_get_sr(s));
2735 gen_set_sr_im(s, ext, 0);
e6e5906b
PB
2736}
2737
2738DISAS_INSN(move_from_sr)
2739{
e1f3808e 2740 TCGv sr;
0633879f 2741
7c0eb318 2742 if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) {
0633879f
PB
2743 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2744 return;
2745 }
2746 sr = gen_get_sr(s);
7c0eb318 2747 DEST_EA(env, insn, OS_WORD, sr, NULL);
e6e5906b
PB
2748}
2749
2750DISAS_INSN(move_to_sr)
2751{
0633879f
PB
2752 if (IS_USER(s)) {
2753 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2754 return;
2755 }
620c6cf6 2756 gen_set_sr(env, s, insn, 0);
0633879f 2757 gen_lookup_tb(s);
e6e5906b
PB
2758}
2759
2760DISAS_INSN(move_from_usp)
2761{
0633879f
PB
2762 if (IS_USER(s)) {
2763 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2764 return;
2765 }
2a8327e8
GU
2766 tcg_gen_ld_i32(AREG(insn, 0), cpu_env,
2767 offsetof(CPUM68KState, sp[M68K_USP]));
e6e5906b
PB
2768}
2769
2770DISAS_INSN(move_to_usp)
2771{
0633879f
PB
2772 if (IS_USER(s)) {
2773 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2774 return;
2775 }
2a8327e8
GU
2776 tcg_gen_st_i32(AREG(insn, 0), cpu_env,
2777 offsetof(CPUM68KState, sp[M68K_USP]));
e6e5906b
PB
2778}
2779
2780DISAS_INSN(halt)
2781{
e1f3808e 2782 gen_exception(s, s->pc, EXCP_HALT_INSN);
e6e5906b
PB
2783}
2784
2785DISAS_INSN(stop)
2786{
0633879f
PB
2787 uint16_t ext;
2788
2789 if (IS_USER(s)) {
2790 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2791 return;
2792 }
2793
28b68cd7 2794 ext = read_im16(env, s);
0633879f
PB
2795
2796 gen_set_sr_im(s, ext, 0);
259186a7 2797 tcg_gen_movi_i32(cpu_halted, 1);
e1f3808e 2798 gen_exception(s, s->pc, EXCP_HLT);
e6e5906b
PB
2799}
2800
2801DISAS_INSN(rte)
2802{
0633879f
PB
2803 if (IS_USER(s)) {
2804 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2805 return;
2806 }
2807 gen_exception(s, s->pc - 2, EXCP_RTE);
e6e5906b
PB
2808}
2809
2810DISAS_INSN(movec)
2811{
0633879f 2812 uint16_t ext;
e1f3808e 2813 TCGv reg;
0633879f
PB
2814
2815 if (IS_USER(s)) {
2816 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2817 return;
2818 }
2819
28b68cd7 2820 ext = read_im16(env, s);
0633879f
PB
2821
2822 if (ext & 0x8000) {
2823 reg = AREG(ext, 12);
2824 } else {
2825 reg = DREG(ext, 12);
2826 }
e1f3808e 2827 gen_helper_movec(cpu_env, tcg_const_i32(ext & 0xfff), reg);
0633879f 2828 gen_lookup_tb(s);
e6e5906b
PB
2829}
2830
2831DISAS_INSN(intouch)
2832{
0633879f
PB
2833 if (IS_USER(s)) {
2834 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2835 return;
2836 }
2837 /* ICache fetch. Implement as no-op. */
e6e5906b
PB
2838}
2839
2840DISAS_INSN(cpushl)
2841{
0633879f
PB
2842 if (IS_USER(s)) {
2843 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2844 return;
2845 }
2846 /* Cache push/invalidate. Implement as no-op. */
e6e5906b
PB
2847}
2848
2849DISAS_INSN(wddata)
2850{
2851 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2852}
2853
2854DISAS_INSN(wdebug)
2855{
a47dddd7
AF
2856 M68kCPU *cpu = m68k_env_get_cpu(env);
2857
0633879f
PB
2858 if (IS_USER(s)) {
2859 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
2860 return;
2861 }
2862 /* TODO: Implement wdebug. */
a47dddd7 2863 cpu_abort(CPU(cpu), "WDEBUG not implemented");
e6e5906b
PB
2864}
2865
2866DISAS_INSN(trap)
2867{
2868 gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf));
2869}
2870
2871/* ??? FP exceptions are not implemented. Most exceptions are deferred until
2872 immediately before the next FP instruction is executed. */
2873DISAS_INSN(fpu)
2874{
2875 uint16_t ext;
a7812ae4 2876 int32_t offset;
e6e5906b 2877 int opmode;
a7812ae4
PB
2878 TCGv_i64 src;
2879 TCGv_i64 dest;
2880 TCGv_i64 res;
2881 TCGv tmp32;
e6e5906b 2882 int round;
a7812ae4 2883 int set_dest;
e6e5906b
PB
2884 int opsize;
2885
28b68cd7 2886 ext = read_im16(env, s);
e6e5906b
PB
2887 opmode = ext & 0x7f;
2888 switch ((ext >> 13) & 7) {
2889 case 0: case 2:
2890 break;
2891 case 1:
2892 goto undef;
2893 case 3: /* fmove out */
2894 src = FREG(ext, 7);
a7812ae4 2895 tmp32 = tcg_temp_new_i32();
e6e5906b
PB
2896 /* fmove */
2897 /* ??? TODO: Proper behavior on overflow. */
2898 switch ((ext >> 10) & 7) {
2899 case 0:
2900 opsize = OS_LONG;
a7812ae4 2901 gen_helper_f64_to_i32(tmp32, cpu_env, src);
e6e5906b
PB
2902 break;
2903 case 1:
2904 opsize = OS_SINGLE;
a7812ae4 2905 gen_helper_f64_to_f32(tmp32, cpu_env, src);
e6e5906b
PB
2906 break;
2907 case 4:
2908 opsize = OS_WORD;
a7812ae4 2909 gen_helper_f64_to_i32(tmp32, cpu_env, src);
e6e5906b 2910 break;
a7812ae4
PB
2911 case 5: /* OS_DOUBLE */
2912 tcg_gen_mov_i32(tmp32, AREG(insn, 0));
c59b97aa 2913 switch ((insn >> 3) & 7) {
a7812ae4
PB
2914 case 2:
2915 case 3:
243ee8f7 2916 break;
a7812ae4
PB
2917 case 4:
2918 tcg_gen_addi_i32(tmp32, tmp32, -8);
2919 break;
2920 case 5:
d4d79bb1 2921 offset = cpu_ldsw_code(env, s->pc);
a7812ae4
PB
2922 s->pc += 2;
2923 tcg_gen_addi_i32(tmp32, tmp32, offset);
2924 break;
2925 default:
2926 goto undef;
2927 }
2928 gen_store64(s, tmp32, src);
c59b97aa 2929 switch ((insn >> 3) & 7) {
a7812ae4
PB
2930 case 3:
2931 tcg_gen_addi_i32(tmp32, tmp32, 8);
2932 tcg_gen_mov_i32(AREG(insn, 0), tmp32);
2933 break;
2934 case 4:
2935 tcg_gen_mov_i32(AREG(insn, 0), tmp32);
2936 break;
2937 }
2938 tcg_temp_free_i32(tmp32);
2939 return;
e6e5906b
PB
2940 case 6:
2941 opsize = OS_BYTE;
a7812ae4 2942 gen_helper_f64_to_i32(tmp32, cpu_env, src);
e6e5906b
PB
2943 break;
2944 default:
2945 goto undef;
2946 }
d4d79bb1 2947 DEST_EA(env, insn, opsize, tmp32, NULL);
a7812ae4 2948 tcg_temp_free_i32(tmp32);
e6e5906b
PB
2949 return;
2950 case 4: /* fmove to control register. */
2951 switch ((ext >> 10) & 7) {
2952 case 4: /* FPCR */
2953 /* Not implemented. Ignore writes. */
2954 break;
2955 case 1: /* FPIAR */
2956 case 2: /* FPSR */
2957 default:
2958 cpu_abort(NULL, "Unimplemented: fmove to control %d",
2959 (ext >> 10) & 7);
2960 }
2961 break;
2962 case 5: /* fmove from control register. */
2963 switch ((ext >> 10) & 7) {
2964 case 4: /* FPCR */
2965 /* Not implemented. Always return zero. */
351326a6 2966 tmp32 = tcg_const_i32(0);
e6e5906b
PB
2967 break;
2968 case 1: /* FPIAR */
2969 case 2: /* FPSR */
2970 default:
2971 cpu_abort(NULL, "Unimplemented: fmove from control %d",
2972 (ext >> 10) & 7);
2973 goto undef;
2974 }
d4d79bb1 2975 DEST_EA(env, insn, OS_LONG, tmp32, NULL);
e6e5906b 2976 break;
5fafdf24 2977 case 6: /* fmovem */
e6e5906b
PB
2978 case 7:
2979 {
e1f3808e
PB
2980 TCGv addr;
2981 uint16_t mask;
2982 int i;
2983 if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
2984 goto undef;
d4d79bb1 2985 tmp32 = gen_lea(env, s, insn, OS_LONG);
a7812ae4 2986 if (IS_NULL_QREG(tmp32)) {
e1f3808e
PB
2987 gen_addr_fault(s);
2988 return;
2989 }
a7812ae4
PB
2990 addr = tcg_temp_new_i32();
2991 tcg_gen_mov_i32(addr, tmp32);
e1f3808e
PB
2992 mask = 0x80;
2993 for (i = 0; i < 8; i++) {
2994 if (ext & mask) {
e1f3808e
PB
2995 dest = FREG(i, 0);
2996 if (ext & (1 << 13)) {
2997 /* store */
2998 tcg_gen_qemu_stf64(dest, addr, IS_USER(s));
2999 } else {
3000 /* load */
3001 tcg_gen_qemu_ldf64(dest, addr, IS_USER(s));
3002 }
3003 if (ext & (mask - 1))
3004 tcg_gen_addi_i32(addr, addr, 8);
e6e5906b 3005 }
e1f3808e 3006 mask >>= 1;
e6e5906b 3007 }
18307f26 3008 tcg_temp_free_i32(addr);
e6e5906b
PB
3009 }
3010 return;
3011 }
3012 if (ext & (1 << 14)) {
e6e5906b
PB
3013 /* Source effective address. */
3014 switch ((ext >> 10) & 7) {
3015 case 0: opsize = OS_LONG; break;
3016 case 1: opsize = OS_SINGLE; break;
3017 case 4: opsize = OS_WORD; break;
3018 case 5: opsize = OS_DOUBLE; break;
3019 case 6: opsize = OS_BYTE; break;
3020 default:
3021 goto undef;
3022 }
e6e5906b 3023 if (opsize == OS_DOUBLE) {
a7812ae4
PB
3024 tmp32 = tcg_temp_new_i32();
3025 tcg_gen_mov_i32(tmp32, AREG(insn, 0));
c59b97aa 3026 switch ((insn >> 3) & 7) {
a7812ae4
PB
3027 case 2:
3028 case 3:
243ee8f7 3029 break;
a7812ae4
PB
3030 case 4:
3031 tcg_gen_addi_i32(tmp32, tmp32, -8);
3032 break;
3033 case 5:
d4d79bb1 3034 offset = cpu_ldsw_code(env, s->pc);
a7812ae4
PB
3035 s->pc += 2;
3036 tcg_gen_addi_i32(tmp32, tmp32, offset);
3037 break;
3038 case 7:
d4d79bb1 3039 offset = cpu_ldsw_code(env, s->pc);
a7812ae4
PB
3040 offset += s->pc - 2;
3041 s->pc += 2;
3042 tcg_gen_addi_i32(tmp32, tmp32, offset);
3043 break;
3044 default:
3045 goto undef;
3046 }
3047 src = gen_load64(s, tmp32);
c59b97aa 3048 switch ((insn >> 3) & 7) {
a7812ae4
PB
3049 case 3:
3050 tcg_gen_addi_i32(tmp32, tmp32, 8);
3051 tcg_gen_mov_i32(AREG(insn, 0), tmp32);
3052 break;
3053 case 4:
3054 tcg_gen_mov_i32(AREG(insn, 0), tmp32);
3055 break;
3056 }
3057 tcg_temp_free_i32(tmp32);
e6e5906b 3058 } else {
d4d79bb1 3059 SRC_EA(env, tmp32, opsize, 1, NULL);
a7812ae4 3060 src = tcg_temp_new_i64();
e6e5906b
PB
3061 switch (opsize) {
3062 case OS_LONG:
3063 case OS_WORD:
3064 case OS_BYTE:
a7812ae4 3065 gen_helper_i32_to_f64(src, cpu_env, tmp32);
e6e5906b
PB
3066 break;
3067 case OS_SINGLE:
a7812ae4 3068 gen_helper_f32_to_f64(src, cpu_env, tmp32);
e6e5906b
PB
3069 break;
3070 }
3071 }
3072 } else {
3073 /* Source register. */
3074 src = FREG(ext, 10);
3075 }
3076 dest = FREG(ext, 7);
a7812ae4 3077 res = tcg_temp_new_i64();
e6e5906b 3078 if (opmode != 0x3a)
e1f3808e 3079 tcg_gen_mov_f64(res, dest);
e6e5906b 3080 round = 1;
a7812ae4 3081 set_dest = 1;
e6e5906b
PB
3082 switch (opmode) {
3083 case 0: case 0x40: case 0x44: /* fmove */
e1f3808e 3084 tcg_gen_mov_f64(res, src);
e6e5906b
PB
3085 break;
3086 case 1: /* fint */
e1f3808e 3087 gen_helper_iround_f64(res, cpu_env, src);
e6e5906b
PB
3088 round = 0;
3089 break;
3090 case 3: /* fintrz */
e1f3808e 3091 gen_helper_itrunc_f64(res, cpu_env, src);
e6e5906b
PB
3092 round = 0;
3093 break;
3094 case 4: case 0x41: case 0x45: /* fsqrt */
e1f3808e 3095 gen_helper_sqrt_f64(res, cpu_env, src);
e6e5906b
PB
3096 break;
3097 case 0x18: case 0x58: case 0x5c: /* fabs */
e1f3808e 3098 gen_helper_abs_f64(res, src);
e6e5906b
PB
3099 break;
3100 case 0x1a: case 0x5a: case 0x5e: /* fneg */
e1f3808e 3101 gen_helper_chs_f64(res, src);
e6e5906b
PB
3102 break;
3103 case 0x20: case 0x60: case 0x64: /* fdiv */
e1f3808e 3104 gen_helper_div_f64(res, cpu_env, res, src);
e6e5906b
PB
3105 break;
3106 case 0x22: case 0x62: case 0x66: /* fadd */
e1f3808e 3107 gen_helper_add_f64(res, cpu_env, res, src);
e6e5906b
PB
3108 break;
3109 case 0x23: case 0x63: case 0x67: /* fmul */
e1f3808e 3110 gen_helper_mul_f64(res, cpu_env, res, src);
e6e5906b
PB
3111 break;
3112 case 0x28: case 0x68: case 0x6c: /* fsub */
e1f3808e 3113 gen_helper_sub_f64(res, cpu_env, res, src);
e6e5906b
PB
3114 break;
3115 case 0x38: /* fcmp */
e1f3808e 3116 gen_helper_sub_cmp_f64(res, cpu_env, res, src);
a7812ae4 3117 set_dest = 0;
e6e5906b
PB
3118 round = 0;
3119 break;
3120 case 0x3a: /* ftst */
e1f3808e 3121 tcg_gen_mov_f64(res, src);
a7812ae4 3122 set_dest = 0;
e6e5906b
PB
3123 round = 0;
3124 break;
3125 default:
3126 goto undef;
3127 }
a7812ae4
PB
3128 if (ext & (1 << 14)) {
3129 tcg_temp_free_i64(src);
3130 }
e6e5906b
PB
3131 if (round) {
3132 if (opmode & 0x40) {
3133 if ((opmode & 0x4) != 0)
3134 round = 0;
3135 } else if ((s->fpcr & M68K_FPCR_PREC) == 0) {
3136 round = 0;
3137 }
3138 }
3139 if (round) {
a7812ae4 3140 TCGv tmp = tcg_temp_new_i32();
e1f3808e
PB
3141 gen_helper_f64_to_f32(tmp, cpu_env, res);
3142 gen_helper_f32_to_f64(res, cpu_env, tmp);
a7812ae4 3143 tcg_temp_free_i32(tmp);
5fafdf24 3144 }
e1f3808e 3145 tcg_gen_mov_f64(QREG_FP_RESULT, res);
a7812ae4 3146 if (set_dest) {
e1f3808e 3147 tcg_gen_mov_f64(dest, res);
e6e5906b 3148 }
a7812ae4 3149 tcg_temp_free_i64(res);
e6e5906b
PB
3150 return;
3151undef:
a7812ae4 3152 /* FIXME: Is this right for offset addressing modes? */
e6e5906b 3153 s->pc -= 2;
d4d79bb1 3154 disas_undef_fpu(env, s, insn);
e6e5906b
PB
3155}
3156
3157DISAS_INSN(fbcc)
3158{
3159 uint32_t offset;
3160 uint32_t addr;
e1f3808e 3161 TCGv flag;
42a268c2 3162 TCGLabel *l1;
e6e5906b
PB
3163
3164 addr = s->pc;
d4d79bb1 3165 offset = cpu_ldsw_code(env, s->pc);
e6e5906b
PB
3166 s->pc += 2;
3167 if (insn & (1 << 6)) {
28b68cd7 3168 offset = (offset << 16) | read_im16(env, s);
e6e5906b
PB
3169 }
3170
3171 l1 = gen_new_label();
3172 /* TODO: Raise BSUN exception. */
a7812ae4 3173 flag = tcg_temp_new();
e1f3808e 3174 gen_helper_compare_f64(flag, cpu_env, QREG_FP_RESULT);
e6e5906b
PB
3175 /* Jump to l1 if condition is true. */
3176 switch (insn & 0xf) {
3177 case 0: /* f */
3178 break;
3179 case 1: /* eq (=0) */
e1f3808e 3180 tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3181 break;
3182 case 2: /* ogt (=1) */
e1f3808e 3183 tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(1), l1);
e6e5906b
PB
3184 break;
3185 case 3: /* oge (=0 or =1) */
e1f3808e 3186 tcg_gen_brcond_i32(TCG_COND_LEU, flag, tcg_const_i32(1), l1);
e6e5906b
PB
3187 break;
3188 case 4: /* olt (=-1) */
e1f3808e 3189 tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3190 break;
3191 case 5: /* ole (=-1 or =0) */
e1f3808e 3192 tcg_gen_brcond_i32(TCG_COND_LE, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3193 break;
3194 case 6: /* ogl (=-1 or =1) */
e1f3808e
PB
3195 tcg_gen_andi_i32(flag, flag, 1);
3196 tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3197 break;
3198 case 7: /* or (=2) */
e1f3808e 3199 tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(2), l1);
e6e5906b
PB
3200 break;
3201 case 8: /* un (<2) */
e1f3808e 3202 tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(2), l1);
e6e5906b
PB
3203 break;
3204 case 9: /* ueq (=0 or =2) */
e1f3808e
PB
3205 tcg_gen_andi_i32(flag, flag, 1);
3206 tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3207 break;
3208 case 10: /* ugt (>0) */
e1f3808e 3209 tcg_gen_brcond_i32(TCG_COND_GT, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3210 break;
3211 case 11: /* uge (>=0) */
e1f3808e 3212 tcg_gen_brcond_i32(TCG_COND_GE, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3213 break;
3214 case 12: /* ult (=-1 or =2) */
e1f3808e 3215 tcg_gen_brcond_i32(TCG_COND_GEU, flag, tcg_const_i32(2), l1);
e6e5906b
PB
3216 break;
3217 case 13: /* ule (!=1) */
e1f3808e 3218 tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(1), l1);
e6e5906b
PB
3219 break;
3220 case 14: /* ne (!=0) */
e1f3808e 3221 tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
e6e5906b
PB
3222 break;
3223 case 15: /* t */
e1f3808e 3224 tcg_gen_br(l1);
e6e5906b
PB
3225 break;
3226 }
3227 gen_jmp_tb(s, 0, s->pc);
3228 gen_set_label(l1);
3229 gen_jmp_tb(s, 1, addr + offset);
3230}
3231
0633879f
PB
3232DISAS_INSN(frestore)
3233{
a47dddd7
AF
3234 M68kCPU *cpu = m68k_env_get_cpu(env);
3235
0633879f 3236 /* TODO: Implement frestore. */
a47dddd7 3237 cpu_abort(CPU(cpu), "FRESTORE not implemented");
0633879f
PB
3238}
3239
3240DISAS_INSN(fsave)
3241{
a47dddd7
AF
3242 M68kCPU *cpu = m68k_env_get_cpu(env);
3243
0633879f 3244 /* TODO: Implement fsave. */
a47dddd7 3245 cpu_abort(CPU(cpu), "FSAVE not implemented");
0633879f
PB
3246}
3247
e1f3808e 3248static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
acf930aa 3249{
a7812ae4 3250 TCGv tmp = tcg_temp_new();
acf930aa
PB
3251 if (s->env->macsr & MACSR_FI) {
3252 if (upper)
e1f3808e 3253 tcg_gen_andi_i32(tmp, val, 0xffff0000);
acf930aa 3254 else
e1f3808e 3255 tcg_gen_shli_i32(tmp, val, 16);
acf930aa
PB
3256 } else if (s->env->macsr & MACSR_SU) {
3257 if (upper)
e1f3808e 3258 tcg_gen_sari_i32(tmp, val, 16);
acf930aa 3259 else
e1f3808e 3260 tcg_gen_ext16s_i32(tmp, val);
acf930aa
PB
3261 } else {
3262 if (upper)
e1f3808e 3263 tcg_gen_shri_i32(tmp, val, 16);
acf930aa 3264 else
e1f3808e 3265 tcg_gen_ext16u_i32(tmp, val);
acf930aa
PB
3266 }
3267 return tmp;
3268}
3269
e1f3808e
PB
3270static void gen_mac_clear_flags(void)
3271{
3272 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR,
3273 ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV));
3274}
3275
acf930aa
PB
3276DISAS_INSN(mac)
3277{
e1f3808e
PB
3278 TCGv rx;
3279 TCGv ry;
acf930aa
PB
3280 uint16_t ext;
3281 int acc;
e1f3808e
PB
3282 TCGv tmp;
3283 TCGv addr;
3284 TCGv loadval;
acf930aa 3285 int dual;
e1f3808e
PB
3286 TCGv saved_flags;
3287
a7812ae4
PB
3288 if (!s->done_mac) {
3289 s->mactmp = tcg_temp_new_i64();
3290 s->done_mac = 1;
3291 }
acf930aa 3292
28b68cd7 3293 ext = read_im16(env, s);
acf930aa
PB
3294
3295 acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
3296 dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
d315c888 3297 if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
d4d79bb1 3298 disas_undef(env, s, insn);
d315c888
PB
3299 return;
3300 }
acf930aa
PB
3301 if (insn & 0x30) {
3302 /* MAC with load. */
d4d79bb1 3303 tmp = gen_lea(env, s, insn, OS_LONG);
a7812ae4 3304 addr = tcg_temp_new();
e1f3808e 3305 tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK);
acf930aa
PB
3306 /* Load the value now to ensure correct exception behavior.
3307 Perform writeback after reading the MAC inputs. */
3308 loadval = gen_load(s, OS_LONG, addr, 0);
3309
3310 acc ^= 1;
3311 rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
3312 ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
3313 } else {
e1f3808e 3314 loadval = addr = NULL_QREG;
acf930aa
PB
3315 rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
3316 ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
3317 }
3318
e1f3808e
PB
3319 gen_mac_clear_flags();
3320#if 0
acf930aa 3321 l1 = -1;
e1f3808e 3322 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3323 if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
3324 /* Skip the multiply if we know we will ignore it. */
3325 l1 = gen_new_label();
a7812ae4 3326 tmp = tcg_temp_new();
e1f3808e 3327 tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8));
acf930aa
PB
3328 gen_op_jmp_nz32(tmp, l1);
3329 }
e1f3808e 3330#endif
acf930aa
PB
3331
3332 if ((ext & 0x0800) == 0) {
3333 /* Word. */
3334 rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
3335 ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
3336 }
3337 if (s->env->macsr & MACSR_FI) {
e1f3808e 3338 gen_helper_macmulf(s->mactmp, cpu_env, rx, ry);
acf930aa
PB
3339 } else {
3340 if (s->env->macsr & MACSR_SU)
e1f3808e 3341 gen_helper_macmuls(s->mactmp, cpu_env, rx, ry);
acf930aa 3342 else
e1f3808e 3343 gen_helper_macmulu(s->mactmp, cpu_env, rx, ry);
acf930aa
PB
3344 switch ((ext >> 9) & 3) {
3345 case 1:
e1f3808e 3346 tcg_gen_shli_i64(s->mactmp, s->mactmp, 1);
acf930aa
PB
3347 break;
3348 case 3:
e1f3808e 3349 tcg_gen_shri_i64(s->mactmp, s->mactmp, 1);
acf930aa
PB
3350 break;
3351 }
3352 }
3353
3354 if (dual) {
3355 /* Save the overflow flag from the multiply. */
a7812ae4 3356 saved_flags = tcg_temp_new();
e1f3808e
PB
3357 tcg_gen_mov_i32(saved_flags, QREG_MACSR);
3358 } else {
3359 saved_flags = NULL_QREG;
acf930aa
PB
3360 }
3361
e1f3808e
PB
3362#if 0
3363 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3364 if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
3365 /* Skip the accumulate if the value is already saturated. */
3366 l1 = gen_new_label();
a7812ae4 3367 tmp = tcg_temp_new();
351326a6 3368 gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
acf930aa
PB
3369 gen_op_jmp_nz32(tmp, l1);
3370 }
e1f3808e 3371#endif
acf930aa
PB
3372
3373 if (insn & 0x100)
e1f3808e 3374 tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 3375 else
e1f3808e 3376 tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa
PB
3377
3378 if (s->env->macsr & MACSR_FI)
e1f3808e 3379 gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
acf930aa 3380 else if (s->env->macsr & MACSR_SU)
e1f3808e 3381 gen_helper_macsats(cpu_env, tcg_const_i32(acc));
acf930aa 3382 else
e1f3808e 3383 gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
acf930aa 3384
e1f3808e
PB
3385#if 0
3386 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3387 if (l1 != -1)
3388 gen_set_label(l1);
e1f3808e 3389#endif
acf930aa
PB
3390
3391 if (dual) {
3392 /* Dual accumulate variant. */
3393 acc = (ext >> 2) & 3;
3394 /* Restore the overflow flag from the multiplier. */
e1f3808e
PB
3395 tcg_gen_mov_i32(QREG_MACSR, saved_flags);
3396#if 0
3397 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3398 if ((s->env->macsr & MACSR_OMC) != 0) {
3399 /* Skip the accumulate if the value is already saturated. */
3400 l1 = gen_new_label();
a7812ae4 3401 tmp = tcg_temp_new();
351326a6 3402 gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
acf930aa
PB
3403 gen_op_jmp_nz32(tmp, l1);
3404 }
e1f3808e 3405#endif
acf930aa 3406 if (ext & 2)
e1f3808e 3407 tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 3408 else
e1f3808e 3409 tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 3410 if (s->env->macsr & MACSR_FI)
e1f3808e 3411 gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
acf930aa 3412 else if (s->env->macsr & MACSR_SU)
e1f3808e 3413 gen_helper_macsats(cpu_env, tcg_const_i32(acc));
acf930aa 3414 else
e1f3808e
PB
3415 gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
3416#if 0
3417 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
3418 if (l1 != -1)
3419 gen_set_label(l1);
e1f3808e 3420#endif
acf930aa 3421 }
e1f3808e 3422 gen_helper_mac_set_flags(cpu_env, tcg_const_i32(acc));
acf930aa
PB
3423
3424 if (insn & 0x30) {
e1f3808e 3425 TCGv rw;
acf930aa 3426 rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
e1f3808e 3427 tcg_gen_mov_i32(rw, loadval);
acf930aa
PB
3428 /* FIXME: Should address writeback happen with the masked or
3429 unmasked value? */
3430 switch ((insn >> 3) & 7) {
3431 case 3: /* Post-increment. */
e1f3808e 3432 tcg_gen_addi_i32(AREG(insn, 0), addr, 4);
acf930aa
PB
3433 break;
3434 case 4: /* Pre-decrement. */
e1f3808e 3435 tcg_gen_mov_i32(AREG(insn, 0), addr);
acf930aa
PB
3436 }
3437 }
3438}
3439
3440DISAS_INSN(from_mac)
3441{
e1f3808e 3442 TCGv rx;
a7812ae4 3443 TCGv_i64 acc;
e1f3808e 3444 int accnum;
acf930aa
PB
3445
3446 rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e
PB
3447 accnum = (insn >> 9) & 3;
3448 acc = MACREG(accnum);
acf930aa 3449 if (s->env->macsr & MACSR_FI) {
a7812ae4 3450 gen_helper_get_macf(rx, cpu_env, acc);
acf930aa 3451 } else if ((s->env->macsr & MACSR_OMC) == 0) {
ecc7b3aa 3452 tcg_gen_extrl_i64_i32(rx, acc);
acf930aa 3453 } else if (s->env->macsr & MACSR_SU) {
e1f3808e 3454 gen_helper_get_macs(rx, acc);
acf930aa 3455 } else {
e1f3808e
PB
3456 gen_helper_get_macu(rx, acc);
3457 }
3458 if (insn & 0x40) {
3459 tcg_gen_movi_i64(acc, 0);
3460 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
acf930aa 3461 }
acf930aa
PB
3462}
3463
3464DISAS_INSN(move_mac)
3465{
e1f3808e 3466 /* FIXME: This can be done without a helper. */
acf930aa 3467 int src;
e1f3808e 3468 TCGv dest;
acf930aa 3469 src = insn & 3;
e1f3808e
PB
3470 dest = tcg_const_i32((insn >> 9) & 3);
3471 gen_helper_mac_move(cpu_env, dest, tcg_const_i32(src));
3472 gen_mac_clear_flags();
3473 gen_helper_mac_set_flags(cpu_env, dest);
acf930aa
PB
3474}
3475
3476DISAS_INSN(from_macsr)
3477{
e1f3808e 3478 TCGv reg;
acf930aa
PB
3479
3480 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 3481 tcg_gen_mov_i32(reg, QREG_MACSR);
acf930aa
PB
3482}
3483
3484DISAS_INSN(from_mask)
3485{
e1f3808e 3486 TCGv reg;
acf930aa 3487 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 3488 tcg_gen_mov_i32(reg, QREG_MAC_MASK);
acf930aa
PB
3489}
3490
3491DISAS_INSN(from_mext)
3492{
e1f3808e
PB
3493 TCGv reg;
3494 TCGv acc;
acf930aa 3495 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 3496 acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
acf930aa 3497 if (s->env->macsr & MACSR_FI)
e1f3808e 3498 gen_helper_get_mac_extf(reg, cpu_env, acc);
acf930aa 3499 else
e1f3808e 3500 gen_helper_get_mac_exti(reg, cpu_env, acc);
acf930aa
PB
3501}
3502
3503DISAS_INSN(macsr_to_ccr)
3504{
620c6cf6
RH
3505 TCGv tmp = tcg_temp_new();
3506 tcg_gen_andi_i32(tmp, QREG_MACSR, 0xf);
3507 gen_helper_set_sr(cpu_env, tmp);
3508 tcg_temp_free(tmp);
9fdb533f 3509 set_cc_op(s, CC_OP_FLAGS);
acf930aa
PB
3510}
3511
3512DISAS_INSN(to_mac)
3513{
a7812ae4 3514 TCGv_i64 acc;
e1f3808e
PB
3515 TCGv val;
3516 int accnum;
3517 accnum = (insn >> 9) & 3;
3518 acc = MACREG(accnum);
d4d79bb1 3519 SRC_EA(env, val, OS_LONG, 0, NULL);
acf930aa 3520 if (s->env->macsr & MACSR_FI) {
e1f3808e
PB
3521 tcg_gen_ext_i32_i64(acc, val);
3522 tcg_gen_shli_i64(acc, acc, 8);
acf930aa 3523 } else if (s->env->macsr & MACSR_SU) {
e1f3808e 3524 tcg_gen_ext_i32_i64(acc, val);
acf930aa 3525 } else {
e1f3808e 3526 tcg_gen_extu_i32_i64(acc, val);
acf930aa 3527 }
e1f3808e
PB
3528 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
3529 gen_mac_clear_flags();
3530 gen_helper_mac_set_flags(cpu_env, tcg_const_i32(accnum));
acf930aa
PB
3531}
3532
3533DISAS_INSN(to_macsr)
3534{
e1f3808e 3535 TCGv val;
d4d79bb1 3536 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 3537 gen_helper_set_macsr(cpu_env, val);
acf930aa
PB
3538 gen_lookup_tb(s);
3539}
3540
3541DISAS_INSN(to_mask)
3542{
e1f3808e 3543 TCGv val;
d4d79bb1 3544 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 3545 tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000);
acf930aa
PB
3546}
3547
3548DISAS_INSN(to_mext)
3549{
e1f3808e
PB
3550 TCGv val;
3551 TCGv acc;
d4d79bb1 3552 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 3553 acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
acf930aa 3554 if (s->env->macsr & MACSR_FI)
e1f3808e 3555 gen_helper_set_mac_extf(cpu_env, val, acc);
acf930aa 3556 else if (s->env->macsr & MACSR_SU)
e1f3808e 3557 gen_helper_set_mac_exts(cpu_env, val, acc);
acf930aa 3558 else
e1f3808e 3559 gen_helper_set_mac_extu(cpu_env, val, acc);
acf930aa
PB
3560}
3561
e6e5906b
PB
3562static disas_proc opcode_table[65536];
3563
3564static void
3565register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
3566{
3567 int i;
3568 int from;
3569 int to;
3570
3571 /* Sanity check. All set bits must be included in the mask. */
5fc4adf6
PB
3572 if (opcode & ~mask) {
3573 fprintf(stderr,
3574 "qemu internal error: bogus opcode definition %04x/%04x\n",
3575 opcode, mask);
e6e5906b 3576 abort();
5fc4adf6 3577 }
e6e5906b
PB
3578 /* This could probably be cleverer. For now just optimize the case where
3579 the top bits are known. */
3580 /* Find the first zero bit in the mask. */
3581 i = 0x8000;
3582 while ((i & mask) != 0)
3583 i >>= 1;
3584 /* Iterate over all combinations of this and lower bits. */
3585 if (i == 0)
3586 i = 1;
3587 else
3588 i <<= 1;
3589 from = opcode & ~(i - 1);
3590 to = from + i;
0633879f 3591 for (i = from; i < to; i++) {
e6e5906b
PB
3592 if ((i & mask) == opcode)
3593 opcode_table[i] = proc;
0633879f 3594 }
e6e5906b
PB
3595}
3596
3597/* Register m68k opcode handlers. Order is important.
3598 Later insn override earlier ones. */
0402f767 3599void register_m68k_insns (CPUM68KState *env)
e6e5906b 3600{
b2085257
JPAG
3601 /* Build the opcode table only once to avoid
3602 multithreading issues. */
3603 if (opcode_table[0] != NULL) {
3604 return;
3605 }
f076803b
LV
3606
3607 /* use BASE() for instruction available
3608 * for CF_ISA_A and M68000.
3609 */
3610#define BASE(name, opcode, mask) \
3611 register_opcode(disas_##name, 0x##opcode, 0x##mask)
d315c888 3612#define INSN(name, opcode, mask, feature) do { \
0402f767 3613 if (m68k_feature(env, M68K_FEATURE_##feature)) \
f076803b 3614 BASE(name, opcode, mask); \
d315c888 3615 } while(0)
f076803b 3616 BASE(undef, 0000, 0000);
0402f767 3617 INSN(arith_im, 0080, fff8, CF_ISA_A);
f076803b
LV
3618 INSN(arith_im, 0000, ff00, M68000);
3619 INSN(undef, 00c0, ffc0, M68000);
d315c888 3620 INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC);
f076803b
LV
3621 BASE(bitop_reg, 0100, f1c0);
3622 BASE(bitop_reg, 0140, f1c0);
3623 BASE(bitop_reg, 0180, f1c0);
3624 BASE(bitop_reg, 01c0, f1c0);
0402f767 3625 INSN(arith_im, 0280, fff8, CF_ISA_A);
f076803b
LV
3626 INSN(arith_im, 0200, ff00, M68000);
3627 INSN(undef, 02c0, ffc0, M68000);
d315c888 3628 INSN(byterev, 02c0, fff8, CF_ISA_APLUSC);
0402f767 3629 INSN(arith_im, 0480, fff8, CF_ISA_A);
f076803b
LV
3630 INSN(arith_im, 0400, ff00, M68000);
3631 INSN(undef, 04c0, ffc0, M68000);
3632 INSN(arith_im, 0600, ff00, M68000);
3633 INSN(undef, 06c0, ffc0, M68000);
d315c888 3634 INSN(ff1, 04c0, fff8, CF_ISA_APLUSC);
0402f767 3635 INSN(arith_im, 0680, fff8, CF_ISA_A);
0402f767 3636 INSN(arith_im, 0c00, ff38, CF_ISA_A);
f076803b
LV
3637 INSN(arith_im, 0c00, ff00, M68000);
3638 BASE(bitop_im, 0800, ffc0);
3639 BASE(bitop_im, 0840, ffc0);
3640 BASE(bitop_im, 0880, ffc0);
3641 BASE(bitop_im, 08c0, ffc0);
3642 INSN(arith_im, 0a80, fff8, CF_ISA_A);
3643 INSN(arith_im, 0a00, ff00, M68000);
3644 BASE(move, 1000, f000);
3645 BASE(move, 2000, f000);
3646 BASE(move, 3000, f000);
d315c888 3647 INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
0402f767 3648 INSN(negx, 4080, fff8, CF_ISA_A);
a665a820
RH
3649 INSN(negx, 4000, ff00, M68000);
3650 INSN(undef, 40c0, ffc0, M68000);
0402f767 3651 INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
f076803b
LV
3652 INSN(move_from_sr, 40c0, ffc0, M68000);
3653 BASE(lea, 41c0, f1c0);
3654 BASE(clr, 4200, ff00);
3655 BASE(undef, 42c0, ffc0);
0402f767 3656 INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
7c0eb318 3657 INSN(move_from_ccr, 42c0, ffc0, M68000);
0402f767 3658 INSN(neg, 4480, fff8, CF_ISA_A);
f076803b
LV
3659 INSN(neg, 4400, ff00, M68000);
3660 INSN(undef, 44c0, ffc0, M68000);
3661 BASE(move_to_ccr, 44c0, ffc0);
0402f767 3662 INSN(not, 4680, fff8, CF_ISA_A);
f076803b
LV
3663 INSN(not, 4600, ff00, M68000);
3664 INSN(undef, 46c0, ffc0, M68000);
0402f767 3665 INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
fb5543d8 3666 INSN(nbcd, 4800, ffc0, M68000);
c630e436 3667 INSN(linkl, 4808, fff8, M68000);
f076803b
LV
3668 BASE(pea, 4840, ffc0);
3669 BASE(swap, 4840, fff8);
71600eda 3670 INSN(bkpt, 4848, fff8, BKPT);
f076803b
LV
3671 BASE(movem, 48c0, fbc0);
3672 BASE(ext, 4880, fff8);
3673 BASE(ext, 48c0, fff8);
3674 BASE(ext, 49c0, fff8);
3675 BASE(tst, 4a00, ff00);
0402f767 3676 INSN(tas, 4ac0, ffc0, CF_ISA_B);
f076803b 3677 INSN(tas, 4ac0, ffc0, M68000);
0402f767
PB
3678 INSN(halt, 4ac8, ffff, CF_ISA_A);
3679 INSN(pulse, 4acc, ffff, CF_ISA_A);
f076803b 3680 BASE(illegal, 4afc, ffff);
0402f767 3681 INSN(mull, 4c00, ffc0, CF_ISA_A);
f076803b 3682 INSN(mull, 4c00, ffc0, LONG_MULDIV);
0402f767 3683 INSN(divl, 4c40, ffc0, CF_ISA_A);
f076803b 3684 INSN(divl, 4c40, ffc0, LONG_MULDIV);
0402f767 3685 INSN(sats, 4c80, fff8, CF_ISA_B);
f076803b
LV
3686 BASE(trap, 4e40, fff0);
3687 BASE(link, 4e50, fff8);
3688 BASE(unlk, 4e58, fff8);
20dcee94
PB
3689 INSN(move_to_usp, 4e60, fff8, USP);
3690 INSN(move_from_usp, 4e68, fff8, USP);
f076803b
LV
3691 BASE(nop, 4e71, ffff);
3692 BASE(stop, 4e72, ffff);
3693 BASE(rte, 4e73, ffff);
3694 BASE(rts, 4e75, ffff);
0402f767 3695 INSN(movec, 4e7b, ffff, CF_ISA_A);
f076803b 3696 BASE(jump, 4e80, ffc0);
8a370c6c 3697 BASE(jump, 4ec0, ffc0);
f076803b 3698 INSN(addsubq, 5000, f080, M68000);
8a370c6c 3699 BASE(addsubq, 5080, f0c0);
d5a3cf33
LV
3700 INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */
3701 INSN(scc, 50c0, f0c0, M68000); /* Scc.B <EA> */
beff27ab 3702 INSN(dbcc, 50c8, f0f8, M68000);
0402f767 3703 INSN(tpf, 51f8, fff8, CF_ISA_A);
d315c888
PB
3704
3705 /* Branch instructions. */
f076803b 3706 BASE(branch, 6000, f000);
d315c888 3707 /* Disable long branch instructions, then add back the ones we want. */
f076803b 3708 BASE(undef, 60ff, f0ff); /* All long branches. */
d315c888
PB
3709 INSN(branch, 60ff, f0ff, CF_ISA_B);
3710 INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */
3711 INSN(branch, 60ff, ffff, BRAL);
f076803b 3712 INSN(branch, 60ff, f0ff, BCCL);
d315c888 3713
f076803b 3714 BASE(moveq, 7000, f100);
0402f767 3715 INSN(mvzs, 7100, f100, CF_ISA_B);
f076803b
LV
3716 BASE(or, 8000, f000);
3717 BASE(divw, 80c0, f0c0);
fb5543d8
LV
3718 INSN(sbcd_reg, 8100, f1f8, M68000);
3719 INSN(sbcd_mem, 8108, f1f8, M68000);
f076803b 3720 BASE(addsub, 9000, f000);
a665a820
RH
3721 INSN(undef, 90c0, f0c0, CF_ISA_A);
3722 INSN(subx_reg, 9180, f1f8, CF_ISA_A);
3723 INSN(subx_reg, 9100, f138, M68000);
3724 INSN(subx_mem, 9108, f138, M68000);
0402f767 3725 INSN(suba, 91c0, f1c0, CF_ISA_A);
415f4b62 3726 INSN(suba, 90c0, f0c0, M68000);
acf930aa 3727
f076803b 3728 BASE(undef_mac, a000, f000);
acf930aa
PB
3729 INSN(mac, a000, f100, CF_EMAC);
3730 INSN(from_mac, a180, f9b0, CF_EMAC);
3731 INSN(move_mac, a110, f9fc, CF_EMAC);
3732 INSN(from_macsr,a980, f9f0, CF_EMAC);
3733 INSN(from_mask, ad80, fff0, CF_EMAC);
3734 INSN(from_mext, ab80, fbf0, CF_EMAC);
3735 INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
3736 INSN(to_mac, a100, f9c0, CF_EMAC);
3737 INSN(to_macsr, a900, ffc0, CF_EMAC);
3738 INSN(to_mext, ab00, fbc0, CF_EMAC);
3739 INSN(to_mask, ad00, ffc0, CF_EMAC);
3740
0402f767
PB
3741 INSN(mov3q, a140, f1c0, CF_ISA_B);
3742 INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */
3743 INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */
3744 INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */
3745 INSN(cmp, b080, f1c0, CF_ISA_A);
3746 INSN(cmpa, b1c0, f1c0, CF_ISA_A);
f076803b
LV
3747 INSN(cmp, b000, f100, M68000);
3748 INSN(eor, b100, f100, M68000);
817af1c7 3749 INSN(cmpm, b108, f138, M68000);
f076803b 3750 INSN(cmpa, b0c0, f0c0, M68000);
0402f767 3751 INSN(eor, b180, f1c0, CF_ISA_A);
f076803b 3752 BASE(and, c000, f000);
29cf437d
LV
3753 INSN(exg_dd, c140, f1f8, M68000);
3754 INSN(exg_aa, c148, f1f8, M68000);
3755 INSN(exg_da, c188, f1f8, M68000);
f076803b 3756 BASE(mulw, c0c0, f0c0);
fb5543d8
LV
3757 INSN(abcd_reg, c100, f1f8, M68000);
3758 INSN(abcd_mem, c108, f1f8, M68000);
f076803b 3759 BASE(addsub, d000, f000);
a665a820
RH
3760 INSN(undef, d0c0, f0c0, CF_ISA_A);
3761 INSN(addx_reg, d180, f1f8, CF_ISA_A);
3762 INSN(addx_reg, d100, f138, M68000);
3763 INSN(addx_mem, d108, f138, M68000);
0402f767 3764 INSN(adda, d1c0, f1c0, CF_ISA_A);
f076803b 3765 INSN(adda, d0c0, f0c0, M68000);
0402f767
PB
3766 INSN(shift_im, e080, f0f0, CF_ISA_A);
3767 INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
3768 INSN(undef_fpu, f000, f000, CF_ISA_A);
e6e5906b
PB
3769 INSN(fpu, f200, ffc0, CF_FPU);
3770 INSN(fbcc, f280, ffc0, CF_FPU);
0633879f
PB
3771 INSN(frestore, f340, ffc0, CF_FPU);
3772 INSN(fsave, f340, ffc0, CF_FPU);
0402f767
PB
3773 INSN(intouch, f340, ffc0, CF_ISA_A);
3774 INSN(cpushl, f428, ff38, CF_ISA_A);
3775 INSN(wddata, fb00, ff00, CF_ISA_A);
3776 INSN(wdebug, fbc0, ffc0, CF_ISA_A);
e6e5906b
PB
3777#undef INSN
3778}
3779
3780/* ??? Some of this implementation is not exception safe. We should always
3781 write back the result to memory before setting the condition codes. */
2b3e3cfe 3782static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
e6e5906b 3783{
8a1e52b6 3784 uint16_t insn = read_im16(env, s);
d4d79bb1 3785 opcode_table[insn](env, s, insn);
8a1e52b6 3786 do_writebacks(s);
e6e5906b
PB
3787}
3788
e6e5906b 3789/* generate intermediate code for basic block 'tb'. */
4e5e1215 3790void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
e6e5906b 3791{
4e5e1215 3792 M68kCPU *cpu = m68k_env_get_cpu(env);
ed2803da 3793 CPUState *cs = CPU(cpu);
e6e5906b 3794 DisasContext dc1, *dc = &dc1;
e6e5906b
PB
3795 target_ulong pc_start;
3796 int pc_offset;
2e70f6ef
PB
3797 int num_insns;
3798 int max_insns;
e6e5906b
PB
3799
3800 /* generate intermediate code */
3801 pc_start = tb->pc;
3b46e624 3802
e6e5906b
PB
3803 dc->tb = tb;
3804
e6dbd3b3 3805 dc->env = env;
e6e5906b
PB
3806 dc->is_jmp = DISAS_NEXT;
3807 dc->pc = pc_start;
3808 dc->cc_op = CC_OP_DYNAMIC;
620c6cf6 3809 dc->cc_op_synced = 1;
ed2803da 3810 dc->singlestep_enabled = cs->singlestep_enabled;
e6e5906b 3811 dc->fpcr = env->fpcr;
0633879f 3812 dc->user = (env->sr & SR_S) == 0;
a7812ae4 3813 dc->done_mac = 0;
8a1e52b6 3814 dc->writeback_mask = 0;
2e70f6ef
PB
3815 num_insns = 0;
3816 max_insns = tb->cflags & CF_COUNT_MASK;
190ce7fb 3817 if (max_insns == 0) {
2e70f6ef 3818 max_insns = CF_COUNT_MASK;
190ce7fb
RH
3819 }
3820 if (max_insns > TCG_MAX_INSNS) {
3821 max_insns = TCG_MAX_INSNS;
3822 }
2e70f6ef 3823
cd42d5b2 3824 gen_tb_start(tb);
e6e5906b 3825 do {
e6e5906b
PB
3826 pc_offset = dc->pc - pc_start;
3827 gen_throws_exception = NULL;
20a8856e 3828 tcg_gen_insn_start(dc->pc, dc->cc_op);
959082fc 3829 num_insns++;
667b8e29 3830
b933066a
RH
3831 if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
3832 gen_exception(dc, dc->pc, EXCP_DEBUG);
3833 dc->is_jmp = DISAS_JUMP;
522a0d4e
RH
3834 /* The address covered by the breakpoint must be included in
3835 [tb->pc, tb->pc + tb->size) in order to for it to be
3836 properly cleared -- thus we increment the PC here so that
3837 the logic setting tb->size below does the right thing. */
3838 dc->pc += 2;
b933066a
RH
3839 break;
3840 }
3841
959082fc 3842 if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
2e70f6ef 3843 gen_io_start();
667b8e29
RH
3844 }
3845
510ff0b7 3846 dc->insn_pc = dc->pc;
e6e5906b 3847 disas_m68k_insn(env, dc);
fe700adb 3848 } while (!dc->is_jmp && !tcg_op_buf_full() &&
ed2803da 3849 !cs->singlestep_enabled &&
1b530a6d 3850 !singlestep &&
2e70f6ef
PB
3851 (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
3852 num_insns < max_insns);
e6e5906b 3853
2e70f6ef
PB
3854 if (tb->cflags & CF_LAST_IO)
3855 gen_io_end();
ed2803da 3856 if (unlikely(cs->singlestep_enabled)) {
e6e5906b
PB
3857 /* Make sure the pc is updated, and raise a debug exception. */
3858 if (!dc->is_jmp) {
9fdb533f 3859 update_cc_op(dc);
e1f3808e 3860 tcg_gen_movi_i32(QREG_PC, dc->pc);
e6e5906b 3861 }
31871141 3862 gen_helper_raise_exception(cpu_env, tcg_const_i32(EXCP_DEBUG));
e6e5906b
PB
3863 } else {
3864 switch(dc->is_jmp) {
3865 case DISAS_NEXT:
9fdb533f 3866 update_cc_op(dc);
e6e5906b
PB
3867 gen_jmp_tb(dc, 0, dc->pc);
3868 break;
3869 default:
3870 case DISAS_JUMP:
3871 case DISAS_UPDATE:
9fdb533f 3872 update_cc_op(dc);
e6e5906b 3873 /* indicate that the hash table must be used to find the next TB */
57fec1fe 3874 tcg_gen_exit_tb(0);
e6e5906b
PB
3875 break;
3876 case DISAS_TB_JUMP:
3877 /* nothing more to generate */
3878 break;
3879 }
3880 }
806f352d 3881 gen_tb_end(tb, num_insns);
e6e5906b
PB
3882
3883#ifdef DEBUG_DISAS
4910e6e4
RH
3884 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
3885 && qemu_log_in_addr_range(pc_start)) {
1ee73216 3886 qemu_log_lock();
93fcfe39
AL
3887 qemu_log("----------------\n");
3888 qemu_log("IN: %s\n", lookup_symbol(pc_start));
d49190c4 3889 log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
93fcfe39 3890 qemu_log("\n");
1ee73216 3891 qemu_log_unlock();
e6e5906b
PB
3892 }
3893#endif
4e5e1215
RH
3894 tb->size = dc->pc - pc_start;
3895 tb->icount = num_insns;
e6e5906b
PB
3896}
3897
878096ee
AF
3898void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
3899 int flags)
e6e5906b 3900{
878096ee
AF
3901 M68kCPU *cpu = M68K_CPU(cs);
3902 CPUM68KState *env = &cpu->env;
e6e5906b
PB
3903 int i;
3904 uint16_t sr;
3905 CPU_DoubleU u;
3906 for (i = 0; i < 8; i++)
3907 {
3908 u.d = env->fregs[i];
8e394cca
RH
3909 cpu_fprintf(f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n",
3910 i, env->dregs[i], i, env->aregs[i],
3911 i, u.l.upper, u.l.lower, *(double *)&u.d);
e6e5906b
PB
3912 }
3913 cpu_fprintf (f, "PC = %08x ", env->pc);
99c51448 3914 sr = env->sr | cpu_m68k_get_ccr(env);
8e394cca
RH
3915 cpu_fprintf(f, "SR = %04x %c%c%c%c%c ", sr, (sr & CCF_X) ? 'X' : '-',
3916 (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-',
3917 (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-');
8fc7cc58 3918 cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result);
e6e5906b
PB
3919}
3920
bad729e2
RH
3921void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb,
3922 target_ulong *data)
d2856f1a 3923{
20a8856e 3924 int cc_op = data[1];
bad729e2 3925 env->pc = data[0];
20a8856e
LV
3926 if (cc_op != CC_OP_DYNAMIC) {
3927 env->cc_op = cc_op;
3928 }
d2856f1a 3929}