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