]> Git Repo - qemu.git/blame - target/m68k/translate.c
target/m68k: Use lookup_and_goto_tb for DISAS_JUMP
[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"
77fc6f5e 28#include "exec/translator.h"
e1f3808e 29
2ef6175a
RH
30#include "exec/helper-proto.h"
31#include "exec/helper-gen.h"
e6e5906b 32
a7e30d84 33#include "trace-tcg.h"
508127e2 34#include "exec/log.h"
24f91e81
AB
35#include "fpu/softfloat.h"
36
a7e30d84 37
0633879f
PB
38//#define DEBUG_DISPATCH 1
39
e1f3808e 40#define DEFO32(name, offset) static TCGv QREG_##name;
a7812ae4 41#define DEFO64(name, offset) static TCGv_i64 QREG_##name;
e1f3808e
PB
42#include "qregs.def"
43#undef DEFO32
44#undef DEFO64
e1f3808e 45
259186a7 46static TCGv_i32 cpu_halted;
27103424 47static TCGv_i32 cpu_exception_index;
259186a7 48
f83311e4 49static char cpu_reg_names[2 * 8 * 3 + 5 * 4];
e1f3808e
PB
50static TCGv cpu_dregs[8];
51static TCGv cpu_aregs[8];
a7812ae4 52static TCGv_i64 cpu_macc[4];
e1f3808e 53
8a1e52b6 54#define REG(insn, pos) (((insn) >> (pos)) & 7)
bcc098b0 55#define DREG(insn, pos) cpu_dregs[REG(insn, pos)]
8a1e52b6 56#define AREG(insn, pos) get_areg(s, REG(insn, pos))
8a1e52b6
RH
57#define MACREG(acc) cpu_macc[acc]
58#define QREG_SP get_areg(s, 7)
e1f3808e
PB
59
60static TCGv NULL_QREG;
11f4e8f8 61#define IS_NULL_QREG(t) (t == NULL_QREG)
e1f3808e
PB
62/* Used to distinguish stores from bad addressing modes. */
63static TCGv store_dummy;
64
022c62cb 65#include "exec/gen-icount.h"
2e70f6ef 66
e1f3808e
PB
67void m68k_tcg_init(void)
68{
69 char *p;
70 int i;
71
e1ccc054
RH
72#define DEFO32(name, offset) \
73 QREG_##name = tcg_global_mem_new_i32(cpu_env, \
74 offsetof(CPUM68KState, offset), #name);
75#define DEFO64(name, offset) \
76 QREG_##name = tcg_global_mem_new_i64(cpu_env, \
77 offsetof(CPUM68KState, offset), #name);
e1f3808e
PB
78#include "qregs.def"
79#undef DEFO32
80#undef DEFO64
e1f3808e 81
e1ccc054 82 cpu_halted = tcg_global_mem_new_i32(cpu_env,
259186a7
AF
83 -offsetof(M68kCPU, env) +
84 offsetof(CPUState, halted), "HALTED");
e1ccc054 85 cpu_exception_index = tcg_global_mem_new_i32(cpu_env,
27103424
AF
86 -offsetof(M68kCPU, env) +
87 offsetof(CPUState, exception_index),
88 "EXCEPTION");
259186a7 89
e1f3808e
PB
90 p = cpu_reg_names;
91 for (i = 0; i < 8; i++) {
92 sprintf(p, "D%d", i);
e1ccc054 93 cpu_dregs[i] = tcg_global_mem_new(cpu_env,
e1f3808e
PB
94 offsetof(CPUM68KState, dregs[i]), p);
95 p += 3;
96 sprintf(p, "A%d", i);
e1ccc054 97 cpu_aregs[i] = tcg_global_mem_new(cpu_env,
e1f3808e
PB
98 offsetof(CPUM68KState, aregs[i]), p);
99 p += 3;
e1f3808e
PB
100 }
101 for (i = 0; i < 4; i++) {
102 sprintf(p, "ACC%d", i);
e1ccc054 103 cpu_macc[i] = tcg_global_mem_new_i64(cpu_env,
e1f3808e
PB
104 offsetof(CPUM68KState, macc[i]), p);
105 p += 5;
106 }
107
e1ccc054
RH
108 NULL_QREG = tcg_global_mem_new(cpu_env, -4, "NULL");
109 store_dummy = tcg_global_mem_new(cpu_env, -8, "NULL");
e1f3808e
PB
110}
111
e6e5906b
PB
112/* internal defines */
113typedef struct DisasContext {
e6dbd3b3 114 CPUM68KState *env;
510ff0b7 115 target_ulong insn_pc; /* Start of the current instruction. */
e6e5906b
PB
116 target_ulong pc;
117 int is_jmp;
9fdb533f 118 CCOp cc_op; /* Current CC operation */
620c6cf6 119 int cc_op_synced;
e6e5906b
PB
120 struct TranslationBlock *tb;
121 int singlestep_enabled;
a7812ae4
PB
122 TCGv_i64 mactmp;
123 int done_mac;
8a1e52b6
RH
124 int writeback_mask;
125 TCGv writeback[8];
ecc207d2
LV
126#define MAX_TO_RELEASE 8
127 int release_count;
128 TCGv release[MAX_TO_RELEASE];
e6e5906b
PB
129} DisasContext;
130
ecc207d2
LV
131static void init_release_array(DisasContext *s)
132{
133#ifdef CONFIG_DEBUG_TCG
134 memset(s->release, 0, sizeof(s->release));
135#endif
136 s->release_count = 0;
137}
138
139static void do_release(DisasContext *s)
140{
141 int i;
142 for (i = 0; i < s->release_count; i++) {
143 tcg_temp_free(s->release[i]);
144 }
145 init_release_array(s);
146}
147
148static TCGv mark_to_release(DisasContext *s, TCGv tmp)
149{
150 g_assert(s->release_count < MAX_TO_RELEASE);
151 return s->release[s->release_count++] = tmp;
152}
153
8a1e52b6
RH
154static TCGv get_areg(DisasContext *s, unsigned regno)
155{
156 if (s->writeback_mask & (1 << regno)) {
157 return s->writeback[regno];
158 } else {
159 return cpu_aregs[regno];
160 }
161}
162
163static void delay_set_areg(DisasContext *s, unsigned regno,
164 TCGv val, bool give_temp)
165{
166 if (s->writeback_mask & (1 << regno)) {
167 if (give_temp) {
168 tcg_temp_free(s->writeback[regno]);
169 s->writeback[regno] = val;
170 } else {
171 tcg_gen_mov_i32(s->writeback[regno], val);
172 }
173 } else {
174 s->writeback_mask |= 1 << regno;
175 if (give_temp) {
176 s->writeback[regno] = val;
177 } else {
178 TCGv tmp = tcg_temp_new();
179 s->writeback[regno] = tmp;
180 tcg_gen_mov_i32(tmp, val);
181 }
182 }
183}
184
185static void do_writebacks(DisasContext *s)
186{
187 unsigned mask = s->writeback_mask;
188 if (mask) {
189 s->writeback_mask = 0;
190 do {
191 unsigned regno = ctz32(mask);
192 tcg_gen_mov_i32(cpu_aregs[regno], s->writeback[regno]);
193 tcg_temp_free(s->writeback[regno]);
194 mask &= mask - 1;
195 } while (mask);
196 }
197}
198
77fc6f5e
LV
199/* is_jmp field values */
200#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
201#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
e6e5906b 202
0633879f
PB
203#if defined(CONFIG_USER_ONLY)
204#define IS_USER(s) 1
205#else
5fa9f1f2
LV
206#define IS_USER(s) (!(s->tb->flags & TB_FLAGS_MSR_S))
207#define SFC_INDEX(s) ((s->tb->flags & TB_FLAGS_SFC_S) ? \
208 MMU_KERNEL_IDX : MMU_USER_IDX)
209#define DFC_INDEX(s) ((s->tb->flags & TB_FLAGS_DFC_S) ? \
210 MMU_KERNEL_IDX : MMU_USER_IDX)
0633879f
PB
211#endif
212
d4d79bb1 213typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn);
e6e5906b 214
0633879f 215#ifdef DEBUG_DISPATCH
d4d79bb1
BS
216#define DISAS_INSN(name) \
217 static void real_disas_##name(CPUM68KState *env, DisasContext *s, \
218 uint16_t insn); \
219 static void disas_##name(CPUM68KState *env, DisasContext *s, \
220 uint16_t insn) \
221 { \
222 qemu_log("Dispatch " #name "\n"); \
a1ff1930 223 real_disas_##name(env, s, insn); \
d4d79bb1
BS
224 } \
225 static void real_disas_##name(CPUM68KState *env, DisasContext *s, \
226 uint16_t insn)
0633879f 227#else
d4d79bb1
BS
228#define DISAS_INSN(name) \
229 static void disas_##name(CPUM68KState *env, DisasContext *s, \
230 uint16_t insn)
0633879f 231#endif
e6e5906b 232
9fdb533f 233static const uint8_t cc_op_live[CC_OP_NB] = {
7deddf96 234 [CC_OP_DYNAMIC] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
620c6cf6 235 [CC_OP_FLAGS] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
db3d7945
LV
236 [CC_OP_ADDB ... CC_OP_ADDL] = CCF_X | CCF_N | CCF_V,
237 [CC_OP_SUBB ... CC_OP_SUBL] = CCF_X | CCF_N | CCF_V,
238 [CC_OP_CMPB ... CC_OP_CMPL] = CCF_X | CCF_N | CCF_V,
620c6cf6 239 [CC_OP_LOGIC] = CCF_X | CCF_N
9fdb533f
LV
240};
241
242static void set_cc_op(DisasContext *s, CCOp op)
243{
620c6cf6 244 CCOp old_op = s->cc_op;
9fdb533f
LV
245 int dead;
246
620c6cf6 247 if (old_op == op) {
9fdb533f
LV
248 return;
249 }
620c6cf6
RH
250 s->cc_op = op;
251 s->cc_op_synced = 0;
9fdb533f 252
620c6cf6
RH
253 /* Discard CC computation that will no longer be used.
254 Note that X and N are never dead. */
255 dead = cc_op_live[old_op] & ~cc_op_live[op];
256 if (dead & CCF_C) {
257 tcg_gen_discard_i32(QREG_CC_C);
9fdb533f 258 }
620c6cf6
RH
259 if (dead & CCF_Z) {
260 tcg_gen_discard_i32(QREG_CC_Z);
9fdb533f 261 }
620c6cf6
RH
262 if (dead & CCF_V) {
263 tcg_gen_discard_i32(QREG_CC_V);
9fdb533f 264 }
9fdb533f
LV
265}
266
267/* Update the CPU env CC_OP state. */
620c6cf6 268static void update_cc_op(DisasContext *s)
9fdb533f 269{
620c6cf6
RH
270 if (!s->cc_op_synced) {
271 s->cc_op_synced = 1;
9fdb533f
LV
272 tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
273 }
274}
275
f83311e4
LV
276/* Generate a jump to an immediate address. */
277static void gen_jmp_im(DisasContext *s, uint32_t dest)
278{
279 update_cc_op(s);
280 tcg_gen_movi_i32(QREG_PC, dest);
281 s->is_jmp = DISAS_JUMP;
282}
283
284/* Generate a jump to the address in qreg DEST. */
285static void gen_jmp(DisasContext *s, TCGv dest)
286{
287 update_cc_op(s);
288 tcg_gen_mov_i32(QREG_PC, dest);
289 s->is_jmp = DISAS_JUMP;
290}
291
cb4add33 292static void gen_exception(DisasContext *s, uint32_t dest, int nr)
f83311e4 293{
cb4add33 294 TCGv_i32 tmp;
f83311e4 295
cb4add33
RH
296 update_cc_op(s);
297 tcg_gen_movi_i32(QREG_PC, dest);
298
299 tmp = tcg_const_i32(nr);
f83311e4
LV
300 gen_helper_raise_exception(cpu_env, tmp);
301 tcg_temp_free_i32(tmp);
f83311e4 302
cb4add33 303 s->is_jmp = DISAS_NORETURN;
f83311e4
LV
304}
305
306static inline void gen_addr_fault(DisasContext *s)
307{
308 gen_exception(s, s->insn_pc, EXCP_ADDRESS);
309}
310
e6e5906b
PB
311/* Generate a load from the specified address. Narrow values are
312 sign extended to full register width. */
54e1e0b5
LV
313static inline TCGv gen_load(DisasContext *s, int opsize, TCGv addr,
314 int sign, int index)
e6e5906b 315{
e1f3808e 316 TCGv tmp;
a7812ae4 317 tmp = tcg_temp_new_i32();
e6e5906b
PB
318 switch(opsize) {
319 case OS_BYTE:
e6e5906b 320 if (sign)
e1f3808e 321 tcg_gen_qemu_ld8s(tmp, addr, index);
e6e5906b 322 else
e1f3808e 323 tcg_gen_qemu_ld8u(tmp, addr, index);
e6e5906b
PB
324 break;
325 case OS_WORD:
e6e5906b 326 if (sign)
e1f3808e 327 tcg_gen_qemu_ld16s(tmp, addr, index);
e6e5906b 328 else
e1f3808e 329 tcg_gen_qemu_ld16u(tmp, addr, index);
e6e5906b
PB
330 break;
331 case OS_LONG:
a7812ae4 332 tcg_gen_qemu_ld32u(tmp, addr, index);
e6e5906b
PB
333 break;
334 default:
7372c2b9 335 g_assert_not_reached();
e6e5906b 336 }
e6e5906b
PB
337 return tmp;
338}
339
340/* Generate a store. */
54e1e0b5
LV
341static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val,
342 int index)
e6e5906b
PB
343{
344 switch(opsize) {
345 case OS_BYTE:
e1f3808e 346 tcg_gen_qemu_st8(val, addr, index);
e6e5906b
PB
347 break;
348 case OS_WORD:
e1f3808e 349 tcg_gen_qemu_st16(val, addr, index);
e6e5906b
PB
350 break;
351 case OS_LONG:
a7812ae4 352 tcg_gen_qemu_st32(val, addr, index);
e6e5906b
PB
353 break;
354 default:
7372c2b9 355 g_assert_not_reached();
e6e5906b 356 }
e6e5906b
PB
357}
358
e1f3808e
PB
359typedef enum {
360 EA_STORE,
361 EA_LOADU,
362 EA_LOADS
363} ea_what;
364
e6e5906b
PB
365/* Generate an unsigned load if VAL is 0 a signed load if val is -1,
366 otherwise generate a store. */
e1f3808e 367static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
54e1e0b5 368 ea_what what, int index)
e6e5906b 369{
e1f3808e 370 if (what == EA_STORE) {
54e1e0b5 371 gen_store(s, opsize, addr, val, index);
e1f3808e 372 return store_dummy;
e6e5906b 373 } else {
ecc207d2
LV
374 return mark_to_release(s, gen_load(s, opsize, addr,
375 what == EA_LOADS, index));
e6e5906b
PB
376 }
377}
378
28b68cd7
LV
379/* Read a 16-bit immediate constant */
380static inline uint16_t read_im16(CPUM68KState *env, DisasContext *s)
381{
382 uint16_t im;
383 im = cpu_lduw_code(env, s->pc);
384 s->pc += 2;
385 return im;
386}
387
388/* Read an 8-bit immediate constant */
389static inline uint8_t read_im8(CPUM68KState *env, DisasContext *s)
390{
391 return read_im16(env, s);
392}
393
e6dbd3b3 394/* Read a 32-bit immediate constant. */
d4d79bb1 395static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s)
e6dbd3b3
PB
396{
397 uint32_t im;
28b68cd7
LV
398 im = read_im16(env, s) << 16;
399 im |= 0xffff & read_im16(env, s);
e6dbd3b3
PB
400 return im;
401}
402
f83311e4
LV
403/* Read a 64-bit immediate constant. */
404static inline uint64_t read_im64(CPUM68KState *env, DisasContext *s)
405{
406 uint64_t im;
407 im = (uint64_t)read_im32(env, s) << 32;
408 im |= (uint64_t)read_im32(env, s);
409 return im;
410}
411
e6dbd3b3 412/* Calculate and address index. */
8a1e52b6 413static TCGv gen_addr_index(DisasContext *s, uint16_t ext, TCGv tmp)
e6dbd3b3 414{
e1f3808e 415 TCGv add;
e6dbd3b3
PB
416 int scale;
417
418 add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
419 if ((ext & 0x800) == 0) {
e1f3808e 420 tcg_gen_ext16s_i32(tmp, add);
e6dbd3b3
PB
421 add = tmp;
422 }
423 scale = (ext >> 9) & 3;
424 if (scale != 0) {
e1f3808e 425 tcg_gen_shli_i32(tmp, add, scale);
e6dbd3b3
PB
426 add = tmp;
427 }
428 return add;
429}
430
e1f3808e
PB
431/* Handle a base + index + displacement effective addresss.
432 A NULL_QREG base means pc-relative. */
a4356126 433static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
e6e5906b 434{
e6e5906b
PB
435 uint32_t offset;
436 uint16_t ext;
e1f3808e
PB
437 TCGv add;
438 TCGv tmp;
e6dbd3b3 439 uint32_t bd, od;
e6e5906b
PB
440
441 offset = s->pc;
28b68cd7 442 ext = read_im16(env, s);
e6dbd3b3
PB
443
444 if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
e1f3808e 445 return NULL_QREG;
e6dbd3b3 446
d8633620
LV
447 if (m68k_feature(s->env, M68K_FEATURE_M68000) &&
448 !m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX)) {
449 ext &= ~(3 << 9);
450 }
451
e6dbd3b3
PB
452 if (ext & 0x100) {
453 /* full extension word format */
454 if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
e1f3808e 455 return NULL_QREG;
e6dbd3b3
PB
456
457 if ((ext & 0x30) > 0x10) {
458 /* base displacement */
459 if ((ext & 0x30) == 0x20) {
28b68cd7 460 bd = (int16_t)read_im16(env, s);
e6dbd3b3 461 } else {
d4d79bb1 462 bd = read_im32(env, s);
e6dbd3b3
PB
463 }
464 } else {
465 bd = 0;
466 }
ecc207d2 467 tmp = mark_to_release(s, tcg_temp_new());
e6dbd3b3
PB
468 if ((ext & 0x44) == 0) {
469 /* pre-index */
8a1e52b6 470 add = gen_addr_index(s, ext, tmp);
e6dbd3b3 471 } else {
e1f3808e 472 add = NULL_QREG;
e6dbd3b3
PB
473 }
474 if ((ext & 0x80) == 0) {
475 /* base not suppressed */
e1f3808e 476 if (IS_NULL_QREG(base)) {
ecc207d2 477 base = mark_to_release(s, tcg_const_i32(offset + bd));
e6dbd3b3
PB
478 bd = 0;
479 }
e1f3808e
PB
480 if (!IS_NULL_QREG(add)) {
481 tcg_gen_add_i32(tmp, add, base);
e6dbd3b3
PB
482 add = tmp;
483 } else {
484 add = base;
485 }
486 }
e1f3808e 487 if (!IS_NULL_QREG(add)) {
e6dbd3b3 488 if (bd != 0) {
e1f3808e 489 tcg_gen_addi_i32(tmp, add, bd);
e6dbd3b3
PB
490 add = tmp;
491 }
492 } else {
ecc207d2 493 add = mark_to_release(s, tcg_const_i32(bd));
e6dbd3b3
PB
494 }
495 if ((ext & 3) != 0) {
496 /* memory indirect */
ecc207d2 497 base = mark_to_release(s, gen_load(s, OS_LONG, add, 0, IS_USER(s)));
e6dbd3b3 498 if ((ext & 0x44) == 4) {
8a1e52b6 499 add = gen_addr_index(s, ext, tmp);
e1f3808e 500 tcg_gen_add_i32(tmp, add, base);
e6dbd3b3
PB
501 add = tmp;
502 } else {
503 add = base;
504 }
505 if ((ext & 3) > 1) {
506 /* outer displacement */
507 if ((ext & 3) == 2) {
28b68cd7 508 od = (int16_t)read_im16(env, s);
e6dbd3b3 509 } else {
d4d79bb1 510 od = read_im32(env, s);
e6dbd3b3
PB
511 }
512 } else {
513 od = 0;
514 }
515 if (od != 0) {
e1f3808e 516 tcg_gen_addi_i32(tmp, add, od);
e6dbd3b3
PB
517 add = tmp;
518 }
519 }
e6e5906b 520 } else {
e6dbd3b3 521 /* brief extension word format */
ecc207d2 522 tmp = mark_to_release(s, tcg_temp_new());
8a1e52b6 523 add = gen_addr_index(s, ext, tmp);
e1f3808e
PB
524 if (!IS_NULL_QREG(base)) {
525 tcg_gen_add_i32(tmp, add, base);
e6dbd3b3 526 if ((int8_t)ext)
e1f3808e 527 tcg_gen_addi_i32(tmp, tmp, (int8_t)ext);
e6dbd3b3 528 } else {
e1f3808e 529 tcg_gen_addi_i32(tmp, add, offset + (int8_t)ext);
e6dbd3b3
PB
530 }
531 add = tmp;
e6e5906b 532 }
e6dbd3b3 533 return add;
e6e5906b
PB
534}
535
db3d7945
LV
536/* Sign or zero extend a value. */
537
538static inline void gen_ext(TCGv res, TCGv val, int opsize, int sign)
539{
540 switch (opsize) {
541 case OS_BYTE:
542 if (sign) {
543 tcg_gen_ext8s_i32(res, val);
544 } else {
545 tcg_gen_ext8u_i32(res, val);
546 }
547 break;
548 case OS_WORD:
549 if (sign) {
550 tcg_gen_ext16s_i32(res, val);
551 } else {
552 tcg_gen_ext16u_i32(res, val);
553 }
554 break;
555 case OS_LONG:
556 tcg_gen_mov_i32(res, val);
557 break;
558 default:
559 g_assert_not_reached();
560 }
561}
562
e6e5906b 563/* Evaluate all the CC flags. */
9fdb533f 564
620c6cf6 565static void gen_flush_flags(DisasContext *s)
e6e5906b 566{
36f0399d 567 TCGv t0, t1;
620c6cf6
RH
568
569 switch (s->cc_op) {
570 case CC_OP_FLAGS:
e6e5906b 571 return;
36f0399d 572
db3d7945
LV
573 case CC_OP_ADDB:
574 case CC_OP_ADDW:
575 case CC_OP_ADDL:
36f0399d
RH
576 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
577 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
578 /* Compute signed overflow for addition. */
579 t0 = tcg_temp_new();
580 t1 = tcg_temp_new();
581 tcg_gen_sub_i32(t0, QREG_CC_N, QREG_CC_V);
db3d7945 582 gen_ext(t0, t0, s->cc_op - CC_OP_ADDB, 1);
36f0399d
RH
583 tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V);
584 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
585 tcg_temp_free(t0);
586 tcg_gen_andc_i32(QREG_CC_V, t1, QREG_CC_V);
587 tcg_temp_free(t1);
588 break;
589
db3d7945
LV
590 case CC_OP_SUBB:
591 case CC_OP_SUBW:
592 case CC_OP_SUBL:
36f0399d
RH
593 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
594 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
595 /* Compute signed overflow for subtraction. */
596 t0 = tcg_temp_new();
597 t1 = tcg_temp_new();
598 tcg_gen_add_i32(t0, QREG_CC_N, QREG_CC_V);
db3d7945 599 gen_ext(t0, t0, s->cc_op - CC_OP_SUBB, 1);
043b936e 600 tcg_gen_xor_i32(t1, QREG_CC_N, t0);
36f0399d
RH
601 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
602 tcg_temp_free(t0);
603 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t1);
604 tcg_temp_free(t1);
605 break;
606
db3d7945
LV
607 case CC_OP_CMPB:
608 case CC_OP_CMPW:
609 case CC_OP_CMPL:
36f0399d
RH
610 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_C, QREG_CC_N, QREG_CC_V);
611 tcg_gen_sub_i32(QREG_CC_Z, QREG_CC_N, QREG_CC_V);
db3d7945 612 gen_ext(QREG_CC_Z, QREG_CC_Z, s->cc_op - CC_OP_CMPB, 1);
36f0399d
RH
613 /* Compute signed overflow for subtraction. */
614 t0 = tcg_temp_new();
615 tcg_gen_xor_i32(t0, QREG_CC_Z, QREG_CC_N);
616 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, QREG_CC_N);
617 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t0);
618 tcg_temp_free(t0);
619 tcg_gen_mov_i32(QREG_CC_N, QREG_CC_Z);
620 break;
621
622 case CC_OP_LOGIC:
623 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
624 tcg_gen_movi_i32(QREG_CC_C, 0);
625 tcg_gen_movi_i32(QREG_CC_V, 0);
626 break;
627
620c6cf6
RH
628 case CC_OP_DYNAMIC:
629 gen_helper_flush_flags(cpu_env, QREG_CC_OP);
695576db 630 s->cc_op_synced = 1;
620c6cf6 631 break;
36f0399d 632
620c6cf6 633 default:
36f0399d
RH
634 t0 = tcg_const_i32(s->cc_op);
635 gen_helper_flush_flags(cpu_env, t0);
636 tcg_temp_free(t0);
695576db 637 s->cc_op_synced = 1;
620c6cf6
RH
638 break;
639 }
640
641 /* Note that flush_flags also assigned to env->cc_op. */
642 s->cc_op = CC_OP_FLAGS;
620c6cf6
RH
643}
644
3f215a14 645static inline TCGv gen_extend(DisasContext *s, TCGv val, int opsize, int sign)
620c6cf6
RH
646{
647 TCGv tmp;
648
649 if (opsize == OS_LONG) {
650 tmp = val;
651 } else {
ecc207d2 652 tmp = mark_to_release(s, tcg_temp_new());
620c6cf6
RH
653 gen_ext(tmp, val, opsize, sign);
654 }
655
656 return tmp;
657}
5dbb6784
LV
658
659static void gen_logic_cc(DisasContext *s, TCGv val, int opsize)
e1f3808e 660{
620c6cf6
RH
661 gen_ext(QREG_CC_N, val, opsize, 1);
662 set_cc_op(s, CC_OP_LOGIC);
e1f3808e
PB
663}
664
ff99b952
LV
665static void gen_update_cc_cmp(DisasContext *s, TCGv dest, TCGv src, int opsize)
666{
667 tcg_gen_mov_i32(QREG_CC_N, dest);
668 tcg_gen_mov_i32(QREG_CC_V, src);
669 set_cc_op(s, CC_OP_CMPB + opsize);
670}
671
db3d7945 672static void gen_update_cc_add(TCGv dest, TCGv src, int opsize)
e1f3808e 673{
db3d7945 674 gen_ext(QREG_CC_N, dest, opsize, 1);
620c6cf6 675 tcg_gen_mov_i32(QREG_CC_V, src);
e1f3808e
PB
676}
677
e6e5906b
PB
678static inline int opsize_bytes(int opsize)
679{
680 switch (opsize) {
681 case OS_BYTE: return 1;
682 case OS_WORD: return 2;
683 case OS_LONG: return 4;
684 case OS_SINGLE: return 4;
685 case OS_DOUBLE: return 8;
7ef25cdd
LV
686 case OS_EXTENDED: return 12;
687 case OS_PACKED: return 12;
688 default:
689 g_assert_not_reached();
690 }
691}
692
693static inline int insn_opsize(int insn)
694{
695 switch ((insn >> 6) & 3) {
696 case 0: return OS_BYTE;
697 case 1: return OS_WORD;
698 case 2: return OS_LONG;
e6e5906b 699 default:
7372c2b9 700 g_assert_not_reached();
e6e5906b
PB
701 }
702}
703
69e69822
LV
704static inline int ext_opsize(int ext, int pos)
705{
706 switch ((ext >> pos) & 7) {
707 case 0: return OS_LONG;
708 case 1: return OS_SINGLE;
709 case 2: return OS_EXTENDED;
710 case 3: return OS_PACKED;
711 case 4: return OS_WORD;
712 case 5: return OS_DOUBLE;
713 case 6: return OS_BYTE;
714 default:
715 g_assert_not_reached();
716 }
717}
718
e6e5906b
PB
719/* Assign value to a register. If the width is less than the register width
720 only the low part of the register is set. */
e1f3808e 721static void gen_partset_reg(int opsize, TCGv reg, TCGv val)
e6e5906b 722{
e1f3808e 723 TCGv tmp;
e6e5906b
PB
724 switch (opsize) {
725 case OS_BYTE:
e1f3808e 726 tcg_gen_andi_i32(reg, reg, 0xffffff00);
a7812ae4 727 tmp = tcg_temp_new();
e1f3808e
PB
728 tcg_gen_ext8u_i32(tmp, val);
729 tcg_gen_or_i32(reg, reg, tmp);
2b5e2170 730 tcg_temp_free(tmp);
e6e5906b
PB
731 break;
732 case OS_WORD:
e1f3808e 733 tcg_gen_andi_i32(reg, reg, 0xffff0000);
a7812ae4 734 tmp = tcg_temp_new();
e1f3808e
PB
735 tcg_gen_ext16u_i32(tmp, val);
736 tcg_gen_or_i32(reg, reg, tmp);
2b5e2170 737 tcg_temp_free(tmp);
e6e5906b
PB
738 break;
739 case OS_LONG:
e6e5906b 740 case OS_SINGLE:
a7812ae4 741 tcg_gen_mov_i32(reg, val);
e6e5906b
PB
742 break;
743 default:
7372c2b9 744 g_assert_not_reached();
e6e5906b
PB
745 }
746}
747
e6e5906b 748/* Generate code for an "effective address". Does not adjust the base
1addc7c5 749 register for autoincrement addressing modes. */
f84aab26
RH
750static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
751 int mode, int reg0, int opsize)
e6e5906b 752{
e1f3808e
PB
753 TCGv reg;
754 TCGv tmp;
e6e5906b
PB
755 uint16_t ext;
756 uint32_t offset;
757
f84aab26 758 switch (mode) {
e6e5906b
PB
759 case 0: /* Data register direct. */
760 case 1: /* Address register direct. */
e1f3808e 761 return NULL_QREG;
e6e5906b 762 case 3: /* Indirect postincrement. */
f2224f2c
RH
763 if (opsize == OS_UNSIZED) {
764 return NULL_QREG;
765 }
766 /* fallthru */
767 case 2: /* Indirect register */
f84aab26 768 return get_areg(s, reg0);
e6e5906b 769 case 4: /* Indirect predecrememnt. */
f2224f2c
RH
770 if (opsize == OS_UNSIZED) {
771 return NULL_QREG;
772 }
f84aab26 773 reg = get_areg(s, reg0);
ecc207d2 774 tmp = mark_to_release(s, tcg_temp_new());
727d937b
LV
775 if (reg0 == 7 && opsize == OS_BYTE &&
776 m68k_feature(s->env, M68K_FEATURE_M68000)) {
777 tcg_gen_subi_i32(tmp, reg, 2);
778 } else {
779 tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize));
780 }
e6e5906b
PB
781 return tmp;
782 case 5: /* Indirect displacement. */
f84aab26 783 reg = get_areg(s, reg0);
ecc207d2 784 tmp = mark_to_release(s, tcg_temp_new());
28b68cd7 785 ext = read_im16(env, s);
e1f3808e 786 tcg_gen_addi_i32(tmp, reg, (int16_t)ext);
e6e5906b
PB
787 return tmp;
788 case 6: /* Indirect index + displacement. */
f84aab26 789 reg = get_areg(s, reg0);
a4356126 790 return gen_lea_indexed(env, s, reg);
e6e5906b 791 case 7: /* Other */
f84aab26 792 switch (reg0) {
e6e5906b 793 case 0: /* Absolute short. */
28b68cd7 794 offset = (int16_t)read_im16(env, s);
ecc207d2 795 return mark_to_release(s, tcg_const_i32(offset));
e6e5906b 796 case 1: /* Absolute long. */
d4d79bb1 797 offset = read_im32(env, s);
ecc207d2 798 return mark_to_release(s, tcg_const_i32(offset));
e6e5906b 799 case 2: /* pc displacement */
e6e5906b 800 offset = s->pc;
28b68cd7 801 offset += (int16_t)read_im16(env, s);
ecc207d2 802 return mark_to_release(s, tcg_const_i32(offset));
e6e5906b 803 case 3: /* pc index+displacement. */
a4356126 804 return gen_lea_indexed(env, s, NULL_QREG);
e6e5906b
PB
805 case 4: /* Immediate. */
806 default:
e1f3808e 807 return NULL_QREG;
e6e5906b
PB
808 }
809 }
810 /* Should never happen. */
e1f3808e 811 return NULL_QREG;
e6e5906b
PB
812}
813
f84aab26
RH
814static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn,
815 int opsize)
e6e5906b 816{
f84aab26
RH
817 int mode = extract32(insn, 3, 3);
818 int reg0 = REG(insn, 0);
819 return gen_lea_mode(env, s, mode, reg0, opsize);
e6e5906b
PB
820}
821
f84aab26 822/* Generate code to load/store a value from/into an EA. If WHAT > 0 this is
e6e5906b
PB
823 a write otherwise it is a read (0 == sign extend, -1 == zero extend).
824 ADDRP is non-null for readwrite operands. */
f84aab26 825static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0,
54e1e0b5
LV
826 int opsize, TCGv val, TCGv *addrp, ea_what what,
827 int index)
e6e5906b 828{
f84aab26
RH
829 TCGv reg, tmp, result;
830 int32_t offset;
e6e5906b 831
f84aab26 832 switch (mode) {
e6e5906b 833 case 0: /* Data register direct. */
f84aab26 834 reg = cpu_dregs[reg0];
e1f3808e 835 if (what == EA_STORE) {
e6e5906b 836 gen_partset_reg(opsize, reg, val);
e1f3808e 837 return store_dummy;
e6e5906b 838 } else {
3f215a14 839 return gen_extend(s, reg, opsize, what == EA_LOADS);
e6e5906b
PB
840 }
841 case 1: /* Address register direct. */
f84aab26 842 reg = get_areg(s, reg0);
e1f3808e
PB
843 if (what == EA_STORE) {
844 tcg_gen_mov_i32(reg, val);
845 return store_dummy;
e6e5906b 846 } else {
3f215a14 847 return gen_extend(s, reg, opsize, what == EA_LOADS);
e6e5906b
PB
848 }
849 case 2: /* Indirect register */
f84aab26 850 reg = get_areg(s, reg0);
54e1e0b5 851 return gen_ldst(s, opsize, reg, val, what, index);
e6e5906b 852 case 3: /* Indirect postincrement. */
f84aab26 853 reg = get_areg(s, reg0);
54e1e0b5 854 result = gen_ldst(s, opsize, reg, val, what, index);
8a1e52b6
RH
855 if (what == EA_STORE || !addrp) {
856 TCGv tmp = tcg_temp_new();
727d937b
LV
857 if (reg0 == 7 && opsize == OS_BYTE &&
858 m68k_feature(s->env, M68K_FEATURE_M68000)) {
859 tcg_gen_addi_i32(tmp, reg, 2);
860 } else {
861 tcg_gen_addi_i32(tmp, reg, opsize_bytes(opsize));
862 }
f84aab26 863 delay_set_areg(s, reg0, tmp, true);
8a1e52b6 864 }
e6e5906b
PB
865 return result;
866 case 4: /* Indirect predecrememnt. */
f84aab26
RH
867 if (addrp && what == EA_STORE) {
868 tmp = *addrp;
869 } else {
870 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
871 if (IS_NULL_QREG(tmp)) {
872 return tmp;
e6e5906b 873 }
f84aab26
RH
874 if (addrp) {
875 *addrp = tmp;
e6e5906b
PB
876 }
877 }
54e1e0b5 878 result = gen_ldst(s, opsize, tmp, val, what, index);
f84aab26
RH
879 if (what == EA_STORE || !addrp) {
880 delay_set_areg(s, reg0, tmp, false);
881 }
e6e5906b
PB
882 return result;
883 case 5: /* Indirect displacement. */
884 case 6: /* Indirect index + displacement. */
f84aab26
RH
885 do_indirect:
886 if (addrp && what == EA_STORE) {
887 tmp = *addrp;
888 } else {
889 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
890 if (IS_NULL_QREG(tmp)) {
891 return tmp;
892 }
893 if (addrp) {
894 *addrp = tmp;
895 }
896 }
54e1e0b5 897 return gen_ldst(s, opsize, tmp, val, what, index);
e6e5906b 898 case 7: /* Other */
f84aab26 899 switch (reg0) {
e6e5906b
PB
900 case 0: /* Absolute short. */
901 case 1: /* Absolute long. */
902 case 2: /* pc displacement */
903 case 3: /* pc index+displacement. */
f84aab26 904 goto do_indirect;
e6e5906b
PB
905 case 4: /* Immediate. */
906 /* Sign extend values for consistency. */
907 switch (opsize) {
908 case OS_BYTE:
31871141 909 if (what == EA_LOADS) {
28b68cd7 910 offset = (int8_t)read_im8(env, s);
31871141 911 } else {
28b68cd7 912 offset = read_im8(env, s);
31871141 913 }
e6e5906b
PB
914 break;
915 case OS_WORD:
31871141 916 if (what == EA_LOADS) {
28b68cd7 917 offset = (int16_t)read_im16(env, s);
31871141 918 } else {
28b68cd7 919 offset = read_im16(env, s);
31871141 920 }
e6e5906b
PB
921 break;
922 case OS_LONG:
d4d79bb1 923 offset = read_im32(env, s);
e6e5906b
PB
924 break;
925 default:
7372c2b9 926 g_assert_not_reached();
e6e5906b 927 }
ecc207d2 928 return mark_to_release(s, tcg_const_i32(offset));
e6e5906b 929 default:
e1f3808e 930 return NULL_QREG;
e6e5906b
PB
931 }
932 }
933 /* Should never happen. */
e1f3808e 934 return NULL_QREG;
e6e5906b
PB
935}
936
f84aab26 937static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn,
54e1e0b5 938 int opsize, TCGv val, TCGv *addrp, ea_what what, int index)
f84aab26
RH
939{
940 int mode = extract32(insn, 3, 3);
941 int reg0 = REG(insn, 0);
54e1e0b5 942 return gen_ea_mode(env, s, mode, reg0, opsize, val, addrp, what, index);
f84aab26
RH
943}
944
f83311e4
LV
945static TCGv_ptr gen_fp_ptr(int freg)
946{
947 TCGv_ptr fp = tcg_temp_new_ptr();
948 tcg_gen_addi_ptr(fp, cpu_env, offsetof(CPUM68KState, fregs[freg]));
949 return fp;
950}
951
952static TCGv_ptr gen_fp_result_ptr(void)
953{
954 TCGv_ptr fp = tcg_temp_new_ptr();
955 tcg_gen_addi_ptr(fp, cpu_env, offsetof(CPUM68KState, fp_result));
956 return fp;
957}
958
959static void gen_fp_move(TCGv_ptr dest, TCGv_ptr src)
960{
961 TCGv t32;
962 TCGv_i64 t64;
963
964 t32 = tcg_temp_new();
965 tcg_gen_ld16u_i32(t32, src, offsetof(FPReg, l.upper));
966 tcg_gen_st16_i32(t32, dest, offsetof(FPReg, l.upper));
967 tcg_temp_free(t32);
968
969 t64 = tcg_temp_new_i64();
970 tcg_gen_ld_i64(t64, src, offsetof(FPReg, l.lower));
971 tcg_gen_st_i64(t64, dest, offsetof(FPReg, l.lower));
972 tcg_temp_free_i64(t64);
973}
974
54e1e0b5
LV
975static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
976 int index)
f83311e4
LV
977{
978 TCGv tmp;
979 TCGv_i64 t64;
f83311e4
LV
980
981 t64 = tcg_temp_new_i64();
982 tmp = tcg_temp_new();
983 switch (opsize) {
984 case OS_BYTE:
985 tcg_gen_qemu_ld8s(tmp, addr, index);
986 gen_helper_exts32(cpu_env, fp, tmp);
987 break;
988 case OS_WORD:
989 tcg_gen_qemu_ld16s(tmp, addr, index);
990 gen_helper_exts32(cpu_env, fp, tmp);
991 break;
992 case OS_LONG:
993 tcg_gen_qemu_ld32u(tmp, addr, index);
994 gen_helper_exts32(cpu_env, fp, tmp);
995 break;
996 case OS_SINGLE:
997 tcg_gen_qemu_ld32u(tmp, addr, index);
998 gen_helper_extf32(cpu_env, fp, tmp);
999 break;
1000 case OS_DOUBLE:
1001 tcg_gen_qemu_ld64(t64, addr, index);
1002 gen_helper_extf64(cpu_env, fp, t64);
f83311e4
LV
1003 break;
1004 case OS_EXTENDED:
1005 if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1006 gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
1007 break;
1008 }
1009 tcg_gen_qemu_ld32u(tmp, addr, index);
1010 tcg_gen_shri_i32(tmp, tmp, 16);
1011 tcg_gen_st16_i32(tmp, fp, offsetof(FPReg, l.upper));
1012 tcg_gen_addi_i32(tmp, addr, 4);
1013 tcg_gen_qemu_ld64(t64, tmp, index);
1014 tcg_gen_st_i64(t64, fp, offsetof(FPReg, l.lower));
1015 break;
1016 case OS_PACKED:
1017 /* unimplemented data type on 68040/ColdFire
1018 * FIXME if needed for another FPU
1019 */
1020 gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
1021 break;
1022 default:
1023 g_assert_not_reached();
1024 }
1025 tcg_temp_free(tmp);
1026 tcg_temp_free_i64(t64);
f83311e4
LV
1027}
1028
54e1e0b5
LV
1029static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
1030 int index)
f83311e4
LV
1031{
1032 TCGv tmp;
1033 TCGv_i64 t64;
f83311e4
LV
1034
1035 t64 = tcg_temp_new_i64();
1036 tmp = tcg_temp_new();
1037 switch (opsize) {
1038 case OS_BYTE:
1039 gen_helper_reds32(tmp, cpu_env, fp);
1040 tcg_gen_qemu_st8(tmp, addr, index);
1041 break;
1042 case OS_WORD:
1043 gen_helper_reds32(tmp, cpu_env, fp);
1044 tcg_gen_qemu_st16(tmp, addr, index);
1045 break;
1046 case OS_LONG:
1047 gen_helper_reds32(tmp, cpu_env, fp);
1048 tcg_gen_qemu_st32(tmp, addr, index);
1049 break;
1050 case OS_SINGLE:
1051 gen_helper_redf32(tmp, cpu_env, fp);
1052 tcg_gen_qemu_st32(tmp, addr, index);
1053 break;
1054 case OS_DOUBLE:
1055 gen_helper_redf64(t64, cpu_env, fp);
1056 tcg_gen_qemu_st64(t64, addr, index);
1057 break;
1058 case OS_EXTENDED:
1059 if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1060 gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
1061 break;
1062 }
1063 tcg_gen_ld16u_i32(tmp, fp, offsetof(FPReg, l.upper));
1064 tcg_gen_shli_i32(tmp, tmp, 16);
1065 tcg_gen_qemu_st32(tmp, addr, index);
1066 tcg_gen_addi_i32(tmp, addr, 4);
1067 tcg_gen_ld_i64(t64, fp, offsetof(FPReg, l.lower));
1068 tcg_gen_qemu_st64(t64, tmp, index);
1069 break;
1070 case OS_PACKED:
1071 /* unimplemented data type on 68040/ColdFire
1072 * FIXME if needed for another FPU
1073 */
1074 gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
1075 break;
1076 default:
1077 g_assert_not_reached();
1078 }
1079 tcg_temp_free(tmp);
1080 tcg_temp_free_i64(t64);
f83311e4
LV
1081}
1082
1083static void gen_ldst_fp(DisasContext *s, int opsize, TCGv addr,
54e1e0b5 1084 TCGv_ptr fp, ea_what what, int index)
f83311e4
LV
1085{
1086 if (what == EA_STORE) {
54e1e0b5 1087 gen_store_fp(s, opsize, addr, fp, index);
f83311e4 1088 } else {
54e1e0b5 1089 gen_load_fp(s, opsize, addr, fp, index);
f83311e4
LV
1090 }
1091}
1092
1093static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
54e1e0b5
LV
1094 int reg0, int opsize, TCGv_ptr fp, ea_what what,
1095 int index)
f83311e4
LV
1096{
1097 TCGv reg, addr, tmp;
1098 TCGv_i64 t64;
1099
1100 switch (mode) {
1101 case 0: /* Data register direct. */
1102 reg = cpu_dregs[reg0];
1103 if (what == EA_STORE) {
1104 switch (opsize) {
1105 case OS_BYTE:
1106 case OS_WORD:
1107 case OS_LONG:
1108 gen_helper_reds32(reg, cpu_env, fp);
1109 break;
1110 case OS_SINGLE:
1111 gen_helper_redf32(reg, cpu_env, fp);
1112 break;
1113 default:
1114 g_assert_not_reached();
1115 }
1116 } else {
1117 tmp = tcg_temp_new();
1118 switch (opsize) {
1119 case OS_BYTE:
1120 tcg_gen_ext8s_i32(tmp, reg);
1121 gen_helper_exts32(cpu_env, fp, tmp);
1122 break;
1123 case OS_WORD:
1124 tcg_gen_ext16s_i32(tmp, reg);
1125 gen_helper_exts32(cpu_env, fp, tmp);
1126 break;
1127 case OS_LONG:
1128 gen_helper_exts32(cpu_env, fp, reg);
1129 break;
1130 case OS_SINGLE:
1131 gen_helper_extf32(cpu_env, fp, reg);
1132 break;
1133 default:
1134 g_assert_not_reached();
1135 }
1136 tcg_temp_free(tmp);
1137 }
1138 return 0;
1139 case 1: /* Address register direct. */
1140 return -1;
1141 case 2: /* Indirect register */
1142 addr = get_areg(s, reg0);
54e1e0b5 1143 gen_ldst_fp(s, opsize, addr, fp, what, index);
f83311e4
LV
1144 return 0;
1145 case 3: /* Indirect postincrement. */
1146 addr = cpu_aregs[reg0];
54e1e0b5 1147 gen_ldst_fp(s, opsize, addr, fp, what, index);
f83311e4
LV
1148 tcg_gen_addi_i32(addr, addr, opsize_bytes(opsize));
1149 return 0;
1150 case 4: /* Indirect predecrememnt. */
1151 addr = gen_lea_mode(env, s, mode, reg0, opsize);
1152 if (IS_NULL_QREG(addr)) {
1153 return -1;
1154 }
54e1e0b5 1155 gen_ldst_fp(s, opsize, addr, fp, what, index);
f83311e4
LV
1156 tcg_gen_mov_i32(cpu_aregs[reg0], addr);
1157 return 0;
1158 case 5: /* Indirect displacement. */
1159 case 6: /* Indirect index + displacement. */
1160 do_indirect:
1161 addr = gen_lea_mode(env, s, mode, reg0, opsize);
1162 if (IS_NULL_QREG(addr)) {
1163 return -1;
1164 }
54e1e0b5 1165 gen_ldst_fp(s, opsize, addr, fp, what, index);
f83311e4
LV
1166 return 0;
1167 case 7: /* Other */
1168 switch (reg0) {
1169 case 0: /* Absolute short. */
1170 case 1: /* Absolute long. */
1171 case 2: /* pc displacement */
1172 case 3: /* pc index+displacement. */
1173 goto do_indirect;
1174 case 4: /* Immediate. */
1175 if (what == EA_STORE) {
1176 return -1;
1177 }
1178 switch (opsize) {
1179 case OS_BYTE:
1180 tmp = tcg_const_i32((int8_t)read_im8(env, s));
1181 gen_helper_exts32(cpu_env, fp, tmp);
1182 tcg_temp_free(tmp);
1183 break;
1184 case OS_WORD:
1185 tmp = tcg_const_i32((int16_t)read_im16(env, s));
1186 gen_helper_exts32(cpu_env, fp, tmp);
1187 tcg_temp_free(tmp);
1188 break;
1189 case OS_LONG:
1190 tmp = tcg_const_i32(read_im32(env, s));
1191 gen_helper_exts32(cpu_env, fp, tmp);
1192 tcg_temp_free(tmp);
1193 break;
1194 case OS_SINGLE:
1195 tmp = tcg_const_i32(read_im32(env, s));
1196 gen_helper_extf32(cpu_env, fp, tmp);
1197 tcg_temp_free(tmp);
1198 break;
1199 case OS_DOUBLE:
1200 t64 = tcg_const_i64(read_im64(env, s));
1201 gen_helper_extf64(cpu_env, fp, t64);
1202 tcg_temp_free_i64(t64);
1203 break;
1204 case OS_EXTENDED:
1205 if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1206 gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
1207 break;
1208 }
1209 tmp = tcg_const_i32(read_im32(env, s) >> 16);
1210 tcg_gen_st16_i32(tmp, fp, offsetof(FPReg, l.upper));
1211 tcg_temp_free(tmp);
1212 t64 = tcg_const_i64(read_im64(env, s));
1213 tcg_gen_st_i64(t64, fp, offsetof(FPReg, l.lower));
1214 tcg_temp_free_i64(t64);
1215 break;
1216 case OS_PACKED:
1217 /* unimplemented data type on 68040/ColdFire
1218 * FIXME if needed for another FPU
1219 */
1220 gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
1221 break;
1222 default:
1223 g_assert_not_reached();
1224 }
1225 return 0;
1226 default:
1227 return -1;
1228 }
1229 }
1230 return -1;
1231}
1232
1233static int gen_ea_fp(CPUM68KState *env, DisasContext *s, uint16_t insn,
54e1e0b5 1234 int opsize, TCGv_ptr fp, ea_what what, int index)
f83311e4
LV
1235{
1236 int mode = extract32(insn, 3, 3);
1237 int reg0 = REG(insn, 0);
54e1e0b5 1238 return gen_ea_mode_fp(env, s, mode, reg0, opsize, fp, what, index);
f83311e4
LV
1239}
1240
6a432295
RH
1241typedef struct {
1242 TCGCond tcond;
1243 bool g1;
1244 bool g2;
1245 TCGv v1;
1246 TCGv v2;
1247} DisasCompare;
1248
1249static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond)
e6e5906b 1250{
620c6cf6
RH
1251 TCGv tmp, tmp2;
1252 TCGCond tcond;
9d896621 1253 CCOp op = s->cc_op;
e6e5906b 1254
9d896621 1255 /* The CC_OP_CMP form can handle most normal comparisons directly. */
db3d7945 1256 if (op == CC_OP_CMPB || op == CC_OP_CMPW || op == CC_OP_CMPL) {
9d896621
RH
1257 c->g1 = c->g2 = 1;
1258 c->v1 = QREG_CC_N;
1259 c->v2 = QREG_CC_V;
1260 switch (cond) {
1261 case 2: /* HI */
1262 case 3: /* LS */
1263 tcond = TCG_COND_LEU;
1264 goto done;
1265 case 4: /* CC */
1266 case 5: /* CS */
1267 tcond = TCG_COND_LTU;
1268 goto done;
1269 case 6: /* NE */
1270 case 7: /* EQ */
1271 tcond = TCG_COND_EQ;
1272 goto done;
1273 case 10: /* PL */
1274 case 11: /* MI */
1275 c->g1 = c->g2 = 0;
1276 c->v2 = tcg_const_i32(0);
1277 c->v1 = tmp = tcg_temp_new();
1278 tcg_gen_sub_i32(tmp, QREG_CC_N, QREG_CC_V);
db3d7945 1279 gen_ext(tmp, tmp, op - CC_OP_CMPB, 1);
9d896621
RH
1280 /* fallthru */
1281 case 12: /* GE */
1282 case 13: /* LT */
1283 tcond = TCG_COND_LT;
1284 goto done;
1285 case 14: /* GT */
1286 case 15: /* LE */
1287 tcond = TCG_COND_LE;
1288 goto done;
1289 }
1290 }
6a432295
RH
1291
1292 c->g1 = 1;
1293 c->g2 = 0;
1294 c->v2 = tcg_const_i32(0);
1295
e6e5906b
PB
1296 switch (cond) {
1297 case 0: /* T */
e6e5906b 1298 case 1: /* F */
6a432295
RH
1299 c->v1 = c->v2;
1300 tcond = TCG_COND_NEVER;
9d896621
RH
1301 goto done;
1302 case 14: /* GT (!(Z || (N ^ V))) */
1303 case 15: /* LE (Z || (N ^ V)) */
1304 /* Logic operations clear V, which simplifies LE to (Z || N),
1305 and since Z and N are co-located, this becomes a normal
1306 comparison vs N. */
1307 if (op == CC_OP_LOGIC) {
1308 c->v1 = QREG_CC_N;
1309 tcond = TCG_COND_LE;
1310 goto done;
1311 }
6a432295 1312 break;
9d896621
RH
1313 case 12: /* GE (!(N ^ V)) */
1314 case 13: /* LT (N ^ V) */
1315 /* Logic operations clear V, which simplifies this to N. */
1316 if (op != CC_OP_LOGIC) {
1317 break;
1318 }
1319 /* fallthru */
1320 case 10: /* PL (!N) */
1321 case 11: /* MI (N) */
1322 /* Several cases represent N normally. */
db3d7945
LV
1323 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1324 op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
1325 op == CC_OP_LOGIC) {
9d896621
RH
1326 c->v1 = QREG_CC_N;
1327 tcond = TCG_COND_LT;
1328 goto done;
1329 }
1330 break;
1331 case 6: /* NE (!Z) */
1332 case 7: /* EQ (Z) */
1333 /* Some cases fold Z into N. */
db3d7945
LV
1334 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1335 op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
1336 op == CC_OP_LOGIC) {
9d896621
RH
1337 tcond = TCG_COND_EQ;
1338 c->v1 = QREG_CC_N;
1339 goto done;
1340 }
1341 break;
1342 case 4: /* CC (!C) */
1343 case 5: /* CS (C) */
1344 /* Some cases fold C into X. */
db3d7945 1345 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
4b5660e4 1346 op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL) {
9d896621
RH
1347 tcond = TCG_COND_NE;
1348 c->v1 = QREG_CC_X;
1349 goto done;
1350 }
1351 /* fallthru */
1352 case 8: /* VC (!V) */
1353 case 9: /* VS (V) */
1354 /* Logic operations clear V and C. */
1355 if (op == CC_OP_LOGIC) {
1356 tcond = TCG_COND_NEVER;
1357 c->v1 = c->v2;
1358 goto done;
1359 }
1360 break;
1361 }
1362
1363 /* Otherwise, flush flag state to CC_OP_FLAGS. */
1364 gen_flush_flags(s);
1365
1366 switch (cond) {
1367 case 0: /* T */
1368 case 1: /* F */
1369 default:
1370 /* Invalid, or handled above. */
1371 abort();
620c6cf6 1372 case 2: /* HI (!C && !Z) -> !(C || Z)*/
e6e5906b 1373 case 3: /* LS (C || Z) */
6a432295
RH
1374 c->v1 = tmp = tcg_temp_new();
1375 c->g1 = 0;
1376 tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
620c6cf6 1377 tcg_gen_or_i32(tmp, tmp, QREG_CC_C);
6a432295 1378 tcond = TCG_COND_NE;
e6e5906b
PB
1379 break;
1380 case 4: /* CC (!C) */
e6e5906b 1381 case 5: /* CS (C) */
6a432295
RH
1382 c->v1 = QREG_CC_C;
1383 tcond = TCG_COND_NE;
e6e5906b
PB
1384 break;
1385 case 6: /* NE (!Z) */
e6e5906b 1386 case 7: /* EQ (Z) */
6a432295
RH
1387 c->v1 = QREG_CC_Z;
1388 tcond = TCG_COND_EQ;
e6e5906b
PB
1389 break;
1390 case 8: /* VC (!V) */
e6e5906b 1391 case 9: /* VS (V) */
6a432295
RH
1392 c->v1 = QREG_CC_V;
1393 tcond = TCG_COND_LT;
e6e5906b
PB
1394 break;
1395 case 10: /* PL (!N) */
e6e5906b 1396 case 11: /* MI (N) */
6a432295
RH
1397 c->v1 = QREG_CC_N;
1398 tcond = TCG_COND_LT;
e6e5906b
PB
1399 break;
1400 case 12: /* GE (!(N ^ V)) */
e6e5906b 1401 case 13: /* LT (N ^ V) */
6a432295
RH
1402 c->v1 = tmp = tcg_temp_new();
1403 c->g1 = 0;
620c6cf6 1404 tcg_gen_xor_i32(tmp, QREG_CC_N, QREG_CC_V);
6a432295 1405 tcond = TCG_COND_LT;
e6e5906b
PB
1406 break;
1407 case 14: /* GT (!(Z || (N ^ V))) */
e6e5906b 1408 case 15: /* LE (Z || (N ^ V)) */
6a432295
RH
1409 c->v1 = tmp = tcg_temp_new();
1410 c->g1 = 0;
1411 tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
620c6cf6
RH
1412 tcg_gen_neg_i32(tmp, tmp);
1413 tmp2 = tcg_temp_new();
1414 tcg_gen_xor_i32(tmp2, QREG_CC_N, QREG_CC_V);
1415 tcg_gen_or_i32(tmp, tmp, tmp2);
6a432295
RH
1416 tcg_temp_free(tmp2);
1417 tcond = TCG_COND_LT;
e6e5906b 1418 break;
e6e5906b 1419 }
9d896621
RH
1420
1421 done:
6a432295
RH
1422 if ((cond & 1) == 0) {
1423 tcond = tcg_invert_cond(tcond);
1424 }
1425 c->tcond = tcond;
1426}
1427
1428static void free_cond(DisasCompare *c)
1429{
1430 if (!c->g1) {
1431 tcg_temp_free(c->v1);
1432 }
1433 if (!c->g2) {
1434 tcg_temp_free(c->v2);
1435 }
1436}
1437
1438static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1)
1439{
1440 DisasCompare c;
1441
1442 gen_cc_cond(&c, s, cond);
1443 update_cc_op(s);
1444 tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
1445 free_cond(&c);
e6e5906b
PB
1446}
1447
0633879f
PB
1448/* Force a TB lookup after an instruction that changes the CPU state. */
1449static void gen_lookup_tb(DisasContext *s)
1450{
9fdb533f 1451 update_cc_op(s);
e1f3808e 1452 tcg_gen_movi_i32(QREG_PC, s->pc);
0633879f
PB
1453 s->is_jmp = DISAS_UPDATE;
1454}
1455
d4d79bb1
BS
1456#define SRC_EA(env, result, opsize, op_sign, addrp) do { \
1457 result = gen_ea(env, s, insn, opsize, NULL_QREG, addrp, \
54e1e0b5 1458 op_sign ? EA_LOADS : EA_LOADU, IS_USER(s)); \
d4d79bb1
BS
1459 if (IS_NULL_QREG(result)) { \
1460 gen_addr_fault(s); \
1461 return; \
1462 } \
510ff0b7
PB
1463 } while (0)
1464
d4d79bb1 1465#define DEST_EA(env, insn, opsize, val, addrp) do { \
54e1e0b5
LV
1466 TCGv ea_result = gen_ea(env, s, insn, opsize, val, addrp, \
1467 EA_STORE, IS_USER(s)); \
d4d79bb1
BS
1468 if (IS_NULL_QREG(ea_result)) { \
1469 gen_addr_fault(s); \
1470 return; \
1471 } \
510ff0b7
PB
1472 } while (0)
1473
90aa39a1
SF
1474static inline bool use_goto_tb(DisasContext *s, uint32_t dest)
1475{
1476#ifndef CONFIG_USER_ONLY
1477 return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
1478 (s->insn_pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
1479#else
1480 return true;
1481#endif
1482}
1483
e6e5906b
PB
1484/* Generate a jump to an immediate address. */
1485static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
1486{
551bd27f 1487 if (unlikely(s->singlestep_enabled)) {
e6e5906b 1488 gen_exception(s, dest, EXCP_DEBUG);
90aa39a1 1489 } else if (use_goto_tb(s, dest)) {
57fec1fe 1490 tcg_gen_goto_tb(n);
e1f3808e 1491 tcg_gen_movi_i32(QREG_PC, dest);
07ea28b4 1492 tcg_gen_exit_tb(s->tb, n);
e6e5906b 1493 } else {
e1f3808e 1494 gen_jmp_im(s, dest);
07ea28b4 1495 tcg_gen_exit_tb(NULL, 0);
e6e5906b 1496 }
825340f5 1497 s->is_jmp = DISAS_NORETURN;
e6e5906b
PB
1498}
1499
d5a3cf33
LV
1500DISAS_INSN(scc)
1501{
1502 DisasCompare c;
1503 int cond;
1504 TCGv tmp;
1505
1506 cond = (insn >> 8) & 0xf;
1507 gen_cc_cond(&c, s, cond);
1508
1509 tmp = tcg_temp_new();
1510 tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2);
1511 free_cond(&c);
1512
1513 tcg_gen_neg_i32(tmp, tmp);
1514 DEST_EA(env, insn, OS_BYTE, tmp, NULL);
1515 tcg_temp_free(tmp);
1516}
1517
beff27ab
LV
1518DISAS_INSN(dbcc)
1519{
1520 TCGLabel *l1;
1521 TCGv reg;
1522 TCGv tmp;
1523 int16_t offset;
1524 uint32_t base;
1525
1526 reg = DREG(insn, 0);
1527 base = s->pc;
1528 offset = (int16_t)read_im16(env, s);
1529 l1 = gen_new_label();
1530 gen_jmpcc(s, (insn >> 8) & 0xf, l1);
1531
1532 tmp = tcg_temp_new();
1533 tcg_gen_ext16s_i32(tmp, reg);
1534 tcg_gen_addi_i32(tmp, tmp, -1);
1535 gen_partset_reg(OS_WORD, reg, tmp);
1536 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1);
1537 gen_jmp_tb(s, 1, base + offset);
1538 gen_set_label(l1);
1539 gen_jmp_tb(s, 0, s->pc);
1540}
1541
e6e5906b
PB
1542DISAS_INSN(undef_mac)
1543{
16a14cdf 1544 gen_exception(s, s->insn_pc, EXCP_LINEA);
e6e5906b
PB
1545}
1546
1547DISAS_INSN(undef_fpu)
1548{
16a14cdf 1549 gen_exception(s, s->insn_pc, EXCP_LINEF);
e6e5906b
PB
1550}
1551
1552DISAS_INSN(undef)
1553{
72d2e4b6
RH
1554 /* ??? This is both instructions that are as yet unimplemented
1555 for the 680x0 series, as well as those that are implemented
1556 but actually illegal for CPU32 or pre-68020. */
21528149 1557 qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n",
16a14cdf
LV
1558 insn, s->insn_pc);
1559 gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED);
e6e5906b
PB
1560}
1561
1562DISAS_INSN(mulw)
1563{
e1f3808e
PB
1564 TCGv reg;
1565 TCGv tmp;
1566 TCGv src;
e6e5906b
PB
1567 int sign;
1568
1569 sign = (insn & 0x100) != 0;
1570 reg = DREG(insn, 9);
a7812ae4 1571 tmp = tcg_temp_new();
e6e5906b 1572 if (sign)
e1f3808e 1573 tcg_gen_ext16s_i32(tmp, reg);
e6e5906b 1574 else
e1f3808e 1575 tcg_gen_ext16u_i32(tmp, reg);
d4d79bb1 1576 SRC_EA(env, src, OS_WORD, sign, NULL);
e1f3808e
PB
1577 tcg_gen_mul_i32(tmp, tmp, src);
1578 tcg_gen_mov_i32(reg, tmp);
4a18cd44 1579 gen_logic_cc(s, tmp, OS_LONG);
2b5e2170 1580 tcg_temp_free(tmp);
e6e5906b
PB
1581}
1582
1583DISAS_INSN(divw)
1584{
e6e5906b 1585 int sign;
0ccb9c1d
LV
1586 TCGv src;
1587 TCGv destr;
1588
1589 /* divX.w <EA>,Dn 32/16 -> 16r:16q */
e6e5906b
PB
1590
1591 sign = (insn & 0x100) != 0;
0ccb9c1d
LV
1592
1593 /* dest.l / src.w */
1594
d4d79bb1 1595 SRC_EA(env, src, OS_WORD, sign, NULL);
0ccb9c1d 1596 destr = tcg_const_i32(REG(insn, 9));
e6e5906b 1597 if (sign) {
0ccb9c1d 1598 gen_helper_divsw(cpu_env, destr, src);
e6e5906b 1599 } else {
0ccb9c1d 1600 gen_helper_divuw(cpu_env, destr, src);
e6e5906b 1601 }
0ccb9c1d 1602 tcg_temp_free(destr);
620c6cf6 1603
9fdb533f 1604 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1605}
1606
1607DISAS_INSN(divl)
1608{
0ccb9c1d
LV
1609 TCGv num, reg, den;
1610 int sign;
e6e5906b
PB
1611 uint16_t ext;
1612
28b68cd7 1613 ext = read_im16(env, s);
0ccb9c1d
LV
1614
1615 sign = (ext & 0x0800) != 0;
1616
1617 if (ext & 0x400) {
1618 if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
1619 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
1620 return;
1621 }
1622
1623 /* divX.l <EA>, Dr:Dq 64/32 -> 32r:32q */
1624
1625 SRC_EA(env, den, OS_LONG, 0, NULL);
1626 num = tcg_const_i32(REG(ext, 12));
1627 reg = tcg_const_i32(REG(ext, 0));
1628 if (sign) {
1629 gen_helper_divsll(cpu_env, num, reg, den);
1630 } else {
1631 gen_helper_divull(cpu_env, num, reg, den);
1632 }
1633 tcg_temp_free(reg);
1634 tcg_temp_free(num);
1635 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1636 return;
1637 }
0ccb9c1d
LV
1638
1639 /* divX.l <EA>, Dq 32/32 -> 32q */
1640 /* divXl.l <EA>, Dr:Dq 32/32 -> 32r:32q */
1641
d4d79bb1 1642 SRC_EA(env, den, OS_LONG, 0, NULL);
0ccb9c1d
LV
1643 num = tcg_const_i32(REG(ext, 12));
1644 reg = tcg_const_i32(REG(ext, 0));
1645 if (sign) {
1646 gen_helper_divsl(cpu_env, num, reg, den);
e6e5906b 1647 } else {
0ccb9c1d 1648 gen_helper_divul(cpu_env, num, reg, den);
e6e5906b 1649 }
0ccb9c1d
LV
1650 tcg_temp_free(reg);
1651 tcg_temp_free(num);
1652
9fdb533f 1653 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
1654}
1655
fb5543d8
LV
1656static void bcd_add(TCGv dest, TCGv src)
1657{
1658 TCGv t0, t1;
1659
1660 /* dest10 = dest10 + src10 + X
1661 *
1662 * t1 = src
1663 * t2 = t1 + 0x066
1664 * t3 = t2 + dest + X
1665 * t4 = t2 ^ dest
1666 * t5 = t3 ^ t4
1667 * t6 = ~t5 & 0x110
1668 * t7 = (t6 >> 2) | (t6 >> 3)
1669 * return t3 - t7
1670 */
1671
1672 /* t1 = (src + 0x066) + dest + X
1673 * = result with some possible exceding 0x6
1674 */
1675
1676 t0 = tcg_const_i32(0x066);
1677 tcg_gen_add_i32(t0, t0, src);
1678
1679 t1 = tcg_temp_new();
1680 tcg_gen_add_i32(t1, t0, dest);
1681 tcg_gen_add_i32(t1, t1, QREG_CC_X);
1682
1683 /* we will remove exceding 0x6 where there is no carry */
1684
1685 /* t0 = (src + 0x0066) ^ dest
1686 * = t1 without carries
1687 */
1688
1689 tcg_gen_xor_i32(t0, t0, dest);
1690
1691 /* extract the carries
1692 * t0 = t0 ^ t1
1693 * = only the carries
1694 */
1695
1696 tcg_gen_xor_i32(t0, t0, t1);
1697
1698 /* generate 0x1 where there is no carry
1699 * and for each 0x10, generate a 0x6
1700 */
1701
1702 tcg_gen_shri_i32(t0, t0, 3);
1703 tcg_gen_not_i32(t0, t0);
1704 tcg_gen_andi_i32(t0, t0, 0x22);
1705 tcg_gen_add_i32(dest, t0, t0);
1706 tcg_gen_add_i32(dest, dest, t0);
1707 tcg_temp_free(t0);
1708
1709 /* remove the exceding 0x6
1710 * for digits that have not generated a carry
1711 */
1712
1713 tcg_gen_sub_i32(dest, t1, dest);
1714 tcg_temp_free(t1);
1715}
1716
1717static void bcd_sub(TCGv dest, TCGv src)
1718{
1719 TCGv t0, t1, t2;
1720
1721 /* dest10 = dest10 - src10 - X
1722 * = bcd_add(dest + 1 - X, 0x199 - src)
1723 */
1724
1725 /* t0 = 0x066 + (0x199 - src) */
1726
1727 t0 = tcg_temp_new();
1728 tcg_gen_subfi_i32(t0, 0x1ff, src);
1729
1730 /* t1 = t0 + dest + 1 - X*/
1731
1732 t1 = tcg_temp_new();
1733 tcg_gen_add_i32(t1, t0, dest);
1734 tcg_gen_addi_i32(t1, t1, 1);
1735 tcg_gen_sub_i32(t1, t1, QREG_CC_X);
1736
1737 /* t2 = t0 ^ dest */
1738
1739 t2 = tcg_temp_new();
1740 tcg_gen_xor_i32(t2, t0, dest);
1741
1742 /* t0 = t1 ^ t2 */
1743
1744 tcg_gen_xor_i32(t0, t1, t2);
1745
1746 /* t2 = ~t0 & 0x110
1747 * t0 = (t2 >> 2) | (t2 >> 3)
1748 *
1749 * to fit on 8bit operands, changed in:
1750 *
1751 * t2 = ~(t0 >> 3) & 0x22
1752 * t0 = t2 + t2
1753 * t0 = t0 + t2
1754 */
1755
1756 tcg_gen_shri_i32(t2, t0, 3);
1757 tcg_gen_not_i32(t2, t2);
1758 tcg_gen_andi_i32(t2, t2, 0x22);
1759 tcg_gen_add_i32(t0, t2, t2);
1760 tcg_gen_add_i32(t0, t0, t2);
1761 tcg_temp_free(t2);
1762
1763 /* return t1 - t0 */
1764
1765 tcg_gen_sub_i32(dest, t1, t0);
1766 tcg_temp_free(t0);
1767 tcg_temp_free(t1);
1768}
1769
1770static void bcd_flags(TCGv val)
1771{
1772 tcg_gen_andi_i32(QREG_CC_C, val, 0x0ff);
1773 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_C);
1774
0d9acef2 1775 tcg_gen_extract_i32(QREG_CC_C, val, 8, 1);
fb5543d8
LV
1776
1777 tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
1778}
1779
1780DISAS_INSN(abcd_reg)
1781{
1782 TCGv src;
1783 TCGv dest;
1784
1785 gen_flush_flags(s); /* !Z is sticky */
1786
3f215a14
LV
1787 src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
1788 dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
fb5543d8
LV
1789 bcd_add(dest, src);
1790 gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1791
1792 bcd_flags(dest);
1793}
1794
1795DISAS_INSN(abcd_mem)
1796{
1797 TCGv src, dest, addr;
1798
1799 gen_flush_flags(s); /* !Z is sticky */
1800
1801 /* Indirect pre-decrement load (mode 4) */
1802
1803 src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
54e1e0b5 1804 NULL_QREG, NULL, EA_LOADU, IS_USER(s));
fb5543d8 1805 dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
54e1e0b5 1806 NULL_QREG, &addr, EA_LOADU, IS_USER(s));
fb5543d8
LV
1807
1808 bcd_add(dest, src);
1809
54e1e0b5
LV
1810 gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr,
1811 EA_STORE, IS_USER(s));
fb5543d8
LV
1812
1813 bcd_flags(dest);
1814}
1815
1816DISAS_INSN(sbcd_reg)
1817{
1818 TCGv src, dest;
1819
1820 gen_flush_flags(s); /* !Z is sticky */
1821
3f215a14
LV
1822 src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
1823 dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
fb5543d8
LV
1824
1825 bcd_sub(dest, src);
1826
1827 gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1828
1829 bcd_flags(dest);
1830}
1831
1832DISAS_INSN(sbcd_mem)
1833{
1834 TCGv src, dest, addr;
1835
1836 gen_flush_flags(s); /* !Z is sticky */
1837
1838 /* Indirect pre-decrement load (mode 4) */
1839
1840 src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
54e1e0b5 1841 NULL_QREG, NULL, EA_LOADU, IS_USER(s));
fb5543d8 1842 dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
54e1e0b5 1843 NULL_QREG, &addr, EA_LOADU, IS_USER(s));
fb5543d8
LV
1844
1845 bcd_sub(dest, src);
1846
54e1e0b5
LV
1847 gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr,
1848 EA_STORE, IS_USER(s));
fb5543d8
LV
1849
1850 bcd_flags(dest);
1851}
1852
1853DISAS_INSN(nbcd)
1854{
1855 TCGv src, dest;
1856 TCGv addr;
1857
1858 gen_flush_flags(s); /* !Z is sticky */
1859
1860 SRC_EA(env, src, OS_BYTE, 0, &addr);
1861
1862 dest = tcg_const_i32(0);
1863 bcd_sub(dest, src);
1864
1865 DEST_EA(env, insn, OS_BYTE, dest, &addr);
1866
1867 bcd_flags(dest);
1868
1869 tcg_temp_free(dest);
1870}
1871
e6e5906b
PB
1872DISAS_INSN(addsub)
1873{
e1f3808e
PB
1874 TCGv reg;
1875 TCGv dest;
1876 TCGv src;
1877 TCGv tmp;
1878 TCGv addr;
e6e5906b 1879 int add;
8a370c6c 1880 int opsize;
e6e5906b
PB
1881
1882 add = (insn & 0x4000) != 0;
8a370c6c 1883 opsize = insn_opsize(insn);
3f215a14 1884 reg = gen_extend(s, DREG(insn, 9), opsize, 1);
a7812ae4 1885 dest = tcg_temp_new();
e6e5906b 1886 if (insn & 0x100) {
8a370c6c 1887 SRC_EA(env, tmp, opsize, 1, &addr);
e6e5906b
PB
1888 src = reg;
1889 } else {
1890 tmp = reg;
8a370c6c 1891 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b
PB
1892 }
1893 if (add) {
e1f3808e 1894 tcg_gen_add_i32(dest, tmp, src);
f9083519 1895 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src);
8a370c6c 1896 set_cc_op(s, CC_OP_ADDB + opsize);
e6e5906b 1897 } else {
f9083519 1898 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src);
e1f3808e 1899 tcg_gen_sub_i32(dest, tmp, src);
8a370c6c 1900 set_cc_op(s, CC_OP_SUBB + opsize);
e6e5906b 1901 }
8a370c6c 1902 gen_update_cc_add(dest, src, opsize);
e6e5906b 1903 if (insn & 0x100) {
8a370c6c 1904 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 1905 } else {
8a370c6c 1906 gen_partset_reg(opsize, DREG(insn, 9), dest);
e6e5906b 1907 }
8a370c6c 1908 tcg_temp_free(dest);
e6e5906b
PB
1909}
1910
e6e5906b
PB
1911/* Reverse the order of the bits in REG. */
1912DISAS_INSN(bitrev)
1913{
e1f3808e 1914 TCGv reg;
e6e5906b 1915 reg = DREG(insn, 0);
e1f3808e 1916 gen_helper_bitrev(reg, reg);
e6e5906b
PB
1917}
1918
1919DISAS_INSN(bitop_reg)
1920{
1921 int opsize;
1922 int op;
e1f3808e
PB
1923 TCGv src1;
1924 TCGv src2;
1925 TCGv tmp;
1926 TCGv addr;
1927 TCGv dest;
e6e5906b
PB
1928
1929 if ((insn & 0x38) != 0)
1930 opsize = OS_BYTE;
1931 else
1932 opsize = OS_LONG;
1933 op = (insn >> 6) & 3;
d4d79bb1 1934 SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
e6e5906b 1935
3c980d2e
LV
1936 gen_flush_flags(s);
1937 src2 = tcg_temp_new();
e6e5906b 1938 if (opsize == OS_BYTE)
3c980d2e 1939 tcg_gen_andi_i32(src2, DREG(insn, 9), 7);
e6e5906b 1940 else
3c980d2e 1941 tcg_gen_andi_i32(src2, DREG(insn, 9), 31);
620c6cf6 1942
3c980d2e
LV
1943 tmp = tcg_const_i32(1);
1944 tcg_gen_shl_i32(tmp, tmp, src2);
1945 tcg_temp_free(src2);
620c6cf6 1946
3c980d2e 1947 tcg_gen_and_i32(QREG_CC_Z, src1, tmp);
620c6cf6 1948
3c980d2e 1949 dest = tcg_temp_new();
e6e5906b
PB
1950 switch (op) {
1951 case 1: /* bchg */
3c980d2e 1952 tcg_gen_xor_i32(dest, src1, tmp);
e6e5906b
PB
1953 break;
1954 case 2: /* bclr */
3c980d2e 1955 tcg_gen_andc_i32(dest, src1, tmp);
e6e5906b
PB
1956 break;
1957 case 3: /* bset */
3c980d2e 1958 tcg_gen_or_i32(dest, src1, tmp);
e6e5906b
PB
1959 break;
1960 default: /* btst */
1961 break;
1962 }
3c980d2e 1963 tcg_temp_free(tmp);
620c6cf6 1964 if (op) {
d4d79bb1 1965 DEST_EA(env, insn, opsize, dest, &addr);
620c6cf6
RH
1966 }
1967 tcg_temp_free(dest);
e6e5906b
PB
1968}
1969
1970DISAS_INSN(sats)
1971{
e1f3808e 1972 TCGv reg;
e6e5906b 1973 reg = DREG(insn, 0);
e6e5906b 1974 gen_flush_flags(s);
620c6cf6 1975 gen_helper_sats(reg, reg, QREG_CC_V);
5dbb6784 1976 gen_logic_cc(s, reg, OS_LONG);
e6e5906b
PB
1977}
1978
e1f3808e 1979static void gen_push(DisasContext *s, TCGv val)
e6e5906b 1980{
e1f3808e 1981 TCGv tmp;
e6e5906b 1982
a7812ae4 1983 tmp = tcg_temp_new();
e1f3808e 1984 tcg_gen_subi_i32(tmp, QREG_SP, 4);
54e1e0b5 1985 gen_store(s, OS_LONG, tmp, val, IS_USER(s));
e1f3808e 1986 tcg_gen_mov_i32(QREG_SP, tmp);
2b5e2170 1987 tcg_temp_free(tmp);
e6e5906b
PB
1988}
1989
7b542eb9
LV
1990static TCGv mreg(int reg)
1991{
1992 if (reg < 8) {
1993 /* Dx */
1994 return cpu_dregs[reg];
1995 }
1996 /* Ax */
1997 return cpu_aregs[reg & 7];
1998}
1999
e6e5906b
PB
2000DISAS_INSN(movem)
2001{
7b542eb9
LV
2002 TCGv addr, incr, tmp, r[16];
2003 int is_load = (insn & 0x0400) != 0;
2004 int opsize = (insn & 0x40) != 0 ? OS_LONG : OS_WORD;
2005 uint16_t mask = read_im16(env, s);
2006 int mode = extract32(insn, 3, 3);
2007 int reg0 = REG(insn, 0);
e6e5906b 2008 int i;
e6e5906b 2009
7b542eb9
LV
2010 tmp = cpu_aregs[reg0];
2011
2012 switch (mode) {
2013 case 0: /* data register direct */
2014 case 1: /* addr register direct */
2015 do_addr_fault:
510ff0b7
PB
2016 gen_addr_fault(s);
2017 return;
7b542eb9
LV
2018
2019 case 2: /* indirect */
2020 break;
2021
2022 case 3: /* indirect post-increment */
2023 if (!is_load) {
2024 /* post-increment is not allowed */
2025 goto do_addr_fault;
2026 }
2027 break;
2028
2029 case 4: /* indirect pre-decrement */
2030 if (is_load) {
2031 /* pre-decrement is not allowed */
2032 goto do_addr_fault;
2033 }
2034 /* We want a bare copy of the address reg, without any pre-decrement
2035 adjustment, as gen_lea would provide. */
2036 break;
2037
2038 default:
2039 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
2040 if (IS_NULL_QREG(tmp)) {
2041 goto do_addr_fault;
2042 }
2043 break;
510ff0b7 2044 }
7b542eb9 2045
a7812ae4 2046 addr = tcg_temp_new();
e1f3808e 2047 tcg_gen_mov_i32(addr, tmp);
7b542eb9
LV
2048 incr = tcg_const_i32(opsize_bytes(opsize));
2049
2050 if (is_load) {
2051 /* memory to register */
2052 for (i = 0; i < 16; i++) {
2053 if (mask & (1 << i)) {
54e1e0b5 2054 r[i] = gen_load(s, opsize, addr, 1, IS_USER(s));
7b542eb9
LV
2055 tcg_gen_add_i32(addr, addr, incr);
2056 }
2057 }
2058 for (i = 0; i < 16; i++) {
2059 if (mask & (1 << i)) {
2060 tcg_gen_mov_i32(mreg(i), r[i]);
2061 tcg_temp_free(r[i]);
2062 }
2063 }
2064 if (mode == 3) {
2065 /* post-increment: movem (An)+,X */
2066 tcg_gen_mov_i32(cpu_aregs[reg0], addr);
2067 }
2068 } else {
2069 /* register to memory */
2070 if (mode == 4) {
2071 /* pre-decrement: movem X,-(An) */
2072 for (i = 15; i >= 0; i--) {
2073 if ((mask << i) & 0x8000) {
2074 tcg_gen_sub_i32(addr, addr, incr);
2075 if (reg0 + 8 == i &&
2076 m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) {
2077 /* M68020+: if the addressing register is the
2078 * register moved to memory, the value written
2079 * is the initial value decremented by the size of
2080 * the operation, regardless of how many actual
2081 * stores have been performed until this point.
2082 * M68000/M68010: the value is the initial value.
2083 */
2084 tmp = tcg_temp_new();
2085 tcg_gen_sub_i32(tmp, cpu_aregs[reg0], incr);
54e1e0b5 2086 gen_store(s, opsize, addr, tmp, IS_USER(s));
7b542eb9
LV
2087 tcg_temp_free(tmp);
2088 } else {
54e1e0b5 2089 gen_store(s, opsize, addr, mreg(i), IS_USER(s));
7b542eb9
LV
2090 }
2091 }
2092 }
2093 tcg_gen_mov_i32(cpu_aregs[reg0], addr);
2094 } else {
2095 for (i = 0; i < 16; i++) {
2096 if (mask & (1 << i)) {
54e1e0b5 2097 gen_store(s, opsize, addr, mreg(i), IS_USER(s));
7b542eb9
LV
2098 tcg_gen_add_i32(addr, addr, incr);
2099 }
e6e5906b 2100 }
e6e5906b
PB
2101 }
2102 }
7b542eb9
LV
2103
2104 tcg_temp_free(incr);
2105 tcg_temp_free(addr);
e6e5906b
PB
2106}
2107
1226e212
PD
2108DISAS_INSN(movep)
2109{
2110 uint8_t i;
2111 int16_t displ;
2112 TCGv reg;
2113 TCGv addr;
2114 TCGv abuf;
2115 TCGv dbuf;
2116
2117 displ = read_im16(env, s);
2118
2119 addr = AREG(insn, 0);
2120 reg = DREG(insn, 9);
2121
2122 abuf = tcg_temp_new();
2123 tcg_gen_addi_i32(abuf, addr, displ);
2124 dbuf = tcg_temp_new();
2125
2126 if (insn & 0x40) {
2127 i = 4;
2128 } else {
2129 i = 2;
2130 }
2131
2132 if (insn & 0x80) {
2133 for ( ; i > 0 ; i--) {
2134 tcg_gen_shri_i32(dbuf, reg, (i - 1) * 8);
2135 tcg_gen_qemu_st8(dbuf, abuf, IS_USER(s));
2136 if (i > 1) {
2137 tcg_gen_addi_i32(abuf, abuf, 2);
2138 }
2139 }
2140 } else {
2141 for ( ; i > 0 ; i--) {
2142 tcg_gen_qemu_ld8u(dbuf, abuf, IS_USER(s));
2143 tcg_gen_deposit_i32(reg, reg, dbuf, (i - 1) * 8, 8);
2144 if (i > 1) {
2145 tcg_gen_addi_i32(abuf, abuf, 2);
2146 }
2147 }
2148 }
2149 tcg_temp_free(abuf);
2150 tcg_temp_free(dbuf);
2151}
2152
e6e5906b
PB
2153DISAS_INSN(bitop_im)
2154{
2155 int opsize;
2156 int op;
e1f3808e 2157 TCGv src1;
e6e5906b
PB
2158 uint32_t mask;
2159 int bitnum;
e1f3808e
PB
2160 TCGv tmp;
2161 TCGv addr;
e6e5906b
PB
2162
2163 if ((insn & 0x38) != 0)
2164 opsize = OS_BYTE;
2165 else
2166 opsize = OS_LONG;
2167 op = (insn >> 6) & 3;
2168
28b68cd7 2169 bitnum = read_im16(env, s);
fe53c2be
LV
2170 if (m68k_feature(s->env, M68K_FEATURE_M68000)) {
2171 if (bitnum & 0xfe00) {
2172 disas_undef(env, s, insn);
2173 return;
2174 }
2175 } else {
2176 if (bitnum & 0xff00) {
2177 disas_undef(env, s, insn);
2178 return;
2179 }
e6e5906b
PB
2180 }
2181
d4d79bb1 2182 SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
e6e5906b 2183
3c980d2e 2184 gen_flush_flags(s);
e6e5906b
PB
2185 if (opsize == OS_BYTE)
2186 bitnum &= 7;
2187 else
2188 bitnum &= 31;
2189 mask = 1 << bitnum;
2190
3c980d2e 2191 tcg_gen_andi_i32(QREG_CC_Z, src1, mask);
620c6cf6 2192
e1f3808e 2193 if (op) {
620c6cf6 2194 tmp = tcg_temp_new();
e1f3808e
PB
2195 switch (op) {
2196 case 1: /* bchg */
2197 tcg_gen_xori_i32(tmp, src1, mask);
2198 break;
2199 case 2: /* bclr */
2200 tcg_gen_andi_i32(tmp, src1, ~mask);
2201 break;
2202 case 3: /* bset */
2203 tcg_gen_ori_i32(tmp, src1, mask);
2204 break;
2205 default: /* btst */
2206 break;
2207 }
d4d79bb1 2208 DEST_EA(env, insn, opsize, tmp, &addr);
620c6cf6 2209 tcg_temp_free(tmp);
e6e5906b 2210 }
e6e5906b 2211}
620c6cf6 2212
01490ea8
LV
2213static TCGv gen_get_ccr(DisasContext *s)
2214{
2215 TCGv dest;
2216
2217 update_cc_op(s);
2218 dest = tcg_temp_new();
2219 gen_helper_get_ccr(dest, cpu_env);
2220 return dest;
2221}
2222
2223static TCGv gen_get_sr(DisasContext *s)
2224{
2225 TCGv ccr;
2226 TCGv sr;
2227
2228 ccr = gen_get_ccr(s);
2229 sr = tcg_temp_new();
2230 tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
2231 tcg_gen_or_i32(sr, sr, ccr);
2232 return sr;
2233}
2234
2235static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
2236{
2237 if (ccr_only) {
2238 tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0);
2239 tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0);
2240 tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1);
2241 tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0);
2242 tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0);
2243 } else {
b6a21d8d
LV
2244 TCGv sr = tcg_const_i32(val);
2245 gen_helper_set_sr(cpu_env, sr);
2246 tcg_temp_free(sr);
01490ea8
LV
2247 }
2248 set_cc_op(s, CC_OP_FLAGS);
2249}
2250
b6a21d8d 2251static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only)
01490ea8 2252{
b6a21d8d
LV
2253 if (ccr_only) {
2254 gen_helper_set_ccr(cpu_env, val);
2255 } else {
2256 gen_helper_set_sr(cpu_env, val);
2257 }
2258 set_cc_op(s, CC_OP_FLAGS);
2259}
2260
2261static void gen_move_to_sr(CPUM68KState *env, DisasContext *s, uint16_t insn,
2262 bool ccr_only)
2263{
2264 if ((insn & 0x3f) == 0x3c) {
01490ea8
LV
2265 uint16_t val;
2266 val = read_im16(env, s);
2267 gen_set_sr_im(s, val, ccr_only);
2268 } else {
b6a21d8d
LV
2269 TCGv src;
2270 SRC_EA(env, src, OS_WORD, 0, NULL);
2271 gen_set_sr(s, src, ccr_only);
01490ea8
LV
2272 }
2273}
2274
e6e5906b
PB
2275DISAS_INSN(arith_im)
2276{
2277 int op;
92c62548 2278 TCGv im;
e1f3808e
PB
2279 TCGv src1;
2280 TCGv dest;
2281 TCGv addr;
92c62548 2282 int opsize;
b5ae1edc 2283 bool with_SR = ((insn & 0x3f) == 0x3c);
e6e5906b
PB
2284
2285 op = (insn >> 9) & 7;
92c62548
LV
2286 opsize = insn_opsize(insn);
2287 switch (opsize) {
2288 case OS_BYTE:
2289 im = tcg_const_i32((int8_t)read_im8(env, s));
2290 break;
2291 case OS_WORD:
2292 im = tcg_const_i32((int16_t)read_im16(env, s));
2293 break;
2294 case OS_LONG:
2295 im = tcg_const_i32(read_im32(env, s));
2296 break;
2297 default:
5cbc6111 2298 g_assert_not_reached();
92c62548 2299 }
b5ae1edc
LV
2300
2301 if (with_SR) {
2302 /* SR/CCR can only be used with andi/eori/ori */
2303 if (op == 2 || op == 3 || op == 6) {
2304 disas_undef(env, s, insn);
2305 return;
2306 }
2307 switch (opsize) {
2308 case OS_BYTE:
2309 src1 = gen_get_ccr(s);
2310 break;
2311 case OS_WORD:
2312 if (IS_USER(s)) {
2313 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
2314 return;
2315 }
2316 src1 = gen_get_sr(s);
2317 break;
5cbc6111
RH
2318 default:
2319 /* OS_LONG; others already g_assert_not_reached. */
b5ae1edc
LV
2320 disas_undef(env, s, insn);
2321 return;
2322 }
2323 } else {
2324 SRC_EA(env, src1, opsize, 1, (op == 6) ? NULL : &addr);
2325 }
a7812ae4 2326 dest = tcg_temp_new();
e6e5906b
PB
2327 switch (op) {
2328 case 0: /* ori */
92c62548 2329 tcg_gen_or_i32(dest, src1, im);
b5ae1edc
LV
2330 if (with_SR) {
2331 gen_set_sr(s, dest, opsize == OS_BYTE);
2332 } else {
2333 DEST_EA(env, insn, opsize, dest, &addr);
2334 gen_logic_cc(s, dest, opsize);
2335 }
e6e5906b
PB
2336 break;
2337 case 1: /* andi */
92c62548 2338 tcg_gen_and_i32(dest, src1, im);
b5ae1edc
LV
2339 if (with_SR) {
2340 gen_set_sr(s, dest, opsize == OS_BYTE);
2341 } else {
2342 DEST_EA(env, insn, opsize, dest, &addr);
2343 gen_logic_cc(s, dest, opsize);
2344 }
e6e5906b
PB
2345 break;
2346 case 2: /* subi */
92c62548
LV
2347 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, src1, im);
2348 tcg_gen_sub_i32(dest, src1, im);
2349 gen_update_cc_add(dest, im, opsize);
2350 set_cc_op(s, CC_OP_SUBB + opsize);
b5ae1edc 2351 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b
PB
2352 break;
2353 case 3: /* addi */
92c62548
LV
2354 tcg_gen_add_i32(dest, src1, im);
2355 gen_update_cc_add(dest, im, opsize);
2356 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, im);
2357 set_cc_op(s, CC_OP_ADDB + opsize);
b5ae1edc 2358 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b
PB
2359 break;
2360 case 5: /* eori */
92c62548 2361 tcg_gen_xor_i32(dest, src1, im);
b5ae1edc
LV
2362 if (with_SR) {
2363 gen_set_sr(s, dest, opsize == OS_BYTE);
2364 } else {
2365 DEST_EA(env, insn, opsize, dest, &addr);
2366 gen_logic_cc(s, dest, opsize);
2367 }
e6e5906b
PB
2368 break;
2369 case 6: /* cmpi */
92c62548 2370 gen_update_cc_cmp(s, src1, im, opsize);
e6e5906b
PB
2371 break;
2372 default:
2373 abort();
2374 }
92c62548 2375 tcg_temp_free(im);
92c62548 2376 tcg_temp_free(dest);
e6e5906b
PB
2377}
2378
14f94406
LV
2379DISAS_INSN(cas)
2380{
2381 int opsize;
2382 TCGv addr;
2383 uint16_t ext;
2384 TCGv load;
2385 TCGv cmp;
2386 TCGMemOp opc;
2387
2388 switch ((insn >> 9) & 3) {
2389 case 1:
2390 opsize = OS_BYTE;
2391 opc = MO_SB;
2392 break;
2393 case 2:
2394 opsize = OS_WORD;
2395 opc = MO_TESW;
2396 break;
2397 case 3:
2398 opsize = OS_LONG;
2399 opc = MO_TESL;
2400 break;
2401 default:
2402 g_assert_not_reached();
2403 }
14f94406
LV
2404
2405 ext = read_im16(env, s);
2406
2407 /* cas Dc,Du,<EA> */
2408
2409 addr = gen_lea(env, s, insn, opsize);
2410 if (IS_NULL_QREG(addr)) {
2411 gen_addr_fault(s);
2412 return;
2413 }
2414
3f215a14 2415 cmp = gen_extend(s, DREG(ext, 0), opsize, 1);
14f94406
LV
2416
2417 /* if <EA> == Dc then
2418 * <EA> = Du
2419 * Dc = <EA> (because <EA> == Dc)
2420 * else
2421 * Dc = <EA>
2422 */
2423
2424 load = tcg_temp_new();
2425 tcg_gen_atomic_cmpxchg_i32(load, addr, cmp, DREG(ext, 6),
2426 IS_USER(s), opc);
2427 /* update flags before setting cmp to load */
2428 gen_update_cc_cmp(s, load, cmp, opsize);
2429 gen_partset_reg(opsize, DREG(ext, 0), load);
2430
2431 tcg_temp_free(load);
308feb93
LV
2432
2433 switch (extract32(insn, 3, 3)) {
2434 case 3: /* Indirect postincrement. */
2435 tcg_gen_addi_i32(AREG(insn, 0), addr, opsize_bytes(opsize));
2436 break;
2437 case 4: /* Indirect predecrememnt. */
2438 tcg_gen_mov_i32(AREG(insn, 0), addr);
2439 break;
2440 }
14f94406
LV
2441}
2442
2443DISAS_INSN(cas2w)
2444{
2445 uint16_t ext1, ext2;
2446 TCGv addr1, addr2;
2447 TCGv regs;
2448
2449 /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
2450
2451 ext1 = read_im16(env, s);
2452
2453 if (ext1 & 0x8000) {
2454 /* Address Register */
2455 addr1 = AREG(ext1, 12);
2456 } else {
2457 /* Data Register */
2458 addr1 = DREG(ext1, 12);
2459 }
2460
2461 ext2 = read_im16(env, s);
2462 if (ext2 & 0x8000) {
2463 /* Address Register */
2464 addr2 = AREG(ext2, 12);
2465 } else {
2466 /* Data Register */
2467 addr2 = DREG(ext2, 12);
2468 }
2469
2470 /* if (R1) == Dc1 && (R2) == Dc2 then
2471 * (R1) = Du1
2472 * (R2) = Du2
2473 * else
2474 * Dc1 = (R1)
2475 * Dc2 = (R2)
2476 */
2477
2478 regs = tcg_const_i32(REG(ext2, 6) |
2479 (REG(ext1, 6) << 3) |
2480 (REG(ext2, 0) << 6) |
2481 (REG(ext1, 0) << 9));
f0ddf11b
EC
2482 if (tb_cflags(s->tb) & CF_PARALLEL) {
2483 gen_helper_exit_atomic(cpu_env);
2484 } else {
2485 gen_helper_cas2w(cpu_env, regs, addr1, addr2);
2486 }
14f94406
LV
2487 tcg_temp_free(regs);
2488
2489 /* Note that cas2w also assigned to env->cc_op. */
2490 s->cc_op = CC_OP_CMPW;
2491 s->cc_op_synced = 1;
2492}
2493
2494DISAS_INSN(cas2l)
2495{
2496 uint16_t ext1, ext2;
2497 TCGv addr1, addr2, regs;
2498
2499 /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
2500
2501 ext1 = read_im16(env, s);
2502
2503 if (ext1 & 0x8000) {
2504 /* Address Register */
2505 addr1 = AREG(ext1, 12);
2506 } else {
2507 /* Data Register */
2508 addr1 = DREG(ext1, 12);
2509 }
2510
2511 ext2 = read_im16(env, s);
2512 if (ext2 & 0x8000) {
2513 /* Address Register */
2514 addr2 = AREG(ext2, 12);
2515 } else {
2516 /* Data Register */
2517 addr2 = DREG(ext2, 12);
2518 }
2519
2520 /* if (R1) == Dc1 && (R2) == Dc2 then
2521 * (R1) = Du1
2522 * (R2) = Du2
2523 * else
2524 * Dc1 = (R1)
2525 * Dc2 = (R2)
2526 */
2527
2528 regs = tcg_const_i32(REG(ext2, 6) |
2529 (REG(ext1, 6) << 3) |
2530 (REG(ext2, 0) << 6) |
2531 (REG(ext1, 0) << 9));
f0ddf11b
EC
2532 if (tb_cflags(s->tb) & CF_PARALLEL) {
2533 gen_helper_cas2l_parallel(cpu_env, regs, addr1, addr2);
2534 } else {
2535 gen_helper_cas2l(cpu_env, regs, addr1, addr2);
2536 }
14f94406
LV
2537 tcg_temp_free(regs);
2538
2539 /* Note that cas2l also assigned to env->cc_op. */
2540 s->cc_op = CC_OP_CMPL;
2541 s->cc_op_synced = 1;
2542}
2543
e6e5906b
PB
2544DISAS_INSN(byterev)
2545{
e1f3808e 2546 TCGv reg;
e6e5906b
PB
2547
2548 reg = DREG(insn, 0);
66896cb8 2549 tcg_gen_bswap32_i32(reg, reg);
e6e5906b
PB
2550}
2551
2552DISAS_INSN(move)
2553{
e1f3808e
PB
2554 TCGv src;
2555 TCGv dest;
e6e5906b
PB
2556 int op;
2557 int opsize;
2558
2559 switch (insn >> 12) {
2560 case 1: /* move.b */
2561 opsize = OS_BYTE;
2562 break;
2563 case 2: /* move.l */
2564 opsize = OS_LONG;
2565 break;
2566 case 3: /* move.w */
2567 opsize = OS_WORD;
2568 break;
2569 default:
2570 abort();
2571 }
d4d79bb1 2572 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b
PB
2573 op = (insn >> 6) & 7;
2574 if (op == 1) {
2575 /* movea */
2576 /* The value will already have been sign extended. */
2577 dest = AREG(insn, 9);
e1f3808e 2578 tcg_gen_mov_i32(dest, src);
e6e5906b
PB
2579 } else {
2580 /* normal move */
2581 uint16_t dest_ea;
2582 dest_ea = ((insn >> 9) & 7) | (op << 3);
d4d79bb1 2583 DEST_EA(env, dest_ea, opsize, src, NULL);
e6e5906b 2584 /* This will be correct because loads sign extend. */
5dbb6784 2585 gen_logic_cc(s, src, opsize);
e6e5906b
PB
2586 }
2587}
2588
2589DISAS_INSN(negx)
2590{
a665a820
RH
2591 TCGv z;
2592 TCGv src;
2593 TCGv addr;
2594 int opsize;
e6e5906b 2595
a665a820
RH
2596 opsize = insn_opsize(insn);
2597 SRC_EA(env, src, opsize, 1, &addr);
2598
2599 gen_flush_flags(s); /* compute old Z */
2600
2601 /* Perform substract with borrow.
2602 * (X, N) = -(src + X);
2603 */
2604
2605 z = tcg_const_i32(0);
2606 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z);
2607 tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X);
2608 tcg_temp_free(z);
2609 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2610
2611 tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
2612
2613 /* Compute signed-overflow for negation. The normal formula for
2614 * subtraction is (res ^ src) & (src ^ dest), but with dest==0
2615 * this simplies to res & src.
2616 */
2617
2618 tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, src);
2619
2620 /* Copy the rest of the results into place. */
2621 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2622 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2623
2624 set_cc_op(s, CC_OP_FLAGS);
2625
2626 /* result is in QREG_CC_N */
2627
2628 DEST_EA(env, insn, opsize, QREG_CC_N, &addr);
e6e5906b
PB
2629}
2630
2631DISAS_INSN(lea)
2632{
e1f3808e
PB
2633 TCGv reg;
2634 TCGv tmp;
e6e5906b
PB
2635
2636 reg = AREG(insn, 9);
d4d79bb1 2637 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 2638 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
2639 gen_addr_fault(s);
2640 return;
2641 }
e1f3808e 2642 tcg_gen_mov_i32(reg, tmp);
e6e5906b
PB
2643}
2644
2645DISAS_INSN(clr)
2646{
2647 int opsize;
2b5e2170
LV
2648 TCGv zero;
2649
2650 zero = tcg_const_i32(0);
e6e5906b 2651
7ef25cdd 2652 opsize = insn_opsize(insn);
2b5e2170
LV
2653 DEST_EA(env, insn, opsize, zero, NULL);
2654 gen_logic_cc(s, zero, opsize);
2655 tcg_temp_free(zero);
e6e5906b
PB
2656}
2657
0633879f
PB
2658DISAS_INSN(move_from_ccr)
2659{
e1f3808e 2660 TCGv ccr;
0633879f
PB
2661
2662 ccr = gen_get_ccr(s);
7c0eb318 2663 DEST_EA(env, insn, OS_WORD, ccr, NULL);
e6e5906b
PB
2664}
2665
2666DISAS_INSN(neg)
2667{
e1f3808e 2668 TCGv src1;
227de713
LV
2669 TCGv dest;
2670 TCGv addr;
2671 int opsize;
e6e5906b 2672
227de713
LV
2673 opsize = insn_opsize(insn);
2674 SRC_EA(env, src1, opsize, 1, &addr);
2675 dest = tcg_temp_new();
2676 tcg_gen_neg_i32(dest, src1);
2677 set_cc_op(s, CC_OP_SUBB + opsize);
2678 gen_update_cc_add(dest, src1, opsize);
2679 tcg_gen_setcondi_i32(TCG_COND_NE, QREG_CC_X, dest, 0);
2680 DEST_EA(env, insn, opsize, dest, &addr);
2681 tcg_temp_free(dest);
e6e5906b
PB
2682}
2683
0633879f
PB
2684DISAS_INSN(move_to_ccr)
2685{
b6a21d8d 2686 gen_move_to_sr(env, s, insn, true);
0633879f
PB
2687}
2688
e6e5906b
PB
2689DISAS_INSN(not)
2690{
ea4f2a84
LV
2691 TCGv src1;
2692 TCGv dest;
2693 TCGv addr;
2694 int opsize;
e6e5906b 2695
ea4f2a84
LV
2696 opsize = insn_opsize(insn);
2697 SRC_EA(env, src1, opsize, 1, &addr);
2698 dest = tcg_temp_new();
2699 tcg_gen_not_i32(dest, src1);
2700 DEST_EA(env, insn, opsize, dest, &addr);
2701 gen_logic_cc(s, dest, opsize);
e6e5906b
PB
2702}
2703
2704DISAS_INSN(swap)
2705{
e1f3808e
PB
2706 TCGv src1;
2707 TCGv src2;
2708 TCGv reg;
e6e5906b 2709
a7812ae4
PB
2710 src1 = tcg_temp_new();
2711 src2 = tcg_temp_new();
e6e5906b 2712 reg = DREG(insn, 0);
e1f3808e
PB
2713 tcg_gen_shli_i32(src1, reg, 16);
2714 tcg_gen_shri_i32(src2, reg, 16);
2715 tcg_gen_or_i32(reg, src1, src2);
2b5e2170
LV
2716 tcg_temp_free(src2);
2717 tcg_temp_free(src1);
5dbb6784 2718 gen_logic_cc(s, reg, OS_LONG);
e6e5906b
PB
2719}
2720
71600eda
LV
2721DISAS_INSN(bkpt)
2722{
16a14cdf 2723 gen_exception(s, s->insn_pc, EXCP_DEBUG);
71600eda
LV
2724}
2725
e6e5906b
PB
2726DISAS_INSN(pea)
2727{
e1f3808e 2728 TCGv tmp;
e6e5906b 2729
d4d79bb1 2730 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 2731 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
2732 gen_addr_fault(s);
2733 return;
2734 }
0633879f 2735 gen_push(s, tmp);
e6e5906b
PB
2736}
2737
2738DISAS_INSN(ext)
2739{
e6e5906b 2740 int op;
e1f3808e
PB
2741 TCGv reg;
2742 TCGv tmp;
e6e5906b
PB
2743
2744 reg = DREG(insn, 0);
2745 op = (insn >> 6) & 7;
a7812ae4 2746 tmp = tcg_temp_new();
e6e5906b 2747 if (op == 3)
e1f3808e 2748 tcg_gen_ext16s_i32(tmp, reg);
e6e5906b 2749 else
e1f3808e 2750 tcg_gen_ext8s_i32(tmp, reg);
e6e5906b
PB
2751 if (op == 2)
2752 gen_partset_reg(OS_WORD, reg, tmp);
2753 else
e1f3808e 2754 tcg_gen_mov_i32(reg, tmp);
5dbb6784 2755 gen_logic_cc(s, tmp, OS_LONG);
2b5e2170 2756 tcg_temp_free(tmp);
e6e5906b
PB
2757}
2758
2759DISAS_INSN(tst)
2760{
2761 int opsize;
e1f3808e 2762 TCGv tmp;
e6e5906b 2763
7ef25cdd 2764 opsize = insn_opsize(insn);
d4d79bb1 2765 SRC_EA(env, tmp, opsize, 1, NULL);
5dbb6784 2766 gen_logic_cc(s, tmp, opsize);
e6e5906b
PB
2767}
2768
2769DISAS_INSN(pulse)
2770{
2771 /* Implemented as a NOP. */
2772}
2773
2774DISAS_INSN(illegal)
2775{
16a14cdf 2776 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
e6e5906b
PB
2777}
2778
2779/* ??? This should be atomic. */
2780DISAS_INSN(tas)
2781{
e1f3808e
PB
2782 TCGv dest;
2783 TCGv src1;
2784 TCGv addr;
e6e5906b 2785
a7812ae4 2786 dest = tcg_temp_new();
d4d79bb1 2787 SRC_EA(env, src1, OS_BYTE, 1, &addr);
5dbb6784 2788 gen_logic_cc(s, src1, OS_BYTE);
e1f3808e 2789 tcg_gen_ori_i32(dest, src1, 0x80);
d4d79bb1 2790 DEST_EA(env, insn, OS_BYTE, dest, &addr);
2b5e2170 2791 tcg_temp_free(dest);
e6e5906b
PB
2792}
2793
2794DISAS_INSN(mull)
2795{
2796 uint16_t ext;
e1f3808e 2797 TCGv src1;
8be95def 2798 int sign;
e6e5906b 2799
28b68cd7 2800 ext = read_im16(env, s);
8be95def
LV
2801
2802 sign = ext & 0x800;
2803
2804 if (ext & 0x400) {
2805 if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
16a14cdf 2806 gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED);
8be95def
LV
2807 return;
2808 }
2809
2810 SRC_EA(env, src1, OS_LONG, 0, NULL);
2811
2812 if (sign) {
2813 tcg_gen_muls2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
2814 } else {
2815 tcg_gen_mulu2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
2816 }
2817 /* if Dl == Dh, 68040 returns low word */
2818 tcg_gen_mov_i32(DREG(ext, 0), QREG_CC_N);
2819 tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_Z);
2820 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N);
2821
2822 tcg_gen_movi_i32(QREG_CC_V, 0);
2823 tcg_gen_movi_i32(QREG_CC_C, 0);
2824
2825 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
2826 return;
2827 }
d4d79bb1 2828 SRC_EA(env, src1, OS_LONG, 0, NULL);
8be95def
LV
2829 if (m68k_feature(s->env, M68K_FEATURE_M68000)) {
2830 tcg_gen_movi_i32(QREG_CC_C, 0);
2831 if (sign) {
2832 tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
2833 /* QREG_CC_V is -(QREG_CC_V != (QREG_CC_N >> 31)) */
2834 tcg_gen_sari_i32(QREG_CC_Z, QREG_CC_N, 31);
2835 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_Z);
2836 } else {
2837 tcg_gen_mulu2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
2838 /* QREG_CC_V is -(QREG_CC_V != 0), use QREG_CC_C as 0 */
2839 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_C);
2840 }
2841 tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V);
2842 tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_N);
2843
2844 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
2845
2846 set_cc_op(s, CC_OP_FLAGS);
2847 } else {
2848 /* The upper 32 bits of the product are discarded, so
2849 muls.l and mulu.l are functionally equivalent. */
2850 tcg_gen_mul_i32(DREG(ext, 12), src1, DREG(ext, 12));
2851 gen_logic_cc(s, DREG(ext, 12), OS_LONG);
2852 }
e6e5906b
PB
2853}
2854
c630e436 2855static void gen_link(DisasContext *s, uint16_t insn, int32_t offset)
e6e5906b 2856{
e1f3808e
PB
2857 TCGv reg;
2858 TCGv tmp;
e6e5906b 2859
e6e5906b 2860 reg = AREG(insn, 0);
a7812ae4 2861 tmp = tcg_temp_new();
e1f3808e 2862 tcg_gen_subi_i32(tmp, QREG_SP, 4);
54e1e0b5 2863 gen_store(s, OS_LONG, tmp, reg, IS_USER(s));
c630e436 2864 if ((insn & 7) != 7) {
e1f3808e 2865 tcg_gen_mov_i32(reg, tmp);
c630e436 2866 }
e1f3808e 2867 tcg_gen_addi_i32(QREG_SP, tmp, offset);
c630e436
LV
2868 tcg_temp_free(tmp);
2869}
2870
2871DISAS_INSN(link)
2872{
2873 int16_t offset;
2874
2875 offset = read_im16(env, s);
2876 gen_link(s, insn, offset);
2877}
2878
2879DISAS_INSN(linkl)
2880{
2881 int32_t offset;
2882
2883 offset = read_im32(env, s);
2884 gen_link(s, insn, offset);
e6e5906b
PB
2885}
2886
2887DISAS_INSN(unlk)
2888{
e1f3808e
PB
2889 TCGv src;
2890 TCGv reg;
2891 TCGv tmp;
e6e5906b 2892
a7812ae4 2893 src = tcg_temp_new();
e6e5906b 2894 reg = AREG(insn, 0);
e1f3808e 2895 tcg_gen_mov_i32(src, reg);
54e1e0b5 2896 tmp = gen_load(s, OS_LONG, src, 0, IS_USER(s));
e1f3808e
PB
2897 tcg_gen_mov_i32(reg, tmp);
2898 tcg_gen_addi_i32(QREG_SP, src, 4);
2b5e2170 2899 tcg_temp_free(src);
24989f0e 2900 tcg_temp_free(tmp);
e6e5906b
PB
2901}
2902
0bdb2b3b
LV
2903#if defined(CONFIG_SOFTMMU)
2904DISAS_INSN(reset)
2905{
2906 if (IS_USER(s)) {
2907 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
2908 return;
2909 }
2910
2911 gen_helper_reset(cpu_env);
2912}
2913#endif
2914
e6e5906b
PB
2915DISAS_INSN(nop)
2916{
2917}
2918
18059c9e
LV
2919DISAS_INSN(rtd)
2920{
2921 TCGv tmp;
2922 int16_t offset = read_im16(env, s);
2923
54e1e0b5 2924 tmp = gen_load(s, OS_LONG, QREG_SP, 0, IS_USER(s));
18059c9e
LV
2925 tcg_gen_addi_i32(QREG_SP, QREG_SP, offset + 4);
2926 gen_jmp(s, tmp);
2927}
2928
e6e5906b
PB
2929DISAS_INSN(rts)
2930{
e1f3808e 2931 TCGv tmp;
e6e5906b 2932
54e1e0b5 2933 tmp = gen_load(s, OS_LONG, QREG_SP, 0, IS_USER(s));
e1f3808e 2934 tcg_gen_addi_i32(QREG_SP, QREG_SP, 4);
e6e5906b
PB
2935 gen_jmp(s, tmp);
2936}
2937
2938DISAS_INSN(jump)
2939{
e1f3808e 2940 TCGv tmp;
e6e5906b
PB
2941
2942 /* Load the target address first to ensure correct exception
2943 behavior. */
d4d79bb1 2944 tmp = gen_lea(env, s, insn, OS_LONG);
e1f3808e 2945 if (IS_NULL_QREG(tmp)) {
510ff0b7
PB
2946 gen_addr_fault(s);
2947 return;
2948 }
e6e5906b
PB
2949 if ((insn & 0x40) == 0) {
2950 /* jsr */
351326a6 2951 gen_push(s, tcg_const_i32(s->pc));
e6e5906b
PB
2952 }
2953 gen_jmp(s, tmp);
2954}
2955
2956DISAS_INSN(addsubq)
2957{
8a370c6c 2958 TCGv src;
e1f3808e 2959 TCGv dest;
8a370c6c
LV
2960 TCGv val;
2961 int imm;
e1f3808e 2962 TCGv addr;
8a370c6c 2963 int opsize;
e6e5906b 2964
8a370c6c
LV
2965 if ((insn & 070) == 010) {
2966 /* Operation on address register is always long. */
2967 opsize = OS_LONG;
2968 } else {
2969 opsize = insn_opsize(insn);
2970 }
2971 SRC_EA(env, src, opsize, 1, &addr);
2972 imm = (insn >> 9) & 7;
2973 if (imm == 0) {
2974 imm = 8;
2975 }
2976 val = tcg_const_i32(imm);
a7812ae4 2977 dest = tcg_temp_new();
8a370c6c 2978 tcg_gen_mov_i32(dest, src);
e6e5906b
PB
2979 if ((insn & 0x38) == 0x08) {
2980 /* Don't update condition codes if the destination is an
2981 address register. */
2982 if (insn & 0x0100) {
8a370c6c 2983 tcg_gen_sub_i32(dest, dest, val);
e6e5906b 2984 } else {
8a370c6c 2985 tcg_gen_add_i32(dest, dest, val);
e6e5906b
PB
2986 }
2987 } else {
2988 if (insn & 0x0100) {
8a370c6c
LV
2989 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2990 tcg_gen_sub_i32(dest, dest, val);
2991 set_cc_op(s, CC_OP_SUBB + opsize);
e6e5906b 2992 } else {
8a370c6c
LV
2993 tcg_gen_add_i32(dest, dest, val);
2994 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2995 set_cc_op(s, CC_OP_ADDB + opsize);
e6e5906b 2996 }
8a370c6c 2997 gen_update_cc_add(dest, val, opsize);
e6e5906b 2998 }
2b5e2170 2999 tcg_temp_free(val);
8a370c6c 3000 DEST_EA(env, insn, opsize, dest, &addr);
2b5e2170 3001 tcg_temp_free(dest);
e6e5906b
PB
3002}
3003
3004DISAS_INSN(tpf)
3005{
3006 switch (insn & 7) {
3007 case 2: /* One extension word. */
3008 s->pc += 2;
3009 break;
3010 case 3: /* Two extension words. */
3011 s->pc += 4;
3012 break;
3013 case 4: /* No extension words. */
3014 break;
3015 default:
d4d79bb1 3016 disas_undef(env, s, insn);
e6e5906b
PB
3017 }
3018}
3019
3020DISAS_INSN(branch)
3021{
3022 int32_t offset;
3023 uint32_t base;
3024 int op;
42a268c2 3025 TCGLabel *l1;
3b46e624 3026
e6e5906b
PB
3027 base = s->pc;
3028 op = (insn >> 8) & 0xf;
3029 offset = (int8_t)insn;
3030 if (offset == 0) {
28b68cd7 3031 offset = (int16_t)read_im16(env, s);
e6e5906b 3032 } else if (offset == -1) {
d4d79bb1 3033 offset = read_im32(env, s);
e6e5906b
PB
3034 }
3035 if (op == 1) {
3036 /* bsr */
351326a6 3037 gen_push(s, tcg_const_i32(s->pc));
e6e5906b 3038 }
e6e5906b
PB
3039 if (op > 1) {
3040 /* Bcc */
3041 l1 = gen_new_label();
3042 gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
3043 gen_jmp_tb(s, 1, base + offset);
3044 gen_set_label(l1);
3045 gen_jmp_tb(s, 0, s->pc);
3046 } else {
3047 /* Unconditional branch. */
7cd7b5ca 3048 update_cc_op(s);
e6e5906b
PB
3049 gen_jmp_tb(s, 0, base + offset);
3050 }
3051}
3052
3053DISAS_INSN(moveq)
3054{
2b5e2170
LV
3055 tcg_gen_movi_i32(DREG(insn, 9), (int8_t)insn);
3056 gen_logic_cc(s, DREG(insn, 9), OS_LONG);
e6e5906b
PB
3057}
3058
3059DISAS_INSN(mvzs)
3060{
3061 int opsize;
e1f3808e
PB
3062 TCGv src;
3063 TCGv reg;
e6e5906b
PB
3064
3065 if (insn & 0x40)
3066 opsize = OS_WORD;
3067 else
3068 opsize = OS_BYTE;
d4d79bb1 3069 SRC_EA(env, src, opsize, (insn & 0x80) == 0, NULL);
e6e5906b 3070 reg = DREG(insn, 9);
e1f3808e 3071 tcg_gen_mov_i32(reg, src);
5dbb6784 3072 gen_logic_cc(s, src, opsize);
e6e5906b
PB
3073}
3074
3075DISAS_INSN(or)
3076{
e1f3808e
PB
3077 TCGv reg;
3078 TCGv dest;
3079 TCGv src;
3080 TCGv addr;
020a4659 3081 int opsize;
e6e5906b 3082
020a4659 3083 opsize = insn_opsize(insn);
3f215a14 3084 reg = gen_extend(s, DREG(insn, 9), opsize, 0);
a7812ae4 3085 dest = tcg_temp_new();
e6e5906b 3086 if (insn & 0x100) {
020a4659 3087 SRC_EA(env, src, opsize, 0, &addr);
e1f3808e 3088 tcg_gen_or_i32(dest, src, reg);
020a4659 3089 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 3090 } else {
020a4659 3091 SRC_EA(env, src, opsize, 0, NULL);
e1f3808e 3092 tcg_gen_or_i32(dest, src, reg);
020a4659 3093 gen_partset_reg(opsize, DREG(insn, 9), dest);
e6e5906b 3094 }
020a4659 3095 gen_logic_cc(s, dest, opsize);
2b5e2170 3096 tcg_temp_free(dest);
e6e5906b
PB
3097}
3098
3099DISAS_INSN(suba)
3100{
e1f3808e
PB
3101 TCGv src;
3102 TCGv reg;
e6e5906b 3103
415f4b62 3104 SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
e6e5906b 3105 reg = AREG(insn, 9);
e1f3808e 3106 tcg_gen_sub_i32(reg, reg, src);
e6e5906b
PB
3107}
3108
a665a820 3109static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
e6e5906b 3110{
a665a820
RH
3111 TCGv tmp;
3112
3113 gen_flush_flags(s); /* compute old Z */
3114
3115 /* Perform substract with borrow.
3116 * (X, N) = dest - (src + X);
3117 */
3118
3119 tmp = tcg_const_i32(0);
3120 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, tmp, QREG_CC_X, tmp);
3121 tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, dest, tmp, QREG_CC_N, QREG_CC_X);
3122 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3123 tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
3124
3125 /* Compute signed-overflow for substract. */
3126
3127 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, dest);
3128 tcg_gen_xor_i32(tmp, dest, src);
3129 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, tmp);
3130 tcg_temp_free(tmp);
3131
3132 /* Copy the rest of the results into place. */
3133 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
3134 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
3135
3136 set_cc_op(s, CC_OP_FLAGS);
3137
3138 /* result is in QREG_CC_N */
3139}
3140
3141DISAS_INSN(subx_reg)
3142{
3143 TCGv dest;
e1f3808e 3144 TCGv src;
a665a820 3145 int opsize;
e6e5906b 3146
a665a820
RH
3147 opsize = insn_opsize(insn);
3148
3f215a14
LV
3149 src = gen_extend(s, DREG(insn, 0), opsize, 1);
3150 dest = gen_extend(s, DREG(insn, 9), opsize, 1);
a665a820
RH
3151
3152 gen_subx(s, src, dest, opsize);
3153
3154 gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
3155}
3156
3157DISAS_INSN(subx_mem)
3158{
3159 TCGv src;
3160 TCGv addr_src;
3161 TCGv dest;
3162 TCGv addr_dest;
3163 int opsize;
3164
3165 opsize = insn_opsize(insn);
3166
3167 addr_src = AREG(insn, 0);
355d4d1c 3168 tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
54e1e0b5 3169 src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
a665a820
RH
3170
3171 addr_dest = AREG(insn, 9);
355d4d1c 3172 tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
54e1e0b5 3173 dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
a665a820
RH
3174
3175 gen_subx(s, src, dest, opsize);
3176
54e1e0b5 3177 gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
24989f0e
LV
3178
3179 tcg_temp_free(dest);
3180 tcg_temp_free(src);
e6e5906b
PB
3181}
3182
3183DISAS_INSN(mov3q)
3184{
e1f3808e 3185 TCGv src;
e6e5906b
PB
3186 int val;
3187
3188 val = (insn >> 9) & 7;
3189 if (val == 0)
3190 val = -1;
351326a6 3191 src = tcg_const_i32(val);
5dbb6784 3192 gen_logic_cc(s, src, OS_LONG);
d4d79bb1 3193 DEST_EA(env, insn, OS_LONG, src, NULL);
2b5e2170 3194 tcg_temp_free(src);
e6e5906b
PB
3195}
3196
3197DISAS_INSN(cmp)
3198{
e1f3808e
PB
3199 TCGv src;
3200 TCGv reg;
e6e5906b
PB
3201 int opsize;
3202
5dbb6784 3203 opsize = insn_opsize(insn);
ff99b952 3204 SRC_EA(env, src, opsize, 1, NULL);
3f215a14 3205 reg = gen_extend(s, DREG(insn, 9), opsize, 1);
ff99b952 3206 gen_update_cc_cmp(s, reg, src, opsize);
e6e5906b
PB
3207}
3208
3209DISAS_INSN(cmpa)
3210{
3211 int opsize;
e1f3808e
PB
3212 TCGv src;
3213 TCGv reg;
e6e5906b
PB
3214
3215 if (insn & 0x100) {
3216 opsize = OS_LONG;
3217 } else {
3218 opsize = OS_WORD;
3219 }
d4d79bb1 3220 SRC_EA(env, src, opsize, 1, NULL);
e6e5906b 3221 reg = AREG(insn, 9);
5436c29d 3222 gen_update_cc_cmp(s, reg, src, OS_LONG);
e6e5906b
PB
3223}
3224
817af1c7
LV
3225DISAS_INSN(cmpm)
3226{
3227 int opsize = insn_opsize(insn);
3228 TCGv src, dst;
3229
3230 /* Post-increment load (mode 3) from Ay. */
3231 src = gen_ea_mode(env, s, 3, REG(insn, 0), opsize,
54e1e0b5 3232 NULL_QREG, NULL, EA_LOADS, IS_USER(s));
817af1c7
LV
3233 /* Post-increment load (mode 3) from Ax. */
3234 dst = gen_ea_mode(env, s, 3, REG(insn, 9), opsize,
54e1e0b5 3235 NULL_QREG, NULL, EA_LOADS, IS_USER(s));
817af1c7
LV
3236
3237 gen_update_cc_cmp(s, dst, src, opsize);
3238}
3239
e6e5906b
PB
3240DISAS_INSN(eor)
3241{
e1f3808e 3242 TCGv src;
e1f3808e
PB
3243 TCGv dest;
3244 TCGv addr;
eec37aec 3245 int opsize;
e6e5906b 3246
eec37aec
LV
3247 opsize = insn_opsize(insn);
3248
3249 SRC_EA(env, src, opsize, 0, &addr);
a7812ae4 3250 dest = tcg_temp_new();
eec37aec
LV
3251 tcg_gen_xor_i32(dest, src, DREG(insn, 9));
3252 gen_logic_cc(s, dest, opsize);
3253 DEST_EA(env, insn, opsize, dest, &addr);
2b5e2170 3254 tcg_temp_free(dest);
e6e5906b
PB
3255}
3256
29cf437d
LV
3257static void do_exg(TCGv reg1, TCGv reg2)
3258{
3259 TCGv temp = tcg_temp_new();
3260 tcg_gen_mov_i32(temp, reg1);
3261 tcg_gen_mov_i32(reg1, reg2);
3262 tcg_gen_mov_i32(reg2, temp);
3263 tcg_temp_free(temp);
3264}
3265
c090c97d 3266DISAS_INSN(exg_dd)
29cf437d
LV
3267{
3268 /* exchange Dx and Dy */
3269 do_exg(DREG(insn, 9), DREG(insn, 0));
3270}
3271
c090c97d 3272DISAS_INSN(exg_aa)
29cf437d
LV
3273{
3274 /* exchange Ax and Ay */
3275 do_exg(AREG(insn, 9), AREG(insn, 0));
3276}
3277
3278DISAS_INSN(exg_da)
3279{
3280 /* exchange Dx and Ay */
3281 do_exg(DREG(insn, 9), AREG(insn, 0));
3282}
3283
e6e5906b
PB
3284DISAS_INSN(and)
3285{
e1f3808e
PB
3286 TCGv src;
3287 TCGv reg;
3288 TCGv dest;
3289 TCGv addr;
52dc23c5 3290 int opsize;
e6e5906b 3291
a7812ae4 3292 dest = tcg_temp_new();
52dc23c5
LV
3293
3294 opsize = insn_opsize(insn);
3295 reg = DREG(insn, 9);
e6e5906b 3296 if (insn & 0x100) {
52dc23c5 3297 SRC_EA(env, src, opsize, 0, &addr);
e1f3808e 3298 tcg_gen_and_i32(dest, src, reg);
52dc23c5 3299 DEST_EA(env, insn, opsize, dest, &addr);
e6e5906b 3300 } else {
52dc23c5 3301 SRC_EA(env, src, opsize, 0, NULL);
e1f3808e 3302 tcg_gen_and_i32(dest, src, reg);
52dc23c5 3303 gen_partset_reg(opsize, reg, dest);
e6e5906b 3304 }
52dc23c5 3305 gen_logic_cc(s, dest, opsize);
2b5e2170 3306 tcg_temp_free(dest);
e6e5906b
PB
3307}
3308
3309DISAS_INSN(adda)
3310{
e1f3808e
PB
3311 TCGv src;
3312 TCGv reg;
e6e5906b 3313
415f4b62 3314 SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
e6e5906b 3315 reg = AREG(insn, 9);
e1f3808e 3316 tcg_gen_add_i32(reg, reg, src);
e6e5906b
PB
3317}
3318
a665a820 3319static inline void gen_addx(DisasContext *s, TCGv src, TCGv dest, int opsize)
e6e5906b 3320{
a665a820
RH
3321 TCGv tmp;
3322
3323 gen_flush_flags(s); /* compute old Z */
3324
3325 /* Perform addition with carry.
3326 * (X, N) = src + dest + X;
3327 */
3328
3329 tmp = tcg_const_i32(0);
3330 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_X, tmp, dest, tmp);
3331 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, tmp);
3332 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3333
3334 /* Compute signed-overflow for addition. */
3335
3336 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
3337 tcg_gen_xor_i32(tmp, dest, src);
3338 tcg_gen_andc_i32(QREG_CC_V, QREG_CC_V, tmp);
3339 tcg_temp_free(tmp);
3340
3341 /* Copy the rest of the results into place. */
3342 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
3343 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
3344
3345 set_cc_op(s, CC_OP_FLAGS);
3346
3347 /* result is in QREG_CC_N */
3348}
3349
3350DISAS_INSN(addx_reg)
3351{
3352 TCGv dest;
e1f3808e 3353 TCGv src;
a665a820 3354 int opsize;
e6e5906b 3355
a665a820
RH
3356 opsize = insn_opsize(insn);
3357
3f215a14
LV
3358 dest = gen_extend(s, DREG(insn, 9), opsize, 1);
3359 src = gen_extend(s, DREG(insn, 0), opsize, 1);
a665a820
RH
3360
3361 gen_addx(s, src, dest, opsize);
3362
3363 gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
3364}
3365
3366DISAS_INSN(addx_mem)
3367{
3368 TCGv src;
3369 TCGv addr_src;
3370 TCGv dest;
3371 TCGv addr_dest;
3372 int opsize;
3373
3374 opsize = insn_opsize(insn);
3375
3376 addr_src = AREG(insn, 0);
3377 tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
54e1e0b5 3378 src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
a665a820
RH
3379
3380 addr_dest = AREG(insn, 9);
3381 tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
54e1e0b5 3382 dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
a665a820
RH
3383
3384 gen_addx(s, src, dest, opsize);
3385
54e1e0b5 3386 gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
24989f0e
LV
3387
3388 tcg_temp_free(dest);
3389 tcg_temp_free(src);
e6e5906b
PB
3390}
3391
367790cc 3392static inline void shift_im(DisasContext *s, uint16_t insn, int opsize)
e6e5906b 3393{
367790cc
RH
3394 int count = (insn >> 9) & 7;
3395 int logical = insn & 8;
3396 int left = insn & 0x100;
3397 int bits = opsize_bytes(opsize) * 8;
3f215a14 3398 TCGv reg = gen_extend(s, DREG(insn, 0), opsize, !logical);
367790cc
RH
3399
3400 if (count == 0) {
3401 count = 8;
3402 }
3403
3404 tcg_gen_movi_i32(QREG_CC_V, 0);
3405 if (left) {
3406 tcg_gen_shri_i32(QREG_CC_C, reg, bits - count);
3407 tcg_gen_shli_i32(QREG_CC_N, reg, count);
3408
3409 /* Note that ColdFire always clears V (done above),
3410 while M68000 sets if the most significant bit is changed at
3411 any time during the shift operation */
3412 if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) {
3413 /* if shift count >= bits, V is (reg != 0) */
3414 if (count >= bits) {
3415 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, reg, QREG_CC_V);
3416 } else {
3417 TCGv t0 = tcg_temp_new();
3418 tcg_gen_sari_i32(QREG_CC_V, reg, bits - 1);
3419 tcg_gen_sari_i32(t0, reg, bits - count - 1);
3420 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, t0);
3421 tcg_temp_free(t0);
3422 }
3423 tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V);
3424 }
3425 } else {
3426 tcg_gen_shri_i32(QREG_CC_C, reg, count - 1);
3427 if (logical) {
3428 tcg_gen_shri_i32(QREG_CC_N, reg, count);
3429 } else {
3430 tcg_gen_sari_i32(QREG_CC_N, reg, count);
3431 }
3432 }
3433
3434 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3435 tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3436 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3437 tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
e6e5906b 3438
367790cc 3439 gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N);
620c6cf6 3440 set_cc_op(s, CC_OP_FLAGS);
367790cc 3441}
620c6cf6 3442
367790cc
RH
3443static inline void shift_reg(DisasContext *s, uint16_t insn, int opsize)
3444{
3445 int logical = insn & 8;
3446 int left = insn & 0x100;
3447 int bits = opsize_bytes(opsize) * 8;
3f215a14 3448 TCGv reg = gen_extend(s, DREG(insn, 0), opsize, !logical);
367790cc
RH
3449 TCGv s32;
3450 TCGv_i64 t64, s64;
3451
3452 t64 = tcg_temp_new_i64();
3453 s64 = tcg_temp_new_i64();
3454 s32 = tcg_temp_new();
3455
3456 /* Note that m68k truncates the shift count modulo 64, not 32.
3457 In addition, a 64-bit shift makes it easy to find "the last
3458 bit shifted out", for the carry flag. */
3459 tcg_gen_andi_i32(s32, DREG(insn, 9), 63);
3460 tcg_gen_extu_i32_i64(s64, s32);
3461 tcg_gen_extu_i32_i64(t64, reg);
3462
3463 /* Optimistically set V=0. Also used as a zero source below. */
3464 tcg_gen_movi_i32(QREG_CC_V, 0);
3465 if (left) {
3466 tcg_gen_shl_i64(t64, t64, s64);
3467
3468 if (opsize == OS_LONG) {
3469 tcg_gen_extr_i64_i32(QREG_CC_N, QREG_CC_C, t64);
3470 /* Note that C=0 if shift count is 0, and we get that for free. */
3471 } else {
3472 TCGv zero = tcg_const_i32(0);
3473 tcg_gen_extrl_i64_i32(QREG_CC_N, t64);
3474 tcg_gen_shri_i32(QREG_CC_C, QREG_CC_N, bits);
3475 tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
3476 s32, zero, zero, QREG_CC_C);
3477 tcg_temp_free(zero);
3478 }
3479 tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3480
3481 /* X = C, but only if the shift count was non-zero. */
3482 tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V,
3483 QREG_CC_C, QREG_CC_X);
3484
3485 /* M68000 sets V if the most significant bit is changed at
3486 * any time during the shift operation. Do this via creating
3487 * an extension of the sign bit, comparing, and discarding
3488 * the bits below the sign bit. I.e.
3489 * int64_t s = (intN_t)reg;
3490 * int64_t t = (int64_t)(intN_t)reg << count;
3491 * V = ((s ^ t) & (-1 << (bits - 1))) != 0
3492 */
3493 if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) {
3494 TCGv_i64 tt = tcg_const_i64(32);
3495 /* if shift is greater than 32, use 32 */
3496 tcg_gen_movcond_i64(TCG_COND_GT, s64, s64, tt, tt, s64);
3497 tcg_temp_free_i64(tt);
3498 /* Sign extend the input to 64 bits; re-do the shift. */
3499 tcg_gen_ext_i32_i64(t64, reg);
3500 tcg_gen_shl_i64(s64, t64, s64);
3501 /* Clear all bits that are unchanged. */
3502 tcg_gen_xor_i64(t64, t64, s64);
3503 /* Ignore the bits below the sign bit. */
3504 tcg_gen_andi_i64(t64, t64, -1ULL << (bits - 1));
3505 /* If any bits remain set, we have overflow. */
3506 tcg_gen_setcondi_i64(TCG_COND_NE, t64, t64, 0);
3507 tcg_gen_extrl_i64_i32(QREG_CC_V, t64);
3508 tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V);
3509 }
e6e5906b 3510 } else {
367790cc
RH
3511 tcg_gen_shli_i64(t64, t64, 32);
3512 if (logical) {
3513 tcg_gen_shr_i64(t64, t64, s64);
e6e5906b 3514 } else {
367790cc 3515 tcg_gen_sar_i64(t64, t64, s64);
e6e5906b 3516 }
367790cc
RH
3517 tcg_gen_extr_i64_i32(QREG_CC_C, QREG_CC_N, t64);
3518
3519 /* Note that C=0 if shift count is 0, and we get that for free. */
3520 tcg_gen_shri_i32(QREG_CC_C, QREG_CC_C, 31);
3521
3522 /* X = C, but only if the shift count was non-zero. */
3523 tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V,
3524 QREG_CC_C, QREG_CC_X);
e6e5906b 3525 }
367790cc
RH
3526 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3527 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3528
3529 tcg_temp_free(s32);
3530 tcg_temp_free_i64(s64);
3531 tcg_temp_free_i64(t64);
3532
3533 /* Write back the result. */
3534 gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N);
3535 set_cc_op(s, CC_OP_FLAGS);
3536}
3537
3538DISAS_INSN(shift8_im)
3539{
3540 shift_im(s, insn, OS_BYTE);
3541}
3542
3543DISAS_INSN(shift16_im)
3544{
3545 shift_im(s, insn, OS_WORD);
3546}
3547
3548DISAS_INSN(shift_im)
3549{
3550 shift_im(s, insn, OS_LONG);
3551}
3552
3553DISAS_INSN(shift8_reg)
3554{
3555 shift_reg(s, insn, OS_BYTE);
3556}
3557
3558DISAS_INSN(shift16_reg)
3559{
3560 shift_reg(s, insn, OS_WORD);
e6e5906b
PB
3561}
3562
3563DISAS_INSN(shift_reg)
3564{
367790cc
RH
3565 shift_reg(s, insn, OS_LONG);
3566}
e6e5906b 3567
367790cc
RH
3568DISAS_INSN(shift_mem)
3569{
3570 int logical = insn & 8;
3571 int left = insn & 0x100;
3572 TCGv src;
3573 TCGv addr;
3574
3575 SRC_EA(env, src, OS_WORD, !logical, &addr);
3576 tcg_gen_movi_i32(QREG_CC_V, 0);
3577 if (left) {
3578 tcg_gen_shri_i32(QREG_CC_C, src, 15);
3579 tcg_gen_shli_i32(QREG_CC_N, src, 1);
3580
3581 /* Note that ColdFire always clears V,
3582 while M68000 sets if the most significant bit is changed at
3583 any time during the shift operation */
3584 if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) {
3f215a14 3585 src = gen_extend(s, src, OS_WORD, 1);
367790cc
RH
3586 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
3587 }
e6e5906b 3588 } else {
367790cc
RH
3589 tcg_gen_mov_i32(QREG_CC_C, src);
3590 if (logical) {
3591 tcg_gen_shri_i32(QREG_CC_N, src, 1);
e6e5906b 3592 } else {
367790cc 3593 tcg_gen_sari_i32(QREG_CC_N, src, 1);
e6e5906b
PB
3594 }
3595 }
367790cc
RH
3596
3597 gen_ext(QREG_CC_N, QREG_CC_N, OS_WORD, 1);
3598 tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3599 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3600 tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
3601
3602 DEST_EA(env, insn, OS_WORD, QREG_CC_N, &addr);
620c6cf6 3603 set_cc_op(s, CC_OP_FLAGS);
e6e5906b
PB
3604}
3605
0194cf31
LV
3606static void rotate(TCGv reg, TCGv shift, int left, int size)
3607{
3608 switch (size) {
3609 case 8:
3610 /* Replicate the 8-bit input so that a 32-bit rotate works. */
3611 tcg_gen_ext8u_i32(reg, reg);
3612 tcg_gen_muli_i32(reg, reg, 0x01010101);
3613 goto do_long;
3614 case 16:
3615 /* Replicate the 16-bit input so that a 32-bit rotate works. */
3616 tcg_gen_deposit_i32(reg, reg, reg, 16, 16);
3617 goto do_long;
3618 do_long:
3619 default:
3620 if (left) {
3621 tcg_gen_rotl_i32(reg, reg, shift);
3622 } else {
3623 tcg_gen_rotr_i32(reg, reg, shift);
3624 }
3625 }
3626
3627 /* compute flags */
3628
3629 switch (size) {
3630 case 8:
3631 tcg_gen_ext8s_i32(reg, reg);
3632 break;
3633 case 16:
3634 tcg_gen_ext16s_i32(reg, reg);
3635 break;
3636 default:
3637 break;
3638 }
3639
3640 /* QREG_CC_X is not affected */
3641
3642 tcg_gen_mov_i32(QREG_CC_N, reg);
3643 tcg_gen_mov_i32(QREG_CC_Z, reg);
3644
3645 if (left) {
3646 tcg_gen_andi_i32(QREG_CC_C, reg, 1);
3647 } else {
3648 tcg_gen_shri_i32(QREG_CC_C, reg, 31);
3649 }
3650
3651 tcg_gen_movi_i32(QREG_CC_V, 0); /* always cleared */
3652}
3653
3654static void rotate_x_flags(TCGv reg, TCGv X, int size)
3655{
3656 switch (size) {
3657 case 8:
3658 tcg_gen_ext8s_i32(reg, reg);
3659 break;
3660 case 16:
3661 tcg_gen_ext16s_i32(reg, reg);
3662 break;
3663 default:
3664 break;
3665 }
3666 tcg_gen_mov_i32(QREG_CC_N, reg);
3667 tcg_gen_mov_i32(QREG_CC_Z, reg);
3668 tcg_gen_mov_i32(QREG_CC_X, X);
3669 tcg_gen_mov_i32(QREG_CC_C, X);
3670 tcg_gen_movi_i32(QREG_CC_V, 0);
3671}
3672
3673/* Result of rotate_x() is valid if 0 <= shift <= size */
3674static TCGv rotate_x(TCGv reg, TCGv shift, int left, int size)
3675{
3676 TCGv X, shl, shr, shx, sz, zero;
3677
3678 sz = tcg_const_i32(size);
3679
3680 shr = tcg_temp_new();
3681 shl = tcg_temp_new();
3682 shx = tcg_temp_new();
3683 if (left) {
3684 tcg_gen_mov_i32(shl, shift); /* shl = shift */
3685 tcg_gen_movi_i32(shr, size + 1);
3686 tcg_gen_sub_i32(shr, shr, shift); /* shr = size + 1 - shift */
3687 tcg_gen_subi_i32(shx, shift, 1); /* shx = shift - 1 */
3688 /* shx = shx < 0 ? size : shx; */
3689 zero = tcg_const_i32(0);
3690 tcg_gen_movcond_i32(TCG_COND_LT, shx, shx, zero, sz, shx);
3691 tcg_temp_free(zero);
3692 } else {
3693 tcg_gen_mov_i32(shr, shift); /* shr = shift */
3694 tcg_gen_movi_i32(shl, size + 1);
3695 tcg_gen_sub_i32(shl, shl, shift); /* shl = size + 1 - shift */
3696 tcg_gen_sub_i32(shx, sz, shift); /* shx = size - shift */
3697 }
3698
3699 /* reg = (reg << shl) | (reg >> shr) | (x << shx); */
3700
3701 tcg_gen_shl_i32(shl, reg, shl);
3702 tcg_gen_shr_i32(shr, reg, shr);
3703 tcg_gen_or_i32(reg, shl, shr);
3704 tcg_temp_free(shl);
3705 tcg_temp_free(shr);
3706 tcg_gen_shl_i32(shx, QREG_CC_X, shx);
3707 tcg_gen_or_i32(reg, reg, shx);
3708 tcg_temp_free(shx);
3709
3710 /* X = (reg >> size) & 1 */
3711
3712 X = tcg_temp_new();
3713 tcg_gen_shr_i32(X, reg, sz);
3714 tcg_gen_andi_i32(X, X, 1);
3715 tcg_temp_free(sz);
3716
3717 return X;
3718}
3719
3720/* Result of rotate32_x() is valid if 0 <= shift < 33 */
3721static TCGv rotate32_x(TCGv reg, TCGv shift, int left)
3722{
3723 TCGv_i64 t0, shift64;
3724 TCGv X, lo, hi, zero;
3725
3726 shift64 = tcg_temp_new_i64();
3727 tcg_gen_extu_i32_i64(shift64, shift);
3728
3729 t0 = tcg_temp_new_i64();
3730
3731 X = tcg_temp_new();
3732 lo = tcg_temp_new();
3733 hi = tcg_temp_new();
3734
3735 if (left) {
3736 /* create [reg:X:..] */
3737
3738 tcg_gen_shli_i32(lo, QREG_CC_X, 31);
3739 tcg_gen_concat_i32_i64(t0, lo, reg);
3740
3741 /* rotate */
3742
3743 tcg_gen_rotl_i64(t0, t0, shift64);
3744 tcg_temp_free_i64(shift64);
3745
3746 /* result is [reg:..:reg:X] */
3747
3748 tcg_gen_extr_i64_i32(lo, hi, t0);
3749 tcg_gen_andi_i32(X, lo, 1);
3750
3751 tcg_gen_shri_i32(lo, lo, 1);
3752 } else {
3753 /* create [..:X:reg] */
3754
3755 tcg_gen_concat_i32_i64(t0, reg, QREG_CC_X);
3756
3757 tcg_gen_rotr_i64(t0, t0, shift64);
3758 tcg_temp_free_i64(shift64);
3759
3760 /* result is value: [X:reg:..:reg] */
3761
3762 tcg_gen_extr_i64_i32(lo, hi, t0);
3763
3764 /* extract X */
3765
3766 tcg_gen_shri_i32(X, hi, 31);
3767
3768 /* extract result */
3769
3770 tcg_gen_shli_i32(hi, hi, 1);
3771 }
3772 tcg_temp_free_i64(t0);
3773 tcg_gen_or_i32(lo, lo, hi);
3774 tcg_temp_free(hi);
3775
3776 /* if shift == 0, register and X are not affected */
3777
3778 zero = tcg_const_i32(0);
3779 tcg_gen_movcond_i32(TCG_COND_EQ, X, shift, zero, QREG_CC_X, X);
3780 tcg_gen_movcond_i32(TCG_COND_EQ, reg, shift, zero, reg, lo);
3781 tcg_temp_free(zero);
3782 tcg_temp_free(lo);
3783
3784 return X;
3785}
3786
3787DISAS_INSN(rotate_im)
3788{
3789 TCGv shift;
3790 int tmp;
3791 int left = (insn & 0x100);
3792
3793 tmp = (insn >> 9) & 7;
3794 if (tmp == 0) {
3795 tmp = 8;
3796 }
3797
3798 shift = tcg_const_i32(tmp);
3799 if (insn & 8) {
3800 rotate(DREG(insn, 0), shift, left, 32);
3801 } else {
3802 TCGv X = rotate32_x(DREG(insn, 0), shift, left);
3803 rotate_x_flags(DREG(insn, 0), X, 32);
3804 tcg_temp_free(X);
3805 }
3806 tcg_temp_free(shift);
3807
3808 set_cc_op(s, CC_OP_FLAGS);
3809}
3810
3811DISAS_INSN(rotate8_im)
3812{
3813 int left = (insn & 0x100);
3814 TCGv reg;
3815 TCGv shift;
3816 int tmp;
3817
3f215a14 3818 reg = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
0194cf31
LV
3819
3820 tmp = (insn >> 9) & 7;
3821 if (tmp == 0) {
3822 tmp = 8;
3823 }
3824
3825 shift = tcg_const_i32(tmp);
3826 if (insn & 8) {
3827 rotate(reg, shift, left, 8);
3828 } else {
3829 TCGv X = rotate_x(reg, shift, left, 8);
3830 rotate_x_flags(reg, X, 8);
3831 tcg_temp_free(X);
3832 }
3833 tcg_temp_free(shift);
3834 gen_partset_reg(OS_BYTE, DREG(insn, 0), reg);
3835 set_cc_op(s, CC_OP_FLAGS);
3836}
3837
3838DISAS_INSN(rotate16_im)
3839{
3840 int left = (insn & 0x100);
3841 TCGv reg;
3842 TCGv shift;
3843 int tmp;
3844
3f215a14 3845 reg = gen_extend(s, DREG(insn, 0), OS_WORD, 0);
0194cf31
LV
3846 tmp = (insn >> 9) & 7;
3847 if (tmp == 0) {
3848 tmp = 8;
3849 }
3850
3851 shift = tcg_const_i32(tmp);
3852 if (insn & 8) {
3853 rotate(reg, shift, left, 16);
3854 } else {
3855 TCGv X = rotate_x(reg, shift, left, 16);
3856 rotate_x_flags(reg, X, 16);
3857 tcg_temp_free(X);
3858 }
3859 tcg_temp_free(shift);
3860 gen_partset_reg(OS_WORD, DREG(insn, 0), reg);
3861 set_cc_op(s, CC_OP_FLAGS);
3862}
3863
3864DISAS_INSN(rotate_reg)
3865{
3866 TCGv reg;
3867 TCGv src;
3868 TCGv t0, t1;
3869 int left = (insn & 0x100);
3870
3871 reg = DREG(insn, 0);
3872 src = DREG(insn, 9);
3873 /* shift in [0..63] */
3874 t0 = tcg_temp_new();
3875 tcg_gen_andi_i32(t0, src, 63);
3876 t1 = tcg_temp_new_i32();
3877 if (insn & 8) {
3878 tcg_gen_andi_i32(t1, src, 31);
3879 rotate(reg, t1, left, 32);
3880 /* if shift == 0, clear C */
3881 tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
3882 t0, QREG_CC_V /* 0 */,
3883 QREG_CC_V /* 0 */, QREG_CC_C);
3884 } else {
3885 TCGv X;
3886 /* modulo 33 */
3887 tcg_gen_movi_i32(t1, 33);
3888 tcg_gen_remu_i32(t1, t0, t1);
3889 X = rotate32_x(DREG(insn, 0), t1, left);
3890 rotate_x_flags(DREG(insn, 0), X, 32);
3891 tcg_temp_free(X);
3892 }
3893 tcg_temp_free(t1);
3894 tcg_temp_free(t0);
3895 set_cc_op(s, CC_OP_FLAGS);
3896}
3897
3898DISAS_INSN(rotate8_reg)
3899{
3900 TCGv reg;
3901 TCGv src;
3902 TCGv t0, t1;
3903 int left = (insn & 0x100);
3904
3f215a14 3905 reg = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
0194cf31
LV
3906 src = DREG(insn, 9);
3907 /* shift in [0..63] */
3908 t0 = tcg_temp_new_i32();
3909 tcg_gen_andi_i32(t0, src, 63);
3910 t1 = tcg_temp_new_i32();
3911 if (insn & 8) {
3912 tcg_gen_andi_i32(t1, src, 7);
3913 rotate(reg, t1, left, 8);
3914 /* if shift == 0, clear C */
3915 tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
3916 t0, QREG_CC_V /* 0 */,
3917 QREG_CC_V /* 0 */, QREG_CC_C);
3918 } else {
3919 TCGv X;
3920 /* modulo 9 */
3921 tcg_gen_movi_i32(t1, 9);
3922 tcg_gen_remu_i32(t1, t0, t1);
3923 X = rotate_x(reg, t1, left, 8);
3924 rotate_x_flags(reg, X, 8);
3925 tcg_temp_free(X);
3926 }
3927 tcg_temp_free(t1);
3928 tcg_temp_free(t0);
3929 gen_partset_reg(OS_BYTE, DREG(insn, 0), reg);
3930 set_cc_op(s, CC_OP_FLAGS);
3931}
3932
3933DISAS_INSN(rotate16_reg)
3934{
3935 TCGv reg;
3936 TCGv src;
3937 TCGv t0, t1;
3938 int left = (insn & 0x100);
3939
3f215a14 3940 reg = gen_extend(s, DREG(insn, 0), OS_WORD, 0);
0194cf31
LV
3941 src = DREG(insn, 9);
3942 /* shift in [0..63] */
3943 t0 = tcg_temp_new_i32();
3944 tcg_gen_andi_i32(t0, src, 63);
3945 t1 = tcg_temp_new_i32();
3946 if (insn & 8) {
3947 tcg_gen_andi_i32(t1, src, 15);
3948 rotate(reg, t1, left, 16);
3949 /* if shift == 0, clear C */
3950 tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
3951 t0, QREG_CC_V /* 0 */,
3952 QREG_CC_V /* 0 */, QREG_CC_C);
3953 } else {
3954 TCGv X;
3955 /* modulo 17 */
3956 tcg_gen_movi_i32(t1, 17);
3957 tcg_gen_remu_i32(t1, t0, t1);
3958 X = rotate_x(reg, t1, left, 16);
3959 rotate_x_flags(reg, X, 16);
3960 tcg_temp_free(X);
3961 }
3962 tcg_temp_free(t1);
3963 tcg_temp_free(t0);
3964 gen_partset_reg(OS_WORD, DREG(insn, 0), reg);
3965 set_cc_op(s, CC_OP_FLAGS);
3966}
3967
3968DISAS_INSN(rotate_mem)
3969{
3970 TCGv src;
3971 TCGv addr;
3972 TCGv shift;
3973 int left = (insn & 0x100);
3974
3975 SRC_EA(env, src, OS_WORD, 0, &addr);
3976
3977 shift = tcg_const_i32(1);
3978 if (insn & 0x0200) {
3979 rotate(src, shift, left, 16);
3980 } else {
3981 TCGv X = rotate_x(src, shift, left, 16);
3982 rotate_x_flags(src, X, 16);
3983 tcg_temp_free(X);
3984 }
3985 tcg_temp_free(shift);
3986 DEST_EA(env, insn, OS_WORD, src, &addr);
3987 set_cc_op(s, CC_OP_FLAGS);
3988}
3989
ac815f46
RH
3990DISAS_INSN(bfext_reg)
3991{
3992 int ext = read_im16(env, s);
3993 int is_sign = insn & 0x200;
3994 TCGv src = DREG(insn, 0);
3995 TCGv dst = DREG(ext, 12);
3996 int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
3997 int ofs = extract32(ext, 6, 5); /* big bit-endian */
3998 int pos = 32 - ofs - len; /* little bit-endian */
3999 TCGv tmp = tcg_temp_new();
4000 TCGv shift;
4001
4002 /* In general, we're going to rotate the field so that it's at the
1d349821 4003 top of the word and then right-shift by the complement of the
ac815f46
RH
4004 width to extend the field. */
4005 if (ext & 0x20) {
4006 /* Variable width. */
4007 if (ext & 0x800) {
4008 /* Variable offset. */
4009 tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
4010 tcg_gen_rotl_i32(tmp, src, tmp);
4011 } else {
4012 tcg_gen_rotli_i32(tmp, src, ofs);
4013 }
4014
4015 shift = tcg_temp_new();
4016 tcg_gen_neg_i32(shift, DREG(ext, 0));
4017 tcg_gen_andi_i32(shift, shift, 31);
4018 tcg_gen_sar_i32(QREG_CC_N, tmp, shift);
4019 if (is_sign) {
4020 tcg_gen_mov_i32(dst, QREG_CC_N);
4021 } else {
4022 tcg_gen_shr_i32(dst, tmp, shift);
4023 }
4024 tcg_temp_free(shift);
4025 } else {
4026 /* Immediate width. */
4027 if (ext & 0x800) {
4028 /* Variable offset */
4029 tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
4030 tcg_gen_rotl_i32(tmp, src, tmp);
4031 src = tmp;
4032 pos = 32 - len;
4033 } else {
4034 /* Immediate offset. If the field doesn't wrap around the
4035 end of the word, rely on (s)extract completely. */
4036 if (pos < 0) {
4037 tcg_gen_rotli_i32(tmp, src, ofs);
4038 src = tmp;
4039 pos = 32 - len;
4040 }
4041 }
4042
4043 tcg_gen_sextract_i32(QREG_CC_N, src, pos, len);
4044 if (is_sign) {
4045 tcg_gen_mov_i32(dst, QREG_CC_N);
4046 } else {
4047 tcg_gen_extract_i32(dst, src, pos, len);
4048 }
4049 }
4050
4051 tcg_temp_free(tmp);
4052 set_cc_op(s, CC_OP_LOGIC);
4053}
4054
f2224f2c
RH
4055DISAS_INSN(bfext_mem)
4056{
4057 int ext = read_im16(env, s);
4058 int is_sign = insn & 0x200;
4059 TCGv dest = DREG(ext, 12);
4060 TCGv addr, len, ofs;
4061
4062 addr = gen_lea(env, s, insn, OS_UNSIZED);
4063 if (IS_NULL_QREG(addr)) {
4064 gen_addr_fault(s);
4065 return;
4066 }
4067
4068 if (ext & 0x20) {
4069 len = DREG(ext, 0);
4070 } else {
4071 len = tcg_const_i32(extract32(ext, 0, 5));
4072 }
4073 if (ext & 0x800) {
4074 ofs = DREG(ext, 6);
4075 } else {
4076 ofs = tcg_const_i32(extract32(ext, 6, 5));
4077 }
4078
4079 if (is_sign) {
4080 gen_helper_bfexts_mem(dest, cpu_env, addr, ofs, len);
4081 tcg_gen_mov_i32(QREG_CC_N, dest);
4082 } else {
4083 TCGv_i64 tmp = tcg_temp_new_i64();
4084 gen_helper_bfextu_mem(tmp, cpu_env, addr, ofs, len);
4085 tcg_gen_extr_i64_i32(dest, QREG_CC_N, tmp);
4086 tcg_temp_free_i64(tmp);
4087 }
4088 set_cc_op(s, CC_OP_LOGIC);
4089
4090 if (!(ext & 0x20)) {
4091 tcg_temp_free(len);
4092 }
4093 if (!(ext & 0x800)) {
4094 tcg_temp_free(ofs);
4095 }
4096}
4097
ac815f46
RH
4098DISAS_INSN(bfop_reg)
4099{
4100 int ext = read_im16(env, s);
4101 TCGv src = DREG(insn, 0);
4102 int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
4103 int ofs = extract32(ext, 6, 5); /* big bit-endian */
a45f1763
RH
4104 TCGv mask, tofs, tlen;
4105
f764718d
RH
4106 tofs = NULL;
4107 tlen = NULL;
a45f1763
RH
4108 if ((insn & 0x0f00) == 0x0d00) { /* bfffo */
4109 tofs = tcg_temp_new();
4110 tlen = tcg_temp_new();
4111 }
ac815f46
RH
4112
4113 if ((ext & 0x820) == 0) {
4114 /* Immediate width and offset. */
4115 uint32_t maski = 0x7fffffffu >> (len - 1);
4116 if (ofs + len <= 32) {
4117 tcg_gen_shli_i32(QREG_CC_N, src, ofs);
4118 } else {
4119 tcg_gen_rotli_i32(QREG_CC_N, src, ofs);
4120 }
4121 tcg_gen_andi_i32(QREG_CC_N, QREG_CC_N, ~maski);
4122 mask = tcg_const_i32(ror32(maski, ofs));
f764718d 4123 if (tofs) {
a45f1763
RH
4124 tcg_gen_movi_i32(tofs, ofs);
4125 tcg_gen_movi_i32(tlen, len);
4126 }
ac815f46
RH
4127 } else {
4128 TCGv tmp = tcg_temp_new();
4129 if (ext & 0x20) {
4130 /* Variable width */
4131 tcg_gen_subi_i32(tmp, DREG(ext, 0), 1);
4132 tcg_gen_andi_i32(tmp, tmp, 31);
4133 mask = tcg_const_i32(0x7fffffffu);
4134 tcg_gen_shr_i32(mask, mask, tmp);
f764718d 4135 if (tlen) {
a45f1763
RH
4136 tcg_gen_addi_i32(tlen, tmp, 1);
4137 }
ac815f46
RH
4138 } else {
4139 /* Immediate width */
4140 mask = tcg_const_i32(0x7fffffffu >> (len - 1));
f764718d 4141 if (tlen) {
a45f1763
RH
4142 tcg_gen_movi_i32(tlen, len);
4143 }
ac815f46
RH
4144 }
4145 if (ext & 0x800) {
4146 /* Variable offset */
4147 tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
4148 tcg_gen_rotl_i32(QREG_CC_N, src, tmp);
4149 tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask);
4150 tcg_gen_rotr_i32(mask, mask, tmp);
f764718d 4151 if (tofs) {
a45f1763
RH
4152 tcg_gen_mov_i32(tofs, tmp);
4153 }
ac815f46
RH
4154 } else {
4155 /* Immediate offset (and variable width) */
4156 tcg_gen_rotli_i32(QREG_CC_N, src, ofs);
4157 tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask);
4158 tcg_gen_rotri_i32(mask, mask, ofs);
f764718d 4159 if (tofs) {
a45f1763
RH
4160 tcg_gen_movi_i32(tofs, ofs);
4161 }
ac815f46
RH
4162 }
4163 tcg_temp_free(tmp);
4164 }
4165 set_cc_op(s, CC_OP_LOGIC);
4166
4167 switch (insn & 0x0f00) {
4168 case 0x0a00: /* bfchg */
4169 tcg_gen_eqv_i32(src, src, mask);
4170 break;
4171 case 0x0c00: /* bfclr */
4172 tcg_gen_and_i32(src, src, mask);
4173 break;
a45f1763
RH
4174 case 0x0d00: /* bfffo */
4175 gen_helper_bfffo_reg(DREG(ext, 12), QREG_CC_N, tofs, tlen);
4176 tcg_temp_free(tlen);
4177 tcg_temp_free(tofs);
4178 break;
ac815f46
RH
4179 case 0x0e00: /* bfset */
4180 tcg_gen_orc_i32(src, src, mask);
4181 break;
4182 case 0x0800: /* bftst */
4183 /* flags already set; no other work to do. */
4184 break;
4185 default:
4186 g_assert_not_reached();
4187 }
4188 tcg_temp_free(mask);
4189}
4190
f2224f2c
RH
4191DISAS_INSN(bfop_mem)
4192{
4193 int ext = read_im16(env, s);
4194 TCGv addr, len, ofs;
a45f1763 4195 TCGv_i64 t64;
f2224f2c
RH
4196
4197 addr = gen_lea(env, s, insn, OS_UNSIZED);
4198 if (IS_NULL_QREG(addr)) {
4199 gen_addr_fault(s);
4200 return;
4201 }
4202
4203 if (ext & 0x20) {
4204 len = DREG(ext, 0);
4205 } else {
4206 len = tcg_const_i32(extract32(ext, 0, 5));
4207 }
4208 if (ext & 0x800) {
4209 ofs = DREG(ext, 6);
4210 } else {
4211 ofs = tcg_const_i32(extract32(ext, 6, 5));
4212 }
4213
4214 switch (insn & 0x0f00) {
4215 case 0x0a00: /* bfchg */
4216 gen_helper_bfchg_mem(QREG_CC_N, cpu_env, addr, ofs, len);
4217 break;
4218 case 0x0c00: /* bfclr */
4219 gen_helper_bfclr_mem(QREG_CC_N, cpu_env, addr, ofs, len);
4220 break;
a45f1763
RH
4221 case 0x0d00: /* bfffo */
4222 t64 = tcg_temp_new_i64();
4223 gen_helper_bfffo_mem(t64, cpu_env, addr, ofs, len);
4224 tcg_gen_extr_i64_i32(DREG(ext, 12), QREG_CC_N, t64);
4225 tcg_temp_free_i64(t64);
4226 break;
f2224f2c
RH
4227 case 0x0e00: /* bfset */
4228 gen_helper_bfset_mem(QREG_CC_N, cpu_env, addr, ofs, len);
4229 break;
4230 case 0x0800: /* bftst */
4231 gen_helper_bfexts_mem(QREG_CC_N, cpu_env, addr, ofs, len);
4232 break;
4233 default:
4234 g_assert_not_reached();
4235 }
4236 set_cc_op(s, CC_OP_LOGIC);
4237
4238 if (!(ext & 0x20)) {
4239 tcg_temp_free(len);
4240 }
4241 if (!(ext & 0x800)) {
4242 tcg_temp_free(ofs);
4243 }
4244}
4245
ac815f46
RH
4246DISAS_INSN(bfins_reg)
4247{
4248 int ext = read_im16(env, s);
4249 TCGv dst = DREG(insn, 0);
4250 TCGv src = DREG(ext, 12);
4251 int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
4252 int ofs = extract32(ext, 6, 5); /* big bit-endian */
4253 int pos = 32 - ofs - len; /* little bit-endian */
4254 TCGv tmp;
4255
4256 tmp = tcg_temp_new();
4257
4258 if (ext & 0x20) {
4259 /* Variable width */
4260 tcg_gen_neg_i32(tmp, DREG(ext, 0));
4261 tcg_gen_andi_i32(tmp, tmp, 31);
4262 tcg_gen_shl_i32(QREG_CC_N, src, tmp);
4263 } else {
4264 /* Immediate width */
4265 tcg_gen_shli_i32(QREG_CC_N, src, 32 - len);
4266 }
4267 set_cc_op(s, CC_OP_LOGIC);
4268
4269 /* Immediate width and offset */
4270 if ((ext & 0x820) == 0) {
4271 /* Check for suitability for deposit. */
4272 if (pos >= 0) {
4273 tcg_gen_deposit_i32(dst, dst, src, pos, len);
4274 } else {
4275 uint32_t maski = -2U << (len - 1);
4276 uint32_t roti = (ofs + len) & 31;
4277 tcg_gen_andi_i32(tmp, src, ~maski);
4278 tcg_gen_rotri_i32(tmp, tmp, roti);
4279 tcg_gen_andi_i32(dst, dst, ror32(maski, roti));
4280 tcg_gen_or_i32(dst, dst, tmp);
4281 }
4282 } else {
4283 TCGv mask = tcg_temp_new();
4284 TCGv rot = tcg_temp_new();
4285
4286 if (ext & 0x20) {
4287 /* Variable width */
4288 tcg_gen_subi_i32(rot, DREG(ext, 0), 1);
4289 tcg_gen_andi_i32(rot, rot, 31);
4290 tcg_gen_movi_i32(mask, -2);
4291 tcg_gen_shl_i32(mask, mask, rot);
4292 tcg_gen_mov_i32(rot, DREG(ext, 0));
4293 tcg_gen_andc_i32(tmp, src, mask);
4294 } else {
4295 /* Immediate width (variable offset) */
4296 uint32_t maski = -2U << (len - 1);
4297 tcg_gen_andi_i32(tmp, src, ~maski);
4298 tcg_gen_movi_i32(mask, maski);
4299 tcg_gen_movi_i32(rot, len & 31);
4300 }
4301 if (ext & 0x800) {
4302 /* Variable offset */
4303 tcg_gen_add_i32(rot, rot, DREG(ext, 6));
4304 } else {
4305 /* Immediate offset (variable width) */
4306 tcg_gen_addi_i32(rot, rot, ofs);
4307 }
4308 tcg_gen_andi_i32(rot, rot, 31);
4309 tcg_gen_rotr_i32(mask, mask, rot);
4310 tcg_gen_rotr_i32(tmp, tmp, rot);
4311 tcg_gen_and_i32(dst, dst, mask);
4312 tcg_gen_or_i32(dst, dst, tmp);
4313
4314 tcg_temp_free(rot);
4315 tcg_temp_free(mask);
4316 }
4317 tcg_temp_free(tmp);
4318}
4319
f2224f2c
RH
4320DISAS_INSN(bfins_mem)
4321{
4322 int ext = read_im16(env, s);
4323 TCGv src = DREG(ext, 12);
4324 TCGv addr, len, ofs;
4325
4326 addr = gen_lea(env, s, insn, OS_UNSIZED);
4327 if (IS_NULL_QREG(addr)) {
4328 gen_addr_fault(s);
4329 return;
4330 }
4331
4332 if (ext & 0x20) {
4333 len = DREG(ext, 0);
4334 } else {
4335 len = tcg_const_i32(extract32(ext, 0, 5));
4336 }
4337 if (ext & 0x800) {
4338 ofs = DREG(ext, 6);
4339 } else {
4340 ofs = tcg_const_i32(extract32(ext, 6, 5));
4341 }
4342
4343 gen_helper_bfins_mem(QREG_CC_N, cpu_env, addr, src, ofs, len);
4344 set_cc_op(s, CC_OP_LOGIC);
4345
4346 if (!(ext & 0x20)) {
4347 tcg_temp_free(len);
4348 }
4349 if (!(ext & 0x800)) {
4350 tcg_temp_free(ofs);
4351 }
4352}
4353
e6e5906b
PB
4354DISAS_INSN(ff1)
4355{
e1f3808e 4356 TCGv reg;
821f7e76 4357 reg = DREG(insn, 0);
5dbb6784 4358 gen_logic_cc(s, reg, OS_LONG);
e1f3808e 4359 gen_helper_ff1(reg, reg);
e6e5906b
PB
4360}
4361
8bf6cbaf 4362DISAS_INSN(chk)
0633879f 4363{
8bf6cbaf
LV
4364 TCGv src, reg;
4365 int opsize;
0633879f 4366
8bf6cbaf
LV
4367 switch ((insn >> 7) & 3) {
4368 case 3:
4369 opsize = OS_WORD;
4370 break;
4371 case 2:
4372 if (m68k_feature(env, M68K_FEATURE_CHK2)) {
4373 opsize = OS_LONG;
4374 break;
4375 }
4376 /* fallthru */
4377 default:
4378 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
4379 return;
4380 }
4381 SRC_EA(env, src, opsize, 1, NULL);
3f215a14 4382 reg = gen_extend(s, DREG(insn, 9), opsize, 1);
8bf6cbaf
LV
4383
4384 gen_flush_flags(s);
4385 gen_helper_chk(cpu_env, reg, src);
4386}
4387
4388DISAS_INSN(chk2)
4389{
4390 uint16_t ext;
4391 TCGv addr1, addr2, bound1, bound2, reg;
4392 int opsize;
4393
4394 switch ((insn >> 9) & 3) {
4395 case 0:
4396 opsize = OS_BYTE;
4397 break;
4398 case 1:
4399 opsize = OS_WORD;
4400 break;
4401 case 2:
4402 opsize = OS_LONG;
4403 break;
4404 default:
4405 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
4406 return;
4407 }
4408
4409 ext = read_im16(env, s);
4410 if ((ext & 0x0800) == 0) {
4411 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
4412 return;
4413 }
4414
4415 addr1 = gen_lea(env, s, insn, OS_UNSIZED);
4416 addr2 = tcg_temp_new();
4417 tcg_gen_addi_i32(addr2, addr1, opsize_bytes(opsize));
4418
54e1e0b5 4419 bound1 = gen_load(s, opsize, addr1, 1, IS_USER(s));
8bf6cbaf 4420 tcg_temp_free(addr1);
54e1e0b5 4421 bound2 = gen_load(s, opsize, addr2, 1, IS_USER(s));
8bf6cbaf
LV
4422 tcg_temp_free(addr2);
4423
4424 reg = tcg_temp_new();
4425 if (ext & 0x8000) {
4426 tcg_gen_mov_i32(reg, AREG(ext, 12));
4427 } else {
4428 gen_ext(reg, DREG(ext, 12), opsize, 1);
4429 }
4430
4431 gen_flush_flags(s);
4432 gen_helper_chk2(cpu_env, reg, bound1, bound2);
4433 tcg_temp_free(reg);
24989f0e
LV
4434 tcg_temp_free(bound1);
4435 tcg_temp_free(bound2);
8bf6cbaf
LV
4436}
4437
9d4f0429
LV
4438static void m68k_copy_line(TCGv dst, TCGv src, int index)
4439{
4440 TCGv addr;
4441 TCGv_i64 t0, t1;
4442
4443 addr = tcg_temp_new();
4444
4445 t0 = tcg_temp_new_i64();
4446 t1 = tcg_temp_new_i64();
4447
4448 tcg_gen_andi_i32(addr, src, ~15);
4449 tcg_gen_qemu_ld64(t0, addr, index);
4450 tcg_gen_addi_i32(addr, addr, 8);
4451 tcg_gen_qemu_ld64(t1, addr, index);
4452
4453 tcg_gen_andi_i32(addr, dst, ~15);
4454 tcg_gen_qemu_st64(t0, addr, index);
4455 tcg_gen_addi_i32(addr, addr, 8);
4456 tcg_gen_qemu_st64(t1, addr, index);
4457
4458 tcg_temp_free_i64(t0);
4459 tcg_temp_free_i64(t1);
4460 tcg_temp_free(addr);
4461}
4462
4463DISAS_INSN(move16_reg)
4464{
4465 int index = IS_USER(s);
4466 TCGv tmp;
4467 uint16_t ext;
4468
4469 ext = read_im16(env, s);
4470 if ((ext & (1 << 15)) == 0) {
4471 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
4472 }
4473
4474 m68k_copy_line(AREG(ext, 12), AREG(insn, 0), index);
4475
4476 /* Ax can be Ay, so save Ay before incrementing Ax */
4477 tmp = tcg_temp_new();
4478 tcg_gen_mov_i32(tmp, AREG(ext, 12));
4479 tcg_gen_addi_i32(AREG(insn, 0), AREG(insn, 0), 16);
4480 tcg_gen_addi_i32(AREG(ext, 12), tmp, 16);
4481 tcg_temp_free(tmp);
4482}
4483
4484DISAS_INSN(move16_mem)
4485{
4486 int index = IS_USER(s);
4487 TCGv reg, addr;
4488
4489 reg = AREG(insn, 0);
4490 addr = tcg_const_i32(read_im32(env, s));
4491
4492 if ((insn >> 3) & 1) {
4493 /* MOVE16 (xxx).L, (Ay) */
4494 m68k_copy_line(reg, addr, index);
4495 } else {
4496 /* MOVE16 (Ay), (xxx).L */
4497 m68k_copy_line(addr, reg, index);
4498 }
4499
4500 tcg_temp_free(addr);
4501
4502 if (((insn >> 3) & 2) == 0) {
4503 /* (Ay)+ */
4504 tcg_gen_addi_i32(reg, reg, 16);
4505 }
0633879f
PB
4506}
4507
e6e5906b
PB
4508DISAS_INSN(strldsr)
4509{
4510 uint16_t ext;
4511 uint32_t addr;
4512
4513 addr = s->pc - 2;
28b68cd7 4514 ext = read_im16(env, s);
0633879f 4515 if (ext != 0x46FC) {
e6e5906b 4516 gen_exception(s, addr, EXCP_UNSUPPORTED);
0633879f
PB
4517 return;
4518 }
28b68cd7 4519 ext = read_im16(env, s);
0633879f 4520 if (IS_USER(s) || (ext & SR_S) == 0) {
e6e5906b 4521 gen_exception(s, addr, EXCP_PRIVILEGE);
0633879f
PB
4522 return;
4523 }
4524 gen_push(s, gen_get_sr(s));
4525 gen_set_sr_im(s, ext, 0);
e6e5906b
PB
4526}
4527
4528DISAS_INSN(move_from_sr)
4529{
e1f3808e 4530 TCGv sr;
0633879f 4531
7c0eb318 4532 if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) {
16a14cdf 4533 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4534 return;
4535 }
4536 sr = gen_get_sr(s);
7c0eb318 4537 DEST_EA(env, insn, OS_WORD, sr, NULL);
e6e5906b
PB
4538}
4539
6ad25764 4540#if defined(CONFIG_SOFTMMU)
5fa9f1f2
LV
4541DISAS_INSN(moves)
4542{
4543 int opsize;
4544 uint16_t ext;
4545 TCGv reg;
4546 TCGv addr;
4547 int extend;
4548
4549 if (IS_USER(s)) {
4550 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
4551 return;
4552 }
4553
4554 ext = read_im16(env, s);
4555
4556 opsize = insn_opsize(insn);
4557
4558 if (ext & 0x8000) {
4559 /* address register */
4560 reg = AREG(ext, 12);
4561 extend = 1;
4562 } else {
4563 /* data register */
4564 reg = DREG(ext, 12);
4565 extend = 0;
4566 }
4567
4568 addr = gen_lea(env, s, insn, opsize);
4569 if (IS_NULL_QREG(addr)) {
4570 gen_addr_fault(s);
4571 return;
4572 }
4573
4574 if (ext & 0x0800) {
4575 /* from reg to ea */
4576 gen_store(s, opsize, addr, reg, DFC_INDEX(s));
4577 } else {
4578 /* from ea to reg */
4579 TCGv tmp = gen_load(s, opsize, addr, 0, SFC_INDEX(s));
4580 if (extend) {
4581 gen_ext(reg, tmp, opsize, 1);
4582 } else {
4583 gen_partset_reg(opsize, reg, tmp);
4584 }
24989f0e 4585 tcg_temp_free(tmp);
5fa9f1f2
LV
4586 }
4587 switch (extract32(insn, 3, 3)) {
4588 case 3: /* Indirect postincrement. */
4589 tcg_gen_addi_i32(AREG(insn, 0), addr,
4590 REG(insn, 0) == 7 && opsize == OS_BYTE
4591 ? 2
4592 : opsize_bytes(opsize));
4593 break;
4594 case 4: /* Indirect predecrememnt. */
4595 tcg_gen_mov_i32(AREG(insn, 0), addr);
4596 break;
4597 }
4598}
4599
e6e5906b
PB
4600DISAS_INSN(move_to_sr)
4601{
0633879f 4602 if (IS_USER(s)) {
16a14cdf 4603 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4604 return;
4605 }
b6a21d8d 4606 gen_move_to_sr(env, s, insn, false);
0633879f 4607 gen_lookup_tb(s);
e6e5906b
PB
4608}
4609
4610DISAS_INSN(move_from_usp)
4611{
0633879f 4612 if (IS_USER(s)) {
16a14cdf 4613 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4614 return;
4615 }
2a8327e8
GU
4616 tcg_gen_ld_i32(AREG(insn, 0), cpu_env,
4617 offsetof(CPUM68KState, sp[M68K_USP]));
e6e5906b
PB
4618}
4619
4620DISAS_INSN(move_to_usp)
4621{
0633879f 4622 if (IS_USER(s)) {
16a14cdf 4623 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4624 return;
4625 }
2a8327e8
GU
4626 tcg_gen_st_i32(AREG(insn, 0), cpu_env,
4627 offsetof(CPUM68KState, sp[M68K_USP]));
e6e5906b
PB
4628}
4629
4630DISAS_INSN(halt)
4631{
6ad25764
LV
4632 if (IS_USER(s)) {
4633 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
4634 return;
4635 }
4636
e1f3808e 4637 gen_exception(s, s->pc, EXCP_HALT_INSN);
e6e5906b
PB
4638}
4639
4640DISAS_INSN(stop)
4641{
0633879f
PB
4642 uint16_t ext;
4643
4644 if (IS_USER(s)) {
16a14cdf 4645 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4646 return;
4647 }
4648
28b68cd7 4649 ext = read_im16(env, s);
0633879f
PB
4650
4651 gen_set_sr_im(s, ext, 0);
259186a7 4652 tcg_gen_movi_i32(cpu_halted, 1);
e1f3808e 4653 gen_exception(s, s->pc, EXCP_HLT);
e6e5906b
PB
4654}
4655
4656DISAS_INSN(rte)
4657{
0633879f 4658 if (IS_USER(s)) {
16a14cdf 4659 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4660 return;
4661 }
16a14cdf 4662 gen_exception(s, s->insn_pc, EXCP_RTE);
e6e5906b
PB
4663}
4664
6e22b28e 4665DISAS_INSN(cf_movec)
e6e5906b 4666{
0633879f 4667 uint16_t ext;
e1f3808e 4668 TCGv reg;
0633879f
PB
4669
4670 if (IS_USER(s)) {
16a14cdf 4671 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4672 return;
4673 }
4674
28b68cd7 4675 ext = read_im16(env, s);
0633879f
PB
4676
4677 if (ext & 0x8000) {
4678 reg = AREG(ext, 12);
4679 } else {
4680 reg = DREG(ext, 12);
4681 }
6e22b28e
LV
4682 gen_helper_cf_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg);
4683 gen_lookup_tb(s);
4684}
4685
4686DISAS_INSN(m68k_movec)
4687{
4688 uint16_t ext;
4689 TCGv reg;
4690
4691 if (IS_USER(s)) {
4692 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
4693 return;
4694 }
4695
4696 ext = read_im16(env, s);
4697
4698 if (ext & 0x8000) {
4699 reg = AREG(ext, 12);
4700 } else {
4701 reg = DREG(ext, 12);
4702 }
4703 if (insn & 1) {
4704 gen_helper_m68k_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg);
4705 } else {
4706 gen_helper_m68k_movec_from(reg, cpu_env, tcg_const_i32(ext & 0xfff));
4707 }
0633879f 4708 gen_lookup_tb(s);
e6e5906b
PB
4709}
4710
4711DISAS_INSN(intouch)
4712{
0633879f 4713 if (IS_USER(s)) {
16a14cdf 4714 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4715 return;
4716 }
4717 /* ICache fetch. Implement as no-op. */
e6e5906b
PB
4718}
4719
4720DISAS_INSN(cpushl)
4721{
0633879f 4722 if (IS_USER(s)) {
16a14cdf 4723 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4724 return;
4725 }
4726 /* Cache push/invalidate. Implement as no-op. */
e6e5906b
PB
4727}
4728
f58ed1c5
LV
4729DISAS_INSN(cpush)
4730{
4731 if (IS_USER(s)) {
4732 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
4733 return;
4734 }
4735 /* Cache push/invalidate. Implement as no-op. */
4736}
4737
4738DISAS_INSN(cinv)
4739{
4740 if (IS_USER(s)) {
4741 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
4742 return;
4743 }
4744 /* Invalidate cache line. Implement as no-op. */
4745}
4746
e55886c3
LV
4747#if defined(CONFIG_SOFTMMU)
4748DISAS_INSN(pflush)
4749{
4750 TCGv opmode;
4751
4752 if (IS_USER(s)) {
4753 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
4754 return;
4755 }
4756
4757 opmode = tcg_const_i32((insn >> 3) & 3);
4758 gen_helper_pflush(cpu_env, AREG(insn, 0), opmode);
4759 tcg_temp_free(opmode);
4760}
4761
4762DISAS_INSN(ptest)
4763{
4764 TCGv is_read;
4765
4766 if (IS_USER(s)) {
4767 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
4768 return;
4769 }
4770 is_read = tcg_const_i32((insn >> 5) & 1);
4771 gen_helper_ptest(cpu_env, AREG(insn, 0), is_read);
4772 tcg_temp_free(is_read);
4773}
4774#endif
4775
e6e5906b
PB
4776DISAS_INSN(wddata)
4777{
16a14cdf 4778 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
e6e5906b
PB
4779}
4780
4781DISAS_INSN(wdebug)
4782{
a47dddd7
AF
4783 M68kCPU *cpu = m68k_env_get_cpu(env);
4784
0633879f 4785 if (IS_USER(s)) {
16a14cdf 4786 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
0633879f
PB
4787 return;
4788 }
4789 /* TODO: Implement wdebug. */
a47dddd7 4790 cpu_abort(CPU(cpu), "WDEBUG not implemented");
e6e5906b 4791}
6ad25764 4792#endif
e6e5906b
PB
4793
4794DISAS_INSN(trap)
4795{
16a14cdf 4796 gen_exception(s, s->insn_pc, EXCP_TRAP0 + (insn & 0xf));
e6e5906b
PB
4797}
4798
ba624944
LV
4799static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
4800{
4801 switch (reg) {
4802 case M68K_FPIAR:
4803 tcg_gen_movi_i32(res, 0);
4804 break;
4805 case M68K_FPSR:
4806 tcg_gen_ld_i32(res, cpu_env, offsetof(CPUM68KState, fpsr));
4807 break;
4808 case M68K_FPCR:
4809 tcg_gen_ld_i32(res, cpu_env, offsetof(CPUM68KState, fpcr));
4810 break;
4811 }
4812}
4813
4814static void gen_store_fcr(DisasContext *s, TCGv val, int reg)
4815{
4816 switch (reg) {
4817 case M68K_FPIAR:
4818 break;
4819 case M68K_FPSR:
4820 tcg_gen_st_i32(val, cpu_env, offsetof(CPUM68KState, fpsr));
4821 break;
4822 case M68K_FPCR:
4823 gen_helper_set_fpcr(cpu_env, val);
4824 break;
4825 }
4826}
4827
4828static void gen_qemu_store_fcr(DisasContext *s, TCGv addr, int reg)
4829{
4830 int index = IS_USER(s);
4831 TCGv tmp;
4832
4833 tmp = tcg_temp_new();
4834 gen_load_fcr(s, tmp, reg);
4835 tcg_gen_qemu_st32(tmp, addr, index);
4836 tcg_temp_free(tmp);
4837}
4838
4839static void gen_qemu_load_fcr(DisasContext *s, TCGv addr, int reg)
4840{
4841 int index = IS_USER(s);
4842 TCGv tmp;
4843
4844 tmp = tcg_temp_new();
4845 tcg_gen_qemu_ld32u(tmp, addr, index);
4846 gen_store_fcr(s, tmp, reg);
4847 tcg_temp_free(tmp);
4848}
4849
4850
860b9ac7
LV
4851static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
4852 uint32_t insn, uint32_t ext)
4853{
4854 int mask = (ext >> 10) & 7;
4855 int is_write = (ext >> 13) & 1;
ba624944
LV
4856 int mode = extract32(insn, 3, 3);
4857 int i;
4858 TCGv addr, tmp;
860b9ac7 4859
ba624944
LV
4860 switch (mode) {
4861 case 0: /* Dn */
4862 if (mask != M68K_FPIAR && mask != M68K_FPSR && mask != M68K_FPCR) {
4863 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
4864 return;
4865 }
860b9ac7 4866 if (is_write) {
ba624944
LV
4867 gen_load_fcr(s, DREG(insn, 0), mask);
4868 } else {
4869 gen_store_fcr(s, DREG(insn, 0), mask);
860b9ac7 4870 }
ba624944
LV
4871 return;
4872 case 1: /* An, only with FPIAR */
4873 if (mask != M68K_FPIAR) {
4874 gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
4875 return;
4876 }
4877 if (is_write) {
4878 gen_load_fcr(s, AREG(insn, 0), mask);
4879 } else {
4880 gen_store_fcr(s, AREG(insn, 0), mask);
4881 }
4882 return;
4883 default:
860b9ac7
LV
4884 break;
4885 }
ba624944
LV
4886
4887 tmp = gen_lea(env, s, insn, OS_LONG);
4888 if (IS_NULL_QREG(tmp)) {
4889 gen_addr_fault(s);
4890 return;
4891 }
4892
4893 addr = tcg_temp_new();
4894 tcg_gen_mov_i32(addr, tmp);
4895
4896 /* mask:
4897 *
4898 * 0b100 Floating-Point Control Register
4899 * 0b010 Floating-Point Status Register
4900 * 0b001 Floating-Point Instruction Address Register
4901 *
4902 */
4903
4904 if (is_write && mode == 4) {
4905 for (i = 2; i >= 0; i--, mask >>= 1) {
4906 if (mask & 1) {
4907 gen_qemu_store_fcr(s, addr, 1 << i);
4908 if (mask != 1) {
4909 tcg_gen_subi_i32(addr, addr, opsize_bytes(OS_LONG));
4910 }
4911 }
4912 }
4913 tcg_gen_mov_i32(AREG(insn, 0), addr);
4914 } else {
4915 for (i = 0; i < 3; i++, mask >>= 1) {
4916 if (mask & 1) {
4917 if (is_write) {
4918 gen_qemu_store_fcr(s, addr, 1 << i);
4919 } else {
4920 gen_qemu_load_fcr(s, addr, 1 << i);
4921 }
4922 if (mask != 1 || mode == 3) {
4923 tcg_gen_addi_i32(addr, addr, opsize_bytes(OS_LONG));
4924 }
4925 }
4926 }
4927 if (mode == 3) {
4928 tcg_gen_mov_i32(AREG(insn, 0), addr);
4929 }
4930 }
4931 tcg_temp_free_i32(addr);
860b9ac7
LV
4932}
4933
a1e58ddc
LV
4934static void gen_op_fmovem(CPUM68KState *env, DisasContext *s,
4935 uint32_t insn, uint32_t ext)
4936{
4937 int opsize;
4938 TCGv addr, tmp;
4939 int mode = (ext >> 11) & 0x3;
4940 int is_load = ((ext & 0x2000) == 0);
4941
4942 if (m68k_feature(s->env, M68K_FEATURE_FPU)) {
4943 opsize = OS_EXTENDED;
4944 } else {
4945 opsize = OS_DOUBLE; /* FIXME */
4946 }
4947
4948 addr = gen_lea(env, s, insn, opsize);
4949 if (IS_NULL_QREG(addr)) {
4950 gen_addr_fault(s);
4951 return;
4952 }
4953
4954 tmp = tcg_temp_new();
4955 if (mode & 0x1) {
4956 /* Dynamic register list */
4957 tcg_gen_ext8u_i32(tmp, DREG(ext, 4));
4958 } else {
4959 /* Static register list */
4960 tcg_gen_movi_i32(tmp, ext & 0xff);
4961 }
4962
4963 if (!is_load && (mode & 2) == 0) {
4964 /* predecrement addressing mode
4965 * only available to store register to memory
4966 */
4967 if (opsize == OS_EXTENDED) {
4968 gen_helper_fmovemx_st_predec(tmp, cpu_env, addr, tmp);
4969 } else {
4970 gen_helper_fmovemd_st_predec(tmp, cpu_env, addr, tmp);
4971 }
4972 } else {
4973 /* postincrement addressing mode */
4974 if (opsize == OS_EXTENDED) {
4975 if (is_load) {
4976 gen_helper_fmovemx_ld_postinc(tmp, cpu_env, addr, tmp);
4977 } else {
4978 gen_helper_fmovemx_st_postinc(tmp, cpu_env, addr, tmp);
4979 }
4980 } else {
4981 if (is_load) {
4982 gen_helper_fmovemd_ld_postinc(tmp, cpu_env, addr, tmp);
4983 } else {
4984 gen_helper_fmovemd_st_postinc(tmp, cpu_env, addr, tmp);
4985 }
4986 }
4987 }
4988 if ((insn & 070) == 030 || (insn & 070) == 040) {
4989 tcg_gen_mov_i32(AREG(insn, 0), tmp);
4990 }
4991 tcg_temp_free(tmp);
4992}
4993
e6e5906b
PB
4994/* ??? FP exceptions are not implemented. Most exceptions are deferred until
4995 immediately before the next FP instruction is executed. */
4996DISAS_INSN(fpu)
4997{
4998 uint16_t ext;
4999 int opmode;
e6e5906b 5000 int opsize;
f83311e4 5001 TCGv_ptr cpu_src, cpu_dest;
e6e5906b 5002
28b68cd7 5003 ext = read_im16(env, s);
e6e5906b
PB
5004 opmode = ext & 0x7f;
5005 switch ((ext >> 13) & 7) {
9d403660 5006 case 0:
e6e5906b
PB
5007 break;
5008 case 1:
5009 goto undef;
9d403660
LV
5010 case 2:
5011 if (insn == 0xf200 && (ext & 0xfc00) == 0x5c00) {
5012 /* fmovecr */
5013 TCGv rom_offset = tcg_const_i32(opmode);
5014 cpu_dest = gen_fp_ptr(REG(ext, 7));
5015 gen_helper_fconst(cpu_env, cpu_dest, rom_offset);
5016 tcg_temp_free_ptr(cpu_dest);
5017 tcg_temp_free(rom_offset);
5018 return;
5019 }
5020 break;
e6e5906b 5021 case 3: /* fmove out */
f83311e4 5022 cpu_src = gen_fp_ptr(REG(ext, 7));
69e69822 5023 opsize = ext_opsize(ext, 10);
54e1e0b5
LV
5024 if (gen_ea_fp(env, s, insn, opsize, cpu_src,
5025 EA_STORE, IS_USER(s)) == -1) {
f83311e4 5026 gen_addr_fault(s);
e6e5906b 5027 }
ba624944 5028 gen_helper_ftst(cpu_env, cpu_src);
f83311e4 5029 tcg_temp_free_ptr(cpu_src);
e6e5906b
PB
5030 return;
5031 case 4: /* fmove to control register. */
e6e5906b 5032 case 5: /* fmove from control register. */
860b9ac7
LV
5033 gen_op_fmove_fcr(env, s, insn, ext);
5034 return;
5fafdf24 5035 case 6: /* fmovem */
e6e5906b 5036 case 7:
a1e58ddc
LV
5037 if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU)) {
5038 goto undef;
e6e5906b 5039 }
a1e58ddc 5040 gen_op_fmovem(env, s, insn, ext);
e6e5906b
PB
5041 return;
5042 }
5043 if (ext & (1 << 14)) {
e6e5906b 5044 /* Source effective address. */
69e69822 5045 opsize = ext_opsize(ext, 10);
f83311e4 5046 cpu_src = gen_fp_result_ptr();
54e1e0b5
LV
5047 if (gen_ea_fp(env, s, insn, opsize, cpu_src,
5048 EA_LOADS, IS_USER(s)) == -1) {
f83311e4
LV
5049 gen_addr_fault(s);
5050 return;
e6e5906b
PB
5051 }
5052 } else {
5053 /* Source register. */
f83311e4
LV
5054 opsize = OS_EXTENDED;
5055 cpu_src = gen_fp_ptr(REG(ext, 10));
e6e5906b 5056 }
f83311e4 5057 cpu_dest = gen_fp_ptr(REG(ext, 7));
e6e5906b 5058 switch (opmode) {
77bdb229 5059 case 0: /* fmove */
f83311e4 5060 gen_fp_move(cpu_dest, cpu_src);
e6e5906b 5061 break;
77bdb229
LV
5062 case 0x40: /* fsmove */
5063 gen_helper_fsround(cpu_env, cpu_dest, cpu_src);
5064 break;
5065 case 0x44: /* fdmove */
5066 gen_helper_fdround(cpu_env, cpu_dest, cpu_src);
5067 break;
e6e5906b 5068 case 1: /* fint */
f83311e4 5069 gen_helper_firound(cpu_env, cpu_dest, cpu_src);
e6e5906b 5070 break;
eee6b892
LV
5071 case 2: /* fsinh */
5072 gen_helper_fsinh(cpu_env, cpu_dest, cpu_src);
5073 break;
e6e5906b 5074 case 3: /* fintrz */
f83311e4 5075 gen_helper_fitrunc(cpu_env, cpu_dest, cpu_src);
e6e5906b 5076 break;
a51b6bc3 5077 case 4: /* fsqrt */
f83311e4 5078 gen_helper_fsqrt(cpu_env, cpu_dest, cpu_src);
e6e5906b 5079 break;
a51b6bc3
LV
5080 case 0x41: /* fssqrt */
5081 gen_helper_fssqrt(cpu_env, cpu_dest, cpu_src);
5082 break;
5083 case 0x45: /* fdsqrt */
5084 gen_helper_fdsqrt(cpu_env, cpu_dest, cpu_src);
5085 break;
4b5c65b8
LV
5086 case 0x06: /* flognp1 */
5087 gen_helper_flognp1(cpu_env, cpu_dest, cpu_src);
5088 break;
9937b029
LV
5089 case 0x09: /* ftanh */
5090 gen_helper_ftanh(cpu_env, cpu_dest, cpu_src);
5091 break;
8c992abc
LV
5092 case 0x0a: /* fatan */
5093 gen_helper_fatan(cpu_env, cpu_dest, cpu_src);
5094 break;
bc20b34e
LV
5095 case 0x0c: /* fasin */
5096 gen_helper_fasin(cpu_env, cpu_dest, cpu_src);
5097 break;
e3655afa
LV
5098 case 0x0d: /* fatanh */
5099 gen_helper_fatanh(cpu_env, cpu_dest, cpu_src);
5100 break;
5add1ac4
LV
5101 case 0x0e: /* fsin */
5102 gen_helper_fsin(cpu_env, cpu_dest, cpu_src);
5103 break;
27340180
LV
5104 case 0x0f: /* ftan */
5105 gen_helper_ftan(cpu_env, cpu_dest, cpu_src);
5106 break;
40ad0873
LV
5107 case 0x10: /* fetox */
5108 gen_helper_fetox(cpu_env, cpu_dest, cpu_src);
5109 break;
068f1615
LV
5110 case 0x11: /* ftwotox */
5111 gen_helper_ftwotox(cpu_env, cpu_dest, cpu_src);
5112 break;
6c25be6e
LV
5113 case 0x12: /* ftentox */
5114 gen_helper_ftentox(cpu_env, cpu_dest, cpu_src);
5115 break;
50067bd1
LV
5116 case 0x14: /* flogn */
5117 gen_helper_flogn(cpu_env, cpu_dest, cpu_src);
5118 break;
248efb66
LV
5119 case 0x15: /* flog10 */
5120 gen_helper_flog10(cpu_env, cpu_dest, cpu_src);
5121 break;
67b453ed
LV
5122 case 0x16: /* flog2 */
5123 gen_helper_flog2(cpu_env, cpu_dest, cpu_src);
5124 break;
77bdb229 5125 case 0x18: /* fabs */
f83311e4 5126 gen_helper_fabs(cpu_env, cpu_dest, cpu_src);
e6e5906b 5127 break;
77bdb229
LV
5128 case 0x58: /* fsabs */
5129 gen_helper_fsabs(cpu_env, cpu_dest, cpu_src);
5130 break;
5131 case 0x5c: /* fdabs */
5132 gen_helper_fdabs(cpu_env, cpu_dest, cpu_src);
5133 break;
02f9124e
LV
5134 case 0x19: /* fcosh */
5135 gen_helper_fcosh(cpu_env, cpu_dest, cpu_src);
5136 break;
77bdb229
LV
5137 case 0x1a: /* fneg */
5138 gen_helper_fneg(cpu_env, cpu_dest, cpu_src);
5139 break;
5140 case 0x5a: /* fsneg */
5141 gen_helper_fsneg(cpu_env, cpu_dest, cpu_src);
5142 break;
5143 case 0x5e: /* fdneg */
5144 gen_helper_fdneg(cpu_env, cpu_dest, cpu_src);
e6e5906b 5145 break;
c84813b8
LV
5146 case 0x1c: /* facos */
5147 gen_helper_facos(cpu_env, cpu_dest, cpu_src);
5148 break;
68d0ed37
LV
5149 case 0x1d: /* fcos */
5150 gen_helper_fcos(cpu_env, cpu_dest, cpu_src);
5151 break;
0d379c17
LV
5152 case 0x1e: /* fgetexp */
5153 gen_helper_fgetexp(cpu_env, cpu_dest, cpu_src);
5154 break;
5155 case 0x1f: /* fgetman */
5156 gen_helper_fgetman(cpu_env, cpu_dest, cpu_src);
5157 break;
a51b6bc3 5158 case 0x20: /* fdiv */
f83311e4 5159 gen_helper_fdiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
e6e5906b 5160 break;
a51b6bc3
LV
5161 case 0x60: /* fsdiv */
5162 gen_helper_fsdiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
5163 break;
5164 case 0x64: /* fddiv */
5165 gen_helper_fddiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
5166 break;
591596b7
LV
5167 case 0x21: /* fmod */
5168 gen_helper_fmod(cpu_env, cpu_dest, cpu_src, cpu_dest);
5169 break;
a51b6bc3 5170 case 0x22: /* fadd */
f83311e4 5171 gen_helper_fadd(cpu_env, cpu_dest, cpu_src, cpu_dest);
e6e5906b 5172 break;
a51b6bc3
LV
5173 case 0x62: /* fsadd */
5174 gen_helper_fsadd(cpu_env, cpu_dest, cpu_src, cpu_dest);
5175 break;
5176 case 0x66: /* fdadd */
5177 gen_helper_fdadd(cpu_env, cpu_dest, cpu_src, cpu_dest);
5178 break;
5179 case 0x23: /* fmul */
f83311e4 5180 gen_helper_fmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
e6e5906b 5181 break;
a51b6bc3
LV
5182 case 0x63: /* fsmul */
5183 gen_helper_fsmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
5184 break;
5185 case 0x67: /* fdmul */
5186 gen_helper_fdmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
5187 break;
2f77995c
LV
5188 case 0x24: /* fsgldiv */
5189 gen_helper_fsgldiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
591596b7
LV
5190 break;
5191 case 0x25: /* frem */
5192 gen_helper_frem(cpu_env, cpu_dest, cpu_src, cpu_dest);
0d379c17
LV
5193 break;
5194 case 0x26: /* fscale */
5195 gen_helper_fscale(cpu_env, cpu_dest, cpu_src, cpu_dest);
2f77995c
LV
5196 break;
5197 case 0x27: /* fsglmul */
5198 gen_helper_fsglmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
5199 break;
a51b6bc3 5200 case 0x28: /* fsub */
f83311e4 5201 gen_helper_fsub(cpu_env, cpu_dest, cpu_src, cpu_dest);
e6e5906b 5202 break;
a51b6bc3
LV
5203 case 0x68: /* fssub */
5204 gen_helper_fssub(cpu_env, cpu_dest, cpu_src, cpu_dest);
5205 break;
5206 case 0x6c: /* fdsub */
5207 gen_helper_fdsub(cpu_env, cpu_dest, cpu_src, cpu_dest);
5208 break;
47446c9c
LV
5209 case 0x30: case 0x31: case 0x32:
5210 case 0x33: case 0x34: case 0x35:
5211 case 0x36: case 0x37: {
5212 TCGv_ptr cpu_dest2 = gen_fp_ptr(REG(ext, 0));
5213 gen_helper_fsincos(cpu_env, cpu_dest, cpu_dest2, cpu_src);
5214 tcg_temp_free_ptr(cpu_dest2);
5215 }
5216 break;
e6e5906b 5217 case 0x38: /* fcmp */
ba624944
LV
5218 gen_helper_fcmp(cpu_env, cpu_src, cpu_dest);
5219 return;
e6e5906b 5220 case 0x3a: /* ftst */
ba624944
LV
5221 gen_helper_ftst(cpu_env, cpu_src);
5222 return;
e6e5906b
PB
5223 default:
5224 goto undef;
5225 }
f83311e4 5226 tcg_temp_free_ptr(cpu_src);
ba624944 5227 gen_helper_ftst(cpu_env, cpu_dest);
f83311e4 5228 tcg_temp_free_ptr(cpu_dest);
e6e5906b
PB
5229 return;
5230undef:
a7812ae4 5231 /* FIXME: Is this right for offset addressing modes? */
e6e5906b 5232 s->pc -= 2;
d4d79bb1 5233 disas_undef_fpu(env, s, insn);
e6e5906b
PB
5234}
5235
dd337bf8 5236static void gen_fcc_cond(DisasCompare *c, DisasContext *s, int cond)
e6e5906b 5237{
dd337bf8 5238 TCGv fpsr;
e6e5906b 5239
dd337bf8
LV
5240 c->g1 = 1;
5241 c->v2 = tcg_const_i32(0);
5242 c->g2 = 0;
5243 /* TODO: Raise BSUN exception. */
ba624944
LV
5244 fpsr = tcg_temp_new();
5245 gen_load_fcr(s, fpsr, M68K_FPSR);
dd337bf8 5246 switch (cond) {
ba624944
LV
5247 case 0: /* False */
5248 case 16: /* Signaling False */
dd337bf8
LV
5249 c->v1 = c->v2;
5250 c->tcond = TCG_COND_NEVER;
e6e5906b 5251 break;
ba624944
LV
5252 case 1: /* EQual Z */
5253 case 17: /* Signaling EQual Z */
dd337bf8
LV
5254 c->v1 = tcg_temp_new();
5255 c->g1 = 0;
5256 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5257 c->tcond = TCG_COND_NE;
e6e5906b 5258 break;
ba624944
LV
5259 case 2: /* Ordered Greater Than !(A || Z || N) */
5260 case 18: /* Greater Than !(A || Z || N) */
dd337bf8
LV
5261 c->v1 = tcg_temp_new();
5262 c->g1 = 0;
5263 tcg_gen_andi_i32(c->v1, fpsr,
ba624944 5264 FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
dd337bf8 5265 c->tcond = TCG_COND_EQ;
e6e5906b 5266 break;
ba624944
LV
5267 case 3: /* Ordered Greater than or Equal Z || !(A || N) */
5268 case 19: /* Greater than or Equal Z || !(A || N) */
dd337bf8
LV
5269 c->v1 = tcg_temp_new();
5270 c->g1 = 0;
5271 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5272 tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
5273 tcg_gen_andi_i32(fpsr, fpsr, FPSR_CC_Z | FPSR_CC_N);
5274 tcg_gen_or_i32(c->v1, c->v1, fpsr);
5275 tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5276 c->tcond = TCG_COND_NE;
e6e5906b 5277 break;
ba624944
LV
5278 case 4: /* Ordered Less Than !(!N || A || Z); */
5279 case 20: /* Less Than !(!N || A || Z); */
dd337bf8
LV
5280 c->v1 = tcg_temp_new();
5281 c->g1 = 0;
5282 tcg_gen_xori_i32(c->v1, fpsr, FPSR_CC_N);
5283 tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_N | FPSR_CC_A | FPSR_CC_Z);
5284 c->tcond = TCG_COND_EQ;
e6e5906b 5285 break;
ba624944
LV
5286 case 5: /* Ordered Less than or Equal Z || (N && !A) */
5287 case 21: /* Less than or Equal Z || (N && !A) */
dd337bf8
LV
5288 c->v1 = tcg_temp_new();
5289 c->g1 = 0;
5290 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5291 tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
5292 tcg_gen_andc_i32(c->v1, fpsr, c->v1);
5293 tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_Z | FPSR_CC_N);
5294 c->tcond = TCG_COND_NE;
e6e5906b 5295 break;
ba624944
LV
5296 case 6: /* Ordered Greater or Less than !(A || Z) */
5297 case 22: /* Greater or Less than !(A || Z) */
dd337bf8
LV
5298 c->v1 = tcg_temp_new();
5299 c->g1 = 0;
5300 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z);
5301 c->tcond = TCG_COND_EQ;
e6e5906b 5302 break;
ba624944
LV
5303 case 7: /* Ordered !A */
5304 case 23: /* Greater, Less or Equal !A */
dd337bf8
LV
5305 c->v1 = tcg_temp_new();
5306 c->g1 = 0;
5307 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5308 c->tcond = TCG_COND_EQ;
e6e5906b 5309 break;
ba624944
LV
5310 case 8: /* Unordered A */
5311 case 24: /* Not Greater, Less or Equal A */
dd337bf8
LV
5312 c->v1 = tcg_temp_new();
5313 c->g1 = 0;
5314 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5315 c->tcond = TCG_COND_NE;
e6e5906b 5316 break;
ba624944
LV
5317 case 9: /* Unordered or Equal A || Z */
5318 case 25: /* Not Greater or Less then A || Z */
dd337bf8
LV
5319 c->v1 = tcg_temp_new();
5320 c->g1 = 0;
5321 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z);
5322 c->tcond = TCG_COND_NE;
e6e5906b 5323 break;
ba624944
LV
5324 case 10: /* Unordered or Greater Than A || !(N || Z)) */
5325 case 26: /* Not Less or Equal A || !(N || Z)) */
dd337bf8
LV
5326 c->v1 = tcg_temp_new();
5327 c->g1 = 0;
5328 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5329 tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
5330 tcg_gen_andi_i32(fpsr, fpsr, FPSR_CC_A | FPSR_CC_N);
5331 tcg_gen_or_i32(c->v1, c->v1, fpsr);
5332 tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5333 c->tcond = TCG_COND_NE;
e6e5906b 5334 break;
ba624944
LV
5335 case 11: /* Unordered or Greater or Equal A || Z || !N */
5336 case 27: /* Not Less Than A || Z || !N */
dd337bf8
LV
5337 c->v1 = tcg_temp_new();
5338 c->g1 = 0;
5339 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
5340 tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5341 c->tcond = TCG_COND_NE;
e6e5906b 5342 break;
ba624944
LV
5343 case 12: /* Unordered or Less Than A || (N && !Z) */
5344 case 28: /* Not Greater than or Equal A || (N && !Z) */
dd337bf8
LV
5345 c->v1 = tcg_temp_new();
5346 c->g1 = 0;
5347 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5348 tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
5349 tcg_gen_andc_i32(c->v1, fpsr, c->v1);
5350 tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_A | FPSR_CC_N);
5351 c->tcond = TCG_COND_NE;
e6e5906b 5352 break;
ba624944
LV
5353 case 13: /* Unordered or Less or Equal A || Z || N */
5354 case 29: /* Not Greater Than A || Z || N */
dd337bf8
LV
5355 c->v1 = tcg_temp_new();
5356 c->g1 = 0;
5357 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
5358 c->tcond = TCG_COND_NE;
e6e5906b 5359 break;
ba624944
LV
5360 case 14: /* Not Equal !Z */
5361 case 30: /* Signaling Not Equal !Z */
dd337bf8
LV
5362 c->v1 = tcg_temp_new();
5363 c->g1 = 0;
5364 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5365 c->tcond = TCG_COND_EQ;
e6e5906b 5366 break;
ba624944
LV
5367 case 15: /* True */
5368 case 31: /* Signaling True */
dd337bf8
LV
5369 c->v1 = c->v2;
5370 c->tcond = TCG_COND_ALWAYS;
e6e5906b
PB
5371 break;
5372 }
ba624944 5373 tcg_temp_free(fpsr);
dd337bf8
LV
5374}
5375
5376static void gen_fjmpcc(DisasContext *s, int cond, TCGLabel *l1)
5377{
5378 DisasCompare c;
5379
5380 gen_fcc_cond(&c, s, cond);
7cd7b5ca 5381 update_cc_op(s);
dd337bf8
LV
5382 tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
5383 free_cond(&c);
5384}
5385
5386DISAS_INSN(fbcc)
5387{
5388 uint32_t offset;
5389 uint32_t base;
5390 TCGLabel *l1;
5391
5392 base = s->pc;
5393 offset = (int16_t)read_im16(env, s);
5394 if (insn & (1 << 6)) {
5395 offset = (offset << 16) | read_im16(env, s);
5396 }
5397
5398 l1 = gen_new_label();
5399 update_cc_op(s);
5400 gen_fjmpcc(s, insn & 0x3f, l1);
e6e5906b
PB
5401 gen_jmp_tb(s, 0, s->pc);
5402 gen_set_label(l1);
dd337bf8
LV
5403 gen_jmp_tb(s, 1, base + offset);
5404}
5405
5406DISAS_INSN(fscc)
5407{
5408 DisasCompare c;
5409 int cond;
5410 TCGv tmp;
5411 uint16_t ext;
5412
5413 ext = read_im16(env, s);
5414 cond = ext & 0x3f;
5415 gen_fcc_cond(&c, s, cond);
5416
5417 tmp = tcg_temp_new();
5418 tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2);
5419 free_cond(&c);
5420
5421 tcg_gen_neg_i32(tmp, tmp);
5422 DEST_EA(env, insn, OS_BYTE, tmp, NULL);
5423 tcg_temp_free(tmp);
e6e5906b
PB
5424}
5425
6ad25764 5426#if defined(CONFIG_SOFTMMU)
0633879f
PB
5427DISAS_INSN(frestore)
5428{
fff3b4b0 5429 TCGv addr;
a47dddd7 5430
6ad25764
LV
5431 if (IS_USER(s)) {
5432 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
5433 return;
5434 }
fff3b4b0
LV
5435 if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
5436 SRC_EA(env, addr, OS_LONG, 0, NULL);
5437 /* FIXME: check the state frame */
5438 } else {
5439 disas_undef(env, s, insn);
5440 }
0633879f
PB
5441}
5442
5443DISAS_INSN(fsave)
5444{
6ad25764
LV
5445 if (IS_USER(s)) {
5446 gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
5447 return;
5448 }
a47dddd7 5449
fff3b4b0
LV
5450 if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
5451 /* always write IDLE */
5452 TCGv idle = tcg_const_i32(0x41000000);
5453 DEST_EA(env, insn, OS_LONG, idle, NULL);
5454 tcg_temp_free(idle);
5455 } else {
5456 disas_undef(env, s, insn);
5457 }
0633879f 5458}
6ad25764 5459#endif
0633879f 5460
e1f3808e 5461static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
acf930aa 5462{
a7812ae4 5463 TCGv tmp = tcg_temp_new();
acf930aa
PB
5464 if (s->env->macsr & MACSR_FI) {
5465 if (upper)
e1f3808e 5466 tcg_gen_andi_i32(tmp, val, 0xffff0000);
acf930aa 5467 else
e1f3808e 5468 tcg_gen_shli_i32(tmp, val, 16);
acf930aa
PB
5469 } else if (s->env->macsr & MACSR_SU) {
5470 if (upper)
e1f3808e 5471 tcg_gen_sari_i32(tmp, val, 16);
acf930aa 5472 else
e1f3808e 5473 tcg_gen_ext16s_i32(tmp, val);
acf930aa
PB
5474 } else {
5475 if (upper)
e1f3808e 5476 tcg_gen_shri_i32(tmp, val, 16);
acf930aa 5477 else
e1f3808e 5478 tcg_gen_ext16u_i32(tmp, val);
acf930aa
PB
5479 }
5480 return tmp;
5481}
5482
e1f3808e
PB
5483static void gen_mac_clear_flags(void)
5484{
5485 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR,
5486 ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV));
5487}
5488
acf930aa
PB
5489DISAS_INSN(mac)
5490{
e1f3808e
PB
5491 TCGv rx;
5492 TCGv ry;
acf930aa
PB
5493 uint16_t ext;
5494 int acc;
e1f3808e
PB
5495 TCGv tmp;
5496 TCGv addr;
5497 TCGv loadval;
acf930aa 5498 int dual;
e1f3808e
PB
5499 TCGv saved_flags;
5500
a7812ae4
PB
5501 if (!s->done_mac) {
5502 s->mactmp = tcg_temp_new_i64();
5503 s->done_mac = 1;
5504 }
acf930aa 5505
28b68cd7 5506 ext = read_im16(env, s);
acf930aa
PB
5507
5508 acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
5509 dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
d315c888 5510 if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
d4d79bb1 5511 disas_undef(env, s, insn);
d315c888
PB
5512 return;
5513 }
acf930aa
PB
5514 if (insn & 0x30) {
5515 /* MAC with load. */
d4d79bb1 5516 tmp = gen_lea(env, s, insn, OS_LONG);
a7812ae4 5517 addr = tcg_temp_new();
e1f3808e 5518 tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK);
acf930aa
PB
5519 /* Load the value now to ensure correct exception behavior.
5520 Perform writeback after reading the MAC inputs. */
54e1e0b5 5521 loadval = gen_load(s, OS_LONG, addr, 0, IS_USER(s));
acf930aa
PB
5522
5523 acc ^= 1;
5524 rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
5525 ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
5526 } else {
e1f3808e 5527 loadval = addr = NULL_QREG;
acf930aa
PB
5528 rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
5529 ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5530 }
5531
e1f3808e
PB
5532 gen_mac_clear_flags();
5533#if 0
acf930aa 5534 l1 = -1;
e1f3808e 5535 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
5536 if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
5537 /* Skip the multiply if we know we will ignore it. */
5538 l1 = gen_new_label();
a7812ae4 5539 tmp = tcg_temp_new();
e1f3808e 5540 tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8));
acf930aa
PB
5541 gen_op_jmp_nz32(tmp, l1);
5542 }
e1f3808e 5543#endif
acf930aa
PB
5544
5545 if ((ext & 0x0800) == 0) {
5546 /* Word. */
5547 rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
5548 ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
5549 }
5550 if (s->env->macsr & MACSR_FI) {
e1f3808e 5551 gen_helper_macmulf(s->mactmp, cpu_env, rx, ry);
acf930aa
PB
5552 } else {
5553 if (s->env->macsr & MACSR_SU)
e1f3808e 5554 gen_helper_macmuls(s->mactmp, cpu_env, rx, ry);
acf930aa 5555 else
e1f3808e 5556 gen_helper_macmulu(s->mactmp, cpu_env, rx, ry);
acf930aa
PB
5557 switch ((ext >> 9) & 3) {
5558 case 1:
e1f3808e 5559 tcg_gen_shli_i64(s->mactmp, s->mactmp, 1);
acf930aa
PB
5560 break;
5561 case 3:
e1f3808e 5562 tcg_gen_shri_i64(s->mactmp, s->mactmp, 1);
acf930aa
PB
5563 break;
5564 }
5565 }
5566
5567 if (dual) {
5568 /* Save the overflow flag from the multiply. */
a7812ae4 5569 saved_flags = tcg_temp_new();
e1f3808e
PB
5570 tcg_gen_mov_i32(saved_flags, QREG_MACSR);
5571 } else {
5572 saved_flags = NULL_QREG;
acf930aa
PB
5573 }
5574
e1f3808e
PB
5575#if 0
5576 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
5577 if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
5578 /* Skip the accumulate if the value is already saturated. */
5579 l1 = gen_new_label();
a7812ae4 5580 tmp = tcg_temp_new();
351326a6 5581 gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
acf930aa
PB
5582 gen_op_jmp_nz32(tmp, l1);
5583 }
e1f3808e 5584#endif
acf930aa
PB
5585
5586 if (insn & 0x100)
e1f3808e 5587 tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 5588 else
e1f3808e 5589 tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa
PB
5590
5591 if (s->env->macsr & MACSR_FI)
e1f3808e 5592 gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
acf930aa 5593 else if (s->env->macsr & MACSR_SU)
e1f3808e 5594 gen_helper_macsats(cpu_env, tcg_const_i32(acc));
acf930aa 5595 else
e1f3808e 5596 gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
acf930aa 5597
e1f3808e
PB
5598#if 0
5599 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
5600 if (l1 != -1)
5601 gen_set_label(l1);
e1f3808e 5602#endif
acf930aa
PB
5603
5604 if (dual) {
5605 /* Dual accumulate variant. */
5606 acc = (ext >> 2) & 3;
5607 /* Restore the overflow flag from the multiplier. */
e1f3808e
PB
5608 tcg_gen_mov_i32(QREG_MACSR, saved_flags);
5609#if 0
5610 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
5611 if ((s->env->macsr & MACSR_OMC) != 0) {
5612 /* Skip the accumulate if the value is already saturated. */
5613 l1 = gen_new_label();
a7812ae4 5614 tmp = tcg_temp_new();
351326a6 5615 gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
acf930aa
PB
5616 gen_op_jmp_nz32(tmp, l1);
5617 }
e1f3808e 5618#endif
acf930aa 5619 if (ext & 2)
e1f3808e 5620 tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 5621 else
e1f3808e 5622 tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
acf930aa 5623 if (s->env->macsr & MACSR_FI)
e1f3808e 5624 gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
acf930aa 5625 else if (s->env->macsr & MACSR_SU)
e1f3808e 5626 gen_helper_macsats(cpu_env, tcg_const_i32(acc));
acf930aa 5627 else
e1f3808e
PB
5628 gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
5629#if 0
5630 /* Disabled because conditional branches clobber temporary vars. */
acf930aa
PB
5631 if (l1 != -1)
5632 gen_set_label(l1);
e1f3808e 5633#endif
acf930aa 5634 }
e1f3808e 5635 gen_helper_mac_set_flags(cpu_env, tcg_const_i32(acc));
acf930aa
PB
5636
5637 if (insn & 0x30) {
e1f3808e 5638 TCGv rw;
acf930aa 5639 rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
e1f3808e 5640 tcg_gen_mov_i32(rw, loadval);
acf930aa
PB
5641 /* FIXME: Should address writeback happen with the masked or
5642 unmasked value? */
5643 switch ((insn >> 3) & 7) {
5644 case 3: /* Post-increment. */
e1f3808e 5645 tcg_gen_addi_i32(AREG(insn, 0), addr, 4);
acf930aa
PB
5646 break;
5647 case 4: /* Pre-decrement. */
e1f3808e 5648 tcg_gen_mov_i32(AREG(insn, 0), addr);
acf930aa 5649 }
24989f0e 5650 tcg_temp_free(loadval);
acf930aa
PB
5651 }
5652}
5653
5654DISAS_INSN(from_mac)
5655{
e1f3808e 5656 TCGv rx;
a7812ae4 5657 TCGv_i64 acc;
e1f3808e 5658 int accnum;
acf930aa
PB
5659
5660 rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e
PB
5661 accnum = (insn >> 9) & 3;
5662 acc = MACREG(accnum);
acf930aa 5663 if (s->env->macsr & MACSR_FI) {
a7812ae4 5664 gen_helper_get_macf(rx, cpu_env, acc);
acf930aa 5665 } else if ((s->env->macsr & MACSR_OMC) == 0) {
ecc7b3aa 5666 tcg_gen_extrl_i64_i32(rx, acc);
acf930aa 5667 } else if (s->env->macsr & MACSR_SU) {
e1f3808e 5668 gen_helper_get_macs(rx, acc);
acf930aa 5669 } else {
e1f3808e
PB
5670 gen_helper_get_macu(rx, acc);
5671 }
5672 if (insn & 0x40) {
5673 tcg_gen_movi_i64(acc, 0);
5674 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
acf930aa 5675 }
acf930aa
PB
5676}
5677
5678DISAS_INSN(move_mac)
5679{
e1f3808e 5680 /* FIXME: This can be done without a helper. */
acf930aa 5681 int src;
e1f3808e 5682 TCGv dest;
acf930aa 5683 src = insn & 3;
e1f3808e
PB
5684 dest = tcg_const_i32((insn >> 9) & 3);
5685 gen_helper_mac_move(cpu_env, dest, tcg_const_i32(src));
5686 gen_mac_clear_flags();
5687 gen_helper_mac_set_flags(cpu_env, dest);
acf930aa
PB
5688}
5689
5690DISAS_INSN(from_macsr)
5691{
e1f3808e 5692 TCGv reg;
acf930aa
PB
5693
5694 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 5695 tcg_gen_mov_i32(reg, QREG_MACSR);
acf930aa
PB
5696}
5697
5698DISAS_INSN(from_mask)
5699{
e1f3808e 5700 TCGv reg;
acf930aa 5701 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 5702 tcg_gen_mov_i32(reg, QREG_MAC_MASK);
acf930aa
PB
5703}
5704
5705DISAS_INSN(from_mext)
5706{
e1f3808e
PB
5707 TCGv reg;
5708 TCGv acc;
acf930aa 5709 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
e1f3808e 5710 acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
acf930aa 5711 if (s->env->macsr & MACSR_FI)
e1f3808e 5712 gen_helper_get_mac_extf(reg, cpu_env, acc);
acf930aa 5713 else
e1f3808e 5714 gen_helper_get_mac_exti(reg, cpu_env, acc);
acf930aa
PB
5715}
5716
5717DISAS_INSN(macsr_to_ccr)
5718{
620c6cf6
RH
5719 TCGv tmp = tcg_temp_new();
5720 tcg_gen_andi_i32(tmp, QREG_MACSR, 0xf);
5721 gen_helper_set_sr(cpu_env, tmp);
5722 tcg_temp_free(tmp);
9fdb533f 5723 set_cc_op(s, CC_OP_FLAGS);
acf930aa
PB
5724}
5725
5726DISAS_INSN(to_mac)
5727{
a7812ae4 5728 TCGv_i64 acc;
e1f3808e
PB
5729 TCGv val;
5730 int accnum;
5731 accnum = (insn >> 9) & 3;
5732 acc = MACREG(accnum);
d4d79bb1 5733 SRC_EA(env, val, OS_LONG, 0, NULL);
acf930aa 5734 if (s->env->macsr & MACSR_FI) {
e1f3808e
PB
5735 tcg_gen_ext_i32_i64(acc, val);
5736 tcg_gen_shli_i64(acc, acc, 8);
acf930aa 5737 } else if (s->env->macsr & MACSR_SU) {
e1f3808e 5738 tcg_gen_ext_i32_i64(acc, val);
acf930aa 5739 } else {
e1f3808e 5740 tcg_gen_extu_i32_i64(acc, val);
acf930aa 5741 }
e1f3808e
PB
5742 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
5743 gen_mac_clear_flags();
5744 gen_helper_mac_set_flags(cpu_env, tcg_const_i32(accnum));
acf930aa
PB
5745}
5746
5747DISAS_INSN(to_macsr)
5748{
e1f3808e 5749 TCGv val;
d4d79bb1 5750 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 5751 gen_helper_set_macsr(cpu_env, val);
acf930aa
PB
5752 gen_lookup_tb(s);
5753}
5754
5755DISAS_INSN(to_mask)
5756{
e1f3808e 5757 TCGv val;
d4d79bb1 5758 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 5759 tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000);
acf930aa
PB
5760}
5761
5762DISAS_INSN(to_mext)
5763{
e1f3808e
PB
5764 TCGv val;
5765 TCGv acc;
d4d79bb1 5766 SRC_EA(env, val, OS_LONG, 0, NULL);
e1f3808e 5767 acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
acf930aa 5768 if (s->env->macsr & MACSR_FI)
e1f3808e 5769 gen_helper_set_mac_extf(cpu_env, val, acc);
acf930aa 5770 else if (s->env->macsr & MACSR_SU)
e1f3808e 5771 gen_helper_set_mac_exts(cpu_env, val, acc);
acf930aa 5772 else
e1f3808e 5773 gen_helper_set_mac_extu(cpu_env, val, acc);
acf930aa
PB
5774}
5775
e6e5906b
PB
5776static disas_proc opcode_table[65536];
5777
5778static void
5779register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
5780{
5781 int i;
5782 int from;
5783 int to;
5784
5785 /* Sanity check. All set bits must be included in the mask. */
5fc4adf6
PB
5786 if (opcode & ~mask) {
5787 fprintf(stderr,
5788 "qemu internal error: bogus opcode definition %04x/%04x\n",
5789 opcode, mask);
e6e5906b 5790 abort();
5fc4adf6 5791 }
e6e5906b
PB
5792 /* This could probably be cleverer. For now just optimize the case where
5793 the top bits are known. */
5794 /* Find the first zero bit in the mask. */
5795 i = 0x8000;
5796 while ((i & mask) != 0)
5797 i >>= 1;
5798 /* Iterate over all combinations of this and lower bits. */
5799 if (i == 0)
5800 i = 1;
5801 else
5802 i <<= 1;
5803 from = opcode & ~(i - 1);
5804 to = from + i;
0633879f 5805 for (i = from; i < to; i++) {
e6e5906b
PB
5806 if ((i & mask) == opcode)
5807 opcode_table[i] = proc;
0633879f 5808 }
e6e5906b
PB
5809}
5810
5811/* Register m68k opcode handlers. Order is important.
5812 Later insn override earlier ones. */
0402f767 5813void register_m68k_insns (CPUM68KState *env)
e6e5906b 5814{
b2085257
JPAG
5815 /* Build the opcode table only once to avoid
5816 multithreading issues. */
5817 if (opcode_table[0] != NULL) {
5818 return;
5819 }
f076803b
LV
5820
5821 /* use BASE() for instruction available
5822 * for CF_ISA_A and M68000.
5823 */
5824#define BASE(name, opcode, mask) \
5825 register_opcode(disas_##name, 0x##opcode, 0x##mask)
d315c888 5826#define INSN(name, opcode, mask, feature) do { \
0402f767 5827 if (m68k_feature(env, M68K_FEATURE_##feature)) \
f076803b 5828 BASE(name, opcode, mask); \
d315c888 5829 } while(0)
f076803b 5830 BASE(undef, 0000, 0000);
0402f767 5831 INSN(arith_im, 0080, fff8, CF_ISA_A);
f076803b 5832 INSN(arith_im, 0000, ff00, M68000);
8bf6cbaf 5833 INSN(chk2, 00c0, f9c0, CHK2);
d315c888 5834 INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC);
f076803b
LV
5835 BASE(bitop_reg, 0100, f1c0);
5836 BASE(bitop_reg, 0140, f1c0);
5837 BASE(bitop_reg, 0180, f1c0);
5838 BASE(bitop_reg, 01c0, f1c0);
1226e212 5839 INSN(movep, 0108, f138, MOVEP);
0402f767 5840 INSN(arith_im, 0280, fff8, CF_ISA_A);
f076803b
LV
5841 INSN(arith_im, 0200, ff00, M68000);
5842 INSN(undef, 02c0, ffc0, M68000);
d315c888 5843 INSN(byterev, 02c0, fff8, CF_ISA_APLUSC);
0402f767 5844 INSN(arith_im, 0480, fff8, CF_ISA_A);
f076803b
LV
5845 INSN(arith_im, 0400, ff00, M68000);
5846 INSN(undef, 04c0, ffc0, M68000);
5847 INSN(arith_im, 0600, ff00, M68000);
5848 INSN(undef, 06c0, ffc0, M68000);
d315c888 5849 INSN(ff1, 04c0, fff8, CF_ISA_APLUSC);
0402f767 5850 INSN(arith_im, 0680, fff8, CF_ISA_A);
0402f767 5851 INSN(arith_im, 0c00, ff38, CF_ISA_A);
f076803b
LV
5852 INSN(arith_im, 0c00, ff00, M68000);
5853 BASE(bitop_im, 0800, ffc0);
5854 BASE(bitop_im, 0840, ffc0);
5855 BASE(bitop_im, 0880, ffc0);
5856 BASE(bitop_im, 08c0, ffc0);
5857 INSN(arith_im, 0a80, fff8, CF_ISA_A);
5858 INSN(arith_im, 0a00, ff00, M68000);
5fa9f1f2
LV
5859#if defined(CONFIG_SOFTMMU)
5860 INSN(moves, 0e00, ff00, M68000);
5861#endif
14f94406
LV
5862 INSN(cas, 0ac0, ffc0, CAS);
5863 INSN(cas, 0cc0, ffc0, CAS);
5864 INSN(cas, 0ec0, ffc0, CAS);
5865 INSN(cas2w, 0cfc, ffff, CAS);
5866 INSN(cas2l, 0efc, ffff, CAS);
f076803b
LV
5867 BASE(move, 1000, f000);
5868 BASE(move, 2000, f000);
5869 BASE(move, 3000, f000);
8bf6cbaf 5870 INSN(chk, 4000, f040, M68000);
d315c888 5871 INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
0402f767 5872 INSN(negx, 4080, fff8, CF_ISA_A);
a665a820
RH
5873 INSN(negx, 4000, ff00, M68000);
5874 INSN(undef, 40c0, ffc0, M68000);
0402f767 5875 INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
f076803b
LV
5876 INSN(move_from_sr, 40c0, ffc0, M68000);
5877 BASE(lea, 41c0, f1c0);
5878 BASE(clr, 4200, ff00);
5879 BASE(undef, 42c0, ffc0);
0402f767 5880 INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
7c0eb318 5881 INSN(move_from_ccr, 42c0, ffc0, M68000);
0402f767 5882 INSN(neg, 4480, fff8, CF_ISA_A);
f076803b
LV
5883 INSN(neg, 4400, ff00, M68000);
5884 INSN(undef, 44c0, ffc0, M68000);
5885 BASE(move_to_ccr, 44c0, ffc0);
0402f767 5886 INSN(not, 4680, fff8, CF_ISA_A);
f076803b 5887 INSN(not, 4600, ff00, M68000);
6ad25764 5888#if defined(CONFIG_SOFTMMU)
b6a21d8d 5889 BASE(move_to_sr, 46c0, ffc0);
6ad25764 5890#endif
fb5543d8 5891 INSN(nbcd, 4800, ffc0, M68000);
c630e436 5892 INSN(linkl, 4808, fff8, M68000);
f076803b
LV
5893 BASE(pea, 4840, ffc0);
5894 BASE(swap, 4840, fff8);
71600eda 5895 INSN(bkpt, 4848, fff8, BKPT);
7b542eb9
LV
5896 INSN(movem, 48d0, fbf8, CF_ISA_A);
5897 INSN(movem, 48e8, fbf8, CF_ISA_A);
5898 INSN(movem, 4880, fb80, M68000);
f076803b
LV
5899 BASE(ext, 4880, fff8);
5900 BASE(ext, 48c0, fff8);
5901 BASE(ext, 49c0, fff8);
5902 BASE(tst, 4a00, ff00);
0402f767 5903 INSN(tas, 4ac0, ffc0, CF_ISA_B);
f076803b 5904 INSN(tas, 4ac0, ffc0, M68000);
6ad25764 5905#if defined(CONFIG_SOFTMMU)
0402f767 5906 INSN(halt, 4ac8, ffff, CF_ISA_A);
6ad25764 5907#endif
0402f767 5908 INSN(pulse, 4acc, ffff, CF_ISA_A);
f076803b 5909 BASE(illegal, 4afc, ffff);
0402f767 5910 INSN(mull, 4c00, ffc0, CF_ISA_A);
f076803b 5911 INSN(mull, 4c00, ffc0, LONG_MULDIV);
0402f767 5912 INSN(divl, 4c40, ffc0, CF_ISA_A);
f076803b 5913 INSN(divl, 4c40, ffc0, LONG_MULDIV);
0402f767 5914 INSN(sats, 4c80, fff8, CF_ISA_B);
f076803b
LV
5915 BASE(trap, 4e40, fff0);
5916 BASE(link, 4e50, fff8);
5917 BASE(unlk, 4e58, fff8);
6ad25764 5918#if defined(CONFIG_SOFTMMU)
20dcee94
PB
5919 INSN(move_to_usp, 4e60, fff8, USP);
5920 INSN(move_from_usp, 4e68, fff8, USP);
0bdb2b3b 5921 INSN(reset, 4e70, ffff, M68000);
f076803b
LV
5922 BASE(stop, 4e72, ffff);
5923 BASE(rte, 4e73, ffff);
6e22b28e
LV
5924 INSN(cf_movec, 4e7b, ffff, CF_ISA_A);
5925 INSN(m68k_movec, 4e7a, fffe, M68000);
6ad25764
LV
5926#endif
5927 BASE(nop, 4e71, ffff);
18059c9e 5928 INSN(rtd, 4e74, ffff, RTD);
f076803b 5929 BASE(rts, 4e75, ffff);
f076803b 5930 BASE(jump, 4e80, ffc0);
8a370c6c 5931 BASE(jump, 4ec0, ffc0);
f076803b 5932 INSN(addsubq, 5000, f080, M68000);
8a370c6c 5933 BASE(addsubq, 5080, f0c0);
d5a3cf33
LV
5934 INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */
5935 INSN(scc, 50c0, f0c0, M68000); /* Scc.B <EA> */
beff27ab 5936 INSN(dbcc, 50c8, f0f8, M68000);
0402f767 5937 INSN(tpf, 51f8, fff8, CF_ISA_A);
d315c888
PB
5938
5939 /* Branch instructions. */
f076803b 5940 BASE(branch, 6000, f000);
d315c888 5941 /* Disable long branch instructions, then add back the ones we want. */
f076803b 5942 BASE(undef, 60ff, f0ff); /* All long branches. */
d315c888
PB
5943 INSN(branch, 60ff, f0ff, CF_ISA_B);
5944 INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */
5945 INSN(branch, 60ff, ffff, BRAL);
f076803b 5946 INSN(branch, 60ff, f0ff, BCCL);
d315c888 5947
f076803b 5948 BASE(moveq, 7000, f100);
0402f767 5949 INSN(mvzs, 7100, f100, CF_ISA_B);
f076803b
LV
5950 BASE(or, 8000, f000);
5951 BASE(divw, 80c0, f0c0);
fb5543d8
LV
5952 INSN(sbcd_reg, 8100, f1f8, M68000);
5953 INSN(sbcd_mem, 8108, f1f8, M68000);
f076803b 5954 BASE(addsub, 9000, f000);
a665a820
RH
5955 INSN(undef, 90c0, f0c0, CF_ISA_A);
5956 INSN(subx_reg, 9180, f1f8, CF_ISA_A);
5957 INSN(subx_reg, 9100, f138, M68000);
5958 INSN(subx_mem, 9108, f138, M68000);
0402f767 5959 INSN(suba, 91c0, f1c0, CF_ISA_A);
415f4b62 5960 INSN(suba, 90c0, f0c0, M68000);
acf930aa 5961
f076803b 5962 BASE(undef_mac, a000, f000);
acf930aa
PB
5963 INSN(mac, a000, f100, CF_EMAC);
5964 INSN(from_mac, a180, f9b0, CF_EMAC);
5965 INSN(move_mac, a110, f9fc, CF_EMAC);
5966 INSN(from_macsr,a980, f9f0, CF_EMAC);
5967 INSN(from_mask, ad80, fff0, CF_EMAC);
5968 INSN(from_mext, ab80, fbf0, CF_EMAC);
5969 INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
5970 INSN(to_mac, a100, f9c0, CF_EMAC);
5971 INSN(to_macsr, a900, ffc0, CF_EMAC);
5972 INSN(to_mext, ab00, fbc0, CF_EMAC);
5973 INSN(to_mask, ad00, ffc0, CF_EMAC);
5974
0402f767
PB
5975 INSN(mov3q, a140, f1c0, CF_ISA_B);
5976 INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */
5977 INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */
5978 INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */
5979 INSN(cmp, b080, f1c0, CF_ISA_A);
5980 INSN(cmpa, b1c0, f1c0, CF_ISA_A);
f076803b
LV
5981 INSN(cmp, b000, f100, M68000);
5982 INSN(eor, b100, f100, M68000);
817af1c7 5983 INSN(cmpm, b108, f138, M68000);
f076803b 5984 INSN(cmpa, b0c0, f0c0, M68000);
0402f767 5985 INSN(eor, b180, f1c0, CF_ISA_A);
f076803b 5986 BASE(and, c000, f000);
29cf437d
LV
5987 INSN(exg_dd, c140, f1f8, M68000);
5988 INSN(exg_aa, c148, f1f8, M68000);
5989 INSN(exg_da, c188, f1f8, M68000);
f076803b 5990 BASE(mulw, c0c0, f0c0);
fb5543d8
LV
5991 INSN(abcd_reg, c100, f1f8, M68000);
5992 INSN(abcd_mem, c108, f1f8, M68000);
f076803b 5993 BASE(addsub, d000, f000);
a665a820
RH
5994 INSN(undef, d0c0, f0c0, CF_ISA_A);
5995 INSN(addx_reg, d180, f1f8, CF_ISA_A);
5996 INSN(addx_reg, d100, f138, M68000);
5997 INSN(addx_mem, d108, f138, M68000);
0402f767 5998 INSN(adda, d1c0, f1c0, CF_ISA_A);
f076803b 5999 INSN(adda, d0c0, f0c0, M68000);
0402f767
PB
6000 INSN(shift_im, e080, f0f0, CF_ISA_A);
6001 INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
367790cc
RH
6002 INSN(shift8_im, e000, f0f0, M68000);
6003 INSN(shift16_im, e040, f0f0, M68000);
6004 INSN(shift_im, e080, f0f0, M68000);
6005 INSN(shift8_reg, e020, f0f0, M68000);
6006 INSN(shift16_reg, e060, f0f0, M68000);
6007 INSN(shift_reg, e0a0, f0f0, M68000);
6008 INSN(shift_mem, e0c0, fcc0, M68000);
0194cf31
LV
6009 INSN(rotate_im, e090, f0f0, M68000);
6010 INSN(rotate8_im, e010, f0f0, M68000);
6011 INSN(rotate16_im, e050, f0f0, M68000);
6012 INSN(rotate_reg, e0b0, f0f0, M68000);
6013 INSN(rotate8_reg, e030, f0f0, M68000);
6014 INSN(rotate16_reg, e070, f0f0, M68000);
6015 INSN(rotate_mem, e4c0, fcc0, M68000);
f2224f2c
RH
6016 INSN(bfext_mem, e9c0, fdc0, BITFIELD); /* bfextu & bfexts */
6017 INSN(bfext_reg, e9c0, fdf8, BITFIELD);
6018 INSN(bfins_mem, efc0, ffc0, BITFIELD);
ac815f46 6019 INSN(bfins_reg, efc0, fff8, BITFIELD);
f2224f2c 6020 INSN(bfop_mem, eac0, ffc0, BITFIELD); /* bfchg */
ac815f46 6021 INSN(bfop_reg, eac0, fff8, BITFIELD); /* bfchg */
f2224f2c 6022 INSN(bfop_mem, ecc0, ffc0, BITFIELD); /* bfclr */
ac815f46 6023 INSN(bfop_reg, ecc0, fff8, BITFIELD); /* bfclr */
a45f1763
RH
6024 INSN(bfop_mem, edc0, ffc0, BITFIELD); /* bfffo */
6025 INSN(bfop_reg, edc0, fff8, BITFIELD); /* bfffo */
f2224f2c 6026 INSN(bfop_mem, eec0, ffc0, BITFIELD); /* bfset */
ac815f46 6027 INSN(bfop_reg, eec0, fff8, BITFIELD); /* bfset */
f2224f2c 6028 INSN(bfop_mem, e8c0, ffc0, BITFIELD); /* bftst */
ac815f46 6029 INSN(bfop_reg, e8c0, fff8, BITFIELD); /* bftst */
f83311e4 6030 BASE(undef_fpu, f000, f000);
e6e5906b
PB
6031 INSN(fpu, f200, ffc0, CF_FPU);
6032 INSN(fbcc, f280, ffc0, CF_FPU);
f83311e4 6033 INSN(fpu, f200, ffc0, FPU);
dd337bf8 6034 INSN(fscc, f240, ffc0, FPU);
f83311e4 6035 INSN(fbcc, f280, ff80, FPU);
6ad25764
LV
6036#if defined(CONFIG_SOFTMMU)
6037 INSN(frestore, f340, ffc0, CF_FPU);
6038 INSN(fsave, f300, ffc0, CF_FPU);
f83311e4
LV
6039 INSN(frestore, f340, ffc0, FPU);
6040 INSN(fsave, f300, ffc0, FPU);
0402f767
PB
6041 INSN(intouch, f340, ffc0, CF_ISA_A);
6042 INSN(cpushl, f428, ff38, CF_ISA_A);
f58ed1c5
LV
6043 INSN(cpush, f420, ff20, M68040);
6044 INSN(cinv, f400, ff20, M68040);
e55886c3
LV
6045 INSN(pflush, f500, ffe0, M68040);
6046 INSN(ptest, f548, ffd8, M68040);
0402f767
PB
6047 INSN(wddata, fb00, ff00, CF_ISA_A);
6048 INSN(wdebug, fbc0, ffc0, CF_ISA_A);
6ad25764
LV
6049#endif
6050 INSN(move16_mem, f600, ffe0, M68040);
6051 INSN(move16_reg, f620, fff8, M68040);
e6e5906b
PB
6052#undef INSN
6053}
6054
6055/* ??? Some of this implementation is not exception safe. We should always
6056 write back the result to memory before setting the condition codes. */
2b3e3cfe 6057static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
e6e5906b 6058{
8a1e52b6 6059 uint16_t insn = read_im16(env, s);
d4d79bb1 6060 opcode_table[insn](env, s, insn);
8a1e52b6 6061 do_writebacks(s);
ecc207d2 6062 do_release(s);
e6e5906b
PB
6063}
6064
e6e5906b 6065/* generate intermediate code for basic block 'tb'. */
9c489ea6 6066void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
e6e5906b 6067{
9c489ea6 6068 CPUM68KState *env = cs->env_ptr;
e6e5906b 6069 DisasContext dc1, *dc = &dc1;
e6e5906b
PB
6070 target_ulong pc_start;
6071 int pc_offset;
2e70f6ef
PB
6072 int num_insns;
6073 int max_insns;
e6e5906b
PB
6074
6075 /* generate intermediate code */
6076 pc_start = tb->pc;
3b46e624 6077
e6e5906b
PB
6078 dc->tb = tb;
6079
e6dbd3b3 6080 dc->env = env;
e6e5906b
PB
6081 dc->is_jmp = DISAS_NEXT;
6082 dc->pc = pc_start;
6083 dc->cc_op = CC_OP_DYNAMIC;
620c6cf6 6084 dc->cc_op_synced = 1;
ed2803da 6085 dc->singlestep_enabled = cs->singlestep_enabled;
a7812ae4 6086 dc->done_mac = 0;
8a1e52b6 6087 dc->writeback_mask = 0;
2e70f6ef 6088 num_insns = 0;
c5a49c63 6089 max_insns = tb_cflags(tb) & CF_COUNT_MASK;
190ce7fb 6090 if (max_insns == 0) {
2e70f6ef 6091 max_insns = CF_COUNT_MASK;
190ce7fb
RH
6092 }
6093 if (max_insns > TCG_MAX_INSNS) {
6094 max_insns = TCG_MAX_INSNS;
6095 }
2e70f6ef 6096
ecc207d2
LV
6097 init_release_array(dc);
6098
cd42d5b2 6099 gen_tb_start(tb);
e6e5906b 6100 do {
e6e5906b 6101 pc_offset = dc->pc - pc_start;
20a8856e 6102 tcg_gen_insn_start(dc->pc, dc->cc_op);
959082fc 6103 num_insns++;
667b8e29 6104
b933066a
RH
6105 if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
6106 gen_exception(dc, dc->pc, EXCP_DEBUG);
522a0d4e
RH
6107 /* The address covered by the breakpoint must be included in
6108 [tb->pc, tb->pc + tb->size) in order to for it to be
6109 properly cleared -- thus we increment the PC here so that
6110 the logic setting tb->size below does the right thing. */
6111 dc->pc += 2;
b933066a
RH
6112 break;
6113 }
6114
c5a49c63 6115 if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
2e70f6ef 6116 gen_io_start();
667b8e29
RH
6117 }
6118
510ff0b7 6119 dc->insn_pc = dc->pc;
e6e5906b 6120 disas_m68k_insn(env, dc);
fe700adb 6121 } while (!dc->is_jmp && !tcg_op_buf_full() &&
ed2803da 6122 !cs->singlestep_enabled &&
1b530a6d 6123 !singlestep &&
2e70f6ef
PB
6124 (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
6125 num_insns < max_insns);
e6e5906b 6126
c5a49c63 6127 if (tb_cflags(tb) & CF_LAST_IO)
2e70f6ef 6128 gen_io_end();
ed2803da 6129 if (unlikely(cs->singlestep_enabled)) {
e6e5906b
PB
6130 /* Make sure the pc is updated, and raise a debug exception. */
6131 if (!dc->is_jmp) {
9fdb533f 6132 update_cc_op(dc);
e1f3808e 6133 tcg_gen_movi_i32(QREG_PC, dc->pc);
e6e5906b 6134 }
31871141 6135 gen_helper_raise_exception(cpu_env, tcg_const_i32(EXCP_DEBUG));
e6e5906b
PB
6136 } else {
6137 switch(dc->is_jmp) {
6138 case DISAS_NEXT:
9fdb533f 6139 update_cc_op(dc);
e6e5906b
PB
6140 gen_jmp_tb(dc, 0, dc->pc);
6141 break;
e6e5906b 6142 case DISAS_JUMP:
8aaf7da9
RH
6143 /* We updated CC_OP and PC in gen_jmp/gen_jmp_im. */
6144 tcg_gen_lookup_and_goto_ptr();
6145 break;
6146 default:
e6e5906b 6147 case DISAS_UPDATE:
9fdb533f 6148 update_cc_op(dc);
e6e5906b 6149 /* indicate that the hash table must be used to find the next TB */
07ea28b4 6150 tcg_gen_exit_tb(NULL, 0);
e6e5906b 6151 break;
cb4add33 6152 case DISAS_NORETURN:
e6e5906b
PB
6153 /* nothing more to generate */
6154 break;
6155 }
6156 }
806f352d 6157 gen_tb_end(tb, num_insns);
e6e5906b
PB
6158
6159#ifdef DEBUG_DISAS
4910e6e4
RH
6160 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
6161 && qemu_log_in_addr_range(pc_start)) {
1ee73216 6162 qemu_log_lock();
93fcfe39
AL
6163 qemu_log("----------------\n");
6164 qemu_log("IN: %s\n", lookup_symbol(pc_start));
1d48474d 6165 log_target_disas(cs, pc_start, dc->pc - pc_start);
93fcfe39 6166 qemu_log("\n");
1ee73216 6167 qemu_log_unlock();
e6e5906b
PB
6168 }
6169#endif
4e5e1215
RH
6170 tb->size = dc->pc - pc_start;
6171 tb->icount = num_insns;
e6e5906b
PB
6172}
6173
f83311e4
LV
6174static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low)
6175{
6176 floatx80 a = { .high = high, .low = low };
6177 union {
6178 float64 f64;
6179 double d;
6180 } u;
6181
6182 u.f64 = floatx80_to_float64(a, &env->fp_status);
6183 return u.d;
6184}
6185
878096ee
AF
6186void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
6187 int flags)
e6e5906b 6188{
878096ee
AF
6189 M68kCPU *cpu = M68K_CPU(cs);
6190 CPUM68KState *env = &cpu->env;
e6e5906b
PB
6191 int i;
6192 uint16_t sr;
f83311e4
LV
6193 for (i = 0; i < 8; i++) {
6194 cpu_fprintf(f, "D%d = %08x A%d = %08x "
6195 "F%d = %04x %016"PRIx64" (%12g)\n",
8e394cca 6196 i, env->dregs[i], i, env->aregs[i],
f83311e4
LV
6197 i, env->fregs[i].l.upper, env->fregs[i].l.lower,
6198 floatx80_to_double(env, env->fregs[i].l.upper,
6199 env->fregs[i].l.lower));
6200 }
e6e5906b 6201 cpu_fprintf (f, "PC = %08x ", env->pc);
99c51448 6202 sr = env->sr | cpu_m68k_get_ccr(env);
cc523026
LV
6203 cpu_fprintf(f, "SR = %04x T:%x I:%x %c%c %c%c%c%c%c\n",
6204 sr, (sr & SR_T) >> SR_T_SHIFT, (sr & SR_I) >> SR_I_SHIFT,
6205 (sr & SR_S) ? 'S' : 'U', (sr & SR_M) ? '%' : 'I',
6206 (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-',
6207 (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-',
6208 (sr & CCF_C) ? 'C' : '-');
ba624944
LV
6209 cpu_fprintf(f, "FPSR = %08x %c%c%c%c ", env->fpsr,
6210 (env->fpsr & FPSR_CC_A) ? 'A' : '-',
6211 (env->fpsr & FPSR_CC_I) ? 'I' : '-',
6212 (env->fpsr & FPSR_CC_Z) ? 'Z' : '-',
6213 (env->fpsr & FPSR_CC_N) ? 'N' : '-');
6214 cpu_fprintf(f, "\n "
6215 "FPCR = %04x ", env->fpcr);
6216 switch (env->fpcr & FPCR_PREC_MASK) {
6217 case FPCR_PREC_X:
6218 cpu_fprintf(f, "X ");
6219 break;
6220 case FPCR_PREC_S:
6221 cpu_fprintf(f, "S ");
6222 break;
6223 case FPCR_PREC_D:
6224 cpu_fprintf(f, "D ");
6225 break;
6226 }
6227 switch (env->fpcr & FPCR_RND_MASK) {
6228 case FPCR_RND_N:
6229 cpu_fprintf(f, "RN ");
6230 break;
6231 case FPCR_RND_Z:
6232 cpu_fprintf(f, "RZ ");
6233 break;
6234 case FPCR_RND_M:
6235 cpu_fprintf(f, "RM ");
6236 break;
6237 case FPCR_RND_P:
6238 cpu_fprintf(f, "RP ");
6239 break;
6240 }
6e22b28e
LV
6241 cpu_fprintf(f, "\n");
6242#ifdef CONFIG_SOFTMMU
6243 cpu_fprintf(f, "%sA7(MSP) = %08x %sA7(USP) = %08x %sA7(ISP) = %08x\n",
6244 env->current_sp == M68K_SSP ? "->" : " ", env->sp[M68K_SSP],
6245 env->current_sp == M68K_USP ? "->" : " ", env->sp[M68K_USP],
6246 env->current_sp == M68K_ISP ? "->" : " ", env->sp[M68K_ISP]);
6247 cpu_fprintf(f, "VBR = 0x%08x\n", env->vbr);
5fa9f1f2 6248 cpu_fprintf(f, "SFC = %x DFC %x\n", env->sfc, env->dfc);
88b2fef6
LV
6249 cpu_fprintf(f, "SSW %08x TCR %08x URP %08x SRP %08x\n",
6250 env->mmu.ssw, env->mmu.tcr, env->mmu.urp, env->mmu.srp);
c05c73b0
LV
6251 cpu_fprintf(f, "DTTR0/1: %08x/%08x ITTR0/1: %08x/%08x\n",
6252 env->mmu.ttr[M68K_DTTR0], env->mmu.ttr[M68K_DTTR1],
6253 env->mmu.ttr[M68K_ITTR0], env->mmu.ttr[M68K_ITTR1]);
e55886c3
LV
6254 cpu_fprintf(f, "MMUSR %08x, fault at %08x\n",
6255 env->mmu.mmusr, env->mmu.ar);
6e22b28e 6256#endif
e6e5906b
PB
6257}
6258
bad729e2
RH
6259void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb,
6260 target_ulong *data)
d2856f1a 6261{
20a8856e 6262 int cc_op = data[1];
bad729e2 6263 env->pc = data[0];
20a8856e
LV
6264 if (cc_op != CC_OP_DYNAMIC) {
6265 env->cc_op = cc_op;
6266 }
d2856f1a 6267}
This page took 1.932618 seconds and 4 git commands to generate.