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