mv64361: Remove extra break from a switch case
[qemu/kevin.git] / target / m68k / translate.c
blob1fee04b8dd6804128335102113d87e659c32ddf8
1 /*
2 * m68k translation
4 * Copyright (c) 2005-2007 CodeSourcery
5 * Written by Paul Brook
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.1 of the License, or (at your option) any later version.
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 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "disas/disas.h"
24 #include "exec/exec-all.h"
25 #include "tcg/tcg-op.h"
26 #include "qemu/log.h"
27 #include "qemu/qemu-print.h"
28 #include "exec/cpu_ldst.h"
29 #include "exec/translator.h"
31 #include "exec/helper-proto.h"
32 #include "exec/helper-gen.h"
34 #include "exec/log.h"
35 #include "fpu/softfloat.h"
38 //#define DEBUG_DISPATCH 1
40 #define DEFO32(name, offset) static TCGv QREG_##name;
41 #define DEFO64(name, offset) static TCGv_i64 QREG_##name;
42 #include "qregs.def"
43 #undef DEFO32
44 #undef DEFO64
46 static TCGv_i32 cpu_halted;
47 static TCGv_i32 cpu_exception_index;
49 static char cpu_reg_names[2 * 8 * 3 + 5 * 4];
50 static TCGv cpu_dregs[8];
51 static TCGv cpu_aregs[8];
52 static TCGv_i64 cpu_macc[4];
54 #define REG(insn, pos) (((insn) >> (pos)) & 7)
55 #define DREG(insn, pos) cpu_dregs[REG(insn, pos)]
56 #define AREG(insn, pos) get_areg(s, REG(insn, pos))
57 #define MACREG(acc) cpu_macc[acc]
58 #define QREG_SP get_areg(s, 7)
60 static TCGv NULL_QREG;
61 #define IS_NULL_QREG(t) (t == NULL_QREG)
62 /* Used to distinguish stores from bad addressing modes. */
63 static TCGv store_dummy;
65 #include "exec/gen-icount.h"
67 void m68k_tcg_init(void)
69 char *p;
70 int i;
72 #define DEFO32(name, offset) \
73 QREG_##name = tcg_global_mem_new_i32(cpu_env, \
74 offsetof(CPUM68KState, offset), #name);
75 #define DEFO64(name, offset) \
76 QREG_##name = tcg_global_mem_new_i64(cpu_env, \
77 offsetof(CPUM68KState, offset), #name);
78 #include "qregs.def"
79 #undef DEFO32
80 #undef DEFO64
82 cpu_halted = tcg_global_mem_new_i32(cpu_env,
83 -offsetof(M68kCPU, env) +
84 offsetof(CPUState, halted), "HALTED");
85 cpu_exception_index = tcg_global_mem_new_i32(cpu_env,
86 -offsetof(M68kCPU, env) +
87 offsetof(CPUState, exception_index),
88 "EXCEPTION");
90 p = cpu_reg_names;
91 for (i = 0; i < 8; i++) {
92 sprintf(p, "D%d", i);
93 cpu_dregs[i] = tcg_global_mem_new(cpu_env,
94 offsetof(CPUM68KState, dregs[i]), p);
95 p += 3;
96 sprintf(p, "A%d", i);
97 cpu_aregs[i] = tcg_global_mem_new(cpu_env,
98 offsetof(CPUM68KState, aregs[i]), p);
99 p += 3;
101 for (i = 0; i < 4; i++) {
102 sprintf(p, "ACC%d", i);
103 cpu_macc[i] = tcg_global_mem_new_i64(cpu_env,
104 offsetof(CPUM68KState, macc[i]), p);
105 p += 5;
108 NULL_QREG = tcg_global_mem_new(cpu_env, -4, "NULL");
109 store_dummy = tcg_global_mem_new(cpu_env, -8, "NULL");
112 /* internal defines */
113 typedef struct DisasContext {
114 DisasContextBase base;
115 CPUM68KState *env;
116 target_ulong pc;
117 CCOp cc_op; /* Current CC operation */
118 int cc_op_synced;
119 TCGv_i64 mactmp;
120 int done_mac;
121 int writeback_mask;
122 TCGv writeback[8];
123 #define MAX_TO_RELEASE 8
124 int release_count;
125 TCGv release[MAX_TO_RELEASE];
126 bool ss_active;
127 } DisasContext;
129 static void init_release_array(DisasContext *s)
131 #ifdef CONFIG_DEBUG_TCG
132 memset(s->release, 0, sizeof(s->release));
133 #endif
134 s->release_count = 0;
137 static void do_release(DisasContext *s)
139 int i;
140 for (i = 0; i < s->release_count; i++) {
141 tcg_temp_free(s->release[i]);
143 init_release_array(s);
146 static TCGv mark_to_release(DisasContext *s, TCGv tmp)
148 g_assert(s->release_count < MAX_TO_RELEASE);
149 return s->release[s->release_count++] = tmp;
152 static TCGv get_areg(DisasContext *s, unsigned regno)
154 if (s->writeback_mask & (1 << regno)) {
155 return s->writeback[regno];
156 } else {
157 return cpu_aregs[regno];
161 static void delay_set_areg(DisasContext *s, unsigned regno,
162 TCGv val, bool give_temp)
164 if (s->writeback_mask & (1 << regno)) {
165 if (give_temp) {
166 tcg_temp_free(s->writeback[regno]);
167 s->writeback[regno] = val;
168 } else {
169 tcg_gen_mov_i32(s->writeback[regno], val);
171 } else {
172 s->writeback_mask |= 1 << regno;
173 if (give_temp) {
174 s->writeback[regno] = val;
175 } else {
176 TCGv tmp = tcg_temp_new();
177 s->writeback[regno] = tmp;
178 tcg_gen_mov_i32(tmp, val);
183 static void do_writebacks(DisasContext *s)
185 unsigned mask = s->writeback_mask;
186 if (mask) {
187 s->writeback_mask = 0;
188 do {
189 unsigned regno = ctz32(mask);
190 tcg_gen_mov_i32(cpu_aregs[regno], s->writeback[regno]);
191 tcg_temp_free(s->writeback[regno]);
192 mask &= mask - 1;
193 } while (mask);
197 static bool is_singlestepping(DisasContext *s)
200 * Return true if we are singlestepping either because of
201 * architectural singlestep or QEMU gdbstub singlestep. This does
202 * not include the command line '-singlestep' mode which is rather
203 * misnamed as it only means "one instruction per TB" and doesn't
204 * affect the code we generate.
206 return s->base.singlestep_enabled || s->ss_active;
209 /* is_jmp field values */
210 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
211 #define DISAS_EXIT DISAS_TARGET_1 /* cpu state was modified dynamically */
213 #if defined(CONFIG_USER_ONLY)
214 #define IS_USER(s) 1
215 #else
216 #define IS_USER(s) (!(s->base.tb->flags & TB_FLAGS_MSR_S))
217 #define SFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_SFC_S) ? \
218 MMU_KERNEL_IDX : MMU_USER_IDX)
219 #define DFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_DFC_S) ? \
220 MMU_KERNEL_IDX : MMU_USER_IDX)
221 #endif
223 typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn);
225 #ifdef DEBUG_DISPATCH
226 #define DISAS_INSN(name) \
227 static void real_disas_##name(CPUM68KState *env, DisasContext *s, \
228 uint16_t insn); \
229 static void disas_##name(CPUM68KState *env, DisasContext *s, \
230 uint16_t insn) \
232 qemu_log("Dispatch " #name "\n"); \
233 real_disas_##name(env, s, insn); \
235 static void real_disas_##name(CPUM68KState *env, DisasContext *s, \
236 uint16_t insn)
237 #else
238 #define DISAS_INSN(name) \
239 static void disas_##name(CPUM68KState *env, DisasContext *s, \
240 uint16_t insn)
241 #endif
243 static const uint8_t cc_op_live[CC_OP_NB] = {
244 [CC_OP_DYNAMIC] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
245 [CC_OP_FLAGS] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
246 [CC_OP_ADDB ... CC_OP_ADDL] = CCF_X | CCF_N | CCF_V,
247 [CC_OP_SUBB ... CC_OP_SUBL] = CCF_X | CCF_N | CCF_V,
248 [CC_OP_CMPB ... CC_OP_CMPL] = CCF_X | CCF_N | CCF_V,
249 [CC_OP_LOGIC] = CCF_X | CCF_N
252 static void set_cc_op(DisasContext *s, CCOp op)
254 CCOp old_op = s->cc_op;
255 int dead;
257 if (old_op == op) {
258 return;
260 s->cc_op = op;
261 s->cc_op_synced = 0;
264 * Discard CC computation that will no longer be used.
265 * Note that X and N are never dead.
267 dead = cc_op_live[old_op] & ~cc_op_live[op];
268 if (dead & CCF_C) {
269 tcg_gen_discard_i32(QREG_CC_C);
271 if (dead & CCF_Z) {
272 tcg_gen_discard_i32(QREG_CC_Z);
274 if (dead & CCF_V) {
275 tcg_gen_discard_i32(QREG_CC_V);
279 /* Update the CPU env CC_OP state. */
280 static void update_cc_op(DisasContext *s)
282 if (!s->cc_op_synced) {
283 s->cc_op_synced = 1;
284 tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
288 /* Generate a jump to an immediate address. */
289 static void gen_jmp_im(DisasContext *s, uint32_t dest)
291 update_cc_op(s);
292 tcg_gen_movi_i32(QREG_PC, dest);
293 s->base.is_jmp = DISAS_JUMP;
296 /* Generate a jump to the address in qreg DEST. */
297 static void gen_jmp(DisasContext *s, TCGv dest)
299 update_cc_op(s);
300 tcg_gen_mov_i32(QREG_PC, dest);
301 s->base.is_jmp = DISAS_JUMP;
304 static void gen_raise_exception(int nr)
306 TCGv_i32 tmp;
308 tmp = tcg_const_i32(nr);
309 gen_helper_raise_exception(cpu_env, tmp);
310 tcg_temp_free_i32(tmp);
313 static void gen_exception(DisasContext *s, uint32_t dest, int nr)
315 update_cc_op(s);
316 tcg_gen_movi_i32(QREG_PC, dest);
318 gen_raise_exception(nr);
320 s->base.is_jmp = DISAS_NORETURN;
323 static void gen_singlestep_exception(DisasContext *s)
326 * Generate the right kind of exception for singlestep, which is
327 * either the architectural singlestep or EXCP_DEBUG for QEMU's
328 * gdb singlestepping.
330 if (s->ss_active) {
331 gen_raise_exception(EXCP_TRACE);
332 } else {
333 gen_raise_exception(EXCP_DEBUG);
337 static inline void gen_addr_fault(DisasContext *s)
339 gen_exception(s, s->base.pc_next, EXCP_ADDRESS);
343 * Generate a load from the specified address. Narrow values are
344 * sign extended to full register width.
346 static inline TCGv gen_load(DisasContext *s, int opsize, TCGv addr,
347 int sign, int index)
349 TCGv tmp;
350 tmp = tcg_temp_new_i32();
351 switch(opsize) {
352 case OS_BYTE:
353 if (sign)
354 tcg_gen_qemu_ld8s(tmp, addr, index);
355 else
356 tcg_gen_qemu_ld8u(tmp, addr, index);
357 break;
358 case OS_WORD:
359 if (sign)
360 tcg_gen_qemu_ld16s(tmp, addr, index);
361 else
362 tcg_gen_qemu_ld16u(tmp, addr, index);
363 break;
364 case OS_LONG:
365 tcg_gen_qemu_ld32u(tmp, addr, index);
366 break;
367 default:
368 g_assert_not_reached();
370 return tmp;
373 /* Generate a store. */
374 static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val,
375 int index)
377 switch(opsize) {
378 case OS_BYTE:
379 tcg_gen_qemu_st8(val, addr, index);
380 break;
381 case OS_WORD:
382 tcg_gen_qemu_st16(val, addr, index);
383 break;
384 case OS_LONG:
385 tcg_gen_qemu_st32(val, addr, index);
386 break;
387 default:
388 g_assert_not_reached();
392 typedef enum {
393 EA_STORE,
394 EA_LOADU,
395 EA_LOADS
396 } ea_what;
399 * Generate an unsigned load if VAL is 0 a signed load if val is -1,
400 * otherwise generate a store.
402 static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
403 ea_what what, int index)
405 if (what == EA_STORE) {
406 gen_store(s, opsize, addr, val, index);
407 return store_dummy;
408 } else {
409 return mark_to_release(s, gen_load(s, opsize, addr,
410 what == EA_LOADS, index));
414 /* Read a 16-bit immediate constant */
415 static inline uint16_t read_im16(CPUM68KState *env, DisasContext *s)
417 uint16_t im;
418 im = translator_lduw(env, s->pc);
419 s->pc += 2;
420 return im;
423 /* Read an 8-bit immediate constant */
424 static inline uint8_t read_im8(CPUM68KState *env, DisasContext *s)
426 return read_im16(env, s);
429 /* Read a 32-bit immediate constant. */
430 static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s)
432 uint32_t im;
433 im = read_im16(env, s) << 16;
434 im |= 0xffff & read_im16(env, s);
435 return im;
438 /* Read a 64-bit immediate constant. */
439 static inline uint64_t read_im64(CPUM68KState *env, DisasContext *s)
441 uint64_t im;
442 im = (uint64_t)read_im32(env, s) << 32;
443 im |= (uint64_t)read_im32(env, s);
444 return im;
447 /* Calculate and address index. */
448 static TCGv gen_addr_index(DisasContext *s, uint16_t ext, TCGv tmp)
450 TCGv add;
451 int scale;
453 add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
454 if ((ext & 0x800) == 0) {
455 tcg_gen_ext16s_i32(tmp, add);
456 add = tmp;
458 scale = (ext >> 9) & 3;
459 if (scale != 0) {
460 tcg_gen_shli_i32(tmp, add, scale);
461 add = tmp;
463 return add;
467 * Handle a base + index + displacement effective address.
468 * A NULL_QREG base means pc-relative.
470 static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
472 uint32_t offset;
473 uint16_t ext;
474 TCGv add;
475 TCGv tmp;
476 uint32_t bd, od;
478 offset = s->pc;
479 ext = read_im16(env, s);
481 if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
482 return NULL_QREG;
484 if (m68k_feature(s->env, M68K_FEATURE_M68000) &&
485 !m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX)) {
486 ext &= ~(3 << 9);
489 if (ext & 0x100) {
490 /* full extension word format */
491 if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
492 return NULL_QREG;
494 if ((ext & 0x30) > 0x10) {
495 /* base displacement */
496 if ((ext & 0x30) == 0x20) {
497 bd = (int16_t)read_im16(env, s);
498 } else {
499 bd = read_im32(env, s);
501 } else {
502 bd = 0;
504 tmp = mark_to_release(s, tcg_temp_new());
505 if ((ext & 0x44) == 0) {
506 /* pre-index */
507 add = gen_addr_index(s, ext, tmp);
508 } else {
509 add = NULL_QREG;
511 if ((ext & 0x80) == 0) {
512 /* base not suppressed */
513 if (IS_NULL_QREG(base)) {
514 base = mark_to_release(s, tcg_const_i32(offset + bd));
515 bd = 0;
517 if (!IS_NULL_QREG(add)) {
518 tcg_gen_add_i32(tmp, add, base);
519 add = tmp;
520 } else {
521 add = base;
524 if (!IS_NULL_QREG(add)) {
525 if (bd != 0) {
526 tcg_gen_addi_i32(tmp, add, bd);
527 add = tmp;
529 } else {
530 add = mark_to_release(s, tcg_const_i32(bd));
532 if ((ext & 3) != 0) {
533 /* memory indirect */
534 base = mark_to_release(s, gen_load(s, OS_LONG, add, 0, IS_USER(s)));
535 if ((ext & 0x44) == 4) {
536 add = gen_addr_index(s, ext, tmp);
537 tcg_gen_add_i32(tmp, add, base);
538 add = tmp;
539 } else {
540 add = base;
542 if ((ext & 3) > 1) {
543 /* outer displacement */
544 if ((ext & 3) == 2) {
545 od = (int16_t)read_im16(env, s);
546 } else {
547 od = read_im32(env, s);
549 } else {
550 od = 0;
552 if (od != 0) {
553 tcg_gen_addi_i32(tmp, add, od);
554 add = tmp;
557 } else {
558 /* brief extension word format */
559 tmp = mark_to_release(s, tcg_temp_new());
560 add = gen_addr_index(s, ext, tmp);
561 if (!IS_NULL_QREG(base)) {
562 tcg_gen_add_i32(tmp, add, base);
563 if ((int8_t)ext)
564 tcg_gen_addi_i32(tmp, tmp, (int8_t)ext);
565 } else {
566 tcg_gen_addi_i32(tmp, add, offset + (int8_t)ext);
568 add = tmp;
570 return add;
573 /* Sign or zero extend a value. */
575 static inline void gen_ext(TCGv res, TCGv val, int opsize, int sign)
577 switch (opsize) {
578 case OS_BYTE:
579 if (sign) {
580 tcg_gen_ext8s_i32(res, val);
581 } else {
582 tcg_gen_ext8u_i32(res, val);
584 break;
585 case OS_WORD:
586 if (sign) {
587 tcg_gen_ext16s_i32(res, val);
588 } else {
589 tcg_gen_ext16u_i32(res, val);
591 break;
592 case OS_LONG:
593 tcg_gen_mov_i32(res, val);
594 break;
595 default:
596 g_assert_not_reached();
600 /* Evaluate all the CC flags. */
602 static void gen_flush_flags(DisasContext *s)
604 TCGv t0, t1;
606 switch (s->cc_op) {
607 case CC_OP_FLAGS:
608 return;
610 case CC_OP_ADDB:
611 case CC_OP_ADDW:
612 case CC_OP_ADDL:
613 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
614 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
615 /* Compute signed overflow for addition. */
616 t0 = tcg_temp_new();
617 t1 = tcg_temp_new();
618 tcg_gen_sub_i32(t0, QREG_CC_N, QREG_CC_V);
619 gen_ext(t0, t0, s->cc_op - CC_OP_ADDB, 1);
620 tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V);
621 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
622 tcg_temp_free(t0);
623 tcg_gen_andc_i32(QREG_CC_V, t1, QREG_CC_V);
624 tcg_temp_free(t1);
625 break;
627 case CC_OP_SUBB:
628 case CC_OP_SUBW:
629 case CC_OP_SUBL:
630 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
631 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
632 /* Compute signed overflow for subtraction. */
633 t0 = tcg_temp_new();
634 t1 = tcg_temp_new();
635 tcg_gen_add_i32(t0, QREG_CC_N, QREG_CC_V);
636 gen_ext(t0, t0, s->cc_op - CC_OP_SUBB, 1);
637 tcg_gen_xor_i32(t1, QREG_CC_N, t0);
638 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
639 tcg_temp_free(t0);
640 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t1);
641 tcg_temp_free(t1);
642 break;
644 case CC_OP_CMPB:
645 case CC_OP_CMPW:
646 case CC_OP_CMPL:
647 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_C, QREG_CC_N, QREG_CC_V);
648 tcg_gen_sub_i32(QREG_CC_Z, QREG_CC_N, QREG_CC_V);
649 gen_ext(QREG_CC_Z, QREG_CC_Z, s->cc_op - CC_OP_CMPB, 1);
650 /* Compute signed overflow for subtraction. */
651 t0 = tcg_temp_new();
652 tcg_gen_xor_i32(t0, QREG_CC_Z, QREG_CC_N);
653 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, QREG_CC_N);
654 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t0);
655 tcg_temp_free(t0);
656 tcg_gen_mov_i32(QREG_CC_N, QREG_CC_Z);
657 break;
659 case CC_OP_LOGIC:
660 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
661 tcg_gen_movi_i32(QREG_CC_C, 0);
662 tcg_gen_movi_i32(QREG_CC_V, 0);
663 break;
665 case CC_OP_DYNAMIC:
666 gen_helper_flush_flags(cpu_env, QREG_CC_OP);
667 s->cc_op_synced = 1;
668 break;
670 default:
671 t0 = tcg_const_i32(s->cc_op);
672 gen_helper_flush_flags(cpu_env, t0);
673 tcg_temp_free(t0);
674 s->cc_op_synced = 1;
675 break;
678 /* Note that flush_flags also assigned to env->cc_op. */
679 s->cc_op = CC_OP_FLAGS;
682 static inline TCGv gen_extend(DisasContext *s, TCGv val, int opsize, int sign)
684 TCGv tmp;
686 if (opsize == OS_LONG) {
687 tmp = val;
688 } else {
689 tmp = mark_to_release(s, tcg_temp_new());
690 gen_ext(tmp, val, opsize, sign);
693 return tmp;
696 static void gen_logic_cc(DisasContext *s, TCGv val, int opsize)
698 gen_ext(QREG_CC_N, val, opsize, 1);
699 set_cc_op(s, CC_OP_LOGIC);
702 static void gen_update_cc_cmp(DisasContext *s, TCGv dest, TCGv src, int opsize)
704 tcg_gen_mov_i32(QREG_CC_N, dest);
705 tcg_gen_mov_i32(QREG_CC_V, src);
706 set_cc_op(s, CC_OP_CMPB + opsize);
709 static void gen_update_cc_add(TCGv dest, TCGv src, int opsize)
711 gen_ext(QREG_CC_N, dest, opsize, 1);
712 tcg_gen_mov_i32(QREG_CC_V, src);
715 static inline int opsize_bytes(int opsize)
717 switch (opsize) {
718 case OS_BYTE: return 1;
719 case OS_WORD: return 2;
720 case OS_LONG: return 4;
721 case OS_SINGLE: return 4;
722 case OS_DOUBLE: return 8;
723 case OS_EXTENDED: return 12;
724 case OS_PACKED: return 12;
725 default:
726 g_assert_not_reached();
730 static inline int insn_opsize(int insn)
732 switch ((insn >> 6) & 3) {
733 case 0: return OS_BYTE;
734 case 1: return OS_WORD;
735 case 2: return OS_LONG;
736 default:
737 g_assert_not_reached();
741 static inline int ext_opsize(int ext, int pos)
743 switch ((ext >> pos) & 7) {
744 case 0: return OS_LONG;
745 case 1: return OS_SINGLE;
746 case 2: return OS_EXTENDED;
747 case 3: return OS_PACKED;
748 case 4: return OS_WORD;
749 case 5: return OS_DOUBLE;
750 case 6: return OS_BYTE;
751 default:
752 g_assert_not_reached();
757 * Assign value to a register. If the width is less than the register width
758 * only the low part of the register is set.
760 static void gen_partset_reg(int opsize, TCGv reg, TCGv val)
762 TCGv tmp;
763 switch (opsize) {
764 case OS_BYTE:
765 tcg_gen_andi_i32(reg, reg, 0xffffff00);
766 tmp = tcg_temp_new();
767 tcg_gen_ext8u_i32(tmp, val);
768 tcg_gen_or_i32(reg, reg, tmp);
769 tcg_temp_free(tmp);
770 break;
771 case OS_WORD:
772 tcg_gen_andi_i32(reg, reg, 0xffff0000);
773 tmp = tcg_temp_new();
774 tcg_gen_ext16u_i32(tmp, val);
775 tcg_gen_or_i32(reg, reg, tmp);
776 tcg_temp_free(tmp);
777 break;
778 case OS_LONG:
779 case OS_SINGLE:
780 tcg_gen_mov_i32(reg, val);
781 break;
782 default:
783 g_assert_not_reached();
788 * Generate code for an "effective address". Does not adjust the base
789 * register for autoincrement addressing modes.
791 static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
792 int mode, int reg0, int opsize)
794 TCGv reg;
795 TCGv tmp;
796 uint16_t ext;
797 uint32_t offset;
799 switch (mode) {
800 case 0: /* Data register direct. */
801 case 1: /* Address register direct. */
802 return NULL_QREG;
803 case 3: /* Indirect postincrement. */
804 if (opsize == OS_UNSIZED) {
805 return NULL_QREG;
807 /* fallthru */
808 case 2: /* Indirect register */
809 return get_areg(s, reg0);
810 case 4: /* Indirect predecrememnt. */
811 if (opsize == OS_UNSIZED) {
812 return NULL_QREG;
814 reg = get_areg(s, reg0);
815 tmp = mark_to_release(s, tcg_temp_new());
816 if (reg0 == 7 && opsize == OS_BYTE &&
817 m68k_feature(s->env, M68K_FEATURE_M68000)) {
818 tcg_gen_subi_i32(tmp, reg, 2);
819 } else {
820 tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize));
822 return tmp;
823 case 5: /* Indirect displacement. */
824 reg = get_areg(s, reg0);
825 tmp = mark_to_release(s, tcg_temp_new());
826 ext = read_im16(env, s);
827 tcg_gen_addi_i32(tmp, reg, (int16_t)ext);
828 return tmp;
829 case 6: /* Indirect index + displacement. */
830 reg = get_areg(s, reg0);
831 return gen_lea_indexed(env, s, reg);
832 case 7: /* Other */
833 switch (reg0) {
834 case 0: /* Absolute short. */
835 offset = (int16_t)read_im16(env, s);
836 return mark_to_release(s, tcg_const_i32(offset));
837 case 1: /* Absolute long. */
838 offset = read_im32(env, s);
839 return mark_to_release(s, tcg_const_i32(offset));
840 case 2: /* pc displacement */
841 offset = s->pc;
842 offset += (int16_t)read_im16(env, s);
843 return mark_to_release(s, tcg_const_i32(offset));
844 case 3: /* pc index+displacement. */
845 return gen_lea_indexed(env, s, NULL_QREG);
846 case 4: /* Immediate. */
847 default:
848 return NULL_QREG;
851 /* Should never happen. */
852 return NULL_QREG;
855 static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn,
856 int opsize)
858 int mode = extract32(insn, 3, 3);
859 int reg0 = REG(insn, 0);
860 return gen_lea_mode(env, s, mode, reg0, opsize);
864 * Generate code to load/store a value from/into an EA. If WHAT > 0 this is
865 * a write otherwise it is a read (0 == sign extend, -1 == zero extend).
866 * ADDRP is non-null for readwrite operands.
868 static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0,
869 int opsize, TCGv val, TCGv *addrp, ea_what what,
870 int index)
872 TCGv reg, tmp, result;
873 int32_t offset;
875 switch (mode) {
876 case 0: /* Data register direct. */
877 reg = cpu_dregs[reg0];
878 if (what == EA_STORE) {
879 gen_partset_reg(opsize, reg, val);
880 return store_dummy;
881 } else {
882 return gen_extend(s, reg, opsize, what == EA_LOADS);
884 case 1: /* Address register direct. */
885 reg = get_areg(s, reg0);
886 if (what == EA_STORE) {
887 tcg_gen_mov_i32(reg, val);
888 return store_dummy;
889 } else {
890 return gen_extend(s, reg, opsize, what == EA_LOADS);
892 case 2: /* Indirect register */
893 reg = get_areg(s, reg0);
894 return gen_ldst(s, opsize, reg, val, what, index);
895 case 3: /* Indirect postincrement. */
896 reg = get_areg(s, reg0);
897 result = gen_ldst(s, opsize, reg, val, what, index);
898 if (what == EA_STORE || !addrp) {
899 TCGv tmp = tcg_temp_new();
900 if (reg0 == 7 && opsize == OS_BYTE &&
901 m68k_feature(s->env, M68K_FEATURE_M68000)) {
902 tcg_gen_addi_i32(tmp, reg, 2);
903 } else {
904 tcg_gen_addi_i32(tmp, reg, opsize_bytes(opsize));
906 delay_set_areg(s, reg0, tmp, true);
908 return result;
909 case 4: /* Indirect predecrememnt. */
910 if (addrp && what == EA_STORE) {
911 tmp = *addrp;
912 } else {
913 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
914 if (IS_NULL_QREG(tmp)) {
915 return tmp;
917 if (addrp) {
918 *addrp = tmp;
921 result = gen_ldst(s, opsize, tmp, val, what, index);
922 if (what == EA_STORE || !addrp) {
923 delay_set_areg(s, reg0, tmp, false);
925 return result;
926 case 5: /* Indirect displacement. */
927 case 6: /* Indirect index + displacement. */
928 do_indirect:
929 if (addrp && what == EA_STORE) {
930 tmp = *addrp;
931 } else {
932 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
933 if (IS_NULL_QREG(tmp)) {
934 return tmp;
936 if (addrp) {
937 *addrp = tmp;
940 return gen_ldst(s, opsize, tmp, val, what, index);
941 case 7: /* Other */
942 switch (reg0) {
943 case 0: /* Absolute short. */
944 case 1: /* Absolute long. */
945 case 2: /* pc displacement */
946 case 3: /* pc index+displacement. */
947 goto do_indirect;
948 case 4: /* Immediate. */
949 /* Sign extend values for consistency. */
950 switch (opsize) {
951 case OS_BYTE:
952 if (what == EA_LOADS) {
953 offset = (int8_t)read_im8(env, s);
954 } else {
955 offset = read_im8(env, s);
957 break;
958 case OS_WORD:
959 if (what == EA_LOADS) {
960 offset = (int16_t)read_im16(env, s);
961 } else {
962 offset = read_im16(env, s);
964 break;
965 case OS_LONG:
966 offset = read_im32(env, s);
967 break;
968 default:
969 g_assert_not_reached();
971 return mark_to_release(s, tcg_const_i32(offset));
972 default:
973 return NULL_QREG;
976 /* Should never happen. */
977 return NULL_QREG;
980 static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn,
981 int opsize, TCGv val, TCGv *addrp, ea_what what, int index)
983 int mode = extract32(insn, 3, 3);
984 int reg0 = REG(insn, 0);
985 return gen_ea_mode(env, s, mode, reg0, opsize, val, addrp, what, index);
988 static TCGv_ptr gen_fp_ptr(int freg)
990 TCGv_ptr fp = tcg_temp_new_ptr();
991 tcg_gen_addi_ptr(fp, cpu_env, offsetof(CPUM68KState, fregs[freg]));
992 return fp;
995 static TCGv_ptr gen_fp_result_ptr(void)
997 TCGv_ptr fp = tcg_temp_new_ptr();
998 tcg_gen_addi_ptr(fp, cpu_env, offsetof(CPUM68KState, fp_result));
999 return fp;
1002 static void gen_fp_move(TCGv_ptr dest, TCGv_ptr src)
1004 TCGv t32;
1005 TCGv_i64 t64;
1007 t32 = tcg_temp_new();
1008 tcg_gen_ld16u_i32(t32, src, offsetof(FPReg, l.upper));
1009 tcg_gen_st16_i32(t32, dest, offsetof(FPReg, l.upper));
1010 tcg_temp_free(t32);
1012 t64 = tcg_temp_new_i64();
1013 tcg_gen_ld_i64(t64, src, offsetof(FPReg, l.lower));
1014 tcg_gen_st_i64(t64, dest, offsetof(FPReg, l.lower));
1015 tcg_temp_free_i64(t64);
1018 static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
1019 int index)
1021 TCGv tmp;
1022 TCGv_i64 t64;
1024 t64 = tcg_temp_new_i64();
1025 tmp = tcg_temp_new();
1026 switch (opsize) {
1027 case OS_BYTE:
1028 tcg_gen_qemu_ld8s(tmp, addr, index);
1029 gen_helper_exts32(cpu_env, fp, tmp);
1030 break;
1031 case OS_WORD:
1032 tcg_gen_qemu_ld16s(tmp, addr, index);
1033 gen_helper_exts32(cpu_env, fp, tmp);
1034 break;
1035 case OS_LONG:
1036 tcg_gen_qemu_ld32u(tmp, addr, index);
1037 gen_helper_exts32(cpu_env, fp, tmp);
1038 break;
1039 case OS_SINGLE:
1040 tcg_gen_qemu_ld32u(tmp, addr, index);
1041 gen_helper_extf32(cpu_env, fp, tmp);
1042 break;
1043 case OS_DOUBLE:
1044 tcg_gen_qemu_ld64(t64, addr, index);
1045 gen_helper_extf64(cpu_env, fp, t64);
1046 break;
1047 case OS_EXTENDED:
1048 if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1049 gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1050 break;
1052 tcg_gen_qemu_ld32u(tmp, addr, index);
1053 tcg_gen_shri_i32(tmp, tmp, 16);
1054 tcg_gen_st16_i32(tmp, fp, offsetof(FPReg, l.upper));
1055 tcg_gen_addi_i32(tmp, addr, 4);
1056 tcg_gen_qemu_ld64(t64, tmp, index);
1057 tcg_gen_st_i64(t64, fp, offsetof(FPReg, l.lower));
1058 break;
1059 case OS_PACKED:
1061 * unimplemented data type on 68040/ColdFire
1062 * FIXME if needed for another FPU
1064 gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1065 break;
1066 default:
1067 g_assert_not_reached();
1069 tcg_temp_free(tmp);
1070 tcg_temp_free_i64(t64);
1073 static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
1074 int index)
1076 TCGv tmp;
1077 TCGv_i64 t64;
1079 t64 = tcg_temp_new_i64();
1080 tmp = tcg_temp_new();
1081 switch (opsize) {
1082 case OS_BYTE:
1083 gen_helper_reds32(tmp, cpu_env, fp);
1084 tcg_gen_qemu_st8(tmp, addr, index);
1085 break;
1086 case OS_WORD:
1087 gen_helper_reds32(tmp, cpu_env, fp);
1088 tcg_gen_qemu_st16(tmp, addr, index);
1089 break;
1090 case OS_LONG:
1091 gen_helper_reds32(tmp, cpu_env, fp);
1092 tcg_gen_qemu_st32(tmp, addr, index);
1093 break;
1094 case OS_SINGLE:
1095 gen_helper_redf32(tmp, cpu_env, fp);
1096 tcg_gen_qemu_st32(tmp, addr, index);
1097 break;
1098 case OS_DOUBLE:
1099 gen_helper_redf64(t64, cpu_env, fp);
1100 tcg_gen_qemu_st64(t64, addr, index);
1101 break;
1102 case OS_EXTENDED:
1103 if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1104 gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1105 break;
1107 tcg_gen_ld16u_i32(tmp, fp, offsetof(FPReg, l.upper));
1108 tcg_gen_shli_i32(tmp, tmp, 16);
1109 tcg_gen_qemu_st32(tmp, addr, index);
1110 tcg_gen_addi_i32(tmp, addr, 4);
1111 tcg_gen_ld_i64(t64, fp, offsetof(FPReg, l.lower));
1112 tcg_gen_qemu_st64(t64, tmp, index);
1113 break;
1114 case OS_PACKED:
1116 * unimplemented data type on 68040/ColdFire
1117 * FIXME if needed for another FPU
1119 gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1120 break;
1121 default:
1122 g_assert_not_reached();
1124 tcg_temp_free(tmp);
1125 tcg_temp_free_i64(t64);
1128 static void gen_ldst_fp(DisasContext *s, int opsize, TCGv addr,
1129 TCGv_ptr fp, ea_what what, int index)
1131 if (what == EA_STORE) {
1132 gen_store_fp(s, opsize, addr, fp, index);
1133 } else {
1134 gen_load_fp(s, opsize, addr, fp, index);
1138 static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
1139 int reg0, int opsize, TCGv_ptr fp, ea_what what,
1140 int index)
1142 TCGv reg, addr, tmp;
1143 TCGv_i64 t64;
1145 switch (mode) {
1146 case 0: /* Data register direct. */
1147 reg = cpu_dregs[reg0];
1148 if (what == EA_STORE) {
1149 switch (opsize) {
1150 case OS_BYTE:
1151 case OS_WORD:
1152 case OS_LONG:
1153 gen_helper_reds32(reg, cpu_env, fp);
1154 break;
1155 case OS_SINGLE:
1156 gen_helper_redf32(reg, cpu_env, fp);
1157 break;
1158 default:
1159 g_assert_not_reached();
1161 } else {
1162 tmp = tcg_temp_new();
1163 switch (opsize) {
1164 case OS_BYTE:
1165 tcg_gen_ext8s_i32(tmp, reg);
1166 gen_helper_exts32(cpu_env, fp, tmp);
1167 break;
1168 case OS_WORD:
1169 tcg_gen_ext16s_i32(tmp, reg);
1170 gen_helper_exts32(cpu_env, fp, tmp);
1171 break;
1172 case OS_LONG:
1173 gen_helper_exts32(cpu_env, fp, reg);
1174 break;
1175 case OS_SINGLE:
1176 gen_helper_extf32(cpu_env, fp, reg);
1177 break;
1178 default:
1179 g_assert_not_reached();
1181 tcg_temp_free(tmp);
1183 return 0;
1184 case 1: /* Address register direct. */
1185 return -1;
1186 case 2: /* Indirect register */
1187 addr = get_areg(s, reg0);
1188 gen_ldst_fp(s, opsize, addr, fp, what, index);
1189 return 0;
1190 case 3: /* Indirect postincrement. */
1191 addr = cpu_aregs[reg0];
1192 gen_ldst_fp(s, opsize, addr, fp, what, index);
1193 tcg_gen_addi_i32(addr, addr, opsize_bytes(opsize));
1194 return 0;
1195 case 4: /* Indirect predecrememnt. */
1196 addr = gen_lea_mode(env, s, mode, reg0, opsize);
1197 if (IS_NULL_QREG(addr)) {
1198 return -1;
1200 gen_ldst_fp(s, opsize, addr, fp, what, index);
1201 tcg_gen_mov_i32(cpu_aregs[reg0], addr);
1202 return 0;
1203 case 5: /* Indirect displacement. */
1204 case 6: /* Indirect index + displacement. */
1205 do_indirect:
1206 addr = gen_lea_mode(env, s, mode, reg0, opsize);
1207 if (IS_NULL_QREG(addr)) {
1208 return -1;
1210 gen_ldst_fp(s, opsize, addr, fp, what, index);
1211 return 0;
1212 case 7: /* Other */
1213 switch (reg0) {
1214 case 0: /* Absolute short. */
1215 case 1: /* Absolute long. */
1216 case 2: /* pc displacement */
1217 case 3: /* pc index+displacement. */
1218 goto do_indirect;
1219 case 4: /* Immediate. */
1220 if (what == EA_STORE) {
1221 return -1;
1223 switch (opsize) {
1224 case OS_BYTE:
1225 tmp = tcg_const_i32((int8_t)read_im8(env, s));
1226 gen_helper_exts32(cpu_env, fp, tmp);
1227 tcg_temp_free(tmp);
1228 break;
1229 case OS_WORD:
1230 tmp = tcg_const_i32((int16_t)read_im16(env, s));
1231 gen_helper_exts32(cpu_env, fp, tmp);
1232 tcg_temp_free(tmp);
1233 break;
1234 case OS_LONG:
1235 tmp = tcg_const_i32(read_im32(env, s));
1236 gen_helper_exts32(cpu_env, fp, tmp);
1237 tcg_temp_free(tmp);
1238 break;
1239 case OS_SINGLE:
1240 tmp = tcg_const_i32(read_im32(env, s));
1241 gen_helper_extf32(cpu_env, fp, tmp);
1242 tcg_temp_free(tmp);
1243 break;
1244 case OS_DOUBLE:
1245 t64 = tcg_const_i64(read_im64(env, s));
1246 gen_helper_extf64(cpu_env, fp, t64);
1247 tcg_temp_free_i64(t64);
1248 break;
1249 case OS_EXTENDED:
1250 if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1251 gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1252 break;
1254 tmp = tcg_const_i32(read_im32(env, s) >> 16);
1255 tcg_gen_st16_i32(tmp, fp, offsetof(FPReg, l.upper));
1256 tcg_temp_free(tmp);
1257 t64 = tcg_const_i64(read_im64(env, s));
1258 tcg_gen_st_i64(t64, fp, offsetof(FPReg, l.lower));
1259 tcg_temp_free_i64(t64);
1260 break;
1261 case OS_PACKED:
1263 * unimplemented data type on 68040/ColdFire
1264 * FIXME if needed for another FPU
1266 gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1267 break;
1268 default:
1269 g_assert_not_reached();
1271 return 0;
1272 default:
1273 return -1;
1276 return -1;
1279 static int gen_ea_fp(CPUM68KState *env, DisasContext *s, uint16_t insn,
1280 int opsize, TCGv_ptr fp, ea_what what, int index)
1282 int mode = extract32(insn, 3, 3);
1283 int reg0 = REG(insn, 0);
1284 return gen_ea_mode_fp(env, s, mode, reg0, opsize, fp, what, index);
1287 typedef struct {
1288 TCGCond tcond;
1289 bool g1;
1290 bool g2;
1291 TCGv v1;
1292 TCGv v2;
1293 } DisasCompare;
1295 static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond)
1297 TCGv tmp, tmp2;
1298 TCGCond tcond;
1299 CCOp op = s->cc_op;
1301 /* The CC_OP_CMP form can handle most normal comparisons directly. */
1302 if (op == CC_OP_CMPB || op == CC_OP_CMPW || op == CC_OP_CMPL) {
1303 c->g1 = c->g2 = 1;
1304 c->v1 = QREG_CC_N;
1305 c->v2 = QREG_CC_V;
1306 switch (cond) {
1307 case 2: /* HI */
1308 case 3: /* LS */
1309 tcond = TCG_COND_LEU;
1310 goto done;
1311 case 4: /* CC */
1312 case 5: /* CS */
1313 tcond = TCG_COND_LTU;
1314 goto done;
1315 case 6: /* NE */
1316 case 7: /* EQ */
1317 tcond = TCG_COND_EQ;
1318 goto done;
1319 case 10: /* PL */
1320 case 11: /* MI */
1321 c->g1 = c->g2 = 0;
1322 c->v2 = tcg_const_i32(0);
1323 c->v1 = tmp = tcg_temp_new();
1324 tcg_gen_sub_i32(tmp, QREG_CC_N, QREG_CC_V);
1325 gen_ext(tmp, tmp, op - CC_OP_CMPB, 1);
1326 /* fallthru */
1327 case 12: /* GE */
1328 case 13: /* LT */
1329 tcond = TCG_COND_LT;
1330 goto done;
1331 case 14: /* GT */
1332 case 15: /* LE */
1333 tcond = TCG_COND_LE;
1334 goto done;
1338 c->g1 = 1;
1339 c->g2 = 0;
1340 c->v2 = tcg_const_i32(0);
1342 switch (cond) {
1343 case 0: /* T */
1344 case 1: /* F */
1345 c->v1 = c->v2;
1346 tcond = TCG_COND_NEVER;
1347 goto done;
1348 case 14: /* GT (!(Z || (N ^ V))) */
1349 case 15: /* LE (Z || (N ^ V)) */
1351 * Logic operations clear V, which simplifies LE to (Z || N),
1352 * and since Z and N are co-located, this becomes a normal
1353 * comparison vs N.
1355 if (op == CC_OP_LOGIC) {
1356 c->v1 = QREG_CC_N;
1357 tcond = TCG_COND_LE;
1358 goto done;
1360 break;
1361 case 12: /* GE (!(N ^ V)) */
1362 case 13: /* LT (N ^ V) */
1363 /* Logic operations clear V, which simplifies this to N. */
1364 if (op != CC_OP_LOGIC) {
1365 break;
1367 /* fallthru */
1368 case 10: /* PL (!N) */
1369 case 11: /* MI (N) */
1370 /* Several cases represent N normally. */
1371 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1372 op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
1373 op == CC_OP_LOGIC) {
1374 c->v1 = QREG_CC_N;
1375 tcond = TCG_COND_LT;
1376 goto done;
1378 break;
1379 case 6: /* NE (!Z) */
1380 case 7: /* EQ (Z) */
1381 /* Some cases fold Z into N. */
1382 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1383 op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
1384 op == CC_OP_LOGIC) {
1385 tcond = TCG_COND_EQ;
1386 c->v1 = QREG_CC_N;
1387 goto done;
1389 break;
1390 case 4: /* CC (!C) */
1391 case 5: /* CS (C) */
1392 /* Some cases fold C into X. */
1393 if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1394 op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL) {
1395 tcond = TCG_COND_NE;
1396 c->v1 = QREG_CC_X;
1397 goto done;
1399 /* fallthru */
1400 case 8: /* VC (!V) */
1401 case 9: /* VS (V) */
1402 /* Logic operations clear V and C. */
1403 if (op == CC_OP_LOGIC) {
1404 tcond = TCG_COND_NEVER;
1405 c->v1 = c->v2;
1406 goto done;
1408 break;
1411 /* Otherwise, flush flag state to CC_OP_FLAGS. */
1412 gen_flush_flags(s);
1414 switch (cond) {
1415 case 0: /* T */
1416 case 1: /* F */
1417 default:
1418 /* Invalid, or handled above. */
1419 abort();
1420 case 2: /* HI (!C && !Z) -> !(C || Z)*/
1421 case 3: /* LS (C || Z) */
1422 c->v1 = tmp = tcg_temp_new();
1423 c->g1 = 0;
1424 tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
1425 tcg_gen_or_i32(tmp, tmp, QREG_CC_C);
1426 tcond = TCG_COND_NE;
1427 break;
1428 case 4: /* CC (!C) */
1429 case 5: /* CS (C) */
1430 c->v1 = QREG_CC_C;
1431 tcond = TCG_COND_NE;
1432 break;
1433 case 6: /* NE (!Z) */
1434 case 7: /* EQ (Z) */
1435 c->v1 = QREG_CC_Z;
1436 tcond = TCG_COND_EQ;
1437 break;
1438 case 8: /* VC (!V) */
1439 case 9: /* VS (V) */
1440 c->v1 = QREG_CC_V;
1441 tcond = TCG_COND_LT;
1442 break;
1443 case 10: /* PL (!N) */
1444 case 11: /* MI (N) */
1445 c->v1 = QREG_CC_N;
1446 tcond = TCG_COND_LT;
1447 break;
1448 case 12: /* GE (!(N ^ V)) */
1449 case 13: /* LT (N ^ V) */
1450 c->v1 = tmp = tcg_temp_new();
1451 c->g1 = 0;
1452 tcg_gen_xor_i32(tmp, QREG_CC_N, QREG_CC_V);
1453 tcond = TCG_COND_LT;
1454 break;
1455 case 14: /* GT (!(Z || (N ^ V))) */
1456 case 15: /* LE (Z || (N ^ V)) */
1457 c->v1 = tmp = tcg_temp_new();
1458 c->g1 = 0;
1459 tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
1460 tcg_gen_neg_i32(tmp, tmp);
1461 tmp2 = tcg_temp_new();
1462 tcg_gen_xor_i32(tmp2, QREG_CC_N, QREG_CC_V);
1463 tcg_gen_or_i32(tmp, tmp, tmp2);
1464 tcg_temp_free(tmp2);
1465 tcond = TCG_COND_LT;
1466 break;
1469 done:
1470 if ((cond & 1) == 0) {
1471 tcond = tcg_invert_cond(tcond);
1473 c->tcond = tcond;
1476 static void free_cond(DisasCompare *c)
1478 if (!c->g1) {
1479 tcg_temp_free(c->v1);
1481 if (!c->g2) {
1482 tcg_temp_free(c->v2);
1486 static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1)
1488 DisasCompare c;
1490 gen_cc_cond(&c, s, cond);
1491 update_cc_op(s);
1492 tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
1493 free_cond(&c);
1496 /* Force a TB lookup after an instruction that changes the CPU state. */
1497 static void gen_exit_tb(DisasContext *s)
1499 update_cc_op(s);
1500 tcg_gen_movi_i32(QREG_PC, s->pc);
1501 s->base.is_jmp = DISAS_EXIT;
1504 #define SRC_EA(env, result, opsize, op_sign, addrp) do { \
1505 result = gen_ea(env, s, insn, opsize, NULL_QREG, addrp, \
1506 op_sign ? EA_LOADS : EA_LOADU, IS_USER(s)); \
1507 if (IS_NULL_QREG(result)) { \
1508 gen_addr_fault(s); \
1509 return; \
1511 } while (0)
1513 #define DEST_EA(env, insn, opsize, val, addrp) do { \
1514 TCGv ea_result = gen_ea(env, s, insn, opsize, val, addrp, \
1515 EA_STORE, IS_USER(s)); \
1516 if (IS_NULL_QREG(ea_result)) { \
1517 gen_addr_fault(s); \
1518 return; \
1520 } while (0)
1522 /* Generate a jump to an immediate address. */
1523 static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
1525 if (unlikely(is_singlestepping(s))) {
1526 update_cc_op(s);
1527 tcg_gen_movi_i32(QREG_PC, dest);
1528 gen_singlestep_exception(s);
1529 } else if (translator_use_goto_tb(&s->base, dest)) {
1530 tcg_gen_goto_tb(n);
1531 tcg_gen_movi_i32(QREG_PC, dest);
1532 tcg_gen_exit_tb(s->base.tb, n);
1533 } else {
1534 gen_jmp_im(s, dest);
1535 tcg_gen_exit_tb(NULL, 0);
1537 s->base.is_jmp = DISAS_NORETURN;
1540 DISAS_INSN(scc)
1542 DisasCompare c;
1543 int cond;
1544 TCGv tmp;
1546 cond = (insn >> 8) & 0xf;
1547 gen_cc_cond(&c, s, cond);
1549 tmp = tcg_temp_new();
1550 tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2);
1551 free_cond(&c);
1553 tcg_gen_neg_i32(tmp, tmp);
1554 DEST_EA(env, insn, OS_BYTE, tmp, NULL);
1555 tcg_temp_free(tmp);
1558 DISAS_INSN(dbcc)
1560 TCGLabel *l1;
1561 TCGv reg;
1562 TCGv tmp;
1563 int16_t offset;
1564 uint32_t base;
1566 reg = DREG(insn, 0);
1567 base = s->pc;
1568 offset = (int16_t)read_im16(env, s);
1569 l1 = gen_new_label();
1570 gen_jmpcc(s, (insn >> 8) & 0xf, l1);
1572 tmp = tcg_temp_new();
1573 tcg_gen_ext16s_i32(tmp, reg);
1574 tcg_gen_addi_i32(tmp, tmp, -1);
1575 gen_partset_reg(OS_WORD, reg, tmp);
1576 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1);
1577 gen_jmp_tb(s, 1, base + offset);
1578 gen_set_label(l1);
1579 gen_jmp_tb(s, 0, s->pc);
1582 DISAS_INSN(undef_mac)
1584 gen_exception(s, s->base.pc_next, EXCP_LINEA);
1587 DISAS_INSN(undef_fpu)
1589 gen_exception(s, s->base.pc_next, EXCP_LINEF);
1592 DISAS_INSN(undef)
1595 * ??? This is both instructions that are as yet unimplemented
1596 * for the 680x0 series, as well as those that are implemented
1597 * but actually illegal for CPU32 or pre-68020.
1599 qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n",
1600 insn, s->base.pc_next);
1601 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
1604 DISAS_INSN(mulw)
1606 TCGv reg;
1607 TCGv tmp;
1608 TCGv src;
1609 int sign;
1611 sign = (insn & 0x100) != 0;
1612 reg = DREG(insn, 9);
1613 tmp = tcg_temp_new();
1614 if (sign)
1615 tcg_gen_ext16s_i32(tmp, reg);
1616 else
1617 tcg_gen_ext16u_i32(tmp, reg);
1618 SRC_EA(env, src, OS_WORD, sign, NULL);
1619 tcg_gen_mul_i32(tmp, tmp, src);
1620 tcg_gen_mov_i32(reg, tmp);
1621 gen_logic_cc(s, tmp, OS_LONG);
1622 tcg_temp_free(tmp);
1625 DISAS_INSN(divw)
1627 int sign;
1628 TCGv src;
1629 TCGv destr;
1631 /* divX.w <EA>,Dn 32/16 -> 16r:16q */
1633 sign = (insn & 0x100) != 0;
1635 /* dest.l / src.w */
1637 SRC_EA(env, src, OS_WORD, sign, NULL);
1638 destr = tcg_const_i32(REG(insn, 9));
1639 if (sign) {
1640 gen_helper_divsw(cpu_env, destr, src);
1641 } else {
1642 gen_helper_divuw(cpu_env, destr, src);
1644 tcg_temp_free(destr);
1646 set_cc_op(s, CC_OP_FLAGS);
1649 DISAS_INSN(divl)
1651 TCGv num, reg, den;
1652 int sign;
1653 uint16_t ext;
1655 ext = read_im16(env, s);
1657 sign = (ext & 0x0800) != 0;
1659 if (ext & 0x400) {
1660 if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
1661 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
1662 return;
1665 /* divX.l <EA>, Dr:Dq 64/32 -> 32r:32q */
1667 SRC_EA(env, den, OS_LONG, 0, NULL);
1668 num = tcg_const_i32(REG(ext, 12));
1669 reg = tcg_const_i32(REG(ext, 0));
1670 if (sign) {
1671 gen_helper_divsll(cpu_env, num, reg, den);
1672 } else {
1673 gen_helper_divull(cpu_env, num, reg, den);
1675 tcg_temp_free(reg);
1676 tcg_temp_free(num);
1677 set_cc_op(s, CC_OP_FLAGS);
1678 return;
1681 /* divX.l <EA>, Dq 32/32 -> 32q */
1682 /* divXl.l <EA>, Dr:Dq 32/32 -> 32r:32q */
1684 SRC_EA(env, den, OS_LONG, 0, NULL);
1685 num = tcg_const_i32(REG(ext, 12));
1686 reg = tcg_const_i32(REG(ext, 0));
1687 if (sign) {
1688 gen_helper_divsl(cpu_env, num, reg, den);
1689 } else {
1690 gen_helper_divul(cpu_env, num, reg, den);
1692 tcg_temp_free(reg);
1693 tcg_temp_free(num);
1695 set_cc_op(s, CC_OP_FLAGS);
1698 static void bcd_add(TCGv dest, TCGv src)
1700 TCGv t0, t1;
1703 * dest10 = dest10 + src10 + X
1705 * t1 = src
1706 * t2 = t1 + 0x066
1707 * t3 = t2 + dest + X
1708 * t4 = t2 ^ dest
1709 * t5 = t3 ^ t4
1710 * t6 = ~t5 & 0x110
1711 * t7 = (t6 >> 2) | (t6 >> 3)
1712 * return t3 - t7
1716 * t1 = (src + 0x066) + dest + X
1717 * = result with some possible exceeding 0x6
1720 t0 = tcg_const_i32(0x066);
1721 tcg_gen_add_i32(t0, t0, src);
1723 t1 = tcg_temp_new();
1724 tcg_gen_add_i32(t1, t0, dest);
1725 tcg_gen_add_i32(t1, t1, QREG_CC_X);
1727 /* we will remove exceeding 0x6 where there is no carry */
1730 * t0 = (src + 0x0066) ^ dest
1731 * = t1 without carries
1734 tcg_gen_xor_i32(t0, t0, dest);
1737 * extract the carries
1738 * t0 = t0 ^ t1
1739 * = only the carries
1742 tcg_gen_xor_i32(t0, t0, t1);
1745 * generate 0x1 where there is no carry
1746 * and for each 0x10, generate a 0x6
1749 tcg_gen_shri_i32(t0, t0, 3);
1750 tcg_gen_not_i32(t0, t0);
1751 tcg_gen_andi_i32(t0, t0, 0x22);
1752 tcg_gen_add_i32(dest, t0, t0);
1753 tcg_gen_add_i32(dest, dest, t0);
1754 tcg_temp_free(t0);
1757 * remove the exceeding 0x6
1758 * for digits that have not generated a carry
1761 tcg_gen_sub_i32(dest, t1, dest);
1762 tcg_temp_free(t1);
1765 static void bcd_sub(TCGv dest, TCGv src)
1767 TCGv t0, t1, t2;
1770 * dest10 = dest10 - src10 - X
1771 * = bcd_add(dest + 1 - X, 0x199 - src)
1774 /* t0 = 0x066 + (0x199 - src) */
1776 t0 = tcg_temp_new();
1777 tcg_gen_subfi_i32(t0, 0x1ff, src);
1779 /* t1 = t0 + dest + 1 - X*/
1781 t1 = tcg_temp_new();
1782 tcg_gen_add_i32(t1, t0, dest);
1783 tcg_gen_addi_i32(t1, t1, 1);
1784 tcg_gen_sub_i32(t1, t1, QREG_CC_X);
1786 /* t2 = t0 ^ dest */
1788 t2 = tcg_temp_new();
1789 tcg_gen_xor_i32(t2, t0, dest);
1791 /* t0 = t1 ^ t2 */
1793 tcg_gen_xor_i32(t0, t1, t2);
1796 * t2 = ~t0 & 0x110
1797 * t0 = (t2 >> 2) | (t2 >> 3)
1799 * to fit on 8bit operands, changed in:
1801 * t2 = ~(t0 >> 3) & 0x22
1802 * t0 = t2 + t2
1803 * t0 = t0 + t2
1806 tcg_gen_shri_i32(t2, t0, 3);
1807 tcg_gen_not_i32(t2, t2);
1808 tcg_gen_andi_i32(t2, t2, 0x22);
1809 tcg_gen_add_i32(t0, t2, t2);
1810 tcg_gen_add_i32(t0, t0, t2);
1811 tcg_temp_free(t2);
1813 /* return t1 - t0 */
1815 tcg_gen_sub_i32(dest, t1, t0);
1816 tcg_temp_free(t0);
1817 tcg_temp_free(t1);
1820 static void bcd_flags(TCGv val)
1822 tcg_gen_andi_i32(QREG_CC_C, val, 0x0ff);
1823 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_C);
1825 tcg_gen_extract_i32(QREG_CC_C, val, 8, 1);
1827 tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
1830 DISAS_INSN(abcd_reg)
1832 TCGv src;
1833 TCGv dest;
1835 gen_flush_flags(s); /* !Z is sticky */
1837 src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
1838 dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
1839 bcd_add(dest, src);
1840 gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1842 bcd_flags(dest);
1845 DISAS_INSN(abcd_mem)
1847 TCGv src, dest, addr;
1849 gen_flush_flags(s); /* !Z is sticky */
1851 /* Indirect pre-decrement load (mode 4) */
1853 src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
1854 NULL_QREG, NULL, EA_LOADU, IS_USER(s));
1855 dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
1856 NULL_QREG, &addr, EA_LOADU, IS_USER(s));
1858 bcd_add(dest, src);
1860 gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr,
1861 EA_STORE, IS_USER(s));
1863 bcd_flags(dest);
1866 DISAS_INSN(sbcd_reg)
1868 TCGv src, dest;
1870 gen_flush_flags(s); /* !Z is sticky */
1872 src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
1873 dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
1875 bcd_sub(dest, src);
1877 gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1879 bcd_flags(dest);
1882 DISAS_INSN(sbcd_mem)
1884 TCGv src, dest, addr;
1886 gen_flush_flags(s); /* !Z is sticky */
1888 /* Indirect pre-decrement load (mode 4) */
1890 src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
1891 NULL_QREG, NULL, EA_LOADU, IS_USER(s));
1892 dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
1893 NULL_QREG, &addr, EA_LOADU, IS_USER(s));
1895 bcd_sub(dest, src);
1897 gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr,
1898 EA_STORE, IS_USER(s));
1900 bcd_flags(dest);
1903 DISAS_INSN(nbcd)
1905 TCGv src, dest;
1906 TCGv addr;
1908 gen_flush_flags(s); /* !Z is sticky */
1910 SRC_EA(env, src, OS_BYTE, 0, &addr);
1912 dest = tcg_const_i32(0);
1913 bcd_sub(dest, src);
1915 DEST_EA(env, insn, OS_BYTE, dest, &addr);
1917 bcd_flags(dest);
1919 tcg_temp_free(dest);
1922 DISAS_INSN(addsub)
1924 TCGv reg;
1925 TCGv dest;
1926 TCGv src;
1927 TCGv tmp;
1928 TCGv addr;
1929 int add;
1930 int opsize;
1932 add = (insn & 0x4000) != 0;
1933 opsize = insn_opsize(insn);
1934 reg = gen_extend(s, DREG(insn, 9), opsize, 1);
1935 dest = tcg_temp_new();
1936 if (insn & 0x100) {
1937 SRC_EA(env, tmp, opsize, 1, &addr);
1938 src = reg;
1939 } else {
1940 tmp = reg;
1941 SRC_EA(env, src, opsize, 1, NULL);
1943 if (add) {
1944 tcg_gen_add_i32(dest, tmp, src);
1945 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src);
1946 set_cc_op(s, CC_OP_ADDB + opsize);
1947 } else {
1948 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src);
1949 tcg_gen_sub_i32(dest, tmp, src);
1950 set_cc_op(s, CC_OP_SUBB + opsize);
1952 gen_update_cc_add(dest, src, opsize);
1953 if (insn & 0x100) {
1954 DEST_EA(env, insn, opsize, dest, &addr);
1955 } else {
1956 gen_partset_reg(opsize, DREG(insn, 9), dest);
1958 tcg_temp_free(dest);
1961 /* Reverse the order of the bits in REG. */
1962 DISAS_INSN(bitrev)
1964 TCGv reg;
1965 reg = DREG(insn, 0);
1966 gen_helper_bitrev(reg, reg);
1969 DISAS_INSN(bitop_reg)
1971 int opsize;
1972 int op;
1973 TCGv src1;
1974 TCGv src2;
1975 TCGv tmp;
1976 TCGv addr;
1977 TCGv dest;
1979 if ((insn & 0x38) != 0)
1980 opsize = OS_BYTE;
1981 else
1982 opsize = OS_LONG;
1983 op = (insn >> 6) & 3;
1984 SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
1986 gen_flush_flags(s);
1987 src2 = tcg_temp_new();
1988 if (opsize == OS_BYTE)
1989 tcg_gen_andi_i32(src2, DREG(insn, 9), 7);
1990 else
1991 tcg_gen_andi_i32(src2, DREG(insn, 9), 31);
1993 tmp = tcg_const_i32(1);
1994 tcg_gen_shl_i32(tmp, tmp, src2);
1995 tcg_temp_free(src2);
1997 tcg_gen_and_i32(QREG_CC_Z, src1, tmp);
1999 dest = tcg_temp_new();
2000 switch (op) {
2001 case 1: /* bchg */
2002 tcg_gen_xor_i32(dest, src1, tmp);
2003 break;
2004 case 2: /* bclr */
2005 tcg_gen_andc_i32(dest, src1, tmp);
2006 break;
2007 case 3: /* bset */
2008 tcg_gen_or_i32(dest, src1, tmp);
2009 break;
2010 default: /* btst */
2011 break;
2013 tcg_temp_free(tmp);
2014 if (op) {
2015 DEST_EA(env, insn, opsize, dest, &addr);
2017 tcg_temp_free(dest);
2020 DISAS_INSN(sats)
2022 TCGv reg;
2023 reg = DREG(insn, 0);
2024 gen_flush_flags(s);
2025 gen_helper_sats(reg, reg, QREG_CC_V);
2026 gen_logic_cc(s, reg, OS_LONG);
2029 static void gen_push(DisasContext *s, TCGv val)
2031 TCGv tmp;
2033 tmp = tcg_temp_new();
2034 tcg_gen_subi_i32(tmp, QREG_SP, 4);
2035 gen_store(s, OS_LONG, tmp, val, IS_USER(s));
2036 tcg_gen_mov_i32(QREG_SP, tmp);
2037 tcg_temp_free(tmp);
2040 static TCGv mreg(int reg)
2042 if (reg < 8) {
2043 /* Dx */
2044 return cpu_dregs[reg];
2046 /* Ax */
2047 return cpu_aregs[reg & 7];
2050 DISAS_INSN(movem)
2052 TCGv addr, incr, tmp, r[16];
2053 int is_load = (insn & 0x0400) != 0;
2054 int opsize = (insn & 0x40) != 0 ? OS_LONG : OS_WORD;
2055 uint16_t mask = read_im16(env, s);
2056 int mode = extract32(insn, 3, 3);
2057 int reg0 = REG(insn, 0);
2058 int i;
2060 tmp = cpu_aregs[reg0];
2062 switch (mode) {
2063 case 0: /* data register direct */
2064 case 1: /* addr register direct */
2065 do_addr_fault:
2066 gen_addr_fault(s);
2067 return;
2069 case 2: /* indirect */
2070 break;
2072 case 3: /* indirect post-increment */
2073 if (!is_load) {
2074 /* post-increment is not allowed */
2075 goto do_addr_fault;
2077 break;
2079 case 4: /* indirect pre-decrement */
2080 if (is_load) {
2081 /* pre-decrement is not allowed */
2082 goto do_addr_fault;
2085 * We want a bare copy of the address reg, without any pre-decrement
2086 * adjustment, as gen_lea would provide.
2088 break;
2090 default:
2091 tmp = gen_lea_mode(env, s, mode, reg0, opsize);
2092 if (IS_NULL_QREG(tmp)) {
2093 goto do_addr_fault;
2095 break;
2098 addr = tcg_temp_new();
2099 tcg_gen_mov_i32(addr, tmp);
2100 incr = tcg_const_i32(opsize_bytes(opsize));
2102 if (is_load) {
2103 /* memory to register */
2104 for (i = 0; i < 16; i++) {
2105 if (mask & (1 << i)) {
2106 r[i] = gen_load(s, opsize, addr, 1, IS_USER(s));
2107 tcg_gen_add_i32(addr, addr, incr);
2110 for (i = 0; i < 16; i++) {
2111 if (mask & (1 << i)) {
2112 tcg_gen_mov_i32(mreg(i), r[i]);
2113 tcg_temp_free(r[i]);
2116 if (mode == 3) {
2117 /* post-increment: movem (An)+,X */
2118 tcg_gen_mov_i32(cpu_aregs[reg0], addr);
2120 } else {
2121 /* register to memory */
2122 if (mode == 4) {
2123 /* pre-decrement: movem X,-(An) */
2124 for (i = 15; i >= 0; i--) {
2125 if ((mask << i) & 0x8000) {
2126 tcg_gen_sub_i32(addr, addr, incr);
2127 if (reg0 + 8 == i &&
2128 m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) {
2130 * M68020+: if the addressing register is the
2131 * register moved to memory, the value written
2132 * is the initial value decremented by the size of
2133 * the operation, regardless of how many actual
2134 * stores have been performed until this point.
2135 * M68000/M68010: the value is the initial value.
2137 tmp = tcg_temp_new();
2138 tcg_gen_sub_i32(tmp, cpu_aregs[reg0], incr);
2139 gen_store(s, opsize, addr, tmp, IS_USER(s));
2140 tcg_temp_free(tmp);
2141 } else {
2142 gen_store(s, opsize, addr, mreg(i), IS_USER(s));
2146 tcg_gen_mov_i32(cpu_aregs[reg0], addr);
2147 } else {
2148 for (i = 0; i < 16; i++) {
2149 if (mask & (1 << i)) {
2150 gen_store(s, opsize, addr, mreg(i), IS_USER(s));
2151 tcg_gen_add_i32(addr, addr, incr);
2157 tcg_temp_free(incr);
2158 tcg_temp_free(addr);
2161 DISAS_INSN(movep)
2163 uint8_t i;
2164 int16_t displ;
2165 TCGv reg;
2166 TCGv addr;
2167 TCGv abuf;
2168 TCGv dbuf;
2170 displ = read_im16(env, s);
2172 addr = AREG(insn, 0);
2173 reg = DREG(insn, 9);
2175 abuf = tcg_temp_new();
2176 tcg_gen_addi_i32(abuf, addr, displ);
2177 dbuf = tcg_temp_new();
2179 if (insn & 0x40) {
2180 i = 4;
2181 } else {
2182 i = 2;
2185 if (insn & 0x80) {
2186 for ( ; i > 0 ; i--) {
2187 tcg_gen_shri_i32(dbuf, reg, (i - 1) * 8);
2188 tcg_gen_qemu_st8(dbuf, abuf, IS_USER(s));
2189 if (i > 1) {
2190 tcg_gen_addi_i32(abuf, abuf, 2);
2193 } else {
2194 for ( ; i > 0 ; i--) {
2195 tcg_gen_qemu_ld8u(dbuf, abuf, IS_USER(s));
2196 tcg_gen_deposit_i32(reg, reg, dbuf, (i - 1) * 8, 8);
2197 if (i > 1) {
2198 tcg_gen_addi_i32(abuf, abuf, 2);
2202 tcg_temp_free(abuf);
2203 tcg_temp_free(dbuf);
2206 DISAS_INSN(bitop_im)
2208 int opsize;
2209 int op;
2210 TCGv src1;
2211 uint32_t mask;
2212 int bitnum;
2213 TCGv tmp;
2214 TCGv addr;
2216 if ((insn & 0x38) != 0)
2217 opsize = OS_BYTE;
2218 else
2219 opsize = OS_LONG;
2220 op = (insn >> 6) & 3;
2222 bitnum = read_im16(env, s);
2223 if (m68k_feature(s->env, M68K_FEATURE_M68000)) {
2224 if (bitnum & 0xfe00) {
2225 disas_undef(env, s, insn);
2226 return;
2228 } else {
2229 if (bitnum & 0xff00) {
2230 disas_undef(env, s, insn);
2231 return;
2235 SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
2237 gen_flush_flags(s);
2238 if (opsize == OS_BYTE)
2239 bitnum &= 7;
2240 else
2241 bitnum &= 31;
2242 mask = 1 << bitnum;
2244 tcg_gen_andi_i32(QREG_CC_Z, src1, mask);
2246 if (op) {
2247 tmp = tcg_temp_new();
2248 switch (op) {
2249 case 1: /* bchg */
2250 tcg_gen_xori_i32(tmp, src1, mask);
2251 break;
2252 case 2: /* bclr */
2253 tcg_gen_andi_i32(tmp, src1, ~mask);
2254 break;
2255 case 3: /* bset */
2256 tcg_gen_ori_i32(tmp, src1, mask);
2257 break;
2258 default: /* btst */
2259 break;
2261 DEST_EA(env, insn, opsize, tmp, &addr);
2262 tcg_temp_free(tmp);
2266 static TCGv gen_get_ccr(DisasContext *s)
2268 TCGv dest;
2270 update_cc_op(s);
2271 dest = tcg_temp_new();
2272 gen_helper_get_ccr(dest, cpu_env);
2273 return dest;
2276 static TCGv gen_get_sr(DisasContext *s)
2278 TCGv ccr;
2279 TCGv sr;
2281 ccr = gen_get_ccr(s);
2282 sr = tcg_temp_new();
2283 tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
2284 tcg_gen_or_i32(sr, sr, ccr);
2285 tcg_temp_free(ccr);
2286 return sr;
2289 static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
2291 if (ccr_only) {
2292 tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0);
2293 tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0);
2294 tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1);
2295 tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0);
2296 tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0);
2297 } else {
2298 TCGv sr = tcg_const_i32(val);
2299 gen_helper_set_sr(cpu_env, sr);
2300 tcg_temp_free(sr);
2302 set_cc_op(s, CC_OP_FLAGS);
2305 static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only)
2307 if (ccr_only) {
2308 gen_helper_set_ccr(cpu_env, val);
2309 } else {
2310 gen_helper_set_sr(cpu_env, val);
2312 set_cc_op(s, CC_OP_FLAGS);
2315 static void gen_move_to_sr(CPUM68KState *env, DisasContext *s, uint16_t insn,
2316 bool ccr_only)
2318 if ((insn & 0x3f) == 0x3c) {
2319 uint16_t val;
2320 val = read_im16(env, s);
2321 gen_set_sr_im(s, val, ccr_only);
2322 } else {
2323 TCGv src;
2324 SRC_EA(env, src, OS_WORD, 0, NULL);
2325 gen_set_sr(s, src, ccr_only);
2329 DISAS_INSN(arith_im)
2331 int op;
2332 TCGv im;
2333 TCGv src1;
2334 TCGv dest;
2335 TCGv addr;
2336 int opsize;
2337 bool with_SR = ((insn & 0x3f) == 0x3c);
2339 op = (insn >> 9) & 7;
2340 opsize = insn_opsize(insn);
2341 switch (opsize) {
2342 case OS_BYTE:
2343 im = tcg_const_i32((int8_t)read_im8(env, s));
2344 break;
2345 case OS_WORD:
2346 im = tcg_const_i32((int16_t)read_im16(env, s));
2347 break;
2348 case OS_LONG:
2349 im = tcg_const_i32(read_im32(env, s));
2350 break;
2351 default:
2352 g_assert_not_reached();
2355 if (with_SR) {
2356 /* SR/CCR can only be used with andi/eori/ori */
2357 if (op == 2 || op == 3 || op == 6) {
2358 disas_undef(env, s, insn);
2359 return;
2361 switch (opsize) {
2362 case OS_BYTE:
2363 src1 = gen_get_ccr(s);
2364 break;
2365 case OS_WORD:
2366 if (IS_USER(s)) {
2367 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
2368 return;
2370 src1 = gen_get_sr(s);
2371 break;
2372 default:
2373 /* OS_LONG; others already g_assert_not_reached. */
2374 disas_undef(env, s, insn);
2375 return;
2377 } else {
2378 SRC_EA(env, src1, opsize, 1, (op == 6) ? NULL : &addr);
2380 dest = tcg_temp_new();
2381 switch (op) {
2382 case 0: /* ori */
2383 tcg_gen_or_i32(dest, src1, im);
2384 if (with_SR) {
2385 gen_set_sr(s, dest, opsize == OS_BYTE);
2386 } else {
2387 DEST_EA(env, insn, opsize, dest, &addr);
2388 gen_logic_cc(s, dest, opsize);
2390 break;
2391 case 1: /* andi */
2392 tcg_gen_and_i32(dest, src1, im);
2393 if (with_SR) {
2394 gen_set_sr(s, dest, opsize == OS_BYTE);
2395 } else {
2396 DEST_EA(env, insn, opsize, dest, &addr);
2397 gen_logic_cc(s, dest, opsize);
2399 break;
2400 case 2: /* subi */
2401 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, src1, im);
2402 tcg_gen_sub_i32(dest, src1, im);
2403 gen_update_cc_add(dest, im, opsize);
2404 set_cc_op(s, CC_OP_SUBB + opsize);
2405 DEST_EA(env, insn, opsize, dest, &addr);
2406 break;
2407 case 3: /* addi */
2408 tcg_gen_add_i32(dest, src1, im);
2409 gen_update_cc_add(dest, im, opsize);
2410 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, im);
2411 set_cc_op(s, CC_OP_ADDB + opsize);
2412 DEST_EA(env, insn, opsize, dest, &addr);
2413 break;
2414 case 5: /* eori */
2415 tcg_gen_xor_i32(dest, src1, im);
2416 if (with_SR) {
2417 gen_set_sr(s, dest, opsize == OS_BYTE);
2418 } else {
2419 DEST_EA(env, insn, opsize, dest, &addr);
2420 gen_logic_cc(s, dest, opsize);
2422 break;
2423 case 6: /* cmpi */
2424 gen_update_cc_cmp(s, src1, im, opsize);
2425 break;
2426 default:
2427 abort();
2429 tcg_temp_free(im);
2430 tcg_temp_free(dest);
2433 DISAS_INSN(cas)
2435 int opsize;
2436 TCGv addr;
2437 uint16_t ext;
2438 TCGv load;
2439 TCGv cmp;
2440 MemOp opc;
2442 switch ((insn >> 9) & 3) {
2443 case 1:
2444 opsize = OS_BYTE;
2445 opc = MO_SB;
2446 break;
2447 case 2:
2448 opsize = OS_WORD;
2449 opc = MO_TESW;
2450 break;
2451 case 3:
2452 opsize = OS_LONG;
2453 opc = MO_TESL;
2454 break;
2455 default:
2456 g_assert_not_reached();
2459 ext = read_im16(env, s);
2461 /* cas Dc,Du,<EA> */
2463 addr = gen_lea(env, s, insn, opsize);
2464 if (IS_NULL_QREG(addr)) {
2465 gen_addr_fault(s);
2466 return;
2469 cmp = gen_extend(s, DREG(ext, 0), opsize, 1);
2472 * if <EA> == Dc then
2473 * <EA> = Du
2474 * Dc = <EA> (because <EA> == Dc)
2475 * else
2476 * Dc = <EA>
2479 load = tcg_temp_new();
2480 tcg_gen_atomic_cmpxchg_i32(load, addr, cmp, DREG(ext, 6),
2481 IS_USER(s), opc);
2482 /* update flags before setting cmp to load */
2483 gen_update_cc_cmp(s, load, cmp, opsize);
2484 gen_partset_reg(opsize, DREG(ext, 0), load);
2486 tcg_temp_free(load);
2488 switch (extract32(insn, 3, 3)) {
2489 case 3: /* Indirect postincrement. */
2490 tcg_gen_addi_i32(AREG(insn, 0), addr, opsize_bytes(opsize));
2491 break;
2492 case 4: /* Indirect predecrememnt. */
2493 tcg_gen_mov_i32(AREG(insn, 0), addr);
2494 break;
2498 DISAS_INSN(cas2w)
2500 uint16_t ext1, ext2;
2501 TCGv addr1, addr2;
2502 TCGv regs;
2504 /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
2506 ext1 = read_im16(env, s);
2508 if (ext1 & 0x8000) {
2509 /* Address Register */
2510 addr1 = AREG(ext1, 12);
2511 } else {
2512 /* Data Register */
2513 addr1 = DREG(ext1, 12);
2516 ext2 = read_im16(env, s);
2517 if (ext2 & 0x8000) {
2518 /* Address Register */
2519 addr2 = AREG(ext2, 12);
2520 } else {
2521 /* Data Register */
2522 addr2 = DREG(ext2, 12);
2526 * if (R1) == Dc1 && (R2) == Dc2 then
2527 * (R1) = Du1
2528 * (R2) = Du2
2529 * else
2530 * Dc1 = (R1)
2531 * Dc2 = (R2)
2534 regs = tcg_const_i32(REG(ext2, 6) |
2535 (REG(ext1, 6) << 3) |
2536 (REG(ext2, 0) << 6) |
2537 (REG(ext1, 0) << 9));
2538 if (tb_cflags(s->base.tb) & CF_PARALLEL) {
2539 gen_helper_exit_atomic(cpu_env);
2540 } else {
2541 gen_helper_cas2w(cpu_env, regs, addr1, addr2);
2543 tcg_temp_free(regs);
2545 /* Note that cas2w also assigned to env->cc_op. */
2546 s->cc_op = CC_OP_CMPW;
2547 s->cc_op_synced = 1;
2550 DISAS_INSN(cas2l)
2552 uint16_t ext1, ext2;
2553 TCGv addr1, addr2, regs;
2555 /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
2557 ext1 = read_im16(env, s);
2559 if (ext1 & 0x8000) {
2560 /* Address Register */
2561 addr1 = AREG(ext1, 12);
2562 } else {
2563 /* Data Register */
2564 addr1 = DREG(ext1, 12);
2567 ext2 = read_im16(env, s);
2568 if (ext2 & 0x8000) {
2569 /* Address Register */
2570 addr2 = AREG(ext2, 12);
2571 } else {
2572 /* Data Register */
2573 addr2 = DREG(ext2, 12);
2577 * if (R1) == Dc1 && (R2) == Dc2 then
2578 * (R1) = Du1
2579 * (R2) = Du2
2580 * else
2581 * Dc1 = (R1)
2582 * Dc2 = (R2)
2585 regs = tcg_const_i32(REG(ext2, 6) |
2586 (REG(ext1, 6) << 3) |
2587 (REG(ext2, 0) << 6) |
2588 (REG(ext1, 0) << 9));
2589 if (tb_cflags(s->base.tb) & CF_PARALLEL) {
2590 gen_helper_cas2l_parallel(cpu_env, regs, addr1, addr2);
2591 } else {
2592 gen_helper_cas2l(cpu_env, regs, addr1, addr2);
2594 tcg_temp_free(regs);
2596 /* Note that cas2l also assigned to env->cc_op. */
2597 s->cc_op = CC_OP_CMPL;
2598 s->cc_op_synced = 1;
2601 DISAS_INSN(byterev)
2603 TCGv reg;
2605 reg = DREG(insn, 0);
2606 tcg_gen_bswap32_i32(reg, reg);
2609 DISAS_INSN(move)
2611 TCGv src;
2612 TCGv dest;
2613 int op;
2614 int opsize;
2616 switch (insn >> 12) {
2617 case 1: /* move.b */
2618 opsize = OS_BYTE;
2619 break;
2620 case 2: /* move.l */
2621 opsize = OS_LONG;
2622 break;
2623 case 3: /* move.w */
2624 opsize = OS_WORD;
2625 break;
2626 default:
2627 abort();
2629 SRC_EA(env, src, opsize, 1, NULL);
2630 op = (insn >> 6) & 7;
2631 if (op == 1) {
2632 /* movea */
2633 /* The value will already have been sign extended. */
2634 dest = AREG(insn, 9);
2635 tcg_gen_mov_i32(dest, src);
2636 } else {
2637 /* normal move */
2638 uint16_t dest_ea;
2639 dest_ea = ((insn >> 9) & 7) | (op << 3);
2640 DEST_EA(env, dest_ea, opsize, src, NULL);
2641 /* This will be correct because loads sign extend. */
2642 gen_logic_cc(s, src, opsize);
2646 DISAS_INSN(negx)
2648 TCGv z;
2649 TCGv src;
2650 TCGv addr;
2651 int opsize;
2653 opsize = insn_opsize(insn);
2654 SRC_EA(env, src, opsize, 1, &addr);
2656 gen_flush_flags(s); /* compute old Z */
2659 * Perform subtract with borrow.
2660 * (X, N) = -(src + X);
2663 z = tcg_const_i32(0);
2664 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z);
2665 tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X);
2666 tcg_temp_free(z);
2667 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2669 tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
2672 * Compute signed-overflow for negation. The normal formula for
2673 * subtraction is (res ^ src) & (src ^ dest), but with dest==0
2674 * this simplifies to res & src.
2677 tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, src);
2679 /* Copy the rest of the results into place. */
2680 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2681 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2683 set_cc_op(s, CC_OP_FLAGS);
2685 /* result is in QREG_CC_N */
2687 DEST_EA(env, insn, opsize, QREG_CC_N, &addr);
2690 DISAS_INSN(lea)
2692 TCGv reg;
2693 TCGv tmp;
2695 reg = AREG(insn, 9);
2696 tmp = gen_lea(env, s, insn, OS_LONG);
2697 if (IS_NULL_QREG(tmp)) {
2698 gen_addr_fault(s);
2699 return;
2701 tcg_gen_mov_i32(reg, tmp);
2704 DISAS_INSN(clr)
2706 int opsize;
2707 TCGv zero;
2709 zero = tcg_const_i32(0);
2711 opsize = insn_opsize(insn);
2712 DEST_EA(env, insn, opsize, zero, NULL);
2713 gen_logic_cc(s, zero, opsize);
2714 tcg_temp_free(zero);
2717 DISAS_INSN(move_from_ccr)
2719 TCGv ccr;
2721 ccr = gen_get_ccr(s);
2722 DEST_EA(env, insn, OS_WORD, ccr, NULL);
2725 DISAS_INSN(neg)
2727 TCGv src1;
2728 TCGv dest;
2729 TCGv addr;
2730 int opsize;
2732 opsize = insn_opsize(insn);
2733 SRC_EA(env, src1, opsize, 1, &addr);
2734 dest = tcg_temp_new();
2735 tcg_gen_neg_i32(dest, src1);
2736 set_cc_op(s, CC_OP_SUBB + opsize);
2737 gen_update_cc_add(dest, src1, opsize);
2738 tcg_gen_setcondi_i32(TCG_COND_NE, QREG_CC_X, dest, 0);
2739 DEST_EA(env, insn, opsize, dest, &addr);
2740 tcg_temp_free(dest);
2743 DISAS_INSN(move_to_ccr)
2745 gen_move_to_sr(env, s, insn, true);
2748 DISAS_INSN(not)
2750 TCGv src1;
2751 TCGv dest;
2752 TCGv addr;
2753 int opsize;
2755 opsize = insn_opsize(insn);
2756 SRC_EA(env, src1, opsize, 1, &addr);
2757 dest = tcg_temp_new();
2758 tcg_gen_not_i32(dest, src1);
2759 DEST_EA(env, insn, opsize, dest, &addr);
2760 gen_logic_cc(s, dest, opsize);
2763 DISAS_INSN(swap)
2765 TCGv src1;
2766 TCGv src2;
2767 TCGv reg;
2769 src1 = tcg_temp_new();
2770 src2 = tcg_temp_new();
2771 reg = DREG(insn, 0);
2772 tcg_gen_shli_i32(src1, reg, 16);
2773 tcg_gen_shri_i32(src2, reg, 16);
2774 tcg_gen_or_i32(reg, src1, src2);
2775 tcg_temp_free(src2);
2776 tcg_temp_free(src1);
2777 gen_logic_cc(s, reg, OS_LONG);
2780 DISAS_INSN(bkpt)
2782 gen_exception(s, s->base.pc_next, EXCP_DEBUG);
2785 DISAS_INSN(pea)
2787 TCGv tmp;
2789 tmp = gen_lea(env, s, insn, OS_LONG);
2790 if (IS_NULL_QREG(tmp)) {
2791 gen_addr_fault(s);
2792 return;
2794 gen_push(s, tmp);
2797 DISAS_INSN(ext)
2799 int op;
2800 TCGv reg;
2801 TCGv tmp;
2803 reg = DREG(insn, 0);
2804 op = (insn >> 6) & 7;
2805 tmp = tcg_temp_new();
2806 if (op == 3)
2807 tcg_gen_ext16s_i32(tmp, reg);
2808 else
2809 tcg_gen_ext8s_i32(tmp, reg);
2810 if (op == 2)
2811 gen_partset_reg(OS_WORD, reg, tmp);
2812 else
2813 tcg_gen_mov_i32(reg, tmp);
2814 gen_logic_cc(s, tmp, OS_LONG);
2815 tcg_temp_free(tmp);
2818 DISAS_INSN(tst)
2820 int opsize;
2821 TCGv tmp;
2823 opsize = insn_opsize(insn);
2824 SRC_EA(env, tmp, opsize, 1, NULL);
2825 gen_logic_cc(s, tmp, opsize);
2828 DISAS_INSN(pulse)
2830 /* Implemented as a NOP. */
2833 DISAS_INSN(illegal)
2835 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
2838 /* ??? This should be atomic. */
2839 DISAS_INSN(tas)
2841 TCGv dest;
2842 TCGv src1;
2843 TCGv addr;
2845 dest = tcg_temp_new();
2846 SRC_EA(env, src1, OS_BYTE, 1, &addr);
2847 gen_logic_cc(s, src1, OS_BYTE);
2848 tcg_gen_ori_i32(dest, src1, 0x80);
2849 DEST_EA(env, insn, OS_BYTE, dest, &addr);
2850 tcg_temp_free(dest);
2853 DISAS_INSN(mull)
2855 uint16_t ext;
2856 TCGv src1;
2857 int sign;
2859 ext = read_im16(env, s);
2861 sign = ext & 0x800;
2863 if (ext & 0x400) {
2864 if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
2865 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
2866 return;
2869 SRC_EA(env, src1, OS_LONG, 0, NULL);
2871 if (sign) {
2872 tcg_gen_muls2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
2873 } else {
2874 tcg_gen_mulu2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
2876 /* if Dl == Dh, 68040 returns low word */
2877 tcg_gen_mov_i32(DREG(ext, 0), QREG_CC_N);
2878 tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_Z);
2879 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N);
2881 tcg_gen_movi_i32(QREG_CC_V, 0);
2882 tcg_gen_movi_i32(QREG_CC_C, 0);
2884 set_cc_op(s, CC_OP_FLAGS);
2885 return;
2887 SRC_EA(env, src1, OS_LONG, 0, NULL);
2888 if (m68k_feature(s->env, M68K_FEATURE_M68000)) {
2889 tcg_gen_movi_i32(QREG_CC_C, 0);
2890 if (sign) {
2891 tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
2892 /* QREG_CC_V is -(QREG_CC_V != (QREG_CC_N >> 31)) */
2893 tcg_gen_sari_i32(QREG_CC_Z, QREG_CC_N, 31);
2894 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_Z);
2895 } else {
2896 tcg_gen_mulu2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
2897 /* QREG_CC_V is -(QREG_CC_V != 0), use QREG_CC_C as 0 */
2898 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_C);
2900 tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V);
2901 tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_N);
2903 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
2905 set_cc_op(s, CC_OP_FLAGS);
2906 } else {
2908 * The upper 32 bits of the product are discarded, so
2909 * muls.l and mulu.l are functionally equivalent.
2911 tcg_gen_mul_i32(DREG(ext, 12), src1, DREG(ext, 12));
2912 gen_logic_cc(s, DREG(ext, 12), OS_LONG);
2916 static void gen_link(DisasContext *s, uint16_t insn, int32_t offset)
2918 TCGv reg;
2919 TCGv tmp;
2921 reg = AREG(insn, 0);
2922 tmp = tcg_temp_new();
2923 tcg_gen_subi_i32(tmp, QREG_SP, 4);
2924 gen_store(s, OS_LONG, tmp, reg, IS_USER(s));
2925 if ((insn & 7) != 7) {
2926 tcg_gen_mov_i32(reg, tmp);
2928 tcg_gen_addi_i32(QREG_SP, tmp, offset);
2929 tcg_temp_free(tmp);
2932 DISAS_INSN(link)
2934 int16_t offset;
2936 offset = read_im16(env, s);
2937 gen_link(s, insn, offset);
2940 DISAS_INSN(linkl)
2942 int32_t offset;
2944 offset = read_im32(env, s);
2945 gen_link(s, insn, offset);
2948 DISAS_INSN(unlk)
2950 TCGv src;
2951 TCGv reg;
2952 TCGv tmp;
2954 src = tcg_temp_new();
2955 reg = AREG(insn, 0);
2956 tcg_gen_mov_i32(src, reg);
2957 tmp = gen_load(s, OS_LONG, src, 0, IS_USER(s));
2958 tcg_gen_mov_i32(reg, tmp);
2959 tcg_gen_addi_i32(QREG_SP, src, 4);
2960 tcg_temp_free(src);
2961 tcg_temp_free(tmp);
2964 #if defined(CONFIG_SOFTMMU)
2965 DISAS_INSN(reset)
2967 if (IS_USER(s)) {
2968 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
2969 return;
2972 gen_helper_reset(cpu_env);
2974 #endif
2976 DISAS_INSN(nop)
2980 DISAS_INSN(rtd)
2982 TCGv tmp;
2983 int16_t offset = read_im16(env, s);
2985 tmp = gen_load(s, OS_LONG, QREG_SP, 0, IS_USER(s));
2986 tcg_gen_addi_i32(QREG_SP, QREG_SP, offset + 4);
2987 gen_jmp(s, tmp);
2990 DISAS_INSN(rtr)
2992 TCGv tmp;
2993 TCGv ccr;
2994 TCGv sp;
2996 sp = tcg_temp_new();
2997 ccr = gen_load(s, OS_WORD, QREG_SP, 0, IS_USER(s));
2998 tcg_gen_addi_i32(sp, QREG_SP, 2);
2999 tmp = gen_load(s, OS_LONG, sp, 0, IS_USER(s));
3000 tcg_gen_addi_i32(QREG_SP, sp, 4);
3001 tcg_temp_free(sp);
3003 gen_set_sr(s, ccr, true);
3004 tcg_temp_free(ccr);
3006 gen_jmp(s, tmp);
3009 DISAS_INSN(rts)
3011 TCGv tmp;
3013 tmp = gen_load(s, OS_LONG, QREG_SP, 0, IS_USER(s));
3014 tcg_gen_addi_i32(QREG_SP, QREG_SP, 4);
3015 gen_jmp(s, tmp);
3018 DISAS_INSN(jump)
3020 TCGv tmp;
3023 * Load the target address first to ensure correct exception
3024 * behavior.
3026 tmp = gen_lea(env, s, insn, OS_LONG);
3027 if (IS_NULL_QREG(tmp)) {
3028 gen_addr_fault(s);
3029 return;
3031 if ((insn & 0x40) == 0) {
3032 /* jsr */
3033 gen_push(s, tcg_const_i32(s->pc));
3035 gen_jmp(s, tmp);
3038 DISAS_INSN(addsubq)
3040 TCGv src;
3041 TCGv dest;
3042 TCGv val;
3043 int imm;
3044 TCGv addr;
3045 int opsize;
3047 if ((insn & 070) == 010) {
3048 /* Operation on address register is always long. */
3049 opsize = OS_LONG;
3050 } else {
3051 opsize = insn_opsize(insn);
3053 SRC_EA(env, src, opsize, 1, &addr);
3054 imm = (insn >> 9) & 7;
3055 if (imm == 0) {
3056 imm = 8;
3058 val = tcg_const_i32(imm);
3059 dest = tcg_temp_new();
3060 tcg_gen_mov_i32(dest, src);
3061 if ((insn & 0x38) == 0x08) {
3063 * Don't update condition codes if the destination is an
3064 * address register.
3066 if (insn & 0x0100) {
3067 tcg_gen_sub_i32(dest, dest, val);
3068 } else {
3069 tcg_gen_add_i32(dest, dest, val);
3071 } else {
3072 if (insn & 0x0100) {
3073 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
3074 tcg_gen_sub_i32(dest, dest, val);
3075 set_cc_op(s, CC_OP_SUBB + opsize);
3076 } else {
3077 tcg_gen_add_i32(dest, dest, val);
3078 tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
3079 set_cc_op(s, CC_OP_ADDB + opsize);
3081 gen_update_cc_add(dest, val, opsize);
3083 tcg_temp_free(val);
3084 DEST_EA(env, insn, opsize, dest, &addr);
3085 tcg_temp_free(dest);
3088 DISAS_INSN(tpf)
3090 switch (insn & 7) {
3091 case 2: /* One extension word. */
3092 s->pc += 2;
3093 break;
3094 case 3: /* Two extension words. */
3095 s->pc += 4;
3096 break;
3097 case 4: /* No extension words. */
3098 break;
3099 default:
3100 disas_undef(env, s, insn);
3104 DISAS_INSN(branch)
3106 int32_t offset;
3107 uint32_t base;
3108 int op;
3110 base = s->pc;
3111 op = (insn >> 8) & 0xf;
3112 offset = (int8_t)insn;
3113 if (offset == 0) {
3114 offset = (int16_t)read_im16(env, s);
3115 } else if (offset == -1) {
3116 offset = read_im32(env, s);
3118 if (op == 1) {
3119 /* bsr */
3120 gen_push(s, tcg_const_i32(s->pc));
3122 if (op > 1) {
3123 /* Bcc */
3124 TCGLabel *l1 = gen_new_label();
3125 gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
3126 gen_jmp_tb(s, 1, base + offset);
3127 gen_set_label(l1);
3128 gen_jmp_tb(s, 0, s->pc);
3129 } else {
3130 /* Unconditional branch. */
3131 update_cc_op(s);
3132 gen_jmp_tb(s, 0, base + offset);
3136 DISAS_INSN(moveq)
3138 tcg_gen_movi_i32(DREG(insn, 9), (int8_t)insn);
3139 gen_logic_cc(s, DREG(insn, 9), OS_LONG);
3142 DISAS_INSN(mvzs)
3144 int opsize;
3145 TCGv src;
3146 TCGv reg;
3148 if (insn & 0x40)
3149 opsize = OS_WORD;
3150 else
3151 opsize = OS_BYTE;
3152 SRC_EA(env, src, opsize, (insn & 0x80) == 0, NULL);
3153 reg = DREG(insn, 9);
3154 tcg_gen_mov_i32(reg, src);
3155 gen_logic_cc(s, src, opsize);
3158 DISAS_INSN(or)
3160 TCGv reg;
3161 TCGv dest;
3162 TCGv src;
3163 TCGv addr;
3164 int opsize;
3166 opsize = insn_opsize(insn);
3167 reg = gen_extend(s, DREG(insn, 9), opsize, 0);
3168 dest = tcg_temp_new();
3169 if (insn & 0x100) {
3170 SRC_EA(env, src, opsize, 0, &addr);
3171 tcg_gen_or_i32(dest, src, reg);
3172 DEST_EA(env, insn, opsize, dest, &addr);
3173 } else {
3174 SRC_EA(env, src, opsize, 0, NULL);
3175 tcg_gen_or_i32(dest, src, reg);
3176 gen_partset_reg(opsize, DREG(insn, 9), dest);
3178 gen_logic_cc(s, dest, opsize);
3179 tcg_temp_free(dest);
3182 DISAS_INSN(suba)
3184 TCGv src;
3185 TCGv reg;
3187 SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
3188 reg = AREG(insn, 9);
3189 tcg_gen_sub_i32(reg, reg, src);
3192 static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
3194 TCGv tmp;
3196 gen_flush_flags(s); /* compute old Z */
3199 * Perform subtract with borrow.
3200 * (X, N) = dest - (src + X);
3203 tmp = tcg_const_i32(0);
3204 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, tmp, QREG_CC_X, tmp);
3205 tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, dest, tmp, QREG_CC_N, QREG_CC_X);
3206 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3207 tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
3209 /* Compute signed-overflow for subtract. */
3211 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, dest);
3212 tcg_gen_xor_i32(tmp, dest, src);
3213 tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, tmp);
3214 tcg_temp_free(tmp);
3216 /* Copy the rest of the results into place. */
3217 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
3218 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
3220 set_cc_op(s, CC_OP_FLAGS);
3222 /* result is in QREG_CC_N */
3225 DISAS_INSN(subx_reg)
3227 TCGv dest;
3228 TCGv src;
3229 int opsize;
3231 opsize = insn_opsize(insn);
3233 src = gen_extend(s, DREG(insn, 0), opsize, 1);
3234 dest = gen_extend(s, DREG(insn, 9), opsize, 1);
3236 gen_subx(s, src, dest, opsize);
3238 gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
3241 DISAS_INSN(subx_mem)
3243 TCGv src;
3244 TCGv addr_src;
3245 TCGv dest;
3246 TCGv addr_dest;
3247 int opsize;
3249 opsize = insn_opsize(insn);
3251 addr_src = AREG(insn, 0);
3252 tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
3253 src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
3255 addr_dest = AREG(insn, 9);
3256 tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
3257 dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
3259 gen_subx(s, src, dest, opsize);
3261 gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
3263 tcg_temp_free(dest);
3264 tcg_temp_free(src);
3267 DISAS_INSN(mov3q)
3269 TCGv src;
3270 int val;
3272 val = (insn >> 9) & 7;
3273 if (val == 0)
3274 val = -1;
3275 src = tcg_const_i32(val);
3276 gen_logic_cc(s, src, OS_LONG);
3277 DEST_EA(env, insn, OS_LONG, src, NULL);
3278 tcg_temp_free(src);
3281 DISAS_INSN(cmp)
3283 TCGv src;
3284 TCGv reg;
3285 int opsize;
3287 opsize = insn_opsize(insn);
3288 SRC_EA(env, src, opsize, 1, NULL);
3289 reg = gen_extend(s, DREG(insn, 9), opsize, 1);
3290 gen_update_cc_cmp(s, reg, src, opsize);
3293 DISAS_INSN(cmpa)
3295 int opsize;
3296 TCGv src;
3297 TCGv reg;
3299 if (insn & 0x100) {
3300 opsize = OS_LONG;
3301 } else {
3302 opsize = OS_WORD;
3304 SRC_EA(env, src, opsize, 1, NULL);
3305 reg = AREG(insn, 9);
3306 gen_update_cc_cmp(s, reg, src, OS_LONG);
3309 DISAS_INSN(cmpm)
3311 int opsize = insn_opsize(insn);
3312 TCGv src, dst;
3314 /* Post-increment load (mode 3) from Ay. */
3315 src = gen_ea_mode(env, s, 3, REG(insn, 0), opsize,
3316 NULL_QREG, NULL, EA_LOADS, IS_USER(s));
3317 /* Post-increment load (mode 3) from Ax. */
3318 dst = gen_ea_mode(env, s, 3, REG(insn, 9), opsize,
3319 NULL_QREG, NULL, EA_LOADS, IS_USER(s));
3321 gen_update_cc_cmp(s, dst, src, opsize);
3324 DISAS_INSN(eor)
3326 TCGv src;
3327 TCGv dest;
3328 TCGv addr;
3329 int opsize;
3331 opsize = insn_opsize(insn);
3333 SRC_EA(env, src, opsize, 0, &addr);
3334 dest = tcg_temp_new();
3335 tcg_gen_xor_i32(dest, src, DREG(insn, 9));
3336 gen_logic_cc(s, dest, opsize);
3337 DEST_EA(env, insn, opsize, dest, &addr);
3338 tcg_temp_free(dest);
3341 static void do_exg(TCGv reg1, TCGv reg2)
3343 TCGv temp = tcg_temp_new();
3344 tcg_gen_mov_i32(temp, reg1);
3345 tcg_gen_mov_i32(reg1, reg2);
3346 tcg_gen_mov_i32(reg2, temp);
3347 tcg_temp_free(temp);
3350 DISAS_INSN(exg_dd)
3352 /* exchange Dx and Dy */
3353 do_exg(DREG(insn, 9), DREG(insn, 0));
3356 DISAS_INSN(exg_aa)
3358 /* exchange Ax and Ay */
3359 do_exg(AREG(insn, 9), AREG(insn, 0));
3362 DISAS_INSN(exg_da)
3364 /* exchange Dx and Ay */
3365 do_exg(DREG(insn, 9), AREG(insn, 0));
3368 DISAS_INSN(and)
3370 TCGv src;
3371 TCGv reg;
3372 TCGv dest;
3373 TCGv addr;
3374 int opsize;
3376 dest = tcg_temp_new();
3378 opsize = insn_opsize(insn);
3379 reg = DREG(insn, 9);
3380 if (insn & 0x100) {
3381 SRC_EA(env, src, opsize, 0, &addr);
3382 tcg_gen_and_i32(dest, src, reg);
3383 DEST_EA(env, insn, opsize, dest, &addr);
3384 } else {
3385 SRC_EA(env, src, opsize, 0, NULL);
3386 tcg_gen_and_i32(dest, src, reg);
3387 gen_partset_reg(opsize, reg, dest);
3389 gen_logic_cc(s, dest, opsize);
3390 tcg_temp_free(dest);
3393 DISAS_INSN(adda)
3395 TCGv src;
3396 TCGv reg;
3398 SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
3399 reg = AREG(insn, 9);
3400 tcg_gen_add_i32(reg, reg, src);
3403 static inline void gen_addx(DisasContext *s, TCGv src, TCGv dest, int opsize)
3405 TCGv tmp;
3407 gen_flush_flags(s); /* compute old Z */
3410 * Perform addition with carry.
3411 * (X, N) = src + dest + X;
3414 tmp = tcg_const_i32(0);
3415 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_X, tmp, dest, tmp);
3416 tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, tmp);
3417 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3419 /* Compute signed-overflow for addition. */
3421 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
3422 tcg_gen_xor_i32(tmp, dest, src);
3423 tcg_gen_andc_i32(QREG_CC_V, QREG_CC_V, tmp);
3424 tcg_temp_free(tmp);
3426 /* Copy the rest of the results into place. */
3427 tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
3428 tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
3430 set_cc_op(s, CC_OP_FLAGS);
3432 /* result is in QREG_CC_N */
3435 DISAS_INSN(addx_reg)
3437 TCGv dest;
3438 TCGv src;
3439 int opsize;
3441 opsize = insn_opsize(insn);
3443 dest = gen_extend(s, DREG(insn, 9), opsize, 1);
3444 src = gen_extend(s, DREG(insn, 0), opsize, 1);
3446 gen_addx(s, src, dest, opsize);
3448 gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
3451 DISAS_INSN(addx_mem)
3453 TCGv src;
3454 TCGv addr_src;
3455 TCGv dest;
3456 TCGv addr_dest;
3457 int opsize;
3459 opsize = insn_opsize(insn);
3461 addr_src = AREG(insn, 0);
3462 tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
3463 src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
3465 addr_dest = AREG(insn, 9);
3466 tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
3467 dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
3469 gen_addx(s, src, dest, opsize);
3471 gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
3473 tcg_temp_free(dest);
3474 tcg_temp_free(src);
3477 static inline void shift_im(DisasContext *s, uint16_t insn, int opsize)
3479 int count = (insn >> 9) & 7;
3480 int logical = insn & 8;
3481 int left = insn & 0x100;
3482 int bits = opsize_bytes(opsize) * 8;
3483 TCGv reg = gen_extend(s, DREG(insn, 0), opsize, !logical);
3485 if (count == 0) {
3486 count = 8;
3489 tcg_gen_movi_i32(QREG_CC_V, 0);
3490 if (left) {
3491 tcg_gen_shri_i32(QREG_CC_C, reg, bits - count);
3492 tcg_gen_shli_i32(QREG_CC_N, reg, count);
3495 * Note that ColdFire always clears V (done above),
3496 * while M68000 sets if the most significant bit is changed at
3497 * any time during the shift operation.
3499 if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) {
3500 /* if shift count >= bits, V is (reg != 0) */
3501 if (count >= bits) {
3502 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, reg, QREG_CC_V);
3503 } else {
3504 TCGv t0 = tcg_temp_new();
3505 tcg_gen_sari_i32(QREG_CC_V, reg, bits - 1);
3506 tcg_gen_sari_i32(t0, reg, bits - count - 1);
3507 tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, t0);
3508 tcg_temp_free(t0);
3510 tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V);
3512 } else {
3513 tcg_gen_shri_i32(QREG_CC_C, reg, count - 1);
3514 if (logical) {
3515 tcg_gen_shri_i32(QREG_CC_N, reg, count);
3516 } else {
3517 tcg_gen_sari_i32(QREG_CC_N, reg, count);
3521 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3522 tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3523 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3524 tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
3526 gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N);
3527 set_cc_op(s, CC_OP_FLAGS);
3530 static inline void shift_reg(DisasContext *s, uint16_t insn, int opsize)
3532 int logical = insn & 8;
3533 int left = insn & 0x100;
3534 int bits = opsize_bytes(opsize) * 8;
3535 TCGv reg = gen_extend(s, DREG(insn, 0), opsize, !logical);
3536 TCGv s32;
3537 TCGv_i64 t64, s64;
3539 t64 = tcg_temp_new_i64();
3540 s64 = tcg_temp_new_i64();
3541 s32 = tcg_temp_new();
3544 * Note that m68k truncates the shift count modulo 64, not 32.
3545 * In addition, a 64-bit shift makes it easy to find "the last
3546 * bit shifted out", for the carry flag.
3548 tcg_gen_andi_i32(s32, DREG(insn, 9), 63);
3549 tcg_gen_extu_i32_i64(s64, s32);
3550 tcg_gen_extu_i32_i64(t64, reg);
3552 /* Optimistically set V=0. Also used as a zero source below. */
3553 tcg_gen_movi_i32(QREG_CC_V, 0);
3554 if (left) {
3555 tcg_gen_shl_i64(t64, t64, s64);
3557 if (opsize == OS_LONG) {
3558 tcg_gen_extr_i64_i32(QREG_CC_N, QREG_CC_C, t64);
3559 /* Note that C=0 if shift count is 0, and we get that for free. */
3560 } else {
3561 TCGv zero = tcg_const_i32(0);
3562 tcg_gen_extrl_i64_i32(QREG_CC_N, t64);
3563 tcg_gen_shri_i32(QREG_CC_C, QREG_CC_N, bits);
3564 tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
3565 s32, zero, zero, QREG_CC_C);
3566 tcg_temp_free(zero);
3568 tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3570 /* X = C, but only if the shift count was non-zero. */
3571 tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V,
3572 QREG_CC_C, QREG_CC_X);
3575 * M68000 sets V if the most significant bit is changed at
3576 * any time during the shift operation. Do this via creating
3577 * an extension of the sign bit, comparing, and discarding
3578 * the bits below the sign bit. I.e.
3579 * int64_t s = (intN_t)reg;
3580 * int64_t t = (int64_t)(intN_t)reg << count;
3581 * V = ((s ^ t) & (-1 << (bits - 1))) != 0
3583 if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) {
3584 TCGv_i64 tt = tcg_const_i64(32);
3585 /* if shift is greater than 32, use 32 */
3586 tcg_gen_movcond_i64(TCG_COND_GT, s64, s64, tt, tt, s64);
3587 tcg_temp_free_i64(tt);
3588 /* Sign extend the input to 64 bits; re-do the shift. */
3589 tcg_gen_ext_i32_i64(t64, reg);
3590 tcg_gen_shl_i64(s64, t64, s64);
3591 /* Clear all bits that are unchanged. */
3592 tcg_gen_xor_i64(t64, t64, s64);
3593 /* Ignore the bits below the sign bit. */
3594 tcg_gen_andi_i64(t64, t64, -1ULL << (bits - 1));
3595 /* If any bits remain set, we have overflow. */
3596 tcg_gen_setcondi_i64(TCG_COND_NE, t64, t64, 0);
3597 tcg_gen_extrl_i64_i32(QREG_CC_V, t64);
3598 tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V);
3600 } else {
3601 tcg_gen_shli_i64(t64, t64, 32);
3602 if (logical) {
3603 tcg_gen_shr_i64(t64, t64, s64);
3604 } else {
3605 tcg_gen_sar_i64(t64, t64, s64);
3607 tcg_gen_extr_i64_i32(QREG_CC_C, QREG_CC_N, t64);
3609 /* Note that C=0 if shift count is 0, and we get that for free. */
3610 tcg_gen_shri_i32(QREG_CC_C, QREG_CC_C, 31);
3612 /* X = C, but only if the shift count was non-zero. */
3613 tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V,
3614 QREG_CC_C, QREG_CC_X);
3616 gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3617 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3619 tcg_temp_free(s32);
3620 tcg_temp_free_i64(s64);
3621 tcg_temp_free_i64(t64);
3623 /* Write back the result. */
3624 gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N);
3625 set_cc_op(s, CC_OP_FLAGS);
3628 DISAS_INSN(shift8_im)
3630 shift_im(s, insn, OS_BYTE);
3633 DISAS_INSN(shift16_im)
3635 shift_im(s, insn, OS_WORD);
3638 DISAS_INSN(shift_im)
3640 shift_im(s, insn, OS_LONG);
3643 DISAS_INSN(shift8_reg)
3645 shift_reg(s, insn, OS_BYTE);
3648 DISAS_INSN(shift16_reg)
3650 shift_reg(s, insn, OS_WORD);
3653 DISAS_INSN(shift_reg)
3655 shift_reg(s, insn, OS_LONG);
3658 DISAS_INSN(shift_mem)
3660 int logical = insn & 8;
3661 int left = insn & 0x100;
3662 TCGv src;
3663 TCGv addr;
3665 SRC_EA(env, src, OS_WORD, !logical, &addr);
3666 tcg_gen_movi_i32(QREG_CC_V, 0);
3667 if (left) {
3668 tcg_gen_shri_i32(QREG_CC_C, src, 15);
3669 tcg_gen_shli_i32(QREG_CC_N, src, 1);
3672 * Note that ColdFire always clears V,
3673 * while M68000 sets if the most significant bit is changed at
3674 * any time during the shift operation
3676 if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) {
3677 src = gen_extend(s, src, OS_WORD, 1);
3678 tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
3680 } else {
3681 tcg_gen_mov_i32(QREG_CC_C, src);
3682 if (logical) {
3683 tcg_gen_shri_i32(QREG_CC_N, src, 1);
3684 } else {
3685 tcg_gen_sari_i32(QREG_CC_N, src, 1);
3689 gen_ext(QREG_CC_N, QREG_CC_N, OS_WORD, 1);
3690 tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3691 tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3692 tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
3694 DEST_EA(env, insn, OS_WORD, QREG_CC_N, &addr);
3695 set_cc_op(s, CC_OP_FLAGS);
3698 static void rotate(TCGv reg, TCGv shift, int left, int size)
3700 switch (size) {
3701 case 8:
3702 /* Replicate the 8-bit input so that a 32-bit rotate works. */
3703 tcg_gen_ext8u_i32(reg, reg);
3704 tcg_gen_muli_i32(reg, reg, 0x01010101);
3705 goto do_long;
3706 case 16:
3707 /* Replicate the 16-bit input so that a 32-bit rotate works. */
3708 tcg_gen_deposit_i32(reg, reg, reg, 16, 16);
3709 goto do_long;
3710 do_long:
3711 default:
3712 if (left) {
3713 tcg_gen_rotl_i32(reg, reg, shift);
3714 } else {
3715 tcg_gen_rotr_i32(reg, reg, shift);
3719 /* compute flags */
3721 switch (size) {
3722 case 8:
3723 tcg_gen_ext8s_i32(reg, reg);
3724 break;
3725 case 16:
3726 tcg_gen_ext16s_i32(reg, reg);
3727 break;
3728 default:
3729 break;
3732 /* QREG_CC_X is not affected */
3734 tcg_gen_mov_i32(QREG_CC_N, reg);
3735 tcg_gen_mov_i32(QREG_CC_Z, reg);
3737 if (left) {
3738 tcg_gen_andi_i32(QREG_CC_C, reg, 1);
3739 } else {
3740 tcg_gen_shri_i32(QREG_CC_C, reg, 31);
3743 tcg_gen_movi_i32(QREG_CC_V, 0); /* always cleared */
3746 static void rotate_x_flags(TCGv reg, TCGv X, int size)
3748 switch (size) {
3749 case 8:
3750 tcg_gen_ext8s_i32(reg, reg);
3751 break;
3752 case 16:
3753 tcg_gen_ext16s_i32(reg, reg);
3754 break;
3755 default:
3756 break;
3758 tcg_gen_mov_i32(QREG_CC_N, reg);
3759 tcg_gen_mov_i32(QREG_CC_Z, reg);
3760 tcg_gen_mov_i32(QREG_CC_X, X);
3761 tcg_gen_mov_i32(QREG_CC_C, X);
3762 tcg_gen_movi_i32(QREG_CC_V, 0);
3765 /* Result of rotate_x() is valid if 0 <= shift <= size */
3766 static TCGv rotate_x(TCGv reg, TCGv shift, int left, int size)
3768 TCGv X, shl, shr, shx, sz, zero;
3770 sz = tcg_const_i32(size);
3772 shr = tcg_temp_new();
3773 shl = tcg_temp_new();
3774 shx = tcg_temp_new();
3775 if (left) {
3776 tcg_gen_mov_i32(shl, shift); /* shl = shift */
3777 tcg_gen_movi_i32(shr, size + 1);
3778 tcg_gen_sub_i32(shr, shr, shift); /* shr = size + 1 - shift */
3779 tcg_gen_subi_i32(shx, shift, 1); /* shx = shift - 1 */
3780 /* shx = shx < 0 ? size : shx; */
3781 zero = tcg_const_i32(0);
3782 tcg_gen_movcond_i32(TCG_COND_LT, shx, shx, zero, sz, shx);
3783 tcg_temp_free(zero);
3784 } else {
3785 tcg_gen_mov_i32(shr, shift); /* shr = shift */
3786 tcg_gen_movi_i32(shl, size + 1);
3787 tcg_gen_sub_i32(shl, shl, shift); /* shl = size + 1 - shift */
3788 tcg_gen_sub_i32(shx, sz, shift); /* shx = size - shift */
3790 tcg_temp_free_i32(sz);
3792 /* reg = (reg << shl) | (reg >> shr) | (x << shx); */
3794 tcg_gen_shl_i32(shl, reg, shl);
3795 tcg_gen_shr_i32(shr, reg, shr);
3796 tcg_gen_or_i32(reg, shl, shr);
3797 tcg_temp_free(shl);
3798 tcg_temp_free(shr);
3799 tcg_gen_shl_i32(shx, QREG_CC_X, shx);
3800 tcg_gen_or_i32(reg, reg, shx);
3801 tcg_temp_free(shx);
3803 /* X = (reg >> size) & 1 */
3805 X = tcg_temp_new();
3806 tcg_gen_extract_i32(X, reg, size, 1);
3808 return X;
3811 /* Result of rotate32_x() is valid if 0 <= shift < 33 */
3812 static TCGv rotate32_x(TCGv reg, TCGv shift, int left)
3814 TCGv_i64 t0, shift64;
3815 TCGv X, lo, hi, zero;
3817 shift64 = tcg_temp_new_i64();
3818 tcg_gen_extu_i32_i64(shift64, shift);
3820 t0 = tcg_temp_new_i64();
3822 X = tcg_temp_new();
3823 lo = tcg_temp_new();
3824 hi = tcg_temp_new();
3826 if (left) {
3827 /* create [reg:X:..] */
3829 tcg_gen_shli_i32(lo, QREG_CC_X, 31);
3830 tcg_gen_concat_i32_i64(t0, lo, reg);
3832 /* rotate */
3834 tcg_gen_rotl_i64(t0, t0, shift64);
3835 tcg_temp_free_i64(shift64);
3837 /* result is [reg:..:reg:X] */
3839 tcg_gen_extr_i64_i32(lo, hi, t0);
3840 tcg_gen_andi_i32(X, lo, 1);
3842 tcg_gen_shri_i32(lo, lo, 1);
3843 } else {
3844 /* create [..:X:reg] */
3846 tcg_gen_concat_i32_i64(t0, reg, QREG_CC_X);
3848 tcg_gen_rotr_i64(t0, t0, shift64);
3849 tcg_temp_free_i64(shift64);
3851 /* result is value: [X:reg:..:reg] */
3853 tcg_gen_extr_i64_i32(lo, hi, t0);
3855 /* extract X */
3857 tcg_gen_shri_i32(X, hi, 31);
3859 /* extract result */
3861 tcg_gen_shli_i32(hi, hi, 1);
3863 tcg_temp_free_i64(t0);
3864 tcg_gen_or_i32(lo, lo, hi);
3865 tcg_temp_free(hi);
3867 /* if shift == 0, register and X are not affected */
3869 zero = tcg_const_i32(0);
3870 tcg_gen_movcond_i32(TCG_COND_EQ, X, shift, zero, QREG_CC_X, X);
3871 tcg_gen_movcond_i32(TCG_COND_EQ, reg, shift, zero, reg, lo);
3872 tcg_temp_free(zero);
3873 tcg_temp_free(lo);
3875 return X;
3878 DISAS_INSN(rotate_im)
3880 TCGv shift;
3881 int tmp;
3882 int left = (insn & 0x100);
3884 tmp = (insn >> 9) & 7;
3885 if (tmp == 0) {
3886 tmp = 8;
3889 shift = tcg_const_i32(tmp);
3890 if (insn & 8) {
3891 rotate(DREG(insn, 0), shift, left, 32);
3892 } else {
3893 TCGv X = rotate32_x(DREG(insn, 0), shift, left);
3894 rotate_x_flags(DREG(insn, 0), X, 32);
3895 tcg_temp_free(X);
3897 tcg_temp_free(shift);
3899 set_cc_op(s, CC_OP_FLAGS);
3902 DISAS_INSN(rotate8_im)
3904 int left = (insn & 0x100);
3905 TCGv reg;
3906 TCGv shift;
3907 int tmp;
3909 reg = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
3911 tmp = (insn >> 9) & 7;
3912 if (tmp == 0) {
3913 tmp = 8;
3916 shift = tcg_const_i32(tmp);
3917 if (insn & 8) {
3918 rotate(reg, shift, left, 8);
3919 } else {
3920 TCGv X = rotate_x(reg, shift, left, 8);
3921 rotate_x_flags(reg, X, 8);
3922 tcg_temp_free(X);
3924 tcg_temp_free(shift);
3925 gen_partset_reg(OS_BYTE, DREG(insn, 0), reg);
3926 set_cc_op(s, CC_OP_FLAGS);
3929 DISAS_INSN(rotate16_im)
3931 int left = (insn & 0x100);
3932 TCGv reg;
3933 TCGv shift;
3934 int tmp;
3936 reg = gen_extend(s, DREG(insn, 0), OS_WORD, 0);
3937 tmp = (insn >> 9) & 7;
3938 if (tmp == 0) {
3939 tmp = 8;
3942 shift = tcg_const_i32(tmp);
3943 if (insn & 8) {
3944 rotate(reg, shift, left, 16);
3945 } else {
3946 TCGv X = rotate_x(reg, shift, left, 16);
3947 rotate_x_flags(reg, X, 16);
3948 tcg_temp_free(X);
3950 tcg_temp_free(shift);
3951 gen_partset_reg(OS_WORD, DREG(insn, 0), reg);
3952 set_cc_op(s, CC_OP_FLAGS);
3955 DISAS_INSN(rotate_reg)
3957 TCGv reg;
3958 TCGv src;
3959 TCGv t0, t1;
3960 int left = (insn & 0x100);
3962 reg = DREG(insn, 0);
3963 src = DREG(insn, 9);
3964 /* shift in [0..63] */
3965 t0 = tcg_temp_new();
3966 tcg_gen_andi_i32(t0, src, 63);
3967 t1 = tcg_temp_new_i32();
3968 if (insn & 8) {
3969 tcg_gen_andi_i32(t1, src, 31);
3970 rotate(reg, t1, left, 32);
3971 /* if shift == 0, clear C */
3972 tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
3973 t0, QREG_CC_V /* 0 */,
3974 QREG_CC_V /* 0 */, QREG_CC_C);
3975 } else {
3976 TCGv X;
3977 /* modulo 33 */
3978 tcg_gen_movi_i32(t1, 33);
3979 tcg_gen_remu_i32(t1, t0, t1);
3980 X = rotate32_x(DREG(insn, 0), t1, left);
3981 rotate_x_flags(DREG(insn, 0), X, 32);
3982 tcg_temp_free(X);
3984 tcg_temp_free(t1);
3985 tcg_temp_free(t0);
3986 set_cc_op(s, CC_OP_FLAGS);
3989 DISAS_INSN(rotate8_reg)
3991 TCGv reg;
3992 TCGv src;
3993 TCGv t0, t1;
3994 int left = (insn & 0x100);
3996 reg = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
3997 src = DREG(insn, 9);
3998 /* shift in [0..63] */
3999 t0 = tcg_temp_new_i32();
4000 tcg_gen_andi_i32(t0, src, 63);
4001 t1 = tcg_temp_new_i32();
4002 if (insn & 8) {
4003 tcg_gen_andi_i32(t1, src, 7);
4004 rotate(reg, t1, left, 8);
4005 /* if shift == 0, clear C */
4006 tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
4007 t0, QREG_CC_V /* 0 */,
4008 QREG_CC_V /* 0 */, QREG_CC_C);
4009 } else {
4010 TCGv X;
4011 /* modulo 9 */
4012 tcg_gen_movi_i32(t1, 9);
4013 tcg_gen_remu_i32(t1, t0, t1);
4014 X = rotate_x(reg, t1, left, 8);
4015 rotate_x_flags(reg, X, 8);
4016 tcg_temp_free(X);
4018 tcg_temp_free(t1);
4019 tcg_temp_free(t0);
4020 gen_partset_reg(OS_BYTE, DREG(insn, 0), reg);
4021 set_cc_op(s, CC_OP_FLAGS);
4024 DISAS_INSN(rotate16_reg)
4026 TCGv reg;
4027 TCGv src;
4028 TCGv t0, t1;
4029 int left = (insn & 0x100);
4031 reg = gen_extend(s, DREG(insn, 0), OS_WORD, 0);
4032 src = DREG(insn, 9);
4033 /* shift in [0..63] */
4034 t0 = tcg_temp_new_i32();
4035 tcg_gen_andi_i32(t0, src, 63);
4036 t1 = tcg_temp_new_i32();
4037 if (insn & 8) {
4038 tcg_gen_andi_i32(t1, src, 15);
4039 rotate(reg, t1, left, 16);
4040 /* if shift == 0, clear C */
4041 tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
4042 t0, QREG_CC_V /* 0 */,
4043 QREG_CC_V /* 0 */, QREG_CC_C);
4044 } else {
4045 TCGv X;
4046 /* modulo 17 */
4047 tcg_gen_movi_i32(t1, 17);
4048 tcg_gen_remu_i32(t1, t0, t1);
4049 X = rotate_x(reg, t1, left, 16);
4050 rotate_x_flags(reg, X, 16);
4051 tcg_temp_free(X);
4053 tcg_temp_free(t1);
4054 tcg_temp_free(t0);
4055 gen_partset_reg(OS_WORD, DREG(insn, 0), reg);
4056 set_cc_op(s, CC_OP_FLAGS);
4059 DISAS_INSN(rotate_mem)
4061 TCGv src;
4062 TCGv addr;
4063 TCGv shift;
4064 int left = (insn & 0x100);
4066 SRC_EA(env, src, OS_WORD, 0, &addr);
4068 shift = tcg_const_i32(1);
4069 if (insn & 0x0200) {
4070 rotate(src, shift, left, 16);
4071 } else {
4072 TCGv X = rotate_x(src, shift, left, 16);
4073 rotate_x_flags(src, X, 16);
4074 tcg_temp_free(X);
4076 tcg_temp_free(shift);
4077 DEST_EA(env, insn, OS_WORD, src, &addr);
4078 set_cc_op(s, CC_OP_FLAGS);
4081 DISAS_INSN(bfext_reg)
4083 int ext = read_im16(env, s);
4084 int is_sign = insn & 0x200;
4085 TCGv src = DREG(insn, 0);
4086 TCGv dst = DREG(ext, 12);
4087 int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
4088 int ofs = extract32(ext, 6, 5); /* big bit-endian */
4089 int pos = 32 - ofs - len; /* little bit-endian */
4090 TCGv tmp = tcg_temp_new();
4091 TCGv shift;
4094 * In general, we're going to rotate the field so that it's at the
4095 * top of the word and then right-shift by the complement of the
4096 * width to extend the field.
4098 if (ext & 0x20) {
4099 /* Variable width. */
4100 if (ext & 0x800) {
4101 /* Variable offset. */
4102 tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
4103 tcg_gen_rotl_i32(tmp, src, tmp);
4104 } else {
4105 tcg_gen_rotli_i32(tmp, src, ofs);
4108 shift = tcg_temp_new();
4109 tcg_gen_neg_i32(shift, DREG(ext, 0));
4110 tcg_gen_andi_i32(shift, shift, 31);
4111 tcg_gen_sar_i32(QREG_CC_N, tmp, shift);
4112 if (is_sign) {
4113 tcg_gen_mov_i32(dst, QREG_CC_N);
4114 } else {
4115 tcg_gen_shr_i32(dst, tmp, shift);
4117 tcg_temp_free(shift);
4118 } else {
4119 /* Immediate width. */
4120 if (ext & 0x800) {
4121 /* Variable offset */
4122 tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
4123 tcg_gen_rotl_i32(tmp, src, tmp);
4124 src = tmp;
4125 pos = 32 - len;
4126 } else {
4128 * Immediate offset. If the field doesn't wrap around the
4129 * end of the word, rely on (s)extract completely.
4131 if (pos < 0) {
4132 tcg_gen_rotli_i32(tmp, src, ofs);
4133 src = tmp;
4134 pos = 32 - len;
4138 tcg_gen_sextract_i32(QREG_CC_N, src, pos, len);
4139 if (is_sign) {
4140 tcg_gen_mov_i32(dst, QREG_CC_N);
4141 } else {
4142 tcg_gen_extract_i32(dst, src, pos, len);
4146 tcg_temp_free(tmp);
4147 set_cc_op(s, CC_OP_LOGIC);
4150 DISAS_INSN(bfext_mem)
4152 int ext = read_im16(env, s);
4153 int is_sign = insn & 0x200;
4154 TCGv dest = DREG(ext, 12);
4155 TCGv addr, len, ofs;
4157 addr = gen_lea(env, s, insn, OS_UNSIZED);
4158 if (IS_NULL_QREG(addr)) {
4159 gen_addr_fault(s);
4160 return;
4163 if (ext & 0x20) {
4164 len = DREG(ext, 0);
4165 } else {
4166 len = tcg_const_i32(extract32(ext, 0, 5));
4168 if (ext & 0x800) {
4169 ofs = DREG(ext, 6);
4170 } else {
4171 ofs = tcg_const_i32(extract32(ext, 6, 5));
4174 if (is_sign) {
4175 gen_helper_bfexts_mem(dest, cpu_env, addr, ofs, len);
4176 tcg_gen_mov_i32(QREG_CC_N, dest);
4177 } else {
4178 TCGv_i64 tmp = tcg_temp_new_i64();
4179 gen_helper_bfextu_mem(tmp, cpu_env, addr, ofs, len);
4180 tcg_gen_extr_i64_i32(dest, QREG_CC_N, tmp);
4181 tcg_temp_free_i64(tmp);
4183 set_cc_op(s, CC_OP_LOGIC);
4185 if (!(ext & 0x20)) {
4186 tcg_temp_free(len);
4188 if (!(ext & 0x800)) {
4189 tcg_temp_free(ofs);
4193 DISAS_INSN(bfop_reg)
4195 int ext = read_im16(env, s);
4196 TCGv src = DREG(insn, 0);
4197 int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
4198 int ofs = extract32(ext, 6, 5); /* big bit-endian */
4199 TCGv mask, tofs, tlen;
4201 tofs = NULL;
4202 tlen = NULL;
4203 if ((insn & 0x0f00) == 0x0d00) { /* bfffo */
4204 tofs = tcg_temp_new();
4205 tlen = tcg_temp_new();
4208 if ((ext & 0x820) == 0) {
4209 /* Immediate width and offset. */
4210 uint32_t maski = 0x7fffffffu >> (len - 1);
4211 if (ofs + len <= 32) {
4212 tcg_gen_shli_i32(QREG_CC_N, src, ofs);
4213 } else {
4214 tcg_gen_rotli_i32(QREG_CC_N, src, ofs);
4216 tcg_gen_andi_i32(QREG_CC_N, QREG_CC_N, ~maski);
4217 mask = tcg_const_i32(ror32(maski, ofs));
4218 if (tofs) {
4219 tcg_gen_movi_i32(tofs, ofs);
4220 tcg_gen_movi_i32(tlen, len);
4222 } else {
4223 TCGv tmp = tcg_temp_new();
4224 if (ext & 0x20) {
4225 /* Variable width */
4226 tcg_gen_subi_i32(tmp, DREG(ext, 0), 1);
4227 tcg_gen_andi_i32(tmp, tmp, 31);
4228 mask = tcg_const_i32(0x7fffffffu);
4229 tcg_gen_shr_i32(mask, mask, tmp);
4230 if (tlen) {
4231 tcg_gen_addi_i32(tlen, tmp, 1);
4233 } else {
4234 /* Immediate width */
4235 mask = tcg_const_i32(0x7fffffffu >> (len - 1));
4236 if (tlen) {
4237 tcg_gen_movi_i32(tlen, len);
4240 if (ext & 0x800) {
4241 /* Variable offset */
4242 tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
4243 tcg_gen_rotl_i32(QREG_CC_N, src, tmp);
4244 tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask);
4245 tcg_gen_rotr_i32(mask, mask, tmp);
4246 if (tofs) {
4247 tcg_gen_mov_i32(tofs, tmp);
4249 } else {
4250 /* Immediate offset (and variable width) */
4251 tcg_gen_rotli_i32(QREG_CC_N, src, ofs);
4252 tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask);
4253 tcg_gen_rotri_i32(mask, mask, ofs);
4254 if (tofs) {
4255 tcg_gen_movi_i32(tofs, ofs);
4258 tcg_temp_free(tmp);
4260 set_cc_op(s, CC_OP_LOGIC);
4262 switch (insn & 0x0f00) {
4263 case 0x0a00: /* bfchg */
4264 tcg_gen_eqv_i32(src, src, mask);
4265 break;
4266 case 0x0c00: /* bfclr */
4267 tcg_gen_and_i32(src, src, mask);
4268 break;
4269 case 0x0d00: /* bfffo */
4270 gen_helper_bfffo_reg(DREG(ext, 12), QREG_CC_N, tofs, tlen);
4271 tcg_temp_free(tlen);
4272 tcg_temp_free(tofs);
4273 break;
4274 case 0x0e00: /* bfset */
4275 tcg_gen_orc_i32(src, src, mask);
4276 break;
4277 case 0x0800: /* bftst */
4278 /* flags already set; no other work to do. */
4279 break;
4280 default:
4281 g_assert_not_reached();
4283 tcg_temp_free(mask);
4286 DISAS_INSN(bfop_mem)
4288 int ext = read_im16(env, s);
4289 TCGv addr, len, ofs;
4290 TCGv_i64 t64;
4292 addr = gen_lea(env, s, insn, OS_UNSIZED);
4293 if (IS_NULL_QREG(addr)) {
4294 gen_addr_fault(s);
4295 return;
4298 if (ext & 0x20) {
4299 len = DREG(ext, 0);
4300 } else {
4301 len = tcg_const_i32(extract32(ext, 0, 5));
4303 if (ext & 0x800) {
4304 ofs = DREG(ext, 6);
4305 } else {
4306 ofs = tcg_const_i32(extract32(ext, 6, 5));
4309 switch (insn & 0x0f00) {
4310 case 0x0a00: /* bfchg */
4311 gen_helper_bfchg_mem(QREG_CC_N, cpu_env, addr, ofs, len);
4312 break;
4313 case 0x0c00: /* bfclr */
4314 gen_helper_bfclr_mem(QREG_CC_N, cpu_env, addr, ofs, len);
4315 break;
4316 case 0x0d00: /* bfffo */
4317 t64 = tcg_temp_new_i64();
4318 gen_helper_bfffo_mem(t64, cpu_env, addr, ofs, len);
4319 tcg_gen_extr_i64_i32(DREG(ext, 12), QREG_CC_N, t64);
4320 tcg_temp_free_i64(t64);
4321 break;
4322 case 0x0e00: /* bfset */
4323 gen_helper_bfset_mem(QREG_CC_N, cpu_env, addr, ofs, len);
4324 break;
4325 case 0x0800: /* bftst */
4326 gen_helper_bfexts_mem(QREG_CC_N, cpu_env, addr, ofs, len);
4327 break;
4328 default:
4329 g_assert_not_reached();
4331 set_cc_op(s, CC_OP_LOGIC);
4333 if (!(ext & 0x20)) {
4334 tcg_temp_free(len);
4336 if (!(ext & 0x800)) {
4337 tcg_temp_free(ofs);
4341 DISAS_INSN(bfins_reg)
4343 int ext = read_im16(env, s);
4344 TCGv dst = DREG(insn, 0);
4345 TCGv src = DREG(ext, 12);
4346 int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
4347 int ofs = extract32(ext, 6, 5); /* big bit-endian */
4348 int pos = 32 - ofs - len; /* little bit-endian */
4349 TCGv tmp;
4351 tmp = tcg_temp_new();
4353 if (ext & 0x20) {
4354 /* Variable width */
4355 tcg_gen_neg_i32(tmp, DREG(ext, 0));
4356 tcg_gen_andi_i32(tmp, tmp, 31);
4357 tcg_gen_shl_i32(QREG_CC_N, src, tmp);
4358 } else {
4359 /* Immediate width */
4360 tcg_gen_shli_i32(QREG_CC_N, src, 32 - len);
4362 set_cc_op(s, CC_OP_LOGIC);
4364 /* Immediate width and offset */
4365 if ((ext & 0x820) == 0) {
4366 /* Check for suitability for deposit. */
4367 if (pos >= 0) {
4368 tcg_gen_deposit_i32(dst, dst, src, pos, len);
4369 } else {
4370 uint32_t maski = -2U << (len - 1);
4371 uint32_t roti = (ofs + len) & 31;
4372 tcg_gen_andi_i32(tmp, src, ~maski);
4373 tcg_gen_rotri_i32(tmp, tmp, roti);
4374 tcg_gen_andi_i32(dst, dst, ror32(maski, roti));
4375 tcg_gen_or_i32(dst, dst, tmp);
4377 } else {
4378 TCGv mask = tcg_temp_new();
4379 TCGv rot = tcg_temp_new();
4381 if (ext & 0x20) {
4382 /* Variable width */
4383 tcg_gen_subi_i32(rot, DREG(ext, 0), 1);
4384 tcg_gen_andi_i32(rot, rot, 31);
4385 tcg_gen_movi_i32(mask, -2);
4386 tcg_gen_shl_i32(mask, mask, rot);
4387 tcg_gen_mov_i32(rot, DREG(ext, 0));
4388 tcg_gen_andc_i32(tmp, src, mask);
4389 } else {
4390 /* Immediate width (variable offset) */
4391 uint32_t maski = -2U << (len - 1);
4392 tcg_gen_andi_i32(tmp, src, ~maski);
4393 tcg_gen_movi_i32(mask, maski);
4394 tcg_gen_movi_i32(rot, len & 31);
4396 if (ext & 0x800) {
4397 /* Variable offset */
4398 tcg_gen_add_i32(rot, rot, DREG(ext, 6));
4399 } else {
4400 /* Immediate offset (variable width) */
4401 tcg_gen_addi_i32(rot, rot, ofs);
4403 tcg_gen_andi_i32(rot, rot, 31);
4404 tcg_gen_rotr_i32(mask, mask, rot);
4405 tcg_gen_rotr_i32(tmp, tmp, rot);
4406 tcg_gen_and_i32(dst, dst, mask);
4407 tcg_gen_or_i32(dst, dst, tmp);
4409 tcg_temp_free(rot);
4410 tcg_temp_free(mask);
4412 tcg_temp_free(tmp);
4415 DISAS_INSN(bfins_mem)
4417 int ext = read_im16(env, s);
4418 TCGv src = DREG(ext, 12);
4419 TCGv addr, len, ofs;
4421 addr = gen_lea(env, s, insn, OS_UNSIZED);
4422 if (IS_NULL_QREG(addr)) {
4423 gen_addr_fault(s);
4424 return;
4427 if (ext & 0x20) {
4428 len = DREG(ext, 0);
4429 } else {
4430 len = tcg_const_i32(extract32(ext, 0, 5));
4432 if (ext & 0x800) {
4433 ofs = DREG(ext, 6);
4434 } else {
4435 ofs = tcg_const_i32(extract32(ext, 6, 5));
4438 gen_helper_bfins_mem(QREG_CC_N, cpu_env, addr, src, ofs, len);
4439 set_cc_op(s, CC_OP_LOGIC);
4441 if (!(ext & 0x20)) {
4442 tcg_temp_free(len);
4444 if (!(ext & 0x800)) {
4445 tcg_temp_free(ofs);
4449 DISAS_INSN(ff1)
4451 TCGv reg;
4452 reg = DREG(insn, 0);
4453 gen_logic_cc(s, reg, OS_LONG);
4454 gen_helper_ff1(reg, reg);
4457 DISAS_INSN(chk)
4459 TCGv src, reg;
4460 int opsize;
4462 switch ((insn >> 7) & 3) {
4463 case 3:
4464 opsize = OS_WORD;
4465 break;
4466 case 2:
4467 if (m68k_feature(env, M68K_FEATURE_CHK2)) {
4468 opsize = OS_LONG;
4469 break;
4471 /* fallthru */
4472 default:
4473 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4474 return;
4476 SRC_EA(env, src, opsize, 1, NULL);
4477 reg = gen_extend(s, DREG(insn, 9), opsize, 1);
4479 gen_flush_flags(s);
4480 gen_helper_chk(cpu_env, reg, src);
4483 DISAS_INSN(chk2)
4485 uint16_t ext;
4486 TCGv addr1, addr2, bound1, bound2, reg;
4487 int opsize;
4489 switch ((insn >> 9) & 3) {
4490 case 0:
4491 opsize = OS_BYTE;
4492 break;
4493 case 1:
4494 opsize = OS_WORD;
4495 break;
4496 case 2:
4497 opsize = OS_LONG;
4498 break;
4499 default:
4500 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4501 return;
4504 ext = read_im16(env, s);
4505 if ((ext & 0x0800) == 0) {
4506 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4507 return;
4510 addr1 = gen_lea(env, s, insn, OS_UNSIZED);
4511 addr2 = tcg_temp_new();
4512 tcg_gen_addi_i32(addr2, addr1, opsize_bytes(opsize));
4514 bound1 = gen_load(s, opsize, addr1, 1, IS_USER(s));
4515 tcg_temp_free(addr1);
4516 bound2 = gen_load(s, opsize, addr2, 1, IS_USER(s));
4517 tcg_temp_free(addr2);
4519 reg = tcg_temp_new();
4520 if (ext & 0x8000) {
4521 tcg_gen_mov_i32(reg, AREG(ext, 12));
4522 } else {
4523 gen_ext(reg, DREG(ext, 12), opsize, 1);
4526 gen_flush_flags(s);
4527 gen_helper_chk2(cpu_env, reg, bound1, bound2);
4528 tcg_temp_free(reg);
4529 tcg_temp_free(bound1);
4530 tcg_temp_free(bound2);
4533 static void m68k_copy_line(TCGv dst, TCGv src, int index)
4535 TCGv addr;
4536 TCGv_i64 t0, t1;
4538 addr = tcg_temp_new();
4540 t0 = tcg_temp_new_i64();
4541 t1 = tcg_temp_new_i64();
4543 tcg_gen_andi_i32(addr, src, ~15);
4544 tcg_gen_qemu_ld64(t0, addr, index);
4545 tcg_gen_addi_i32(addr, addr, 8);
4546 tcg_gen_qemu_ld64(t1, addr, index);
4548 tcg_gen_andi_i32(addr, dst, ~15);
4549 tcg_gen_qemu_st64(t0, addr, index);
4550 tcg_gen_addi_i32(addr, addr, 8);
4551 tcg_gen_qemu_st64(t1, addr, index);
4553 tcg_temp_free_i64(t0);
4554 tcg_temp_free_i64(t1);
4555 tcg_temp_free(addr);
4558 DISAS_INSN(move16_reg)
4560 int index = IS_USER(s);
4561 TCGv tmp;
4562 uint16_t ext;
4564 ext = read_im16(env, s);
4565 if ((ext & (1 << 15)) == 0) {
4566 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4569 m68k_copy_line(AREG(ext, 12), AREG(insn, 0), index);
4571 /* Ax can be Ay, so save Ay before incrementing Ax */
4572 tmp = tcg_temp_new();
4573 tcg_gen_mov_i32(tmp, AREG(ext, 12));
4574 tcg_gen_addi_i32(AREG(insn, 0), AREG(insn, 0), 16);
4575 tcg_gen_addi_i32(AREG(ext, 12), tmp, 16);
4576 tcg_temp_free(tmp);
4579 DISAS_INSN(move16_mem)
4581 int index = IS_USER(s);
4582 TCGv reg, addr;
4584 reg = AREG(insn, 0);
4585 addr = tcg_const_i32(read_im32(env, s));
4587 if ((insn >> 3) & 1) {
4588 /* MOVE16 (xxx).L, (Ay) */
4589 m68k_copy_line(reg, addr, index);
4590 } else {
4591 /* MOVE16 (Ay), (xxx).L */
4592 m68k_copy_line(addr, reg, index);
4595 tcg_temp_free(addr);
4597 if (((insn >> 3) & 2) == 0) {
4598 /* (Ay)+ */
4599 tcg_gen_addi_i32(reg, reg, 16);
4603 DISAS_INSN(strldsr)
4605 uint16_t ext;
4606 uint32_t addr;
4608 addr = s->pc - 2;
4609 ext = read_im16(env, s);
4610 if (ext != 0x46FC) {
4611 gen_exception(s, addr, EXCP_ILLEGAL);
4612 return;
4614 ext = read_im16(env, s);
4615 if (IS_USER(s) || (ext & SR_S) == 0) {
4616 gen_exception(s, addr, EXCP_PRIVILEGE);
4617 return;
4619 gen_push(s, gen_get_sr(s));
4620 gen_set_sr_im(s, ext, 0);
4623 DISAS_INSN(move_from_sr)
4625 TCGv sr;
4627 if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) {
4628 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4629 return;
4631 sr = gen_get_sr(s);
4632 DEST_EA(env, insn, OS_WORD, sr, NULL);
4635 #if defined(CONFIG_SOFTMMU)
4636 DISAS_INSN(moves)
4638 int opsize;
4639 uint16_t ext;
4640 TCGv reg;
4641 TCGv addr;
4642 int extend;
4644 if (IS_USER(s)) {
4645 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4646 return;
4649 ext = read_im16(env, s);
4651 opsize = insn_opsize(insn);
4653 if (ext & 0x8000) {
4654 /* address register */
4655 reg = AREG(ext, 12);
4656 extend = 1;
4657 } else {
4658 /* data register */
4659 reg = DREG(ext, 12);
4660 extend = 0;
4663 addr = gen_lea(env, s, insn, opsize);
4664 if (IS_NULL_QREG(addr)) {
4665 gen_addr_fault(s);
4666 return;
4669 if (ext & 0x0800) {
4670 /* from reg to ea */
4671 gen_store(s, opsize, addr, reg, DFC_INDEX(s));
4672 } else {
4673 /* from ea to reg */
4674 TCGv tmp = gen_load(s, opsize, addr, 0, SFC_INDEX(s));
4675 if (extend) {
4676 gen_ext(reg, tmp, opsize, 1);
4677 } else {
4678 gen_partset_reg(opsize, reg, tmp);
4680 tcg_temp_free(tmp);
4682 switch (extract32(insn, 3, 3)) {
4683 case 3: /* Indirect postincrement. */
4684 tcg_gen_addi_i32(AREG(insn, 0), addr,
4685 REG(insn, 0) == 7 && opsize == OS_BYTE
4687 : opsize_bytes(opsize));
4688 break;
4689 case 4: /* Indirect predecrememnt. */
4690 tcg_gen_mov_i32(AREG(insn, 0), addr);
4691 break;
4695 DISAS_INSN(move_to_sr)
4697 if (IS_USER(s)) {
4698 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4699 return;
4701 gen_move_to_sr(env, s, insn, false);
4702 gen_exit_tb(s);
4705 DISAS_INSN(move_from_usp)
4707 if (IS_USER(s)) {
4708 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4709 return;
4711 tcg_gen_ld_i32(AREG(insn, 0), cpu_env,
4712 offsetof(CPUM68KState, sp[M68K_USP]));
4715 DISAS_INSN(move_to_usp)
4717 if (IS_USER(s)) {
4718 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4719 return;
4721 tcg_gen_st_i32(AREG(insn, 0), cpu_env,
4722 offsetof(CPUM68KState, sp[M68K_USP]));
4725 DISAS_INSN(halt)
4727 if (IS_USER(s)) {
4728 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4729 return;
4732 gen_exception(s, s->pc, EXCP_HALT_INSN);
4735 DISAS_INSN(stop)
4737 uint16_t ext;
4739 if (IS_USER(s)) {
4740 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4741 return;
4744 ext = read_im16(env, s);
4746 gen_set_sr_im(s, ext, 0);
4747 tcg_gen_movi_i32(cpu_halted, 1);
4748 gen_exception(s, s->pc, EXCP_HLT);
4751 DISAS_INSN(rte)
4753 if (IS_USER(s)) {
4754 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4755 return;
4757 gen_exception(s, s->base.pc_next, EXCP_RTE);
4760 DISAS_INSN(cf_movec)
4762 uint16_t ext;
4763 TCGv reg;
4765 if (IS_USER(s)) {
4766 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4767 return;
4770 ext = read_im16(env, s);
4772 if (ext & 0x8000) {
4773 reg = AREG(ext, 12);
4774 } else {
4775 reg = DREG(ext, 12);
4777 gen_helper_cf_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg);
4778 gen_exit_tb(s);
4781 DISAS_INSN(m68k_movec)
4783 uint16_t ext;
4784 TCGv reg;
4786 if (IS_USER(s)) {
4787 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4788 return;
4791 ext = read_im16(env, s);
4793 if (ext & 0x8000) {
4794 reg = AREG(ext, 12);
4795 } else {
4796 reg = DREG(ext, 12);
4798 if (insn & 1) {
4799 gen_helper_m68k_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg);
4800 } else {
4801 gen_helper_m68k_movec_from(reg, cpu_env, tcg_const_i32(ext & 0xfff));
4803 gen_exit_tb(s);
4806 DISAS_INSN(intouch)
4808 if (IS_USER(s)) {
4809 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4810 return;
4812 /* ICache fetch. Implement as no-op. */
4815 DISAS_INSN(cpushl)
4817 if (IS_USER(s)) {
4818 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4819 return;
4821 /* Cache push/invalidate. Implement as no-op. */
4824 DISAS_INSN(cpush)
4826 if (IS_USER(s)) {
4827 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4828 return;
4830 /* Cache push/invalidate. Implement as no-op. */
4833 DISAS_INSN(cinv)
4835 if (IS_USER(s)) {
4836 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4837 return;
4839 /* Invalidate cache line. Implement as no-op. */
4842 #if defined(CONFIG_SOFTMMU)
4843 DISAS_INSN(pflush)
4845 TCGv opmode;
4847 if (IS_USER(s)) {
4848 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4849 return;
4852 opmode = tcg_const_i32((insn >> 3) & 3);
4853 gen_helper_pflush(cpu_env, AREG(insn, 0), opmode);
4854 tcg_temp_free(opmode);
4857 DISAS_INSN(ptest)
4859 TCGv is_read;
4861 if (IS_USER(s)) {
4862 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4863 return;
4865 is_read = tcg_const_i32((insn >> 5) & 1);
4866 gen_helper_ptest(cpu_env, AREG(insn, 0), is_read);
4867 tcg_temp_free(is_read);
4869 #endif
4871 DISAS_INSN(wddata)
4873 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4876 DISAS_INSN(wdebug)
4878 if (IS_USER(s)) {
4879 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4880 return;
4882 /* TODO: Implement wdebug. */
4883 cpu_abort(env_cpu(env), "WDEBUG not implemented");
4885 #endif
4887 DISAS_INSN(trap)
4889 gen_exception(s, s->base.pc_next, EXCP_TRAP0 + (insn & 0xf));
4892 static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
4894 switch (reg) {
4895 case M68K_FPIAR:
4896 tcg_gen_movi_i32(res, 0);
4897 break;
4898 case M68K_FPSR:
4899 tcg_gen_ld_i32(res, cpu_env, offsetof(CPUM68KState, fpsr));
4900 break;
4901 case M68K_FPCR:
4902 tcg_gen_ld_i32(res, cpu_env, offsetof(CPUM68KState, fpcr));
4903 break;
4907 static void gen_store_fcr(DisasContext *s, TCGv val, int reg)
4909 switch (reg) {
4910 case M68K_FPIAR:
4911 break;
4912 case M68K_FPSR:
4913 tcg_gen_st_i32(val, cpu_env, offsetof(CPUM68KState, fpsr));
4914 break;
4915 case M68K_FPCR:
4916 gen_helper_set_fpcr(cpu_env, val);
4917 break;
4921 static void gen_qemu_store_fcr(DisasContext *s, TCGv addr, int reg)
4923 int index = IS_USER(s);
4924 TCGv tmp;
4926 tmp = tcg_temp_new();
4927 gen_load_fcr(s, tmp, reg);
4928 tcg_gen_qemu_st32(tmp, addr, index);
4929 tcg_temp_free(tmp);
4932 static void gen_qemu_load_fcr(DisasContext *s, TCGv addr, int reg)
4934 int index = IS_USER(s);
4935 TCGv tmp;
4937 tmp = tcg_temp_new();
4938 tcg_gen_qemu_ld32u(tmp, addr, index);
4939 gen_store_fcr(s, tmp, reg);
4940 tcg_temp_free(tmp);
4944 static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
4945 uint32_t insn, uint32_t ext)
4947 int mask = (ext >> 10) & 7;
4948 int is_write = (ext >> 13) & 1;
4949 int mode = extract32(insn, 3, 3);
4950 int i;
4951 TCGv addr, tmp;
4953 switch (mode) {
4954 case 0: /* Dn */
4955 if (mask != M68K_FPIAR && mask != M68K_FPSR && mask != M68K_FPCR) {
4956 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4957 return;
4959 if (is_write) {
4960 gen_load_fcr(s, DREG(insn, 0), mask);
4961 } else {
4962 gen_store_fcr(s, DREG(insn, 0), mask);
4964 return;
4965 case 1: /* An, only with FPIAR */
4966 if (mask != M68K_FPIAR) {
4967 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4968 return;
4970 if (is_write) {
4971 gen_load_fcr(s, AREG(insn, 0), mask);
4972 } else {
4973 gen_store_fcr(s, AREG(insn, 0), mask);
4975 return;
4976 case 7: /* Immediate */
4977 if (REG(insn, 0) == 4) {
4978 if (is_write ||
4979 (mask != M68K_FPIAR && mask != M68K_FPSR &&
4980 mask != M68K_FPCR)) {
4981 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4982 return;
4984 tmp = tcg_const_i32(read_im32(env, s));
4985 gen_store_fcr(s, tmp, mask);
4986 tcg_temp_free(tmp);
4987 return;
4989 break;
4990 default:
4991 break;
4994 tmp = gen_lea(env, s, insn, OS_LONG);
4995 if (IS_NULL_QREG(tmp)) {
4996 gen_addr_fault(s);
4997 return;
5000 addr = tcg_temp_new();
5001 tcg_gen_mov_i32(addr, tmp);
5004 * mask:
5006 * 0b100 Floating-Point Control Register
5007 * 0b010 Floating-Point Status Register
5008 * 0b001 Floating-Point Instruction Address Register
5012 if (is_write && mode == 4) {
5013 for (i = 2; i >= 0; i--, mask >>= 1) {
5014 if (mask & 1) {
5015 gen_qemu_store_fcr(s, addr, 1 << i);
5016 if (mask != 1) {
5017 tcg_gen_subi_i32(addr, addr, opsize_bytes(OS_LONG));
5021 tcg_gen_mov_i32(AREG(insn, 0), addr);
5022 } else {
5023 for (i = 0; i < 3; i++, mask >>= 1) {
5024 if (mask & 1) {
5025 if (is_write) {
5026 gen_qemu_store_fcr(s, addr, 1 << i);
5027 } else {
5028 gen_qemu_load_fcr(s, addr, 1 << i);
5030 if (mask != 1 || mode == 3) {
5031 tcg_gen_addi_i32(addr, addr, opsize_bytes(OS_LONG));
5035 if (mode == 3) {
5036 tcg_gen_mov_i32(AREG(insn, 0), addr);
5039 tcg_temp_free_i32(addr);
5042 static void gen_op_fmovem(CPUM68KState *env, DisasContext *s,
5043 uint32_t insn, uint32_t ext)
5045 int opsize;
5046 TCGv addr, tmp;
5047 int mode = (ext >> 11) & 0x3;
5048 int is_load = ((ext & 0x2000) == 0);
5050 if (m68k_feature(s->env, M68K_FEATURE_FPU)) {
5051 opsize = OS_EXTENDED;
5052 } else {
5053 opsize = OS_DOUBLE; /* FIXME */
5056 addr = gen_lea(env, s, insn, opsize);
5057 if (IS_NULL_QREG(addr)) {
5058 gen_addr_fault(s);
5059 return;
5062 tmp = tcg_temp_new();
5063 if (mode & 0x1) {
5064 /* Dynamic register list */
5065 tcg_gen_ext8u_i32(tmp, DREG(ext, 4));
5066 } else {
5067 /* Static register list */
5068 tcg_gen_movi_i32(tmp, ext & 0xff);
5071 if (!is_load && (mode & 2) == 0) {
5073 * predecrement addressing mode
5074 * only available to store register to memory
5076 if (opsize == OS_EXTENDED) {
5077 gen_helper_fmovemx_st_predec(tmp, cpu_env, addr, tmp);
5078 } else {
5079 gen_helper_fmovemd_st_predec(tmp, cpu_env, addr, tmp);
5081 } else {
5082 /* postincrement addressing mode */
5083 if (opsize == OS_EXTENDED) {
5084 if (is_load) {
5085 gen_helper_fmovemx_ld_postinc(tmp, cpu_env, addr, tmp);
5086 } else {
5087 gen_helper_fmovemx_st_postinc(tmp, cpu_env, addr, tmp);
5089 } else {
5090 if (is_load) {
5091 gen_helper_fmovemd_ld_postinc(tmp, cpu_env, addr, tmp);
5092 } else {
5093 gen_helper_fmovemd_st_postinc(tmp, cpu_env, addr, tmp);
5097 if ((insn & 070) == 030 || (insn & 070) == 040) {
5098 tcg_gen_mov_i32(AREG(insn, 0), tmp);
5100 tcg_temp_free(tmp);
5104 * ??? FP exceptions are not implemented. Most exceptions are deferred until
5105 * immediately before the next FP instruction is executed.
5107 DISAS_INSN(fpu)
5109 uint16_t ext;
5110 int opmode;
5111 int opsize;
5112 TCGv_ptr cpu_src, cpu_dest;
5114 ext = read_im16(env, s);
5115 opmode = ext & 0x7f;
5116 switch ((ext >> 13) & 7) {
5117 case 0:
5118 break;
5119 case 1:
5120 goto undef;
5121 case 2:
5122 if (insn == 0xf200 && (ext & 0xfc00) == 0x5c00) {
5123 /* fmovecr */
5124 TCGv rom_offset = tcg_const_i32(opmode);
5125 cpu_dest = gen_fp_ptr(REG(ext, 7));
5126 gen_helper_fconst(cpu_env, cpu_dest, rom_offset);
5127 tcg_temp_free_ptr(cpu_dest);
5128 tcg_temp_free(rom_offset);
5129 return;
5131 break;
5132 case 3: /* fmove out */
5133 cpu_src = gen_fp_ptr(REG(ext, 7));
5134 opsize = ext_opsize(ext, 10);
5135 if (gen_ea_fp(env, s, insn, opsize, cpu_src,
5136 EA_STORE, IS_USER(s)) == -1) {
5137 gen_addr_fault(s);
5139 gen_helper_ftst(cpu_env, cpu_src);
5140 tcg_temp_free_ptr(cpu_src);
5141 return;
5142 case 4: /* fmove to control register. */
5143 case 5: /* fmove from control register. */
5144 gen_op_fmove_fcr(env, s, insn, ext);
5145 return;
5146 case 6: /* fmovem */
5147 case 7:
5148 if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU)) {
5149 goto undef;
5151 gen_op_fmovem(env, s, insn, ext);
5152 return;
5154 if (ext & (1 << 14)) {
5155 /* Source effective address. */
5156 opsize = ext_opsize(ext, 10);
5157 cpu_src = gen_fp_result_ptr();
5158 if (gen_ea_fp(env, s, insn, opsize, cpu_src,
5159 EA_LOADS, IS_USER(s)) == -1) {
5160 gen_addr_fault(s);
5161 return;
5163 } else {
5164 /* Source register. */
5165 opsize = OS_EXTENDED;
5166 cpu_src = gen_fp_ptr(REG(ext, 10));
5168 cpu_dest = gen_fp_ptr(REG(ext, 7));
5169 switch (opmode) {
5170 case 0: /* fmove */
5171 gen_fp_move(cpu_dest, cpu_src);
5172 break;
5173 case 0x40: /* fsmove */
5174 gen_helper_fsround(cpu_env, cpu_dest, cpu_src);
5175 break;
5176 case 0x44: /* fdmove */
5177 gen_helper_fdround(cpu_env, cpu_dest, cpu_src);
5178 break;
5179 case 1: /* fint */
5180 gen_helper_firound(cpu_env, cpu_dest, cpu_src);
5181 break;
5182 case 2: /* fsinh */
5183 gen_helper_fsinh(cpu_env, cpu_dest, cpu_src);
5184 break;
5185 case 3: /* fintrz */
5186 gen_helper_fitrunc(cpu_env, cpu_dest, cpu_src);
5187 break;
5188 case 4: /* fsqrt */
5189 gen_helper_fsqrt(cpu_env, cpu_dest, cpu_src);
5190 break;
5191 case 0x41: /* fssqrt */
5192 gen_helper_fssqrt(cpu_env, cpu_dest, cpu_src);
5193 break;
5194 case 0x45: /* fdsqrt */
5195 gen_helper_fdsqrt(cpu_env, cpu_dest, cpu_src);
5196 break;
5197 case 0x06: /* flognp1 */
5198 gen_helper_flognp1(cpu_env, cpu_dest, cpu_src);
5199 break;
5200 case 0x08: /* fetoxm1 */
5201 gen_helper_fetoxm1(cpu_env, cpu_dest, cpu_src);
5202 break;
5203 case 0x09: /* ftanh */
5204 gen_helper_ftanh(cpu_env, cpu_dest, cpu_src);
5205 break;
5206 case 0x0a: /* fatan */
5207 gen_helper_fatan(cpu_env, cpu_dest, cpu_src);
5208 break;
5209 case 0x0c: /* fasin */
5210 gen_helper_fasin(cpu_env, cpu_dest, cpu_src);
5211 break;
5212 case 0x0d: /* fatanh */
5213 gen_helper_fatanh(cpu_env, cpu_dest, cpu_src);
5214 break;
5215 case 0x0e: /* fsin */
5216 gen_helper_fsin(cpu_env, cpu_dest, cpu_src);
5217 break;
5218 case 0x0f: /* ftan */
5219 gen_helper_ftan(cpu_env, cpu_dest, cpu_src);
5220 break;
5221 case 0x10: /* fetox */
5222 gen_helper_fetox(cpu_env, cpu_dest, cpu_src);
5223 break;
5224 case 0x11: /* ftwotox */
5225 gen_helper_ftwotox(cpu_env, cpu_dest, cpu_src);
5226 break;
5227 case 0x12: /* ftentox */
5228 gen_helper_ftentox(cpu_env, cpu_dest, cpu_src);
5229 break;
5230 case 0x14: /* flogn */
5231 gen_helper_flogn(cpu_env, cpu_dest, cpu_src);
5232 break;
5233 case 0x15: /* flog10 */
5234 gen_helper_flog10(cpu_env, cpu_dest, cpu_src);
5235 break;
5236 case 0x16: /* flog2 */
5237 gen_helper_flog2(cpu_env, cpu_dest, cpu_src);
5238 break;
5239 case 0x18: /* fabs */
5240 gen_helper_fabs(cpu_env, cpu_dest, cpu_src);
5241 break;
5242 case 0x58: /* fsabs */
5243 gen_helper_fsabs(cpu_env, cpu_dest, cpu_src);
5244 break;
5245 case 0x5c: /* fdabs */
5246 gen_helper_fdabs(cpu_env, cpu_dest, cpu_src);
5247 break;
5248 case 0x19: /* fcosh */
5249 gen_helper_fcosh(cpu_env, cpu_dest, cpu_src);
5250 break;
5251 case 0x1a: /* fneg */
5252 gen_helper_fneg(cpu_env, cpu_dest, cpu_src);
5253 break;
5254 case 0x5a: /* fsneg */
5255 gen_helper_fsneg(cpu_env, cpu_dest, cpu_src);
5256 break;
5257 case 0x5e: /* fdneg */
5258 gen_helper_fdneg(cpu_env, cpu_dest, cpu_src);
5259 break;
5260 case 0x1c: /* facos */
5261 gen_helper_facos(cpu_env, cpu_dest, cpu_src);
5262 break;
5263 case 0x1d: /* fcos */
5264 gen_helper_fcos(cpu_env, cpu_dest, cpu_src);
5265 break;
5266 case 0x1e: /* fgetexp */
5267 gen_helper_fgetexp(cpu_env, cpu_dest, cpu_src);
5268 break;
5269 case 0x1f: /* fgetman */
5270 gen_helper_fgetman(cpu_env, cpu_dest, cpu_src);
5271 break;
5272 case 0x20: /* fdiv */
5273 gen_helper_fdiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
5274 break;
5275 case 0x60: /* fsdiv */
5276 gen_helper_fsdiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
5277 break;
5278 case 0x64: /* fddiv */
5279 gen_helper_fddiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
5280 break;
5281 case 0x21: /* fmod */
5282 gen_helper_fmod(cpu_env, cpu_dest, cpu_src, cpu_dest);
5283 break;
5284 case 0x22: /* fadd */
5285 gen_helper_fadd(cpu_env, cpu_dest, cpu_src, cpu_dest);
5286 break;
5287 case 0x62: /* fsadd */
5288 gen_helper_fsadd(cpu_env, cpu_dest, cpu_src, cpu_dest);
5289 break;
5290 case 0x66: /* fdadd */
5291 gen_helper_fdadd(cpu_env, cpu_dest, cpu_src, cpu_dest);
5292 break;
5293 case 0x23: /* fmul */
5294 gen_helper_fmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
5295 break;
5296 case 0x63: /* fsmul */
5297 gen_helper_fsmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
5298 break;
5299 case 0x67: /* fdmul */
5300 gen_helper_fdmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
5301 break;
5302 case 0x24: /* fsgldiv */
5303 gen_helper_fsgldiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
5304 break;
5305 case 0x25: /* frem */
5306 gen_helper_frem(cpu_env, cpu_dest, cpu_src, cpu_dest);
5307 break;
5308 case 0x26: /* fscale */
5309 gen_helper_fscale(cpu_env, cpu_dest, cpu_src, cpu_dest);
5310 break;
5311 case 0x27: /* fsglmul */
5312 gen_helper_fsglmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
5313 break;
5314 case 0x28: /* fsub */
5315 gen_helper_fsub(cpu_env, cpu_dest, cpu_src, cpu_dest);
5316 break;
5317 case 0x68: /* fssub */
5318 gen_helper_fssub(cpu_env, cpu_dest, cpu_src, cpu_dest);
5319 break;
5320 case 0x6c: /* fdsub */
5321 gen_helper_fdsub(cpu_env, cpu_dest, cpu_src, cpu_dest);
5322 break;
5323 case 0x30: case 0x31: case 0x32:
5324 case 0x33: case 0x34: case 0x35:
5325 case 0x36: case 0x37: {
5326 TCGv_ptr cpu_dest2 = gen_fp_ptr(REG(ext, 0));
5327 gen_helper_fsincos(cpu_env, cpu_dest, cpu_dest2, cpu_src);
5328 tcg_temp_free_ptr(cpu_dest2);
5330 break;
5331 case 0x38: /* fcmp */
5332 gen_helper_fcmp(cpu_env, cpu_src, cpu_dest);
5333 return;
5334 case 0x3a: /* ftst */
5335 gen_helper_ftst(cpu_env, cpu_src);
5336 return;
5337 default:
5338 goto undef;
5340 tcg_temp_free_ptr(cpu_src);
5341 gen_helper_ftst(cpu_env, cpu_dest);
5342 tcg_temp_free_ptr(cpu_dest);
5343 return;
5344 undef:
5345 /* FIXME: Is this right for offset addressing modes? */
5346 s->pc -= 2;
5347 disas_undef_fpu(env, s, insn);
5350 static void gen_fcc_cond(DisasCompare *c, DisasContext *s, int cond)
5352 TCGv fpsr;
5354 c->g1 = 1;
5355 c->v2 = tcg_const_i32(0);
5356 c->g2 = 0;
5357 /* TODO: Raise BSUN exception. */
5358 fpsr = tcg_temp_new();
5359 gen_load_fcr(s, fpsr, M68K_FPSR);
5360 switch (cond) {
5361 case 0: /* False */
5362 case 16: /* Signaling False */
5363 c->v1 = c->v2;
5364 c->tcond = TCG_COND_NEVER;
5365 break;
5366 case 1: /* EQual Z */
5367 case 17: /* Signaling EQual Z */
5368 c->v1 = tcg_temp_new();
5369 c->g1 = 0;
5370 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5371 c->tcond = TCG_COND_NE;
5372 break;
5373 case 2: /* Ordered Greater Than !(A || Z || N) */
5374 case 18: /* Greater Than !(A || Z || N) */
5375 c->v1 = tcg_temp_new();
5376 c->g1 = 0;
5377 tcg_gen_andi_i32(c->v1, fpsr,
5378 FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
5379 c->tcond = TCG_COND_EQ;
5380 break;
5381 case 3: /* Ordered Greater than or Equal Z || !(A || N) */
5382 case 19: /* Greater than or Equal Z || !(A || N) */
5383 c->v1 = tcg_temp_new();
5384 c->g1 = 0;
5385 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5386 tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
5387 tcg_gen_andi_i32(fpsr, fpsr, FPSR_CC_Z | FPSR_CC_N);
5388 tcg_gen_or_i32(c->v1, c->v1, fpsr);
5389 tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5390 c->tcond = TCG_COND_NE;
5391 break;
5392 case 4: /* Ordered Less Than !(!N || A || Z); */
5393 case 20: /* Less Than !(!N || A || Z); */
5394 c->v1 = tcg_temp_new();
5395 c->g1 = 0;
5396 tcg_gen_xori_i32(c->v1, fpsr, FPSR_CC_N);
5397 tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_N | FPSR_CC_A | FPSR_CC_Z);
5398 c->tcond = TCG_COND_EQ;
5399 break;
5400 case 5: /* Ordered Less than or Equal Z || (N && !A) */
5401 case 21: /* Less than or Equal Z || (N && !A) */
5402 c->v1 = tcg_temp_new();
5403 c->g1 = 0;
5404 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5405 tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
5406 tcg_gen_andc_i32(c->v1, fpsr, c->v1);
5407 tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_Z | FPSR_CC_N);
5408 c->tcond = TCG_COND_NE;
5409 break;
5410 case 6: /* Ordered Greater or Less than !(A || Z) */
5411 case 22: /* Greater or Less than !(A || Z) */
5412 c->v1 = tcg_temp_new();
5413 c->g1 = 0;
5414 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z);
5415 c->tcond = TCG_COND_EQ;
5416 break;
5417 case 7: /* Ordered !A */
5418 case 23: /* Greater, Less or Equal !A */
5419 c->v1 = tcg_temp_new();
5420 c->g1 = 0;
5421 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5422 c->tcond = TCG_COND_EQ;
5423 break;
5424 case 8: /* Unordered A */
5425 case 24: /* Not Greater, Less or Equal A */
5426 c->v1 = tcg_temp_new();
5427 c->g1 = 0;
5428 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5429 c->tcond = TCG_COND_NE;
5430 break;
5431 case 9: /* Unordered or Equal A || Z */
5432 case 25: /* Not Greater or Less then A || Z */
5433 c->v1 = tcg_temp_new();
5434 c->g1 = 0;
5435 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z);
5436 c->tcond = TCG_COND_NE;
5437 break;
5438 case 10: /* Unordered or Greater Than A || !(N || Z)) */
5439 case 26: /* Not Less or Equal A || !(N || Z)) */
5440 c->v1 = tcg_temp_new();
5441 c->g1 = 0;
5442 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5443 tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
5444 tcg_gen_andi_i32(fpsr, fpsr, FPSR_CC_A | FPSR_CC_N);
5445 tcg_gen_or_i32(c->v1, c->v1, fpsr);
5446 tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5447 c->tcond = TCG_COND_NE;
5448 break;
5449 case 11: /* Unordered or Greater or Equal A || Z || !N */
5450 case 27: /* Not Less Than A || Z || !N */
5451 c->v1 = tcg_temp_new();
5452 c->g1 = 0;
5453 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
5454 tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5455 c->tcond = TCG_COND_NE;
5456 break;
5457 case 12: /* Unordered or Less Than A || (N && !Z) */
5458 case 28: /* Not Greater than or Equal A || (N && !Z) */
5459 c->v1 = tcg_temp_new();
5460 c->g1 = 0;
5461 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5462 tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
5463 tcg_gen_andc_i32(c->v1, fpsr, c->v1);
5464 tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_A | FPSR_CC_N);
5465 c->tcond = TCG_COND_NE;
5466 break;
5467 case 13: /* Unordered or Less or Equal A || Z || N */
5468 case 29: /* Not Greater Than A || Z || N */
5469 c->v1 = tcg_temp_new();
5470 c->g1 = 0;
5471 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
5472 c->tcond = TCG_COND_NE;
5473 break;
5474 case 14: /* Not Equal !Z */
5475 case 30: /* Signaling Not Equal !Z */
5476 c->v1 = tcg_temp_new();
5477 c->g1 = 0;
5478 tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5479 c->tcond = TCG_COND_EQ;
5480 break;
5481 case 15: /* True */
5482 case 31: /* Signaling True */
5483 c->v1 = c->v2;
5484 c->tcond = TCG_COND_ALWAYS;
5485 break;
5487 tcg_temp_free(fpsr);
5490 static void gen_fjmpcc(DisasContext *s, int cond, TCGLabel *l1)
5492 DisasCompare c;
5494 gen_fcc_cond(&c, s, cond);
5495 update_cc_op(s);
5496 tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
5497 free_cond(&c);
5500 DISAS_INSN(fbcc)
5502 uint32_t offset;
5503 uint32_t base;
5504 TCGLabel *l1;
5506 base = s->pc;
5507 offset = (int16_t)read_im16(env, s);
5508 if (insn & (1 << 6)) {
5509 offset = (offset << 16) | read_im16(env, s);
5512 l1 = gen_new_label();
5513 update_cc_op(s);
5514 gen_fjmpcc(s, insn & 0x3f, l1);
5515 gen_jmp_tb(s, 0, s->pc);
5516 gen_set_label(l1);
5517 gen_jmp_tb(s, 1, base + offset);
5520 DISAS_INSN(fscc)
5522 DisasCompare c;
5523 int cond;
5524 TCGv tmp;
5525 uint16_t ext;
5527 ext = read_im16(env, s);
5528 cond = ext & 0x3f;
5529 gen_fcc_cond(&c, s, cond);
5531 tmp = tcg_temp_new();
5532 tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2);
5533 free_cond(&c);
5535 tcg_gen_neg_i32(tmp, tmp);
5536 DEST_EA(env, insn, OS_BYTE, tmp, NULL);
5537 tcg_temp_free(tmp);
5540 #if defined(CONFIG_SOFTMMU)
5541 DISAS_INSN(frestore)
5543 TCGv addr;
5545 if (IS_USER(s)) {
5546 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
5547 return;
5549 if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
5550 SRC_EA(env, addr, OS_LONG, 0, NULL);
5551 /* FIXME: check the state frame */
5552 } else {
5553 disas_undef(env, s, insn);
5557 DISAS_INSN(fsave)
5559 if (IS_USER(s)) {
5560 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
5561 return;
5564 if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
5565 /* always write IDLE */
5566 TCGv idle = tcg_const_i32(0x41000000);
5567 DEST_EA(env, insn, OS_LONG, idle, NULL);
5568 tcg_temp_free(idle);
5569 } else {
5570 disas_undef(env, s, insn);
5573 #endif
5575 static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
5577 TCGv tmp = tcg_temp_new();
5578 if (s->env->macsr & MACSR_FI) {
5579 if (upper)
5580 tcg_gen_andi_i32(tmp, val, 0xffff0000);
5581 else
5582 tcg_gen_shli_i32(tmp, val, 16);
5583 } else if (s->env->macsr & MACSR_SU) {
5584 if (upper)
5585 tcg_gen_sari_i32(tmp, val, 16);
5586 else
5587 tcg_gen_ext16s_i32(tmp, val);
5588 } else {
5589 if (upper)
5590 tcg_gen_shri_i32(tmp, val, 16);
5591 else
5592 tcg_gen_ext16u_i32(tmp, val);
5594 return tmp;
5597 static void gen_mac_clear_flags(void)
5599 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR,
5600 ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV));
5603 DISAS_INSN(mac)
5605 TCGv rx;
5606 TCGv ry;
5607 uint16_t ext;
5608 int acc;
5609 TCGv tmp;
5610 TCGv addr;
5611 TCGv loadval;
5612 int dual;
5613 TCGv saved_flags;
5615 if (!s->done_mac) {
5616 s->mactmp = tcg_temp_new_i64();
5617 s->done_mac = 1;
5620 ext = read_im16(env, s);
5622 acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
5623 dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
5624 if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
5625 disas_undef(env, s, insn);
5626 return;
5628 if (insn & 0x30) {
5629 /* MAC with load. */
5630 tmp = gen_lea(env, s, insn, OS_LONG);
5631 addr = tcg_temp_new();
5632 tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK);
5634 * Load the value now to ensure correct exception behavior.
5635 * Perform writeback after reading the MAC inputs.
5637 loadval = gen_load(s, OS_LONG, addr, 0, IS_USER(s));
5639 acc ^= 1;
5640 rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
5641 ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
5642 } else {
5643 loadval = addr = NULL_QREG;
5644 rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
5645 ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5648 gen_mac_clear_flags();
5649 #if 0
5650 l1 = -1;
5651 /* Disabled because conditional branches clobber temporary vars. */
5652 if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
5653 /* Skip the multiply if we know we will ignore it. */
5654 l1 = gen_new_label();
5655 tmp = tcg_temp_new();
5656 tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8));
5657 gen_op_jmp_nz32(tmp, l1);
5659 #endif
5661 if ((ext & 0x0800) == 0) {
5662 /* Word. */
5663 rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
5664 ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
5666 if (s->env->macsr & MACSR_FI) {
5667 gen_helper_macmulf(s->mactmp, cpu_env, rx, ry);
5668 } else {
5669 if (s->env->macsr & MACSR_SU)
5670 gen_helper_macmuls(s->mactmp, cpu_env, rx, ry);
5671 else
5672 gen_helper_macmulu(s->mactmp, cpu_env, rx, ry);
5673 switch ((ext >> 9) & 3) {
5674 case 1:
5675 tcg_gen_shli_i64(s->mactmp, s->mactmp, 1);
5676 break;
5677 case 3:
5678 tcg_gen_shri_i64(s->mactmp, s->mactmp, 1);
5679 break;
5683 if (dual) {
5684 /* Save the overflow flag from the multiply. */
5685 saved_flags = tcg_temp_new();
5686 tcg_gen_mov_i32(saved_flags, QREG_MACSR);
5687 } else {
5688 saved_flags = NULL_QREG;
5691 #if 0
5692 /* Disabled because conditional branches clobber temporary vars. */
5693 if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
5694 /* Skip the accumulate if the value is already saturated. */
5695 l1 = gen_new_label();
5696 tmp = tcg_temp_new();
5697 gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
5698 gen_op_jmp_nz32(tmp, l1);
5700 #endif
5702 if (insn & 0x100)
5703 tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
5704 else
5705 tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
5707 if (s->env->macsr & MACSR_FI)
5708 gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
5709 else if (s->env->macsr & MACSR_SU)
5710 gen_helper_macsats(cpu_env, tcg_const_i32(acc));
5711 else
5712 gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
5714 #if 0
5715 /* Disabled because conditional branches clobber temporary vars. */
5716 if (l1 != -1)
5717 gen_set_label(l1);
5718 #endif
5720 if (dual) {
5721 /* Dual accumulate variant. */
5722 acc = (ext >> 2) & 3;
5723 /* Restore the overflow flag from the multiplier. */
5724 tcg_gen_mov_i32(QREG_MACSR, saved_flags);
5725 #if 0
5726 /* Disabled because conditional branches clobber temporary vars. */
5727 if ((s->env->macsr & MACSR_OMC) != 0) {
5728 /* Skip the accumulate if the value is already saturated. */
5729 l1 = gen_new_label();
5730 tmp = tcg_temp_new();
5731 gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
5732 gen_op_jmp_nz32(tmp, l1);
5734 #endif
5735 if (ext & 2)
5736 tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
5737 else
5738 tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
5739 if (s->env->macsr & MACSR_FI)
5740 gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
5741 else if (s->env->macsr & MACSR_SU)
5742 gen_helper_macsats(cpu_env, tcg_const_i32(acc));
5743 else
5744 gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
5745 #if 0
5746 /* Disabled because conditional branches clobber temporary vars. */
5747 if (l1 != -1)
5748 gen_set_label(l1);
5749 #endif
5751 gen_helper_mac_set_flags(cpu_env, tcg_const_i32(acc));
5753 if (insn & 0x30) {
5754 TCGv rw;
5755 rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
5756 tcg_gen_mov_i32(rw, loadval);
5758 * FIXME: Should address writeback happen with the masked or
5759 * unmasked value?
5761 switch ((insn >> 3) & 7) {
5762 case 3: /* Post-increment. */
5763 tcg_gen_addi_i32(AREG(insn, 0), addr, 4);
5764 break;
5765 case 4: /* Pre-decrement. */
5766 tcg_gen_mov_i32(AREG(insn, 0), addr);
5768 tcg_temp_free(loadval);
5772 DISAS_INSN(from_mac)
5774 TCGv rx;
5775 TCGv_i64 acc;
5776 int accnum;
5778 rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5779 accnum = (insn >> 9) & 3;
5780 acc = MACREG(accnum);
5781 if (s->env->macsr & MACSR_FI) {
5782 gen_helper_get_macf(rx, cpu_env, acc);
5783 } else if ((s->env->macsr & MACSR_OMC) == 0) {
5784 tcg_gen_extrl_i64_i32(rx, acc);
5785 } else if (s->env->macsr & MACSR_SU) {
5786 gen_helper_get_macs(rx, acc);
5787 } else {
5788 gen_helper_get_macu(rx, acc);
5790 if (insn & 0x40) {
5791 tcg_gen_movi_i64(acc, 0);
5792 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
5796 DISAS_INSN(move_mac)
5798 /* FIXME: This can be done without a helper. */
5799 int src;
5800 TCGv dest;
5801 src = insn & 3;
5802 dest = tcg_const_i32((insn >> 9) & 3);
5803 gen_helper_mac_move(cpu_env, dest, tcg_const_i32(src));
5804 gen_mac_clear_flags();
5805 gen_helper_mac_set_flags(cpu_env, dest);
5808 DISAS_INSN(from_macsr)
5810 TCGv reg;
5812 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5813 tcg_gen_mov_i32(reg, QREG_MACSR);
5816 DISAS_INSN(from_mask)
5818 TCGv reg;
5819 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5820 tcg_gen_mov_i32(reg, QREG_MAC_MASK);
5823 DISAS_INSN(from_mext)
5825 TCGv reg;
5826 TCGv acc;
5827 reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5828 acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
5829 if (s->env->macsr & MACSR_FI)
5830 gen_helper_get_mac_extf(reg, cpu_env, acc);
5831 else
5832 gen_helper_get_mac_exti(reg, cpu_env, acc);
5835 DISAS_INSN(macsr_to_ccr)
5837 TCGv tmp = tcg_temp_new();
5838 tcg_gen_andi_i32(tmp, QREG_MACSR, 0xf);
5839 gen_helper_set_sr(cpu_env, tmp);
5840 tcg_temp_free(tmp);
5841 set_cc_op(s, CC_OP_FLAGS);
5844 DISAS_INSN(to_mac)
5846 TCGv_i64 acc;
5847 TCGv val;
5848 int accnum;
5849 accnum = (insn >> 9) & 3;
5850 acc = MACREG(accnum);
5851 SRC_EA(env, val, OS_LONG, 0, NULL);
5852 if (s->env->macsr & MACSR_FI) {
5853 tcg_gen_ext_i32_i64(acc, val);
5854 tcg_gen_shli_i64(acc, acc, 8);
5855 } else if (s->env->macsr & MACSR_SU) {
5856 tcg_gen_ext_i32_i64(acc, val);
5857 } else {
5858 tcg_gen_extu_i32_i64(acc, val);
5860 tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
5861 gen_mac_clear_flags();
5862 gen_helper_mac_set_flags(cpu_env, tcg_const_i32(accnum));
5865 DISAS_INSN(to_macsr)
5867 TCGv val;
5868 SRC_EA(env, val, OS_LONG, 0, NULL);
5869 gen_helper_set_macsr(cpu_env, val);
5870 gen_exit_tb(s);
5873 DISAS_INSN(to_mask)
5875 TCGv val;
5876 SRC_EA(env, val, OS_LONG, 0, NULL);
5877 tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000);
5880 DISAS_INSN(to_mext)
5882 TCGv val;
5883 TCGv acc;
5884 SRC_EA(env, val, OS_LONG, 0, NULL);
5885 acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
5886 if (s->env->macsr & MACSR_FI)
5887 gen_helper_set_mac_extf(cpu_env, val, acc);
5888 else if (s->env->macsr & MACSR_SU)
5889 gen_helper_set_mac_exts(cpu_env, val, acc);
5890 else
5891 gen_helper_set_mac_extu(cpu_env, val, acc);
5894 static disas_proc opcode_table[65536];
5896 static void
5897 register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
5899 int i;
5900 int from;
5901 int to;
5903 /* Sanity check. All set bits must be included in the mask. */
5904 if (opcode & ~mask) {
5905 fprintf(stderr,
5906 "qemu internal error: bogus opcode definition %04x/%04x\n",
5907 opcode, mask);
5908 abort();
5911 * This could probably be cleverer. For now just optimize the case where
5912 * the top bits are known.
5914 /* Find the first zero bit in the mask. */
5915 i = 0x8000;
5916 while ((i & mask) != 0)
5917 i >>= 1;
5918 /* Iterate over all combinations of this and lower bits. */
5919 if (i == 0)
5920 i = 1;
5921 else
5922 i <<= 1;
5923 from = opcode & ~(i - 1);
5924 to = from + i;
5925 for (i = from; i < to; i++) {
5926 if ((i & mask) == opcode)
5927 opcode_table[i] = proc;
5932 * Register m68k opcode handlers. Order is important.
5933 * Later insn override earlier ones.
5935 void register_m68k_insns (CPUM68KState *env)
5938 * Build the opcode table only once to avoid
5939 * multithreading issues.
5941 if (opcode_table[0] != NULL) {
5942 return;
5946 * use BASE() for instruction available
5947 * for CF_ISA_A and M68000.
5949 #define BASE(name, opcode, mask) \
5950 register_opcode(disas_##name, 0x##opcode, 0x##mask)
5951 #define INSN(name, opcode, mask, feature) do { \
5952 if (m68k_feature(env, M68K_FEATURE_##feature)) \
5953 BASE(name, opcode, mask); \
5954 } while(0)
5955 BASE(undef, 0000, 0000);
5956 INSN(arith_im, 0080, fff8, CF_ISA_A);
5957 INSN(arith_im, 0000, ff00, M68000);
5958 INSN(chk2, 00c0, f9c0, CHK2);
5959 INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC);
5960 BASE(bitop_reg, 0100, f1c0);
5961 BASE(bitop_reg, 0140, f1c0);
5962 BASE(bitop_reg, 0180, f1c0);
5963 BASE(bitop_reg, 01c0, f1c0);
5964 INSN(movep, 0108, f138, MOVEP);
5965 INSN(arith_im, 0280, fff8, CF_ISA_A);
5966 INSN(arith_im, 0200, ff00, M68000);
5967 INSN(undef, 02c0, ffc0, M68000);
5968 INSN(byterev, 02c0, fff8, CF_ISA_APLUSC);
5969 INSN(arith_im, 0480, fff8, CF_ISA_A);
5970 INSN(arith_im, 0400, ff00, M68000);
5971 INSN(undef, 04c0, ffc0, M68000);
5972 INSN(arith_im, 0600, ff00, M68000);
5973 INSN(undef, 06c0, ffc0, M68000);
5974 INSN(ff1, 04c0, fff8, CF_ISA_APLUSC);
5975 INSN(arith_im, 0680, fff8, CF_ISA_A);
5976 INSN(arith_im, 0c00, ff38, CF_ISA_A);
5977 INSN(arith_im, 0c00, ff00, M68000);
5978 BASE(bitop_im, 0800, ffc0);
5979 BASE(bitop_im, 0840, ffc0);
5980 BASE(bitop_im, 0880, ffc0);
5981 BASE(bitop_im, 08c0, ffc0);
5982 INSN(arith_im, 0a80, fff8, CF_ISA_A);
5983 INSN(arith_im, 0a00, ff00, M68000);
5984 #if defined(CONFIG_SOFTMMU)
5985 INSN(moves, 0e00, ff00, M68000);
5986 #endif
5987 INSN(cas, 0ac0, ffc0, CAS);
5988 INSN(cas, 0cc0, ffc0, CAS);
5989 INSN(cas, 0ec0, ffc0, CAS);
5990 INSN(cas2w, 0cfc, ffff, CAS);
5991 INSN(cas2l, 0efc, ffff, CAS);
5992 BASE(move, 1000, f000);
5993 BASE(move, 2000, f000);
5994 BASE(move, 3000, f000);
5995 INSN(chk, 4000, f040, M68000);
5996 INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
5997 INSN(negx, 4080, fff8, CF_ISA_A);
5998 INSN(negx, 4000, ff00, M68000);
5999 INSN(undef, 40c0, ffc0, M68000);
6000 INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
6001 INSN(move_from_sr, 40c0, ffc0, M68000);
6002 BASE(lea, 41c0, f1c0);
6003 BASE(clr, 4200, ff00);
6004 BASE(undef, 42c0, ffc0);
6005 INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
6006 INSN(move_from_ccr, 42c0, ffc0, M68000);
6007 INSN(neg, 4480, fff8, CF_ISA_A);
6008 INSN(neg, 4400, ff00, M68000);
6009 INSN(undef, 44c0, ffc0, M68000);
6010 BASE(move_to_ccr, 44c0, ffc0);
6011 INSN(not, 4680, fff8, CF_ISA_A);
6012 INSN(not, 4600, ff00, M68000);
6013 #if defined(CONFIG_SOFTMMU)
6014 BASE(move_to_sr, 46c0, ffc0);
6015 #endif
6016 INSN(nbcd, 4800, ffc0, M68000);
6017 INSN(linkl, 4808, fff8, M68000);
6018 BASE(pea, 4840, ffc0);
6019 BASE(swap, 4840, fff8);
6020 INSN(bkpt, 4848, fff8, BKPT);
6021 INSN(movem, 48d0, fbf8, CF_ISA_A);
6022 INSN(movem, 48e8, fbf8, CF_ISA_A);
6023 INSN(movem, 4880, fb80, M68000);
6024 BASE(ext, 4880, fff8);
6025 BASE(ext, 48c0, fff8);
6026 BASE(ext, 49c0, fff8);
6027 BASE(tst, 4a00, ff00);
6028 INSN(tas, 4ac0, ffc0, CF_ISA_B);
6029 INSN(tas, 4ac0, ffc0, M68000);
6030 #if defined(CONFIG_SOFTMMU)
6031 INSN(halt, 4ac8, ffff, CF_ISA_A);
6032 #endif
6033 INSN(pulse, 4acc, ffff, CF_ISA_A);
6034 BASE(illegal, 4afc, ffff);
6035 INSN(mull, 4c00, ffc0, CF_ISA_A);
6036 INSN(mull, 4c00, ffc0, LONG_MULDIV);
6037 INSN(divl, 4c40, ffc0, CF_ISA_A);
6038 INSN(divl, 4c40, ffc0, LONG_MULDIV);
6039 INSN(sats, 4c80, fff8, CF_ISA_B);
6040 BASE(trap, 4e40, fff0);
6041 BASE(link, 4e50, fff8);
6042 BASE(unlk, 4e58, fff8);
6043 #if defined(CONFIG_SOFTMMU)
6044 INSN(move_to_usp, 4e60, fff8, USP);
6045 INSN(move_from_usp, 4e68, fff8, USP);
6046 INSN(reset, 4e70, ffff, M68000);
6047 BASE(stop, 4e72, ffff);
6048 BASE(rte, 4e73, ffff);
6049 INSN(cf_movec, 4e7b, ffff, CF_ISA_A);
6050 INSN(m68k_movec, 4e7a, fffe, MOVEC);
6051 #endif
6052 BASE(nop, 4e71, ffff);
6053 INSN(rtd, 4e74, ffff, RTD);
6054 BASE(rts, 4e75, ffff);
6055 INSN(rtr, 4e77, ffff, M68000);
6056 BASE(jump, 4e80, ffc0);
6057 BASE(jump, 4ec0, ffc0);
6058 INSN(addsubq, 5000, f080, M68000);
6059 BASE(addsubq, 5080, f0c0);
6060 INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */
6061 INSN(scc, 50c0, f0c0, M68000); /* Scc.B <EA> */
6062 INSN(dbcc, 50c8, f0f8, M68000);
6063 INSN(tpf, 51f8, fff8, CF_ISA_A);
6065 /* Branch instructions. */
6066 BASE(branch, 6000, f000);
6067 /* Disable long branch instructions, then add back the ones we want. */
6068 BASE(undef, 60ff, f0ff); /* All long branches. */
6069 INSN(branch, 60ff, f0ff, CF_ISA_B);
6070 INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */
6071 INSN(branch, 60ff, ffff, BRAL);
6072 INSN(branch, 60ff, f0ff, BCCL);
6074 BASE(moveq, 7000, f100);
6075 INSN(mvzs, 7100, f100, CF_ISA_B);
6076 BASE(or, 8000, f000);
6077 BASE(divw, 80c0, f0c0);
6078 INSN(sbcd_reg, 8100, f1f8, M68000);
6079 INSN(sbcd_mem, 8108, f1f8, M68000);
6080 BASE(addsub, 9000, f000);
6081 INSN(undef, 90c0, f0c0, CF_ISA_A);
6082 INSN(subx_reg, 9180, f1f8, CF_ISA_A);
6083 INSN(subx_reg, 9100, f138, M68000);
6084 INSN(subx_mem, 9108, f138, M68000);
6085 INSN(suba, 91c0, f1c0, CF_ISA_A);
6086 INSN(suba, 90c0, f0c0, M68000);
6088 BASE(undef_mac, a000, f000);
6089 INSN(mac, a000, f100, CF_EMAC);
6090 INSN(from_mac, a180, f9b0, CF_EMAC);
6091 INSN(move_mac, a110, f9fc, CF_EMAC);
6092 INSN(from_macsr,a980, f9f0, CF_EMAC);
6093 INSN(from_mask, ad80, fff0, CF_EMAC);
6094 INSN(from_mext, ab80, fbf0, CF_EMAC);
6095 INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
6096 INSN(to_mac, a100, f9c0, CF_EMAC);
6097 INSN(to_macsr, a900, ffc0, CF_EMAC);
6098 INSN(to_mext, ab00, fbc0, CF_EMAC);
6099 INSN(to_mask, ad00, ffc0, CF_EMAC);
6101 INSN(mov3q, a140, f1c0, CF_ISA_B);
6102 INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */
6103 INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */
6104 INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */
6105 INSN(cmp, b080, f1c0, CF_ISA_A);
6106 INSN(cmpa, b1c0, f1c0, CF_ISA_A);
6107 INSN(cmp, b000, f100, M68000);
6108 INSN(eor, b100, f100, M68000);
6109 INSN(cmpm, b108, f138, M68000);
6110 INSN(cmpa, b0c0, f0c0, M68000);
6111 INSN(eor, b180, f1c0, CF_ISA_A);
6112 BASE(and, c000, f000);
6113 INSN(exg_dd, c140, f1f8, M68000);
6114 INSN(exg_aa, c148, f1f8, M68000);
6115 INSN(exg_da, c188, f1f8, M68000);
6116 BASE(mulw, c0c0, f0c0);
6117 INSN(abcd_reg, c100, f1f8, M68000);
6118 INSN(abcd_mem, c108, f1f8, M68000);
6119 BASE(addsub, d000, f000);
6120 INSN(undef, d0c0, f0c0, CF_ISA_A);
6121 INSN(addx_reg, d180, f1f8, CF_ISA_A);
6122 INSN(addx_reg, d100, f138, M68000);
6123 INSN(addx_mem, d108, f138, M68000);
6124 INSN(adda, d1c0, f1c0, CF_ISA_A);
6125 INSN(adda, d0c0, f0c0, M68000);
6126 INSN(shift_im, e080, f0f0, CF_ISA_A);
6127 INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
6128 INSN(shift8_im, e000, f0f0, M68000);
6129 INSN(shift16_im, e040, f0f0, M68000);
6130 INSN(shift_im, e080, f0f0, M68000);
6131 INSN(shift8_reg, e020, f0f0, M68000);
6132 INSN(shift16_reg, e060, f0f0, M68000);
6133 INSN(shift_reg, e0a0, f0f0, M68000);
6134 INSN(shift_mem, e0c0, fcc0, M68000);
6135 INSN(rotate_im, e090, f0f0, M68000);
6136 INSN(rotate8_im, e010, f0f0, M68000);
6137 INSN(rotate16_im, e050, f0f0, M68000);
6138 INSN(rotate_reg, e0b0, f0f0, M68000);
6139 INSN(rotate8_reg, e030, f0f0, M68000);
6140 INSN(rotate16_reg, e070, f0f0, M68000);
6141 INSN(rotate_mem, e4c0, fcc0, M68000);
6142 INSN(bfext_mem, e9c0, fdc0, BITFIELD); /* bfextu & bfexts */
6143 INSN(bfext_reg, e9c0, fdf8, BITFIELD);
6144 INSN(bfins_mem, efc0, ffc0, BITFIELD);
6145 INSN(bfins_reg, efc0, fff8, BITFIELD);
6146 INSN(bfop_mem, eac0, ffc0, BITFIELD); /* bfchg */
6147 INSN(bfop_reg, eac0, fff8, BITFIELD); /* bfchg */
6148 INSN(bfop_mem, ecc0, ffc0, BITFIELD); /* bfclr */
6149 INSN(bfop_reg, ecc0, fff8, BITFIELD); /* bfclr */
6150 INSN(bfop_mem, edc0, ffc0, BITFIELD); /* bfffo */
6151 INSN(bfop_reg, edc0, fff8, BITFIELD); /* bfffo */
6152 INSN(bfop_mem, eec0, ffc0, BITFIELD); /* bfset */
6153 INSN(bfop_reg, eec0, fff8, BITFIELD); /* bfset */
6154 INSN(bfop_mem, e8c0, ffc0, BITFIELD); /* bftst */
6155 INSN(bfop_reg, e8c0, fff8, BITFIELD); /* bftst */
6156 BASE(undef_fpu, f000, f000);
6157 INSN(fpu, f200, ffc0, CF_FPU);
6158 INSN(fbcc, f280, ffc0, CF_FPU);
6159 INSN(fpu, f200, ffc0, FPU);
6160 INSN(fscc, f240, ffc0, FPU);
6161 INSN(fbcc, f280, ff80, FPU);
6162 #if defined(CONFIG_SOFTMMU)
6163 INSN(frestore, f340, ffc0, CF_FPU);
6164 INSN(fsave, f300, ffc0, CF_FPU);
6165 INSN(frestore, f340, ffc0, FPU);
6166 INSN(fsave, f300, ffc0, FPU);
6167 INSN(intouch, f340, ffc0, CF_ISA_A);
6168 INSN(cpushl, f428, ff38, CF_ISA_A);
6169 INSN(cpush, f420, ff20, M68040);
6170 INSN(cinv, f400, ff20, M68040);
6171 INSN(pflush, f500, ffe0, M68040);
6172 INSN(ptest, f548, ffd8, M68040);
6173 INSN(wddata, fb00, ff00, CF_ISA_A);
6174 INSN(wdebug, fbc0, ffc0, CF_ISA_A);
6175 #endif
6176 INSN(move16_mem, f600, ffe0, M68040);
6177 INSN(move16_reg, f620, fff8, M68040);
6178 #undef INSN
6181 static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
6183 DisasContext *dc = container_of(dcbase, DisasContext, base);
6184 CPUM68KState *env = cpu->env_ptr;
6186 dc->env = env;
6187 dc->pc = dc->base.pc_first;
6188 dc->cc_op = CC_OP_DYNAMIC;
6189 dc->cc_op_synced = 1;
6190 dc->done_mac = 0;
6191 dc->writeback_mask = 0;
6192 init_release_array(dc);
6194 dc->ss_active = (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS);
6195 /* If architectural single step active, limit to 1 */
6196 if (is_singlestepping(dc)) {
6197 dc->base.max_insns = 1;
6201 static void m68k_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
6205 static void m68k_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
6207 DisasContext *dc = container_of(dcbase, DisasContext, base);
6208 tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
6211 static bool m68k_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
6212 const CPUBreakpoint *bp)
6214 DisasContext *dc = container_of(dcbase, DisasContext, base);
6216 gen_exception(dc, dc->base.pc_next, EXCP_DEBUG);
6218 * The address covered by the breakpoint must be included in
6219 * [tb->pc, tb->pc + tb->size) in order to for it to be
6220 * properly cleared -- thus we increment the PC here so that
6221 * the logic setting tb->size below does the right thing.
6223 dc->base.pc_next += 2;
6225 return true;
6228 static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
6230 DisasContext *dc = container_of(dcbase, DisasContext, base);
6231 CPUM68KState *env = cpu->env_ptr;
6232 uint16_t insn = read_im16(env, dc);
6234 opcode_table[insn](env, dc, insn);
6235 do_writebacks(dc);
6236 do_release(dc);
6238 dc->base.pc_next = dc->pc;
6240 if (dc->base.is_jmp == DISAS_NEXT) {
6242 * Stop translation when the next insn might touch a new page.
6243 * This ensures that prefetch aborts at the right place.
6245 * We cannot determine the size of the next insn without
6246 * completely decoding it. However, the maximum insn size
6247 * is 32 bytes, so end if we do not have that much remaining.
6248 * This may produce several small TBs at the end of each page,
6249 * but they will all be linked with goto_tb.
6251 * ??? ColdFire maximum is 4 bytes; MC68000's maximum is also
6252 * smaller than MC68020's.
6254 target_ulong start_page_offset
6255 = dc->pc - (dc->base.pc_first & TARGET_PAGE_MASK);
6257 if (start_page_offset >= TARGET_PAGE_SIZE - 32) {
6258 dc->base.is_jmp = DISAS_TOO_MANY;
6263 static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
6265 DisasContext *dc = container_of(dcbase, DisasContext, base);
6267 switch (dc->base.is_jmp) {
6268 case DISAS_NORETURN:
6269 break;
6270 case DISAS_TOO_MANY:
6271 update_cc_op(dc);
6272 if (is_singlestepping(dc)) {
6273 tcg_gen_movi_i32(QREG_PC, dc->pc);
6274 gen_singlestep_exception(dc);
6275 } else {
6276 gen_jmp_tb(dc, 0, dc->pc);
6278 break;
6279 case DISAS_JUMP:
6280 /* We updated CC_OP and PC in gen_jmp/gen_jmp_im. */
6281 if (is_singlestepping(dc)) {
6282 gen_singlestep_exception(dc);
6283 } else {
6284 tcg_gen_lookup_and_goto_ptr();
6286 break;
6287 case DISAS_EXIT:
6289 * We updated CC_OP and PC in gen_exit_tb, but also modified
6290 * other state that may require returning to the main loop.
6292 if (is_singlestepping(dc)) {
6293 gen_singlestep_exception(dc);
6294 } else {
6295 tcg_gen_exit_tb(NULL, 0);
6297 break;
6298 default:
6299 g_assert_not_reached();
6303 static void m68k_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
6305 qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
6306 log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
6309 static const TranslatorOps m68k_tr_ops = {
6310 .init_disas_context = m68k_tr_init_disas_context,
6311 .tb_start = m68k_tr_tb_start,
6312 .insn_start = m68k_tr_insn_start,
6313 .breakpoint_check = m68k_tr_breakpoint_check,
6314 .translate_insn = m68k_tr_translate_insn,
6315 .tb_stop = m68k_tr_tb_stop,
6316 .disas_log = m68k_tr_disas_log,
6319 void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
6321 DisasContext dc;
6322 translator_loop(&m68k_tr_ops, &dc.base, cpu, tb, max_insns);
6325 static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low)
6327 floatx80 a = { .high = high, .low = low };
6328 union {
6329 float64 f64;
6330 double d;
6331 } u;
6333 u.f64 = floatx80_to_float64(a, &env->fp_status);
6334 return u.d;
6337 void m68k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
6339 M68kCPU *cpu = M68K_CPU(cs);
6340 CPUM68KState *env = &cpu->env;
6341 int i;
6342 uint16_t sr;
6343 for (i = 0; i < 8; i++) {
6344 qemu_fprintf(f, "D%d = %08x A%d = %08x "
6345 "F%d = %04x %016"PRIx64" (%12g)\n",
6346 i, env->dregs[i], i, env->aregs[i],
6347 i, env->fregs[i].l.upper, env->fregs[i].l.lower,
6348 floatx80_to_double(env, env->fregs[i].l.upper,
6349 env->fregs[i].l.lower));
6351 qemu_fprintf(f, "PC = %08x ", env->pc);
6352 sr = env->sr | cpu_m68k_get_ccr(env);
6353 qemu_fprintf(f, "SR = %04x T:%x I:%x %c%c %c%c%c%c%c\n",
6354 sr, (sr & SR_T) >> SR_T_SHIFT, (sr & SR_I) >> SR_I_SHIFT,
6355 (sr & SR_S) ? 'S' : 'U', (sr & SR_M) ? '%' : 'I',
6356 (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-',
6357 (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-',
6358 (sr & CCF_C) ? 'C' : '-');
6359 qemu_fprintf(f, "FPSR = %08x %c%c%c%c ", env->fpsr,
6360 (env->fpsr & FPSR_CC_A) ? 'A' : '-',
6361 (env->fpsr & FPSR_CC_I) ? 'I' : '-',
6362 (env->fpsr & FPSR_CC_Z) ? 'Z' : '-',
6363 (env->fpsr & FPSR_CC_N) ? 'N' : '-');
6364 qemu_fprintf(f, "\n "
6365 "FPCR = %04x ", env->fpcr);
6366 switch (env->fpcr & FPCR_PREC_MASK) {
6367 case FPCR_PREC_X:
6368 qemu_fprintf(f, "X ");
6369 break;
6370 case FPCR_PREC_S:
6371 qemu_fprintf(f, "S ");
6372 break;
6373 case FPCR_PREC_D:
6374 qemu_fprintf(f, "D ");
6375 break;
6377 switch (env->fpcr & FPCR_RND_MASK) {
6378 case FPCR_RND_N:
6379 qemu_fprintf(f, "RN ");
6380 break;
6381 case FPCR_RND_Z:
6382 qemu_fprintf(f, "RZ ");
6383 break;
6384 case FPCR_RND_M:
6385 qemu_fprintf(f, "RM ");
6386 break;
6387 case FPCR_RND_P:
6388 qemu_fprintf(f, "RP ");
6389 break;
6391 qemu_fprintf(f, "\n");
6392 #ifdef CONFIG_SOFTMMU
6393 qemu_fprintf(f, "%sA7(MSP) = %08x %sA7(USP) = %08x %sA7(ISP) = %08x\n",
6394 env->current_sp == M68K_SSP ? "->" : " ", env->sp[M68K_SSP],
6395 env->current_sp == M68K_USP ? "->" : " ", env->sp[M68K_USP],
6396 env->current_sp == M68K_ISP ? "->" : " ", env->sp[M68K_ISP]);
6397 qemu_fprintf(f, "VBR = 0x%08x\n", env->vbr);
6398 qemu_fprintf(f, "SFC = %x DFC %x\n", env->sfc, env->dfc);
6399 qemu_fprintf(f, "SSW %08x TCR %08x URP %08x SRP %08x\n",
6400 env->mmu.ssw, env->mmu.tcr, env->mmu.urp, env->mmu.srp);
6401 qemu_fprintf(f, "DTTR0/1: %08x/%08x ITTR0/1: %08x/%08x\n",
6402 env->mmu.ttr[M68K_DTTR0], env->mmu.ttr[M68K_DTTR1],
6403 env->mmu.ttr[M68K_ITTR0], env->mmu.ttr[M68K_ITTR1]);
6404 qemu_fprintf(f, "MMUSR %08x, fault at %08x\n",
6405 env->mmu.mmusr, env->mmu.ar);
6406 #endif
6409 void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb,
6410 target_ulong *data)
6412 int cc_op = data[1];
6413 env->pc = data[0];
6414 if (cc_op != CC_OP_DYNAMIC) {
6415 env->cc_op = cc_op;