xref: /openbmc/qemu/target/m68k/translate.c (revision a4f9d9a4b2167201d53050eb7e00bef0c863d075)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  m68k translation
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2005-2007 CodeSourcery
5fcf5ef2aSThomas Huth  *  Written by Paul Brook
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
10d749fb85SThomas Huth  * version 2.1 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15d749fb85SThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth  */
20fcf5ef2aSThomas Huth 
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "exec/exec-all.h"
24dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
25fcf5ef2aSThomas Huth #include "qemu/log.h"
2690c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
2777fc6f5eSLluís Vilanova #include "exec/translator.h"
28fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
29fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
30fcf5ef2aSThomas Huth #include "exec/log.h"
3124f91e81SAlex Bennée #include "fpu/softfloat.h"
32f161e723SRichard Henderson #include "semihosting/semihost.h"
3324f91e81SAlex Bennée 
34d53106c9SRichard Henderson #define HELPER_H "helper.h"
35d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
36d53106c9SRichard Henderson #undef  HELPER_H
37fcf5ef2aSThomas Huth 
38fcf5ef2aSThomas Huth //#define DEBUG_DISPATCH 1
39fcf5ef2aSThomas Huth 
40fcf5ef2aSThomas Huth #define DEFO32(name, offset) static TCGv QREG_##name;
41fcf5ef2aSThomas Huth #define DEFO64(name, offset) static TCGv_i64 QREG_##name;
420f208a97SPhilippe Mathieu-Daudé #include "qregs.h.inc"
43fcf5ef2aSThomas Huth #undef DEFO32
44fcf5ef2aSThomas Huth #undef DEFO64
45fcf5ef2aSThomas Huth 
46fcf5ef2aSThomas Huth static TCGv_i32 cpu_halted;
47fcf5ef2aSThomas Huth static TCGv_i32 cpu_exception_index;
48fcf5ef2aSThomas Huth 
49f83311e4SLaurent Vivier static char cpu_reg_names[2 * 8 * 3 + 5 * 4];
50fcf5ef2aSThomas Huth static TCGv cpu_dregs[8];
51fcf5ef2aSThomas Huth static TCGv cpu_aregs[8];
52fcf5ef2aSThomas Huth static TCGv_i64 cpu_macc[4];
53fcf5ef2aSThomas Huth 
54fcf5ef2aSThomas Huth #define REG(insn, pos)  (((insn) >> (pos)) & 7)
55fcf5ef2aSThomas Huth #define DREG(insn, pos) cpu_dregs[REG(insn, pos)]
568a1e52b6SRichard Henderson #define AREG(insn, pos) get_areg(s, REG(insn, pos))
57fcf5ef2aSThomas Huth #define MACREG(acc)     cpu_macc[acc]
588a1e52b6SRichard Henderson #define QREG_SP         get_areg(s, 7)
59fcf5ef2aSThomas Huth 
60fcf5ef2aSThomas Huth static TCGv NULL_QREG;
6111f4e8f8SRichard Henderson #define IS_NULL_QREG(t) (t == NULL_QREG)
62fcf5ef2aSThomas Huth /* Used to distinguish stores from bad addressing modes.  */
63fcf5ef2aSThomas Huth static TCGv store_dummy;
64fcf5ef2aSThomas Huth 
m68k_tcg_init(void)65fcf5ef2aSThomas Huth void m68k_tcg_init(void)
66fcf5ef2aSThomas Huth {
67fcf5ef2aSThomas Huth     char *p;
68fcf5ef2aSThomas Huth     int i;
69fcf5ef2aSThomas Huth 
70fcf5ef2aSThomas Huth #define DEFO32(name, offset) \
71ad75a51eSRichard Henderson     QREG_##name = tcg_global_mem_new_i32(tcg_env, \
72fcf5ef2aSThomas Huth         offsetof(CPUM68KState, offset), #name);
73fcf5ef2aSThomas Huth #define DEFO64(name, offset) \
74ad75a51eSRichard Henderson     QREG_##name = tcg_global_mem_new_i64(tcg_env, \
75fcf5ef2aSThomas Huth         offsetof(CPUM68KState, offset), #name);
760f208a97SPhilippe Mathieu-Daudé #include "qregs.h.inc"
77fcf5ef2aSThomas Huth #undef DEFO32
78fcf5ef2aSThomas Huth #undef DEFO64
79fcf5ef2aSThomas Huth 
80ad75a51eSRichard Henderson     cpu_halted = tcg_global_mem_new_i32(tcg_env,
81fcf5ef2aSThomas Huth                                         -offsetof(M68kCPU, env) +
82fcf5ef2aSThomas Huth                                         offsetof(CPUState, halted), "HALTED");
83ad75a51eSRichard Henderson     cpu_exception_index = tcg_global_mem_new_i32(tcg_env,
84fcf5ef2aSThomas Huth                                                  -offsetof(M68kCPU, env) +
85fcf5ef2aSThomas Huth                                                  offsetof(CPUState, exception_index),
86fcf5ef2aSThomas Huth                                                  "EXCEPTION");
87fcf5ef2aSThomas Huth 
88fcf5ef2aSThomas Huth     p = cpu_reg_names;
89fcf5ef2aSThomas Huth     for (i = 0; i < 8; i++) {
90fcf5ef2aSThomas Huth         sprintf(p, "D%d", i);
91ad75a51eSRichard Henderson         cpu_dregs[i] = tcg_global_mem_new(tcg_env,
92fcf5ef2aSThomas Huth                                           offsetof(CPUM68KState, dregs[i]), p);
93fcf5ef2aSThomas Huth         p += 3;
94fcf5ef2aSThomas Huth         sprintf(p, "A%d", i);
95ad75a51eSRichard Henderson         cpu_aregs[i] = tcg_global_mem_new(tcg_env,
96fcf5ef2aSThomas Huth                                           offsetof(CPUM68KState, aregs[i]), p);
97fcf5ef2aSThomas Huth         p += 3;
98fcf5ef2aSThomas Huth     }
99fcf5ef2aSThomas Huth     for (i = 0; i < 4; i++) {
100fcf5ef2aSThomas Huth         sprintf(p, "ACC%d", i);
101ad75a51eSRichard Henderson         cpu_macc[i] = tcg_global_mem_new_i64(tcg_env,
102fcf5ef2aSThomas Huth                                          offsetof(CPUM68KState, macc[i]), p);
103fcf5ef2aSThomas Huth         p += 5;
104fcf5ef2aSThomas Huth     }
105fcf5ef2aSThomas Huth 
106ad75a51eSRichard Henderson     NULL_QREG = tcg_global_mem_new(tcg_env, -4, "NULL");
107ad75a51eSRichard Henderson     store_dummy = tcg_global_mem_new(tcg_env, -8, "NULL");
108fcf5ef2aSThomas Huth }
109fcf5ef2aSThomas Huth 
110fcf5ef2aSThomas Huth /* internal defines */
111fcf5ef2aSThomas Huth typedef struct DisasContext {
112a575cbe0SRichard Henderson     DisasContextBase base;
113fcf5ef2aSThomas Huth     CPUM68KState *env;
114fcf5ef2aSThomas Huth     target_ulong pc;
1158115fc93SRichard Henderson     target_ulong pc_prev;
116fcf5ef2aSThomas Huth     CCOp cc_op; /* Current CC operation */
117fcf5ef2aSThomas Huth     int cc_op_synced;
118fcf5ef2aSThomas Huth     TCGv_i64 mactmp;
119fcf5ef2aSThomas Huth     int done_mac;
1208a1e52b6SRichard Henderson     int writeback_mask;
1218a1e52b6SRichard Henderson     TCGv writeback[8];
1225e50c6c7SMark Cave-Ayland     bool ss_active;
123fcf5ef2aSThomas Huth } DisasContext;
124fcf5ef2aSThomas Huth 
get_areg(DisasContext * s,unsigned regno)1258a1e52b6SRichard Henderson static TCGv get_areg(DisasContext *s, unsigned regno)
1268a1e52b6SRichard Henderson {
1278a1e52b6SRichard Henderson     if (s->writeback_mask & (1 << regno)) {
1288a1e52b6SRichard Henderson         return s->writeback[regno];
1298a1e52b6SRichard Henderson     } else {
1308a1e52b6SRichard Henderson         return cpu_aregs[regno];
1318a1e52b6SRichard Henderson     }
1328a1e52b6SRichard Henderson }
1338a1e52b6SRichard Henderson 
delay_set_areg(DisasContext * s,unsigned regno,TCGv val,bool give_temp)1348a1e52b6SRichard Henderson static void delay_set_areg(DisasContext *s, unsigned regno,
1358a1e52b6SRichard Henderson                            TCGv val, bool give_temp)
1368a1e52b6SRichard Henderson {
1378a1e52b6SRichard Henderson     if (s->writeback_mask & (1 << regno)) {
1388a1e52b6SRichard Henderson         if (give_temp) {
1398a1e52b6SRichard Henderson             s->writeback[regno] = val;
1408a1e52b6SRichard Henderson         } else {
1418a1e52b6SRichard Henderson             tcg_gen_mov_i32(s->writeback[regno], val);
1428a1e52b6SRichard Henderson         }
1438a1e52b6SRichard Henderson     } else {
1448a1e52b6SRichard Henderson         s->writeback_mask |= 1 << regno;
1458a1e52b6SRichard Henderson         if (give_temp) {
1468a1e52b6SRichard Henderson             s->writeback[regno] = val;
1478a1e52b6SRichard Henderson         } else {
1488a1e52b6SRichard Henderson             TCGv tmp = tcg_temp_new();
1498a1e52b6SRichard Henderson             s->writeback[regno] = tmp;
1508a1e52b6SRichard Henderson             tcg_gen_mov_i32(tmp, val);
1518a1e52b6SRichard Henderson         }
1528a1e52b6SRichard Henderson     }
1538a1e52b6SRichard Henderson }
1548a1e52b6SRichard Henderson 
do_writebacks(DisasContext * s)1558a1e52b6SRichard Henderson static void do_writebacks(DisasContext *s)
1568a1e52b6SRichard Henderson {
1578a1e52b6SRichard Henderson     unsigned mask = s->writeback_mask;
1588a1e52b6SRichard Henderson     if (mask) {
1598a1e52b6SRichard Henderson         s->writeback_mask = 0;
1608a1e52b6SRichard Henderson         do {
1618a1e52b6SRichard Henderson             unsigned regno = ctz32(mask);
1628a1e52b6SRichard Henderson             tcg_gen_mov_i32(cpu_aregs[regno], s->writeback[regno]);
1638a1e52b6SRichard Henderson             mask &= mask - 1;
1648a1e52b6SRichard Henderson         } while (mask);
1658a1e52b6SRichard Henderson     }
1668a1e52b6SRichard Henderson }
1678a1e52b6SRichard Henderson 
16877fc6f5eSLluís Vilanova /* is_jmp field values */
16977fc6f5eSLluís Vilanova #define DISAS_JUMP      DISAS_TARGET_0 /* only pc was modified dynamically */
1704106f26eSRichard Henderson #define DISAS_EXIT      DISAS_TARGET_1 /* cpu state was modified dynamically */
171fcf5ef2aSThomas Huth 
172fcf5ef2aSThomas Huth #if defined(CONFIG_USER_ONLY)
173fcf5ef2aSThomas Huth #define IS_USER(s) 1
174fcf5ef2aSThomas Huth #else
175a575cbe0SRichard Henderson #define IS_USER(s)   (!(s->base.tb->flags & TB_FLAGS_MSR_S))
176a575cbe0SRichard Henderson #define SFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_SFC_S) ? \
1775fa9f1f2SLaurent Vivier                       MMU_KERNEL_IDX : MMU_USER_IDX)
178a575cbe0SRichard Henderson #define DFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_DFC_S) ? \
1795fa9f1f2SLaurent Vivier                       MMU_KERNEL_IDX : MMU_USER_IDX)
180fcf5ef2aSThomas Huth #endif
181fcf5ef2aSThomas Huth 
182fcf5ef2aSThomas Huth typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn);
183fcf5ef2aSThomas Huth 
184fcf5ef2aSThomas Huth #ifdef DEBUG_DISPATCH
185fcf5ef2aSThomas Huth #define DISAS_INSN(name)                                                \
186fcf5ef2aSThomas Huth     static void real_disas_##name(CPUM68KState *env, DisasContext *s,   \
187fcf5ef2aSThomas Huth                                   uint16_t insn);                       \
188fcf5ef2aSThomas Huth     static void disas_##name(CPUM68KState *env, DisasContext *s,        \
189fcf5ef2aSThomas Huth                              uint16_t insn)                             \
190fcf5ef2aSThomas Huth     {                                                                   \
191fcf5ef2aSThomas Huth         qemu_log("Dispatch " #name "\n");                               \
192fcf5ef2aSThomas Huth         real_disas_##name(env, s, insn);                                \
193fcf5ef2aSThomas Huth     }                                                                   \
194fcf5ef2aSThomas Huth     static void real_disas_##name(CPUM68KState *env, DisasContext *s,   \
195fcf5ef2aSThomas Huth                                   uint16_t insn)
196fcf5ef2aSThomas Huth #else
197fcf5ef2aSThomas Huth #define DISAS_INSN(name)                                                \
198fcf5ef2aSThomas Huth     static void disas_##name(CPUM68KState *env, DisasContext *s,        \
199fcf5ef2aSThomas Huth                              uint16_t insn)
200fcf5ef2aSThomas Huth #endif
201fcf5ef2aSThomas Huth 
202fcf5ef2aSThomas Huth static const uint8_t cc_op_live[CC_OP_NB] = {
2037deddf96SLaurent Vivier     [CC_OP_DYNAMIC] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
204fcf5ef2aSThomas Huth     [CC_OP_FLAGS] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
205fcf5ef2aSThomas Huth     [CC_OP_ADDB ... CC_OP_ADDL] = CCF_X | CCF_N | CCF_V,
206fcf5ef2aSThomas Huth     [CC_OP_SUBB ... CC_OP_SUBL] = CCF_X | CCF_N | CCF_V,
207fcf5ef2aSThomas Huth     [CC_OP_CMPB ... CC_OP_CMPL] = CCF_X | CCF_N | CCF_V,
208fcf5ef2aSThomas Huth     [CC_OP_LOGIC] = CCF_X | CCF_N
209fcf5ef2aSThomas Huth };
210fcf5ef2aSThomas Huth 
set_cc_op(DisasContext * s,CCOp op)211fcf5ef2aSThomas Huth static void set_cc_op(DisasContext *s, CCOp op)
212fcf5ef2aSThomas Huth {
213fcf5ef2aSThomas Huth     CCOp old_op = s->cc_op;
214fcf5ef2aSThomas Huth     int dead;
215fcf5ef2aSThomas Huth 
216fcf5ef2aSThomas Huth     if (old_op == op) {
217fcf5ef2aSThomas Huth         return;
218fcf5ef2aSThomas Huth     }
219fcf5ef2aSThomas Huth     s->cc_op = op;
220fcf5ef2aSThomas Huth     s->cc_op_synced = 0;
221fcf5ef2aSThomas Huth 
222808d77bcSLucien Murray-Pitts     /*
223808d77bcSLucien Murray-Pitts      * Discard CC computation that will no longer be used.
224808d77bcSLucien Murray-Pitts      * Note that X and N are never dead.
225808d77bcSLucien Murray-Pitts      */
226fcf5ef2aSThomas Huth     dead = cc_op_live[old_op] & ~cc_op_live[op];
227fcf5ef2aSThomas Huth     if (dead & CCF_C) {
228fcf5ef2aSThomas Huth         tcg_gen_discard_i32(QREG_CC_C);
229fcf5ef2aSThomas Huth     }
230fcf5ef2aSThomas Huth     if (dead & CCF_Z) {
231fcf5ef2aSThomas Huth         tcg_gen_discard_i32(QREG_CC_Z);
232fcf5ef2aSThomas Huth     }
233fcf5ef2aSThomas Huth     if (dead & CCF_V) {
234fcf5ef2aSThomas Huth         tcg_gen_discard_i32(QREG_CC_V);
235fcf5ef2aSThomas Huth     }
236fcf5ef2aSThomas Huth }
237fcf5ef2aSThomas Huth 
238fcf5ef2aSThomas Huth /* Update the CPU env CC_OP state.  */
update_cc_op(DisasContext * s)239fcf5ef2aSThomas Huth static void update_cc_op(DisasContext *s)
240fcf5ef2aSThomas Huth {
241fcf5ef2aSThomas Huth     if (!s->cc_op_synced) {
242fcf5ef2aSThomas Huth         s->cc_op_synced = 1;
243fcf5ef2aSThomas Huth         tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
244fcf5ef2aSThomas Huth     }
245fcf5ef2aSThomas Huth }
246fcf5ef2aSThomas Huth 
247f83311e4SLaurent Vivier /* Generate a jump to an immediate address.  */
gen_jmp_im(DisasContext * s,uint32_t dest)248f83311e4SLaurent Vivier static void gen_jmp_im(DisasContext *s, uint32_t dest)
249f83311e4SLaurent Vivier {
250f83311e4SLaurent Vivier     update_cc_op(s);
251f83311e4SLaurent Vivier     tcg_gen_movi_i32(QREG_PC, dest);
252a575cbe0SRichard Henderson     s->base.is_jmp = DISAS_JUMP;
253f83311e4SLaurent Vivier }
254f83311e4SLaurent Vivier 
255f83311e4SLaurent Vivier /* Generate a jump to the address in qreg DEST.  */
gen_jmp(DisasContext * s,TCGv dest)256f83311e4SLaurent Vivier static void gen_jmp(DisasContext *s, TCGv dest)
257f83311e4SLaurent Vivier {
258f83311e4SLaurent Vivier     update_cc_op(s);
259f83311e4SLaurent Vivier     tcg_gen_mov_i32(QREG_PC, dest);
260a575cbe0SRichard Henderson     s->base.is_jmp = DISAS_JUMP;
261f83311e4SLaurent Vivier }
262f83311e4SLaurent Vivier 
gen_raise_exception(int nr)263322f244aSLaurent Vivier static void gen_raise_exception(int nr)
264f83311e4SLaurent Vivier {
265ad75a51eSRichard Henderson     gen_helper_raise_exception(tcg_env, tcg_constant_i32(nr));
266322f244aSLaurent Vivier }
267322f244aSLaurent Vivier 
gen_raise_exception_format2(DisasContext * s,int nr,target_ulong this_pc)2688115fc93SRichard Henderson static void gen_raise_exception_format2(DisasContext *s, int nr,
2698115fc93SRichard Henderson                                         target_ulong this_pc)
2708115fc93SRichard Henderson {
2718115fc93SRichard Henderson     /*
2728115fc93SRichard Henderson      * Pass the address of the insn to the exception handler,
2738115fc93SRichard Henderson      * for recording in the Format $2 (6-word) stack frame.
2748115fc93SRichard Henderson      * Re-use mmu.ar for the purpose, since that's only valid
2758115fc93SRichard Henderson      * after tlb_fill.
2768115fc93SRichard Henderson      */
277ad75a51eSRichard Henderson     tcg_gen_st_i32(tcg_constant_i32(this_pc), tcg_env,
2788115fc93SRichard Henderson                    offsetof(CPUM68KState, mmu.ar));
2798115fc93SRichard Henderson     gen_raise_exception(nr);
2808115fc93SRichard Henderson     s->base.is_jmp = DISAS_NORETURN;
2818115fc93SRichard Henderson }
2828115fc93SRichard Henderson 
gen_exception(DisasContext * s,uint32_t dest,int nr)283322f244aSLaurent Vivier static void gen_exception(DisasContext *s, uint32_t dest, int nr)
284322f244aSLaurent Vivier {
285322f244aSLaurent Vivier     update_cc_op(s);
286322f244aSLaurent Vivier     tcg_gen_movi_i32(QREG_PC, dest);
287322f244aSLaurent Vivier 
288322f244aSLaurent Vivier     gen_raise_exception(nr);
289f83311e4SLaurent Vivier 
290a575cbe0SRichard Henderson     s->base.is_jmp = DISAS_NORETURN;
291f83311e4SLaurent Vivier }
292f83311e4SLaurent Vivier 
gen_addr_fault(DisasContext * s)293f83311e4SLaurent Vivier static inline void gen_addr_fault(DisasContext *s)
294f83311e4SLaurent Vivier {
295a575cbe0SRichard Henderson     gen_exception(s, s->base.pc_next, EXCP_ADDRESS);
296f83311e4SLaurent Vivier }
297f83311e4SLaurent Vivier 
298808d77bcSLucien Murray-Pitts /*
299808d77bcSLucien Murray-Pitts  * Generate a load from the specified address.  Narrow values are
300808d77bcSLucien Murray-Pitts  *  sign extended to full register width.
301808d77bcSLucien Murray-Pitts  */
gen_load(DisasContext * s,int opsize,TCGv addr,int sign,int index)30254e1e0b5SLaurent Vivier static inline TCGv gen_load(DisasContext *s, int opsize, TCGv addr,
30354e1e0b5SLaurent Vivier                             int sign, int index)
304fcf5ef2aSThomas Huth {
305b7a94da9SRichard Henderson     TCGv tmp = tcg_temp_new_i32();
306b7a94da9SRichard Henderson 
307fcf5ef2aSThomas Huth     switch (opsize) {
308fcf5ef2aSThomas Huth     case OS_BYTE:
309fcf5ef2aSThomas Huth     case OS_WORD:
310fcf5ef2aSThomas Huth     case OS_LONG:
311b7a94da9SRichard Henderson         tcg_gen_qemu_ld_tl(tmp, addr, index,
312b7a94da9SRichard Henderson                            opsize | (sign ? MO_SIGN : 0) | MO_TE);
313fcf5ef2aSThomas Huth         break;
314fcf5ef2aSThomas Huth     default:
315fcf5ef2aSThomas Huth         g_assert_not_reached();
316fcf5ef2aSThomas Huth     }
317fcf5ef2aSThomas Huth     return tmp;
318fcf5ef2aSThomas Huth }
319fcf5ef2aSThomas Huth 
320fcf5ef2aSThomas Huth /* Generate a store.  */
gen_store(DisasContext * s,int opsize,TCGv addr,TCGv val,int index)32154e1e0b5SLaurent Vivier static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val,
32254e1e0b5SLaurent Vivier                              int index)
323fcf5ef2aSThomas Huth {
324fcf5ef2aSThomas Huth     switch (opsize) {
325fcf5ef2aSThomas Huth     case OS_BYTE:
326fcf5ef2aSThomas Huth     case OS_WORD:
327fcf5ef2aSThomas Huth     case OS_LONG:
328b7a94da9SRichard Henderson         tcg_gen_qemu_st_tl(val, addr, index, opsize | MO_TE);
329fcf5ef2aSThomas Huth         break;
330fcf5ef2aSThomas Huth     default:
331fcf5ef2aSThomas Huth         g_assert_not_reached();
332fcf5ef2aSThomas Huth     }
333fcf5ef2aSThomas Huth }
334fcf5ef2aSThomas Huth 
335fcf5ef2aSThomas Huth typedef enum {
336fcf5ef2aSThomas Huth     EA_STORE,
337fcf5ef2aSThomas Huth     EA_LOADU,
338fcf5ef2aSThomas Huth     EA_LOADS
339fcf5ef2aSThomas Huth } ea_what;
340fcf5ef2aSThomas Huth 
341808d77bcSLucien Murray-Pitts /*
342808d77bcSLucien Murray-Pitts  * Generate an unsigned load if VAL is 0 a signed load if val is -1,
343808d77bcSLucien Murray-Pitts  * otherwise generate a store.
344808d77bcSLucien Murray-Pitts  */
gen_ldst(DisasContext * s,int opsize,TCGv addr,TCGv val,ea_what what,int index)345fcf5ef2aSThomas Huth static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
34654e1e0b5SLaurent Vivier                      ea_what what, int index)
347fcf5ef2aSThomas Huth {
348fcf5ef2aSThomas Huth     if (what == EA_STORE) {
34954e1e0b5SLaurent Vivier         gen_store(s, opsize, addr, val, index);
350fcf5ef2aSThomas Huth         return store_dummy;
351fcf5ef2aSThomas Huth     } else {
35254dc8d2fSRichard Henderson         return gen_load(s, opsize, addr, what == EA_LOADS, index);
353fcf5ef2aSThomas Huth     }
354fcf5ef2aSThomas Huth }
355fcf5ef2aSThomas Huth 
356fcf5ef2aSThomas Huth /* Read a 16-bit immediate constant */
read_im16(CPUM68KState * env,DisasContext * s)357fcf5ef2aSThomas Huth static inline uint16_t read_im16(CPUM68KState *env, DisasContext *s)
358fcf5ef2aSThomas Huth {
359fcf5ef2aSThomas Huth     uint16_t im;
3604e116893SIlya Leoshkevich     im = translator_lduw(env, &s->base, s->pc);
361fcf5ef2aSThomas Huth     s->pc += 2;
362fcf5ef2aSThomas Huth     return im;
363fcf5ef2aSThomas Huth }
364fcf5ef2aSThomas Huth 
365fcf5ef2aSThomas Huth /* Read an 8-bit immediate constant */
read_im8(CPUM68KState * env,DisasContext * s)366fcf5ef2aSThomas Huth static inline uint8_t read_im8(CPUM68KState *env, DisasContext *s)
367fcf5ef2aSThomas Huth {
368fcf5ef2aSThomas Huth     return read_im16(env, s);
369fcf5ef2aSThomas Huth }
370fcf5ef2aSThomas Huth 
371fcf5ef2aSThomas Huth /* Read a 32-bit immediate constant.  */
read_im32(CPUM68KState * env,DisasContext * s)372fcf5ef2aSThomas Huth static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s)
373fcf5ef2aSThomas Huth {
374fcf5ef2aSThomas Huth     uint32_t im;
375fcf5ef2aSThomas Huth     im = read_im16(env, s) << 16;
376fcf5ef2aSThomas Huth     im |= 0xffff & read_im16(env, s);
377fcf5ef2aSThomas Huth     return im;
378fcf5ef2aSThomas Huth }
379fcf5ef2aSThomas Huth 
380f83311e4SLaurent Vivier /* Read a 64-bit immediate constant.  */
read_im64(CPUM68KState * env,DisasContext * s)381f83311e4SLaurent Vivier static inline uint64_t read_im64(CPUM68KState *env, DisasContext *s)
382f83311e4SLaurent Vivier {
383f83311e4SLaurent Vivier     uint64_t im;
384f83311e4SLaurent Vivier     im = (uint64_t)read_im32(env, s) << 32;
385f83311e4SLaurent Vivier     im |= (uint64_t)read_im32(env, s);
386f83311e4SLaurent Vivier     return im;
387f83311e4SLaurent Vivier }
388f83311e4SLaurent Vivier 
389fcf5ef2aSThomas Huth /* Calculate and address index.  */
gen_addr_index(DisasContext * s,uint16_t ext,TCGv tmp)3908a1e52b6SRichard Henderson static TCGv gen_addr_index(DisasContext *s, uint16_t ext, TCGv tmp)
391fcf5ef2aSThomas Huth {
392fcf5ef2aSThomas Huth     TCGv add;
393fcf5ef2aSThomas Huth     int scale;
394fcf5ef2aSThomas Huth 
395fcf5ef2aSThomas Huth     add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
396fcf5ef2aSThomas Huth     if ((ext & 0x800) == 0) {
397fcf5ef2aSThomas Huth         tcg_gen_ext16s_i32(tmp, add);
398fcf5ef2aSThomas Huth         add = tmp;
399fcf5ef2aSThomas Huth     }
400fcf5ef2aSThomas Huth     scale = (ext >> 9) & 3;
401fcf5ef2aSThomas Huth     if (scale != 0) {
402fcf5ef2aSThomas Huth         tcg_gen_shli_i32(tmp, add, scale);
403fcf5ef2aSThomas Huth         add = tmp;
404fcf5ef2aSThomas Huth     }
405fcf5ef2aSThomas Huth     return add;
406fcf5ef2aSThomas Huth }
407fcf5ef2aSThomas Huth 
408808d77bcSLucien Murray-Pitts /*
409ce00ff72Szhaolichang  * Handle a base + index + displacement effective address.
410808d77bcSLucien Murray-Pitts  * A NULL_QREG base means pc-relative.
411808d77bcSLucien Murray-Pitts  */
gen_lea_indexed(CPUM68KState * env,DisasContext * s,TCGv base)412fcf5ef2aSThomas Huth static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
413fcf5ef2aSThomas Huth {
414fcf5ef2aSThomas Huth     uint32_t offset;
415fcf5ef2aSThomas Huth     uint16_t ext;
416fcf5ef2aSThomas Huth     TCGv add;
417fcf5ef2aSThomas Huth     TCGv tmp;
418fcf5ef2aSThomas Huth     uint32_t bd, od;
419fcf5ef2aSThomas Huth 
420fcf5ef2aSThomas Huth     offset = s->pc;
421fcf5ef2aSThomas Huth     ext = read_im16(env, s);
422fcf5ef2aSThomas Huth 
423fcf5ef2aSThomas Huth     if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
424fcf5ef2aSThomas Huth         return NULL_QREG;
425fcf5ef2aSThomas Huth 
426aece90d8SMark Cave-Ayland     if (m68k_feature(s->env, M68K_FEATURE_M68K) &&
427fcf5ef2aSThomas Huth         !m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX)) {
428fcf5ef2aSThomas Huth         ext &= ~(3 << 9);
429fcf5ef2aSThomas Huth     }
430fcf5ef2aSThomas Huth 
431fcf5ef2aSThomas Huth     if (ext & 0x100) {
432fcf5ef2aSThomas Huth         /* full extension word format */
433fcf5ef2aSThomas Huth         if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
434fcf5ef2aSThomas Huth             return NULL_QREG;
435fcf5ef2aSThomas Huth 
436fcf5ef2aSThomas Huth         if ((ext & 0x30) > 0x10) {
437fcf5ef2aSThomas Huth             /* base displacement */
438fcf5ef2aSThomas Huth             if ((ext & 0x30) == 0x20) {
439fcf5ef2aSThomas Huth                 bd = (int16_t)read_im16(env, s);
440fcf5ef2aSThomas Huth             } else {
441fcf5ef2aSThomas Huth                 bd = read_im32(env, s);
442fcf5ef2aSThomas Huth             }
443fcf5ef2aSThomas Huth         } else {
444fcf5ef2aSThomas Huth             bd = 0;
445fcf5ef2aSThomas Huth         }
44654dc8d2fSRichard Henderson         tmp = tcg_temp_new();
447fcf5ef2aSThomas Huth         if ((ext & 0x44) == 0) {
448fcf5ef2aSThomas Huth             /* pre-index */
4498a1e52b6SRichard Henderson             add = gen_addr_index(s, ext, tmp);
450fcf5ef2aSThomas Huth         } else {
451fcf5ef2aSThomas Huth             add = NULL_QREG;
452fcf5ef2aSThomas Huth         }
453fcf5ef2aSThomas Huth         if ((ext & 0x80) == 0) {
454fcf5ef2aSThomas Huth             /* base not suppressed */
455fcf5ef2aSThomas Huth             if (IS_NULL_QREG(base)) {
4561852ce5aSRichard Henderson                 base = tcg_constant_i32(offset + bd);
457fcf5ef2aSThomas Huth                 bd = 0;
458fcf5ef2aSThomas Huth             }
459fcf5ef2aSThomas Huth             if (!IS_NULL_QREG(add)) {
460fcf5ef2aSThomas Huth                 tcg_gen_add_i32(tmp, add, base);
461fcf5ef2aSThomas Huth                 add = tmp;
462fcf5ef2aSThomas Huth             } else {
463fcf5ef2aSThomas Huth                 add = base;
464fcf5ef2aSThomas Huth             }
465fcf5ef2aSThomas Huth         }
466fcf5ef2aSThomas Huth         if (!IS_NULL_QREG(add)) {
467fcf5ef2aSThomas Huth             if (bd != 0) {
468fcf5ef2aSThomas Huth                 tcg_gen_addi_i32(tmp, add, bd);
469fcf5ef2aSThomas Huth                 add = tmp;
470fcf5ef2aSThomas Huth             }
471fcf5ef2aSThomas Huth         } else {
4721852ce5aSRichard Henderson             add = tcg_constant_i32(bd);
473fcf5ef2aSThomas Huth         }
474fcf5ef2aSThomas Huth         if ((ext & 3) != 0) {
475fcf5ef2aSThomas Huth             /* memory indirect */
47654dc8d2fSRichard Henderson             base = gen_load(s, OS_LONG, add, 0, IS_USER(s));
477fcf5ef2aSThomas Huth             if ((ext & 0x44) == 4) {
4788a1e52b6SRichard Henderson                 add = gen_addr_index(s, ext, tmp);
479fcf5ef2aSThomas Huth                 tcg_gen_add_i32(tmp, add, base);
480fcf5ef2aSThomas Huth                 add = tmp;
481fcf5ef2aSThomas Huth             } else {
482fcf5ef2aSThomas Huth                 add = base;
483fcf5ef2aSThomas Huth             }
484fcf5ef2aSThomas Huth             if ((ext & 3) > 1) {
485fcf5ef2aSThomas Huth                 /* outer displacement */
486fcf5ef2aSThomas Huth                 if ((ext & 3) == 2) {
487fcf5ef2aSThomas Huth                     od = (int16_t)read_im16(env, s);
488fcf5ef2aSThomas Huth                 } else {
489fcf5ef2aSThomas Huth                     od = read_im32(env, s);
490fcf5ef2aSThomas Huth                 }
491fcf5ef2aSThomas Huth             } else {
492fcf5ef2aSThomas Huth                 od = 0;
493fcf5ef2aSThomas Huth             }
494fcf5ef2aSThomas Huth             if (od != 0) {
495fcf5ef2aSThomas Huth                 tcg_gen_addi_i32(tmp, add, od);
496fcf5ef2aSThomas Huth                 add = tmp;
497fcf5ef2aSThomas Huth             }
498fcf5ef2aSThomas Huth         }
499fcf5ef2aSThomas Huth     } else {
500fcf5ef2aSThomas Huth         /* brief extension word format */
50154dc8d2fSRichard Henderson         tmp = tcg_temp_new();
5028a1e52b6SRichard Henderson         add = gen_addr_index(s, ext, tmp);
503fcf5ef2aSThomas Huth         if (!IS_NULL_QREG(base)) {
504fcf5ef2aSThomas Huth             tcg_gen_add_i32(tmp, add, base);
505fcf5ef2aSThomas Huth             if ((int8_t)ext)
506fcf5ef2aSThomas Huth                 tcg_gen_addi_i32(tmp, tmp, (int8_t)ext);
507fcf5ef2aSThomas Huth         } else {
508fcf5ef2aSThomas Huth             tcg_gen_addi_i32(tmp, add, offset + (int8_t)ext);
509fcf5ef2aSThomas Huth         }
510fcf5ef2aSThomas Huth         add = tmp;
511fcf5ef2aSThomas Huth     }
512fcf5ef2aSThomas Huth     return add;
513fcf5ef2aSThomas Huth }
514fcf5ef2aSThomas Huth 
515fcf5ef2aSThomas Huth /* Sign or zero extend a value.  */
516fcf5ef2aSThomas Huth 
gen_ext(TCGv res,TCGv val,int opsize,int sign)517fcf5ef2aSThomas Huth static inline void gen_ext(TCGv res, TCGv val, int opsize, int sign)
518fcf5ef2aSThomas Huth {
519fcf5ef2aSThomas Huth     switch (opsize) {
520fcf5ef2aSThomas Huth     case OS_BYTE:
521fcf5ef2aSThomas Huth     case OS_WORD:
522fcf5ef2aSThomas Huth     case OS_LONG:
523443025e4SRichard Henderson         tcg_gen_ext_i32(res, val, opsize | (sign ? MO_SIGN : 0));
524fcf5ef2aSThomas Huth         break;
525fcf5ef2aSThomas Huth     default:
526fcf5ef2aSThomas Huth         g_assert_not_reached();
527fcf5ef2aSThomas Huth     }
528fcf5ef2aSThomas Huth }
529fcf5ef2aSThomas Huth 
530fcf5ef2aSThomas Huth /* Evaluate all the CC flags.  */
531fcf5ef2aSThomas Huth 
gen_flush_flags(DisasContext * s)532fcf5ef2aSThomas Huth static void gen_flush_flags(DisasContext *s)
533fcf5ef2aSThomas Huth {
534fcf5ef2aSThomas Huth     TCGv t0, t1;
535fcf5ef2aSThomas Huth 
536fcf5ef2aSThomas Huth     switch (s->cc_op) {
537fcf5ef2aSThomas Huth     case CC_OP_FLAGS:
538fcf5ef2aSThomas Huth         return;
539fcf5ef2aSThomas Huth 
540fcf5ef2aSThomas Huth     case CC_OP_ADDB:
541fcf5ef2aSThomas Huth     case CC_OP_ADDW:
542fcf5ef2aSThomas Huth     case CC_OP_ADDL:
543fcf5ef2aSThomas Huth         tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
544fcf5ef2aSThomas Huth         tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
545fcf5ef2aSThomas Huth         /* Compute signed overflow for addition.  */
546fcf5ef2aSThomas Huth         t0 = tcg_temp_new();
547fcf5ef2aSThomas Huth         t1 = tcg_temp_new();
548fcf5ef2aSThomas Huth         tcg_gen_sub_i32(t0, QREG_CC_N, QREG_CC_V);
549fcf5ef2aSThomas Huth         gen_ext(t0, t0, s->cc_op - CC_OP_ADDB, 1);
550fcf5ef2aSThomas Huth         tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V);
551fcf5ef2aSThomas Huth         tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
552fcf5ef2aSThomas Huth         tcg_gen_andc_i32(QREG_CC_V, t1, QREG_CC_V);
553fcf5ef2aSThomas Huth         break;
554fcf5ef2aSThomas Huth 
555fcf5ef2aSThomas Huth     case CC_OP_SUBB:
556fcf5ef2aSThomas Huth     case CC_OP_SUBW:
557fcf5ef2aSThomas Huth     case CC_OP_SUBL:
558fcf5ef2aSThomas Huth         tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
559fcf5ef2aSThomas Huth         tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
560fcf5ef2aSThomas Huth         /* Compute signed overflow for subtraction.  */
561fcf5ef2aSThomas Huth         t0 = tcg_temp_new();
562fcf5ef2aSThomas Huth         t1 = tcg_temp_new();
563fcf5ef2aSThomas Huth         tcg_gen_add_i32(t0, QREG_CC_N, QREG_CC_V);
564fcf5ef2aSThomas Huth         gen_ext(t0, t0, s->cc_op - CC_OP_SUBB, 1);
565043b936eSLaurent Vivier         tcg_gen_xor_i32(t1, QREG_CC_N, t0);
566fcf5ef2aSThomas Huth         tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
567fcf5ef2aSThomas Huth         tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t1);
568fcf5ef2aSThomas Huth         break;
569fcf5ef2aSThomas Huth 
570fcf5ef2aSThomas Huth     case CC_OP_CMPB:
571fcf5ef2aSThomas Huth     case CC_OP_CMPW:
572fcf5ef2aSThomas Huth     case CC_OP_CMPL:
573fcf5ef2aSThomas Huth         tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_C, QREG_CC_N, QREG_CC_V);
574fcf5ef2aSThomas Huth         tcg_gen_sub_i32(QREG_CC_Z, QREG_CC_N, QREG_CC_V);
575fcf5ef2aSThomas Huth         gen_ext(QREG_CC_Z, QREG_CC_Z, s->cc_op - CC_OP_CMPB, 1);
576fcf5ef2aSThomas Huth         /* Compute signed overflow for subtraction.  */
577fcf5ef2aSThomas Huth         t0 = tcg_temp_new();
578fcf5ef2aSThomas Huth         tcg_gen_xor_i32(t0, QREG_CC_Z, QREG_CC_N);
579fcf5ef2aSThomas Huth         tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, QREG_CC_N);
580fcf5ef2aSThomas Huth         tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t0);
581fcf5ef2aSThomas Huth         tcg_gen_mov_i32(QREG_CC_N, QREG_CC_Z);
582fcf5ef2aSThomas Huth         break;
583fcf5ef2aSThomas Huth 
584fcf5ef2aSThomas Huth     case CC_OP_LOGIC:
585fcf5ef2aSThomas Huth         tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
586fcf5ef2aSThomas Huth         tcg_gen_movi_i32(QREG_CC_C, 0);
587fcf5ef2aSThomas Huth         tcg_gen_movi_i32(QREG_CC_V, 0);
588fcf5ef2aSThomas Huth         break;
589fcf5ef2aSThomas Huth 
590fcf5ef2aSThomas Huth     case CC_OP_DYNAMIC:
591ad75a51eSRichard Henderson         gen_helper_flush_flags(tcg_env, QREG_CC_OP);
592695576dbSLaurent Vivier         s->cc_op_synced = 1;
593fcf5ef2aSThomas Huth         break;
594fcf5ef2aSThomas Huth 
595fcf5ef2aSThomas Huth     default:
596ad75a51eSRichard Henderson         gen_helper_flush_flags(tcg_env, tcg_constant_i32(s->cc_op));
597695576dbSLaurent Vivier         s->cc_op_synced = 1;
598fcf5ef2aSThomas Huth         break;
599fcf5ef2aSThomas Huth     }
600fcf5ef2aSThomas Huth 
601fcf5ef2aSThomas Huth     /* Note that flush_flags also assigned to env->cc_op.  */
602fcf5ef2aSThomas Huth     s->cc_op = CC_OP_FLAGS;
603fcf5ef2aSThomas Huth }
604fcf5ef2aSThomas Huth 
gen_extend(DisasContext * s,TCGv val,int opsize,int sign)6053f215a14SLaurent Vivier static inline TCGv gen_extend(DisasContext *s, TCGv val, int opsize, int sign)
606fcf5ef2aSThomas Huth {
607fcf5ef2aSThomas Huth     TCGv tmp;
608fcf5ef2aSThomas Huth 
609fcf5ef2aSThomas Huth     if (opsize == OS_LONG) {
610fcf5ef2aSThomas Huth         tmp = val;
611fcf5ef2aSThomas Huth     } else {
61254dc8d2fSRichard Henderson         tmp = tcg_temp_new();
613fcf5ef2aSThomas Huth         gen_ext(tmp, val, opsize, sign);
614fcf5ef2aSThomas Huth     }
615fcf5ef2aSThomas Huth 
616fcf5ef2aSThomas Huth     return tmp;
617fcf5ef2aSThomas Huth }
618fcf5ef2aSThomas Huth 
gen_logic_cc(DisasContext * s,TCGv val,int opsize)619fcf5ef2aSThomas Huth static void gen_logic_cc(DisasContext *s, TCGv val, int opsize)
620fcf5ef2aSThomas Huth {
621fcf5ef2aSThomas Huth     gen_ext(QREG_CC_N, val, opsize, 1);
622fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_LOGIC);
623fcf5ef2aSThomas Huth }
624fcf5ef2aSThomas Huth 
gen_update_cc_cmp(DisasContext * s,TCGv dest,TCGv src,int opsize)625fcf5ef2aSThomas Huth static void gen_update_cc_cmp(DisasContext *s, TCGv dest, TCGv src, int opsize)
626fcf5ef2aSThomas Huth {
627fcf5ef2aSThomas Huth     tcg_gen_mov_i32(QREG_CC_N, dest);
628fcf5ef2aSThomas Huth     tcg_gen_mov_i32(QREG_CC_V, src);
629fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_CMPB + opsize);
630fcf5ef2aSThomas Huth }
631fcf5ef2aSThomas Huth 
gen_update_cc_add(TCGv dest,TCGv src,int opsize)632fcf5ef2aSThomas Huth static void gen_update_cc_add(TCGv dest, TCGv src, int opsize)
633fcf5ef2aSThomas Huth {
634fcf5ef2aSThomas Huth     gen_ext(QREG_CC_N, dest, opsize, 1);
635fcf5ef2aSThomas Huth     tcg_gen_mov_i32(QREG_CC_V, src);
636fcf5ef2aSThomas Huth }
637fcf5ef2aSThomas Huth 
opsize_bytes(int opsize)638fcf5ef2aSThomas Huth static inline int opsize_bytes(int opsize)
639fcf5ef2aSThomas Huth {
640fcf5ef2aSThomas Huth     switch (opsize) {
641fcf5ef2aSThomas Huth     case OS_BYTE: return 1;
642fcf5ef2aSThomas Huth     case OS_WORD: return 2;
643fcf5ef2aSThomas Huth     case OS_LONG: return 4;
644fcf5ef2aSThomas Huth     case OS_SINGLE: return 4;
645fcf5ef2aSThomas Huth     case OS_DOUBLE: return 8;
646fcf5ef2aSThomas Huth     case OS_EXTENDED: return 12;
647fcf5ef2aSThomas Huth     case OS_PACKED: return 12;
648fcf5ef2aSThomas Huth     default:
649fcf5ef2aSThomas Huth         g_assert_not_reached();
650fcf5ef2aSThomas Huth     }
651fcf5ef2aSThomas Huth }
652fcf5ef2aSThomas Huth 
insn_opsize(int insn)653fcf5ef2aSThomas Huth static inline int insn_opsize(int insn)
654fcf5ef2aSThomas Huth {
655fcf5ef2aSThomas Huth     switch ((insn >> 6) & 3) {
656fcf5ef2aSThomas Huth     case 0: return OS_BYTE;
657fcf5ef2aSThomas Huth     case 1: return OS_WORD;
658fcf5ef2aSThomas Huth     case 2: return OS_LONG;
659fcf5ef2aSThomas Huth     default:
660fcf5ef2aSThomas Huth         g_assert_not_reached();
661fcf5ef2aSThomas Huth     }
662fcf5ef2aSThomas Huth }
663fcf5ef2aSThomas Huth 
ext_opsize(int ext,int pos)66469e69822SLaurent Vivier static inline int ext_opsize(int ext, int pos)
66569e69822SLaurent Vivier {
66669e69822SLaurent Vivier     switch ((ext >> pos) & 7) {
66769e69822SLaurent Vivier     case 0: return OS_LONG;
66869e69822SLaurent Vivier     case 1: return OS_SINGLE;
66969e69822SLaurent Vivier     case 2: return OS_EXTENDED;
67069e69822SLaurent Vivier     case 3: return OS_PACKED;
67169e69822SLaurent Vivier     case 4: return OS_WORD;
67269e69822SLaurent Vivier     case 5: return OS_DOUBLE;
67369e69822SLaurent Vivier     case 6: return OS_BYTE;
67469e69822SLaurent Vivier     default:
67569e69822SLaurent Vivier         g_assert_not_reached();
67669e69822SLaurent Vivier     }
67769e69822SLaurent Vivier }
67869e69822SLaurent Vivier 
679808d77bcSLucien Murray-Pitts /*
680808d77bcSLucien Murray-Pitts  * Assign value to a register.  If the width is less than the register width
681808d77bcSLucien Murray-Pitts  * only the low part of the register is set.
682808d77bcSLucien Murray-Pitts  */
gen_partset_reg(int opsize,TCGv reg,TCGv val)683fcf5ef2aSThomas Huth static void gen_partset_reg(int opsize, TCGv reg, TCGv val)
684fcf5ef2aSThomas Huth {
685fcf5ef2aSThomas Huth     switch (opsize) {
686fcf5ef2aSThomas Huth     case OS_BYTE:
68764919f71SRichard Henderson         tcg_gen_deposit_i32(reg, reg, val, 0, 8);
688fcf5ef2aSThomas Huth         break;
689fcf5ef2aSThomas Huth     case OS_WORD:
69064919f71SRichard Henderson         tcg_gen_deposit_i32(reg, reg, val, 0, 16);
691fcf5ef2aSThomas Huth         break;
692fcf5ef2aSThomas Huth     case OS_LONG:
693fcf5ef2aSThomas Huth     case OS_SINGLE:
694fcf5ef2aSThomas Huth         tcg_gen_mov_i32(reg, val);
695fcf5ef2aSThomas Huth         break;
696fcf5ef2aSThomas Huth     default:
697fcf5ef2aSThomas Huth         g_assert_not_reached();
698fcf5ef2aSThomas Huth     }
699fcf5ef2aSThomas Huth }
700fcf5ef2aSThomas Huth 
701808d77bcSLucien Murray-Pitts /*
702808d77bcSLucien Murray-Pitts  * Generate code for an "effective address".  Does not adjust the base
703808d77bcSLucien Murray-Pitts  * register for autoincrement addressing modes.
704808d77bcSLucien Murray-Pitts  */
gen_lea_mode(CPUM68KState * env,DisasContext * s,int mode,int reg0,int opsize)705f84aab26SRichard Henderson static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
706f84aab26SRichard Henderson                          int mode, int reg0, int opsize)
707fcf5ef2aSThomas Huth {
708fcf5ef2aSThomas Huth     TCGv reg;
709fcf5ef2aSThomas Huth     TCGv tmp;
710fcf5ef2aSThomas Huth     uint16_t ext;
711fcf5ef2aSThomas Huth     uint32_t offset;
712fcf5ef2aSThomas Huth 
713f84aab26SRichard Henderson     switch (mode) {
714fcf5ef2aSThomas Huth     case 0: /* Data register direct.  */
715fcf5ef2aSThomas Huth     case 1: /* Address register direct.  */
716fcf5ef2aSThomas Huth         return NULL_QREG;
717fcf5ef2aSThomas Huth     case 3: /* Indirect postincrement.  */
718f2224f2cSRichard Henderson         if (opsize == OS_UNSIZED) {
719f2224f2cSRichard Henderson             return NULL_QREG;
720f2224f2cSRichard Henderson         }
721f2224f2cSRichard Henderson         /* fallthru */
722f2224f2cSRichard Henderson     case 2: /* Indirect register */
723*a4f9d9a4SRichard Henderson         tmp = tcg_temp_new();
724*a4f9d9a4SRichard Henderson         tcg_gen_mov_i32(tmp, get_areg(s, reg0));
725*a4f9d9a4SRichard Henderson         return tmp;
726fcf5ef2aSThomas Huth     case 4: /* Indirect predecrememnt.  */
727f2224f2cSRichard Henderson         if (opsize == OS_UNSIZED) {
728f2224f2cSRichard Henderson             return NULL_QREG;
729f2224f2cSRichard Henderson         }
730f84aab26SRichard Henderson         reg = get_areg(s, reg0);
73154dc8d2fSRichard Henderson         tmp = tcg_temp_new();
732727d937bSLaurent Vivier         if (reg0 == 7 && opsize == OS_BYTE &&
733aece90d8SMark Cave-Ayland             m68k_feature(s->env, M68K_FEATURE_M68K)) {
734727d937bSLaurent Vivier             tcg_gen_subi_i32(tmp, reg, 2);
735727d937bSLaurent Vivier         } else {
736fcf5ef2aSThomas Huth             tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize));
737727d937bSLaurent Vivier         }
738fcf5ef2aSThomas Huth         return tmp;
739fcf5ef2aSThomas Huth     case 5: /* Indirect displacement.  */
740f84aab26SRichard Henderson         reg = get_areg(s, reg0);
74154dc8d2fSRichard Henderson         tmp = tcg_temp_new();
742fcf5ef2aSThomas Huth         ext = read_im16(env, s);
743fcf5ef2aSThomas Huth         tcg_gen_addi_i32(tmp, reg, (int16_t)ext);
744fcf5ef2aSThomas Huth         return tmp;
745fcf5ef2aSThomas Huth     case 6: /* Indirect index + displacement.  */
746f84aab26SRichard Henderson         reg = get_areg(s, reg0);
747fcf5ef2aSThomas Huth         return gen_lea_indexed(env, s, reg);
748fcf5ef2aSThomas Huth     case 7: /* Other */
749f84aab26SRichard Henderson         switch (reg0) {
750fcf5ef2aSThomas Huth         case 0: /* Absolute short.  */
751fcf5ef2aSThomas Huth             offset = (int16_t)read_im16(env, s);
752*a4f9d9a4SRichard Henderson             break;
753fcf5ef2aSThomas Huth         case 1: /* Absolute long.  */
754fcf5ef2aSThomas Huth             offset = read_im32(env, s);
755*a4f9d9a4SRichard Henderson             break;
756fcf5ef2aSThomas Huth         case 2: /* pc displacement  */
757fcf5ef2aSThomas Huth             offset = s->pc;
758fcf5ef2aSThomas Huth             offset += (int16_t)read_im16(env, s);
759*a4f9d9a4SRichard Henderson             break;
760fcf5ef2aSThomas Huth         case 3: /* pc index+displacement.  */
761fcf5ef2aSThomas Huth             return gen_lea_indexed(env, s, NULL_QREG);
762fcf5ef2aSThomas Huth         case 4: /* Immediate.  */
763fcf5ef2aSThomas Huth         default:
764fcf5ef2aSThomas Huth             return NULL_QREG;
765fcf5ef2aSThomas Huth         }
766*a4f9d9a4SRichard Henderson         tmp = tcg_temp_new();
767*a4f9d9a4SRichard Henderson         tcg_gen_movi_i32(tmp, offset);
768*a4f9d9a4SRichard Henderson         return tmp;
769fcf5ef2aSThomas Huth     }
770fcf5ef2aSThomas Huth     /* Should never happen.  */
771fcf5ef2aSThomas Huth     return NULL_QREG;
772fcf5ef2aSThomas Huth }
773fcf5ef2aSThomas Huth 
gen_lea(CPUM68KState * env,DisasContext * s,uint16_t insn,int opsize)774f84aab26SRichard Henderson static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn,
775f84aab26SRichard Henderson                     int opsize)
776fcf5ef2aSThomas Huth {
777f84aab26SRichard Henderson     int mode = extract32(insn, 3, 3);
778f84aab26SRichard Henderson     int reg0 = REG(insn, 0);
779f84aab26SRichard Henderson     return gen_lea_mode(env, s, mode, reg0, opsize);
780fcf5ef2aSThomas Huth }
781fcf5ef2aSThomas Huth 
782808d77bcSLucien Murray-Pitts /*
783808d77bcSLucien Murray-Pitts  * Generate code to load/store a value from/into an EA.  If WHAT > 0 this is
784808d77bcSLucien Murray-Pitts  * a write otherwise it is a read (0 == sign extend, -1 == zero extend).
785808d77bcSLucien Murray-Pitts  * ADDRP is non-null for readwrite operands.
786808d77bcSLucien Murray-Pitts  */
gen_ea_mode(CPUM68KState * env,DisasContext * s,int mode,int reg0,int opsize,TCGv val,TCGv * addrp,ea_what what,int index)787f84aab26SRichard Henderson static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0,
78854e1e0b5SLaurent Vivier                         int opsize, TCGv val, TCGv *addrp, ea_what what,
78954e1e0b5SLaurent Vivier                         int index)
790fcf5ef2aSThomas Huth {
791f84aab26SRichard Henderson     TCGv reg, tmp, result;
792f84aab26SRichard Henderson     int32_t offset;
793fcf5ef2aSThomas Huth 
794f84aab26SRichard Henderson     switch (mode) {
795fcf5ef2aSThomas Huth     case 0: /* Data register direct.  */
796f84aab26SRichard Henderson         reg = cpu_dregs[reg0];
797fcf5ef2aSThomas Huth         if (what == EA_STORE) {
798fcf5ef2aSThomas Huth             gen_partset_reg(opsize, reg, val);
799fcf5ef2aSThomas Huth             return store_dummy;
800fcf5ef2aSThomas Huth         } else {
8013f215a14SLaurent Vivier             return gen_extend(s, reg, opsize, what == EA_LOADS);
802fcf5ef2aSThomas Huth         }
803fcf5ef2aSThomas Huth     case 1: /* Address register direct.  */
804f84aab26SRichard Henderson         reg = get_areg(s, reg0);
805fcf5ef2aSThomas Huth         if (what == EA_STORE) {
806fcf5ef2aSThomas Huth             tcg_gen_mov_i32(reg, val);
807fcf5ef2aSThomas Huth             return store_dummy;
808fcf5ef2aSThomas Huth         } else {
8093f215a14SLaurent Vivier             return gen_extend(s, reg, opsize, what == EA_LOADS);
810fcf5ef2aSThomas Huth         }
811fcf5ef2aSThomas Huth     case 2: /* Indirect register */
812f84aab26SRichard Henderson         reg = get_areg(s, reg0);
81354e1e0b5SLaurent Vivier         return gen_ldst(s, opsize, reg, val, what, index);
814fcf5ef2aSThomas Huth     case 3: /* Indirect postincrement.  */
815f84aab26SRichard Henderson         reg = get_areg(s, reg0);
81654e1e0b5SLaurent Vivier         result = gen_ldst(s, opsize, reg, val, what, index);
8178a1e52b6SRichard Henderson         if (what == EA_STORE || !addrp) {
818574d5725SPhilippe Mathieu-Daudé             tmp = tcg_temp_new();
819727d937bSLaurent Vivier             if (reg0 == 7 && opsize == OS_BYTE &&
820aece90d8SMark Cave-Ayland                 m68k_feature(s->env, M68K_FEATURE_M68K)) {
821727d937bSLaurent Vivier                 tcg_gen_addi_i32(tmp, reg, 2);
822727d937bSLaurent Vivier             } else {
8238a1e52b6SRichard Henderson                 tcg_gen_addi_i32(tmp, reg, opsize_bytes(opsize));
824727d937bSLaurent Vivier             }
825f84aab26SRichard Henderson             delay_set_areg(s, reg0, tmp, true);
8268a1e52b6SRichard Henderson         }
827fcf5ef2aSThomas Huth         return result;
828fcf5ef2aSThomas Huth     case 4: /* Indirect predecrememnt.  */
829fcf5ef2aSThomas Huth         if (addrp && what == EA_STORE) {
830fcf5ef2aSThomas Huth             tmp = *addrp;
831fcf5ef2aSThomas Huth         } else {
832f84aab26SRichard Henderson             tmp = gen_lea_mode(env, s, mode, reg0, opsize);
833f84aab26SRichard Henderson             if (IS_NULL_QREG(tmp)) {
834fcf5ef2aSThomas Huth                 return tmp;
835f84aab26SRichard Henderson             }
836f84aab26SRichard Henderson             if (addrp) {
837fcf5ef2aSThomas Huth                 *addrp = tmp;
838fcf5ef2aSThomas Huth             }
839f84aab26SRichard Henderson         }
84054e1e0b5SLaurent Vivier         result = gen_ldst(s, opsize, tmp, val, what, index);
841fcf5ef2aSThomas Huth         if (what == EA_STORE || !addrp) {
842f84aab26SRichard Henderson             delay_set_areg(s, reg0, tmp, false);
843fcf5ef2aSThomas Huth         }
844fcf5ef2aSThomas Huth         return result;
845fcf5ef2aSThomas Huth     case 5: /* Indirect displacement.  */
846fcf5ef2aSThomas Huth     case 6: /* Indirect index + displacement.  */
847f84aab26SRichard Henderson     do_indirect:
848f84aab26SRichard Henderson         if (addrp && what == EA_STORE) {
849f84aab26SRichard Henderson             tmp = *addrp;
850f84aab26SRichard Henderson         } else {
851f84aab26SRichard Henderson             tmp = gen_lea_mode(env, s, mode, reg0, opsize);
852f84aab26SRichard Henderson             if (IS_NULL_QREG(tmp)) {
853f84aab26SRichard Henderson                 return tmp;
854f84aab26SRichard Henderson             }
855f84aab26SRichard Henderson             if (addrp) {
856f84aab26SRichard Henderson                 *addrp = tmp;
857f84aab26SRichard Henderson             }
858f84aab26SRichard Henderson         }
85954e1e0b5SLaurent Vivier         return gen_ldst(s, opsize, tmp, val, what, index);
860fcf5ef2aSThomas Huth     case 7: /* Other */
861f84aab26SRichard Henderson         switch (reg0) {
862fcf5ef2aSThomas Huth         case 0: /* Absolute short.  */
863fcf5ef2aSThomas Huth         case 1: /* Absolute long.  */
864fcf5ef2aSThomas Huth         case 2: /* pc displacement  */
865fcf5ef2aSThomas Huth         case 3: /* pc index+displacement.  */
866f84aab26SRichard Henderson             goto do_indirect;
867fcf5ef2aSThomas Huth         case 4: /* Immediate.  */
868fcf5ef2aSThomas Huth             /* Sign extend values for consistency.  */
869fcf5ef2aSThomas Huth             switch (opsize) {
870fcf5ef2aSThomas Huth             case OS_BYTE:
871fcf5ef2aSThomas Huth                 if (what == EA_LOADS) {
872fcf5ef2aSThomas Huth                     offset = (int8_t)read_im8(env, s);
873fcf5ef2aSThomas Huth                 } else {
874fcf5ef2aSThomas Huth                     offset = read_im8(env, s);
875fcf5ef2aSThomas Huth                 }
876fcf5ef2aSThomas Huth                 break;
877fcf5ef2aSThomas Huth             case OS_WORD:
878fcf5ef2aSThomas Huth                 if (what == EA_LOADS) {
879fcf5ef2aSThomas Huth                     offset = (int16_t)read_im16(env, s);
880fcf5ef2aSThomas Huth                 } else {
881fcf5ef2aSThomas Huth                     offset = read_im16(env, s);
882fcf5ef2aSThomas Huth                 }
883fcf5ef2aSThomas Huth                 break;
884fcf5ef2aSThomas Huth             case OS_LONG:
885fcf5ef2aSThomas Huth                 offset = read_im32(env, s);
886fcf5ef2aSThomas Huth                 break;
887fcf5ef2aSThomas Huth             default:
888fcf5ef2aSThomas Huth                 g_assert_not_reached();
889fcf5ef2aSThomas Huth             }
890999b7c26SRichard Henderson             return tcg_constant_i32(offset);
891fcf5ef2aSThomas Huth         default:
892fcf5ef2aSThomas Huth             return NULL_QREG;
893fcf5ef2aSThomas Huth         }
894fcf5ef2aSThomas Huth     }
895fcf5ef2aSThomas Huth     /* Should never happen.  */
896fcf5ef2aSThomas Huth     return NULL_QREG;
897fcf5ef2aSThomas Huth }
898fcf5ef2aSThomas Huth 
gen_ea(CPUM68KState * env,DisasContext * s,uint16_t insn,int opsize,TCGv val,TCGv * addrp,ea_what what,int index)899f84aab26SRichard Henderson static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn,
90054e1e0b5SLaurent Vivier                    int opsize, TCGv val, TCGv *addrp, ea_what what, int index)
901f84aab26SRichard Henderson {
902f84aab26SRichard Henderson     int mode = extract32(insn, 3, 3);
903f84aab26SRichard Henderson     int reg0 = REG(insn, 0);
90454e1e0b5SLaurent Vivier     return gen_ea_mode(env, s, mode, reg0, opsize, val, addrp, what, index);
905f84aab26SRichard Henderson }
906f84aab26SRichard Henderson 
gen_fp_ptr(int freg)907f83311e4SLaurent Vivier static TCGv_ptr gen_fp_ptr(int freg)
908f83311e4SLaurent Vivier {
909f83311e4SLaurent Vivier     TCGv_ptr fp = tcg_temp_new_ptr();
910ad75a51eSRichard Henderson     tcg_gen_addi_ptr(fp, tcg_env, offsetof(CPUM68KState, fregs[freg]));
911f83311e4SLaurent Vivier     return fp;
912f83311e4SLaurent Vivier }
913f83311e4SLaurent Vivier 
gen_fp_result_ptr(void)914f83311e4SLaurent Vivier static TCGv_ptr gen_fp_result_ptr(void)
915f83311e4SLaurent Vivier {
916f83311e4SLaurent Vivier     TCGv_ptr fp = tcg_temp_new_ptr();
917ad75a51eSRichard Henderson     tcg_gen_addi_ptr(fp, tcg_env, offsetof(CPUM68KState, fp_result));
918f83311e4SLaurent Vivier     return fp;
919f83311e4SLaurent Vivier }
920f83311e4SLaurent Vivier 
gen_fp_move(TCGv_ptr dest,TCGv_ptr src)921f83311e4SLaurent Vivier static void gen_fp_move(TCGv_ptr dest, TCGv_ptr src)
922f83311e4SLaurent Vivier {
923f83311e4SLaurent Vivier     TCGv t32;
924f83311e4SLaurent Vivier     TCGv_i64 t64;
925f83311e4SLaurent Vivier 
926f83311e4SLaurent Vivier     t32 = tcg_temp_new();
927f83311e4SLaurent Vivier     tcg_gen_ld16u_i32(t32, src, offsetof(FPReg, l.upper));
928f83311e4SLaurent Vivier     tcg_gen_st16_i32(t32, dest, offsetof(FPReg, l.upper));
929f83311e4SLaurent Vivier 
930f83311e4SLaurent Vivier     t64 = tcg_temp_new_i64();
931f83311e4SLaurent Vivier     tcg_gen_ld_i64(t64, src, offsetof(FPReg, l.lower));
932f83311e4SLaurent Vivier     tcg_gen_st_i64(t64, dest, offsetof(FPReg, l.lower));
933f83311e4SLaurent Vivier }
934f83311e4SLaurent Vivier 
gen_load_fp(DisasContext * s,int opsize,TCGv addr,TCGv_ptr fp,int index)93554e1e0b5SLaurent Vivier static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
93654e1e0b5SLaurent Vivier                         int index)
937f83311e4SLaurent Vivier {
938f83311e4SLaurent Vivier     TCGv tmp;
939f83311e4SLaurent Vivier     TCGv_i64 t64;
940f83311e4SLaurent Vivier 
941f83311e4SLaurent Vivier     t64 = tcg_temp_new_i64();
942f83311e4SLaurent Vivier     tmp = tcg_temp_new();
943f83311e4SLaurent Vivier     switch (opsize) {
944f83311e4SLaurent Vivier     case OS_BYTE:
945f83311e4SLaurent Vivier     case OS_WORD:
946a0f06a62SRichard Henderson     case OS_LONG:
947b7a94da9SRichard Henderson         tcg_gen_qemu_ld_tl(tmp, addr, index, opsize | MO_SIGN | MO_TE);
948ad75a51eSRichard Henderson         gen_helper_exts32(tcg_env, fp, tmp);
949f83311e4SLaurent Vivier         break;
950f83311e4SLaurent Vivier     case OS_SINGLE:
951b7a94da9SRichard Henderson         tcg_gen_qemu_ld_tl(tmp, addr, index, MO_TEUL);
952ad75a51eSRichard Henderson         gen_helper_extf32(tcg_env, fp, tmp);
953f83311e4SLaurent Vivier         break;
954f83311e4SLaurent Vivier     case OS_DOUBLE:
955b7a94da9SRichard Henderson         tcg_gen_qemu_ld_i64(t64, addr, index, MO_TEUQ);
956ad75a51eSRichard Henderson         gen_helper_extf64(tcg_env, fp, t64);
957f83311e4SLaurent Vivier         break;
958f83311e4SLaurent Vivier     case OS_EXTENDED:
959f83311e4SLaurent Vivier         if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
960a575cbe0SRichard Henderson             gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
961f83311e4SLaurent Vivier             break;
962f83311e4SLaurent Vivier         }
963b7a94da9SRichard Henderson         tcg_gen_qemu_ld_i32(tmp, addr, index, MO_TEUL);
964f83311e4SLaurent Vivier         tcg_gen_shri_i32(tmp, tmp, 16);
965f83311e4SLaurent Vivier         tcg_gen_st16_i32(tmp, fp, offsetof(FPReg, l.upper));
966f83311e4SLaurent Vivier         tcg_gen_addi_i32(tmp, addr, 4);
967b7a94da9SRichard Henderson         tcg_gen_qemu_ld_i64(t64, tmp, index, MO_TEUQ);
968f83311e4SLaurent Vivier         tcg_gen_st_i64(t64, fp, offsetof(FPReg, l.lower));
969f83311e4SLaurent Vivier         break;
970f83311e4SLaurent Vivier     case OS_PACKED:
971808d77bcSLucien Murray-Pitts         /*
972808d77bcSLucien Murray-Pitts          * unimplemented data type on 68040/ColdFire
973f83311e4SLaurent Vivier          * FIXME if needed for another FPU
974f83311e4SLaurent Vivier          */
975a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
976f83311e4SLaurent Vivier         break;
977f83311e4SLaurent Vivier     default:
978f83311e4SLaurent Vivier         g_assert_not_reached();
979f83311e4SLaurent Vivier     }
980f83311e4SLaurent Vivier }
981f83311e4SLaurent Vivier 
gen_store_fp(DisasContext * s,int opsize,TCGv addr,TCGv_ptr fp,int index)98254e1e0b5SLaurent Vivier static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
98354e1e0b5SLaurent Vivier                          int index)
984f83311e4SLaurent Vivier {
985f83311e4SLaurent Vivier     TCGv tmp;
986f83311e4SLaurent Vivier     TCGv_i64 t64;
987f83311e4SLaurent Vivier 
988f83311e4SLaurent Vivier     t64 = tcg_temp_new_i64();
989f83311e4SLaurent Vivier     tmp = tcg_temp_new();
990f83311e4SLaurent Vivier     switch (opsize) {
991f83311e4SLaurent Vivier     case OS_BYTE:
992f83311e4SLaurent Vivier     case OS_WORD:
993f83311e4SLaurent Vivier     case OS_LONG:
994ad75a51eSRichard Henderson         gen_helper_reds32(tmp, tcg_env, fp);
995b7a94da9SRichard Henderson         tcg_gen_qemu_st_tl(tmp, addr, index, opsize | MO_TE);
996f83311e4SLaurent Vivier         break;
997f83311e4SLaurent Vivier     case OS_SINGLE:
998ad75a51eSRichard Henderson         gen_helper_redf32(tmp, tcg_env, fp);
999b7a94da9SRichard Henderson         tcg_gen_qemu_st_tl(tmp, addr, index, MO_TEUL);
1000f83311e4SLaurent Vivier         break;
1001f83311e4SLaurent Vivier     case OS_DOUBLE:
1002ad75a51eSRichard Henderson         gen_helper_redf64(t64, tcg_env, fp);
1003b7a94da9SRichard Henderson         tcg_gen_qemu_st_i64(t64, addr, index, MO_TEUQ);
1004f83311e4SLaurent Vivier         break;
1005f83311e4SLaurent Vivier     case OS_EXTENDED:
1006f83311e4SLaurent Vivier         if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1007a575cbe0SRichard Henderson             gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1008f83311e4SLaurent Vivier             break;
1009f83311e4SLaurent Vivier         }
1010f83311e4SLaurent Vivier         tcg_gen_ld16u_i32(tmp, fp, offsetof(FPReg, l.upper));
1011f83311e4SLaurent Vivier         tcg_gen_shli_i32(tmp, tmp, 16);
1012b7a94da9SRichard Henderson         tcg_gen_qemu_st_i32(tmp, addr, index, MO_TEUL);
1013f83311e4SLaurent Vivier         tcg_gen_addi_i32(tmp, addr, 4);
1014f83311e4SLaurent Vivier         tcg_gen_ld_i64(t64, fp, offsetof(FPReg, l.lower));
1015b7a94da9SRichard Henderson         tcg_gen_qemu_st_i64(t64, tmp, index, MO_TEUQ);
1016f83311e4SLaurent Vivier         break;
1017f83311e4SLaurent Vivier     case OS_PACKED:
1018808d77bcSLucien Murray-Pitts         /*
1019808d77bcSLucien Murray-Pitts          * unimplemented data type on 68040/ColdFire
1020f83311e4SLaurent Vivier          * FIXME if needed for another FPU
1021f83311e4SLaurent Vivier          */
1022a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1023f83311e4SLaurent Vivier         break;
1024f83311e4SLaurent Vivier     default:
1025f83311e4SLaurent Vivier         g_assert_not_reached();
1026f83311e4SLaurent Vivier     }
1027f83311e4SLaurent Vivier }
1028f83311e4SLaurent Vivier 
gen_ldst_fp(DisasContext * s,int opsize,TCGv addr,TCGv_ptr fp,ea_what what,int index)1029f83311e4SLaurent Vivier static void gen_ldst_fp(DisasContext *s, int opsize, TCGv addr,
103054e1e0b5SLaurent Vivier                         TCGv_ptr fp, ea_what what, int index)
1031f83311e4SLaurent Vivier {
1032f83311e4SLaurent Vivier     if (what == EA_STORE) {
103354e1e0b5SLaurent Vivier         gen_store_fp(s, opsize, addr, fp, index);
1034f83311e4SLaurent Vivier     } else {
103554e1e0b5SLaurent Vivier         gen_load_fp(s, opsize, addr, fp, index);
1036f83311e4SLaurent Vivier     }
1037f83311e4SLaurent Vivier }
1038f83311e4SLaurent Vivier 
gen_ea_mode_fp(CPUM68KState * env,DisasContext * s,int mode,int reg0,int opsize,TCGv_ptr fp,ea_what what,int index)1039f83311e4SLaurent Vivier static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
104054e1e0b5SLaurent Vivier                           int reg0, int opsize, TCGv_ptr fp, ea_what what,
104154e1e0b5SLaurent Vivier                           int index)
1042f83311e4SLaurent Vivier {
1043f83311e4SLaurent Vivier     TCGv reg, addr, tmp;
1044f83311e4SLaurent Vivier     TCGv_i64 t64;
1045f83311e4SLaurent Vivier 
1046f83311e4SLaurent Vivier     switch (mode) {
1047f83311e4SLaurent Vivier     case 0: /* Data register direct.  */
1048f83311e4SLaurent Vivier         reg = cpu_dregs[reg0];
1049f83311e4SLaurent Vivier         if (what == EA_STORE) {
1050f83311e4SLaurent Vivier             switch (opsize) {
1051f83311e4SLaurent Vivier             case OS_BYTE:
1052f83311e4SLaurent Vivier             case OS_WORD:
1053f83311e4SLaurent Vivier             case OS_LONG:
1054ad75a51eSRichard Henderson                 gen_helper_reds32(reg, tcg_env, fp);
1055f83311e4SLaurent Vivier                 break;
1056f83311e4SLaurent Vivier             case OS_SINGLE:
1057ad75a51eSRichard Henderson                 gen_helper_redf32(reg, tcg_env, fp);
1058f83311e4SLaurent Vivier                 break;
1059f83311e4SLaurent Vivier             default:
1060f83311e4SLaurent Vivier                 g_assert_not_reached();
1061f83311e4SLaurent Vivier             }
1062f83311e4SLaurent Vivier         } else {
1063f83311e4SLaurent Vivier             tmp = tcg_temp_new();
1064f83311e4SLaurent Vivier             switch (opsize) {
1065f83311e4SLaurent Vivier             case OS_BYTE:
1066f83311e4SLaurent Vivier             case OS_WORD:
1067f83311e4SLaurent Vivier             case OS_LONG:
1068443025e4SRichard Henderson                 tcg_gen_ext_i32(tmp, reg, opsize | MO_SIGN);
1069443025e4SRichard Henderson                 gen_helper_exts32(tcg_env, fp, tmp);
1070f83311e4SLaurent Vivier                 break;
1071f83311e4SLaurent Vivier             case OS_SINGLE:
1072ad75a51eSRichard Henderson                 gen_helper_extf32(tcg_env, fp, reg);
1073f83311e4SLaurent Vivier                 break;
1074f83311e4SLaurent Vivier             default:
1075f83311e4SLaurent Vivier                 g_assert_not_reached();
1076f83311e4SLaurent Vivier             }
1077f83311e4SLaurent Vivier         }
1078f83311e4SLaurent Vivier         return 0;
1079f83311e4SLaurent Vivier     case 1: /* Address register direct.  */
1080f83311e4SLaurent Vivier         return -1;
1081f83311e4SLaurent Vivier     case 2: /* Indirect register */
1082f83311e4SLaurent Vivier         addr = get_areg(s, reg0);
108354e1e0b5SLaurent Vivier         gen_ldst_fp(s, opsize, addr, fp, what, index);
1084f83311e4SLaurent Vivier         return 0;
1085f83311e4SLaurent Vivier     case 3: /* Indirect postincrement.  */
1086f83311e4SLaurent Vivier         addr = cpu_aregs[reg0];
108754e1e0b5SLaurent Vivier         gen_ldst_fp(s, opsize, addr, fp, what, index);
1088f83311e4SLaurent Vivier         tcg_gen_addi_i32(addr, addr, opsize_bytes(opsize));
1089f83311e4SLaurent Vivier         return 0;
1090f83311e4SLaurent Vivier     case 4: /* Indirect predecrememnt.  */
1091f83311e4SLaurent Vivier         addr = gen_lea_mode(env, s, mode, reg0, opsize);
1092f83311e4SLaurent Vivier         if (IS_NULL_QREG(addr)) {
1093f83311e4SLaurent Vivier             return -1;
1094f83311e4SLaurent Vivier         }
109554e1e0b5SLaurent Vivier         gen_ldst_fp(s, opsize, addr, fp, what, index);
1096f83311e4SLaurent Vivier         tcg_gen_mov_i32(cpu_aregs[reg0], addr);
1097f83311e4SLaurent Vivier         return 0;
1098f83311e4SLaurent Vivier     case 5: /* Indirect displacement.  */
1099f83311e4SLaurent Vivier     case 6: /* Indirect index + displacement.  */
1100f83311e4SLaurent Vivier     do_indirect:
1101f83311e4SLaurent Vivier         addr = gen_lea_mode(env, s, mode, reg0, opsize);
1102f83311e4SLaurent Vivier         if (IS_NULL_QREG(addr)) {
1103f83311e4SLaurent Vivier             return -1;
1104f83311e4SLaurent Vivier         }
110554e1e0b5SLaurent Vivier         gen_ldst_fp(s, opsize, addr, fp, what, index);
1106f83311e4SLaurent Vivier         return 0;
1107f83311e4SLaurent Vivier     case 7: /* Other */
1108f83311e4SLaurent Vivier         switch (reg0) {
1109f83311e4SLaurent Vivier         case 0: /* Absolute short.  */
1110f83311e4SLaurent Vivier         case 1: /* Absolute long.  */
1111f83311e4SLaurent Vivier         case 2: /* pc displacement  */
1112f83311e4SLaurent Vivier         case 3: /* pc index+displacement.  */
1113f83311e4SLaurent Vivier             goto do_indirect;
1114f83311e4SLaurent Vivier         case 4: /* Immediate.  */
1115f83311e4SLaurent Vivier             if (what == EA_STORE) {
1116f83311e4SLaurent Vivier                 return -1;
1117f83311e4SLaurent Vivier             }
1118f83311e4SLaurent Vivier             switch (opsize) {
1119f83311e4SLaurent Vivier             case OS_BYTE:
11201852ce5aSRichard Henderson                 tmp = tcg_constant_i32((int8_t)read_im8(env, s));
1121ad75a51eSRichard Henderson                 gen_helper_exts32(tcg_env, fp, tmp);
1122f83311e4SLaurent Vivier                 break;
1123f83311e4SLaurent Vivier             case OS_WORD:
11241852ce5aSRichard Henderson                 tmp = tcg_constant_i32((int16_t)read_im16(env, s));
1125ad75a51eSRichard Henderson                 gen_helper_exts32(tcg_env, fp, tmp);
1126f83311e4SLaurent Vivier                 break;
1127f83311e4SLaurent Vivier             case OS_LONG:
11281852ce5aSRichard Henderson                 tmp = tcg_constant_i32(read_im32(env, s));
1129ad75a51eSRichard Henderson                 gen_helper_exts32(tcg_env, fp, tmp);
1130f83311e4SLaurent Vivier                 break;
1131f83311e4SLaurent Vivier             case OS_SINGLE:
11321852ce5aSRichard Henderson                 tmp = tcg_constant_i32(read_im32(env, s));
1133ad75a51eSRichard Henderson                 gen_helper_extf32(tcg_env, fp, tmp);
1134f83311e4SLaurent Vivier                 break;
1135f83311e4SLaurent Vivier             case OS_DOUBLE:
11361852ce5aSRichard Henderson                 t64 = tcg_constant_i64(read_im64(env, s));
1137ad75a51eSRichard Henderson                 gen_helper_extf64(tcg_env, fp, t64);
1138f83311e4SLaurent Vivier                 break;
1139f83311e4SLaurent Vivier             case OS_EXTENDED:
1140f83311e4SLaurent Vivier                 if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1141a575cbe0SRichard Henderson                     gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1142f83311e4SLaurent Vivier                     break;
1143f83311e4SLaurent Vivier                 }
11441852ce5aSRichard Henderson                 tmp = tcg_constant_i32(read_im32(env, s) >> 16);
1145f83311e4SLaurent Vivier                 tcg_gen_st16_i32(tmp, fp, offsetof(FPReg, l.upper));
11461852ce5aSRichard Henderson                 t64 = tcg_constant_i64(read_im64(env, s));
1147f83311e4SLaurent Vivier                 tcg_gen_st_i64(t64, fp, offsetof(FPReg, l.lower));
1148f83311e4SLaurent Vivier                 break;
1149f83311e4SLaurent Vivier             case OS_PACKED:
1150808d77bcSLucien Murray-Pitts                 /*
1151808d77bcSLucien Murray-Pitts                  * unimplemented data type on 68040/ColdFire
1152f83311e4SLaurent Vivier                  * FIXME if needed for another FPU
1153f83311e4SLaurent Vivier                  */
1154a575cbe0SRichard Henderson                 gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1155f83311e4SLaurent Vivier                 break;
1156f83311e4SLaurent Vivier             default:
1157f83311e4SLaurent Vivier                 g_assert_not_reached();
1158f83311e4SLaurent Vivier             }
1159f83311e4SLaurent Vivier             return 0;
1160f83311e4SLaurent Vivier         default:
1161f83311e4SLaurent Vivier             return -1;
1162f83311e4SLaurent Vivier         }
1163f83311e4SLaurent Vivier     }
1164f83311e4SLaurent Vivier     return -1;
1165f83311e4SLaurent Vivier }
1166f83311e4SLaurent Vivier 
gen_ea_fp(CPUM68KState * env,DisasContext * s,uint16_t insn,int opsize,TCGv_ptr fp,ea_what what,int index)1167f83311e4SLaurent Vivier static int gen_ea_fp(CPUM68KState *env, DisasContext *s, uint16_t insn,
116854e1e0b5SLaurent Vivier                        int opsize, TCGv_ptr fp, ea_what what, int index)
1169f83311e4SLaurent Vivier {
1170f83311e4SLaurent Vivier     int mode = extract32(insn, 3, 3);
1171f83311e4SLaurent Vivier     int reg0 = REG(insn, 0);
117254e1e0b5SLaurent Vivier     return gen_ea_mode_fp(env, s, mode, reg0, opsize, fp, what, index);
1173f83311e4SLaurent Vivier }
1174f83311e4SLaurent Vivier 
1175fcf5ef2aSThomas Huth typedef struct {
1176fcf5ef2aSThomas Huth     TCGCond tcond;
1177fcf5ef2aSThomas Huth     TCGv v1;
1178fcf5ef2aSThomas Huth     TCGv v2;
1179fcf5ef2aSThomas Huth } DisasCompare;
1180fcf5ef2aSThomas Huth 
gen_cc_cond(DisasCompare * c,DisasContext * s,int cond)1181fcf5ef2aSThomas Huth static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond)
1182fcf5ef2aSThomas Huth {
1183fcf5ef2aSThomas Huth     TCGv tmp, tmp2;
1184fcf5ef2aSThomas Huth     TCGCond tcond;
1185fcf5ef2aSThomas Huth     CCOp op = s->cc_op;
1186fcf5ef2aSThomas Huth 
1187fcf5ef2aSThomas Huth     /* The CC_OP_CMP form can handle most normal comparisons directly.  */
1188fcf5ef2aSThomas Huth     if (op == CC_OP_CMPB || op == CC_OP_CMPW || op == CC_OP_CMPL) {
1189fcf5ef2aSThomas Huth         c->v1 = QREG_CC_N;
1190fcf5ef2aSThomas Huth         c->v2 = QREG_CC_V;
1191fcf5ef2aSThomas Huth         switch (cond) {
1192fcf5ef2aSThomas Huth         case 2: /* HI */
1193fcf5ef2aSThomas Huth         case 3: /* LS */
1194fcf5ef2aSThomas Huth             tcond = TCG_COND_LEU;
1195fcf5ef2aSThomas Huth             goto done;
1196fcf5ef2aSThomas Huth         case 4: /* CC */
1197fcf5ef2aSThomas Huth         case 5: /* CS */
1198fcf5ef2aSThomas Huth             tcond = TCG_COND_LTU;
1199fcf5ef2aSThomas Huth             goto done;
1200fcf5ef2aSThomas Huth         case 6: /* NE */
1201fcf5ef2aSThomas Huth         case 7: /* EQ */
1202fcf5ef2aSThomas Huth             tcond = TCG_COND_EQ;
1203fcf5ef2aSThomas Huth             goto done;
1204fcf5ef2aSThomas Huth         case 10: /* PL */
1205fcf5ef2aSThomas Huth         case 11: /* MI */
12061852ce5aSRichard Henderson             c->v2 = tcg_constant_i32(0);
1207fcf5ef2aSThomas Huth             c->v1 = tmp = tcg_temp_new();
1208fcf5ef2aSThomas Huth             tcg_gen_sub_i32(tmp, QREG_CC_N, QREG_CC_V);
1209fcf5ef2aSThomas Huth             gen_ext(tmp, tmp, op - CC_OP_CMPB, 1);
1210fcf5ef2aSThomas Huth             /* fallthru */
1211fcf5ef2aSThomas Huth         case 12: /* GE */
1212fcf5ef2aSThomas Huth         case 13: /* LT */
1213fcf5ef2aSThomas Huth             tcond = TCG_COND_LT;
1214fcf5ef2aSThomas Huth             goto done;
1215fcf5ef2aSThomas Huth         case 14: /* GT */
1216fcf5ef2aSThomas Huth         case 15: /* LE */
1217fcf5ef2aSThomas Huth             tcond = TCG_COND_LE;
1218fcf5ef2aSThomas Huth             goto done;
1219fcf5ef2aSThomas Huth         }
1220fcf5ef2aSThomas Huth     }
1221fcf5ef2aSThomas Huth 
12221852ce5aSRichard Henderson     c->v2 = tcg_constant_i32(0);
1223fcf5ef2aSThomas Huth 
1224fcf5ef2aSThomas Huth     switch (cond) {
1225fcf5ef2aSThomas Huth     case 0: /* T */
1226fcf5ef2aSThomas Huth     case 1: /* F */
1227fcf5ef2aSThomas Huth         c->v1 = c->v2;
1228fcf5ef2aSThomas Huth         tcond = TCG_COND_NEVER;
1229fcf5ef2aSThomas Huth         goto done;
1230fcf5ef2aSThomas Huth     case 14: /* GT (!(Z || (N ^ V))) */
1231fcf5ef2aSThomas Huth     case 15: /* LE (Z || (N ^ V)) */
1232808d77bcSLucien Murray-Pitts         /*
1233808d77bcSLucien Murray-Pitts          * Logic operations clear V, which simplifies LE to (Z || N),
1234808d77bcSLucien Murray-Pitts          * and since Z and N are co-located, this becomes a normal
1235808d77bcSLucien Murray-Pitts          * comparison vs N.
1236808d77bcSLucien Murray-Pitts          */
1237fcf5ef2aSThomas Huth         if (op == CC_OP_LOGIC) {
1238fcf5ef2aSThomas Huth             c->v1 = QREG_CC_N;
1239fcf5ef2aSThomas Huth             tcond = TCG_COND_LE;
1240fcf5ef2aSThomas Huth             goto done;
1241fcf5ef2aSThomas Huth         }
1242fcf5ef2aSThomas Huth         break;
1243fcf5ef2aSThomas Huth     case 12: /* GE (!(N ^ V)) */
1244fcf5ef2aSThomas Huth     case 13: /* LT (N ^ V) */
1245fcf5ef2aSThomas Huth         /* Logic operations clear V, which simplifies this to N.  */
1246fcf5ef2aSThomas Huth         if (op != CC_OP_LOGIC) {
1247fcf5ef2aSThomas Huth             break;
1248fcf5ef2aSThomas Huth         }
1249fcf5ef2aSThomas Huth         /* fallthru */
1250fcf5ef2aSThomas Huth     case 10: /* PL (!N) */
1251fcf5ef2aSThomas Huth     case 11: /* MI (N) */
1252fcf5ef2aSThomas Huth         /* Several cases represent N normally.  */
1253fcf5ef2aSThomas Huth         if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1254fcf5ef2aSThomas Huth             op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
1255fcf5ef2aSThomas Huth             op == CC_OP_LOGIC) {
1256fcf5ef2aSThomas Huth             c->v1 = QREG_CC_N;
1257fcf5ef2aSThomas Huth             tcond = TCG_COND_LT;
1258fcf5ef2aSThomas Huth             goto done;
1259fcf5ef2aSThomas Huth         }
1260fcf5ef2aSThomas Huth         break;
1261fcf5ef2aSThomas Huth     case 6: /* NE (!Z) */
1262fcf5ef2aSThomas Huth     case 7: /* EQ (Z) */
1263fcf5ef2aSThomas Huth         /* Some cases fold Z into N.  */
1264fcf5ef2aSThomas Huth         if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1265fcf5ef2aSThomas Huth             op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
1266fcf5ef2aSThomas Huth             op == CC_OP_LOGIC) {
1267fcf5ef2aSThomas Huth             tcond = TCG_COND_EQ;
1268fcf5ef2aSThomas Huth             c->v1 = QREG_CC_N;
1269fcf5ef2aSThomas Huth             goto done;
1270fcf5ef2aSThomas Huth         }
1271fcf5ef2aSThomas Huth         break;
1272fcf5ef2aSThomas Huth     case 4: /* CC (!C) */
1273fcf5ef2aSThomas Huth     case 5: /* CS (C) */
1274fcf5ef2aSThomas Huth         /* Some cases fold C into X.  */
1275fcf5ef2aSThomas Huth         if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
12764b5660e4SPhilippe Mathieu-Daudé             op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL) {
1277fcf5ef2aSThomas Huth             tcond = TCG_COND_NE;
1278fcf5ef2aSThomas Huth             c->v1 = QREG_CC_X;
1279fcf5ef2aSThomas Huth             goto done;
1280fcf5ef2aSThomas Huth         }
1281fcf5ef2aSThomas Huth         /* fallthru */
1282fcf5ef2aSThomas Huth     case 8: /* VC (!V) */
1283fcf5ef2aSThomas Huth     case 9: /* VS (V) */
1284fcf5ef2aSThomas Huth         /* Logic operations clear V and C.  */
1285fcf5ef2aSThomas Huth         if (op == CC_OP_LOGIC) {
1286fcf5ef2aSThomas Huth             tcond = TCG_COND_NEVER;
1287fcf5ef2aSThomas Huth             c->v1 = c->v2;
1288fcf5ef2aSThomas Huth             goto done;
1289fcf5ef2aSThomas Huth         }
1290fcf5ef2aSThomas Huth         break;
1291fcf5ef2aSThomas Huth     }
1292fcf5ef2aSThomas Huth 
1293fcf5ef2aSThomas Huth     /* Otherwise, flush flag state to CC_OP_FLAGS.  */
1294fcf5ef2aSThomas Huth     gen_flush_flags(s);
1295fcf5ef2aSThomas Huth 
1296fcf5ef2aSThomas Huth     switch (cond) {
1297fcf5ef2aSThomas Huth     case 0: /* T */
1298fcf5ef2aSThomas Huth     case 1: /* F */
1299fcf5ef2aSThomas Huth     default:
1300fcf5ef2aSThomas Huth         /* Invalid, or handled above.  */
1301fcf5ef2aSThomas Huth         abort();
1302fcf5ef2aSThomas Huth     case 2: /* HI (!C && !Z) -> !(C || Z)*/
1303fcf5ef2aSThomas Huth     case 3: /* LS (C || Z) */
1304fcf5ef2aSThomas Huth         c->v1 = tmp = tcg_temp_new();
1305fcf5ef2aSThomas Huth         tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
1306fcf5ef2aSThomas Huth         tcg_gen_or_i32(tmp, tmp, QREG_CC_C);
1307fcf5ef2aSThomas Huth         tcond = TCG_COND_NE;
1308fcf5ef2aSThomas Huth         break;
1309fcf5ef2aSThomas Huth     case 4: /* CC (!C) */
1310fcf5ef2aSThomas Huth     case 5: /* CS (C) */
1311fcf5ef2aSThomas Huth         c->v1 = QREG_CC_C;
1312fcf5ef2aSThomas Huth         tcond = TCG_COND_NE;
1313fcf5ef2aSThomas Huth         break;
1314fcf5ef2aSThomas Huth     case 6: /* NE (!Z) */
1315fcf5ef2aSThomas Huth     case 7: /* EQ (Z) */
1316fcf5ef2aSThomas Huth         c->v1 = QREG_CC_Z;
1317fcf5ef2aSThomas Huth         tcond = TCG_COND_EQ;
1318fcf5ef2aSThomas Huth         break;
1319fcf5ef2aSThomas Huth     case 8: /* VC (!V) */
1320fcf5ef2aSThomas Huth     case 9: /* VS (V) */
1321fcf5ef2aSThomas Huth         c->v1 = QREG_CC_V;
1322fcf5ef2aSThomas Huth         tcond = TCG_COND_LT;
1323fcf5ef2aSThomas Huth         break;
1324fcf5ef2aSThomas Huth     case 10: /* PL (!N) */
1325fcf5ef2aSThomas Huth     case 11: /* MI (N) */
1326fcf5ef2aSThomas Huth         c->v1 = QREG_CC_N;
1327fcf5ef2aSThomas Huth         tcond = TCG_COND_LT;
1328fcf5ef2aSThomas Huth         break;
1329fcf5ef2aSThomas Huth     case 12: /* GE (!(N ^ V)) */
1330fcf5ef2aSThomas Huth     case 13: /* LT (N ^ V) */
1331fcf5ef2aSThomas Huth         c->v1 = tmp = tcg_temp_new();
1332fcf5ef2aSThomas Huth         tcg_gen_xor_i32(tmp, QREG_CC_N, QREG_CC_V);
1333fcf5ef2aSThomas Huth         tcond = TCG_COND_LT;
1334fcf5ef2aSThomas Huth         break;
1335fcf5ef2aSThomas Huth     case 14: /* GT (!(Z || (N ^ V))) */
1336fcf5ef2aSThomas Huth     case 15: /* LE (Z || (N ^ V)) */
1337fcf5ef2aSThomas Huth         c->v1 = tmp = tcg_temp_new();
133827f9af76SRichard Henderson         tcg_gen_negsetcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
1339fcf5ef2aSThomas Huth         tmp2 = tcg_temp_new();
1340fcf5ef2aSThomas Huth         tcg_gen_xor_i32(tmp2, QREG_CC_N, QREG_CC_V);
1341fcf5ef2aSThomas Huth         tcg_gen_or_i32(tmp, tmp, tmp2);
1342fcf5ef2aSThomas Huth         tcond = TCG_COND_LT;
1343fcf5ef2aSThomas Huth         break;
1344fcf5ef2aSThomas Huth     }
1345fcf5ef2aSThomas Huth 
1346fcf5ef2aSThomas Huth  done:
1347fcf5ef2aSThomas Huth     if ((cond & 1) == 0) {
1348fcf5ef2aSThomas Huth         tcond = tcg_invert_cond(tcond);
1349fcf5ef2aSThomas Huth     }
1350fcf5ef2aSThomas Huth     c->tcond = tcond;
1351fcf5ef2aSThomas Huth }
1352fcf5ef2aSThomas Huth 
gen_jmpcc(DisasContext * s,int cond,TCGLabel * l1)1353fcf5ef2aSThomas Huth static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1)
1354fcf5ef2aSThomas Huth {
1355fcf5ef2aSThomas Huth   DisasCompare c;
1356fcf5ef2aSThomas Huth 
1357fcf5ef2aSThomas Huth   gen_cc_cond(&c, s, cond);
1358fcf5ef2aSThomas Huth   update_cc_op(s);
1359fcf5ef2aSThomas Huth   tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
1360fcf5ef2aSThomas Huth }
1361fcf5ef2aSThomas Huth 
1362fcf5ef2aSThomas Huth /* Force a TB lookup after an instruction that changes the CPU state.  */
gen_exit_tb(DisasContext * s)13634106f26eSRichard Henderson static void gen_exit_tb(DisasContext *s)
1364fcf5ef2aSThomas Huth {
1365fcf5ef2aSThomas Huth     update_cc_op(s);
1366fcf5ef2aSThomas Huth     tcg_gen_movi_i32(QREG_PC, s->pc);
1367a575cbe0SRichard Henderson     s->base.is_jmp = DISAS_EXIT;
1368fcf5ef2aSThomas Huth }
1369fcf5ef2aSThomas Huth 
1370fcf5ef2aSThomas Huth #define SRC_EA(env, result, opsize, op_sign, addrp) do {                \
1371fcf5ef2aSThomas Huth         result = gen_ea(env, s, insn, opsize, NULL_QREG, addrp,         \
137254e1e0b5SLaurent Vivier                         op_sign ? EA_LOADS : EA_LOADU, IS_USER(s));     \
1373fcf5ef2aSThomas Huth         if (IS_NULL_QREG(result)) {                                     \
1374fcf5ef2aSThomas Huth             gen_addr_fault(s);                                          \
1375fcf5ef2aSThomas Huth             return;                                                     \
1376fcf5ef2aSThomas Huth         }                                                               \
1377fcf5ef2aSThomas Huth     } while (0)
1378fcf5ef2aSThomas Huth 
1379fcf5ef2aSThomas Huth #define DEST_EA(env, insn, opsize, val, addrp) do {                     \
138054e1e0b5SLaurent Vivier         TCGv ea_result = gen_ea(env, s, insn, opsize, val, addrp,       \
138154e1e0b5SLaurent Vivier                                 EA_STORE, IS_USER(s));                  \
1382fcf5ef2aSThomas Huth         if (IS_NULL_QREG(ea_result)) {                                  \
1383fcf5ef2aSThomas Huth             gen_addr_fault(s);                                          \
1384fcf5ef2aSThomas Huth             return;                                                     \
1385fcf5ef2aSThomas Huth         }                                                               \
1386fcf5ef2aSThomas Huth     } while (0)
1387fcf5ef2aSThomas Huth 
1388fcf5ef2aSThomas Huth /* Generate a jump to an immediate address.  */
gen_jmp_tb(DisasContext * s,int n,target_ulong dest,target_ulong src)13898115fc93SRichard Henderson static void gen_jmp_tb(DisasContext *s, int n, target_ulong dest,
13908115fc93SRichard Henderson                        target_ulong src)
1391fcf5ef2aSThomas Huth {
1392661da0f6SRichard Henderson     if (unlikely(s->ss_active)) {
13934f2b21efSMark Cave-Ayland         update_cc_op(s);
13944f2b21efSMark Cave-Ayland         tcg_gen_movi_i32(QREG_PC, dest);
13958115fc93SRichard Henderson         gen_raise_exception_format2(s, EXCP_TRACE, src);
1396fbf565c4SRichard Henderson     } else if (translator_use_goto_tb(&s->base, dest)) {
1397fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1398fcf5ef2aSThomas Huth         tcg_gen_movi_i32(QREG_PC, dest);
1399a575cbe0SRichard Henderson         tcg_gen_exit_tb(s->base.tb, n);
1400fcf5ef2aSThomas Huth     } else {
1401fcf5ef2aSThomas Huth         gen_jmp_im(s, dest);
140207ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1403fcf5ef2aSThomas Huth     }
1404a575cbe0SRichard Henderson     s->base.is_jmp = DISAS_NORETURN;
1405fcf5ef2aSThomas Huth }
1406fcf5ef2aSThomas Huth 
1407f161e723SRichard Henderson #ifndef CONFIG_USER_ONLY
semihosting_test(DisasContext * s)1408f161e723SRichard Henderson static bool semihosting_test(DisasContext *s)
1409f161e723SRichard Henderson {
1410f161e723SRichard Henderson     uint32_t test;
1411f161e723SRichard Henderson 
1412f161e723SRichard Henderson     if (!semihosting_enabled(IS_USER(s))) {
1413f161e723SRichard Henderson         return false;
1414f161e723SRichard Henderson     }
1415f161e723SRichard Henderson 
1416f161e723SRichard Henderson     /*
1417f161e723SRichard Henderson      * "The semihosting instruction is immediately preceded by a
1418f161e723SRichard Henderson      * nop aligned to a 4-byte boundary..."
1419f161e723SRichard Henderson      * The preceding 2-byte (aligned) nop plus the 2-byte halt/bkpt
1420f161e723SRichard Henderson      * means that we have advanced 4 bytes from the required nop.
1421f161e723SRichard Henderson      */
1422f161e723SRichard Henderson     if (s->pc % 4 != 0) {
1423f161e723SRichard Henderson         return false;
1424f161e723SRichard Henderson     }
1425f161e723SRichard Henderson     test = translator_lduw(s->env, &s->base, s->pc - 4);
1426f161e723SRichard Henderson     if (test != 0x4e71) {
1427f161e723SRichard Henderson         return false;
1428f161e723SRichard Henderson     }
1429f161e723SRichard Henderson     /* "... and followed by an invalid sentinel instruction movec %sp,0." */
1430f161e723SRichard Henderson     test = translator_ldl(s->env, &s->base, s->pc);
1431f161e723SRichard Henderson     if (test != 0x4e7bf000) {
1432f161e723SRichard Henderson         return false;
1433f161e723SRichard Henderson     }
1434f161e723SRichard Henderson 
1435f161e723SRichard Henderson     /* Consume the sentinel. */
1436f161e723SRichard Henderson     s->pc += 4;
1437f161e723SRichard Henderson     return true;
1438f161e723SRichard Henderson }
1439f161e723SRichard Henderson #endif /* !CONFIG_USER_ONLY */
1440f161e723SRichard Henderson 
DISAS_INSN(scc)1441fcf5ef2aSThomas Huth DISAS_INSN(scc)
1442fcf5ef2aSThomas Huth {
1443fcf5ef2aSThomas Huth     DisasCompare c;
1444fcf5ef2aSThomas Huth     int cond;
1445fcf5ef2aSThomas Huth     TCGv tmp;
1446fcf5ef2aSThomas Huth 
1447fcf5ef2aSThomas Huth     cond = (insn >> 8) & 0xf;
1448fcf5ef2aSThomas Huth     gen_cc_cond(&c, s, cond);
1449fcf5ef2aSThomas Huth 
1450fcf5ef2aSThomas Huth     tmp = tcg_temp_new();
145127f9af76SRichard Henderson     tcg_gen_negsetcond_i32(c.tcond, tmp, c.v1, c.v2);
1452fcf5ef2aSThomas Huth 
1453fcf5ef2aSThomas Huth     DEST_EA(env, insn, OS_BYTE, tmp, NULL);
1454fcf5ef2aSThomas Huth }
1455fcf5ef2aSThomas Huth 
DISAS_INSN(dbcc)1456fcf5ef2aSThomas Huth DISAS_INSN(dbcc)
1457fcf5ef2aSThomas Huth {
1458fcf5ef2aSThomas Huth     TCGLabel *l1;
1459fcf5ef2aSThomas Huth     TCGv reg;
1460fcf5ef2aSThomas Huth     TCGv tmp;
1461fcf5ef2aSThomas Huth     int16_t offset;
1462fcf5ef2aSThomas Huth     uint32_t base;
1463fcf5ef2aSThomas Huth 
1464fcf5ef2aSThomas Huth     reg = DREG(insn, 0);
1465fcf5ef2aSThomas Huth     base = s->pc;
1466fcf5ef2aSThomas Huth     offset = (int16_t)read_im16(env, s);
1467fcf5ef2aSThomas Huth     l1 = gen_new_label();
1468fcf5ef2aSThomas Huth     gen_jmpcc(s, (insn >> 8) & 0xf, l1);
1469fcf5ef2aSThomas Huth 
1470fcf5ef2aSThomas Huth     tmp = tcg_temp_new();
1471fcf5ef2aSThomas Huth     tcg_gen_ext16s_i32(tmp, reg);
1472fcf5ef2aSThomas Huth     tcg_gen_addi_i32(tmp, tmp, -1);
1473fcf5ef2aSThomas Huth     gen_partset_reg(OS_WORD, reg, tmp);
1474fcf5ef2aSThomas Huth     tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1);
14758115fc93SRichard Henderson     gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
1476fcf5ef2aSThomas Huth     gen_set_label(l1);
14778115fc93SRichard Henderson     gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
1478fcf5ef2aSThomas Huth }
1479fcf5ef2aSThomas Huth 
DISAS_INSN(undef_mac)1480fcf5ef2aSThomas Huth DISAS_INSN(undef_mac)
1481fcf5ef2aSThomas Huth {
1482a575cbe0SRichard Henderson     gen_exception(s, s->base.pc_next, EXCP_LINEA);
1483fcf5ef2aSThomas Huth }
1484fcf5ef2aSThomas Huth 
DISAS_INSN(undef_fpu)1485fcf5ef2aSThomas Huth DISAS_INSN(undef_fpu)
1486fcf5ef2aSThomas Huth {
1487a575cbe0SRichard Henderson     gen_exception(s, s->base.pc_next, EXCP_LINEF);
1488fcf5ef2aSThomas Huth }
1489fcf5ef2aSThomas Huth 
DISAS_INSN(undef)1490fcf5ef2aSThomas Huth DISAS_INSN(undef)
1491fcf5ef2aSThomas Huth {
1492808d77bcSLucien Murray-Pitts     /*
1493808d77bcSLucien Murray-Pitts      * ??? This is both instructions that are as yet unimplemented
1494808d77bcSLucien Murray-Pitts      * for the 680x0 series, as well as those that are implemented
1495808d77bcSLucien Murray-Pitts      * but actually illegal for CPU32 or pre-68020.
1496808d77bcSLucien Murray-Pitts      */
149785c19af6SAnton Johansson     qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %" VADDR_PRIx "\n",
1498a575cbe0SRichard Henderson                   insn, s->base.pc_next);
1499b9f8e55bSLaurent Vivier     gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
1500fcf5ef2aSThomas Huth }
1501fcf5ef2aSThomas Huth 
DISAS_INSN(mulw)1502fcf5ef2aSThomas Huth DISAS_INSN(mulw)
1503fcf5ef2aSThomas Huth {
1504fcf5ef2aSThomas Huth     TCGv reg;
1505fcf5ef2aSThomas Huth     TCGv tmp;
1506fcf5ef2aSThomas Huth     TCGv src;
1507fcf5ef2aSThomas Huth     int sign;
1508fcf5ef2aSThomas Huth 
1509fcf5ef2aSThomas Huth     sign = (insn & 0x100) != 0;
1510fcf5ef2aSThomas Huth     reg = DREG(insn, 9);
1511fcf5ef2aSThomas Huth     tmp = tcg_temp_new();
1512fcf5ef2aSThomas Huth     if (sign)
1513fcf5ef2aSThomas Huth         tcg_gen_ext16s_i32(tmp, reg);
1514fcf5ef2aSThomas Huth     else
1515fcf5ef2aSThomas Huth         tcg_gen_ext16u_i32(tmp, reg);
1516fcf5ef2aSThomas Huth     SRC_EA(env, src, OS_WORD, sign, NULL);
1517fcf5ef2aSThomas Huth     tcg_gen_mul_i32(tmp, tmp, src);
1518fcf5ef2aSThomas Huth     tcg_gen_mov_i32(reg, tmp);
1519fcf5ef2aSThomas Huth     gen_logic_cc(s, tmp, OS_LONG);
1520fcf5ef2aSThomas Huth }
1521fcf5ef2aSThomas Huth 
DISAS_INSN(divw)1522fcf5ef2aSThomas Huth DISAS_INSN(divw)
1523fcf5ef2aSThomas Huth {
1524fcf5ef2aSThomas Huth     int sign;
15250ccb9c1dSLaurent Vivier     TCGv src;
15260ccb9c1dSLaurent Vivier     TCGv destr;
1527710d747bSRichard Henderson     TCGv ilen;
15280ccb9c1dSLaurent Vivier 
15290ccb9c1dSLaurent Vivier     /* divX.w <EA>,Dn    32/16 -> 16r:16q */
1530fcf5ef2aSThomas Huth 
1531fcf5ef2aSThomas Huth     sign = (insn & 0x100) != 0;
1532fcf5ef2aSThomas Huth 
15330ccb9c1dSLaurent Vivier     /* dest.l / src.w */
15340ccb9c1dSLaurent Vivier 
15350ccb9c1dSLaurent Vivier     SRC_EA(env, src, OS_WORD, sign, NULL);
1536710d747bSRichard Henderson     destr = tcg_constant_i32(REG(insn, 9));
1537710d747bSRichard Henderson     ilen = tcg_constant_i32(s->pc - s->base.pc_next);
15380ccb9c1dSLaurent Vivier     if (sign) {
1539ad75a51eSRichard Henderson         gen_helper_divsw(tcg_env, destr, src, ilen);
15400ccb9c1dSLaurent Vivier     } else {
1541ad75a51eSRichard Henderson         gen_helper_divuw(tcg_env, destr, src, ilen);
15420ccb9c1dSLaurent Vivier     }
1543fcf5ef2aSThomas Huth 
1544fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_FLAGS);
1545fcf5ef2aSThomas Huth }
1546fcf5ef2aSThomas Huth 
DISAS_INSN(divl)1547fcf5ef2aSThomas Huth DISAS_INSN(divl)
1548fcf5ef2aSThomas Huth {
1549710d747bSRichard Henderson     TCGv num, reg, den, ilen;
15500ccb9c1dSLaurent Vivier     int sign;
1551fcf5ef2aSThomas Huth     uint16_t ext;
1552fcf5ef2aSThomas Huth 
1553fcf5ef2aSThomas Huth     ext = read_im16(env, s);
15540ccb9c1dSLaurent Vivier 
15550ccb9c1dSLaurent Vivier     sign = (ext & 0x0800) != 0;
15560ccb9c1dSLaurent Vivier 
15570ccb9c1dSLaurent Vivier     if (ext & 0x400) {
15580ccb9c1dSLaurent Vivier         if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
1559a575cbe0SRichard Henderson             gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
1560fcf5ef2aSThomas Huth             return;
1561fcf5ef2aSThomas Huth         }
15620ccb9c1dSLaurent Vivier 
15630ccb9c1dSLaurent Vivier         /* divX.l <EA>, Dr:Dq    64/32 -> 32r:32q */
15640ccb9c1dSLaurent Vivier 
1565fcf5ef2aSThomas Huth         SRC_EA(env, den, OS_LONG, 0, NULL);
1566710d747bSRichard Henderson         num = tcg_constant_i32(REG(ext, 12));
1567710d747bSRichard Henderson         reg = tcg_constant_i32(REG(ext, 0));
1568710d747bSRichard Henderson         ilen = tcg_constant_i32(s->pc - s->base.pc_next);
15690ccb9c1dSLaurent Vivier         if (sign) {
1570ad75a51eSRichard Henderson             gen_helper_divsll(tcg_env, num, reg, den, ilen);
1571fcf5ef2aSThomas Huth         } else {
1572ad75a51eSRichard Henderson             gen_helper_divull(tcg_env, num, reg, den, ilen);
1573fcf5ef2aSThomas Huth         }
15740ccb9c1dSLaurent Vivier         set_cc_op(s, CC_OP_FLAGS);
15750ccb9c1dSLaurent Vivier         return;
15760ccb9c1dSLaurent Vivier     }
15770ccb9c1dSLaurent Vivier 
15780ccb9c1dSLaurent Vivier     /* divX.l <EA>, Dq        32/32 -> 32q     */
15790ccb9c1dSLaurent Vivier     /* divXl.l <EA>, Dr:Dq    32/32 -> 32r:32q */
15800ccb9c1dSLaurent Vivier 
15810ccb9c1dSLaurent Vivier     SRC_EA(env, den, OS_LONG, 0, NULL);
1582710d747bSRichard Henderson     num = tcg_constant_i32(REG(ext, 12));
1583710d747bSRichard Henderson     reg = tcg_constant_i32(REG(ext, 0));
1584710d747bSRichard Henderson     ilen = tcg_constant_i32(s->pc - s->base.pc_next);
15850ccb9c1dSLaurent Vivier     if (sign) {
1586ad75a51eSRichard Henderson         gen_helper_divsl(tcg_env, num, reg, den, ilen);
1587fcf5ef2aSThomas Huth     } else {
1588ad75a51eSRichard Henderson         gen_helper_divul(tcg_env, num, reg, den, ilen);
1589fcf5ef2aSThomas Huth     }
15900ccb9c1dSLaurent Vivier 
1591fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_FLAGS);
1592fcf5ef2aSThomas Huth }
1593fcf5ef2aSThomas Huth 
bcd_add(TCGv dest,TCGv src)1594fb5543d8SLaurent Vivier static void bcd_add(TCGv dest, TCGv src)
1595fb5543d8SLaurent Vivier {
1596fb5543d8SLaurent Vivier     TCGv t0, t1;
1597fb5543d8SLaurent Vivier 
1598808d77bcSLucien Murray-Pitts     /*
1599808d77bcSLucien Murray-Pitts      * dest10 = dest10 + src10 + X
1600fb5543d8SLaurent Vivier      *
1601fb5543d8SLaurent Vivier      *        t1 = src
1602fb5543d8SLaurent Vivier      *        t2 = t1 + 0x066
1603fb5543d8SLaurent Vivier      *        t3 = t2 + dest + X
1604fb5543d8SLaurent Vivier      *        t4 = t2 ^ dest
1605fb5543d8SLaurent Vivier      *        t5 = t3 ^ t4
1606fb5543d8SLaurent Vivier      *        t6 = ~t5 & 0x110
1607fb5543d8SLaurent Vivier      *        t7 = (t6 >> 2) | (t6 >> 3)
1608fb5543d8SLaurent Vivier      *        return t3 - t7
1609fb5543d8SLaurent Vivier      */
1610fb5543d8SLaurent Vivier 
1611808d77bcSLucien Murray-Pitts     /*
1612808d77bcSLucien Murray-Pitts      * t1 = (src + 0x066) + dest + X
1613ce00ff72Szhaolichang      *    = result with some possible exceeding 0x6
1614fb5543d8SLaurent Vivier      */
1615fb5543d8SLaurent Vivier 
1616b32a07d4SRichard Henderson     t0 = tcg_temp_new();
1617b32a07d4SRichard Henderson     tcg_gen_addi_i32(t0, src, 0x066);
1618fb5543d8SLaurent Vivier 
1619fb5543d8SLaurent Vivier     t1 = tcg_temp_new();
1620fb5543d8SLaurent Vivier     tcg_gen_add_i32(t1, t0, dest);
1621fb5543d8SLaurent Vivier     tcg_gen_add_i32(t1, t1, QREG_CC_X);
1622fb5543d8SLaurent Vivier 
1623ce00ff72Szhaolichang     /* we will remove exceeding 0x6 where there is no carry */
1624fb5543d8SLaurent Vivier 
1625808d77bcSLucien Murray-Pitts     /*
1626808d77bcSLucien Murray-Pitts      * t0 = (src + 0x0066) ^ dest
1627fb5543d8SLaurent Vivier      *    = t1 without carries
1628fb5543d8SLaurent Vivier      */
1629fb5543d8SLaurent Vivier 
1630fb5543d8SLaurent Vivier     tcg_gen_xor_i32(t0, t0, dest);
1631fb5543d8SLaurent Vivier 
1632808d77bcSLucien Murray-Pitts     /*
1633808d77bcSLucien Murray-Pitts      * extract the carries
1634fb5543d8SLaurent Vivier      * t0 = t0 ^ t1
1635fb5543d8SLaurent Vivier      *    = only the carries
1636fb5543d8SLaurent Vivier      */
1637fb5543d8SLaurent Vivier 
1638fb5543d8SLaurent Vivier     tcg_gen_xor_i32(t0, t0, t1);
1639fb5543d8SLaurent Vivier 
1640808d77bcSLucien Murray-Pitts     /*
1641808d77bcSLucien Murray-Pitts      * generate 0x1 where there is no carry
1642fb5543d8SLaurent Vivier      * and for each 0x10, generate a 0x6
1643fb5543d8SLaurent Vivier      */
1644fb5543d8SLaurent Vivier 
1645fb5543d8SLaurent Vivier     tcg_gen_shri_i32(t0, t0, 3);
1646fb5543d8SLaurent Vivier     tcg_gen_not_i32(t0, t0);
1647fb5543d8SLaurent Vivier     tcg_gen_andi_i32(t0, t0, 0x22);
1648fb5543d8SLaurent Vivier     tcg_gen_add_i32(dest, t0, t0);
1649fb5543d8SLaurent Vivier     tcg_gen_add_i32(dest, dest, t0);
1650fb5543d8SLaurent Vivier 
1651808d77bcSLucien Murray-Pitts     /*
1652ce00ff72Szhaolichang      * remove the exceeding 0x6
1653fb5543d8SLaurent Vivier      * for digits that have not generated a carry
1654fb5543d8SLaurent Vivier      */
1655fb5543d8SLaurent Vivier 
1656fb5543d8SLaurent Vivier     tcg_gen_sub_i32(dest, t1, dest);
1657fb5543d8SLaurent Vivier }
1658fb5543d8SLaurent Vivier 
bcd_sub(TCGv dest,TCGv src)1659fb5543d8SLaurent Vivier static void bcd_sub(TCGv dest, TCGv src)
1660fb5543d8SLaurent Vivier {
1661fb5543d8SLaurent Vivier     TCGv t0, t1, t2;
1662fb5543d8SLaurent Vivier 
1663808d77bcSLucien Murray-Pitts     /*
1664808d77bcSLucien Murray-Pitts      *  dest10 = dest10 - src10 - X
1665fb5543d8SLaurent Vivier      *         = bcd_add(dest + 1 - X, 0x199 - src)
1666fb5543d8SLaurent Vivier      */
1667fb5543d8SLaurent Vivier 
1668fb5543d8SLaurent Vivier     /* t0 = 0x066 + (0x199 - src) */
1669fb5543d8SLaurent Vivier 
1670fb5543d8SLaurent Vivier     t0 = tcg_temp_new();
1671fb5543d8SLaurent Vivier     tcg_gen_subfi_i32(t0, 0x1ff, src);
1672fb5543d8SLaurent Vivier 
1673fb5543d8SLaurent Vivier     /* t1 = t0 + dest + 1 - X*/
1674fb5543d8SLaurent Vivier 
1675fb5543d8SLaurent Vivier     t1 = tcg_temp_new();
1676fb5543d8SLaurent Vivier     tcg_gen_add_i32(t1, t0, dest);
1677fb5543d8SLaurent Vivier     tcg_gen_addi_i32(t1, t1, 1);
1678fb5543d8SLaurent Vivier     tcg_gen_sub_i32(t1, t1, QREG_CC_X);
1679fb5543d8SLaurent Vivier 
1680fb5543d8SLaurent Vivier     /* t2 = t0 ^ dest */
1681fb5543d8SLaurent Vivier 
1682fb5543d8SLaurent Vivier     t2 = tcg_temp_new();
1683fb5543d8SLaurent Vivier     tcg_gen_xor_i32(t2, t0, dest);
1684fb5543d8SLaurent Vivier 
1685fb5543d8SLaurent Vivier     /* t0 = t1 ^ t2 */
1686fb5543d8SLaurent Vivier 
1687fb5543d8SLaurent Vivier     tcg_gen_xor_i32(t0, t1, t2);
1688fb5543d8SLaurent Vivier 
1689808d77bcSLucien Murray-Pitts     /*
1690808d77bcSLucien Murray-Pitts      * t2 = ~t0 & 0x110
1691fb5543d8SLaurent Vivier      * t0 = (t2 >> 2) | (t2 >> 3)
1692fb5543d8SLaurent Vivier      *
1693fb5543d8SLaurent Vivier      * to fit on 8bit operands, changed in:
1694fb5543d8SLaurent Vivier      *
1695fb5543d8SLaurent Vivier      * t2 = ~(t0 >> 3) & 0x22
1696fb5543d8SLaurent Vivier      * t0 = t2 + t2
1697fb5543d8SLaurent Vivier      * t0 = t0 + t2
1698fb5543d8SLaurent Vivier      */
1699fb5543d8SLaurent Vivier 
1700fb5543d8SLaurent Vivier     tcg_gen_shri_i32(t2, t0, 3);
1701fb5543d8SLaurent Vivier     tcg_gen_not_i32(t2, t2);
1702fb5543d8SLaurent Vivier     tcg_gen_andi_i32(t2, t2, 0x22);
1703fb5543d8SLaurent Vivier     tcg_gen_add_i32(t0, t2, t2);
1704fb5543d8SLaurent Vivier     tcg_gen_add_i32(t0, t0, t2);
1705fb5543d8SLaurent Vivier 
1706fb5543d8SLaurent Vivier     /* return t1 - t0 */
1707fb5543d8SLaurent Vivier 
1708fb5543d8SLaurent Vivier     tcg_gen_sub_i32(dest, t1, t0);
1709fb5543d8SLaurent Vivier }
1710fb5543d8SLaurent Vivier 
bcd_flags(TCGv val)1711fb5543d8SLaurent Vivier static void bcd_flags(TCGv val)
1712fb5543d8SLaurent Vivier {
1713fb5543d8SLaurent Vivier     tcg_gen_andi_i32(QREG_CC_C, val, 0x0ff);
1714fb5543d8SLaurent Vivier     tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_C);
1715fb5543d8SLaurent Vivier 
17160d9acef2SPhilippe Mathieu-Daudé     tcg_gen_extract_i32(QREG_CC_C, val, 8, 1);
1717fb5543d8SLaurent Vivier 
1718fb5543d8SLaurent Vivier     tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
1719fb5543d8SLaurent Vivier }
1720fb5543d8SLaurent Vivier 
DISAS_INSN(abcd_reg)1721fb5543d8SLaurent Vivier DISAS_INSN(abcd_reg)
1722fb5543d8SLaurent Vivier {
1723fb5543d8SLaurent Vivier     TCGv src;
1724fb5543d8SLaurent Vivier     TCGv dest;
1725fb5543d8SLaurent Vivier 
1726fb5543d8SLaurent Vivier     gen_flush_flags(s); /* !Z is sticky */
1727fb5543d8SLaurent Vivier 
17283f215a14SLaurent Vivier     src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
17293f215a14SLaurent Vivier     dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
1730fb5543d8SLaurent Vivier     bcd_add(dest, src);
1731fb5543d8SLaurent Vivier     gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1732fb5543d8SLaurent Vivier 
1733fb5543d8SLaurent Vivier     bcd_flags(dest);
1734fb5543d8SLaurent Vivier }
1735fb5543d8SLaurent Vivier 
DISAS_INSN(abcd_mem)1736fb5543d8SLaurent Vivier DISAS_INSN(abcd_mem)
1737fb5543d8SLaurent Vivier {
1738fb5543d8SLaurent Vivier     TCGv src, dest, addr;
1739fb5543d8SLaurent Vivier 
1740fb5543d8SLaurent Vivier     gen_flush_flags(s); /* !Z is sticky */
1741fb5543d8SLaurent Vivier 
1742fb5543d8SLaurent Vivier     /* Indirect pre-decrement load (mode 4) */
1743fb5543d8SLaurent Vivier 
1744fb5543d8SLaurent Vivier     src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
174554e1e0b5SLaurent Vivier                       NULL_QREG, NULL, EA_LOADU, IS_USER(s));
1746fb5543d8SLaurent Vivier     dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
174754e1e0b5SLaurent Vivier                        NULL_QREG, &addr, EA_LOADU, IS_USER(s));
1748fb5543d8SLaurent Vivier 
1749fb5543d8SLaurent Vivier     bcd_add(dest, src);
1750fb5543d8SLaurent Vivier 
175154e1e0b5SLaurent Vivier     gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr,
175254e1e0b5SLaurent Vivier                 EA_STORE, IS_USER(s));
1753fb5543d8SLaurent Vivier 
1754fb5543d8SLaurent Vivier     bcd_flags(dest);
1755fb5543d8SLaurent Vivier }
1756fb5543d8SLaurent Vivier 
DISAS_INSN(sbcd_reg)1757fb5543d8SLaurent Vivier DISAS_INSN(sbcd_reg)
1758fb5543d8SLaurent Vivier {
1759fb5543d8SLaurent Vivier     TCGv src, dest;
1760fb5543d8SLaurent Vivier 
1761fb5543d8SLaurent Vivier     gen_flush_flags(s); /* !Z is sticky */
1762fb5543d8SLaurent Vivier 
17633f215a14SLaurent Vivier     src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
17643f215a14SLaurent Vivier     dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
1765fb5543d8SLaurent Vivier 
1766fb5543d8SLaurent Vivier     bcd_sub(dest, src);
1767fb5543d8SLaurent Vivier 
1768fb5543d8SLaurent Vivier     gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1769fb5543d8SLaurent Vivier 
1770fb5543d8SLaurent Vivier     bcd_flags(dest);
1771fb5543d8SLaurent Vivier }
1772fb5543d8SLaurent Vivier 
DISAS_INSN(sbcd_mem)1773fb5543d8SLaurent Vivier DISAS_INSN(sbcd_mem)
1774fb5543d8SLaurent Vivier {
1775fb5543d8SLaurent Vivier     TCGv src, dest, addr;
1776fb5543d8SLaurent Vivier 
1777fb5543d8SLaurent Vivier     gen_flush_flags(s); /* !Z is sticky */
1778fb5543d8SLaurent Vivier 
1779fb5543d8SLaurent Vivier     /* Indirect pre-decrement load (mode 4) */
1780fb5543d8SLaurent Vivier 
1781fb5543d8SLaurent Vivier     src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
178254e1e0b5SLaurent Vivier                       NULL_QREG, NULL, EA_LOADU, IS_USER(s));
1783fb5543d8SLaurent Vivier     dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
178454e1e0b5SLaurent Vivier                        NULL_QREG, &addr, EA_LOADU, IS_USER(s));
1785fb5543d8SLaurent Vivier 
1786fb5543d8SLaurent Vivier     bcd_sub(dest, src);
1787fb5543d8SLaurent Vivier 
178854e1e0b5SLaurent Vivier     gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr,
178954e1e0b5SLaurent Vivier                 EA_STORE, IS_USER(s));
1790fb5543d8SLaurent Vivier 
1791fb5543d8SLaurent Vivier     bcd_flags(dest);
1792fb5543d8SLaurent Vivier }
1793fb5543d8SLaurent Vivier 
DISAS_INSN(nbcd)1794fb5543d8SLaurent Vivier DISAS_INSN(nbcd)
1795fb5543d8SLaurent Vivier {
1796fb5543d8SLaurent Vivier     TCGv src, dest;
1797fb5543d8SLaurent Vivier     TCGv addr;
1798fb5543d8SLaurent Vivier 
1799fb5543d8SLaurent Vivier     gen_flush_flags(s); /* !Z is sticky */
1800fb5543d8SLaurent Vivier 
1801fb5543d8SLaurent Vivier     SRC_EA(env, src, OS_BYTE, 0, &addr);
1802fb5543d8SLaurent Vivier 
1803b32a07d4SRichard Henderson     dest = tcg_temp_new();
1804b32a07d4SRichard Henderson     tcg_gen_movi_i32(dest, 0);
1805fb5543d8SLaurent Vivier     bcd_sub(dest, src);
1806fb5543d8SLaurent Vivier 
1807fb5543d8SLaurent Vivier     DEST_EA(env, insn, OS_BYTE, dest, &addr);
1808fb5543d8SLaurent Vivier 
1809fb5543d8SLaurent Vivier     bcd_flags(dest);
1810fb5543d8SLaurent Vivier }
1811fb5543d8SLaurent Vivier 
DISAS_INSN(addsub)1812fcf5ef2aSThomas Huth DISAS_INSN(addsub)
1813fcf5ef2aSThomas Huth {
1814fcf5ef2aSThomas Huth     TCGv reg;
1815fcf5ef2aSThomas Huth     TCGv dest;
1816fcf5ef2aSThomas Huth     TCGv src;
1817fcf5ef2aSThomas Huth     TCGv tmp;
1818fcf5ef2aSThomas Huth     TCGv addr;
1819fcf5ef2aSThomas Huth     int add;
1820fcf5ef2aSThomas Huth     int opsize;
1821fcf5ef2aSThomas Huth 
1822fcf5ef2aSThomas Huth     add = (insn & 0x4000) != 0;
1823fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
18243f215a14SLaurent Vivier     reg = gen_extend(s, DREG(insn, 9), opsize, 1);
1825fcf5ef2aSThomas Huth     dest = tcg_temp_new();
1826fcf5ef2aSThomas Huth     if (insn & 0x100) {
1827fcf5ef2aSThomas Huth         SRC_EA(env, tmp, opsize, 1, &addr);
1828fcf5ef2aSThomas Huth         src = reg;
1829fcf5ef2aSThomas Huth     } else {
1830fcf5ef2aSThomas Huth         tmp = reg;
1831fcf5ef2aSThomas Huth         SRC_EA(env, src, opsize, 1, NULL);
1832fcf5ef2aSThomas Huth     }
1833fcf5ef2aSThomas Huth     if (add) {
1834fcf5ef2aSThomas Huth         tcg_gen_add_i32(dest, tmp, src);
1835fcf5ef2aSThomas Huth         tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src);
1836fcf5ef2aSThomas Huth         set_cc_op(s, CC_OP_ADDB + opsize);
1837fcf5ef2aSThomas Huth     } else {
1838fcf5ef2aSThomas Huth         tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src);
1839fcf5ef2aSThomas Huth         tcg_gen_sub_i32(dest, tmp, src);
1840fcf5ef2aSThomas Huth         set_cc_op(s, CC_OP_SUBB + opsize);
1841fcf5ef2aSThomas Huth     }
1842fcf5ef2aSThomas Huth     gen_update_cc_add(dest, src, opsize);
1843fcf5ef2aSThomas Huth     if (insn & 0x100) {
1844fcf5ef2aSThomas Huth         DEST_EA(env, insn, opsize, dest, &addr);
1845fcf5ef2aSThomas Huth     } else {
1846fcf5ef2aSThomas Huth         gen_partset_reg(opsize, DREG(insn, 9), dest);
1847fcf5ef2aSThomas Huth     }
1848fcf5ef2aSThomas Huth }
1849fcf5ef2aSThomas Huth 
1850fcf5ef2aSThomas Huth /* Reverse the order of the bits in REG.  */
DISAS_INSN(bitrev)1851fcf5ef2aSThomas Huth DISAS_INSN(bitrev)
1852fcf5ef2aSThomas Huth {
1853fcf5ef2aSThomas Huth     TCGv reg;
1854fcf5ef2aSThomas Huth     reg = DREG(insn, 0);
1855fcf5ef2aSThomas Huth     gen_helper_bitrev(reg, reg);
1856fcf5ef2aSThomas Huth }
1857fcf5ef2aSThomas Huth 
DISAS_INSN(bitop_reg)1858fcf5ef2aSThomas Huth DISAS_INSN(bitop_reg)
1859fcf5ef2aSThomas Huth {
1860fcf5ef2aSThomas Huth     int opsize;
1861fcf5ef2aSThomas Huth     int op;
1862fcf5ef2aSThomas Huth     TCGv src1;
1863fcf5ef2aSThomas Huth     TCGv src2;
1864fcf5ef2aSThomas Huth     TCGv tmp;
1865fcf5ef2aSThomas Huth     TCGv addr;
1866fcf5ef2aSThomas Huth     TCGv dest;
1867fcf5ef2aSThomas Huth 
1868fcf5ef2aSThomas Huth     if ((insn & 0x38) != 0)
1869fcf5ef2aSThomas Huth         opsize = OS_BYTE;
1870fcf5ef2aSThomas Huth     else
1871fcf5ef2aSThomas Huth         opsize = OS_LONG;
1872fcf5ef2aSThomas Huth     op = (insn >> 6) & 3;
1873fcf5ef2aSThomas Huth     SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
1874fcf5ef2aSThomas Huth 
1875fcf5ef2aSThomas Huth     gen_flush_flags(s);
1876fcf5ef2aSThomas Huth     src2 = tcg_temp_new();
1877fcf5ef2aSThomas Huth     if (opsize == OS_BYTE)
1878fcf5ef2aSThomas Huth         tcg_gen_andi_i32(src2, DREG(insn, 9), 7);
1879fcf5ef2aSThomas Huth     else
1880fcf5ef2aSThomas Huth         tcg_gen_andi_i32(src2, DREG(insn, 9), 31);
1881fcf5ef2aSThomas Huth 
1882b32a07d4SRichard Henderson     tmp = tcg_temp_new();
1883b32a07d4SRichard Henderson     tcg_gen_shl_i32(tmp, tcg_constant_i32(1), src2);
1884fcf5ef2aSThomas Huth 
1885fcf5ef2aSThomas Huth     tcg_gen_and_i32(QREG_CC_Z, src1, tmp);
1886fcf5ef2aSThomas Huth 
1887fcf5ef2aSThomas Huth     dest = tcg_temp_new();
1888fcf5ef2aSThomas Huth     switch (op) {
1889fcf5ef2aSThomas Huth     case 1: /* bchg */
1890fcf5ef2aSThomas Huth         tcg_gen_xor_i32(dest, src1, tmp);
1891fcf5ef2aSThomas Huth         break;
1892fcf5ef2aSThomas Huth     case 2: /* bclr */
1893fcf5ef2aSThomas Huth         tcg_gen_andc_i32(dest, src1, tmp);
1894fcf5ef2aSThomas Huth         break;
1895fcf5ef2aSThomas Huth     case 3: /* bset */
1896fcf5ef2aSThomas Huth         tcg_gen_or_i32(dest, src1, tmp);
1897fcf5ef2aSThomas Huth         break;
1898fcf5ef2aSThomas Huth     default: /* btst */
1899fcf5ef2aSThomas Huth         break;
1900fcf5ef2aSThomas Huth     }
1901fcf5ef2aSThomas Huth     if (op) {
1902fcf5ef2aSThomas Huth         DEST_EA(env, insn, opsize, dest, &addr);
1903fcf5ef2aSThomas Huth     }
1904fcf5ef2aSThomas Huth }
1905fcf5ef2aSThomas Huth 
DISAS_INSN(sats)1906fcf5ef2aSThomas Huth DISAS_INSN(sats)
1907fcf5ef2aSThomas Huth {
1908fcf5ef2aSThomas Huth     TCGv reg;
1909fcf5ef2aSThomas Huth     reg = DREG(insn, 0);
1910fcf5ef2aSThomas Huth     gen_flush_flags(s);
1911fcf5ef2aSThomas Huth     gen_helper_sats(reg, reg, QREG_CC_V);
1912fcf5ef2aSThomas Huth     gen_logic_cc(s, reg, OS_LONG);
1913fcf5ef2aSThomas Huth }
1914fcf5ef2aSThomas Huth 
gen_push(DisasContext * s,TCGv val)1915fcf5ef2aSThomas Huth static void gen_push(DisasContext *s, TCGv val)
1916fcf5ef2aSThomas Huth {
1917fcf5ef2aSThomas Huth     TCGv tmp;
1918fcf5ef2aSThomas Huth 
1919fcf5ef2aSThomas Huth     tmp = tcg_temp_new();
1920fcf5ef2aSThomas Huth     tcg_gen_subi_i32(tmp, QREG_SP, 4);
192154e1e0b5SLaurent Vivier     gen_store(s, OS_LONG, tmp, val, IS_USER(s));
1922fcf5ef2aSThomas Huth     tcg_gen_mov_i32(QREG_SP, tmp);
1923fcf5ef2aSThomas Huth }
1924fcf5ef2aSThomas Huth 
mreg(int reg)19257b542eb9SLaurent Vivier static TCGv mreg(int reg)
19267b542eb9SLaurent Vivier {
19277b542eb9SLaurent Vivier     if (reg < 8) {
19287b542eb9SLaurent Vivier         /* Dx */
19297b542eb9SLaurent Vivier         return cpu_dregs[reg];
19307b542eb9SLaurent Vivier     }
19317b542eb9SLaurent Vivier     /* Ax */
19327b542eb9SLaurent Vivier     return cpu_aregs[reg & 7];
19337b542eb9SLaurent Vivier }
19347b542eb9SLaurent Vivier 
DISAS_INSN(movem)1935fcf5ef2aSThomas Huth DISAS_INSN(movem)
1936fcf5ef2aSThomas Huth {
19377b542eb9SLaurent Vivier     TCGv addr, incr, tmp, r[16];
19387b542eb9SLaurent Vivier     int is_load = (insn & 0x0400) != 0;
19397b542eb9SLaurent Vivier     int opsize = (insn & 0x40) != 0 ? OS_LONG : OS_WORD;
19407b542eb9SLaurent Vivier     uint16_t mask = read_im16(env, s);
19417b542eb9SLaurent Vivier     int mode = extract32(insn, 3, 3);
19427b542eb9SLaurent Vivier     int reg0 = REG(insn, 0);
1943fcf5ef2aSThomas Huth     int i;
1944fcf5ef2aSThomas Huth 
19457b542eb9SLaurent Vivier     tmp = cpu_aregs[reg0];
19467b542eb9SLaurent Vivier 
19477b542eb9SLaurent Vivier     switch (mode) {
19487b542eb9SLaurent Vivier     case 0: /* data register direct */
19497b542eb9SLaurent Vivier     case 1: /* addr register direct */
19507b542eb9SLaurent Vivier     do_addr_fault:
1951fcf5ef2aSThomas Huth         gen_addr_fault(s);
1952fcf5ef2aSThomas Huth         return;
19537b542eb9SLaurent Vivier 
19547b542eb9SLaurent Vivier     case 2: /* indirect */
19557b542eb9SLaurent Vivier         break;
19567b542eb9SLaurent Vivier 
19577b542eb9SLaurent Vivier     case 3: /* indirect post-increment */
19587b542eb9SLaurent Vivier         if (!is_load) {
19597b542eb9SLaurent Vivier             /* post-increment is not allowed */
19607b542eb9SLaurent Vivier             goto do_addr_fault;
1961fcf5ef2aSThomas Huth         }
19627b542eb9SLaurent Vivier         break;
19637b542eb9SLaurent Vivier 
19647b542eb9SLaurent Vivier     case 4: /* indirect pre-decrement */
19657b542eb9SLaurent Vivier         if (is_load) {
19667b542eb9SLaurent Vivier             /* pre-decrement is not allowed */
19677b542eb9SLaurent Vivier             goto do_addr_fault;
19687b542eb9SLaurent Vivier         }
1969808d77bcSLucien Murray-Pitts         /*
1970808d77bcSLucien Murray-Pitts          * We want a bare copy of the address reg, without any pre-decrement
1971808d77bcSLucien Murray-Pitts          * adjustment, as gen_lea would provide.
1972808d77bcSLucien Murray-Pitts          */
19737b542eb9SLaurent Vivier         break;
19747b542eb9SLaurent Vivier 
19757b542eb9SLaurent Vivier     default:
19767b542eb9SLaurent Vivier         tmp = gen_lea_mode(env, s, mode, reg0, opsize);
19777b542eb9SLaurent Vivier         if (IS_NULL_QREG(tmp)) {
19787b542eb9SLaurent Vivier             goto do_addr_fault;
19797b542eb9SLaurent Vivier         }
19807b542eb9SLaurent Vivier         break;
19817b542eb9SLaurent Vivier     }
19827b542eb9SLaurent Vivier 
1983fcf5ef2aSThomas Huth     addr = tcg_temp_new();
1984fcf5ef2aSThomas Huth     tcg_gen_mov_i32(addr, tmp);
19851852ce5aSRichard Henderson     incr = tcg_constant_i32(opsize_bytes(opsize));
19867b542eb9SLaurent Vivier 
1987fcf5ef2aSThomas Huth     if (is_load) {
19887b542eb9SLaurent Vivier         /* memory to register */
19897b542eb9SLaurent Vivier         for (i = 0; i < 16; i++) {
19907b542eb9SLaurent Vivier             if (mask & (1 << i)) {
199154e1e0b5SLaurent Vivier                 r[i] = gen_load(s, opsize, addr, 1, IS_USER(s));
19927b542eb9SLaurent Vivier                 tcg_gen_add_i32(addr, addr, incr);
19937b542eb9SLaurent Vivier             }
19947b542eb9SLaurent Vivier         }
19957b542eb9SLaurent Vivier         for (i = 0; i < 16; i++) {
19967b542eb9SLaurent Vivier             if (mask & (1 << i)) {
19977b542eb9SLaurent Vivier                 tcg_gen_mov_i32(mreg(i), r[i]);
19987b542eb9SLaurent Vivier             }
19997b542eb9SLaurent Vivier         }
20007b542eb9SLaurent Vivier         if (mode == 3) {
20017b542eb9SLaurent Vivier             /* post-increment: movem (An)+,X */
20027b542eb9SLaurent Vivier             tcg_gen_mov_i32(cpu_aregs[reg0], addr);
20037b542eb9SLaurent Vivier         }
2004fcf5ef2aSThomas Huth     } else {
20057b542eb9SLaurent Vivier         /* register to memory */
20067b542eb9SLaurent Vivier         if (mode == 4) {
20077b542eb9SLaurent Vivier             /* pre-decrement: movem X,-(An) */
20087b542eb9SLaurent Vivier             for (i = 15; i >= 0; i--) {
20097b542eb9SLaurent Vivier                 if ((mask << i) & 0x8000) {
20107b542eb9SLaurent Vivier                     tcg_gen_sub_i32(addr, addr, incr);
20117b542eb9SLaurent Vivier                     if (reg0 + 8 == i &&
20127b542eb9SLaurent Vivier                         m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) {
2013808d77bcSLucien Murray-Pitts                         /*
2014808d77bcSLucien Murray-Pitts                          * M68020+: if the addressing register is the
20157b542eb9SLaurent Vivier                          * register moved to memory, the value written
20167b542eb9SLaurent Vivier                          * is the initial value decremented by the size of
20177b542eb9SLaurent Vivier                          * the operation, regardless of how many actual
20187b542eb9SLaurent Vivier                          * stores have been performed until this point.
20197b542eb9SLaurent Vivier                          * M68000/M68010: the value is the initial value.
20207b542eb9SLaurent Vivier                          */
20217b542eb9SLaurent Vivier                         tmp = tcg_temp_new();
20227b542eb9SLaurent Vivier                         tcg_gen_sub_i32(tmp, cpu_aregs[reg0], incr);
202354e1e0b5SLaurent Vivier                         gen_store(s, opsize, addr, tmp, IS_USER(s));
20247b542eb9SLaurent Vivier                     } else {
202554e1e0b5SLaurent Vivier                         gen_store(s, opsize, addr, mreg(i), IS_USER(s));
2026fcf5ef2aSThomas Huth                     }
2027fcf5ef2aSThomas Huth                 }
2028fcf5ef2aSThomas Huth             }
20297b542eb9SLaurent Vivier             tcg_gen_mov_i32(cpu_aregs[reg0], addr);
20307b542eb9SLaurent Vivier         } else {
20317b542eb9SLaurent Vivier             for (i = 0; i < 16; i++) {
20327b542eb9SLaurent Vivier                 if (mask & (1 << i)) {
203354e1e0b5SLaurent Vivier                     gen_store(s, opsize, addr, mreg(i), IS_USER(s));
20347b542eb9SLaurent Vivier                     tcg_gen_add_i32(addr, addr, incr);
20357b542eb9SLaurent Vivier                 }
20367b542eb9SLaurent Vivier             }
20377b542eb9SLaurent Vivier         }
20387b542eb9SLaurent Vivier     }
20397b542eb9SLaurent Vivier }
2040fcf5ef2aSThomas Huth 
DISAS_INSN(movep)20411226e212SPavel Dovgalyuk DISAS_INSN(movep)
20421226e212SPavel Dovgalyuk {
20431226e212SPavel Dovgalyuk     uint8_t i;
20441226e212SPavel Dovgalyuk     int16_t displ;
20451226e212SPavel Dovgalyuk     TCGv reg;
20461226e212SPavel Dovgalyuk     TCGv addr;
20471226e212SPavel Dovgalyuk     TCGv abuf;
20481226e212SPavel Dovgalyuk     TCGv dbuf;
20491226e212SPavel Dovgalyuk 
20501226e212SPavel Dovgalyuk     displ = read_im16(env, s);
20511226e212SPavel Dovgalyuk 
20521226e212SPavel Dovgalyuk     addr = AREG(insn, 0);
20531226e212SPavel Dovgalyuk     reg = DREG(insn, 9);
20541226e212SPavel Dovgalyuk 
20551226e212SPavel Dovgalyuk     abuf = tcg_temp_new();
20561226e212SPavel Dovgalyuk     tcg_gen_addi_i32(abuf, addr, displ);
20571226e212SPavel Dovgalyuk     dbuf = tcg_temp_new();
20581226e212SPavel Dovgalyuk 
20591226e212SPavel Dovgalyuk     if (insn & 0x40) {
20601226e212SPavel Dovgalyuk         i = 4;
20611226e212SPavel Dovgalyuk     } else {
20621226e212SPavel Dovgalyuk         i = 2;
20631226e212SPavel Dovgalyuk     }
20641226e212SPavel Dovgalyuk 
20651226e212SPavel Dovgalyuk     if (insn & 0x80) {
20661226e212SPavel Dovgalyuk         for ( ; i > 0 ; i--) {
20671226e212SPavel Dovgalyuk             tcg_gen_shri_i32(dbuf, reg, (i - 1) * 8);
2068b7a94da9SRichard Henderson             tcg_gen_qemu_st_i32(dbuf, abuf, IS_USER(s), MO_UB);
20691226e212SPavel Dovgalyuk             if (i > 1) {
20701226e212SPavel Dovgalyuk                 tcg_gen_addi_i32(abuf, abuf, 2);
20711226e212SPavel Dovgalyuk             }
20721226e212SPavel Dovgalyuk         }
20731226e212SPavel Dovgalyuk     } else {
20741226e212SPavel Dovgalyuk         for ( ; i > 0 ; i--) {
2075b7a94da9SRichard Henderson             tcg_gen_qemu_ld_tl(dbuf, abuf, IS_USER(s), MO_UB);
20761226e212SPavel Dovgalyuk             tcg_gen_deposit_i32(reg, reg, dbuf, (i - 1) * 8, 8);
20771226e212SPavel Dovgalyuk             if (i > 1) {
20781226e212SPavel Dovgalyuk                 tcg_gen_addi_i32(abuf, abuf, 2);
20791226e212SPavel Dovgalyuk             }
20801226e212SPavel Dovgalyuk         }
20811226e212SPavel Dovgalyuk     }
20821226e212SPavel Dovgalyuk }
20831226e212SPavel Dovgalyuk 
DISAS_INSN(bitop_im)2084fcf5ef2aSThomas Huth DISAS_INSN(bitop_im)
2085fcf5ef2aSThomas Huth {
2086fcf5ef2aSThomas Huth     int opsize;
2087fcf5ef2aSThomas Huth     int op;
2088fcf5ef2aSThomas Huth     TCGv src1;
2089fcf5ef2aSThomas Huth     uint32_t mask;
2090fcf5ef2aSThomas Huth     int bitnum;
2091fcf5ef2aSThomas Huth     TCGv tmp;
2092fcf5ef2aSThomas Huth     TCGv addr;
2093fcf5ef2aSThomas Huth 
2094fcf5ef2aSThomas Huth     if ((insn & 0x38) != 0)
2095fcf5ef2aSThomas Huth         opsize = OS_BYTE;
2096fcf5ef2aSThomas Huth     else
2097fcf5ef2aSThomas Huth         opsize = OS_LONG;
2098fcf5ef2aSThomas Huth     op = (insn >> 6) & 3;
2099fcf5ef2aSThomas Huth 
2100fcf5ef2aSThomas Huth     bitnum = read_im16(env, s);
2101aece90d8SMark Cave-Ayland     if (m68k_feature(s->env, M68K_FEATURE_M68K)) {
2102fe53c2beSLaurent Vivier         if (bitnum & 0xfe00) {
2103fe53c2beSLaurent Vivier             disas_undef(env, s, insn);
2104fe53c2beSLaurent Vivier             return;
2105fe53c2beSLaurent Vivier         }
2106fe53c2beSLaurent Vivier     } else {
2107fcf5ef2aSThomas Huth         if (bitnum & 0xff00) {
2108fcf5ef2aSThomas Huth             disas_undef(env, s, insn);
2109fcf5ef2aSThomas Huth             return;
2110fcf5ef2aSThomas Huth         }
2111fe53c2beSLaurent Vivier     }
2112fcf5ef2aSThomas Huth 
2113fcf5ef2aSThomas Huth     SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
2114fcf5ef2aSThomas Huth 
2115fcf5ef2aSThomas Huth     gen_flush_flags(s);
2116fcf5ef2aSThomas Huth     if (opsize == OS_BYTE)
2117fcf5ef2aSThomas Huth         bitnum &= 7;
2118fcf5ef2aSThomas Huth     else
2119fcf5ef2aSThomas Huth         bitnum &= 31;
2120fcf5ef2aSThomas Huth     mask = 1 << bitnum;
2121fcf5ef2aSThomas Huth 
2122fcf5ef2aSThomas Huth    tcg_gen_andi_i32(QREG_CC_Z, src1, mask);
2123fcf5ef2aSThomas Huth 
2124fcf5ef2aSThomas Huth     if (op) {
2125fcf5ef2aSThomas Huth         tmp = tcg_temp_new();
2126fcf5ef2aSThomas Huth         switch (op) {
2127fcf5ef2aSThomas Huth         case 1: /* bchg */
2128fcf5ef2aSThomas Huth             tcg_gen_xori_i32(tmp, src1, mask);
2129fcf5ef2aSThomas Huth             break;
2130fcf5ef2aSThomas Huth         case 2: /* bclr */
2131fcf5ef2aSThomas Huth             tcg_gen_andi_i32(tmp, src1, ~mask);
2132fcf5ef2aSThomas Huth             break;
2133fcf5ef2aSThomas Huth         case 3: /* bset */
2134fcf5ef2aSThomas Huth             tcg_gen_ori_i32(tmp, src1, mask);
2135fcf5ef2aSThomas Huth             break;
2136fcf5ef2aSThomas Huth         default: /* btst */
2137fcf5ef2aSThomas Huth             break;
2138fcf5ef2aSThomas Huth         }
2139fcf5ef2aSThomas Huth         DEST_EA(env, insn, opsize, tmp, &addr);
2140fcf5ef2aSThomas Huth     }
2141fcf5ef2aSThomas Huth }
2142fcf5ef2aSThomas Huth 
gen_get_ccr(DisasContext * s)214301490ea8SLaurent Vivier static TCGv gen_get_ccr(DisasContext *s)
214401490ea8SLaurent Vivier {
214501490ea8SLaurent Vivier     TCGv dest;
214601490ea8SLaurent Vivier 
214701490ea8SLaurent Vivier     update_cc_op(s);
214801490ea8SLaurent Vivier     dest = tcg_temp_new();
2149ad75a51eSRichard Henderson     gen_helper_get_ccr(dest, tcg_env);
215001490ea8SLaurent Vivier     return dest;
215101490ea8SLaurent Vivier }
215201490ea8SLaurent Vivier 
gen_get_sr(DisasContext * s)215301490ea8SLaurent Vivier static TCGv gen_get_sr(DisasContext *s)
215401490ea8SLaurent Vivier {
215501490ea8SLaurent Vivier     TCGv ccr;
215601490ea8SLaurent Vivier     TCGv sr;
215701490ea8SLaurent Vivier 
215801490ea8SLaurent Vivier     ccr = gen_get_ccr(s);
215901490ea8SLaurent Vivier     sr = tcg_temp_new();
216001490ea8SLaurent Vivier     tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
216101490ea8SLaurent Vivier     tcg_gen_or_i32(sr, sr, ccr);
216201490ea8SLaurent Vivier     return sr;
216301490ea8SLaurent Vivier }
216401490ea8SLaurent Vivier 
gen_set_sr_im(DisasContext * s,uint16_t val,int ccr_only)216501490ea8SLaurent Vivier static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
216601490ea8SLaurent Vivier {
216701490ea8SLaurent Vivier     if (ccr_only) {
216801490ea8SLaurent Vivier         tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0);
216901490ea8SLaurent Vivier         tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0);
217001490ea8SLaurent Vivier         tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1);
217101490ea8SLaurent Vivier         tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0);
217201490ea8SLaurent Vivier         tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0);
217301490ea8SLaurent Vivier     } else {
2174214c6002SRichard Henderson         /* Must writeback before changing security state. */
2175214c6002SRichard Henderson         do_writebacks(s);
2176ad75a51eSRichard Henderson         gen_helper_set_sr(tcg_env, tcg_constant_i32(val));
217701490ea8SLaurent Vivier     }
217801490ea8SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
217901490ea8SLaurent Vivier }
218001490ea8SLaurent Vivier 
gen_set_sr(DisasContext * s,TCGv val,int ccr_only)2181b6a21d8dSLaurent Vivier static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only)
218201490ea8SLaurent Vivier {
218301490ea8SLaurent Vivier     if (ccr_only) {
2184ad75a51eSRichard Henderson         gen_helper_set_ccr(tcg_env, val);
218501490ea8SLaurent Vivier     } else {
2186214c6002SRichard Henderson         /* Must writeback before changing security state. */
2187214c6002SRichard Henderson         do_writebacks(s);
2188ad75a51eSRichard Henderson         gen_helper_set_sr(tcg_env, val);
218901490ea8SLaurent Vivier     }
219001490ea8SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
2191b6a21d8dSLaurent Vivier }
2192b6a21d8dSLaurent Vivier 
gen_move_to_sr(CPUM68KState * env,DisasContext * s,uint16_t insn,bool ccr_only)2193b6a21d8dSLaurent Vivier static void gen_move_to_sr(CPUM68KState *env, DisasContext *s, uint16_t insn,
2194b6a21d8dSLaurent Vivier                            bool ccr_only)
2195b6a21d8dSLaurent Vivier {
2196b6a21d8dSLaurent Vivier     if ((insn & 0x3f) == 0x3c) {
219701490ea8SLaurent Vivier         uint16_t val;
219801490ea8SLaurent Vivier         val = read_im16(env, s);
219901490ea8SLaurent Vivier         gen_set_sr_im(s, val, ccr_only);
220001490ea8SLaurent Vivier     } else {
2201b6a21d8dSLaurent Vivier         TCGv src;
2202b6a21d8dSLaurent Vivier         SRC_EA(env, src, OS_WORD, 0, NULL);
2203b6a21d8dSLaurent Vivier         gen_set_sr(s, src, ccr_only);
220401490ea8SLaurent Vivier     }
220501490ea8SLaurent Vivier }
220601490ea8SLaurent Vivier 
DISAS_INSN(arith_im)2207fcf5ef2aSThomas Huth DISAS_INSN(arith_im)
2208fcf5ef2aSThomas Huth {
2209fcf5ef2aSThomas Huth     int op;
2210fcf5ef2aSThomas Huth     TCGv im;
2211fcf5ef2aSThomas Huth     TCGv src1;
2212fcf5ef2aSThomas Huth     TCGv dest;
2213fcf5ef2aSThomas Huth     TCGv addr;
2214fcf5ef2aSThomas Huth     int opsize;
2215b5ae1edcSLaurent Vivier     bool with_SR = ((insn & 0x3f) == 0x3c);
2216fcf5ef2aSThomas Huth 
2217fcf5ef2aSThomas Huth     op = (insn >> 9) & 7;
2218fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
2219fcf5ef2aSThomas Huth     switch (opsize) {
2220fcf5ef2aSThomas Huth     case OS_BYTE:
22211852ce5aSRichard Henderson         im = tcg_constant_i32((int8_t)read_im8(env, s));
2222fcf5ef2aSThomas Huth         break;
2223fcf5ef2aSThomas Huth     case OS_WORD:
22241852ce5aSRichard Henderson         im = tcg_constant_i32((int16_t)read_im16(env, s));
2225fcf5ef2aSThomas Huth         break;
2226fcf5ef2aSThomas Huth     case OS_LONG:
22271852ce5aSRichard Henderson         im = tcg_constant_i32(read_im32(env, s));
2228fcf5ef2aSThomas Huth         break;
2229fcf5ef2aSThomas Huth     default:
22305cbc6111SRichard Henderson         g_assert_not_reached();
2231fcf5ef2aSThomas Huth     }
2232b5ae1edcSLaurent Vivier 
2233b5ae1edcSLaurent Vivier     if (with_SR) {
2234b5ae1edcSLaurent Vivier         /* SR/CCR can only be used with andi/eori/ori */
2235b5ae1edcSLaurent Vivier         if (op == 2 || op == 3 || op == 6) {
2236b5ae1edcSLaurent Vivier             disas_undef(env, s, insn);
2237b5ae1edcSLaurent Vivier             return;
2238b5ae1edcSLaurent Vivier         }
2239b5ae1edcSLaurent Vivier         switch (opsize) {
2240b5ae1edcSLaurent Vivier         case OS_BYTE:
2241b5ae1edcSLaurent Vivier             src1 = gen_get_ccr(s);
2242b5ae1edcSLaurent Vivier             break;
2243b5ae1edcSLaurent Vivier         case OS_WORD:
2244b5ae1edcSLaurent Vivier             if (IS_USER(s)) {
2245a575cbe0SRichard Henderson                 gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
2246b5ae1edcSLaurent Vivier                 return;
2247b5ae1edcSLaurent Vivier             }
2248b5ae1edcSLaurent Vivier             src1 = gen_get_sr(s);
2249b5ae1edcSLaurent Vivier             break;
22505cbc6111SRichard Henderson         default:
22515cbc6111SRichard Henderson             /* OS_LONG; others already g_assert_not_reached.  */
2252b5ae1edcSLaurent Vivier             disas_undef(env, s, insn);
2253b5ae1edcSLaurent Vivier             return;
2254b5ae1edcSLaurent Vivier         }
2255b5ae1edcSLaurent Vivier     } else {
2256fcf5ef2aSThomas Huth         SRC_EA(env, src1, opsize, 1, (op == 6) ? NULL : &addr);
2257b5ae1edcSLaurent Vivier     }
2258fcf5ef2aSThomas Huth     dest = tcg_temp_new();
2259fcf5ef2aSThomas Huth     switch (op) {
2260fcf5ef2aSThomas Huth     case 0: /* ori */
2261fcf5ef2aSThomas Huth         tcg_gen_or_i32(dest, src1, im);
2262b5ae1edcSLaurent Vivier         if (with_SR) {
2263b5ae1edcSLaurent Vivier             gen_set_sr(s, dest, opsize == OS_BYTE);
2264c7546abfSMark Cave-Ayland             gen_exit_tb(s);
2265b5ae1edcSLaurent Vivier         } else {
2266b5ae1edcSLaurent Vivier             DEST_EA(env, insn, opsize, dest, &addr);
2267fcf5ef2aSThomas Huth             gen_logic_cc(s, dest, opsize);
2268b5ae1edcSLaurent Vivier         }
2269fcf5ef2aSThomas Huth         break;
2270fcf5ef2aSThomas Huth     case 1: /* andi */
2271fcf5ef2aSThomas Huth         tcg_gen_and_i32(dest, src1, im);
2272b5ae1edcSLaurent Vivier         if (with_SR) {
2273b5ae1edcSLaurent Vivier             gen_set_sr(s, dest, opsize == OS_BYTE);
2274c7546abfSMark Cave-Ayland             gen_exit_tb(s);
2275b5ae1edcSLaurent Vivier         } else {
2276b5ae1edcSLaurent Vivier             DEST_EA(env, insn, opsize, dest, &addr);
2277fcf5ef2aSThomas Huth             gen_logic_cc(s, dest, opsize);
2278b5ae1edcSLaurent Vivier         }
2279fcf5ef2aSThomas Huth         break;
2280fcf5ef2aSThomas Huth     case 2: /* subi */
2281fcf5ef2aSThomas Huth         tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, src1, im);
2282fcf5ef2aSThomas Huth         tcg_gen_sub_i32(dest, src1, im);
2283fcf5ef2aSThomas Huth         gen_update_cc_add(dest, im, opsize);
2284fcf5ef2aSThomas Huth         set_cc_op(s, CC_OP_SUBB + opsize);
2285b5ae1edcSLaurent Vivier         DEST_EA(env, insn, opsize, dest, &addr);
2286fcf5ef2aSThomas Huth         break;
2287fcf5ef2aSThomas Huth     case 3: /* addi */
2288fcf5ef2aSThomas Huth         tcg_gen_add_i32(dest, src1, im);
2289fcf5ef2aSThomas Huth         gen_update_cc_add(dest, im, opsize);
2290fcf5ef2aSThomas Huth         tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, im);
2291fcf5ef2aSThomas Huth         set_cc_op(s, CC_OP_ADDB + opsize);
2292b5ae1edcSLaurent Vivier         DEST_EA(env, insn, opsize, dest, &addr);
2293fcf5ef2aSThomas Huth         break;
2294fcf5ef2aSThomas Huth     case 5: /* eori */
2295fcf5ef2aSThomas Huth         tcg_gen_xor_i32(dest, src1, im);
2296b5ae1edcSLaurent Vivier         if (with_SR) {
2297b5ae1edcSLaurent Vivier             gen_set_sr(s, dest, opsize == OS_BYTE);
2298c7546abfSMark Cave-Ayland             gen_exit_tb(s);
2299b5ae1edcSLaurent Vivier         } else {
2300b5ae1edcSLaurent Vivier             DEST_EA(env, insn, opsize, dest, &addr);
2301fcf5ef2aSThomas Huth             gen_logic_cc(s, dest, opsize);
2302b5ae1edcSLaurent Vivier         }
2303fcf5ef2aSThomas Huth         break;
2304fcf5ef2aSThomas Huth     case 6: /* cmpi */
2305fcf5ef2aSThomas Huth         gen_update_cc_cmp(s, src1, im, opsize);
2306fcf5ef2aSThomas Huth         break;
2307fcf5ef2aSThomas Huth     default:
2308fcf5ef2aSThomas Huth         abort();
2309fcf5ef2aSThomas Huth     }
2310fcf5ef2aSThomas Huth }
2311fcf5ef2aSThomas Huth 
DISAS_INSN(cas)231214f94406SLaurent Vivier DISAS_INSN(cas)
231314f94406SLaurent Vivier {
231414f94406SLaurent Vivier     int opsize;
231514f94406SLaurent Vivier     TCGv addr;
231614f94406SLaurent Vivier     uint16_t ext;
231714f94406SLaurent Vivier     TCGv load;
231814f94406SLaurent Vivier     TCGv cmp;
231914776ab5STony Nguyen     MemOp opc;
232014f94406SLaurent Vivier 
232114f94406SLaurent Vivier     switch ((insn >> 9) & 3) {
232214f94406SLaurent Vivier     case 1:
232314f94406SLaurent Vivier         opsize = OS_BYTE;
232414f94406SLaurent Vivier         opc = MO_SB;
232514f94406SLaurent Vivier         break;
232614f94406SLaurent Vivier     case 2:
232714f94406SLaurent Vivier         opsize = OS_WORD;
232814f94406SLaurent Vivier         opc = MO_TESW;
232914f94406SLaurent Vivier         break;
233014f94406SLaurent Vivier     case 3:
233114f94406SLaurent Vivier         opsize = OS_LONG;
233214f94406SLaurent Vivier         opc = MO_TESL;
233314f94406SLaurent Vivier         break;
233414f94406SLaurent Vivier     default:
233514f94406SLaurent Vivier         g_assert_not_reached();
233614f94406SLaurent Vivier     }
233714f94406SLaurent Vivier 
233814f94406SLaurent Vivier     ext = read_im16(env, s);
233914f94406SLaurent Vivier 
234014f94406SLaurent Vivier     /* cas Dc,Du,<EA> */
234114f94406SLaurent Vivier 
234214f94406SLaurent Vivier     addr = gen_lea(env, s, insn, opsize);
234314f94406SLaurent Vivier     if (IS_NULL_QREG(addr)) {
234414f94406SLaurent Vivier         gen_addr_fault(s);
234514f94406SLaurent Vivier         return;
234614f94406SLaurent Vivier     }
234714f94406SLaurent Vivier 
23483f215a14SLaurent Vivier     cmp = gen_extend(s, DREG(ext, 0), opsize, 1);
234914f94406SLaurent Vivier 
2350808d77bcSLucien Murray-Pitts     /*
2351808d77bcSLucien Murray-Pitts      * if  <EA> == Dc then
235214f94406SLaurent Vivier      *     <EA> = Du
235314f94406SLaurent Vivier      *     Dc = <EA> (because <EA> == Dc)
235414f94406SLaurent Vivier      * else
235514f94406SLaurent Vivier      *     Dc = <EA>
235614f94406SLaurent Vivier      */
235714f94406SLaurent Vivier 
235814f94406SLaurent Vivier     load = tcg_temp_new();
235914f94406SLaurent Vivier     tcg_gen_atomic_cmpxchg_i32(load, addr, cmp, DREG(ext, 6),
236014f94406SLaurent Vivier                                IS_USER(s), opc);
236114f94406SLaurent Vivier     /* update flags before setting cmp to load */
236214f94406SLaurent Vivier     gen_update_cc_cmp(s, load, cmp, opsize);
236314f94406SLaurent Vivier     gen_partset_reg(opsize, DREG(ext, 0), load);
236414f94406SLaurent Vivier 
2365308feb93SLaurent Vivier     switch (extract32(insn, 3, 3)) {
2366308feb93SLaurent Vivier     case 3: /* Indirect postincrement.  */
2367308feb93SLaurent Vivier         tcg_gen_addi_i32(AREG(insn, 0), addr, opsize_bytes(opsize));
2368308feb93SLaurent Vivier         break;
2369308feb93SLaurent Vivier     case 4: /* Indirect predecrememnt.  */
2370308feb93SLaurent Vivier         tcg_gen_mov_i32(AREG(insn, 0), addr);
2371308feb93SLaurent Vivier         break;
2372308feb93SLaurent Vivier     }
237314f94406SLaurent Vivier }
237414f94406SLaurent Vivier 
DISAS_INSN(cas2w)237514f94406SLaurent Vivier DISAS_INSN(cas2w)
237614f94406SLaurent Vivier {
237714f94406SLaurent Vivier     uint16_t ext1, ext2;
237814f94406SLaurent Vivier     TCGv addr1, addr2;
237914f94406SLaurent Vivier 
238014f94406SLaurent Vivier     /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
238114f94406SLaurent Vivier 
238214f94406SLaurent Vivier     ext1 = read_im16(env, s);
238314f94406SLaurent Vivier 
238414f94406SLaurent Vivier     if (ext1 & 0x8000) {
238514f94406SLaurent Vivier         /* Address Register */
238614f94406SLaurent Vivier         addr1 = AREG(ext1, 12);
238714f94406SLaurent Vivier     } else {
238814f94406SLaurent Vivier         /* Data Register */
238914f94406SLaurent Vivier         addr1 = DREG(ext1, 12);
239014f94406SLaurent Vivier     }
239114f94406SLaurent Vivier 
239214f94406SLaurent Vivier     ext2 = read_im16(env, s);
239314f94406SLaurent Vivier     if (ext2 & 0x8000) {
239414f94406SLaurent Vivier         /* Address Register */
239514f94406SLaurent Vivier         addr2 = AREG(ext2, 12);
239614f94406SLaurent Vivier     } else {
239714f94406SLaurent Vivier         /* Data Register */
239814f94406SLaurent Vivier         addr2 = DREG(ext2, 12);
239914f94406SLaurent Vivier     }
240014f94406SLaurent Vivier 
2401808d77bcSLucien Murray-Pitts     /*
2402808d77bcSLucien Murray-Pitts      * if (R1) == Dc1 && (R2) == Dc2 then
240314f94406SLaurent Vivier      *     (R1) = Du1
240414f94406SLaurent Vivier      *     (R2) = Du2
240514f94406SLaurent Vivier      * else
240614f94406SLaurent Vivier      *     Dc1 = (R1)
240714f94406SLaurent Vivier      *     Dc2 = (R2)
240814f94406SLaurent Vivier      */
240914f94406SLaurent Vivier 
2410a575cbe0SRichard Henderson     if (tb_cflags(s->base.tb) & CF_PARALLEL) {
2411ad75a51eSRichard Henderson         gen_helper_exit_atomic(tcg_env);
2412f0ddf11bSEmilio G. Cota     } else {
24131852ce5aSRichard Henderson         TCGv regs = tcg_constant_i32(REG(ext2, 6) |
24141852ce5aSRichard Henderson                                      (REG(ext1, 6) << 3) |
24151852ce5aSRichard Henderson                                      (REG(ext2, 0) << 6) |
24161852ce5aSRichard Henderson                                      (REG(ext1, 0) << 9));
2417ad75a51eSRichard Henderson         gen_helper_cas2w(tcg_env, regs, addr1, addr2);
2418f0ddf11bSEmilio G. Cota     }
241914f94406SLaurent Vivier 
242014f94406SLaurent Vivier     /* Note that cas2w also assigned to env->cc_op.  */
242114f94406SLaurent Vivier     s->cc_op = CC_OP_CMPW;
242214f94406SLaurent Vivier     s->cc_op_synced = 1;
242314f94406SLaurent Vivier }
242414f94406SLaurent Vivier 
DISAS_INSN(cas2l)242514f94406SLaurent Vivier DISAS_INSN(cas2l)
242614f94406SLaurent Vivier {
242714f94406SLaurent Vivier     uint16_t ext1, ext2;
242814f94406SLaurent Vivier     TCGv addr1, addr2, regs;
242914f94406SLaurent Vivier 
243014f94406SLaurent Vivier     /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
243114f94406SLaurent Vivier 
243214f94406SLaurent Vivier     ext1 = read_im16(env, s);
243314f94406SLaurent Vivier 
243414f94406SLaurent Vivier     if (ext1 & 0x8000) {
243514f94406SLaurent Vivier         /* Address Register */
243614f94406SLaurent Vivier         addr1 = AREG(ext1, 12);
243714f94406SLaurent Vivier     } else {
243814f94406SLaurent Vivier         /* Data Register */
243914f94406SLaurent Vivier         addr1 = DREG(ext1, 12);
244014f94406SLaurent Vivier     }
244114f94406SLaurent Vivier 
244214f94406SLaurent Vivier     ext2 = read_im16(env, s);
244314f94406SLaurent Vivier     if (ext2 & 0x8000) {
244414f94406SLaurent Vivier         /* Address Register */
244514f94406SLaurent Vivier         addr2 = AREG(ext2, 12);
244614f94406SLaurent Vivier     } else {
244714f94406SLaurent Vivier         /* Data Register */
244814f94406SLaurent Vivier         addr2 = DREG(ext2, 12);
244914f94406SLaurent Vivier     }
245014f94406SLaurent Vivier 
2451808d77bcSLucien Murray-Pitts     /*
2452808d77bcSLucien Murray-Pitts      * if (R1) == Dc1 && (R2) == Dc2 then
245314f94406SLaurent Vivier      *     (R1) = Du1
245414f94406SLaurent Vivier      *     (R2) = Du2
245514f94406SLaurent Vivier      * else
245614f94406SLaurent Vivier      *     Dc1 = (R1)
245714f94406SLaurent Vivier      *     Dc2 = (R2)
245814f94406SLaurent Vivier      */
245914f94406SLaurent Vivier 
24601852ce5aSRichard Henderson     regs = tcg_constant_i32(REG(ext2, 6) |
246114f94406SLaurent Vivier                             (REG(ext1, 6) << 3) |
246214f94406SLaurent Vivier                             (REG(ext2, 0) << 6) |
246314f94406SLaurent Vivier                             (REG(ext1, 0) << 9));
2464a575cbe0SRichard Henderson     if (tb_cflags(s->base.tb) & CF_PARALLEL) {
2465ad75a51eSRichard Henderson         gen_helper_cas2l_parallel(tcg_env, regs, addr1, addr2);
2466f0ddf11bSEmilio G. Cota     } else {
2467ad75a51eSRichard Henderson         gen_helper_cas2l(tcg_env, regs, addr1, addr2);
2468f0ddf11bSEmilio G. Cota     }
246914f94406SLaurent Vivier 
247014f94406SLaurent Vivier     /* Note that cas2l also assigned to env->cc_op.  */
247114f94406SLaurent Vivier     s->cc_op = CC_OP_CMPL;
247214f94406SLaurent Vivier     s->cc_op_synced = 1;
247314f94406SLaurent Vivier }
247414f94406SLaurent Vivier 
DISAS_INSN(byterev)2475fcf5ef2aSThomas Huth DISAS_INSN(byterev)
2476fcf5ef2aSThomas Huth {
2477fcf5ef2aSThomas Huth     TCGv reg;
2478fcf5ef2aSThomas Huth 
2479fcf5ef2aSThomas Huth     reg = DREG(insn, 0);
2480fcf5ef2aSThomas Huth     tcg_gen_bswap32_i32(reg, reg);
2481fcf5ef2aSThomas Huth }
2482fcf5ef2aSThomas Huth 
DISAS_INSN(move)2483fcf5ef2aSThomas Huth DISAS_INSN(move)
2484fcf5ef2aSThomas Huth {
2485fcf5ef2aSThomas Huth     TCGv src;
2486fcf5ef2aSThomas Huth     TCGv dest;
2487fcf5ef2aSThomas Huth     int op;
2488fcf5ef2aSThomas Huth     int opsize;
2489fcf5ef2aSThomas Huth 
2490fcf5ef2aSThomas Huth     switch (insn >> 12) {
2491fcf5ef2aSThomas Huth     case 1: /* move.b */
2492fcf5ef2aSThomas Huth         opsize = OS_BYTE;
2493fcf5ef2aSThomas Huth         break;
2494fcf5ef2aSThomas Huth     case 2: /* move.l */
2495fcf5ef2aSThomas Huth         opsize = OS_LONG;
2496fcf5ef2aSThomas Huth         break;
2497fcf5ef2aSThomas Huth     case 3: /* move.w */
2498fcf5ef2aSThomas Huth         opsize = OS_WORD;
2499fcf5ef2aSThomas Huth         break;
2500fcf5ef2aSThomas Huth     default:
2501fcf5ef2aSThomas Huth         abort();
2502fcf5ef2aSThomas Huth     }
2503fcf5ef2aSThomas Huth     SRC_EA(env, src, opsize, 1, NULL);
2504fcf5ef2aSThomas Huth     op = (insn >> 6) & 7;
2505fcf5ef2aSThomas Huth     if (op == 1) {
2506fcf5ef2aSThomas Huth         /* movea */
2507fcf5ef2aSThomas Huth         /* The value will already have been sign extended.  */
2508fcf5ef2aSThomas Huth         dest = AREG(insn, 9);
2509fcf5ef2aSThomas Huth         tcg_gen_mov_i32(dest, src);
2510fcf5ef2aSThomas Huth     } else {
2511fcf5ef2aSThomas Huth         /* normal move */
2512fcf5ef2aSThomas Huth         uint16_t dest_ea;
2513fcf5ef2aSThomas Huth         dest_ea = ((insn >> 9) & 7) | (op << 3);
2514fcf5ef2aSThomas Huth         DEST_EA(env, dest_ea, opsize, src, NULL);
2515fcf5ef2aSThomas Huth         /* This will be correct because loads sign extend.  */
2516fcf5ef2aSThomas Huth         gen_logic_cc(s, src, opsize);
2517fcf5ef2aSThomas Huth     }
2518fcf5ef2aSThomas Huth }
2519fcf5ef2aSThomas Huth 
DISAS_INSN(negx)2520fcf5ef2aSThomas Huth DISAS_INSN(negx)
2521fcf5ef2aSThomas Huth {
2522fcf5ef2aSThomas Huth     TCGv z;
2523fcf5ef2aSThomas Huth     TCGv src;
2524fcf5ef2aSThomas Huth     TCGv addr;
2525fcf5ef2aSThomas Huth     int opsize;
2526fcf5ef2aSThomas Huth 
2527fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
2528fcf5ef2aSThomas Huth     SRC_EA(env, src, opsize, 1, &addr);
2529fcf5ef2aSThomas Huth 
2530fcf5ef2aSThomas Huth     gen_flush_flags(s); /* compute old Z */
2531fcf5ef2aSThomas Huth 
2532808d77bcSLucien Murray-Pitts     /*
2533ce00ff72Szhaolichang      * Perform subtract with borrow.
2534fcf5ef2aSThomas Huth      * (X, N) =  -(src + X);
2535fcf5ef2aSThomas Huth      */
2536fcf5ef2aSThomas Huth 
25371852ce5aSRichard Henderson     z = tcg_constant_i32(0);
2538fcf5ef2aSThomas Huth     tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z);
2539fcf5ef2aSThomas Huth     tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X);
2540fcf5ef2aSThomas Huth     gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2541fcf5ef2aSThomas Huth 
2542fcf5ef2aSThomas Huth     tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
2543fcf5ef2aSThomas Huth 
2544808d77bcSLucien Murray-Pitts     /*
2545808d77bcSLucien Murray-Pitts      * Compute signed-overflow for negation.  The normal formula for
2546fcf5ef2aSThomas Huth      * subtraction is (res ^ src) & (src ^ dest), but with dest==0
2547ce00ff72Szhaolichang      * this simplifies to res & src.
2548fcf5ef2aSThomas Huth      */
2549fcf5ef2aSThomas Huth 
2550fcf5ef2aSThomas Huth     tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, src);
2551fcf5ef2aSThomas Huth 
2552fcf5ef2aSThomas Huth     /* Copy the rest of the results into place.  */
2553fcf5ef2aSThomas Huth     tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2554fcf5ef2aSThomas Huth     tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2555fcf5ef2aSThomas Huth 
2556fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_FLAGS);
2557fcf5ef2aSThomas Huth 
2558fcf5ef2aSThomas Huth     /* result is in QREG_CC_N */
2559fcf5ef2aSThomas Huth 
2560fcf5ef2aSThomas Huth     DEST_EA(env, insn, opsize, QREG_CC_N, &addr);
2561fcf5ef2aSThomas Huth }
2562fcf5ef2aSThomas Huth 
DISAS_INSN(lea)2563fcf5ef2aSThomas Huth DISAS_INSN(lea)
2564fcf5ef2aSThomas Huth {
2565fcf5ef2aSThomas Huth     TCGv reg;
2566fcf5ef2aSThomas Huth     TCGv tmp;
2567fcf5ef2aSThomas Huth 
2568fcf5ef2aSThomas Huth     reg = AREG(insn, 9);
2569fcf5ef2aSThomas Huth     tmp = gen_lea(env, s, insn, OS_LONG);
2570fcf5ef2aSThomas Huth     if (IS_NULL_QREG(tmp)) {
2571fcf5ef2aSThomas Huth         gen_addr_fault(s);
2572fcf5ef2aSThomas Huth         return;
2573fcf5ef2aSThomas Huth     }
2574fcf5ef2aSThomas Huth     tcg_gen_mov_i32(reg, tmp);
2575fcf5ef2aSThomas Huth }
2576fcf5ef2aSThomas Huth 
DISAS_INSN(clr)2577fcf5ef2aSThomas Huth DISAS_INSN(clr)
2578fcf5ef2aSThomas Huth {
2579fcf5ef2aSThomas Huth     int opsize;
25802b5e2170SLaurent Vivier     TCGv zero;
25812b5e2170SLaurent Vivier 
25821852ce5aSRichard Henderson     zero = tcg_constant_i32(0);
2583fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
25842b5e2170SLaurent Vivier     DEST_EA(env, insn, opsize, zero, NULL);
25852b5e2170SLaurent Vivier     gen_logic_cc(s, zero, opsize);
2586fcf5ef2aSThomas Huth }
2587fcf5ef2aSThomas Huth 
DISAS_INSN(move_from_ccr)2588fcf5ef2aSThomas Huth DISAS_INSN(move_from_ccr)
2589fcf5ef2aSThomas Huth {
2590fcf5ef2aSThomas Huth     TCGv ccr;
2591fcf5ef2aSThomas Huth 
2592fcf5ef2aSThomas Huth     ccr = gen_get_ccr(s);
2593fcf5ef2aSThomas Huth     DEST_EA(env, insn, OS_WORD, ccr, NULL);
2594fcf5ef2aSThomas Huth }
2595fcf5ef2aSThomas Huth 
DISAS_INSN(neg)2596fcf5ef2aSThomas Huth DISAS_INSN(neg)
2597fcf5ef2aSThomas Huth {
2598fcf5ef2aSThomas Huth     TCGv src1;
2599fcf5ef2aSThomas Huth     TCGv dest;
2600fcf5ef2aSThomas Huth     TCGv addr;
2601fcf5ef2aSThomas Huth     int opsize;
2602fcf5ef2aSThomas Huth 
2603fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
2604fcf5ef2aSThomas Huth     SRC_EA(env, src1, opsize, 1, &addr);
2605fcf5ef2aSThomas Huth     dest = tcg_temp_new();
2606fcf5ef2aSThomas Huth     tcg_gen_neg_i32(dest, src1);
2607fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_SUBB + opsize);
2608fcf5ef2aSThomas Huth     gen_update_cc_add(dest, src1, opsize);
2609fcf5ef2aSThomas Huth     tcg_gen_setcondi_i32(TCG_COND_NE, QREG_CC_X, dest, 0);
2610fcf5ef2aSThomas Huth     DEST_EA(env, insn, opsize, dest, &addr);
2611fcf5ef2aSThomas Huth }
2612fcf5ef2aSThomas Huth 
DISAS_INSN(move_to_ccr)2613fcf5ef2aSThomas Huth DISAS_INSN(move_to_ccr)
2614fcf5ef2aSThomas Huth {
2615b6a21d8dSLaurent Vivier     gen_move_to_sr(env, s, insn, true);
2616fcf5ef2aSThomas Huth }
2617fcf5ef2aSThomas Huth 
DISAS_INSN(not)2618fcf5ef2aSThomas Huth DISAS_INSN(not)
2619fcf5ef2aSThomas Huth {
2620fcf5ef2aSThomas Huth     TCGv src1;
2621fcf5ef2aSThomas Huth     TCGv dest;
2622fcf5ef2aSThomas Huth     TCGv addr;
2623fcf5ef2aSThomas Huth     int opsize;
2624fcf5ef2aSThomas Huth 
2625fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
2626fcf5ef2aSThomas Huth     SRC_EA(env, src1, opsize, 1, &addr);
2627fcf5ef2aSThomas Huth     dest = tcg_temp_new();
2628fcf5ef2aSThomas Huth     tcg_gen_not_i32(dest, src1);
2629fcf5ef2aSThomas Huth     DEST_EA(env, insn, opsize, dest, &addr);
2630fcf5ef2aSThomas Huth     gen_logic_cc(s, dest, opsize);
2631fcf5ef2aSThomas Huth }
2632fcf5ef2aSThomas Huth 
DISAS_INSN(swap)2633fcf5ef2aSThomas Huth DISAS_INSN(swap)
2634fcf5ef2aSThomas Huth {
2635fcf5ef2aSThomas Huth     TCGv src1;
2636fcf5ef2aSThomas Huth     TCGv src2;
2637fcf5ef2aSThomas Huth     TCGv reg;
2638fcf5ef2aSThomas Huth 
2639fcf5ef2aSThomas Huth     src1 = tcg_temp_new();
2640fcf5ef2aSThomas Huth     src2 = tcg_temp_new();
2641fcf5ef2aSThomas Huth     reg = DREG(insn, 0);
2642fcf5ef2aSThomas Huth     tcg_gen_shli_i32(src1, reg, 16);
2643fcf5ef2aSThomas Huth     tcg_gen_shri_i32(src2, reg, 16);
2644fcf5ef2aSThomas Huth     tcg_gen_or_i32(reg, src1, src2);
2645fcf5ef2aSThomas Huth     gen_logic_cc(s, reg, OS_LONG);
2646fcf5ef2aSThomas Huth }
2647fcf5ef2aSThomas Huth 
DISAS_INSN(bkpt)2648fcf5ef2aSThomas Huth DISAS_INSN(bkpt)
2649fcf5ef2aSThomas Huth {
26506a140586SPhilippe Mathieu-Daudé #if defined(CONFIG_USER_ONLY)
2651a575cbe0SRichard Henderson     gen_exception(s, s->base.pc_next, EXCP_DEBUG);
26526a140586SPhilippe Mathieu-Daudé #else
26530815c228SKeith Packard     /* BKPT #0 is the alternate semihosting instruction. */
26540815c228SKeith Packard     if ((insn & 7) == 0 && semihosting_test(s)) {
26550815c228SKeith Packard         gen_exception(s, s->pc, EXCP_SEMIHOSTING);
26560815c228SKeith Packard         return;
26570815c228SKeith Packard     }
26586a140586SPhilippe Mathieu-Daudé     gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
2659c1fc91b8SLaurent Vivier #endif
2660fcf5ef2aSThomas Huth }
2661fcf5ef2aSThomas Huth 
DISAS_INSN(pea)2662fcf5ef2aSThomas Huth DISAS_INSN(pea)
2663fcf5ef2aSThomas Huth {
2664fcf5ef2aSThomas Huth     TCGv tmp;
2665fcf5ef2aSThomas Huth 
2666fcf5ef2aSThomas Huth     tmp = gen_lea(env, s, insn, OS_LONG);
2667fcf5ef2aSThomas Huth     if (IS_NULL_QREG(tmp)) {
2668fcf5ef2aSThomas Huth         gen_addr_fault(s);
2669fcf5ef2aSThomas Huth         return;
2670fcf5ef2aSThomas Huth     }
2671fcf5ef2aSThomas Huth     gen_push(s, tmp);
2672fcf5ef2aSThomas Huth }
2673fcf5ef2aSThomas Huth 
DISAS_INSN(ext)2674fcf5ef2aSThomas Huth DISAS_INSN(ext)
2675fcf5ef2aSThomas Huth {
2676fcf5ef2aSThomas Huth     int op;
2677fcf5ef2aSThomas Huth     TCGv reg;
2678fcf5ef2aSThomas Huth     TCGv tmp;
2679fcf5ef2aSThomas Huth 
2680fcf5ef2aSThomas Huth     reg = DREG(insn, 0);
2681fcf5ef2aSThomas Huth     op = (insn >> 6) & 7;
2682fcf5ef2aSThomas Huth     tmp = tcg_temp_new();
2683fcf5ef2aSThomas Huth     if (op == 3)
2684fcf5ef2aSThomas Huth         tcg_gen_ext16s_i32(tmp, reg);
2685fcf5ef2aSThomas Huth     else
2686fcf5ef2aSThomas Huth         tcg_gen_ext8s_i32(tmp, reg);
2687fcf5ef2aSThomas Huth     if (op == 2)
2688fcf5ef2aSThomas Huth         gen_partset_reg(OS_WORD, reg, tmp);
2689fcf5ef2aSThomas Huth     else
2690fcf5ef2aSThomas Huth         tcg_gen_mov_i32(reg, tmp);
2691fcf5ef2aSThomas Huth     gen_logic_cc(s, tmp, OS_LONG);
2692fcf5ef2aSThomas Huth }
2693fcf5ef2aSThomas Huth 
DISAS_INSN(tst)2694fcf5ef2aSThomas Huth DISAS_INSN(tst)
2695fcf5ef2aSThomas Huth {
2696fcf5ef2aSThomas Huth     int opsize;
2697fcf5ef2aSThomas Huth     TCGv tmp;
2698fcf5ef2aSThomas Huth 
2699fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
2700fcf5ef2aSThomas Huth     SRC_EA(env, tmp, opsize, 1, NULL);
2701fcf5ef2aSThomas Huth     gen_logic_cc(s, tmp, opsize);
2702fcf5ef2aSThomas Huth }
2703fcf5ef2aSThomas Huth 
DISAS_INSN(pulse)2704fcf5ef2aSThomas Huth DISAS_INSN(pulse)
2705fcf5ef2aSThomas Huth {
2706fcf5ef2aSThomas Huth   /* Implemented as a NOP.  */
2707fcf5ef2aSThomas Huth }
2708fcf5ef2aSThomas Huth 
DISAS_INSN(illegal)2709fcf5ef2aSThomas Huth DISAS_INSN(illegal)
2710fcf5ef2aSThomas Huth {
2711a575cbe0SRichard Henderson     gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
2712fcf5ef2aSThomas Huth }
2713fcf5ef2aSThomas Huth 
DISAS_INSN(tas)2714fcf5ef2aSThomas Huth DISAS_INSN(tas)
2715fcf5ef2aSThomas Huth {
27165934dae7SRichard Henderson     int mode = extract32(insn, 3, 3);
27175934dae7SRichard Henderson     int reg0 = REG(insn, 0);
2718fcf5ef2aSThomas Huth 
27195934dae7SRichard Henderson     if (mode == 0) {
27205934dae7SRichard Henderson         /* data register direct */
27215934dae7SRichard Henderson         TCGv dest = cpu_dregs[reg0];
27225934dae7SRichard Henderson         gen_logic_cc(s, dest, OS_BYTE);
27235934dae7SRichard Henderson         tcg_gen_ori_tl(dest, dest, 0x80);
27245934dae7SRichard Henderson     } else {
27255934dae7SRichard Henderson         TCGv src1, addr;
27265934dae7SRichard Henderson 
27275934dae7SRichard Henderson         addr = gen_lea_mode(env, s, mode, reg0, OS_BYTE);
27285934dae7SRichard Henderson         if (IS_NULL_QREG(addr)) {
27295934dae7SRichard Henderson             gen_addr_fault(s);
27305934dae7SRichard Henderson             return;
27315934dae7SRichard Henderson         }
27325934dae7SRichard Henderson         src1 = tcg_temp_new();
27335934dae7SRichard Henderson         tcg_gen_atomic_fetch_or_tl(src1, addr, tcg_constant_tl(0x80),
27345934dae7SRichard Henderson                                    IS_USER(s), MO_SB);
2735fcf5ef2aSThomas Huth         gen_logic_cc(s, src1, OS_BYTE);
27365934dae7SRichard Henderson 
27375934dae7SRichard Henderson         switch (mode) {
27385934dae7SRichard Henderson         case 3: /* Indirect postincrement.  */
27395934dae7SRichard Henderson             tcg_gen_addi_i32(AREG(insn, 0), addr, 1);
27405934dae7SRichard Henderson             break;
27415934dae7SRichard Henderson         case 4: /* Indirect predecrememnt.  */
27425934dae7SRichard Henderson             tcg_gen_mov_i32(AREG(insn, 0), addr);
27435934dae7SRichard Henderson             break;
27445934dae7SRichard Henderson         }
27455934dae7SRichard Henderson     }
2746fcf5ef2aSThomas Huth }
2747fcf5ef2aSThomas Huth 
DISAS_INSN(mull)2748fcf5ef2aSThomas Huth DISAS_INSN(mull)
2749fcf5ef2aSThomas Huth {
2750fcf5ef2aSThomas Huth     uint16_t ext;
2751fcf5ef2aSThomas Huth     TCGv src1;
27528be95defSLaurent Vivier     int sign;
2753fcf5ef2aSThomas Huth 
2754fcf5ef2aSThomas Huth     ext = read_im16(env, s);
27558be95defSLaurent Vivier 
27568be95defSLaurent Vivier     sign = ext & 0x800;
27578be95defSLaurent Vivier 
27588be95defSLaurent Vivier     if (ext & 0x400) {
27598be95defSLaurent Vivier         if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
2760b9f8e55bSLaurent Vivier             gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
2761fcf5ef2aSThomas Huth             return;
2762fcf5ef2aSThomas Huth         }
27638be95defSLaurent Vivier 
2764fcf5ef2aSThomas Huth         SRC_EA(env, src1, OS_LONG, 0, NULL);
27658be95defSLaurent Vivier 
27668be95defSLaurent Vivier         if (sign) {
27678be95defSLaurent Vivier             tcg_gen_muls2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
27688be95defSLaurent Vivier         } else {
27698be95defSLaurent Vivier             tcg_gen_mulu2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
27708be95defSLaurent Vivier         }
27718be95defSLaurent Vivier         /* if Dl == Dh, 68040 returns low word */
27728be95defSLaurent Vivier         tcg_gen_mov_i32(DREG(ext, 0), QREG_CC_N);
27738be95defSLaurent Vivier         tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_Z);
27748be95defSLaurent Vivier         tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N);
27758be95defSLaurent Vivier 
27768be95defSLaurent Vivier         tcg_gen_movi_i32(QREG_CC_V, 0);
27778be95defSLaurent Vivier         tcg_gen_movi_i32(QREG_CC_C, 0);
27788be95defSLaurent Vivier 
27798be95defSLaurent Vivier         set_cc_op(s, CC_OP_FLAGS);
27808be95defSLaurent Vivier         return;
27818be95defSLaurent Vivier     }
27828be95defSLaurent Vivier     SRC_EA(env, src1, OS_LONG, 0, NULL);
2783aece90d8SMark Cave-Ayland     if (m68k_feature(s->env, M68K_FEATURE_M68K)) {
27848be95defSLaurent Vivier         tcg_gen_movi_i32(QREG_CC_C, 0);
27858be95defSLaurent Vivier         if (sign) {
27868be95defSLaurent Vivier             tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
27878be95defSLaurent Vivier             /* QREG_CC_V is -(QREG_CC_V != (QREG_CC_N >> 31)) */
27888be95defSLaurent Vivier             tcg_gen_sari_i32(QREG_CC_Z, QREG_CC_N, 31);
278927f9af76SRichard Henderson             tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V,
279027f9af76SRichard Henderson                                    QREG_CC_V, QREG_CC_Z);
27918be95defSLaurent Vivier         } else {
27928be95defSLaurent Vivier             tcg_gen_mulu2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
27938be95defSLaurent Vivier             /* QREG_CC_V is -(QREG_CC_V != 0), use QREG_CC_C as 0 */
279427f9af76SRichard Henderson             tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V,
279527f9af76SRichard Henderson                                    QREG_CC_V, QREG_CC_C);
27968be95defSLaurent Vivier         }
27978be95defSLaurent Vivier         tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_N);
27988be95defSLaurent Vivier 
27998be95defSLaurent Vivier         tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
28008be95defSLaurent Vivier 
28018be95defSLaurent Vivier         set_cc_op(s, CC_OP_FLAGS);
28028be95defSLaurent Vivier     } else {
2803808d77bcSLucien Murray-Pitts         /*
2804808d77bcSLucien Murray-Pitts          * The upper 32 bits of the product are discarded, so
2805808d77bcSLucien Murray-Pitts          * muls.l and mulu.l are functionally equivalent.
2806808d77bcSLucien Murray-Pitts          */
28078be95defSLaurent Vivier         tcg_gen_mul_i32(DREG(ext, 12), src1, DREG(ext, 12));
28088be95defSLaurent Vivier         gen_logic_cc(s, DREG(ext, 12), OS_LONG);
28098be95defSLaurent Vivier     }
2810fcf5ef2aSThomas Huth }
2811fcf5ef2aSThomas Huth 
gen_link(DisasContext * s,uint16_t insn,int32_t offset)2812fcf5ef2aSThomas Huth static void gen_link(DisasContext *s, uint16_t insn, int32_t offset)
2813fcf5ef2aSThomas Huth {
2814fcf5ef2aSThomas Huth     TCGv reg;
2815fcf5ef2aSThomas Huth     TCGv tmp;
2816fcf5ef2aSThomas Huth 
2817fcf5ef2aSThomas Huth     reg = AREG(insn, 0);
2818fcf5ef2aSThomas Huth     tmp = tcg_temp_new();
2819fcf5ef2aSThomas Huth     tcg_gen_subi_i32(tmp, QREG_SP, 4);
282054e1e0b5SLaurent Vivier     gen_store(s, OS_LONG, tmp, reg, IS_USER(s));
2821fcf5ef2aSThomas Huth     if ((insn & 7) != 7) {
2822fcf5ef2aSThomas Huth         tcg_gen_mov_i32(reg, tmp);
2823fcf5ef2aSThomas Huth     }
2824fcf5ef2aSThomas Huth     tcg_gen_addi_i32(QREG_SP, tmp, offset);
2825fcf5ef2aSThomas Huth }
2826fcf5ef2aSThomas Huth 
DISAS_INSN(link)2827fcf5ef2aSThomas Huth DISAS_INSN(link)
2828fcf5ef2aSThomas Huth {
2829fcf5ef2aSThomas Huth     int16_t offset;
2830fcf5ef2aSThomas Huth 
2831fcf5ef2aSThomas Huth     offset = read_im16(env, s);
2832fcf5ef2aSThomas Huth     gen_link(s, insn, offset);
2833fcf5ef2aSThomas Huth }
2834fcf5ef2aSThomas Huth 
DISAS_INSN(linkl)2835fcf5ef2aSThomas Huth DISAS_INSN(linkl)
2836fcf5ef2aSThomas Huth {
2837fcf5ef2aSThomas Huth     int32_t offset;
2838fcf5ef2aSThomas Huth 
2839fcf5ef2aSThomas Huth     offset = read_im32(env, s);
2840fcf5ef2aSThomas Huth     gen_link(s, insn, offset);
2841fcf5ef2aSThomas Huth }
2842fcf5ef2aSThomas Huth 
DISAS_INSN(unlk)2843fcf5ef2aSThomas Huth DISAS_INSN(unlk)
2844fcf5ef2aSThomas Huth {
2845fcf5ef2aSThomas Huth     TCGv src;
2846fcf5ef2aSThomas Huth     TCGv reg;
2847fcf5ef2aSThomas Huth     TCGv tmp;
2848fcf5ef2aSThomas Huth 
2849fcf5ef2aSThomas Huth     src = tcg_temp_new();
2850fcf5ef2aSThomas Huth     reg = AREG(insn, 0);
2851fcf5ef2aSThomas Huth     tcg_gen_mov_i32(src, reg);
285254e1e0b5SLaurent Vivier     tmp = gen_load(s, OS_LONG, src, 0, IS_USER(s));
2853fcf5ef2aSThomas Huth     tcg_gen_mov_i32(reg, tmp);
2854fcf5ef2aSThomas Huth     tcg_gen_addi_i32(QREG_SP, src, 4);
2855fcf5ef2aSThomas Huth }
2856fcf5ef2aSThomas Huth 
28576a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
DISAS_INSN(reset)28580bdb2b3bSLaurent Vivier DISAS_INSN(reset)
28590bdb2b3bSLaurent Vivier {
28600bdb2b3bSLaurent Vivier     if (IS_USER(s)) {
2861a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
28620bdb2b3bSLaurent Vivier         return;
28630bdb2b3bSLaurent Vivier     }
28640bdb2b3bSLaurent Vivier 
2865ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
28660bdb2b3bSLaurent Vivier }
28670bdb2b3bSLaurent Vivier #endif
28680bdb2b3bSLaurent Vivier 
DISAS_INSN(nop)2869fcf5ef2aSThomas Huth DISAS_INSN(nop)
2870fcf5ef2aSThomas Huth {
2871fcf5ef2aSThomas Huth }
2872fcf5ef2aSThomas Huth 
DISAS_INSN(rtd)287318059c9eSLaurent Vivier DISAS_INSN(rtd)
287418059c9eSLaurent Vivier {
287518059c9eSLaurent Vivier     TCGv tmp;
287618059c9eSLaurent Vivier     int16_t offset = read_im16(env, s);
287718059c9eSLaurent Vivier 
287854e1e0b5SLaurent Vivier     tmp = gen_load(s, OS_LONG, QREG_SP, 0, IS_USER(s));
287918059c9eSLaurent Vivier     tcg_gen_addi_i32(QREG_SP, QREG_SP, offset + 4);
288018059c9eSLaurent Vivier     gen_jmp(s, tmp);
288118059c9eSLaurent Vivier }
288218059c9eSLaurent Vivier 
DISAS_INSN(rtr)28836abcec36SLaurent Vivier DISAS_INSN(rtr)
28846abcec36SLaurent Vivier {
28856abcec36SLaurent Vivier     TCGv tmp;
28866abcec36SLaurent Vivier     TCGv ccr;
28876abcec36SLaurent Vivier     TCGv sp;
28886abcec36SLaurent Vivier 
28896abcec36SLaurent Vivier     sp = tcg_temp_new();
28906abcec36SLaurent Vivier     ccr = gen_load(s, OS_WORD, QREG_SP, 0, IS_USER(s));
28916abcec36SLaurent Vivier     tcg_gen_addi_i32(sp, QREG_SP, 2);
28926abcec36SLaurent Vivier     tmp = gen_load(s, OS_LONG, sp, 0, IS_USER(s));
28936abcec36SLaurent Vivier     tcg_gen_addi_i32(QREG_SP, sp, 4);
28946abcec36SLaurent Vivier 
28956abcec36SLaurent Vivier     gen_set_sr(s, ccr, true);
28966abcec36SLaurent Vivier 
28976abcec36SLaurent Vivier     gen_jmp(s, tmp);
28986abcec36SLaurent Vivier }
28996abcec36SLaurent Vivier 
DISAS_INSN(rts)2900fcf5ef2aSThomas Huth DISAS_INSN(rts)
2901fcf5ef2aSThomas Huth {
2902fcf5ef2aSThomas Huth     TCGv tmp;
2903fcf5ef2aSThomas Huth 
290454e1e0b5SLaurent Vivier     tmp = gen_load(s, OS_LONG, QREG_SP, 0, IS_USER(s));
2905fcf5ef2aSThomas Huth     tcg_gen_addi_i32(QREG_SP, QREG_SP, 4);
2906fcf5ef2aSThomas Huth     gen_jmp(s, tmp);
2907fcf5ef2aSThomas Huth }
2908fcf5ef2aSThomas Huth 
DISAS_INSN(jump)2909fcf5ef2aSThomas Huth DISAS_INSN(jump)
2910fcf5ef2aSThomas Huth {
2911fcf5ef2aSThomas Huth     TCGv tmp;
2912fcf5ef2aSThomas Huth 
2913808d77bcSLucien Murray-Pitts     /*
2914808d77bcSLucien Murray-Pitts      * Load the target address first to ensure correct exception
2915808d77bcSLucien Murray-Pitts      * behavior.
2916808d77bcSLucien Murray-Pitts      */
2917fcf5ef2aSThomas Huth     tmp = gen_lea(env, s, insn, OS_LONG);
2918fcf5ef2aSThomas Huth     if (IS_NULL_QREG(tmp)) {
2919fcf5ef2aSThomas Huth         gen_addr_fault(s);
2920fcf5ef2aSThomas Huth         return;
2921fcf5ef2aSThomas Huth     }
2922fcf5ef2aSThomas Huth     if ((insn & 0x40) == 0) {
2923fcf5ef2aSThomas Huth         /* jsr */
29241852ce5aSRichard Henderson         gen_push(s, tcg_constant_i32(s->pc));
2925fcf5ef2aSThomas Huth     }
2926fcf5ef2aSThomas Huth     gen_jmp(s, tmp);
2927fcf5ef2aSThomas Huth }
2928fcf5ef2aSThomas Huth 
DISAS_INSN(addsubq)2929fcf5ef2aSThomas Huth DISAS_INSN(addsubq)
2930fcf5ef2aSThomas Huth {
2931fcf5ef2aSThomas Huth     TCGv src;
2932fcf5ef2aSThomas Huth     TCGv dest;
2933fcf5ef2aSThomas Huth     TCGv val;
2934fcf5ef2aSThomas Huth     int imm;
2935fcf5ef2aSThomas Huth     TCGv addr;
2936fcf5ef2aSThomas Huth     int opsize;
2937fcf5ef2aSThomas Huth 
2938fcf5ef2aSThomas Huth     if ((insn & 070) == 010) {
2939fcf5ef2aSThomas Huth         /* Operation on address register is always long.  */
2940fcf5ef2aSThomas Huth         opsize = OS_LONG;
2941fcf5ef2aSThomas Huth     } else {
2942fcf5ef2aSThomas Huth         opsize = insn_opsize(insn);
2943fcf5ef2aSThomas Huth     }
2944fcf5ef2aSThomas Huth     SRC_EA(env, src, opsize, 1, &addr);
2945fcf5ef2aSThomas Huth     imm = (insn >> 9) & 7;
2946fcf5ef2aSThomas Huth     if (imm == 0) {
2947fcf5ef2aSThomas Huth         imm = 8;
2948fcf5ef2aSThomas Huth     }
29491852ce5aSRichard Henderson     val = tcg_constant_i32(imm);
2950fcf5ef2aSThomas Huth     dest = tcg_temp_new();
2951fcf5ef2aSThomas Huth     tcg_gen_mov_i32(dest, src);
2952fcf5ef2aSThomas Huth     if ((insn & 0x38) == 0x08) {
2953808d77bcSLucien Murray-Pitts         /*
2954808d77bcSLucien Murray-Pitts          * Don't update condition codes if the destination is an
2955808d77bcSLucien Murray-Pitts          * address register.
2956808d77bcSLucien Murray-Pitts          */
2957fcf5ef2aSThomas Huth         if (insn & 0x0100) {
2958fcf5ef2aSThomas Huth             tcg_gen_sub_i32(dest, dest, val);
2959fcf5ef2aSThomas Huth         } else {
2960fcf5ef2aSThomas Huth             tcg_gen_add_i32(dest, dest, val);
2961fcf5ef2aSThomas Huth         }
2962fcf5ef2aSThomas Huth     } else {
2963fcf5ef2aSThomas Huth         if (insn & 0x0100) {
2964fcf5ef2aSThomas Huth             tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2965fcf5ef2aSThomas Huth             tcg_gen_sub_i32(dest, dest, val);
2966fcf5ef2aSThomas Huth             set_cc_op(s, CC_OP_SUBB + opsize);
2967fcf5ef2aSThomas Huth         } else {
2968fcf5ef2aSThomas Huth             tcg_gen_add_i32(dest, dest, val);
2969fcf5ef2aSThomas Huth             tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2970fcf5ef2aSThomas Huth             set_cc_op(s, CC_OP_ADDB + opsize);
2971fcf5ef2aSThomas Huth         }
2972fcf5ef2aSThomas Huth         gen_update_cc_add(dest, val, opsize);
2973fcf5ef2aSThomas Huth     }
2974fcf5ef2aSThomas Huth     DEST_EA(env, insn, opsize, dest, &addr);
2975fcf5ef2aSThomas Huth }
2976fcf5ef2aSThomas Huth 
DISAS_INSN(branch)2977fcf5ef2aSThomas Huth DISAS_INSN(branch)
2978fcf5ef2aSThomas Huth {
2979fcf5ef2aSThomas Huth     int32_t offset;
2980fcf5ef2aSThomas Huth     uint32_t base;
2981fcf5ef2aSThomas Huth     int op;
2982fcf5ef2aSThomas Huth 
2983fcf5ef2aSThomas Huth     base = s->pc;
2984fcf5ef2aSThomas Huth     op = (insn >> 8) & 0xf;
2985fcf5ef2aSThomas Huth     offset = (int8_t)insn;
2986fcf5ef2aSThomas Huth     if (offset == 0) {
2987fcf5ef2aSThomas Huth         offset = (int16_t)read_im16(env, s);
2988fcf5ef2aSThomas Huth     } else if (offset == -1) {
2989fcf5ef2aSThomas Huth         offset = read_im32(env, s);
2990fcf5ef2aSThomas Huth     }
2991fcf5ef2aSThomas Huth     if (op == 1) {
2992fcf5ef2aSThomas Huth         /* bsr */
29931852ce5aSRichard Henderson         gen_push(s, tcg_constant_i32(s->pc));
2994fcf5ef2aSThomas Huth     }
2995fcf5ef2aSThomas Huth     if (op > 1) {
2996fcf5ef2aSThomas Huth         /* Bcc */
299789fa312bSPhilippe Mathieu-Daudé         TCGLabel *l1 = gen_new_label();
2998fcf5ef2aSThomas Huth         gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
29998115fc93SRichard Henderson         gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
3000fcf5ef2aSThomas Huth         gen_set_label(l1);
30018115fc93SRichard Henderson         gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
3002fcf5ef2aSThomas Huth     } else {
3003fcf5ef2aSThomas Huth         /* Unconditional branch.  */
30047cd7b5caSLaurent Vivier         update_cc_op(s);
30058115fc93SRichard Henderson         gen_jmp_tb(s, 0, base + offset, s->base.pc_next);
3006fcf5ef2aSThomas Huth     }
3007fcf5ef2aSThomas Huth }
3008fcf5ef2aSThomas Huth 
DISAS_INSN(moveq)3009fcf5ef2aSThomas Huth DISAS_INSN(moveq)
3010fcf5ef2aSThomas Huth {
30112b5e2170SLaurent Vivier     tcg_gen_movi_i32(DREG(insn, 9), (int8_t)insn);
30122b5e2170SLaurent Vivier     gen_logic_cc(s, DREG(insn, 9), OS_LONG);
3013fcf5ef2aSThomas Huth }
3014fcf5ef2aSThomas Huth 
DISAS_INSN(mvzs)3015fcf5ef2aSThomas Huth DISAS_INSN(mvzs)
3016fcf5ef2aSThomas Huth {
3017fcf5ef2aSThomas Huth     int opsize;
3018fcf5ef2aSThomas Huth     TCGv src;
3019fcf5ef2aSThomas Huth     TCGv reg;
3020fcf5ef2aSThomas Huth 
3021fcf5ef2aSThomas Huth     if (insn & 0x40)
3022fcf5ef2aSThomas Huth         opsize = OS_WORD;
3023fcf5ef2aSThomas Huth     else
3024fcf5ef2aSThomas Huth         opsize = OS_BYTE;
3025fcf5ef2aSThomas Huth     SRC_EA(env, src, opsize, (insn & 0x80) == 0, NULL);
3026fcf5ef2aSThomas Huth     reg = DREG(insn, 9);
3027fcf5ef2aSThomas Huth     tcg_gen_mov_i32(reg, src);
3028fcf5ef2aSThomas Huth     gen_logic_cc(s, src, opsize);
3029fcf5ef2aSThomas Huth }
3030fcf5ef2aSThomas Huth 
DISAS_INSN(or)3031fcf5ef2aSThomas Huth DISAS_INSN(or)
3032fcf5ef2aSThomas Huth {
3033fcf5ef2aSThomas Huth     TCGv reg;
3034fcf5ef2aSThomas Huth     TCGv dest;
3035fcf5ef2aSThomas Huth     TCGv src;
3036fcf5ef2aSThomas Huth     TCGv addr;
3037fcf5ef2aSThomas Huth     int opsize;
3038fcf5ef2aSThomas Huth 
3039fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
30403f215a14SLaurent Vivier     reg = gen_extend(s, DREG(insn, 9), opsize, 0);
3041fcf5ef2aSThomas Huth     dest = tcg_temp_new();
3042fcf5ef2aSThomas Huth     if (insn & 0x100) {
3043fcf5ef2aSThomas Huth         SRC_EA(env, src, opsize, 0, &addr);
3044fcf5ef2aSThomas Huth         tcg_gen_or_i32(dest, src, reg);
3045fcf5ef2aSThomas Huth         DEST_EA(env, insn, opsize, dest, &addr);
3046fcf5ef2aSThomas Huth     } else {
3047fcf5ef2aSThomas Huth         SRC_EA(env, src, opsize, 0, NULL);
3048fcf5ef2aSThomas Huth         tcg_gen_or_i32(dest, src, reg);
3049fcf5ef2aSThomas Huth         gen_partset_reg(opsize, DREG(insn, 9), dest);
3050fcf5ef2aSThomas Huth     }
3051fcf5ef2aSThomas Huth     gen_logic_cc(s, dest, opsize);
3052fcf5ef2aSThomas Huth }
3053fcf5ef2aSThomas Huth 
DISAS_INSN(suba)3054fcf5ef2aSThomas Huth DISAS_INSN(suba)
3055fcf5ef2aSThomas Huth {
3056fcf5ef2aSThomas Huth     TCGv src;
3057fcf5ef2aSThomas Huth     TCGv reg;
3058fcf5ef2aSThomas Huth 
3059fcf5ef2aSThomas Huth     SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
3060fcf5ef2aSThomas Huth     reg = AREG(insn, 9);
3061fcf5ef2aSThomas Huth     tcg_gen_sub_i32(reg, reg, src);
3062fcf5ef2aSThomas Huth }
3063fcf5ef2aSThomas Huth 
gen_subx(DisasContext * s,TCGv src,TCGv dest,int opsize)3064fcf5ef2aSThomas Huth static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
3065fcf5ef2aSThomas Huth {
3066b32a07d4SRichard Henderson     TCGv tmp, zero;
3067fcf5ef2aSThomas Huth 
3068fcf5ef2aSThomas Huth     gen_flush_flags(s); /* compute old Z */
3069fcf5ef2aSThomas Huth 
3070808d77bcSLucien Murray-Pitts     /*
3071ce00ff72Szhaolichang      * Perform subtract with borrow.
3072fcf5ef2aSThomas Huth      * (X, N) = dest - (src + X);
3073fcf5ef2aSThomas Huth      */
3074fcf5ef2aSThomas Huth 
3075b32a07d4SRichard Henderson     zero = tcg_constant_i32(0);
3076b32a07d4SRichard Henderson     tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, zero, QREG_CC_X, zero);
3077b32a07d4SRichard Henderson     tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, dest, zero, QREG_CC_N, QREG_CC_X);
3078fcf5ef2aSThomas Huth     gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3079fcf5ef2aSThomas Huth     tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
3080fcf5ef2aSThomas Huth 
3081ce00ff72Szhaolichang     /* Compute signed-overflow for subtract.  */
3082fcf5ef2aSThomas Huth 
3083b32a07d4SRichard Henderson     tmp = tcg_temp_new();
3084fcf5ef2aSThomas Huth     tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, dest);
3085fcf5ef2aSThomas Huth     tcg_gen_xor_i32(tmp, dest, src);
3086fcf5ef2aSThomas Huth     tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, tmp);
3087fcf5ef2aSThomas Huth 
3088fcf5ef2aSThomas Huth     /* Copy the rest of the results into place.  */
3089fcf5ef2aSThomas Huth     tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
3090fcf5ef2aSThomas Huth     tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
3091fcf5ef2aSThomas Huth 
3092fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_FLAGS);
3093fcf5ef2aSThomas Huth 
3094fcf5ef2aSThomas Huth     /* result is in QREG_CC_N */
3095fcf5ef2aSThomas Huth }
3096fcf5ef2aSThomas Huth 
DISAS_INSN(subx_reg)3097fcf5ef2aSThomas Huth DISAS_INSN(subx_reg)
3098fcf5ef2aSThomas Huth {
3099fcf5ef2aSThomas Huth     TCGv dest;
3100fcf5ef2aSThomas Huth     TCGv src;
3101fcf5ef2aSThomas Huth     int opsize;
3102fcf5ef2aSThomas Huth 
3103fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
3104fcf5ef2aSThomas Huth 
31053f215a14SLaurent Vivier     src = gen_extend(s, DREG(insn, 0), opsize, 1);
31063f215a14SLaurent Vivier     dest = gen_extend(s, DREG(insn, 9), opsize, 1);
3107fcf5ef2aSThomas Huth 
3108fcf5ef2aSThomas Huth     gen_subx(s, src, dest, opsize);
3109fcf5ef2aSThomas Huth 
3110fcf5ef2aSThomas Huth     gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
3111fcf5ef2aSThomas Huth }
3112fcf5ef2aSThomas Huth 
DISAS_INSN(subx_mem)3113fcf5ef2aSThomas Huth DISAS_INSN(subx_mem)
3114fcf5ef2aSThomas Huth {
3115fcf5ef2aSThomas Huth     TCGv src;
3116fcf5ef2aSThomas Huth     TCGv addr_src;
3117fcf5ef2aSThomas Huth     TCGv dest;
3118fcf5ef2aSThomas Huth     TCGv addr_dest;
3119fcf5ef2aSThomas Huth     int opsize;
3120fcf5ef2aSThomas Huth 
3121fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
3122fcf5ef2aSThomas Huth 
3123fcf5ef2aSThomas Huth     addr_src = AREG(insn, 0);
3124355d4d1cSPavel Dovgalyuk     tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
312554e1e0b5SLaurent Vivier     src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
3126fcf5ef2aSThomas Huth 
3127fcf5ef2aSThomas Huth     addr_dest = AREG(insn, 9);
3128355d4d1cSPavel Dovgalyuk     tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
312954e1e0b5SLaurent Vivier     dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
3130fcf5ef2aSThomas Huth 
3131fcf5ef2aSThomas Huth     gen_subx(s, src, dest, opsize);
3132fcf5ef2aSThomas Huth 
313354e1e0b5SLaurent Vivier     gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
3134fcf5ef2aSThomas Huth }
3135fcf5ef2aSThomas Huth 
DISAS_INSN(mov3q)3136fcf5ef2aSThomas Huth DISAS_INSN(mov3q)
3137fcf5ef2aSThomas Huth {
3138fcf5ef2aSThomas Huth     TCGv src;
3139fcf5ef2aSThomas Huth     int val;
3140fcf5ef2aSThomas Huth 
3141fcf5ef2aSThomas Huth     val = (insn >> 9) & 7;
31421852ce5aSRichard Henderson     if (val == 0) {
3143fcf5ef2aSThomas Huth         val = -1;
31441852ce5aSRichard Henderson     }
31451852ce5aSRichard Henderson     src = tcg_constant_i32(val);
3146fcf5ef2aSThomas Huth     gen_logic_cc(s, src, OS_LONG);
3147fcf5ef2aSThomas Huth     DEST_EA(env, insn, OS_LONG, src, NULL);
3148fcf5ef2aSThomas Huth }
3149fcf5ef2aSThomas Huth 
DISAS_INSN(cmp)3150fcf5ef2aSThomas Huth DISAS_INSN(cmp)
3151fcf5ef2aSThomas Huth {
3152fcf5ef2aSThomas Huth     TCGv src;
3153fcf5ef2aSThomas Huth     TCGv reg;
3154fcf5ef2aSThomas Huth     int opsize;
3155fcf5ef2aSThomas Huth 
3156fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
3157fcf5ef2aSThomas Huth     SRC_EA(env, src, opsize, 1, NULL);
31583f215a14SLaurent Vivier     reg = gen_extend(s, DREG(insn, 9), opsize, 1);
3159fcf5ef2aSThomas Huth     gen_update_cc_cmp(s, reg, src, opsize);
3160fcf5ef2aSThomas Huth }
3161fcf5ef2aSThomas Huth 
DISAS_INSN(cmpa)3162fcf5ef2aSThomas Huth DISAS_INSN(cmpa)
3163fcf5ef2aSThomas Huth {
3164fcf5ef2aSThomas Huth     int opsize;
3165fcf5ef2aSThomas Huth     TCGv src;
3166fcf5ef2aSThomas Huth     TCGv reg;
3167fcf5ef2aSThomas Huth 
3168fcf5ef2aSThomas Huth     if (insn & 0x100) {
3169fcf5ef2aSThomas Huth         opsize = OS_LONG;
3170fcf5ef2aSThomas Huth     } else {
3171fcf5ef2aSThomas Huth         opsize = OS_WORD;
3172fcf5ef2aSThomas Huth     }
3173fcf5ef2aSThomas Huth     SRC_EA(env, src, opsize, 1, NULL);
3174fcf5ef2aSThomas Huth     reg = AREG(insn, 9);
3175fcf5ef2aSThomas Huth     gen_update_cc_cmp(s, reg, src, OS_LONG);
3176fcf5ef2aSThomas Huth }
3177fcf5ef2aSThomas Huth 
DISAS_INSN(cmpm)3178817af1c7SLaurent Vivier DISAS_INSN(cmpm)
3179817af1c7SLaurent Vivier {
3180817af1c7SLaurent Vivier     int opsize = insn_opsize(insn);
3181817af1c7SLaurent Vivier     TCGv src, dst;
3182817af1c7SLaurent Vivier 
3183817af1c7SLaurent Vivier     /* Post-increment load (mode 3) from Ay.  */
3184817af1c7SLaurent Vivier     src = gen_ea_mode(env, s, 3, REG(insn, 0), opsize,
318554e1e0b5SLaurent Vivier                       NULL_QREG, NULL, EA_LOADS, IS_USER(s));
3186817af1c7SLaurent Vivier     /* Post-increment load (mode 3) from Ax.  */
3187817af1c7SLaurent Vivier     dst = gen_ea_mode(env, s, 3, REG(insn, 9), opsize,
318854e1e0b5SLaurent Vivier                       NULL_QREG, NULL, EA_LOADS, IS_USER(s));
3189817af1c7SLaurent Vivier 
3190817af1c7SLaurent Vivier     gen_update_cc_cmp(s, dst, src, opsize);
3191817af1c7SLaurent Vivier }
3192817af1c7SLaurent Vivier 
DISAS_INSN(eor)3193fcf5ef2aSThomas Huth DISAS_INSN(eor)
3194fcf5ef2aSThomas Huth {
3195fcf5ef2aSThomas Huth     TCGv src;
3196fcf5ef2aSThomas Huth     TCGv dest;
3197fcf5ef2aSThomas Huth     TCGv addr;
3198fcf5ef2aSThomas Huth     int opsize;
3199fcf5ef2aSThomas Huth 
3200fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
3201fcf5ef2aSThomas Huth 
3202fcf5ef2aSThomas Huth     SRC_EA(env, src, opsize, 0, &addr);
3203fcf5ef2aSThomas Huth     dest = tcg_temp_new();
3204fcf5ef2aSThomas Huth     tcg_gen_xor_i32(dest, src, DREG(insn, 9));
3205fcf5ef2aSThomas Huth     gen_logic_cc(s, dest, opsize);
3206fcf5ef2aSThomas Huth     DEST_EA(env, insn, opsize, dest, &addr);
3207fcf5ef2aSThomas Huth }
3208fcf5ef2aSThomas Huth 
do_exg(TCGv reg1,TCGv reg2)3209fcf5ef2aSThomas Huth static void do_exg(TCGv reg1, TCGv reg2)
3210fcf5ef2aSThomas Huth {
3211fcf5ef2aSThomas Huth     TCGv temp = tcg_temp_new();
3212fcf5ef2aSThomas Huth     tcg_gen_mov_i32(temp, reg1);
3213fcf5ef2aSThomas Huth     tcg_gen_mov_i32(reg1, reg2);
3214fcf5ef2aSThomas Huth     tcg_gen_mov_i32(reg2, temp);
3215fcf5ef2aSThomas Huth }
3216fcf5ef2aSThomas Huth 
DISAS_INSN(exg_dd)3217fcf5ef2aSThomas Huth DISAS_INSN(exg_dd)
3218fcf5ef2aSThomas Huth {
3219fcf5ef2aSThomas Huth     /* exchange Dx and Dy */
3220fcf5ef2aSThomas Huth     do_exg(DREG(insn, 9), DREG(insn, 0));
3221fcf5ef2aSThomas Huth }
3222fcf5ef2aSThomas Huth 
DISAS_INSN(exg_aa)3223fcf5ef2aSThomas Huth DISAS_INSN(exg_aa)
3224fcf5ef2aSThomas Huth {
3225fcf5ef2aSThomas Huth     /* exchange Ax and Ay */
3226fcf5ef2aSThomas Huth     do_exg(AREG(insn, 9), AREG(insn, 0));
3227fcf5ef2aSThomas Huth }
3228fcf5ef2aSThomas Huth 
DISAS_INSN(exg_da)3229fcf5ef2aSThomas Huth DISAS_INSN(exg_da)
3230fcf5ef2aSThomas Huth {
3231fcf5ef2aSThomas Huth     /* exchange Dx and Ay */
3232fcf5ef2aSThomas Huth     do_exg(DREG(insn, 9), AREG(insn, 0));
3233fcf5ef2aSThomas Huth }
3234fcf5ef2aSThomas Huth 
DISAS_INSN(and)3235fcf5ef2aSThomas Huth DISAS_INSN(and)
3236fcf5ef2aSThomas Huth {
3237fcf5ef2aSThomas Huth     TCGv src;
3238fcf5ef2aSThomas Huth     TCGv reg;
3239fcf5ef2aSThomas Huth     TCGv dest;
3240fcf5ef2aSThomas Huth     TCGv addr;
3241fcf5ef2aSThomas Huth     int opsize;
3242fcf5ef2aSThomas Huth 
3243fcf5ef2aSThomas Huth     dest = tcg_temp_new();
3244fcf5ef2aSThomas Huth 
3245fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
3246fcf5ef2aSThomas Huth     reg = DREG(insn, 9);
3247fcf5ef2aSThomas Huth     if (insn & 0x100) {
3248fcf5ef2aSThomas Huth         SRC_EA(env, src, opsize, 0, &addr);
3249fcf5ef2aSThomas Huth         tcg_gen_and_i32(dest, src, reg);
3250fcf5ef2aSThomas Huth         DEST_EA(env, insn, opsize, dest, &addr);
3251fcf5ef2aSThomas Huth     } else {
3252fcf5ef2aSThomas Huth         SRC_EA(env, src, opsize, 0, NULL);
3253fcf5ef2aSThomas Huth         tcg_gen_and_i32(dest, src, reg);
3254fcf5ef2aSThomas Huth         gen_partset_reg(opsize, reg, dest);
3255fcf5ef2aSThomas Huth     }
3256fcf5ef2aSThomas Huth     gen_logic_cc(s, dest, opsize);
3257fcf5ef2aSThomas Huth }
3258fcf5ef2aSThomas Huth 
DISAS_INSN(adda)3259fcf5ef2aSThomas Huth DISAS_INSN(adda)
3260fcf5ef2aSThomas Huth {
3261fcf5ef2aSThomas Huth     TCGv src;
3262fcf5ef2aSThomas Huth     TCGv reg;
3263fcf5ef2aSThomas Huth 
3264fcf5ef2aSThomas Huth     SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
3265fcf5ef2aSThomas Huth     reg = AREG(insn, 9);
3266fcf5ef2aSThomas Huth     tcg_gen_add_i32(reg, reg, src);
3267fcf5ef2aSThomas Huth }
3268fcf5ef2aSThomas Huth 
gen_addx(DisasContext * s,TCGv src,TCGv dest,int opsize)3269fcf5ef2aSThomas Huth static inline void gen_addx(DisasContext *s, TCGv src, TCGv dest, int opsize)
3270fcf5ef2aSThomas Huth {
3271b32a07d4SRichard Henderson     TCGv tmp, zero;
3272fcf5ef2aSThomas Huth 
3273fcf5ef2aSThomas Huth     gen_flush_flags(s); /* compute old Z */
3274fcf5ef2aSThomas Huth 
3275808d77bcSLucien Murray-Pitts     /*
3276808d77bcSLucien Murray-Pitts      * Perform addition with carry.
3277fcf5ef2aSThomas Huth      * (X, N) = src + dest + X;
3278fcf5ef2aSThomas Huth      */
3279fcf5ef2aSThomas Huth 
3280b32a07d4SRichard Henderson     zero = tcg_constant_i32(0);
3281b32a07d4SRichard Henderson     tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_X, zero, dest, zero);
3282b32a07d4SRichard Henderson     tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, zero);
3283fcf5ef2aSThomas Huth     gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3284fcf5ef2aSThomas Huth 
3285fcf5ef2aSThomas Huth     /* Compute signed-overflow for addition.  */
3286fcf5ef2aSThomas Huth 
3287b32a07d4SRichard Henderson     tmp = tcg_temp_new();
3288fcf5ef2aSThomas Huth     tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
3289fcf5ef2aSThomas Huth     tcg_gen_xor_i32(tmp, dest, src);
3290fcf5ef2aSThomas Huth     tcg_gen_andc_i32(QREG_CC_V, QREG_CC_V, tmp);
3291fcf5ef2aSThomas Huth 
3292fcf5ef2aSThomas Huth     /* Copy the rest of the results into place.  */
3293fcf5ef2aSThomas Huth     tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
3294fcf5ef2aSThomas Huth     tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
3295fcf5ef2aSThomas Huth 
3296fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_FLAGS);
3297fcf5ef2aSThomas Huth 
3298fcf5ef2aSThomas Huth     /* result is in QREG_CC_N */
3299fcf5ef2aSThomas Huth }
3300fcf5ef2aSThomas Huth 
DISAS_INSN(addx_reg)3301fcf5ef2aSThomas Huth DISAS_INSN(addx_reg)
3302fcf5ef2aSThomas Huth {
3303fcf5ef2aSThomas Huth     TCGv dest;
3304fcf5ef2aSThomas Huth     TCGv src;
3305fcf5ef2aSThomas Huth     int opsize;
3306fcf5ef2aSThomas Huth 
3307fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
3308fcf5ef2aSThomas Huth 
33093f215a14SLaurent Vivier     dest = gen_extend(s, DREG(insn, 9), opsize, 1);
33103f215a14SLaurent Vivier     src = gen_extend(s, DREG(insn, 0), opsize, 1);
3311fcf5ef2aSThomas Huth 
3312fcf5ef2aSThomas Huth     gen_addx(s, src, dest, opsize);
3313fcf5ef2aSThomas Huth 
3314fcf5ef2aSThomas Huth     gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
3315fcf5ef2aSThomas Huth }
3316fcf5ef2aSThomas Huth 
DISAS_INSN(addx_mem)3317fcf5ef2aSThomas Huth DISAS_INSN(addx_mem)
3318fcf5ef2aSThomas Huth {
3319fcf5ef2aSThomas Huth     TCGv src;
3320fcf5ef2aSThomas Huth     TCGv addr_src;
3321fcf5ef2aSThomas Huth     TCGv dest;
3322fcf5ef2aSThomas Huth     TCGv addr_dest;
3323fcf5ef2aSThomas Huth     int opsize;
3324fcf5ef2aSThomas Huth 
3325fcf5ef2aSThomas Huth     opsize = insn_opsize(insn);
3326fcf5ef2aSThomas Huth 
3327fcf5ef2aSThomas Huth     addr_src = AREG(insn, 0);
3328fcf5ef2aSThomas Huth     tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
332954e1e0b5SLaurent Vivier     src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
3330fcf5ef2aSThomas Huth 
3331fcf5ef2aSThomas Huth     addr_dest = AREG(insn, 9);
3332fcf5ef2aSThomas Huth     tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
333354e1e0b5SLaurent Vivier     dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
3334fcf5ef2aSThomas Huth 
3335fcf5ef2aSThomas Huth     gen_addx(s, src, dest, opsize);
3336fcf5ef2aSThomas Huth 
333754e1e0b5SLaurent Vivier     gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
3338fcf5ef2aSThomas Huth }
3339fcf5ef2aSThomas Huth 
shift_im(DisasContext * s,uint16_t insn,int opsize)3340367790ccSRichard Henderson static inline void shift_im(DisasContext *s, uint16_t insn, int opsize)
3341367790ccSRichard Henderson {
3342367790ccSRichard Henderson     int count = (insn >> 9) & 7;
3343367790ccSRichard Henderson     int logical = insn & 8;
3344367790ccSRichard Henderson     int left = insn & 0x100;
3345367790ccSRichard Henderson     int bits = opsize_bytes(opsize) * 8;
33463f215a14SLaurent Vivier     TCGv reg = gen_extend(s, DREG(insn, 0), opsize, !logical);
3347367790ccSRichard Henderson 
3348367790ccSRichard Henderson     if (count == 0) {
3349367790ccSRichard Henderson         count = 8;
3350367790ccSRichard Henderson     }
3351367790ccSRichard Henderson 
3352367790ccSRichard Henderson     tcg_gen_movi_i32(QREG_CC_V, 0);
3353367790ccSRichard Henderson     if (left) {
3354367790ccSRichard Henderson         tcg_gen_shri_i32(QREG_CC_C, reg, bits - count);
3355367790ccSRichard Henderson         tcg_gen_shli_i32(QREG_CC_N, reg, count);
3356367790ccSRichard Henderson 
3357808d77bcSLucien Murray-Pitts         /*
3358808d77bcSLucien Murray-Pitts          * Note that ColdFire always clears V (done above),
3359808d77bcSLucien Murray-Pitts          * while M68000 sets if the most significant bit is changed at
3360808d77bcSLucien Murray-Pitts          * any time during the shift operation.
3361808d77bcSLucien Murray-Pitts          */
3362aece90d8SMark Cave-Ayland         if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) {
3363367790ccSRichard Henderson             /* if shift count >= bits, V is (reg != 0) */
3364367790ccSRichard Henderson             if (count >= bits) {
336527f9af76SRichard Henderson                 tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V, reg, QREG_CC_V);
3366367790ccSRichard Henderson             } else {
3367367790ccSRichard Henderson                 TCGv t0 = tcg_temp_new();
3368367790ccSRichard Henderson                 tcg_gen_sari_i32(QREG_CC_V, reg, bits - 1);
3369367790ccSRichard Henderson                 tcg_gen_sari_i32(t0, reg, bits - count - 1);
337027f9af76SRichard Henderson                 tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, t0);
3371367790ccSRichard Henderson             }
3372367790ccSRichard Henderson         }
3373367790ccSRichard Henderson     } else {
3374367790ccSRichard Henderson         tcg_gen_shri_i32(QREG_CC_C, reg, count - 1);
3375367790ccSRichard Henderson         if (logical) {
3376367790ccSRichard Henderson             tcg_gen_shri_i32(QREG_CC_N, reg, count);
3377367790ccSRichard Henderson         } else {
3378367790ccSRichard Henderson             tcg_gen_sari_i32(QREG_CC_N, reg, count);
3379367790ccSRichard Henderson         }
3380367790ccSRichard Henderson     }
3381367790ccSRichard Henderson 
3382367790ccSRichard Henderson     gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3383367790ccSRichard Henderson     tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3384367790ccSRichard Henderson     tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3385367790ccSRichard Henderson     tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
3386367790ccSRichard Henderson 
3387367790ccSRichard Henderson     gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N);
3388367790ccSRichard Henderson     set_cc_op(s, CC_OP_FLAGS);
3389367790ccSRichard Henderson }
3390367790ccSRichard Henderson 
shift_reg(DisasContext * s,uint16_t insn,int opsize)3391367790ccSRichard Henderson static inline void shift_reg(DisasContext *s, uint16_t insn, int opsize)
3392367790ccSRichard Henderson {
3393367790ccSRichard Henderson     int logical = insn & 8;
3394367790ccSRichard Henderson     int left = insn & 0x100;
3395367790ccSRichard Henderson     int bits = opsize_bytes(opsize) * 8;
33963f215a14SLaurent Vivier     TCGv reg = gen_extend(s, DREG(insn, 0), opsize, !logical);
3397367790ccSRichard Henderson     TCGv s32;
3398367790ccSRichard Henderson     TCGv_i64 t64, s64;
3399367790ccSRichard Henderson 
3400367790ccSRichard Henderson     t64 = tcg_temp_new_i64();
3401367790ccSRichard Henderson     s64 = tcg_temp_new_i64();
3402367790ccSRichard Henderson     s32 = tcg_temp_new();
3403367790ccSRichard Henderson 
3404808d77bcSLucien Murray-Pitts     /*
3405808d77bcSLucien Murray-Pitts      * Note that m68k truncates the shift count modulo 64, not 32.
3406808d77bcSLucien Murray-Pitts      * In addition, a 64-bit shift makes it easy to find "the last
3407808d77bcSLucien Murray-Pitts      * bit shifted out", for the carry flag.
3408808d77bcSLucien Murray-Pitts      */
3409367790ccSRichard Henderson     tcg_gen_andi_i32(s32, DREG(insn, 9), 63);
3410367790ccSRichard Henderson     tcg_gen_extu_i32_i64(s64, s32);
3411367790ccSRichard Henderson     tcg_gen_extu_i32_i64(t64, reg);
3412367790ccSRichard Henderson 
3413367790ccSRichard Henderson     /* Optimistically set V=0.  Also used as a zero source below.  */
3414367790ccSRichard Henderson     tcg_gen_movi_i32(QREG_CC_V, 0);
3415367790ccSRichard Henderson     if (left) {
3416367790ccSRichard Henderson         tcg_gen_shl_i64(t64, t64, s64);
3417367790ccSRichard Henderson 
3418367790ccSRichard Henderson         if (opsize == OS_LONG) {
3419367790ccSRichard Henderson             tcg_gen_extr_i64_i32(QREG_CC_N, QREG_CC_C, t64);
3420367790ccSRichard Henderson             /* Note that C=0 if shift count is 0, and we get that for free.  */
3421367790ccSRichard Henderson         } else {
34221852ce5aSRichard Henderson             TCGv zero = tcg_constant_i32(0);
3423367790ccSRichard Henderson             tcg_gen_extrl_i64_i32(QREG_CC_N, t64);
3424367790ccSRichard Henderson             tcg_gen_shri_i32(QREG_CC_C, QREG_CC_N, bits);
3425367790ccSRichard Henderson             tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
3426367790ccSRichard Henderson                                 s32, zero, zero, QREG_CC_C);
3427367790ccSRichard Henderson         }
3428367790ccSRichard Henderson         tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3429367790ccSRichard Henderson 
3430367790ccSRichard Henderson         /* X = C, but only if the shift count was non-zero.  */
3431367790ccSRichard Henderson         tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V,
3432367790ccSRichard Henderson                             QREG_CC_C, QREG_CC_X);
3433367790ccSRichard Henderson 
3434808d77bcSLucien Murray-Pitts         /*
3435808d77bcSLucien Murray-Pitts          * M68000 sets V if the most significant bit is changed at
3436367790ccSRichard Henderson          * any time during the shift operation.  Do this via creating
3437367790ccSRichard Henderson          * an extension of the sign bit, comparing, and discarding
3438367790ccSRichard Henderson          * the bits below the sign bit.  I.e.
3439367790ccSRichard Henderson          *     int64_t s = (intN_t)reg;
3440367790ccSRichard Henderson          *     int64_t t = (int64_t)(intN_t)reg << count;
3441367790ccSRichard Henderson          *     V = ((s ^ t) & (-1 << (bits - 1))) != 0
3442367790ccSRichard Henderson          */
3443aece90d8SMark Cave-Ayland         if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) {
34441852ce5aSRichard Henderson             TCGv_i64 tt = tcg_constant_i64(32);
3445367790ccSRichard Henderson             /* if shift is greater than 32, use 32 */
3446367790ccSRichard Henderson             tcg_gen_movcond_i64(TCG_COND_GT, s64, s64, tt, tt, s64);
3447367790ccSRichard Henderson             /* Sign extend the input to 64 bits; re-do the shift.  */
3448367790ccSRichard Henderson             tcg_gen_ext_i32_i64(t64, reg);
3449367790ccSRichard Henderson             tcg_gen_shl_i64(s64, t64, s64);
3450367790ccSRichard Henderson             /* Clear all bits that are unchanged.  */
3451367790ccSRichard Henderson             tcg_gen_xor_i64(t64, t64, s64);
3452367790ccSRichard Henderson             /* Ignore the bits below the sign bit.  */
3453367790ccSRichard Henderson             tcg_gen_andi_i64(t64, t64, -1ULL << (bits - 1));
3454367790ccSRichard Henderson             /* If any bits remain set, we have overflow.  */
345527f9af76SRichard Henderson             tcg_gen_negsetcond_i64(TCG_COND_NE, t64, t64, tcg_constant_i64(0));
3456367790ccSRichard Henderson             tcg_gen_extrl_i64_i32(QREG_CC_V, t64);
3457367790ccSRichard Henderson         }
3458367790ccSRichard Henderson     } else {
3459367790ccSRichard Henderson         tcg_gen_shli_i64(t64, t64, 32);
3460367790ccSRichard Henderson         if (logical) {
3461367790ccSRichard Henderson             tcg_gen_shr_i64(t64, t64, s64);
3462367790ccSRichard Henderson         } else {
3463367790ccSRichard Henderson             tcg_gen_sar_i64(t64, t64, s64);
3464367790ccSRichard Henderson         }
3465367790ccSRichard Henderson         tcg_gen_extr_i64_i32(QREG_CC_C, QREG_CC_N, t64);
3466367790ccSRichard Henderson 
3467367790ccSRichard Henderson         /* Note that C=0 if shift count is 0, and we get that for free.  */
3468367790ccSRichard Henderson         tcg_gen_shri_i32(QREG_CC_C, QREG_CC_C, 31);
3469367790ccSRichard Henderson 
3470367790ccSRichard Henderson         /* X = C, but only if the shift count was non-zero.  */
3471367790ccSRichard Henderson         tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V,
3472367790ccSRichard Henderson                             QREG_CC_C, QREG_CC_X);
3473367790ccSRichard Henderson     }
3474367790ccSRichard Henderson     gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3475367790ccSRichard Henderson     tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3476367790ccSRichard Henderson 
3477367790ccSRichard Henderson     /* Write back the result.  */
3478367790ccSRichard Henderson     gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N);
3479367790ccSRichard Henderson     set_cc_op(s, CC_OP_FLAGS);
3480367790ccSRichard Henderson }
3481367790ccSRichard Henderson 
DISAS_INSN(shift8_im)3482367790ccSRichard Henderson DISAS_INSN(shift8_im)
3483367790ccSRichard Henderson {
3484367790ccSRichard Henderson     shift_im(s, insn, OS_BYTE);
3485367790ccSRichard Henderson }
3486367790ccSRichard Henderson 
DISAS_INSN(shift16_im)3487367790ccSRichard Henderson DISAS_INSN(shift16_im)
3488367790ccSRichard Henderson {
3489367790ccSRichard Henderson     shift_im(s, insn, OS_WORD);
3490367790ccSRichard Henderson }
3491367790ccSRichard Henderson 
DISAS_INSN(shift_im)3492fcf5ef2aSThomas Huth DISAS_INSN(shift_im)
3493fcf5ef2aSThomas Huth {
3494367790ccSRichard Henderson     shift_im(s, insn, OS_LONG);
3495fcf5ef2aSThomas Huth }
3496367790ccSRichard Henderson 
DISAS_INSN(shift8_reg)3497367790ccSRichard Henderson DISAS_INSN(shift8_reg)
3498367790ccSRichard Henderson {
3499367790ccSRichard Henderson     shift_reg(s, insn, OS_BYTE);
3500fcf5ef2aSThomas Huth }
3501367790ccSRichard Henderson 
DISAS_INSN(shift16_reg)3502367790ccSRichard Henderson DISAS_INSN(shift16_reg)
3503367790ccSRichard Henderson {
3504367790ccSRichard Henderson     shift_reg(s, insn, OS_WORD);
3505fcf5ef2aSThomas Huth }
3506fcf5ef2aSThomas Huth 
DISAS_INSN(shift_reg)3507fcf5ef2aSThomas Huth DISAS_INSN(shift_reg)
3508fcf5ef2aSThomas Huth {
3509367790ccSRichard Henderson     shift_reg(s, insn, OS_LONG);
3510367790ccSRichard Henderson }
3511fcf5ef2aSThomas Huth 
DISAS_INSN(shift_mem)3512367790ccSRichard Henderson DISAS_INSN(shift_mem)
3513367790ccSRichard Henderson {
3514367790ccSRichard Henderson     int logical = insn & 8;
3515367790ccSRichard Henderson     int left = insn & 0x100;
3516367790ccSRichard Henderson     TCGv src;
3517367790ccSRichard Henderson     TCGv addr;
3518367790ccSRichard Henderson 
3519367790ccSRichard Henderson     SRC_EA(env, src, OS_WORD, !logical, &addr);
3520367790ccSRichard Henderson     tcg_gen_movi_i32(QREG_CC_V, 0);
3521367790ccSRichard Henderson     if (left) {
3522367790ccSRichard Henderson         tcg_gen_shri_i32(QREG_CC_C, src, 15);
3523367790ccSRichard Henderson         tcg_gen_shli_i32(QREG_CC_N, src, 1);
3524367790ccSRichard Henderson 
3525808d77bcSLucien Murray-Pitts         /*
3526808d77bcSLucien Murray-Pitts          * Note that ColdFire always clears V,
3527808d77bcSLucien Murray-Pitts          * while M68000 sets if the most significant bit is changed at
3528808d77bcSLucien Murray-Pitts          * any time during the shift operation
3529808d77bcSLucien Murray-Pitts          */
3530aece90d8SMark Cave-Ayland         if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) {
35313f215a14SLaurent Vivier             src = gen_extend(s, src, OS_WORD, 1);
3532367790ccSRichard Henderson             tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
3533367790ccSRichard Henderson         }
3534fcf5ef2aSThomas Huth     } else {
3535367790ccSRichard Henderson         tcg_gen_mov_i32(QREG_CC_C, src);
3536367790ccSRichard Henderson         if (logical) {
3537367790ccSRichard Henderson             tcg_gen_shri_i32(QREG_CC_N, src, 1);
3538fcf5ef2aSThomas Huth         } else {
3539367790ccSRichard Henderson             tcg_gen_sari_i32(QREG_CC_N, src, 1);
3540fcf5ef2aSThomas Huth         }
3541fcf5ef2aSThomas Huth     }
3542367790ccSRichard Henderson 
3543367790ccSRichard Henderson     gen_ext(QREG_CC_N, QREG_CC_N, OS_WORD, 1);
3544367790ccSRichard Henderson     tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3545367790ccSRichard Henderson     tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3546367790ccSRichard Henderson     tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
3547367790ccSRichard Henderson 
3548367790ccSRichard Henderson     DEST_EA(env, insn, OS_WORD, QREG_CC_N, &addr);
3549fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_FLAGS);
3550fcf5ef2aSThomas Huth }
3551fcf5ef2aSThomas Huth 
rotate(TCGv reg,TCGv shift,int left,int size)35520194cf31SLaurent Vivier static void rotate(TCGv reg, TCGv shift, int left, int size)
35530194cf31SLaurent Vivier {
35540194cf31SLaurent Vivier     switch (size) {
35550194cf31SLaurent Vivier     case 8:
35560194cf31SLaurent Vivier         /* Replicate the 8-bit input so that a 32-bit rotate works.  */
35570194cf31SLaurent Vivier         tcg_gen_ext8u_i32(reg, reg);
35580194cf31SLaurent Vivier         tcg_gen_muli_i32(reg, reg, 0x01010101);
35590194cf31SLaurent Vivier         goto do_long;
35600194cf31SLaurent Vivier     case 16:
35610194cf31SLaurent Vivier         /* Replicate the 16-bit input so that a 32-bit rotate works.  */
35620194cf31SLaurent Vivier         tcg_gen_deposit_i32(reg, reg, reg, 16, 16);
35630194cf31SLaurent Vivier         goto do_long;
35640194cf31SLaurent Vivier     do_long:
35650194cf31SLaurent Vivier     default:
35660194cf31SLaurent Vivier         if (left) {
35670194cf31SLaurent Vivier             tcg_gen_rotl_i32(reg, reg, shift);
35680194cf31SLaurent Vivier         } else {
35690194cf31SLaurent Vivier             tcg_gen_rotr_i32(reg, reg, shift);
35700194cf31SLaurent Vivier         }
35710194cf31SLaurent Vivier     }
35720194cf31SLaurent Vivier 
35730194cf31SLaurent Vivier     /* compute flags */
35740194cf31SLaurent Vivier 
35750194cf31SLaurent Vivier     switch (size) {
35760194cf31SLaurent Vivier     case 8:
35770194cf31SLaurent Vivier         tcg_gen_ext8s_i32(reg, reg);
35780194cf31SLaurent Vivier         break;
35790194cf31SLaurent Vivier     case 16:
35800194cf31SLaurent Vivier         tcg_gen_ext16s_i32(reg, reg);
35810194cf31SLaurent Vivier         break;
35820194cf31SLaurent Vivier     default:
35830194cf31SLaurent Vivier         break;
35840194cf31SLaurent Vivier     }
35850194cf31SLaurent Vivier 
35860194cf31SLaurent Vivier     /* QREG_CC_X is not affected */
35870194cf31SLaurent Vivier 
35880194cf31SLaurent Vivier     tcg_gen_mov_i32(QREG_CC_N, reg);
35890194cf31SLaurent Vivier     tcg_gen_mov_i32(QREG_CC_Z, reg);
35900194cf31SLaurent Vivier 
35910194cf31SLaurent Vivier     if (left) {
35920194cf31SLaurent Vivier         tcg_gen_andi_i32(QREG_CC_C, reg, 1);
35930194cf31SLaurent Vivier     } else {
35940194cf31SLaurent Vivier         tcg_gen_shri_i32(QREG_CC_C, reg, 31);
35950194cf31SLaurent Vivier     }
35960194cf31SLaurent Vivier 
35970194cf31SLaurent Vivier     tcg_gen_movi_i32(QREG_CC_V, 0); /* always cleared */
35980194cf31SLaurent Vivier }
35990194cf31SLaurent Vivier 
rotate_x_flags(TCGv reg,TCGv X,int size)36000194cf31SLaurent Vivier static void rotate_x_flags(TCGv reg, TCGv X, int size)
36010194cf31SLaurent Vivier {
36020194cf31SLaurent Vivier     switch (size) {
36030194cf31SLaurent Vivier     case 8:
36040194cf31SLaurent Vivier         tcg_gen_ext8s_i32(reg, reg);
36050194cf31SLaurent Vivier         break;
36060194cf31SLaurent Vivier     case 16:
36070194cf31SLaurent Vivier         tcg_gen_ext16s_i32(reg, reg);
36080194cf31SLaurent Vivier         break;
36090194cf31SLaurent Vivier     default:
36100194cf31SLaurent Vivier         break;
36110194cf31SLaurent Vivier     }
36120194cf31SLaurent Vivier     tcg_gen_mov_i32(QREG_CC_N, reg);
36130194cf31SLaurent Vivier     tcg_gen_mov_i32(QREG_CC_Z, reg);
36140194cf31SLaurent Vivier     tcg_gen_mov_i32(QREG_CC_X, X);
36150194cf31SLaurent Vivier     tcg_gen_mov_i32(QREG_CC_C, X);
36160194cf31SLaurent Vivier     tcg_gen_movi_i32(QREG_CC_V, 0);
36170194cf31SLaurent Vivier }
36180194cf31SLaurent Vivier 
36190194cf31SLaurent Vivier /* Result of rotate_x() is valid if 0 <= shift <= size */
rotate_x(TCGv reg,TCGv shift,int left,int size)36200194cf31SLaurent Vivier static TCGv rotate_x(TCGv reg, TCGv shift, int left, int size)
36210194cf31SLaurent Vivier {
36220194cf31SLaurent Vivier     TCGv X, shl, shr, shx, sz, zero;
36230194cf31SLaurent Vivier 
36241852ce5aSRichard Henderson     sz = tcg_constant_i32(size);
36250194cf31SLaurent Vivier 
36260194cf31SLaurent Vivier     shr = tcg_temp_new();
36270194cf31SLaurent Vivier     shl = tcg_temp_new();
36280194cf31SLaurent Vivier     shx = tcg_temp_new();
36290194cf31SLaurent Vivier     if (left) {
36300194cf31SLaurent Vivier         tcg_gen_mov_i32(shl, shift);      /* shl = shift */
36310194cf31SLaurent Vivier         tcg_gen_movi_i32(shr, size + 1);
36320194cf31SLaurent Vivier         tcg_gen_sub_i32(shr, shr, shift); /* shr = size + 1 - shift */
36330194cf31SLaurent Vivier         tcg_gen_subi_i32(shx, shift, 1);  /* shx = shift - 1 */
36340194cf31SLaurent Vivier         /* shx = shx < 0 ? size : shx; */
36351852ce5aSRichard Henderson         zero = tcg_constant_i32(0);
36360194cf31SLaurent Vivier         tcg_gen_movcond_i32(TCG_COND_LT, shx, shx, zero, sz, shx);
36370194cf31SLaurent Vivier     } else {
36380194cf31SLaurent Vivier         tcg_gen_mov_i32(shr, shift);      /* shr = shift */
36390194cf31SLaurent Vivier         tcg_gen_movi_i32(shl, size + 1);
36400194cf31SLaurent Vivier         tcg_gen_sub_i32(shl, shl, shift); /* shl = size + 1 - shift */
36410194cf31SLaurent Vivier         tcg_gen_sub_i32(shx, sz, shift); /* shx = size - shift */
36420194cf31SLaurent Vivier     }
36430194cf31SLaurent Vivier 
36440194cf31SLaurent Vivier     /* reg = (reg << shl) | (reg >> shr) | (x << shx); */
36450194cf31SLaurent Vivier 
36460194cf31SLaurent Vivier     tcg_gen_shl_i32(shl, reg, shl);
36470194cf31SLaurent Vivier     tcg_gen_shr_i32(shr, reg, shr);
36480194cf31SLaurent Vivier     tcg_gen_or_i32(reg, shl, shr);
36490194cf31SLaurent Vivier     tcg_gen_shl_i32(shx, QREG_CC_X, shx);
36500194cf31SLaurent Vivier     tcg_gen_or_i32(reg, reg, shx);
36510194cf31SLaurent Vivier 
36520194cf31SLaurent Vivier     /* X = (reg >> size) & 1 */
36530194cf31SLaurent Vivier 
36540194cf31SLaurent Vivier     X = tcg_temp_new();
365560d3d0cfSPhilippe Mathieu-Daudé     tcg_gen_extract_i32(X, reg, size, 1);
36560194cf31SLaurent Vivier 
36570194cf31SLaurent Vivier     return X;
36580194cf31SLaurent Vivier }
36590194cf31SLaurent Vivier 
36600194cf31SLaurent Vivier /* Result of rotate32_x() is valid if 0 <= shift < 33 */
rotate32_x(TCGv reg,TCGv shift,int left)36610194cf31SLaurent Vivier static TCGv rotate32_x(TCGv reg, TCGv shift, int left)
36620194cf31SLaurent Vivier {
36630194cf31SLaurent Vivier     TCGv_i64 t0, shift64;
36640194cf31SLaurent Vivier     TCGv X, lo, hi, zero;
36650194cf31SLaurent Vivier 
36660194cf31SLaurent Vivier     shift64 = tcg_temp_new_i64();
36670194cf31SLaurent Vivier     tcg_gen_extu_i32_i64(shift64, shift);
36680194cf31SLaurent Vivier 
36690194cf31SLaurent Vivier     t0 = tcg_temp_new_i64();
36700194cf31SLaurent Vivier 
36710194cf31SLaurent Vivier     X = tcg_temp_new();
36720194cf31SLaurent Vivier     lo = tcg_temp_new();
36730194cf31SLaurent Vivier     hi = tcg_temp_new();
36740194cf31SLaurent Vivier 
36750194cf31SLaurent Vivier     if (left) {
36760194cf31SLaurent Vivier         /* create [reg:X:..] */
36770194cf31SLaurent Vivier 
36780194cf31SLaurent Vivier         tcg_gen_shli_i32(lo, QREG_CC_X, 31);
36790194cf31SLaurent Vivier         tcg_gen_concat_i32_i64(t0, lo, reg);
36800194cf31SLaurent Vivier 
36810194cf31SLaurent Vivier         /* rotate */
36820194cf31SLaurent Vivier 
36830194cf31SLaurent Vivier         tcg_gen_rotl_i64(t0, t0, shift64);
36840194cf31SLaurent Vivier 
36850194cf31SLaurent Vivier         /* result is [reg:..:reg:X] */
36860194cf31SLaurent Vivier 
36870194cf31SLaurent Vivier         tcg_gen_extr_i64_i32(lo, hi, t0);
36880194cf31SLaurent Vivier         tcg_gen_andi_i32(X, lo, 1);
36890194cf31SLaurent Vivier 
36900194cf31SLaurent Vivier         tcg_gen_shri_i32(lo, lo, 1);
36910194cf31SLaurent Vivier     } else {
36920194cf31SLaurent Vivier         /* create [..:X:reg] */
36930194cf31SLaurent Vivier 
36940194cf31SLaurent Vivier         tcg_gen_concat_i32_i64(t0, reg, QREG_CC_X);
36950194cf31SLaurent Vivier 
36960194cf31SLaurent Vivier         tcg_gen_rotr_i64(t0, t0, shift64);
36970194cf31SLaurent Vivier 
36980194cf31SLaurent Vivier         /* result is value: [X:reg:..:reg] */
36990194cf31SLaurent Vivier 
37000194cf31SLaurent Vivier         tcg_gen_extr_i64_i32(lo, hi, t0);
37010194cf31SLaurent Vivier 
37020194cf31SLaurent Vivier         /* extract X */
37030194cf31SLaurent Vivier 
37040194cf31SLaurent Vivier         tcg_gen_shri_i32(X, hi, 31);
37050194cf31SLaurent Vivier 
37060194cf31SLaurent Vivier         /* extract result */
37070194cf31SLaurent Vivier 
37080194cf31SLaurent Vivier         tcg_gen_shli_i32(hi, hi, 1);
37090194cf31SLaurent Vivier     }
37100194cf31SLaurent Vivier     tcg_gen_or_i32(lo, lo, hi);
37110194cf31SLaurent Vivier 
37120194cf31SLaurent Vivier     /* if shift == 0, register and X are not affected */
37130194cf31SLaurent Vivier 
37141852ce5aSRichard Henderson     zero = tcg_constant_i32(0);
37150194cf31SLaurent Vivier     tcg_gen_movcond_i32(TCG_COND_EQ, X, shift, zero, QREG_CC_X, X);
37160194cf31SLaurent Vivier     tcg_gen_movcond_i32(TCG_COND_EQ, reg, shift, zero, reg, lo);
37170194cf31SLaurent Vivier 
37180194cf31SLaurent Vivier     return X;
37190194cf31SLaurent Vivier }
37200194cf31SLaurent Vivier 
DISAS_INSN(rotate_im)37210194cf31SLaurent Vivier DISAS_INSN(rotate_im)
37220194cf31SLaurent Vivier {
37230194cf31SLaurent Vivier     TCGv shift;
37240194cf31SLaurent Vivier     int tmp;
37250194cf31SLaurent Vivier     int left = (insn & 0x100);
37260194cf31SLaurent Vivier 
37270194cf31SLaurent Vivier     tmp = (insn >> 9) & 7;
37280194cf31SLaurent Vivier     if (tmp == 0) {
37290194cf31SLaurent Vivier         tmp = 8;
37300194cf31SLaurent Vivier     }
37310194cf31SLaurent Vivier 
37321852ce5aSRichard Henderson     shift = tcg_constant_i32(tmp);
37330194cf31SLaurent Vivier     if (insn & 8) {
37340194cf31SLaurent Vivier         rotate(DREG(insn, 0), shift, left, 32);
37350194cf31SLaurent Vivier     } else {
37360194cf31SLaurent Vivier         TCGv X = rotate32_x(DREG(insn, 0), shift, left);
37370194cf31SLaurent Vivier         rotate_x_flags(DREG(insn, 0), X, 32);
37380194cf31SLaurent Vivier     }
37390194cf31SLaurent Vivier 
37400194cf31SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
37410194cf31SLaurent Vivier }
37420194cf31SLaurent Vivier 
DISAS_INSN(rotate8_im)37430194cf31SLaurent Vivier DISAS_INSN(rotate8_im)
37440194cf31SLaurent Vivier {
37450194cf31SLaurent Vivier     int left = (insn & 0x100);
37460194cf31SLaurent Vivier     TCGv reg;
37470194cf31SLaurent Vivier     TCGv shift;
37480194cf31SLaurent Vivier     int tmp;
37490194cf31SLaurent Vivier 
37503f215a14SLaurent Vivier     reg = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
37510194cf31SLaurent Vivier 
37520194cf31SLaurent Vivier     tmp = (insn >> 9) & 7;
37530194cf31SLaurent Vivier     if (tmp == 0) {
37540194cf31SLaurent Vivier         tmp = 8;
37550194cf31SLaurent Vivier     }
37560194cf31SLaurent Vivier 
37571852ce5aSRichard Henderson     shift = tcg_constant_i32(tmp);
37580194cf31SLaurent Vivier     if (insn & 8) {
37590194cf31SLaurent Vivier         rotate(reg, shift, left, 8);
37600194cf31SLaurent Vivier     } else {
37610194cf31SLaurent Vivier         TCGv X = rotate_x(reg, shift, left, 8);
37620194cf31SLaurent Vivier         rotate_x_flags(reg, X, 8);
37630194cf31SLaurent Vivier     }
37640194cf31SLaurent Vivier     gen_partset_reg(OS_BYTE, DREG(insn, 0), reg);
37650194cf31SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
37660194cf31SLaurent Vivier }
37670194cf31SLaurent Vivier 
DISAS_INSN(rotate16_im)37680194cf31SLaurent Vivier DISAS_INSN(rotate16_im)
37690194cf31SLaurent Vivier {
37700194cf31SLaurent Vivier     int left = (insn & 0x100);
37710194cf31SLaurent Vivier     TCGv reg;
37720194cf31SLaurent Vivier     TCGv shift;
37730194cf31SLaurent Vivier     int tmp;
37740194cf31SLaurent Vivier 
37753f215a14SLaurent Vivier     reg = gen_extend(s, DREG(insn, 0), OS_WORD, 0);
37760194cf31SLaurent Vivier     tmp = (insn >> 9) & 7;
37770194cf31SLaurent Vivier     if (tmp == 0) {
37780194cf31SLaurent Vivier         tmp = 8;
37790194cf31SLaurent Vivier     }
37800194cf31SLaurent Vivier 
37811852ce5aSRichard Henderson     shift = tcg_constant_i32(tmp);
37820194cf31SLaurent Vivier     if (insn & 8) {
37830194cf31SLaurent Vivier         rotate(reg, shift, left, 16);
37840194cf31SLaurent Vivier     } else {
37850194cf31SLaurent Vivier         TCGv X = rotate_x(reg, shift, left, 16);
37860194cf31SLaurent Vivier         rotate_x_flags(reg, X, 16);
37870194cf31SLaurent Vivier     }
37880194cf31SLaurent Vivier     gen_partset_reg(OS_WORD, DREG(insn, 0), reg);
37890194cf31SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
37900194cf31SLaurent Vivier }
37910194cf31SLaurent Vivier 
DISAS_INSN(rotate_reg)37920194cf31SLaurent Vivier DISAS_INSN(rotate_reg)
37930194cf31SLaurent Vivier {
37940194cf31SLaurent Vivier     TCGv reg;
37950194cf31SLaurent Vivier     TCGv src;
37960194cf31SLaurent Vivier     TCGv t0, t1;
37970194cf31SLaurent Vivier     int left = (insn & 0x100);
37980194cf31SLaurent Vivier 
37990194cf31SLaurent Vivier     reg = DREG(insn, 0);
38000194cf31SLaurent Vivier     src = DREG(insn, 9);
38010194cf31SLaurent Vivier     /* shift in [0..63] */
38020194cf31SLaurent Vivier     t0 = tcg_temp_new();
38030194cf31SLaurent Vivier     tcg_gen_andi_i32(t0, src, 63);
38040194cf31SLaurent Vivier     t1 = tcg_temp_new_i32();
38050194cf31SLaurent Vivier     if (insn & 8) {
38060194cf31SLaurent Vivier         tcg_gen_andi_i32(t1, src, 31);
38070194cf31SLaurent Vivier         rotate(reg, t1, left, 32);
38080194cf31SLaurent Vivier         /* if shift == 0, clear C */
38090194cf31SLaurent Vivier         tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
38100194cf31SLaurent Vivier                             t0, QREG_CC_V /* 0 */,
38110194cf31SLaurent Vivier                             QREG_CC_V /* 0 */, QREG_CC_C);
38120194cf31SLaurent Vivier     } else {
38130194cf31SLaurent Vivier         TCGv X;
38140194cf31SLaurent Vivier         /* modulo 33 */
38150194cf31SLaurent Vivier         tcg_gen_movi_i32(t1, 33);
38160194cf31SLaurent Vivier         tcg_gen_remu_i32(t1, t0, t1);
38170194cf31SLaurent Vivier         X = rotate32_x(DREG(insn, 0), t1, left);
38180194cf31SLaurent Vivier         rotate_x_flags(DREG(insn, 0), X, 32);
38190194cf31SLaurent Vivier     }
38200194cf31SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
38210194cf31SLaurent Vivier }
38220194cf31SLaurent Vivier 
DISAS_INSN(rotate8_reg)38230194cf31SLaurent Vivier DISAS_INSN(rotate8_reg)
38240194cf31SLaurent Vivier {
38250194cf31SLaurent Vivier     TCGv reg;
38260194cf31SLaurent Vivier     TCGv src;
38270194cf31SLaurent Vivier     TCGv t0, t1;
38280194cf31SLaurent Vivier     int left = (insn & 0x100);
38290194cf31SLaurent Vivier 
38303f215a14SLaurent Vivier     reg = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
38310194cf31SLaurent Vivier     src = DREG(insn, 9);
38320194cf31SLaurent Vivier     /* shift in [0..63] */
38330194cf31SLaurent Vivier     t0 = tcg_temp_new_i32();
38340194cf31SLaurent Vivier     tcg_gen_andi_i32(t0, src, 63);
38350194cf31SLaurent Vivier     t1 = tcg_temp_new_i32();
38360194cf31SLaurent Vivier     if (insn & 8) {
38370194cf31SLaurent Vivier         tcg_gen_andi_i32(t1, src, 7);
38380194cf31SLaurent Vivier         rotate(reg, t1, left, 8);
38390194cf31SLaurent Vivier         /* if shift == 0, clear C */
38400194cf31SLaurent Vivier         tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
38410194cf31SLaurent Vivier                             t0, QREG_CC_V /* 0 */,
38420194cf31SLaurent Vivier                             QREG_CC_V /* 0 */, QREG_CC_C);
38430194cf31SLaurent Vivier     } else {
38440194cf31SLaurent Vivier         TCGv X;
38450194cf31SLaurent Vivier         /* modulo 9 */
38460194cf31SLaurent Vivier         tcg_gen_movi_i32(t1, 9);
38470194cf31SLaurent Vivier         tcg_gen_remu_i32(t1, t0, t1);
38480194cf31SLaurent Vivier         X = rotate_x(reg, t1, left, 8);
38490194cf31SLaurent Vivier         rotate_x_flags(reg, X, 8);
38500194cf31SLaurent Vivier     }
38510194cf31SLaurent Vivier     gen_partset_reg(OS_BYTE, DREG(insn, 0), reg);
38520194cf31SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
38530194cf31SLaurent Vivier }
38540194cf31SLaurent Vivier 
DISAS_INSN(rotate16_reg)38550194cf31SLaurent Vivier DISAS_INSN(rotate16_reg)
38560194cf31SLaurent Vivier {
38570194cf31SLaurent Vivier     TCGv reg;
38580194cf31SLaurent Vivier     TCGv src;
38590194cf31SLaurent Vivier     TCGv t0, t1;
38600194cf31SLaurent Vivier     int left = (insn & 0x100);
38610194cf31SLaurent Vivier 
38623f215a14SLaurent Vivier     reg = gen_extend(s, DREG(insn, 0), OS_WORD, 0);
38630194cf31SLaurent Vivier     src = DREG(insn, 9);
38640194cf31SLaurent Vivier     /* shift in [0..63] */
38650194cf31SLaurent Vivier     t0 = tcg_temp_new_i32();
38660194cf31SLaurent Vivier     tcg_gen_andi_i32(t0, src, 63);
38670194cf31SLaurent Vivier     t1 = tcg_temp_new_i32();
38680194cf31SLaurent Vivier     if (insn & 8) {
38690194cf31SLaurent Vivier         tcg_gen_andi_i32(t1, src, 15);
38700194cf31SLaurent Vivier         rotate(reg, t1, left, 16);
38710194cf31SLaurent Vivier         /* if shift == 0, clear C */
38720194cf31SLaurent Vivier         tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
38730194cf31SLaurent Vivier                             t0, QREG_CC_V /* 0 */,
38740194cf31SLaurent Vivier                             QREG_CC_V /* 0 */, QREG_CC_C);
38750194cf31SLaurent Vivier     } else {
38760194cf31SLaurent Vivier         TCGv X;
38770194cf31SLaurent Vivier         /* modulo 17 */
38780194cf31SLaurent Vivier         tcg_gen_movi_i32(t1, 17);
38790194cf31SLaurent Vivier         tcg_gen_remu_i32(t1, t0, t1);
38800194cf31SLaurent Vivier         X = rotate_x(reg, t1, left, 16);
38810194cf31SLaurent Vivier         rotate_x_flags(reg, X, 16);
38820194cf31SLaurent Vivier     }
38830194cf31SLaurent Vivier     gen_partset_reg(OS_WORD, DREG(insn, 0), reg);
38840194cf31SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
38850194cf31SLaurent Vivier }
38860194cf31SLaurent Vivier 
DISAS_INSN(rotate_mem)38870194cf31SLaurent Vivier DISAS_INSN(rotate_mem)
38880194cf31SLaurent Vivier {
38890194cf31SLaurent Vivier     TCGv src;
38900194cf31SLaurent Vivier     TCGv addr;
38910194cf31SLaurent Vivier     TCGv shift;
38920194cf31SLaurent Vivier     int left = (insn & 0x100);
38930194cf31SLaurent Vivier 
38940194cf31SLaurent Vivier     SRC_EA(env, src, OS_WORD, 0, &addr);
38950194cf31SLaurent Vivier 
38961852ce5aSRichard Henderson     shift = tcg_constant_i32(1);
38970194cf31SLaurent Vivier     if (insn & 0x0200) {
38980194cf31SLaurent Vivier         rotate(src, shift, left, 16);
38990194cf31SLaurent Vivier     } else {
39000194cf31SLaurent Vivier         TCGv X = rotate_x(src, shift, left, 16);
39010194cf31SLaurent Vivier         rotate_x_flags(src, X, 16);
39020194cf31SLaurent Vivier     }
39030194cf31SLaurent Vivier     DEST_EA(env, insn, OS_WORD, src, &addr);
39040194cf31SLaurent Vivier     set_cc_op(s, CC_OP_FLAGS);
39050194cf31SLaurent Vivier }
39060194cf31SLaurent Vivier 
DISAS_INSN(bfext_reg)3907ac815f46SRichard Henderson DISAS_INSN(bfext_reg)
3908ac815f46SRichard Henderson {
3909ac815f46SRichard Henderson     int ext = read_im16(env, s);
3910ac815f46SRichard Henderson     int is_sign = insn & 0x200;
3911ac815f46SRichard Henderson     TCGv src = DREG(insn, 0);
3912ac815f46SRichard Henderson     TCGv dst = DREG(ext, 12);
3913ac815f46SRichard Henderson     int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
3914ac815f46SRichard Henderson     int ofs = extract32(ext, 6, 5);  /* big bit-endian */
3915ac815f46SRichard Henderson     int pos = 32 - ofs - len;        /* little bit-endian */
3916ac815f46SRichard Henderson     TCGv tmp = tcg_temp_new();
3917ac815f46SRichard Henderson     TCGv shift;
3918ac815f46SRichard Henderson 
3919808d77bcSLucien Murray-Pitts     /*
3920808d77bcSLucien Murray-Pitts      * In general, we're going to rotate the field so that it's at the
3921808d77bcSLucien Murray-Pitts      * top of the word and then right-shift by the complement of the
3922808d77bcSLucien Murray-Pitts      * width to extend the field.
3923808d77bcSLucien Murray-Pitts      */
3924ac815f46SRichard Henderson     if (ext & 0x20) {
3925ac815f46SRichard Henderson         /* Variable width.  */
3926ac815f46SRichard Henderson         if (ext & 0x800) {
3927ac815f46SRichard Henderson             /* Variable offset.  */
3928ac815f46SRichard Henderson             tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
3929ac815f46SRichard Henderson             tcg_gen_rotl_i32(tmp, src, tmp);
3930ac815f46SRichard Henderson         } else {
3931ac815f46SRichard Henderson             tcg_gen_rotli_i32(tmp, src, ofs);
3932ac815f46SRichard Henderson         }
3933ac815f46SRichard Henderson 
3934ac815f46SRichard Henderson         shift = tcg_temp_new();
3935ac815f46SRichard Henderson         tcg_gen_neg_i32(shift, DREG(ext, 0));
3936ac815f46SRichard Henderson         tcg_gen_andi_i32(shift, shift, 31);
3937ac815f46SRichard Henderson         tcg_gen_sar_i32(QREG_CC_N, tmp, shift);
3938ac815f46SRichard Henderson         if (is_sign) {
3939ac815f46SRichard Henderson             tcg_gen_mov_i32(dst, QREG_CC_N);
3940ac815f46SRichard Henderson         } else {
3941ac815f46SRichard Henderson             tcg_gen_shr_i32(dst, tmp, shift);
3942ac815f46SRichard Henderson         }
3943ac815f46SRichard Henderson     } else {
3944ac815f46SRichard Henderson         /* Immediate width.  */
3945ac815f46SRichard Henderson         if (ext & 0x800) {
3946ac815f46SRichard Henderson             /* Variable offset */
3947ac815f46SRichard Henderson             tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
3948ac815f46SRichard Henderson             tcg_gen_rotl_i32(tmp, src, tmp);
3949ac815f46SRichard Henderson             src = tmp;
3950ac815f46SRichard Henderson             pos = 32 - len;
3951ac815f46SRichard Henderson         } else {
3952808d77bcSLucien Murray-Pitts             /*
3953808d77bcSLucien Murray-Pitts              * Immediate offset.  If the field doesn't wrap around the
3954808d77bcSLucien Murray-Pitts              * end of the word, rely on (s)extract completely.
3955808d77bcSLucien Murray-Pitts              */
3956ac815f46SRichard Henderson             if (pos < 0) {
3957ac815f46SRichard Henderson                 tcg_gen_rotli_i32(tmp, src, ofs);
3958ac815f46SRichard Henderson                 src = tmp;
3959ac815f46SRichard Henderson                 pos = 32 - len;
3960ac815f46SRichard Henderson             }
3961ac815f46SRichard Henderson         }
3962ac815f46SRichard Henderson 
3963ac815f46SRichard Henderson         tcg_gen_sextract_i32(QREG_CC_N, src, pos, len);
3964ac815f46SRichard Henderson         if (is_sign) {
3965ac815f46SRichard Henderson             tcg_gen_mov_i32(dst, QREG_CC_N);
3966ac815f46SRichard Henderson         } else {
3967ac815f46SRichard Henderson             tcg_gen_extract_i32(dst, src, pos, len);
3968ac815f46SRichard Henderson         }
3969ac815f46SRichard Henderson     }
3970ac815f46SRichard Henderson 
3971ac815f46SRichard Henderson     set_cc_op(s, CC_OP_LOGIC);
3972ac815f46SRichard Henderson }
3973ac815f46SRichard Henderson 
DISAS_INSN(bfext_mem)3974f2224f2cSRichard Henderson DISAS_INSN(bfext_mem)
3975f2224f2cSRichard Henderson {
3976f2224f2cSRichard Henderson     int ext = read_im16(env, s);
3977f2224f2cSRichard Henderson     int is_sign = insn & 0x200;
3978f2224f2cSRichard Henderson     TCGv dest = DREG(ext, 12);
3979f2224f2cSRichard Henderson     TCGv addr, len, ofs;
3980f2224f2cSRichard Henderson 
3981f2224f2cSRichard Henderson     addr = gen_lea(env, s, insn, OS_UNSIZED);
3982f2224f2cSRichard Henderson     if (IS_NULL_QREG(addr)) {
3983f2224f2cSRichard Henderson         gen_addr_fault(s);
3984f2224f2cSRichard Henderson         return;
3985f2224f2cSRichard Henderson     }
3986f2224f2cSRichard Henderson 
3987f2224f2cSRichard Henderson     if (ext & 0x20) {
3988f2224f2cSRichard Henderson         len = DREG(ext, 0);
3989f2224f2cSRichard Henderson     } else {
39901852ce5aSRichard Henderson         len = tcg_constant_i32(extract32(ext, 0, 5));
3991f2224f2cSRichard Henderson     }
3992f2224f2cSRichard Henderson     if (ext & 0x800) {
3993f2224f2cSRichard Henderson         ofs = DREG(ext, 6);
3994f2224f2cSRichard Henderson     } else {
39951852ce5aSRichard Henderson         ofs = tcg_constant_i32(extract32(ext, 6, 5));
3996f2224f2cSRichard Henderson     }
3997f2224f2cSRichard Henderson 
3998f2224f2cSRichard Henderson     if (is_sign) {
3999ad75a51eSRichard Henderson         gen_helper_bfexts_mem(dest, tcg_env, addr, ofs, len);
4000f2224f2cSRichard Henderson         tcg_gen_mov_i32(QREG_CC_N, dest);
4001f2224f2cSRichard Henderson     } else {
4002f2224f2cSRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
4003ad75a51eSRichard Henderson         gen_helper_bfextu_mem(tmp, tcg_env, addr, ofs, len);
4004f2224f2cSRichard Henderson         tcg_gen_extr_i64_i32(dest, QREG_CC_N, tmp);
4005f2224f2cSRichard Henderson     }
4006f2224f2cSRichard Henderson     set_cc_op(s, CC_OP_LOGIC);
4007f2224f2cSRichard Henderson }
4008f2224f2cSRichard Henderson 
DISAS_INSN(bfop_reg)4009ac815f46SRichard Henderson DISAS_INSN(bfop_reg)
4010ac815f46SRichard Henderson {
4011ac815f46SRichard Henderson     int ext = read_im16(env, s);
4012ac815f46SRichard Henderson     TCGv src = DREG(insn, 0);
4013ac815f46SRichard Henderson     int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
4014ac815f46SRichard Henderson     int ofs = extract32(ext, 6, 5);  /* big bit-endian */
40157b346e46SRichard Henderson     TCGv mask, tofs = NULL, tlen = NULL;
40167b346e46SRichard Henderson     bool is_bfffo = (insn & 0x0f00) == 0x0d00;
4017ac815f46SRichard Henderson 
4018ac815f46SRichard Henderson     if ((ext & 0x820) == 0) {
4019ac815f46SRichard Henderson         /* Immediate width and offset.  */
4020ac815f46SRichard Henderson         uint32_t maski = 0x7fffffffu >> (len - 1);
4021ac815f46SRichard Henderson         if (ofs + len <= 32) {
4022ac815f46SRichard Henderson             tcg_gen_shli_i32(QREG_CC_N, src, ofs);
4023ac815f46SRichard Henderson         } else {
4024ac815f46SRichard Henderson             tcg_gen_rotli_i32(QREG_CC_N, src, ofs);
4025ac815f46SRichard Henderson         }
4026ac815f46SRichard Henderson         tcg_gen_andi_i32(QREG_CC_N, QREG_CC_N, ~maski);
40277b346e46SRichard Henderson 
40287b346e46SRichard Henderson         mask = tcg_constant_i32(ror32(maski, ofs));
40297b346e46SRichard Henderson         if (is_bfffo) {
40307b346e46SRichard Henderson             tofs = tcg_constant_i32(ofs);
40317b346e46SRichard Henderson             tlen = tcg_constant_i32(len);
4032a45f1763SRichard Henderson         }
4033ac815f46SRichard Henderson     } else {
4034ac815f46SRichard Henderson         TCGv tmp = tcg_temp_new();
40357b346e46SRichard Henderson 
40367b346e46SRichard Henderson         mask = tcg_temp_new();
4037ac815f46SRichard Henderson         if (ext & 0x20) {
4038ac815f46SRichard Henderson             /* Variable width */
4039ac815f46SRichard Henderson             tcg_gen_subi_i32(tmp, DREG(ext, 0), 1);
4040ac815f46SRichard Henderson             tcg_gen_andi_i32(tmp, tmp, 31);
40417b346e46SRichard Henderson             tcg_gen_shr_i32(mask, tcg_constant_i32(0x7fffffffu), tmp);
40427b346e46SRichard Henderson             if (is_bfffo) {
40437b346e46SRichard Henderson                 tlen = tcg_temp_new();
4044a45f1763SRichard Henderson                 tcg_gen_addi_i32(tlen, tmp, 1);
4045a45f1763SRichard Henderson             }
4046ac815f46SRichard Henderson         } else {
4047ac815f46SRichard Henderson             /* Immediate width */
40487b346e46SRichard Henderson             tcg_gen_movi_i32(mask, 0x7fffffffu >> (len - 1));
40497b346e46SRichard Henderson             if (is_bfffo) {
40507b346e46SRichard Henderson                 tlen = tcg_constant_i32(len);
4051a45f1763SRichard Henderson             }
4052ac815f46SRichard Henderson         }
40537b346e46SRichard Henderson 
4054ac815f46SRichard Henderson         if (ext & 0x800) {
4055ac815f46SRichard Henderson             /* Variable offset */
4056ac815f46SRichard Henderson             tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
4057ac815f46SRichard Henderson             tcg_gen_rotl_i32(QREG_CC_N, src, tmp);
4058ac815f46SRichard Henderson             tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask);
4059ac815f46SRichard Henderson             tcg_gen_rotr_i32(mask, mask, tmp);
40607b346e46SRichard Henderson             if (is_bfffo) {
40617b346e46SRichard Henderson                 tofs = tmp;
4062a45f1763SRichard Henderson             }
4063ac815f46SRichard Henderson         } else {
4064ac815f46SRichard Henderson             /* Immediate offset (and variable width) */
4065ac815f46SRichard Henderson             tcg_gen_rotli_i32(QREG_CC_N, src, ofs);
4066ac815f46SRichard Henderson             tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask);
4067ac815f46SRichard Henderson             tcg_gen_rotri_i32(mask, mask, ofs);
40687b346e46SRichard Henderson             if (is_bfffo) {
40697b346e46SRichard Henderson                 tofs = tcg_constant_i32(ofs);
4070a45f1763SRichard Henderson             }
4071ac815f46SRichard Henderson         }
4072ac815f46SRichard Henderson     }
4073ac815f46SRichard Henderson     set_cc_op(s, CC_OP_LOGIC);
4074ac815f46SRichard Henderson 
4075ac815f46SRichard Henderson     switch (insn & 0x0f00) {
4076ac815f46SRichard Henderson     case 0x0a00: /* bfchg */
4077ac815f46SRichard Henderson         tcg_gen_eqv_i32(src, src, mask);
4078ac815f46SRichard Henderson         break;
4079ac815f46SRichard Henderson     case 0x0c00: /* bfclr */
4080ac815f46SRichard Henderson         tcg_gen_and_i32(src, src, mask);
4081ac815f46SRichard Henderson         break;
4082a45f1763SRichard Henderson     case 0x0d00: /* bfffo */
4083a45f1763SRichard Henderson         gen_helper_bfffo_reg(DREG(ext, 12), QREG_CC_N, tofs, tlen);
4084a45f1763SRichard Henderson         break;
4085ac815f46SRichard Henderson     case 0x0e00: /* bfset */
4086ac815f46SRichard Henderson         tcg_gen_orc_i32(src, src, mask);
4087ac815f46SRichard Henderson         break;
4088ac815f46SRichard Henderson     case 0x0800: /* bftst */
4089ac815f46SRichard Henderson         /* flags already set; no other work to do.  */
4090ac815f46SRichard Henderson         break;
4091ac815f46SRichard Henderson     default:
4092ac815f46SRichard Henderson         g_assert_not_reached();
4093ac815f46SRichard Henderson     }
4094ac815f46SRichard Henderson }
4095ac815f46SRichard Henderson 
DISAS_INSN(bfop_mem)4096f2224f2cSRichard Henderson DISAS_INSN(bfop_mem)
4097f2224f2cSRichard Henderson {
4098f2224f2cSRichard Henderson     int ext = read_im16(env, s);
4099f2224f2cSRichard Henderson     TCGv addr, len, ofs;
4100a45f1763SRichard Henderson     TCGv_i64 t64;
4101f2224f2cSRichard Henderson 
4102f2224f2cSRichard Henderson     addr = gen_lea(env, s, insn, OS_UNSIZED);
4103f2224f2cSRichard Henderson     if (IS_NULL_QREG(addr)) {
4104f2224f2cSRichard Henderson         gen_addr_fault(s);
4105f2224f2cSRichard Henderson         return;
4106f2224f2cSRichard Henderson     }
4107f2224f2cSRichard Henderson 
4108f2224f2cSRichard Henderson     if (ext & 0x20) {
4109f2224f2cSRichard Henderson         len = DREG(ext, 0);
4110f2224f2cSRichard Henderson     } else {
41111852ce5aSRichard Henderson         len = tcg_constant_i32(extract32(ext, 0, 5));
4112f2224f2cSRichard Henderson     }
4113f2224f2cSRichard Henderson     if (ext & 0x800) {
4114f2224f2cSRichard Henderson         ofs = DREG(ext, 6);
4115f2224f2cSRichard Henderson     } else {
41161852ce5aSRichard Henderson         ofs = tcg_constant_i32(extract32(ext, 6, 5));
4117f2224f2cSRichard Henderson     }
4118f2224f2cSRichard Henderson 
4119f2224f2cSRichard Henderson     switch (insn & 0x0f00) {
4120f2224f2cSRichard Henderson     case 0x0a00: /* bfchg */
4121ad75a51eSRichard Henderson         gen_helper_bfchg_mem(QREG_CC_N, tcg_env, addr, ofs, len);
4122f2224f2cSRichard Henderson         break;
4123f2224f2cSRichard Henderson     case 0x0c00: /* bfclr */
4124ad75a51eSRichard Henderson         gen_helper_bfclr_mem(QREG_CC_N, tcg_env, addr, ofs, len);
4125f2224f2cSRichard Henderson         break;
4126a45f1763SRichard Henderson     case 0x0d00: /* bfffo */
4127a45f1763SRichard Henderson         t64 = tcg_temp_new_i64();
4128ad75a51eSRichard Henderson         gen_helper_bfffo_mem(t64, tcg_env, addr, ofs, len);
4129a45f1763SRichard Henderson         tcg_gen_extr_i64_i32(DREG(ext, 12), QREG_CC_N, t64);
4130a45f1763SRichard Henderson         break;
4131f2224f2cSRichard Henderson     case 0x0e00: /* bfset */
4132ad75a51eSRichard Henderson         gen_helper_bfset_mem(QREG_CC_N, tcg_env, addr, ofs, len);
4133f2224f2cSRichard Henderson         break;
4134f2224f2cSRichard Henderson     case 0x0800: /* bftst */
4135ad75a51eSRichard Henderson         gen_helper_bfexts_mem(QREG_CC_N, tcg_env, addr, ofs, len);
4136f2224f2cSRichard Henderson         break;
4137f2224f2cSRichard Henderson     default:
4138f2224f2cSRichard Henderson         g_assert_not_reached();
4139f2224f2cSRichard Henderson     }
4140f2224f2cSRichard Henderson     set_cc_op(s, CC_OP_LOGIC);
4141f2224f2cSRichard Henderson }
4142f2224f2cSRichard Henderson 
DISAS_INSN(bfins_reg)4143ac815f46SRichard Henderson DISAS_INSN(bfins_reg)
4144ac815f46SRichard Henderson {
4145ac815f46SRichard Henderson     int ext = read_im16(env, s);
4146ac815f46SRichard Henderson     TCGv dst = DREG(insn, 0);
4147ac815f46SRichard Henderson     TCGv src = DREG(ext, 12);
4148ac815f46SRichard Henderson     int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
4149ac815f46SRichard Henderson     int ofs = extract32(ext, 6, 5);  /* big bit-endian */
4150ac815f46SRichard Henderson     int pos = 32 - ofs - len;        /* little bit-endian */
4151ac815f46SRichard Henderson     TCGv tmp;
4152ac815f46SRichard Henderson 
4153ac815f46SRichard Henderson     tmp = tcg_temp_new();
4154ac815f46SRichard Henderson 
4155ac815f46SRichard Henderson     if (ext & 0x20) {
4156ac815f46SRichard Henderson         /* Variable width */
4157ac815f46SRichard Henderson         tcg_gen_neg_i32(tmp, DREG(ext, 0));
4158ac815f46SRichard Henderson         tcg_gen_andi_i32(tmp, tmp, 31);
4159ac815f46SRichard Henderson         tcg_gen_shl_i32(QREG_CC_N, src, tmp);
4160ac815f46SRichard Henderson     } else {
4161ac815f46SRichard Henderson         /* Immediate width */
4162ac815f46SRichard Henderson         tcg_gen_shli_i32(QREG_CC_N, src, 32 - len);
4163ac815f46SRichard Henderson     }
4164ac815f46SRichard Henderson     set_cc_op(s, CC_OP_LOGIC);
4165ac815f46SRichard Henderson 
4166ac815f46SRichard Henderson     /* Immediate width and offset */
4167ac815f46SRichard Henderson     if ((ext & 0x820) == 0) {
4168ac815f46SRichard Henderson         /* Check for suitability for deposit.  */
4169ac815f46SRichard Henderson         if (pos >= 0) {
4170ac815f46SRichard Henderson             tcg_gen_deposit_i32(dst, dst, src, pos, len);
4171ac815f46SRichard Henderson         } else {
4172ac815f46SRichard Henderson             uint32_t maski = -2U << (len - 1);
4173ac815f46SRichard Henderson             uint32_t roti = (ofs + len) & 31;
4174ac815f46SRichard Henderson             tcg_gen_andi_i32(tmp, src, ~maski);
4175ac815f46SRichard Henderson             tcg_gen_rotri_i32(tmp, tmp, roti);
4176ac815f46SRichard Henderson             tcg_gen_andi_i32(dst, dst, ror32(maski, roti));
4177ac815f46SRichard Henderson             tcg_gen_or_i32(dst, dst, tmp);
4178ac815f46SRichard Henderson         }
4179ac815f46SRichard Henderson     } else {
4180ac815f46SRichard Henderson         TCGv mask = tcg_temp_new();
4181ac815f46SRichard Henderson         TCGv rot = tcg_temp_new();
4182ac815f46SRichard Henderson 
4183ac815f46SRichard Henderson         if (ext & 0x20) {
4184ac815f46SRichard Henderson             /* Variable width */
4185ac815f46SRichard Henderson             tcg_gen_subi_i32(rot, DREG(ext, 0), 1);
4186ac815f46SRichard Henderson             tcg_gen_andi_i32(rot, rot, 31);
4187ac815f46SRichard Henderson             tcg_gen_movi_i32(mask, -2);
4188ac815f46SRichard Henderson             tcg_gen_shl_i32(mask, mask, rot);
4189ac815f46SRichard Henderson             tcg_gen_mov_i32(rot, DREG(ext, 0));
4190ac815f46SRichard Henderson             tcg_gen_andc_i32(tmp, src, mask);
4191ac815f46SRichard Henderson         } else {
4192ac815f46SRichard Henderson             /* Immediate width (variable offset) */
4193ac815f46SRichard Henderson             uint32_t maski = -2U << (len - 1);
4194ac815f46SRichard Henderson             tcg_gen_andi_i32(tmp, src, ~maski);
4195ac815f46SRichard Henderson             tcg_gen_movi_i32(mask, maski);
4196ac815f46SRichard Henderson             tcg_gen_movi_i32(rot, len & 31);
4197ac815f46SRichard Henderson         }
4198ac815f46SRichard Henderson         if (ext & 0x800) {
4199ac815f46SRichard Henderson             /* Variable offset */
4200ac815f46SRichard Henderson             tcg_gen_add_i32(rot, rot, DREG(ext, 6));
4201ac815f46SRichard Henderson         } else {
4202ac815f46SRichard Henderson             /* Immediate offset (variable width) */
4203ac815f46SRichard Henderson             tcg_gen_addi_i32(rot, rot, ofs);
4204ac815f46SRichard Henderson         }
4205ac815f46SRichard Henderson         tcg_gen_andi_i32(rot, rot, 31);
4206ac815f46SRichard Henderson         tcg_gen_rotr_i32(mask, mask, rot);
4207ac815f46SRichard Henderson         tcg_gen_rotr_i32(tmp, tmp, rot);
4208ac815f46SRichard Henderson         tcg_gen_and_i32(dst, dst, mask);
4209ac815f46SRichard Henderson         tcg_gen_or_i32(dst, dst, tmp);
4210ac815f46SRichard Henderson     }
4211ac815f46SRichard Henderson }
4212ac815f46SRichard Henderson 
DISAS_INSN(bfins_mem)4213f2224f2cSRichard Henderson DISAS_INSN(bfins_mem)
4214f2224f2cSRichard Henderson {
4215f2224f2cSRichard Henderson     int ext = read_im16(env, s);
4216f2224f2cSRichard Henderson     TCGv src = DREG(ext, 12);
4217f2224f2cSRichard Henderson     TCGv addr, len, ofs;
4218f2224f2cSRichard Henderson 
4219f2224f2cSRichard Henderson     addr = gen_lea(env, s, insn, OS_UNSIZED);
4220f2224f2cSRichard Henderson     if (IS_NULL_QREG(addr)) {
4221f2224f2cSRichard Henderson         gen_addr_fault(s);
4222f2224f2cSRichard Henderson         return;
4223f2224f2cSRichard Henderson     }
4224f2224f2cSRichard Henderson 
4225f2224f2cSRichard Henderson     if (ext & 0x20) {
4226f2224f2cSRichard Henderson         len = DREG(ext, 0);
4227f2224f2cSRichard Henderson     } else {
42281852ce5aSRichard Henderson         len = tcg_constant_i32(extract32(ext, 0, 5));
4229f2224f2cSRichard Henderson     }
4230f2224f2cSRichard Henderson     if (ext & 0x800) {
4231f2224f2cSRichard Henderson         ofs = DREG(ext, 6);
4232f2224f2cSRichard Henderson     } else {
42331852ce5aSRichard Henderson         ofs = tcg_constant_i32(extract32(ext, 6, 5));
4234f2224f2cSRichard Henderson     }
4235f2224f2cSRichard Henderson 
4236ad75a51eSRichard Henderson     gen_helper_bfins_mem(QREG_CC_N, tcg_env, addr, src, ofs, len);
4237f2224f2cSRichard Henderson     set_cc_op(s, CC_OP_LOGIC);
4238f2224f2cSRichard Henderson }
4239f2224f2cSRichard Henderson 
DISAS_INSN(ff1)4240fcf5ef2aSThomas Huth DISAS_INSN(ff1)
4241fcf5ef2aSThomas Huth {
4242fcf5ef2aSThomas Huth     TCGv reg;
4243fcf5ef2aSThomas Huth     reg = DREG(insn, 0);
4244fcf5ef2aSThomas Huth     gen_logic_cc(s, reg, OS_LONG);
4245fcf5ef2aSThomas Huth     gen_helper_ff1(reg, reg);
4246fcf5ef2aSThomas Huth }
4247fcf5ef2aSThomas Huth 
DISAS_INSN(chk)42488bf6cbafSLaurent Vivier DISAS_INSN(chk)
4249fcf5ef2aSThomas Huth {
42508bf6cbafSLaurent Vivier     TCGv src, reg;
42518bf6cbafSLaurent Vivier     int opsize;
4252fcf5ef2aSThomas Huth 
42538bf6cbafSLaurent Vivier     switch ((insn >> 7) & 3) {
42548bf6cbafSLaurent Vivier     case 3:
42558bf6cbafSLaurent Vivier         opsize = OS_WORD;
42568bf6cbafSLaurent Vivier         break;
42578bf6cbafSLaurent Vivier     case 2:
42588bf6cbafSLaurent Vivier         if (m68k_feature(env, M68K_FEATURE_CHK2)) {
42598bf6cbafSLaurent Vivier             opsize = OS_LONG;
42608bf6cbafSLaurent Vivier             break;
42618bf6cbafSLaurent Vivier         }
42628bf6cbafSLaurent Vivier         /* fallthru */
42638bf6cbafSLaurent Vivier     default:
4264a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
42658bf6cbafSLaurent Vivier         return;
42668bf6cbafSLaurent Vivier     }
42678bf6cbafSLaurent Vivier     SRC_EA(env, src, opsize, 1, NULL);
42683f215a14SLaurent Vivier     reg = gen_extend(s, DREG(insn, 9), opsize, 1);
42698bf6cbafSLaurent Vivier 
42708bf6cbafSLaurent Vivier     gen_flush_flags(s);
4271ad75a51eSRichard Henderson     gen_helper_chk(tcg_env, reg, src);
42728bf6cbafSLaurent Vivier }
42738bf6cbafSLaurent Vivier 
DISAS_INSN(chk2)42748bf6cbafSLaurent Vivier DISAS_INSN(chk2)
42758bf6cbafSLaurent Vivier {
42768bf6cbafSLaurent Vivier     uint16_t ext;
42778bf6cbafSLaurent Vivier     TCGv addr1, addr2, bound1, bound2, reg;
42788bf6cbafSLaurent Vivier     int opsize;
42798bf6cbafSLaurent Vivier 
42808bf6cbafSLaurent Vivier     switch ((insn >> 9) & 3) {
42818bf6cbafSLaurent Vivier     case 0:
42828bf6cbafSLaurent Vivier         opsize = OS_BYTE;
42838bf6cbafSLaurent Vivier         break;
42848bf6cbafSLaurent Vivier     case 1:
42858bf6cbafSLaurent Vivier         opsize = OS_WORD;
42868bf6cbafSLaurent Vivier         break;
42878bf6cbafSLaurent Vivier     case 2:
42888bf6cbafSLaurent Vivier         opsize = OS_LONG;
42898bf6cbafSLaurent Vivier         break;
42908bf6cbafSLaurent Vivier     default:
4291a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
42928bf6cbafSLaurent Vivier         return;
42938bf6cbafSLaurent Vivier     }
42948bf6cbafSLaurent Vivier 
42958bf6cbafSLaurent Vivier     ext = read_im16(env, s);
42968bf6cbafSLaurent Vivier     if ((ext & 0x0800) == 0) {
4297a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
42988bf6cbafSLaurent Vivier         return;
42998bf6cbafSLaurent Vivier     }
43008bf6cbafSLaurent Vivier 
43018bf6cbafSLaurent Vivier     addr1 = gen_lea(env, s, insn, OS_UNSIZED);
43028bf6cbafSLaurent Vivier     addr2 = tcg_temp_new();
43038bf6cbafSLaurent Vivier     tcg_gen_addi_i32(addr2, addr1, opsize_bytes(opsize));
43048bf6cbafSLaurent Vivier 
430554e1e0b5SLaurent Vivier     bound1 = gen_load(s, opsize, addr1, 1, IS_USER(s));
430654e1e0b5SLaurent Vivier     bound2 = gen_load(s, opsize, addr2, 1, IS_USER(s));
43078bf6cbafSLaurent Vivier 
43088bf6cbafSLaurent Vivier     reg = tcg_temp_new();
43098bf6cbafSLaurent Vivier     if (ext & 0x8000) {
43108bf6cbafSLaurent Vivier         tcg_gen_mov_i32(reg, AREG(ext, 12));
43118bf6cbafSLaurent Vivier     } else {
43128bf6cbafSLaurent Vivier         gen_ext(reg, DREG(ext, 12), opsize, 1);
43138bf6cbafSLaurent Vivier     }
43148bf6cbafSLaurent Vivier 
43158bf6cbafSLaurent Vivier     gen_flush_flags(s);
4316ad75a51eSRichard Henderson     gen_helper_chk2(tcg_env, reg, bound1, bound2);
43178bf6cbafSLaurent Vivier }
43188bf6cbafSLaurent Vivier 
m68k_copy_line(TCGv dst,TCGv src,int index)43199d4f0429SLaurent Vivier static void m68k_copy_line(TCGv dst, TCGv src, int index)
43209d4f0429SLaurent Vivier {
43219d4f0429SLaurent Vivier     TCGv addr;
43229d4f0429SLaurent Vivier     TCGv_i64 t0, t1;
43239d4f0429SLaurent Vivier 
43249d4f0429SLaurent Vivier     addr = tcg_temp_new();
43259d4f0429SLaurent Vivier 
43269d4f0429SLaurent Vivier     t0 = tcg_temp_new_i64();
43279d4f0429SLaurent Vivier     t1 = tcg_temp_new_i64();
43289d4f0429SLaurent Vivier 
43299d4f0429SLaurent Vivier     tcg_gen_andi_i32(addr, src, ~15);
4330b7a94da9SRichard Henderson     tcg_gen_qemu_ld_i64(t0, addr, index, MO_TEUQ);
43319d4f0429SLaurent Vivier     tcg_gen_addi_i32(addr, addr, 8);
4332b7a94da9SRichard Henderson     tcg_gen_qemu_ld_i64(t1, addr, index, MO_TEUQ);
43339d4f0429SLaurent Vivier 
43349d4f0429SLaurent Vivier     tcg_gen_andi_i32(addr, dst, ~15);
4335b7a94da9SRichard Henderson     tcg_gen_qemu_st_i64(t0, addr, index, MO_TEUQ);
43369d4f0429SLaurent Vivier     tcg_gen_addi_i32(addr, addr, 8);
4337b7a94da9SRichard Henderson     tcg_gen_qemu_st_i64(t1, addr, index, MO_TEUQ);
43389d4f0429SLaurent Vivier }
43399d4f0429SLaurent Vivier 
DISAS_INSN(move16_reg)43409d4f0429SLaurent Vivier DISAS_INSN(move16_reg)
43419d4f0429SLaurent Vivier {
43429d4f0429SLaurent Vivier     int index = IS_USER(s);
43439d4f0429SLaurent Vivier     TCGv tmp;
43449d4f0429SLaurent Vivier     uint16_t ext;
43459d4f0429SLaurent Vivier 
43469d4f0429SLaurent Vivier     ext = read_im16(env, s);
43479d4f0429SLaurent Vivier     if ((ext & (1 << 15)) == 0) {
4348a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
43499d4f0429SLaurent Vivier     }
43509d4f0429SLaurent Vivier 
43519d4f0429SLaurent Vivier     m68k_copy_line(AREG(ext, 12), AREG(insn, 0), index);
43529d4f0429SLaurent Vivier 
43539d4f0429SLaurent Vivier     /* Ax can be Ay, so save Ay before incrementing Ax */
43549d4f0429SLaurent Vivier     tmp = tcg_temp_new();
43559d4f0429SLaurent Vivier     tcg_gen_mov_i32(tmp, AREG(ext, 12));
43569d4f0429SLaurent Vivier     tcg_gen_addi_i32(AREG(insn, 0), AREG(insn, 0), 16);
43579d4f0429SLaurent Vivier     tcg_gen_addi_i32(AREG(ext, 12), tmp, 16);
43589d4f0429SLaurent Vivier }
43599d4f0429SLaurent Vivier 
DISAS_INSN(move16_mem)43609d4f0429SLaurent Vivier DISAS_INSN(move16_mem)
43619d4f0429SLaurent Vivier {
43629d4f0429SLaurent Vivier     int index = IS_USER(s);
43639d4f0429SLaurent Vivier     TCGv reg, addr;
43649d4f0429SLaurent Vivier 
43659d4f0429SLaurent Vivier     reg = AREG(insn, 0);
43661852ce5aSRichard Henderson     addr = tcg_constant_i32(read_im32(env, s));
43679d4f0429SLaurent Vivier 
43689d4f0429SLaurent Vivier     if ((insn >> 3) & 1) {
43699d4f0429SLaurent Vivier         /* MOVE16 (xxx).L, (Ay) */
43709d4f0429SLaurent Vivier         m68k_copy_line(reg, addr, index);
43719d4f0429SLaurent Vivier     } else {
43729d4f0429SLaurent Vivier         /* MOVE16 (Ay), (xxx).L */
43739d4f0429SLaurent Vivier         m68k_copy_line(addr, reg, index);
43749d4f0429SLaurent Vivier     }
43759d4f0429SLaurent Vivier 
43769d4f0429SLaurent Vivier     if (((insn >> 3) & 2) == 0) {
43779d4f0429SLaurent Vivier         /* (Ay)+ */
43789d4f0429SLaurent Vivier         tcg_gen_addi_i32(reg, reg, 16);
43799d4f0429SLaurent Vivier     }
4380fcf5ef2aSThomas Huth }
4381fcf5ef2aSThomas Huth 
DISAS_INSN(strldsr)4382fcf5ef2aSThomas Huth DISAS_INSN(strldsr)
4383fcf5ef2aSThomas Huth {
4384fcf5ef2aSThomas Huth     uint16_t ext;
4385fcf5ef2aSThomas Huth     uint32_t addr;
4386fcf5ef2aSThomas Huth 
4387fcf5ef2aSThomas Huth     addr = s->pc - 2;
4388fcf5ef2aSThomas Huth     ext = read_im16(env, s);
4389fcf5ef2aSThomas Huth     if (ext != 0x46FC) {
4390b9f8e55bSLaurent Vivier         gen_exception(s, addr, EXCP_ILLEGAL);
4391fcf5ef2aSThomas Huth         return;
4392fcf5ef2aSThomas Huth     }
4393fcf5ef2aSThomas Huth     ext = read_im16(env, s);
4394fcf5ef2aSThomas Huth     if (IS_USER(s) || (ext & SR_S) == 0) {
4395fcf5ef2aSThomas Huth         gen_exception(s, addr, EXCP_PRIVILEGE);
4396fcf5ef2aSThomas Huth         return;
4397fcf5ef2aSThomas Huth     }
4398fcf5ef2aSThomas Huth     gen_push(s, gen_get_sr(s));
4399fcf5ef2aSThomas Huth     gen_set_sr_im(s, ext, 0);
4400c7546abfSMark Cave-Ayland     gen_exit_tb(s);
4401fcf5ef2aSThomas Huth }
4402fcf5ef2aSThomas Huth 
DISAS_INSN(move_from_sr)4403fcf5ef2aSThomas Huth DISAS_INSN(move_from_sr)
4404fcf5ef2aSThomas Huth {
4405fcf5ef2aSThomas Huth     TCGv sr;
4406fcf5ef2aSThomas Huth 
4407b342e56bSMark Cave-Ayland     if (IS_USER(s) && m68k_feature(env, M68K_FEATURE_MOVEFROMSR_PRIV)) {
4408a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4409fcf5ef2aSThomas Huth         return;
4410fcf5ef2aSThomas Huth     }
4411fcf5ef2aSThomas Huth     sr = gen_get_sr(s);
4412fcf5ef2aSThomas Huth     DEST_EA(env, insn, OS_WORD, sr, NULL);
4413fcf5ef2aSThomas Huth }
4414fcf5ef2aSThomas Huth 
44156a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
DISAS_INSN(moves)44165fa9f1f2SLaurent Vivier DISAS_INSN(moves)
44175fa9f1f2SLaurent Vivier {
44185fa9f1f2SLaurent Vivier     int opsize;
44195fa9f1f2SLaurent Vivier     uint16_t ext;
44205fa9f1f2SLaurent Vivier     TCGv reg;
44215fa9f1f2SLaurent Vivier     TCGv addr;
44225fa9f1f2SLaurent Vivier     int extend;
44235fa9f1f2SLaurent Vivier 
44245fa9f1f2SLaurent Vivier     if (IS_USER(s)) {
4425a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
44265fa9f1f2SLaurent Vivier         return;
44275fa9f1f2SLaurent Vivier     }
44285fa9f1f2SLaurent Vivier 
44295fa9f1f2SLaurent Vivier     ext = read_im16(env, s);
44305fa9f1f2SLaurent Vivier 
44315fa9f1f2SLaurent Vivier     opsize = insn_opsize(insn);
44325fa9f1f2SLaurent Vivier 
44335fa9f1f2SLaurent Vivier     if (ext & 0x8000) {
44345fa9f1f2SLaurent Vivier         /* address register */
44355fa9f1f2SLaurent Vivier         reg = AREG(ext, 12);
44365fa9f1f2SLaurent Vivier         extend = 1;
44375fa9f1f2SLaurent Vivier     } else {
44385fa9f1f2SLaurent Vivier         /* data register */
44395fa9f1f2SLaurent Vivier         reg = DREG(ext, 12);
44405fa9f1f2SLaurent Vivier         extend = 0;
44415fa9f1f2SLaurent Vivier     }
44425fa9f1f2SLaurent Vivier 
44435fa9f1f2SLaurent Vivier     addr = gen_lea(env, s, insn, opsize);
44445fa9f1f2SLaurent Vivier     if (IS_NULL_QREG(addr)) {
44455fa9f1f2SLaurent Vivier         gen_addr_fault(s);
44465fa9f1f2SLaurent Vivier         return;
44475fa9f1f2SLaurent Vivier     }
44485fa9f1f2SLaurent Vivier 
44495fa9f1f2SLaurent Vivier     if (ext & 0x0800) {
44505fa9f1f2SLaurent Vivier         /* from reg to ea */
44515fa9f1f2SLaurent Vivier         gen_store(s, opsize, addr, reg, DFC_INDEX(s));
44525fa9f1f2SLaurent Vivier     } else {
44535fa9f1f2SLaurent Vivier         /* from ea to reg */
44545fa9f1f2SLaurent Vivier         TCGv tmp = gen_load(s, opsize, addr, 0, SFC_INDEX(s));
44555fa9f1f2SLaurent Vivier         if (extend) {
44565fa9f1f2SLaurent Vivier             gen_ext(reg, tmp, opsize, 1);
44575fa9f1f2SLaurent Vivier         } else {
44585fa9f1f2SLaurent Vivier             gen_partset_reg(opsize, reg, tmp);
44595fa9f1f2SLaurent Vivier         }
44605fa9f1f2SLaurent Vivier     }
44615fa9f1f2SLaurent Vivier     switch (extract32(insn, 3, 3)) {
44625fa9f1f2SLaurent Vivier     case 3: /* Indirect postincrement.  */
44635fa9f1f2SLaurent Vivier         tcg_gen_addi_i32(AREG(insn, 0), addr,
44645fa9f1f2SLaurent Vivier                          REG(insn, 0) == 7 && opsize == OS_BYTE
44655fa9f1f2SLaurent Vivier                          ? 2
44665fa9f1f2SLaurent Vivier                          : opsize_bytes(opsize));
44675fa9f1f2SLaurent Vivier         break;
44685fa9f1f2SLaurent Vivier     case 4: /* Indirect predecrememnt.  */
44695fa9f1f2SLaurent Vivier         tcg_gen_mov_i32(AREG(insn, 0), addr);
44705fa9f1f2SLaurent Vivier         break;
44715fa9f1f2SLaurent Vivier     }
44725fa9f1f2SLaurent Vivier }
44735fa9f1f2SLaurent Vivier 
DISAS_INSN(move_to_sr)4474fcf5ef2aSThomas Huth DISAS_INSN(move_to_sr)
4475fcf5ef2aSThomas Huth {
4476fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4477a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4478fcf5ef2aSThomas Huth         return;
4479fcf5ef2aSThomas Huth     }
4480b6a21d8dSLaurent Vivier     gen_move_to_sr(env, s, insn, false);
44814106f26eSRichard Henderson     gen_exit_tb(s);
4482fcf5ef2aSThomas Huth }
4483fcf5ef2aSThomas Huth 
DISAS_INSN(move_from_usp)4484fcf5ef2aSThomas Huth DISAS_INSN(move_from_usp)
4485fcf5ef2aSThomas Huth {
4486fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4487a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4488fcf5ef2aSThomas Huth         return;
4489fcf5ef2aSThomas Huth     }
4490ad75a51eSRichard Henderson     tcg_gen_ld_i32(AREG(insn, 0), tcg_env,
4491fcf5ef2aSThomas Huth                    offsetof(CPUM68KState, sp[M68K_USP]));
4492fcf5ef2aSThomas Huth }
4493fcf5ef2aSThomas Huth 
DISAS_INSN(move_to_usp)4494fcf5ef2aSThomas Huth DISAS_INSN(move_to_usp)
4495fcf5ef2aSThomas Huth {
4496fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4497a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4498fcf5ef2aSThomas Huth         return;
4499fcf5ef2aSThomas Huth     }
4500ad75a51eSRichard Henderson     tcg_gen_st_i32(AREG(insn, 0), tcg_env,
4501fcf5ef2aSThomas Huth                    offsetof(CPUM68KState, sp[M68K_USP]));
4502fcf5ef2aSThomas Huth }
4503fcf5ef2aSThomas Huth 
DISAS_INSN(halt)4504fcf5ef2aSThomas Huth DISAS_INSN(halt)
4505fcf5ef2aSThomas Huth {
45066ad25764SLaurent Vivier     if (IS_USER(s)) {
4507a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
45086ad25764SLaurent Vivier         return;
45096ad25764SLaurent Vivier     }
4510f161e723SRichard Henderson     if (semihosting_test(s)) {
4511f161e723SRichard Henderson         gen_exception(s, s->pc, EXCP_SEMIHOSTING);
4512f161e723SRichard Henderson         return;
4513f161e723SRichard Henderson     }
4514f161e723SRichard Henderson     tcg_gen_movi_i32(cpu_halted, 1);
4515f161e723SRichard Henderson     gen_exception(s, s->pc, EXCP_HLT);
4516fcf5ef2aSThomas Huth }
4517fcf5ef2aSThomas Huth 
DISAS_INSN(stop)4518fcf5ef2aSThomas Huth DISAS_INSN(stop)
4519fcf5ef2aSThomas Huth {
4520fcf5ef2aSThomas Huth     uint16_t ext;
4521fcf5ef2aSThomas Huth 
4522fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4523a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4524fcf5ef2aSThomas Huth         return;
4525fcf5ef2aSThomas Huth     }
4526fcf5ef2aSThomas Huth 
4527fcf5ef2aSThomas Huth     ext = read_im16(env, s);
4528fcf5ef2aSThomas Huth 
4529fcf5ef2aSThomas Huth     gen_set_sr_im(s, ext, 0);
4530fcf5ef2aSThomas Huth     tcg_gen_movi_i32(cpu_halted, 1);
4531fcf5ef2aSThomas Huth     gen_exception(s, s->pc, EXCP_HLT);
4532fcf5ef2aSThomas Huth }
4533fcf5ef2aSThomas Huth 
DISAS_INSN(rte)4534fcf5ef2aSThomas Huth DISAS_INSN(rte)
4535fcf5ef2aSThomas Huth {
4536fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4537a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4538fcf5ef2aSThomas Huth         return;
4539fcf5ef2aSThomas Huth     }
4540a575cbe0SRichard Henderson     gen_exception(s, s->base.pc_next, EXCP_RTE);
4541fcf5ef2aSThomas Huth }
4542fcf5ef2aSThomas Huth 
DISAS_INSN(cf_movec)45436e22b28eSLaurent Vivier DISAS_INSN(cf_movec)
4544fcf5ef2aSThomas Huth {
4545fcf5ef2aSThomas Huth     uint16_t ext;
4546fcf5ef2aSThomas Huth     TCGv reg;
4547fcf5ef2aSThomas Huth 
4548fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4549a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4550fcf5ef2aSThomas Huth         return;
4551fcf5ef2aSThomas Huth     }
4552fcf5ef2aSThomas Huth 
4553fcf5ef2aSThomas Huth     ext = read_im16(env, s);
4554fcf5ef2aSThomas Huth 
4555fcf5ef2aSThomas Huth     if (ext & 0x8000) {
4556fcf5ef2aSThomas Huth         reg = AREG(ext, 12);
4557fcf5ef2aSThomas Huth     } else {
4558fcf5ef2aSThomas Huth         reg = DREG(ext, 12);
4559fcf5ef2aSThomas Huth     }
4560ad75a51eSRichard Henderson     gen_helper_cf_movec_to(tcg_env, tcg_constant_i32(ext & 0xfff), reg);
45614106f26eSRichard Henderson     gen_exit_tb(s);
45626e22b28eSLaurent Vivier }
45636e22b28eSLaurent Vivier 
DISAS_INSN(m68k_movec)45646e22b28eSLaurent Vivier DISAS_INSN(m68k_movec)
45656e22b28eSLaurent Vivier {
45666e22b28eSLaurent Vivier     uint16_t ext;
45671852ce5aSRichard Henderson     TCGv reg, creg;
45686e22b28eSLaurent Vivier 
45696e22b28eSLaurent Vivier     if (IS_USER(s)) {
4570a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
45716e22b28eSLaurent Vivier         return;
45726e22b28eSLaurent Vivier     }
45736e22b28eSLaurent Vivier 
45746e22b28eSLaurent Vivier     ext = read_im16(env, s);
45756e22b28eSLaurent Vivier 
45766e22b28eSLaurent Vivier     if (ext & 0x8000) {
45776e22b28eSLaurent Vivier         reg = AREG(ext, 12);
45786e22b28eSLaurent Vivier     } else {
45796e22b28eSLaurent Vivier         reg = DREG(ext, 12);
45806e22b28eSLaurent Vivier     }
45811852ce5aSRichard Henderson     creg = tcg_constant_i32(ext & 0xfff);
45826e22b28eSLaurent Vivier     if (insn & 1) {
4583ad75a51eSRichard Henderson         gen_helper_m68k_movec_to(tcg_env, creg, reg);
45846e22b28eSLaurent Vivier     } else {
4585ad75a51eSRichard Henderson         gen_helper_m68k_movec_from(reg, tcg_env, creg);
45866e22b28eSLaurent Vivier     }
45874106f26eSRichard Henderson     gen_exit_tb(s);
4588fcf5ef2aSThomas Huth }
4589fcf5ef2aSThomas Huth 
DISAS_INSN(intouch)4590fcf5ef2aSThomas Huth DISAS_INSN(intouch)
4591fcf5ef2aSThomas Huth {
4592fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4593a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4594fcf5ef2aSThomas Huth         return;
4595fcf5ef2aSThomas Huth     }
4596fcf5ef2aSThomas Huth     /* ICache fetch.  Implement as no-op.  */
4597fcf5ef2aSThomas Huth }
4598fcf5ef2aSThomas Huth 
DISAS_INSN(cpushl)4599fcf5ef2aSThomas Huth DISAS_INSN(cpushl)
4600fcf5ef2aSThomas Huth {
4601fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4602a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4603fcf5ef2aSThomas Huth         return;
4604fcf5ef2aSThomas Huth     }
4605fcf5ef2aSThomas Huth     /* Cache push/invalidate.  Implement as no-op.  */
4606fcf5ef2aSThomas Huth }
4607fcf5ef2aSThomas Huth 
DISAS_INSN(cpush)4608f58ed1c5SLaurent Vivier DISAS_INSN(cpush)
4609f58ed1c5SLaurent Vivier {
4610f58ed1c5SLaurent Vivier     if (IS_USER(s)) {
4611a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4612f58ed1c5SLaurent Vivier         return;
4613f58ed1c5SLaurent Vivier     }
4614f58ed1c5SLaurent Vivier     /* Cache push/invalidate.  Implement as no-op.  */
4615f58ed1c5SLaurent Vivier }
4616f58ed1c5SLaurent Vivier 
DISAS_INSN(cinv)4617f58ed1c5SLaurent Vivier DISAS_INSN(cinv)
4618f58ed1c5SLaurent Vivier {
4619f58ed1c5SLaurent Vivier     if (IS_USER(s)) {
4620a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4621f58ed1c5SLaurent Vivier         return;
4622f58ed1c5SLaurent Vivier     }
4623f58ed1c5SLaurent Vivier     /* Invalidate cache line.  Implement as no-op.  */
4624f58ed1c5SLaurent Vivier }
4625f58ed1c5SLaurent Vivier 
46266a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
DISAS_INSN(pflush)4627e55886c3SLaurent Vivier DISAS_INSN(pflush)
4628e55886c3SLaurent Vivier {
4629e55886c3SLaurent Vivier     TCGv opmode;
4630e55886c3SLaurent Vivier 
4631e55886c3SLaurent Vivier     if (IS_USER(s)) {
4632a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4633e55886c3SLaurent Vivier         return;
4634e55886c3SLaurent Vivier     }
4635e55886c3SLaurent Vivier 
46361852ce5aSRichard Henderson     opmode = tcg_constant_i32((insn >> 3) & 3);
4637ad75a51eSRichard Henderson     gen_helper_pflush(tcg_env, AREG(insn, 0), opmode);
4638e55886c3SLaurent Vivier }
4639e55886c3SLaurent Vivier 
DISAS_INSN(ptest)4640e55886c3SLaurent Vivier DISAS_INSN(ptest)
4641e55886c3SLaurent Vivier {
4642e55886c3SLaurent Vivier     TCGv is_read;
4643e55886c3SLaurent Vivier 
4644e55886c3SLaurent Vivier     if (IS_USER(s)) {
4645a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4646e55886c3SLaurent Vivier         return;
4647e55886c3SLaurent Vivier     }
46481852ce5aSRichard Henderson     is_read = tcg_constant_i32((insn >> 5) & 1);
4649ad75a51eSRichard Henderson     gen_helper_ptest(tcg_env, AREG(insn, 0), is_read);
4650e55886c3SLaurent Vivier }
4651e55886c3SLaurent Vivier #endif
4652e55886c3SLaurent Vivier 
DISAS_INSN(wddata)4653fcf5ef2aSThomas Huth DISAS_INSN(wddata)
4654fcf5ef2aSThomas Huth {
4655a575cbe0SRichard Henderson     gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4656fcf5ef2aSThomas Huth }
4657fcf5ef2aSThomas Huth 
DISAS_INSN(wdebug)4658fcf5ef2aSThomas Huth DISAS_INSN(wdebug)
4659fcf5ef2aSThomas Huth {
4660fcf5ef2aSThomas Huth     if (IS_USER(s)) {
4661a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4662fcf5ef2aSThomas Huth         return;
4663fcf5ef2aSThomas Huth     }
4664fcf5ef2aSThomas Huth     /* TODO: Implement wdebug.  */
4665a8d92fd8SRichard Henderson     cpu_abort(env_cpu(env), "WDEBUG not implemented");
4666fcf5ef2aSThomas Huth }
46676ad25764SLaurent Vivier #endif
4668fcf5ef2aSThomas Huth 
DISAS_INSN(trap)4669fcf5ef2aSThomas Huth DISAS_INSN(trap)
4670fcf5ef2aSThomas Huth {
467179e1d527SRichard Henderson     gen_exception(s, s->pc, EXCP_TRAP0 + (insn & 0xf));
4672fcf5ef2aSThomas Huth }
4673fcf5ef2aSThomas Huth 
do_trapcc(DisasContext * s,DisasCompare * c)4674aeeb90afSRichard Henderson static void do_trapcc(DisasContext *s, DisasCompare *c)
4675aeeb90afSRichard Henderson {
4676aeeb90afSRichard Henderson     if (c->tcond != TCG_COND_NEVER) {
4677aeeb90afSRichard Henderson         TCGLabel *over = NULL;
4678aeeb90afSRichard Henderson 
4679aeeb90afSRichard Henderson         update_cc_op(s);
4680aeeb90afSRichard Henderson 
4681aeeb90afSRichard Henderson         if (c->tcond != TCG_COND_ALWAYS) {
4682aeeb90afSRichard Henderson             /* Jump over if !c. */
4683aeeb90afSRichard Henderson             over = gen_new_label();
4684aeeb90afSRichard Henderson             tcg_gen_brcond_i32(tcg_invert_cond(c->tcond), c->v1, c->v2, over);
4685aeeb90afSRichard Henderson         }
4686aeeb90afSRichard Henderson 
4687aeeb90afSRichard Henderson         tcg_gen_movi_i32(QREG_PC, s->pc);
4688aeeb90afSRichard Henderson         gen_raise_exception_format2(s, EXCP_TRAPCC, s->base.pc_next);
4689aeeb90afSRichard Henderson 
4690aeeb90afSRichard Henderson         if (over != NULL) {
4691aeeb90afSRichard Henderson             gen_set_label(over);
4692aeeb90afSRichard Henderson             s->base.is_jmp = DISAS_NEXT;
4693aeeb90afSRichard Henderson         }
4694aeeb90afSRichard Henderson     }
4695aeeb90afSRichard Henderson }
4696aeeb90afSRichard Henderson 
DISAS_INSN(trapcc)4697aeeb90afSRichard Henderson DISAS_INSN(trapcc)
4698aeeb90afSRichard Henderson {
4699aeeb90afSRichard Henderson     DisasCompare c;
4700aeeb90afSRichard Henderson 
4701aeeb90afSRichard Henderson     /* Consume and discard the immediate operand. */
4702aeeb90afSRichard Henderson     switch (extract32(insn, 0, 3)) {
4703aeeb90afSRichard Henderson     case 2: /* trapcc.w */
4704aeeb90afSRichard Henderson         (void)read_im16(env, s);
4705aeeb90afSRichard Henderson         break;
4706aeeb90afSRichard Henderson     case 3: /* trapcc.l */
4707aeeb90afSRichard Henderson         (void)read_im32(env, s);
4708aeeb90afSRichard Henderson         break;
4709aeeb90afSRichard Henderson     case 4: /* trapcc (no operand) */
4710aeeb90afSRichard Henderson         break;
4711aeeb90afSRichard Henderson     default:
4712aeeb90afSRichard Henderson         /* trapcc registered with only valid opmodes */
4713aeeb90afSRichard Henderson         g_assert_not_reached();
4714aeeb90afSRichard Henderson     }
4715aeeb90afSRichard Henderson 
4716aeeb90afSRichard Henderson     gen_cc_cond(&c, s, extract32(insn, 8, 4));
4717aeeb90afSRichard Henderson     do_trapcc(s, &c);
4718aeeb90afSRichard Henderson }
4719aeeb90afSRichard Henderson 
DISAS_INSN(trapv)472043accc48SRichard Henderson DISAS_INSN(trapv)
472143accc48SRichard Henderson {
472243accc48SRichard Henderson     DisasCompare c;
472343accc48SRichard Henderson 
472443accc48SRichard Henderson     gen_cc_cond(&c, s, 9); /* V set */
472543accc48SRichard Henderson     do_trapcc(s, &c);
472643accc48SRichard Henderson }
472743accc48SRichard Henderson 
gen_load_fcr(DisasContext * s,TCGv res,int reg)4728ba624944SLaurent Vivier static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
4729ba624944SLaurent Vivier {
4730ba624944SLaurent Vivier     switch (reg) {
4731ba624944SLaurent Vivier     case M68K_FPIAR:
4732ba624944SLaurent Vivier         tcg_gen_movi_i32(res, 0);
4733ba624944SLaurent Vivier         break;
4734ba624944SLaurent Vivier     case M68K_FPSR:
473558883579SKeith Packard         gen_helper_get_fpsr(res, tcg_env);
4736ba624944SLaurent Vivier         break;
4737ba624944SLaurent Vivier     case M68K_FPCR:
4738ad75a51eSRichard Henderson         tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpcr));
4739ba624944SLaurent Vivier         break;
4740ba624944SLaurent Vivier     }
4741ba624944SLaurent Vivier }
4742ba624944SLaurent Vivier 
gen_store_fcr(DisasContext * s,TCGv val,int reg)4743ba624944SLaurent Vivier static void gen_store_fcr(DisasContext *s, TCGv val, int reg)
4744ba624944SLaurent Vivier {
4745ba624944SLaurent Vivier     switch (reg) {
4746ba624944SLaurent Vivier     case M68K_FPIAR:
4747ba624944SLaurent Vivier         break;
4748ba624944SLaurent Vivier     case M68K_FPSR:
474958883579SKeith Packard         gen_helper_set_fpsr(tcg_env, val);
4750ba624944SLaurent Vivier         break;
4751ba624944SLaurent Vivier     case M68K_FPCR:
4752ad75a51eSRichard Henderson         gen_helper_set_fpcr(tcg_env, val);
4753ba624944SLaurent Vivier         break;
4754ba624944SLaurent Vivier     }
4755ba624944SLaurent Vivier }
4756ba624944SLaurent Vivier 
gen_qemu_store_fcr(DisasContext * s,TCGv addr,int reg)4757ba624944SLaurent Vivier static void gen_qemu_store_fcr(DisasContext *s, TCGv addr, int reg)
4758ba624944SLaurent Vivier {
4759ba624944SLaurent Vivier     int index = IS_USER(s);
4760ba624944SLaurent Vivier     TCGv tmp;
4761ba624944SLaurent Vivier 
4762ba624944SLaurent Vivier     tmp = tcg_temp_new();
4763ba624944SLaurent Vivier     gen_load_fcr(s, tmp, reg);
4764b7a94da9SRichard Henderson     tcg_gen_qemu_st_tl(tmp, addr, index, MO_TEUL);
4765ba624944SLaurent Vivier }
4766ba624944SLaurent Vivier 
gen_qemu_load_fcr(DisasContext * s,TCGv addr,int reg)4767ba624944SLaurent Vivier static void gen_qemu_load_fcr(DisasContext *s, TCGv addr, int reg)
4768ba624944SLaurent Vivier {
4769ba624944SLaurent Vivier     int index = IS_USER(s);
4770ba624944SLaurent Vivier     TCGv tmp;
4771ba624944SLaurent Vivier 
4772ba624944SLaurent Vivier     tmp = tcg_temp_new();
4773b7a94da9SRichard Henderson     tcg_gen_qemu_ld_tl(tmp, addr, index, MO_TEUL);
4774ba624944SLaurent Vivier     gen_store_fcr(s, tmp, reg);
4775ba624944SLaurent Vivier }
4776ba624944SLaurent Vivier 
4777ba624944SLaurent Vivier 
gen_op_fmove_fcr(CPUM68KState * env,DisasContext * s,uint32_t insn,uint32_t ext)4778860b9ac7SLaurent Vivier static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
4779860b9ac7SLaurent Vivier                              uint32_t insn, uint32_t ext)
4780860b9ac7SLaurent Vivier {
4781860b9ac7SLaurent Vivier     int mask = (ext >> 10) & 7;
4782860b9ac7SLaurent Vivier     int is_write = (ext >> 13) & 1;
4783ba624944SLaurent Vivier     int mode = extract32(insn, 3, 3);
4784ba624944SLaurent Vivier     int i;
4785ba624944SLaurent Vivier     TCGv addr, tmp;
4786860b9ac7SLaurent Vivier 
4787ba624944SLaurent Vivier     switch (mode) {
4788ba624944SLaurent Vivier     case 0: /* Dn */
4789ba624944SLaurent Vivier         if (mask != M68K_FPIAR && mask != M68K_FPSR && mask != M68K_FPCR) {
4790a575cbe0SRichard Henderson             gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4791ba624944SLaurent Vivier             return;
4792860b9ac7SLaurent Vivier         }
4793ba624944SLaurent Vivier         if (is_write) {
4794ba624944SLaurent Vivier             gen_load_fcr(s, DREG(insn, 0), mask);
4795ba624944SLaurent Vivier         } else {
4796ba624944SLaurent Vivier             gen_store_fcr(s, DREG(insn, 0), mask);
4797860b9ac7SLaurent Vivier         }
4798860b9ac7SLaurent Vivier         return;
4799ba624944SLaurent Vivier     case 1: /* An, only with FPIAR */
4800ba624944SLaurent Vivier         if (mask != M68K_FPIAR) {
4801a575cbe0SRichard Henderson             gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4802ba624944SLaurent Vivier             return;
4803ba624944SLaurent Vivier         }
4804ba624944SLaurent Vivier         if (is_write) {
4805ba624944SLaurent Vivier             gen_load_fcr(s, AREG(insn, 0), mask);
4806ba624944SLaurent Vivier         } else {
4807ba624944SLaurent Vivier             gen_store_fcr(s, AREG(insn, 0), mask);
4808ba624944SLaurent Vivier         }
4809ba624944SLaurent Vivier         return;
48106a0e8bb4SLaurent Vivier     case 7: /* Immediate */
48116a0e8bb4SLaurent Vivier         if (REG(insn, 0) == 4) {
48126a0e8bb4SLaurent Vivier             if (is_write ||
48136a0e8bb4SLaurent Vivier                 (mask != M68K_FPIAR && mask != M68K_FPSR &&
48146a0e8bb4SLaurent Vivier                  mask != M68K_FPCR)) {
48156a0e8bb4SLaurent Vivier                 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
48166a0e8bb4SLaurent Vivier                 return;
48176a0e8bb4SLaurent Vivier             }
48181852ce5aSRichard Henderson             tmp = tcg_constant_i32(read_im32(env, s));
48196a0e8bb4SLaurent Vivier             gen_store_fcr(s, tmp, mask);
48206a0e8bb4SLaurent Vivier             return;
48216a0e8bb4SLaurent Vivier         }
48226a0e8bb4SLaurent Vivier         break;
4823ba624944SLaurent Vivier     default:
4824ba624944SLaurent Vivier         break;
4825ba624944SLaurent Vivier     }
4826ba624944SLaurent Vivier 
4827ba624944SLaurent Vivier     tmp = gen_lea(env, s, insn, OS_LONG);
4828ba624944SLaurent Vivier     if (IS_NULL_QREG(tmp)) {
4829ba624944SLaurent Vivier         gen_addr_fault(s);
4830ba624944SLaurent Vivier         return;
4831ba624944SLaurent Vivier     }
4832ba624944SLaurent Vivier 
4833ba624944SLaurent Vivier     addr = tcg_temp_new();
4834ba624944SLaurent Vivier     tcg_gen_mov_i32(addr, tmp);
4835ba624944SLaurent Vivier 
4836808d77bcSLucien Murray-Pitts     /*
4837808d77bcSLucien Murray-Pitts      * mask:
4838ba624944SLaurent Vivier      *
4839ba624944SLaurent Vivier      * 0b100 Floating-Point Control Register
4840ba624944SLaurent Vivier      * 0b010 Floating-Point Status Register
4841ba624944SLaurent Vivier      * 0b001 Floating-Point Instruction Address Register
4842ba624944SLaurent Vivier      *
4843ba624944SLaurent Vivier      */
4844ba624944SLaurent Vivier 
4845ba624944SLaurent Vivier     if (is_write && mode == 4) {
4846ba624944SLaurent Vivier         for (i = 2; i >= 0; i--, mask >>= 1) {
4847ba624944SLaurent Vivier             if (mask & 1) {
4848ba624944SLaurent Vivier                 gen_qemu_store_fcr(s, addr, 1 << i);
4849ba624944SLaurent Vivier                 if (mask != 1) {
4850ba624944SLaurent Vivier                     tcg_gen_subi_i32(addr, addr, opsize_bytes(OS_LONG));
4851ba624944SLaurent Vivier                 }
4852ba624944SLaurent Vivier             }
4853ba624944SLaurent Vivier        }
4854ba624944SLaurent Vivier        tcg_gen_mov_i32(AREG(insn, 0), addr);
4855ba624944SLaurent Vivier     } else {
4856ba624944SLaurent Vivier         for (i = 0; i < 3; i++, mask >>= 1) {
4857ba624944SLaurent Vivier             if (mask & 1) {
4858ba624944SLaurent Vivier                 if (is_write) {
4859ba624944SLaurent Vivier                     gen_qemu_store_fcr(s, addr, 1 << i);
4860ba624944SLaurent Vivier                 } else {
4861ba624944SLaurent Vivier                     gen_qemu_load_fcr(s, addr, 1 << i);
4862ba624944SLaurent Vivier                 }
4863ba624944SLaurent Vivier                 if (mask != 1 || mode == 3) {
4864ba624944SLaurent Vivier                     tcg_gen_addi_i32(addr, addr, opsize_bytes(OS_LONG));
4865ba624944SLaurent Vivier                 }
4866ba624944SLaurent Vivier             }
4867ba624944SLaurent Vivier         }
4868ba624944SLaurent Vivier         if (mode == 3) {
4869ba624944SLaurent Vivier             tcg_gen_mov_i32(AREG(insn, 0), addr);
4870ba624944SLaurent Vivier         }
4871ba624944SLaurent Vivier     }
4872860b9ac7SLaurent Vivier }
4873860b9ac7SLaurent Vivier 
gen_op_fmovem(CPUM68KState * env,DisasContext * s,uint32_t insn,uint32_t ext)4874a1e58ddcSLaurent Vivier static void gen_op_fmovem(CPUM68KState *env, DisasContext *s,
4875a1e58ddcSLaurent Vivier                           uint32_t insn, uint32_t ext)
4876a1e58ddcSLaurent Vivier {
4877a1e58ddcSLaurent Vivier     int opsize;
4878a1e58ddcSLaurent Vivier     TCGv addr, tmp;
4879a1e58ddcSLaurent Vivier     int mode = (ext >> 11) & 0x3;
4880a1e58ddcSLaurent Vivier     int is_load = ((ext & 0x2000) == 0);
4881a1e58ddcSLaurent Vivier 
4882a1e58ddcSLaurent Vivier     if (m68k_feature(s->env, M68K_FEATURE_FPU)) {
4883a1e58ddcSLaurent Vivier         opsize = OS_EXTENDED;
4884a1e58ddcSLaurent Vivier     } else {
4885a1e58ddcSLaurent Vivier         opsize = OS_DOUBLE;  /* FIXME */
4886a1e58ddcSLaurent Vivier     }
4887a1e58ddcSLaurent Vivier 
4888a1e58ddcSLaurent Vivier     addr = gen_lea(env, s, insn, opsize);
4889a1e58ddcSLaurent Vivier     if (IS_NULL_QREG(addr)) {
4890a1e58ddcSLaurent Vivier         gen_addr_fault(s);
4891a1e58ddcSLaurent Vivier         return;
4892a1e58ddcSLaurent Vivier     }
4893a1e58ddcSLaurent Vivier 
4894a1e58ddcSLaurent Vivier     tmp = tcg_temp_new();
4895a1e58ddcSLaurent Vivier     if (mode & 0x1) {
4896a1e58ddcSLaurent Vivier         /* Dynamic register list */
4897a1e58ddcSLaurent Vivier         tcg_gen_ext8u_i32(tmp, DREG(ext, 4));
4898a1e58ddcSLaurent Vivier     } else {
4899a1e58ddcSLaurent Vivier         /* Static register list */
4900a1e58ddcSLaurent Vivier         tcg_gen_movi_i32(tmp, ext & 0xff);
4901a1e58ddcSLaurent Vivier     }
4902a1e58ddcSLaurent Vivier 
4903a1e58ddcSLaurent Vivier     if (!is_load && (mode & 2) == 0) {
4904808d77bcSLucien Murray-Pitts         /*
4905808d77bcSLucien Murray-Pitts          * predecrement addressing mode
4906a1e58ddcSLaurent Vivier          * only available to store register to memory
4907a1e58ddcSLaurent Vivier          */
4908a1e58ddcSLaurent Vivier         if (opsize == OS_EXTENDED) {
4909ad75a51eSRichard Henderson             gen_helper_fmovemx_st_predec(tmp, tcg_env, addr, tmp);
4910a1e58ddcSLaurent Vivier         } else {
4911ad75a51eSRichard Henderson             gen_helper_fmovemd_st_predec(tmp, tcg_env, addr, tmp);
4912a1e58ddcSLaurent Vivier         }
4913a1e58ddcSLaurent Vivier     } else {
4914a1e58ddcSLaurent Vivier         /* postincrement addressing mode */
4915a1e58ddcSLaurent Vivier         if (opsize == OS_EXTENDED) {
4916a1e58ddcSLaurent Vivier             if (is_load) {
4917ad75a51eSRichard Henderson                 gen_helper_fmovemx_ld_postinc(tmp, tcg_env, addr, tmp);
4918a1e58ddcSLaurent Vivier             } else {
4919ad75a51eSRichard Henderson                 gen_helper_fmovemx_st_postinc(tmp, tcg_env, addr, tmp);
4920a1e58ddcSLaurent Vivier             }
4921a1e58ddcSLaurent Vivier         } else {
4922a1e58ddcSLaurent Vivier             if (is_load) {
4923ad75a51eSRichard Henderson                 gen_helper_fmovemd_ld_postinc(tmp, tcg_env, addr, tmp);
4924a1e58ddcSLaurent Vivier             } else {
4925ad75a51eSRichard Henderson                 gen_helper_fmovemd_st_postinc(tmp, tcg_env, addr, tmp);
4926a1e58ddcSLaurent Vivier             }
4927a1e58ddcSLaurent Vivier         }
4928a1e58ddcSLaurent Vivier     }
4929a1e58ddcSLaurent Vivier     if ((insn & 070) == 030 || (insn & 070) == 040) {
4930a1e58ddcSLaurent Vivier         tcg_gen_mov_i32(AREG(insn, 0), tmp);
4931a1e58ddcSLaurent Vivier     }
4932a1e58ddcSLaurent Vivier }
4933a1e58ddcSLaurent Vivier 
4934808d77bcSLucien Murray-Pitts /*
4935808d77bcSLucien Murray-Pitts  * ??? FP exceptions are not implemented.  Most exceptions are deferred until
4936808d77bcSLucien Murray-Pitts  * immediately before the next FP instruction is executed.
4937808d77bcSLucien Murray-Pitts  */
DISAS_INSN(fpu)4938fcf5ef2aSThomas Huth DISAS_INSN(fpu)
4939fcf5ef2aSThomas Huth {
4940fcf5ef2aSThomas Huth     uint16_t ext;
4941fcf5ef2aSThomas Huth     int opmode;
4942fcf5ef2aSThomas Huth     int opsize;
4943f83311e4SLaurent Vivier     TCGv_ptr cpu_src, cpu_dest;
4944fcf5ef2aSThomas Huth 
4945fcf5ef2aSThomas Huth     ext = read_im16(env, s);
4946fcf5ef2aSThomas Huth     opmode = ext & 0x7f;
4947fcf5ef2aSThomas Huth     switch ((ext >> 13) & 7) {
49489d403660SLaurent Vivier     case 0:
4949fcf5ef2aSThomas Huth         break;
4950fcf5ef2aSThomas Huth     case 1:
4951fcf5ef2aSThomas Huth         goto undef;
49529d403660SLaurent Vivier     case 2:
49539d403660SLaurent Vivier         if (insn == 0xf200 && (ext & 0xfc00) == 0x5c00) {
49549d403660SLaurent Vivier             /* fmovecr */
49551852ce5aSRichard Henderson             TCGv rom_offset = tcg_constant_i32(opmode);
49569d403660SLaurent Vivier             cpu_dest = gen_fp_ptr(REG(ext, 7));
4957ad75a51eSRichard Henderson             gen_helper_fconst(tcg_env, cpu_dest, rom_offset);
49589d403660SLaurent Vivier             return;
49599d403660SLaurent Vivier         }
49609d403660SLaurent Vivier         break;
4961fcf5ef2aSThomas Huth     case 3: /* fmove out */
4962f83311e4SLaurent Vivier         cpu_src = gen_fp_ptr(REG(ext, 7));
496369e69822SLaurent Vivier         opsize = ext_opsize(ext, 10);
496454e1e0b5SLaurent Vivier         if (gen_ea_fp(env, s, insn, opsize, cpu_src,
496554e1e0b5SLaurent Vivier                       EA_STORE, IS_USER(s)) == -1) {
4966f83311e4SLaurent Vivier             gen_addr_fault(s);
4967fcf5ef2aSThomas Huth         }
4968ad75a51eSRichard Henderson         gen_helper_ftst(tcg_env, cpu_src);
4969fcf5ef2aSThomas Huth         return;
4970fcf5ef2aSThomas Huth     case 4: /* fmove to control register.  */
4971fcf5ef2aSThomas Huth     case 5: /* fmove from control register.  */
4972860b9ac7SLaurent Vivier         gen_op_fmove_fcr(env, s, insn, ext);
4973860b9ac7SLaurent Vivier         return;
4974fcf5ef2aSThomas Huth     case 6: /* fmovem */
4975fcf5ef2aSThomas Huth     case 7:
4976a1e58ddcSLaurent Vivier         if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU)) {
4977fcf5ef2aSThomas Huth             goto undef;
4978fcf5ef2aSThomas Huth         }
4979a1e58ddcSLaurent Vivier         gen_op_fmovem(env, s, insn, ext);
4980fcf5ef2aSThomas Huth         return;
4981fcf5ef2aSThomas Huth     }
4982fcf5ef2aSThomas Huth     if (ext & (1 << 14)) {
4983fcf5ef2aSThomas Huth         /* Source effective address.  */
498469e69822SLaurent Vivier         opsize = ext_opsize(ext, 10);
4985f83311e4SLaurent Vivier         cpu_src = gen_fp_result_ptr();
498654e1e0b5SLaurent Vivier         if (gen_ea_fp(env, s, insn, opsize, cpu_src,
498754e1e0b5SLaurent Vivier                       EA_LOADS, IS_USER(s)) == -1) {
4988f83311e4SLaurent Vivier             gen_addr_fault(s);
4989f83311e4SLaurent Vivier             return;
4990fcf5ef2aSThomas Huth         }
4991fcf5ef2aSThomas Huth     } else {
4992fcf5ef2aSThomas Huth         /* Source register.  */
4993f83311e4SLaurent Vivier         opsize = OS_EXTENDED;
4994f83311e4SLaurent Vivier         cpu_src = gen_fp_ptr(REG(ext, 10));
4995fcf5ef2aSThomas Huth     }
4996f83311e4SLaurent Vivier     cpu_dest = gen_fp_ptr(REG(ext, 7));
4997fcf5ef2aSThomas Huth     switch (opmode) {
499877bdb229SLaurent Vivier     case 0: /* fmove */
4999f83311e4SLaurent Vivier         gen_fp_move(cpu_dest, cpu_src);
5000fcf5ef2aSThomas Huth         break;
500177bdb229SLaurent Vivier     case 0x40: /* fsmove */
5002ad75a51eSRichard Henderson         gen_helper_fsround(tcg_env, cpu_dest, cpu_src);
500377bdb229SLaurent Vivier         break;
500477bdb229SLaurent Vivier     case 0x44: /* fdmove */
5005ad75a51eSRichard Henderson         gen_helper_fdround(tcg_env, cpu_dest, cpu_src);
500677bdb229SLaurent Vivier         break;
5007fcf5ef2aSThomas Huth     case 1: /* fint */
5008ad75a51eSRichard Henderson         gen_helper_firound(tcg_env, cpu_dest, cpu_src);
5009fcf5ef2aSThomas Huth         break;
5010eee6b892SLaurent Vivier     case 2: /* fsinh */
5011ad75a51eSRichard Henderson         gen_helper_fsinh(tcg_env, cpu_dest, cpu_src);
5012eee6b892SLaurent Vivier         break;
5013fcf5ef2aSThomas Huth     case 3: /* fintrz */
5014ad75a51eSRichard Henderson         gen_helper_fitrunc(tcg_env, cpu_dest, cpu_src);
5015fcf5ef2aSThomas Huth         break;
5016a51b6bc3SLaurent Vivier     case 4: /* fsqrt */
5017ad75a51eSRichard Henderson         gen_helper_fsqrt(tcg_env, cpu_dest, cpu_src);
5018fcf5ef2aSThomas Huth         break;
5019a51b6bc3SLaurent Vivier     case 0x41: /* fssqrt */
5020ad75a51eSRichard Henderson         gen_helper_fssqrt(tcg_env, cpu_dest, cpu_src);
5021a51b6bc3SLaurent Vivier         break;
5022a51b6bc3SLaurent Vivier     case 0x45: /* fdsqrt */
5023ad75a51eSRichard Henderson         gen_helper_fdsqrt(tcg_env, cpu_dest, cpu_src);
5024a51b6bc3SLaurent Vivier         break;
50254b5c65b8SLaurent Vivier     case 0x06: /* flognp1 */
5026ad75a51eSRichard Henderson         gen_helper_flognp1(tcg_env, cpu_dest, cpu_src);
50274b5c65b8SLaurent Vivier         break;
5028250b1da3SLaurent Vivier     case 0x08: /* fetoxm1 */
5029ad75a51eSRichard Henderson         gen_helper_fetoxm1(tcg_env, cpu_dest, cpu_src);
5030250b1da3SLaurent Vivier         break;
50319937b029SLaurent Vivier     case 0x09: /* ftanh */
5032ad75a51eSRichard Henderson         gen_helper_ftanh(tcg_env, cpu_dest, cpu_src);
50339937b029SLaurent Vivier         break;
50348c992abcSLaurent Vivier     case 0x0a: /* fatan */
5035ad75a51eSRichard Henderson         gen_helper_fatan(tcg_env, cpu_dest, cpu_src);
50368c992abcSLaurent Vivier         break;
5037bc20b34eSLaurent Vivier     case 0x0c: /* fasin */
5038ad75a51eSRichard Henderson         gen_helper_fasin(tcg_env, cpu_dest, cpu_src);
5039bc20b34eSLaurent Vivier         break;
5040e3655afaSLaurent Vivier     case 0x0d: /* fatanh */
5041ad75a51eSRichard Henderson         gen_helper_fatanh(tcg_env, cpu_dest, cpu_src);
5042e3655afaSLaurent Vivier         break;
50435add1ac4SLaurent Vivier     case 0x0e: /* fsin */
5044ad75a51eSRichard Henderson         gen_helper_fsin(tcg_env, cpu_dest, cpu_src);
50455add1ac4SLaurent Vivier         break;
504627340180SLaurent Vivier     case 0x0f: /* ftan */
5047ad75a51eSRichard Henderson         gen_helper_ftan(tcg_env, cpu_dest, cpu_src);
504827340180SLaurent Vivier         break;
504940ad0873SLaurent Vivier     case 0x10: /* fetox */
5050ad75a51eSRichard Henderson         gen_helper_fetox(tcg_env, cpu_dest, cpu_src);
505140ad0873SLaurent Vivier         break;
5052068f1615SLaurent Vivier     case 0x11: /* ftwotox */
5053ad75a51eSRichard Henderson         gen_helper_ftwotox(tcg_env, cpu_dest, cpu_src);
5054068f1615SLaurent Vivier         break;
50556c25be6eSLaurent Vivier     case 0x12: /* ftentox */
5056ad75a51eSRichard Henderson         gen_helper_ftentox(tcg_env, cpu_dest, cpu_src);
50576c25be6eSLaurent Vivier         break;
505850067bd1SLaurent Vivier     case 0x14: /* flogn */
5059ad75a51eSRichard Henderson         gen_helper_flogn(tcg_env, cpu_dest, cpu_src);
506050067bd1SLaurent Vivier         break;
5061248efb66SLaurent Vivier     case 0x15: /* flog10 */
5062ad75a51eSRichard Henderson         gen_helper_flog10(tcg_env, cpu_dest, cpu_src);
5063248efb66SLaurent Vivier         break;
506467b453edSLaurent Vivier     case 0x16: /* flog2 */
5065ad75a51eSRichard Henderson         gen_helper_flog2(tcg_env, cpu_dest, cpu_src);
506667b453edSLaurent Vivier         break;
506777bdb229SLaurent Vivier     case 0x18: /* fabs */
5068ad75a51eSRichard Henderson         gen_helper_fabs(tcg_env, cpu_dest, cpu_src);
5069fcf5ef2aSThomas Huth         break;
507077bdb229SLaurent Vivier     case 0x58: /* fsabs */
5071ad75a51eSRichard Henderson         gen_helper_fsabs(tcg_env, cpu_dest, cpu_src);
507277bdb229SLaurent Vivier         break;
507377bdb229SLaurent Vivier     case 0x5c: /* fdabs */
5074ad75a51eSRichard Henderson         gen_helper_fdabs(tcg_env, cpu_dest, cpu_src);
507577bdb229SLaurent Vivier         break;
507602f9124eSLaurent Vivier     case 0x19: /* fcosh */
5077ad75a51eSRichard Henderson         gen_helper_fcosh(tcg_env, cpu_dest, cpu_src);
507802f9124eSLaurent Vivier         break;
507977bdb229SLaurent Vivier     case 0x1a: /* fneg */
5080ad75a51eSRichard Henderson         gen_helper_fneg(tcg_env, cpu_dest, cpu_src);
508177bdb229SLaurent Vivier         break;
508277bdb229SLaurent Vivier     case 0x5a: /* fsneg */
5083ad75a51eSRichard Henderson         gen_helper_fsneg(tcg_env, cpu_dest, cpu_src);
508477bdb229SLaurent Vivier         break;
508577bdb229SLaurent Vivier     case 0x5e: /* fdneg */
5086ad75a51eSRichard Henderson         gen_helper_fdneg(tcg_env, cpu_dest, cpu_src);
5087fcf5ef2aSThomas Huth         break;
5088c84813b8SLaurent Vivier     case 0x1c: /* facos */
5089ad75a51eSRichard Henderson         gen_helper_facos(tcg_env, cpu_dest, cpu_src);
5090c84813b8SLaurent Vivier         break;
509168d0ed37SLaurent Vivier     case 0x1d: /* fcos */
5092ad75a51eSRichard Henderson         gen_helper_fcos(tcg_env, cpu_dest, cpu_src);
509368d0ed37SLaurent Vivier         break;
50940d379c17SLaurent Vivier     case 0x1e: /* fgetexp */
5095ad75a51eSRichard Henderson         gen_helper_fgetexp(tcg_env, cpu_dest, cpu_src);
50960d379c17SLaurent Vivier         break;
50970d379c17SLaurent Vivier     case 0x1f: /* fgetman */
5098ad75a51eSRichard Henderson         gen_helper_fgetman(tcg_env, cpu_dest, cpu_src);
50990d379c17SLaurent Vivier         break;
5100a51b6bc3SLaurent Vivier     case 0x20: /* fdiv */
5101ad75a51eSRichard Henderson         gen_helper_fdiv(tcg_env, cpu_dest, cpu_src, cpu_dest);
5102fcf5ef2aSThomas Huth         break;
5103a51b6bc3SLaurent Vivier     case 0x60: /* fsdiv */
5104ad75a51eSRichard Henderson         gen_helper_fsdiv(tcg_env, cpu_dest, cpu_src, cpu_dest);
5105a51b6bc3SLaurent Vivier         break;
5106a51b6bc3SLaurent Vivier     case 0x64: /* fddiv */
5107ad75a51eSRichard Henderson         gen_helper_fddiv(tcg_env, cpu_dest, cpu_src, cpu_dest);
5108a51b6bc3SLaurent Vivier         break;
5109591596b7SLaurent Vivier     case 0x21: /* fmod */
5110ad75a51eSRichard Henderson         gen_helper_fmod(tcg_env, cpu_dest, cpu_src, cpu_dest);
5111591596b7SLaurent Vivier         break;
5112a51b6bc3SLaurent Vivier     case 0x22: /* fadd */
5113ad75a51eSRichard Henderson         gen_helper_fadd(tcg_env, cpu_dest, cpu_src, cpu_dest);
5114fcf5ef2aSThomas Huth         break;
5115a51b6bc3SLaurent Vivier     case 0x62: /* fsadd */
5116ad75a51eSRichard Henderson         gen_helper_fsadd(tcg_env, cpu_dest, cpu_src, cpu_dest);
5117a51b6bc3SLaurent Vivier         break;
5118a51b6bc3SLaurent Vivier     case 0x66: /* fdadd */
5119ad75a51eSRichard Henderson         gen_helper_fdadd(tcg_env, cpu_dest, cpu_src, cpu_dest);
5120a51b6bc3SLaurent Vivier         break;
5121a51b6bc3SLaurent Vivier     case 0x23: /* fmul */
5122ad75a51eSRichard Henderson         gen_helper_fmul(tcg_env, cpu_dest, cpu_src, cpu_dest);
5123fcf5ef2aSThomas Huth         break;
5124a51b6bc3SLaurent Vivier     case 0x63: /* fsmul */
5125ad75a51eSRichard Henderson         gen_helper_fsmul(tcg_env, cpu_dest, cpu_src, cpu_dest);
5126a51b6bc3SLaurent Vivier         break;
5127a51b6bc3SLaurent Vivier     case 0x67: /* fdmul */
5128ad75a51eSRichard Henderson         gen_helper_fdmul(tcg_env, cpu_dest, cpu_src, cpu_dest);
5129a51b6bc3SLaurent Vivier         break;
51302f77995cSLaurent Vivier     case 0x24: /* fsgldiv */
5131ad75a51eSRichard Henderson         gen_helper_fsgldiv(tcg_env, cpu_dest, cpu_src, cpu_dest);
51322f77995cSLaurent Vivier         break;
5133591596b7SLaurent Vivier     case 0x25: /* frem */
5134ad75a51eSRichard Henderson         gen_helper_frem(tcg_env, cpu_dest, cpu_src, cpu_dest);
5135591596b7SLaurent Vivier         break;
51360d379c17SLaurent Vivier     case 0x26: /* fscale */
5137ad75a51eSRichard Henderson         gen_helper_fscale(tcg_env, cpu_dest, cpu_src, cpu_dest);
51380d379c17SLaurent Vivier         break;
51392f77995cSLaurent Vivier     case 0x27: /* fsglmul */
5140ad75a51eSRichard Henderson         gen_helper_fsglmul(tcg_env, cpu_dest, cpu_src, cpu_dest);
51412f77995cSLaurent Vivier         break;
5142a51b6bc3SLaurent Vivier     case 0x28: /* fsub */
5143ad75a51eSRichard Henderson         gen_helper_fsub(tcg_env, cpu_dest, cpu_src, cpu_dest);
5144fcf5ef2aSThomas Huth         break;
5145a51b6bc3SLaurent Vivier     case 0x68: /* fssub */
5146ad75a51eSRichard Henderson         gen_helper_fssub(tcg_env, cpu_dest, cpu_src, cpu_dest);
5147a51b6bc3SLaurent Vivier         break;
5148a51b6bc3SLaurent Vivier     case 0x6c: /* fdsub */
5149ad75a51eSRichard Henderson         gen_helper_fdsub(tcg_env, cpu_dest, cpu_src, cpu_dest);
5150a51b6bc3SLaurent Vivier         break;
515147446c9cSLaurent Vivier     case 0x30: case 0x31: case 0x32:
515247446c9cSLaurent Vivier     case 0x33: case 0x34: case 0x35:
515347446c9cSLaurent Vivier     case 0x36: case 0x37: {
515447446c9cSLaurent Vivier             TCGv_ptr cpu_dest2 = gen_fp_ptr(REG(ext, 0));
5155ad75a51eSRichard Henderson             gen_helper_fsincos(tcg_env, cpu_dest, cpu_dest2, cpu_src);
515647446c9cSLaurent Vivier         }
515747446c9cSLaurent Vivier         break;
5158fcf5ef2aSThomas Huth     case 0x38: /* fcmp */
5159ad75a51eSRichard Henderson         gen_helper_fcmp(tcg_env, cpu_src, cpu_dest);
5160ba624944SLaurent Vivier         return;
5161fcf5ef2aSThomas Huth     case 0x3a: /* ftst */
5162ad75a51eSRichard Henderson         gen_helper_ftst(tcg_env, cpu_src);
5163ba624944SLaurent Vivier         return;
5164fcf5ef2aSThomas Huth     default:
5165fcf5ef2aSThomas Huth         goto undef;
5166fcf5ef2aSThomas Huth     }
5167ad75a51eSRichard Henderson     gen_helper_ftst(tcg_env, cpu_dest);
5168fcf5ef2aSThomas Huth     return;
5169fcf5ef2aSThomas Huth undef:
5170fcf5ef2aSThomas Huth     /* FIXME: Is this right for offset addressing modes?  */
5171fcf5ef2aSThomas Huth     s->pc -= 2;
5172fcf5ef2aSThomas Huth     disas_undef_fpu(env, s, insn);
5173fcf5ef2aSThomas Huth }
5174fcf5ef2aSThomas Huth 
gen_fcc_cond(DisasCompare * c,DisasContext * s,int cond)5175dd337bf8SLaurent Vivier static void gen_fcc_cond(DisasCompare *c, DisasContext *s, int cond)
5176dd337bf8SLaurent Vivier {
5177dd337bf8SLaurent Vivier     TCGv fpsr;
51782358cf77SRichard Henderson     int imm = 0;
5179dd337bf8SLaurent Vivier 
5180dd337bf8SLaurent Vivier     /* TODO: Raise BSUN exception.  */
5181dd337bf8SLaurent Vivier     fpsr = tcg_temp_new();
5182dd337bf8SLaurent Vivier     gen_load_fcr(s, fpsr, M68K_FPSR);
51832358cf77SRichard Henderson     c->v1 = fpsr;
51842358cf77SRichard Henderson 
5185dd337bf8SLaurent Vivier     switch (cond) {
5186dd337bf8SLaurent Vivier     case 0:  /* False */
5187dd337bf8SLaurent Vivier     case 16: /* Signaling False */
5188dd337bf8SLaurent Vivier         c->tcond = TCG_COND_NEVER;
5189dd337bf8SLaurent Vivier         break;
5190dd337bf8SLaurent Vivier     case 1:  /* EQual Z */
5191dd337bf8SLaurent Vivier     case 17: /* Signaling EQual Z */
51922358cf77SRichard Henderson         imm = FPSR_CC_Z;
51932358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5194dd337bf8SLaurent Vivier         break;
5195dd337bf8SLaurent Vivier     case 2:  /* Ordered Greater Than !(A || Z || N) */
5196dd337bf8SLaurent Vivier     case 18: /* Greater Than !(A || Z || N) */
51972358cf77SRichard Henderson         imm = FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N;
51982358cf77SRichard Henderson         c->tcond = TCG_COND_TSTEQ;
5199dd337bf8SLaurent Vivier         break;
5200dd337bf8SLaurent Vivier     case 3:  /* Ordered Greater than or Equal Z || !(A || N) */
5201dd337bf8SLaurent Vivier     case 19: /* Greater than or Equal Z || !(A || N) */
5202dd337bf8SLaurent Vivier         c->v1 = tcg_temp_new();
5203dd337bf8SLaurent Vivier         tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5204dd337bf8SLaurent Vivier         tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
5205dd337bf8SLaurent Vivier         tcg_gen_or_i32(c->v1, c->v1, fpsr);
5206dd337bf8SLaurent Vivier         tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
52072358cf77SRichard Henderson         imm = FPSR_CC_Z | FPSR_CC_N;
52082358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5209dd337bf8SLaurent Vivier         break;
5210dd337bf8SLaurent Vivier     case 4:  /* Ordered Less Than !(!N || A || Z); */
5211dd337bf8SLaurent Vivier     case 20: /* Less Than !(!N || A || Z); */
5212dd337bf8SLaurent Vivier         c->v1 = tcg_temp_new();
5213dd337bf8SLaurent Vivier         tcg_gen_xori_i32(c->v1, fpsr, FPSR_CC_N);
52142358cf77SRichard Henderson         imm = FPSR_CC_N | FPSR_CC_A | FPSR_CC_Z;
52152358cf77SRichard Henderson         c->tcond = TCG_COND_TSTEQ;
5216dd337bf8SLaurent Vivier         break;
5217dd337bf8SLaurent Vivier     case 5:  /* Ordered Less than or Equal Z || (N && !A) */
5218dd337bf8SLaurent Vivier     case 21: /* Less than or Equal Z || (N && !A) */
5219dd337bf8SLaurent Vivier         c->v1 = tcg_temp_new();
5220dd337bf8SLaurent Vivier         tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5221dd337bf8SLaurent Vivier         tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
5222dd337bf8SLaurent Vivier         tcg_gen_andc_i32(c->v1, fpsr, c->v1);
52232358cf77SRichard Henderson         imm = FPSR_CC_Z | FPSR_CC_N;
52242358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5225dd337bf8SLaurent Vivier         break;
5226dd337bf8SLaurent Vivier     case 6:  /* Ordered Greater or Less than !(A || Z) */
5227dd337bf8SLaurent Vivier     case 22: /* Greater or Less than !(A || Z) */
52282358cf77SRichard Henderson         imm = FPSR_CC_A | FPSR_CC_Z;
52292358cf77SRichard Henderson         c->tcond = TCG_COND_TSTEQ;
5230dd337bf8SLaurent Vivier         break;
5231dd337bf8SLaurent Vivier     case 7:  /* Ordered !A */
5232dd337bf8SLaurent Vivier     case 23: /* Greater, Less or Equal !A */
52332358cf77SRichard Henderson         imm = FPSR_CC_A;
52342358cf77SRichard Henderson         c->tcond = TCG_COND_TSTEQ;
5235dd337bf8SLaurent Vivier         break;
5236dd337bf8SLaurent Vivier     case 8:  /* Unordered A */
5237dd337bf8SLaurent Vivier     case 24: /* Not Greater, Less or Equal A */
52382358cf77SRichard Henderson         imm = FPSR_CC_A;
52392358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5240dd337bf8SLaurent Vivier         break;
5241dd337bf8SLaurent Vivier     case 9:  /* Unordered or Equal A || Z */
5242dd337bf8SLaurent Vivier     case 25: /* Not Greater or Less then A || Z */
52432358cf77SRichard Henderson         imm = FPSR_CC_A | FPSR_CC_Z;
52442358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5245dd337bf8SLaurent Vivier         break;
5246dd337bf8SLaurent Vivier     case 10: /* Unordered or Greater Than A || !(N || Z)) */
5247dd337bf8SLaurent Vivier     case 26: /* Not Less or Equal A || !(N || Z)) */
5248dd337bf8SLaurent Vivier         c->v1 = tcg_temp_new();
5249dd337bf8SLaurent Vivier         tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5250dd337bf8SLaurent Vivier         tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
5251dd337bf8SLaurent Vivier         tcg_gen_or_i32(c->v1, c->v1, fpsr);
5252dd337bf8SLaurent Vivier         tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
52532358cf77SRichard Henderson         imm = FPSR_CC_A | FPSR_CC_N;
52542358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5255dd337bf8SLaurent Vivier         break;
5256dd337bf8SLaurent Vivier     case 11: /* Unordered or Greater or Equal A || Z || !N */
5257dd337bf8SLaurent Vivier     case 27: /* Not Less Than A || Z || !N */
5258dd337bf8SLaurent Vivier         c->v1 = tcg_temp_new();
52592358cf77SRichard Henderson         tcg_gen_xori_i32(c->v1, fpsr, FPSR_CC_N);
52602358cf77SRichard Henderson         imm = FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N;
52612358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5262dd337bf8SLaurent Vivier         break;
5263dd337bf8SLaurent Vivier     case 12: /* Unordered or Less Than A || (N && !Z) */
5264dd337bf8SLaurent Vivier     case 28: /* Not Greater than or Equal A || (N && !Z) */
5265dd337bf8SLaurent Vivier         c->v1 = tcg_temp_new();
5266dd337bf8SLaurent Vivier         tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5267dd337bf8SLaurent Vivier         tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
5268dd337bf8SLaurent Vivier         tcg_gen_andc_i32(c->v1, fpsr, c->v1);
52692358cf77SRichard Henderson         imm = FPSR_CC_A | FPSR_CC_N;
52702358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5271dd337bf8SLaurent Vivier         break;
5272dd337bf8SLaurent Vivier     case 13: /* Unordered or Less or Equal A || Z || N */
5273dd337bf8SLaurent Vivier     case 29: /* Not Greater Than A || Z || N */
52742358cf77SRichard Henderson         imm = FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N;
52752358cf77SRichard Henderson         c->tcond = TCG_COND_TSTNE;
5276dd337bf8SLaurent Vivier         break;
5277dd337bf8SLaurent Vivier     case 14: /* Not Equal !Z */
5278dd337bf8SLaurent Vivier     case 30: /* Signaling Not Equal !Z */
52792358cf77SRichard Henderson         imm = FPSR_CC_Z;
52802358cf77SRichard Henderson         c->tcond = TCG_COND_TSTEQ;
5281dd337bf8SLaurent Vivier         break;
5282dd337bf8SLaurent Vivier     case 15: /* True */
5283dd337bf8SLaurent Vivier     case 31: /* Signaling True */
5284dd337bf8SLaurent Vivier         c->tcond = TCG_COND_ALWAYS;
5285dd337bf8SLaurent Vivier         break;
5286dd337bf8SLaurent Vivier     }
52872358cf77SRichard Henderson     c->v2 = tcg_constant_i32(imm);
5288dd337bf8SLaurent Vivier }
5289dd337bf8SLaurent Vivier 
gen_fjmpcc(DisasContext * s,int cond,TCGLabel * l1)5290dd337bf8SLaurent Vivier static void gen_fjmpcc(DisasContext *s, int cond, TCGLabel *l1)
5291dd337bf8SLaurent Vivier {
5292dd337bf8SLaurent Vivier     DisasCompare c;
5293dd337bf8SLaurent Vivier 
5294dd337bf8SLaurent Vivier     gen_fcc_cond(&c, s, cond);
52957cd7b5caSLaurent Vivier     update_cc_op(s);
5296dd337bf8SLaurent Vivier     tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
5297dd337bf8SLaurent Vivier }
5298dd337bf8SLaurent Vivier 
DISAS_INSN(fbcc)5299fcf5ef2aSThomas Huth DISAS_INSN(fbcc)
5300fcf5ef2aSThomas Huth {
5301fcf5ef2aSThomas Huth     uint32_t offset;
5302dd337bf8SLaurent Vivier     uint32_t base;
5303fcf5ef2aSThomas Huth     TCGLabel *l1;
5304fcf5ef2aSThomas Huth 
5305dd337bf8SLaurent Vivier     base = s->pc;
5306dd337bf8SLaurent Vivier     offset = (int16_t)read_im16(env, s);
5307fcf5ef2aSThomas Huth     if (insn & (1 << 6)) {
5308fcf5ef2aSThomas Huth         offset = (offset << 16) | read_im16(env, s);
5309fcf5ef2aSThomas Huth     }
5310fcf5ef2aSThomas Huth 
5311fcf5ef2aSThomas Huth     l1 = gen_new_label();
5312dd337bf8SLaurent Vivier     update_cc_op(s);
5313dd337bf8SLaurent Vivier     gen_fjmpcc(s, insn & 0x3f, l1);
53148115fc93SRichard Henderson     gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
5315fcf5ef2aSThomas Huth     gen_set_label(l1);
53168115fc93SRichard Henderson     gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
5317dd337bf8SLaurent Vivier }
5318dd337bf8SLaurent Vivier 
DISAS_INSN(fscc)5319dd337bf8SLaurent Vivier DISAS_INSN(fscc)
5320dd337bf8SLaurent Vivier {
5321dd337bf8SLaurent Vivier     DisasCompare c;
5322dd337bf8SLaurent Vivier     int cond;
5323dd337bf8SLaurent Vivier     TCGv tmp;
5324dd337bf8SLaurent Vivier     uint16_t ext;
5325dd337bf8SLaurent Vivier 
5326dd337bf8SLaurent Vivier     ext = read_im16(env, s);
5327dd337bf8SLaurent Vivier     cond = ext & 0x3f;
5328dd337bf8SLaurent Vivier     gen_fcc_cond(&c, s, cond);
5329dd337bf8SLaurent Vivier 
5330dd337bf8SLaurent Vivier     tmp = tcg_temp_new();
533127f9af76SRichard Henderson     tcg_gen_negsetcond_i32(c.tcond, tmp, c.v1, c.v2);
5332dd337bf8SLaurent Vivier 
5333dd337bf8SLaurent Vivier     DEST_EA(env, insn, OS_BYTE, tmp, NULL);
5334fcf5ef2aSThomas Huth }
5335fcf5ef2aSThomas Huth 
DISAS_INSN(ftrapcc)5336cc1cc264SRichard Henderson DISAS_INSN(ftrapcc)
5337cc1cc264SRichard Henderson {
5338cc1cc264SRichard Henderson     DisasCompare c;
5339cc1cc264SRichard Henderson     uint16_t ext;
5340cc1cc264SRichard Henderson     int cond;
5341cc1cc264SRichard Henderson 
5342cc1cc264SRichard Henderson     ext = read_im16(env, s);
5343cc1cc264SRichard Henderson     cond = ext & 0x3f;
5344cc1cc264SRichard Henderson 
5345cc1cc264SRichard Henderson     /* Consume and discard the immediate operand. */
5346cc1cc264SRichard Henderson     switch (extract32(insn, 0, 3)) {
5347cc1cc264SRichard Henderson     case 2: /* ftrapcc.w */
5348cc1cc264SRichard Henderson         (void)read_im16(env, s);
5349cc1cc264SRichard Henderson         break;
5350cc1cc264SRichard Henderson     case 3: /* ftrapcc.l */
5351cc1cc264SRichard Henderson         (void)read_im32(env, s);
5352cc1cc264SRichard Henderson         break;
5353cc1cc264SRichard Henderson     case 4: /* ftrapcc (no operand) */
5354cc1cc264SRichard Henderson         break;
5355cc1cc264SRichard Henderson     default:
5356cc1cc264SRichard Henderson         /* ftrapcc registered with only valid opmodes */
5357cc1cc264SRichard Henderson         g_assert_not_reached();
5358cc1cc264SRichard Henderson     }
5359cc1cc264SRichard Henderson 
5360cc1cc264SRichard Henderson     gen_fcc_cond(&c, s, cond);
5361cc1cc264SRichard Henderson     do_trapcc(s, &c);
5362cc1cc264SRichard Henderson }
5363cc1cc264SRichard Henderson 
53646a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
DISAS_INSN(frestore)5365fcf5ef2aSThomas Huth DISAS_INSN(frestore)
5366fcf5ef2aSThomas Huth {
5367fff3b4b0SLaurent Vivier     TCGv addr;
5368fcf5ef2aSThomas Huth 
53696ad25764SLaurent Vivier     if (IS_USER(s)) {
5370a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
53716ad25764SLaurent Vivier         return;
53726ad25764SLaurent Vivier     }
5373fff3b4b0SLaurent Vivier     if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
5374fff3b4b0SLaurent Vivier         SRC_EA(env, addr, OS_LONG, 0, NULL);
5375fff3b4b0SLaurent Vivier         /* FIXME: check the state frame */
5376fff3b4b0SLaurent Vivier     } else {
5377fff3b4b0SLaurent Vivier         disas_undef(env, s, insn);
5378fff3b4b0SLaurent Vivier     }
5379fcf5ef2aSThomas Huth }
5380fcf5ef2aSThomas Huth 
DISAS_INSN(fsave)5381fcf5ef2aSThomas Huth DISAS_INSN(fsave)
5382fcf5ef2aSThomas Huth {
53836ad25764SLaurent Vivier     if (IS_USER(s)) {
5384a575cbe0SRichard Henderson         gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
53856ad25764SLaurent Vivier         return;
5386fcf5ef2aSThomas Huth     }
5387fcf5ef2aSThomas Huth 
5388fff3b4b0SLaurent Vivier     if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
5389fff3b4b0SLaurent Vivier         /* always write IDLE */
53901852ce5aSRichard Henderson         TCGv idle = tcg_constant_i32(0x41000000);
5391fff3b4b0SLaurent Vivier         DEST_EA(env, insn, OS_LONG, idle, NULL);
5392fff3b4b0SLaurent Vivier     } else {
5393fff3b4b0SLaurent Vivier         disas_undef(env, s, insn);
5394fff3b4b0SLaurent Vivier     }
5395fcf5ef2aSThomas Huth }
53966ad25764SLaurent Vivier #endif
5397fcf5ef2aSThomas Huth 
gen_mac_extract_word(DisasContext * s,TCGv val,int upper)5398fcf5ef2aSThomas Huth static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
5399fcf5ef2aSThomas Huth {
5400fcf5ef2aSThomas Huth     TCGv tmp = tcg_temp_new();
5401fcf5ef2aSThomas Huth     if (s->env->macsr & MACSR_FI) {
5402fcf5ef2aSThomas Huth         if (upper)
5403fcf5ef2aSThomas Huth             tcg_gen_andi_i32(tmp, val, 0xffff0000);
5404fcf5ef2aSThomas Huth         else
5405fcf5ef2aSThomas Huth             tcg_gen_shli_i32(tmp, val, 16);
5406fcf5ef2aSThomas Huth     } else if (s->env->macsr & MACSR_SU) {
5407fcf5ef2aSThomas Huth         if (upper)
5408fcf5ef2aSThomas Huth             tcg_gen_sari_i32(tmp, val, 16);
5409fcf5ef2aSThomas Huth         else
5410fcf5ef2aSThomas Huth             tcg_gen_ext16s_i32(tmp, val);
5411fcf5ef2aSThomas Huth     } else {
5412fcf5ef2aSThomas Huth         if (upper)
5413fcf5ef2aSThomas Huth             tcg_gen_shri_i32(tmp, val, 16);
5414fcf5ef2aSThomas Huth         else
5415fcf5ef2aSThomas Huth             tcg_gen_ext16u_i32(tmp, val);
5416fcf5ef2aSThomas Huth     }
5417fcf5ef2aSThomas Huth     return tmp;
5418fcf5ef2aSThomas Huth }
5419fcf5ef2aSThomas Huth 
gen_mac_clear_flags(void)5420fcf5ef2aSThomas Huth static void gen_mac_clear_flags(void)
5421fcf5ef2aSThomas Huth {
5422fcf5ef2aSThomas Huth     tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR,
5423fcf5ef2aSThomas Huth                      ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV));
5424fcf5ef2aSThomas Huth }
5425fcf5ef2aSThomas Huth 
DISAS_INSN(mac)5426fcf5ef2aSThomas Huth DISAS_INSN(mac)
5427fcf5ef2aSThomas Huth {
5428fcf5ef2aSThomas Huth     TCGv rx;
5429fcf5ef2aSThomas Huth     TCGv ry;
5430fcf5ef2aSThomas Huth     uint16_t ext;
5431fcf5ef2aSThomas Huth     int acc;
5432fcf5ef2aSThomas Huth     TCGv tmp;
5433fcf5ef2aSThomas Huth     TCGv addr;
5434fcf5ef2aSThomas Huth     TCGv loadval;
5435fcf5ef2aSThomas Huth     int dual;
5436fcf5ef2aSThomas Huth     TCGv saved_flags;
5437fcf5ef2aSThomas Huth 
5438fcf5ef2aSThomas Huth     if (!s->done_mac) {
5439fcf5ef2aSThomas Huth         s->mactmp = tcg_temp_new_i64();
5440fcf5ef2aSThomas Huth         s->done_mac = 1;
5441fcf5ef2aSThomas Huth     }
5442fcf5ef2aSThomas Huth 
5443fcf5ef2aSThomas Huth     ext = read_im16(env, s);
5444fcf5ef2aSThomas Huth 
5445fcf5ef2aSThomas Huth     acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
5446fcf5ef2aSThomas Huth     dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
5447fcf5ef2aSThomas Huth     if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
5448fcf5ef2aSThomas Huth         disas_undef(env, s, insn);
5449fcf5ef2aSThomas Huth         return;
5450fcf5ef2aSThomas Huth     }
5451fcf5ef2aSThomas Huth     if (insn & 0x30) {
5452fcf5ef2aSThomas Huth         /* MAC with load.  */
5453fcf5ef2aSThomas Huth         tmp = gen_lea(env, s, insn, OS_LONG);
5454fcf5ef2aSThomas Huth         addr = tcg_temp_new();
5455fcf5ef2aSThomas Huth         tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK);
5456808d77bcSLucien Murray-Pitts         /*
5457808d77bcSLucien Murray-Pitts          * Load the value now to ensure correct exception behavior.
5458808d77bcSLucien Murray-Pitts          * Perform writeback after reading the MAC inputs.
5459808d77bcSLucien Murray-Pitts          */
546054e1e0b5SLaurent Vivier         loadval = gen_load(s, OS_LONG, addr, 0, IS_USER(s));
5461fcf5ef2aSThomas Huth 
5462fcf5ef2aSThomas Huth         acc ^= 1;
5463fcf5ef2aSThomas Huth         rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
5464fcf5ef2aSThomas Huth         ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
5465fcf5ef2aSThomas Huth     } else {
5466fcf5ef2aSThomas Huth         loadval = addr = NULL_QREG;
5467fcf5ef2aSThomas Huth         rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
5468fcf5ef2aSThomas Huth         ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5469fcf5ef2aSThomas Huth     }
5470fcf5ef2aSThomas Huth 
5471fcf5ef2aSThomas Huth     gen_mac_clear_flags();
5472fcf5ef2aSThomas Huth #if 0
5473fcf5ef2aSThomas Huth     l1 = -1;
5474fcf5ef2aSThomas Huth     /* Disabled because conditional branches clobber temporary vars.  */
5475fcf5ef2aSThomas Huth     if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
5476fcf5ef2aSThomas Huth         /* Skip the multiply if we know we will ignore it.  */
5477fcf5ef2aSThomas Huth         l1 = gen_new_label();
5478fcf5ef2aSThomas Huth         tmp = tcg_temp_new();
5479fcf5ef2aSThomas Huth         tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8));
5480fcf5ef2aSThomas Huth         gen_op_jmp_nz32(tmp, l1);
5481fcf5ef2aSThomas Huth     }
5482fcf5ef2aSThomas Huth #endif
5483fcf5ef2aSThomas Huth 
5484fcf5ef2aSThomas Huth     if ((ext & 0x0800) == 0) {
5485fcf5ef2aSThomas Huth         /* Word.  */
5486fcf5ef2aSThomas Huth         rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
5487fcf5ef2aSThomas Huth         ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
5488fcf5ef2aSThomas Huth     }
5489fcf5ef2aSThomas Huth     if (s->env->macsr & MACSR_FI) {
5490ad75a51eSRichard Henderson         gen_helper_macmulf(s->mactmp, tcg_env, rx, ry);
5491fcf5ef2aSThomas Huth     } else {
5492fcf5ef2aSThomas Huth         if (s->env->macsr & MACSR_SU)
5493ad75a51eSRichard Henderson             gen_helper_macmuls(s->mactmp, tcg_env, rx, ry);
5494fcf5ef2aSThomas Huth         else
5495ad75a51eSRichard Henderson             gen_helper_macmulu(s->mactmp, tcg_env, rx, ry);
5496fcf5ef2aSThomas Huth         switch ((ext >> 9) & 3) {
5497fcf5ef2aSThomas Huth         case 1:
5498fcf5ef2aSThomas Huth             tcg_gen_shli_i64(s->mactmp, s->mactmp, 1);
5499fcf5ef2aSThomas Huth             break;
5500fcf5ef2aSThomas Huth         case 3:
5501fcf5ef2aSThomas Huth             tcg_gen_shri_i64(s->mactmp, s->mactmp, 1);
5502fcf5ef2aSThomas Huth             break;
5503fcf5ef2aSThomas Huth         }
5504fcf5ef2aSThomas Huth     }
5505fcf5ef2aSThomas Huth 
5506fcf5ef2aSThomas Huth     if (dual) {
5507fcf5ef2aSThomas Huth         /* Save the overflow flag from the multiply.  */
5508fcf5ef2aSThomas Huth         saved_flags = tcg_temp_new();
5509fcf5ef2aSThomas Huth         tcg_gen_mov_i32(saved_flags, QREG_MACSR);
5510fcf5ef2aSThomas Huth     } else {
5511fcf5ef2aSThomas Huth         saved_flags = NULL_QREG;
5512fcf5ef2aSThomas Huth     }
5513fcf5ef2aSThomas Huth 
5514fcf5ef2aSThomas Huth #if 0
5515fcf5ef2aSThomas Huth     /* Disabled because conditional branches clobber temporary vars.  */
5516fcf5ef2aSThomas Huth     if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
5517fcf5ef2aSThomas Huth         /* Skip the accumulate if the value is already saturated.  */
5518fcf5ef2aSThomas Huth         l1 = gen_new_label();
5519fcf5ef2aSThomas Huth         tmp = tcg_temp_new();
55201852ce5aSRichard Henderson         gen_op_and32(tmp, QREG_MACSR, tcg_constant_i32(MACSR_PAV0 << acc));
5521fcf5ef2aSThomas Huth         gen_op_jmp_nz32(tmp, l1);
5522fcf5ef2aSThomas Huth     }
5523fcf5ef2aSThomas Huth #endif
5524fcf5ef2aSThomas Huth 
5525fcf5ef2aSThomas Huth     if (insn & 0x100)
5526fcf5ef2aSThomas Huth         tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
5527fcf5ef2aSThomas Huth     else
5528fcf5ef2aSThomas Huth         tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
5529fcf5ef2aSThomas Huth 
5530fcf5ef2aSThomas Huth     if (s->env->macsr & MACSR_FI)
5531ad75a51eSRichard Henderson         gen_helper_macsatf(tcg_env, tcg_constant_i32(acc));
5532fcf5ef2aSThomas Huth     else if (s->env->macsr & MACSR_SU)
5533ad75a51eSRichard Henderson         gen_helper_macsats(tcg_env, tcg_constant_i32(acc));
5534fcf5ef2aSThomas Huth     else
5535ad75a51eSRichard Henderson         gen_helper_macsatu(tcg_env, tcg_constant_i32(acc));
5536fcf5ef2aSThomas Huth 
5537fcf5ef2aSThomas Huth #if 0
5538fcf5ef2aSThomas Huth     /* Disabled because conditional branches clobber temporary vars.  */
5539fcf5ef2aSThomas Huth     if (l1 != -1)
5540fcf5ef2aSThomas Huth         gen_set_label(l1);
5541fcf5ef2aSThomas Huth #endif
5542fcf5ef2aSThomas Huth 
5543fcf5ef2aSThomas Huth     if (dual) {
5544fcf5ef2aSThomas Huth         /* Dual accumulate variant.  */
5545fcf5ef2aSThomas Huth         acc = (ext >> 2) & 3;
5546fcf5ef2aSThomas Huth         /* Restore the overflow flag from the multiplier.  */
5547fcf5ef2aSThomas Huth         tcg_gen_mov_i32(QREG_MACSR, saved_flags);
5548fcf5ef2aSThomas Huth #if 0
5549fcf5ef2aSThomas Huth         /* Disabled because conditional branches clobber temporary vars.  */
5550fcf5ef2aSThomas Huth         if ((s->env->macsr & MACSR_OMC) != 0) {
5551fcf5ef2aSThomas Huth             /* Skip the accumulate if the value is already saturated.  */
5552fcf5ef2aSThomas Huth             l1 = gen_new_label();
5553fcf5ef2aSThomas Huth             tmp = tcg_temp_new();
55541852ce5aSRichard Henderson             gen_op_and32(tmp, QREG_MACSR, tcg_constant_i32(MACSR_PAV0 << acc));
5555fcf5ef2aSThomas Huth             gen_op_jmp_nz32(tmp, l1);
5556fcf5ef2aSThomas Huth         }
5557fcf5ef2aSThomas Huth #endif
5558fcf5ef2aSThomas Huth         if (ext & 2)
5559fcf5ef2aSThomas Huth             tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
5560fcf5ef2aSThomas Huth         else
5561fcf5ef2aSThomas Huth             tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
5562fcf5ef2aSThomas Huth         if (s->env->macsr & MACSR_FI)
5563ad75a51eSRichard Henderson             gen_helper_macsatf(tcg_env, tcg_constant_i32(acc));
5564fcf5ef2aSThomas Huth         else if (s->env->macsr & MACSR_SU)
5565ad75a51eSRichard Henderson             gen_helper_macsats(tcg_env, tcg_constant_i32(acc));
5566fcf5ef2aSThomas Huth         else
5567ad75a51eSRichard Henderson             gen_helper_macsatu(tcg_env, tcg_constant_i32(acc));
5568fcf5ef2aSThomas Huth #if 0
5569fcf5ef2aSThomas Huth         /* Disabled because conditional branches clobber temporary vars.  */
5570fcf5ef2aSThomas Huth         if (l1 != -1)
5571fcf5ef2aSThomas Huth             gen_set_label(l1);
5572fcf5ef2aSThomas Huth #endif
5573fcf5ef2aSThomas Huth     }
5574ad75a51eSRichard Henderson     gen_helper_mac_set_flags(tcg_env, tcg_constant_i32(acc));
5575fcf5ef2aSThomas Huth 
5576fcf5ef2aSThomas Huth     if (insn & 0x30) {
5577fcf5ef2aSThomas Huth         TCGv rw;
5578fcf5ef2aSThomas Huth         rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
5579fcf5ef2aSThomas Huth         tcg_gen_mov_i32(rw, loadval);
5580808d77bcSLucien Murray-Pitts         /*
5581808d77bcSLucien Murray-Pitts          * FIXME: Should address writeback happen with the masked or
5582808d77bcSLucien Murray-Pitts          * unmasked value?
5583808d77bcSLucien Murray-Pitts          */
5584fcf5ef2aSThomas Huth         switch ((insn >> 3) & 7) {
5585fcf5ef2aSThomas Huth         case 3: /* Post-increment.  */
5586fcf5ef2aSThomas Huth             tcg_gen_addi_i32(AREG(insn, 0), addr, 4);
5587fcf5ef2aSThomas Huth             break;
5588fcf5ef2aSThomas Huth         case 4: /* Pre-decrement.  */
5589fcf5ef2aSThomas Huth             tcg_gen_mov_i32(AREG(insn, 0), addr);
5590fcf5ef2aSThomas Huth         }
5591fcf5ef2aSThomas Huth     }
5592fcf5ef2aSThomas Huth }
5593fcf5ef2aSThomas Huth 
DISAS_INSN(from_mac)5594fcf5ef2aSThomas Huth DISAS_INSN(from_mac)
5595fcf5ef2aSThomas Huth {
5596fcf5ef2aSThomas Huth     TCGv rx;
5597fcf5ef2aSThomas Huth     TCGv_i64 acc;
5598fcf5ef2aSThomas Huth     int accnum;
5599fcf5ef2aSThomas Huth 
5600fcf5ef2aSThomas Huth     rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5601fcf5ef2aSThomas Huth     accnum = (insn >> 9) & 3;
5602fcf5ef2aSThomas Huth     acc = MACREG(accnum);
5603fcf5ef2aSThomas Huth     if (s->env->macsr & MACSR_FI) {
5604ad75a51eSRichard Henderson         gen_helper_get_macf(rx, tcg_env, acc);
5605fcf5ef2aSThomas Huth     } else if ((s->env->macsr & MACSR_OMC) == 0) {
5606fcf5ef2aSThomas Huth         tcg_gen_extrl_i64_i32(rx, acc);
5607fcf5ef2aSThomas Huth     } else if (s->env->macsr & MACSR_SU) {
5608fcf5ef2aSThomas Huth         gen_helper_get_macs(rx, acc);
5609fcf5ef2aSThomas Huth     } else {
5610fcf5ef2aSThomas Huth         gen_helper_get_macu(rx, acc);
5611fcf5ef2aSThomas Huth     }
5612fcf5ef2aSThomas Huth     if (insn & 0x40) {
5613fcf5ef2aSThomas Huth         tcg_gen_movi_i64(acc, 0);
5614fcf5ef2aSThomas Huth         tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
5615fcf5ef2aSThomas Huth     }
5616fcf5ef2aSThomas Huth }
5617fcf5ef2aSThomas Huth 
DISAS_INSN(move_mac)5618fcf5ef2aSThomas Huth DISAS_INSN(move_mac)
5619fcf5ef2aSThomas Huth {
5620fcf5ef2aSThomas Huth     /* FIXME: This can be done without a helper.  */
5621fcf5ef2aSThomas Huth     int src;
5622fcf5ef2aSThomas Huth     TCGv dest;
5623fcf5ef2aSThomas Huth     src = insn & 3;
56241852ce5aSRichard Henderson     dest = tcg_constant_i32((insn >> 9) & 3);
5625ad75a51eSRichard Henderson     gen_helper_mac_move(tcg_env, dest, tcg_constant_i32(src));
5626fcf5ef2aSThomas Huth     gen_mac_clear_flags();
5627ad75a51eSRichard Henderson     gen_helper_mac_set_flags(tcg_env, dest);
5628fcf5ef2aSThomas Huth }
5629fcf5ef2aSThomas Huth 
DISAS_INSN(from_macsr)5630fcf5ef2aSThomas Huth DISAS_INSN(from_macsr)
5631fcf5ef2aSThomas Huth {
5632fcf5ef2aSThomas Huth     TCGv reg;
5633fcf5ef2aSThomas Huth 
5634fcf5ef2aSThomas Huth     reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5635fcf5ef2aSThomas Huth     tcg_gen_mov_i32(reg, QREG_MACSR);
5636fcf5ef2aSThomas Huth }
5637fcf5ef2aSThomas Huth 
DISAS_INSN(from_mask)5638fcf5ef2aSThomas Huth DISAS_INSN(from_mask)
5639fcf5ef2aSThomas Huth {
5640fcf5ef2aSThomas Huth     TCGv reg;
5641fcf5ef2aSThomas Huth     reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5642fcf5ef2aSThomas Huth     tcg_gen_mov_i32(reg, QREG_MAC_MASK);
5643fcf5ef2aSThomas Huth }
5644fcf5ef2aSThomas Huth 
DISAS_INSN(from_mext)5645fcf5ef2aSThomas Huth DISAS_INSN(from_mext)
5646fcf5ef2aSThomas Huth {
5647fcf5ef2aSThomas Huth     TCGv reg;
5648fcf5ef2aSThomas Huth     TCGv acc;
5649fcf5ef2aSThomas Huth     reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
56501852ce5aSRichard Henderson     acc = tcg_constant_i32((insn & 0x400) ? 2 : 0);
5651fcf5ef2aSThomas Huth     if (s->env->macsr & MACSR_FI)
5652ad75a51eSRichard Henderson         gen_helper_get_mac_extf(reg, tcg_env, acc);
5653fcf5ef2aSThomas Huth     else
5654ad75a51eSRichard Henderson         gen_helper_get_mac_exti(reg, tcg_env, acc);
5655fcf5ef2aSThomas Huth }
5656fcf5ef2aSThomas Huth 
DISAS_INSN(macsr_to_ccr)5657fcf5ef2aSThomas Huth DISAS_INSN(macsr_to_ccr)
5658fcf5ef2aSThomas Huth {
5659fcf5ef2aSThomas Huth     TCGv tmp = tcg_temp_new();
566024ec52f9SRichard Henderson 
566124ec52f9SRichard Henderson     /* Note that X and C are always cleared. */
566224ec52f9SRichard Henderson     tcg_gen_andi_i32(tmp, QREG_MACSR, CCF_N | CCF_Z | CCF_V);
5663ad75a51eSRichard Henderson     gen_helper_set_ccr(tcg_env, tmp);
5664fcf5ef2aSThomas Huth     set_cc_op(s, CC_OP_FLAGS);
5665fcf5ef2aSThomas Huth }
5666fcf5ef2aSThomas Huth 
DISAS_INSN(to_mac)5667fcf5ef2aSThomas Huth DISAS_INSN(to_mac)
5668fcf5ef2aSThomas Huth {
5669fcf5ef2aSThomas Huth     TCGv_i64 acc;
5670fcf5ef2aSThomas Huth     TCGv val;
5671fcf5ef2aSThomas Huth     int accnum;
5672fcf5ef2aSThomas Huth     accnum = (insn >> 9) & 3;
5673fcf5ef2aSThomas Huth     acc = MACREG(accnum);
5674fcf5ef2aSThomas Huth     SRC_EA(env, val, OS_LONG, 0, NULL);
5675fcf5ef2aSThomas Huth     if (s->env->macsr & MACSR_FI) {
5676fcf5ef2aSThomas Huth         tcg_gen_ext_i32_i64(acc, val);
5677fcf5ef2aSThomas Huth         tcg_gen_shli_i64(acc, acc, 8);
5678fcf5ef2aSThomas Huth     } else if (s->env->macsr & MACSR_SU) {
5679fcf5ef2aSThomas Huth         tcg_gen_ext_i32_i64(acc, val);
5680fcf5ef2aSThomas Huth     } else {
5681fcf5ef2aSThomas Huth         tcg_gen_extu_i32_i64(acc, val);
5682fcf5ef2aSThomas Huth     }
5683fcf5ef2aSThomas Huth     tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
5684fcf5ef2aSThomas Huth     gen_mac_clear_flags();
5685ad75a51eSRichard Henderson     gen_helper_mac_set_flags(tcg_env, tcg_constant_i32(accnum));
5686fcf5ef2aSThomas Huth }
5687fcf5ef2aSThomas Huth 
DISAS_INSN(to_macsr)5688fcf5ef2aSThomas Huth DISAS_INSN(to_macsr)
5689fcf5ef2aSThomas Huth {
5690fcf5ef2aSThomas Huth     TCGv val;
5691fcf5ef2aSThomas Huth     SRC_EA(env, val, OS_LONG, 0, NULL);
5692ad75a51eSRichard Henderson     gen_helper_set_macsr(tcg_env, val);
56934106f26eSRichard Henderson     gen_exit_tb(s);
5694fcf5ef2aSThomas Huth }
5695fcf5ef2aSThomas Huth 
DISAS_INSN(to_mask)5696fcf5ef2aSThomas Huth DISAS_INSN(to_mask)
5697fcf5ef2aSThomas Huth {
5698fcf5ef2aSThomas Huth     TCGv val;
5699fcf5ef2aSThomas Huth     SRC_EA(env, val, OS_LONG, 0, NULL);
5700fcf5ef2aSThomas Huth     tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000);
5701fcf5ef2aSThomas Huth }
5702fcf5ef2aSThomas Huth 
DISAS_INSN(to_mext)5703fcf5ef2aSThomas Huth DISAS_INSN(to_mext)
5704fcf5ef2aSThomas Huth {
5705fcf5ef2aSThomas Huth     TCGv val;
5706fcf5ef2aSThomas Huth     TCGv acc;
5707fcf5ef2aSThomas Huth     SRC_EA(env, val, OS_LONG, 0, NULL);
57081852ce5aSRichard Henderson     acc = tcg_constant_i32((insn & 0x400) ? 2 : 0);
5709fcf5ef2aSThomas Huth     if (s->env->macsr & MACSR_FI)
5710ad75a51eSRichard Henderson         gen_helper_set_mac_extf(tcg_env, val, acc);
5711fcf5ef2aSThomas Huth     else if (s->env->macsr & MACSR_SU)
5712ad75a51eSRichard Henderson         gen_helper_set_mac_exts(tcg_env, val, acc);
5713fcf5ef2aSThomas Huth     else
5714ad75a51eSRichard Henderson         gen_helper_set_mac_extu(tcg_env, val, acc);
5715fcf5ef2aSThomas Huth }
5716fcf5ef2aSThomas Huth 
5717fcf5ef2aSThomas Huth static disas_proc opcode_table[65536];
5718fcf5ef2aSThomas Huth 
5719fcf5ef2aSThomas Huth static void
register_opcode(disas_proc proc,uint16_t opcode,uint16_t mask)5720fcf5ef2aSThomas Huth register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
5721fcf5ef2aSThomas Huth {
5722fcf5ef2aSThomas Huth   int i;
5723fcf5ef2aSThomas Huth   int from;
5724fcf5ef2aSThomas Huth   int to;
5725fcf5ef2aSThomas Huth 
5726fcf5ef2aSThomas Huth   /* Sanity check.  All set bits must be included in the mask.  */
5727fcf5ef2aSThomas Huth   if (opcode & ~mask) {
5728fcf5ef2aSThomas Huth       fprintf(stderr,
5729fcf5ef2aSThomas Huth               "qemu internal error: bogus opcode definition %04x/%04x\n",
5730fcf5ef2aSThomas Huth               opcode, mask);
5731fcf5ef2aSThomas Huth       abort();
5732fcf5ef2aSThomas Huth   }
5733808d77bcSLucien Murray-Pitts   /*
5734808d77bcSLucien Murray-Pitts    * This could probably be cleverer.  For now just optimize the case where
5735808d77bcSLucien Murray-Pitts    * the top bits are known.
5736808d77bcSLucien Murray-Pitts    */
5737fcf5ef2aSThomas Huth   /* Find the first zero bit in the mask.  */
5738fcf5ef2aSThomas Huth   i = 0x8000;
5739fcf5ef2aSThomas Huth   while ((i & mask) != 0)
5740fcf5ef2aSThomas Huth       i >>= 1;
5741fcf5ef2aSThomas Huth   /* Iterate over all combinations of this and lower bits.  */
5742fcf5ef2aSThomas Huth   if (i == 0)
5743fcf5ef2aSThomas Huth       i = 1;
5744fcf5ef2aSThomas Huth   else
5745fcf5ef2aSThomas Huth       i <<= 1;
5746fcf5ef2aSThomas Huth   from = opcode & ~(i - 1);
5747fcf5ef2aSThomas Huth   to = from + i;
5748fcf5ef2aSThomas Huth   for (i = from; i < to; i++) {
5749fcf5ef2aSThomas Huth       if ((i & mask) == opcode)
5750fcf5ef2aSThomas Huth           opcode_table[i] = proc;
5751fcf5ef2aSThomas Huth   }
5752fcf5ef2aSThomas Huth }
5753fcf5ef2aSThomas Huth 
5754808d77bcSLucien Murray-Pitts /*
5755808d77bcSLucien Murray-Pitts  * Register m68k opcode handlers.  Order is important.
5756808d77bcSLucien Murray-Pitts  * Later insn override earlier ones.
5757808d77bcSLucien Murray-Pitts  */
register_m68k_insns(CPUM68KState * env)5758fcf5ef2aSThomas Huth void register_m68k_insns (CPUM68KState *env)
5759fcf5ef2aSThomas Huth {
5760808d77bcSLucien Murray-Pitts     /*
5761808d77bcSLucien Murray-Pitts      * Build the opcode table only once to avoid
5762808d77bcSLucien Murray-Pitts      * multithreading issues.
5763808d77bcSLucien Murray-Pitts      */
5764fcf5ef2aSThomas Huth     if (opcode_table[0] != NULL) {
5765fcf5ef2aSThomas Huth         return;
5766fcf5ef2aSThomas Huth     }
5767fcf5ef2aSThomas Huth 
5768808d77bcSLucien Murray-Pitts     /*
5769808d77bcSLucien Murray-Pitts      * use BASE() for instruction available
5770fcf5ef2aSThomas Huth      * for CF_ISA_A and M68000.
5771fcf5ef2aSThomas Huth      */
5772fcf5ef2aSThomas Huth #define BASE(name, opcode, mask) \
5773fcf5ef2aSThomas Huth     register_opcode(disas_##name, 0x##opcode, 0x##mask)
5774fcf5ef2aSThomas Huth #define INSN(name, opcode, mask, feature) do { \
5775fcf5ef2aSThomas Huth     if (m68k_feature(env, M68K_FEATURE_##feature)) \
5776fcf5ef2aSThomas Huth         BASE(name, opcode, mask); \
5777fcf5ef2aSThomas Huth     } while(0)
5778fcf5ef2aSThomas Huth     BASE(undef,     0000, 0000);
5779fcf5ef2aSThomas Huth     INSN(arith_im,  0080, fff8, CF_ISA_A);
5780aece90d8SMark Cave-Ayland     INSN(arith_im,  0000, ff00, M68K);
57818bf6cbafSLaurent Vivier     INSN(chk2,      00c0, f9c0, CHK2);
5782fcf5ef2aSThomas Huth     INSN(bitrev,    00c0, fff8, CF_ISA_APLUSC);
5783fcf5ef2aSThomas Huth     BASE(bitop_reg, 0100, f1c0);
5784fcf5ef2aSThomas Huth     BASE(bitop_reg, 0140, f1c0);
5785fcf5ef2aSThomas Huth     BASE(bitop_reg, 0180, f1c0);
5786fcf5ef2aSThomas Huth     BASE(bitop_reg, 01c0, f1c0);
57871226e212SPavel Dovgalyuk     INSN(movep,     0108, f138, MOVEP);
5788fcf5ef2aSThomas Huth     INSN(arith_im,  0280, fff8, CF_ISA_A);
5789aece90d8SMark Cave-Ayland     INSN(arith_im,  0200, ff00, M68K);
5790aece90d8SMark Cave-Ayland     INSN(undef,     02c0, ffc0, M68K);
5791fcf5ef2aSThomas Huth     INSN(byterev,   02c0, fff8, CF_ISA_APLUSC);
5792fcf5ef2aSThomas Huth     INSN(arith_im,  0480, fff8, CF_ISA_A);
5793aece90d8SMark Cave-Ayland     INSN(arith_im,  0400, ff00, M68K);
5794aece90d8SMark Cave-Ayland     INSN(undef,     04c0, ffc0, M68K);
5795aece90d8SMark Cave-Ayland     INSN(arith_im,  0600, ff00, M68K);
5796aece90d8SMark Cave-Ayland     INSN(undef,     06c0, ffc0, M68K);
5797fcf5ef2aSThomas Huth     INSN(ff1,       04c0, fff8, CF_ISA_APLUSC);
5798fcf5ef2aSThomas Huth     INSN(arith_im,  0680, fff8, CF_ISA_A);
5799fcf5ef2aSThomas Huth     INSN(arith_im,  0c00, ff38, CF_ISA_A);
5800aece90d8SMark Cave-Ayland     INSN(arith_im,  0c00, ff00, M68K);
5801fcf5ef2aSThomas Huth     BASE(bitop_im,  0800, ffc0);
5802fcf5ef2aSThomas Huth     BASE(bitop_im,  0840, ffc0);
5803fcf5ef2aSThomas Huth     BASE(bitop_im,  0880, ffc0);
5804fcf5ef2aSThomas Huth     BASE(bitop_im,  08c0, ffc0);
5805fcf5ef2aSThomas Huth     INSN(arith_im,  0a80, fff8, CF_ISA_A);
5806aece90d8SMark Cave-Ayland     INSN(arith_im,  0a00, ff00, M68K);
58076a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
5808aece90d8SMark Cave-Ayland     INSN(moves,     0e00, ff00, M68K);
58095fa9f1f2SLaurent Vivier #endif
581014f94406SLaurent Vivier     INSN(cas,       0ac0, ffc0, CAS);
581114f94406SLaurent Vivier     INSN(cas,       0cc0, ffc0, CAS);
581214f94406SLaurent Vivier     INSN(cas,       0ec0, ffc0, CAS);
581314f94406SLaurent Vivier     INSN(cas2w,     0cfc, ffff, CAS);
581414f94406SLaurent Vivier     INSN(cas2l,     0efc, ffff, CAS);
5815fcf5ef2aSThomas Huth     BASE(move,      1000, f000);
5816fcf5ef2aSThomas Huth     BASE(move,      2000, f000);
5817fcf5ef2aSThomas Huth     BASE(move,      3000, f000);
5818aece90d8SMark Cave-Ayland     INSN(chk,       4000, f040, M68K);
5819fcf5ef2aSThomas Huth     INSN(strldsr,   40e7, ffff, CF_ISA_APLUSC);
5820fcf5ef2aSThomas Huth     INSN(negx,      4080, fff8, CF_ISA_A);
5821aece90d8SMark Cave-Ayland     INSN(negx,      4000, ff00, M68K);
5822aece90d8SMark Cave-Ayland     INSN(undef,     40c0, ffc0, M68K);
5823fcf5ef2aSThomas Huth     INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
5824aece90d8SMark Cave-Ayland     INSN(move_from_sr, 40c0, ffc0, M68K);
5825fcf5ef2aSThomas Huth     BASE(lea,       41c0, f1c0);
5826fcf5ef2aSThomas Huth     BASE(clr,       4200, ff00);
5827fcf5ef2aSThomas Huth     BASE(undef,     42c0, ffc0);
5828fcf5ef2aSThomas Huth     INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
5829aece90d8SMark Cave-Ayland     INSN(move_from_ccr, 42c0, ffc0, M68K);
5830fcf5ef2aSThomas Huth     INSN(neg,       4480, fff8, CF_ISA_A);
5831aece90d8SMark Cave-Ayland     INSN(neg,       4400, ff00, M68K);
5832aece90d8SMark Cave-Ayland     INSN(undef,     44c0, ffc0, M68K);
5833fcf5ef2aSThomas Huth     BASE(move_to_ccr, 44c0, ffc0);
5834fcf5ef2aSThomas Huth     INSN(not,       4680, fff8, CF_ISA_A);
5835aece90d8SMark Cave-Ayland     INSN(not,       4600, ff00, M68K);
58366a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
5837b6a21d8dSLaurent Vivier     BASE(move_to_sr, 46c0, ffc0);
58386ad25764SLaurent Vivier #endif
5839aece90d8SMark Cave-Ayland     INSN(nbcd,      4800, ffc0, M68K);
5840aece90d8SMark Cave-Ayland     INSN(linkl,     4808, fff8, M68K);
5841fcf5ef2aSThomas Huth     BASE(pea,       4840, ffc0);
5842fcf5ef2aSThomas Huth     BASE(swap,      4840, fff8);
5843fcf5ef2aSThomas Huth     INSN(bkpt,      4848, fff8, BKPT);
58447b542eb9SLaurent Vivier     INSN(movem,     48d0, fbf8, CF_ISA_A);
58457b542eb9SLaurent Vivier     INSN(movem,     48e8, fbf8, CF_ISA_A);
5846aece90d8SMark Cave-Ayland     INSN(movem,     4880, fb80, M68K);
5847fcf5ef2aSThomas Huth     BASE(ext,       4880, fff8);
5848fcf5ef2aSThomas Huth     BASE(ext,       48c0, fff8);
5849fcf5ef2aSThomas Huth     BASE(ext,       49c0, fff8);
5850fcf5ef2aSThomas Huth     BASE(tst,       4a00, ff00);
5851fcf5ef2aSThomas Huth     INSN(tas,       4ac0, ffc0, CF_ISA_B);
5852aece90d8SMark Cave-Ayland     INSN(tas,       4ac0, ffc0, M68K);
58536a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
5854fcf5ef2aSThomas Huth     INSN(halt,      4ac8, ffff, CF_ISA_A);
5855aece90d8SMark Cave-Ayland     INSN(halt,      4ac8, ffff, M68K);
58566ad25764SLaurent Vivier #endif
5857fcf5ef2aSThomas Huth     INSN(pulse,     4acc, ffff, CF_ISA_A);
5858fcf5ef2aSThomas Huth     BASE(illegal,   4afc, ffff);
5859fcf5ef2aSThomas Huth     INSN(mull,      4c00, ffc0, CF_ISA_A);
5860fcf5ef2aSThomas Huth     INSN(mull,      4c00, ffc0, LONG_MULDIV);
5861fcf5ef2aSThomas Huth     INSN(divl,      4c40, ffc0, CF_ISA_A);
5862fcf5ef2aSThomas Huth     INSN(divl,      4c40, ffc0, LONG_MULDIV);
5863fcf5ef2aSThomas Huth     INSN(sats,      4c80, fff8, CF_ISA_B);
5864fcf5ef2aSThomas Huth     BASE(trap,      4e40, fff0);
5865fcf5ef2aSThomas Huth     BASE(link,      4e50, fff8);
5866fcf5ef2aSThomas Huth     BASE(unlk,      4e58, fff8);
58676a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
5868fcf5ef2aSThomas Huth     INSN(move_to_usp, 4e60, fff8, USP);
5869fcf5ef2aSThomas Huth     INSN(move_from_usp, 4e68, fff8, USP);
5870aece90d8SMark Cave-Ayland     INSN(reset,     4e70, ffff, M68K);
5871fcf5ef2aSThomas Huth     BASE(stop,      4e72, ffff);
5872fcf5ef2aSThomas Huth     BASE(rte,       4e73, ffff);
58736e22b28eSLaurent Vivier     INSN(cf_movec,  4e7b, ffff, CF_ISA_A);
58748df0e6aeSLucien Murray-Pitts     INSN(m68k_movec, 4e7a, fffe, MOVEC);
58756ad25764SLaurent Vivier #endif
58766ad25764SLaurent Vivier     BASE(nop,       4e71, ffff);
587718059c9eSLaurent Vivier     INSN(rtd,       4e74, ffff, RTD);
5878fcf5ef2aSThomas Huth     BASE(rts,       4e75, ffff);
5879aece90d8SMark Cave-Ayland     INSN(trapv,     4e76, ffff, M68K);
5880aece90d8SMark Cave-Ayland     INSN(rtr,       4e77, ffff, M68K);
5881fcf5ef2aSThomas Huth     BASE(jump,      4e80, ffc0);
5882fcf5ef2aSThomas Huth     BASE(jump,      4ec0, ffc0);
5883aece90d8SMark Cave-Ayland     INSN(addsubq,   5000, f080, M68K);
5884fcf5ef2aSThomas Huth     BASE(addsubq,   5080, f0c0);
5885fcf5ef2aSThomas Huth     INSN(scc,       50c0, f0f8, CF_ISA_A); /* Scc.B Dx   */
5886aece90d8SMark Cave-Ayland     INSN(scc,       50c0, f0c0, M68K);     /* Scc.B <EA> */
5887aece90d8SMark Cave-Ayland     INSN(dbcc,      50c8, f0f8, M68K);
5888aeeb90afSRichard Henderson     INSN(trapcc,    50fa, f0fe, TRAPCC);   /* opmode 010, 011 */
5889aeeb90afSRichard Henderson     INSN(trapcc,    50fc, f0ff, TRAPCC);   /* opmode 100 */
5890815c6deaSRichard Henderson     INSN(trapcc,    51fa, fffe, CF_ISA_A); /* TPF (trapf) opmode 010, 011 */
5891815c6deaSRichard Henderson     INSN(trapcc,    51fc, ffff, CF_ISA_A); /* TPF (trapf) opmode 100 */
5892fcf5ef2aSThomas Huth 
5893fcf5ef2aSThomas Huth     /* Branch instructions.  */
5894fcf5ef2aSThomas Huth     BASE(branch,    6000, f000);
5895fcf5ef2aSThomas Huth     /* Disable long branch instructions, then add back the ones we want.  */
5896fcf5ef2aSThomas Huth     BASE(undef,     60ff, f0ff); /* All long branches.  */
5897fcf5ef2aSThomas Huth     INSN(branch,    60ff, f0ff, CF_ISA_B);
5898fcf5ef2aSThomas Huth     INSN(undef,     60ff, ffff, CF_ISA_B); /* bra.l */
5899fcf5ef2aSThomas Huth     INSN(branch,    60ff, ffff, BRAL);
5900fcf5ef2aSThomas Huth     INSN(branch,    60ff, f0ff, BCCL);
5901fcf5ef2aSThomas Huth 
5902fcf5ef2aSThomas Huth     BASE(moveq,     7000, f100);
5903fcf5ef2aSThomas Huth     INSN(mvzs,      7100, f100, CF_ISA_B);
5904fcf5ef2aSThomas Huth     BASE(or,        8000, f000);
5905fcf5ef2aSThomas Huth     BASE(divw,      80c0, f0c0);
5906aece90d8SMark Cave-Ayland     INSN(sbcd_reg,  8100, f1f8, M68K);
5907aece90d8SMark Cave-Ayland     INSN(sbcd_mem,  8108, f1f8, M68K);
5908fcf5ef2aSThomas Huth     BASE(addsub,    9000, f000);
5909fcf5ef2aSThomas Huth     INSN(undef,     90c0, f0c0, CF_ISA_A);
5910fcf5ef2aSThomas Huth     INSN(subx_reg,  9180, f1f8, CF_ISA_A);
5911aece90d8SMark Cave-Ayland     INSN(subx_reg,  9100, f138, M68K);
5912aece90d8SMark Cave-Ayland     INSN(subx_mem,  9108, f138, M68K);
5913fcf5ef2aSThomas Huth     INSN(suba,      91c0, f1c0, CF_ISA_A);
5914aece90d8SMark Cave-Ayland     INSN(suba,      90c0, f0c0, M68K);
5915fcf5ef2aSThomas Huth 
5916fcf5ef2aSThomas Huth     BASE(undef_mac, a000, f000);
5917fcf5ef2aSThomas Huth     INSN(mac,       a000, f100, CF_EMAC);
5918fcf5ef2aSThomas Huth     INSN(from_mac,  a180, f9b0, CF_EMAC);
5919fcf5ef2aSThomas Huth     INSN(move_mac,  a110, f9fc, CF_EMAC);
5920fcf5ef2aSThomas Huth     INSN(from_macsr,a980, f9f0, CF_EMAC);
5921fcf5ef2aSThomas Huth     INSN(from_mask, ad80, fff0, CF_EMAC);
5922fcf5ef2aSThomas Huth     INSN(from_mext, ab80, fbf0, CF_EMAC);
5923fcf5ef2aSThomas Huth     INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
5924fcf5ef2aSThomas Huth     INSN(to_mac,    a100, f9c0, CF_EMAC);
5925fcf5ef2aSThomas Huth     INSN(to_macsr,  a900, ffc0, CF_EMAC);
5926fcf5ef2aSThomas Huth     INSN(to_mext,   ab00, fbc0, CF_EMAC);
5927fcf5ef2aSThomas Huth     INSN(to_mask,   ad00, ffc0, CF_EMAC);
5928fcf5ef2aSThomas Huth 
5929fcf5ef2aSThomas Huth     INSN(mov3q,     a140, f1c0, CF_ISA_B);
5930fcf5ef2aSThomas Huth     INSN(cmp,       b000, f1c0, CF_ISA_B); /* cmp.b */
5931fcf5ef2aSThomas Huth     INSN(cmp,       b040, f1c0, CF_ISA_B); /* cmp.w */
5932fcf5ef2aSThomas Huth     INSN(cmpa,      b0c0, f1c0, CF_ISA_B); /* cmpa.w */
5933fcf5ef2aSThomas Huth     INSN(cmp,       b080, f1c0, CF_ISA_A);
5934fcf5ef2aSThomas Huth     INSN(cmpa,      b1c0, f1c0, CF_ISA_A);
5935aece90d8SMark Cave-Ayland     INSN(cmp,       b000, f100, M68K);
5936aece90d8SMark Cave-Ayland     INSN(eor,       b100, f100, M68K);
5937aece90d8SMark Cave-Ayland     INSN(cmpm,      b108, f138, M68K);
5938aece90d8SMark Cave-Ayland     INSN(cmpa,      b0c0, f0c0, M68K);
5939fcf5ef2aSThomas Huth     INSN(eor,       b180, f1c0, CF_ISA_A);
5940fcf5ef2aSThomas Huth     BASE(and,       c000, f000);
5941aece90d8SMark Cave-Ayland     INSN(exg_dd,    c140, f1f8, M68K);
5942aece90d8SMark Cave-Ayland     INSN(exg_aa,    c148, f1f8, M68K);
5943aece90d8SMark Cave-Ayland     INSN(exg_da,    c188, f1f8, M68K);
5944fcf5ef2aSThomas Huth     BASE(mulw,      c0c0, f0c0);
5945aece90d8SMark Cave-Ayland     INSN(abcd_reg,  c100, f1f8, M68K);
5946aece90d8SMark Cave-Ayland     INSN(abcd_mem,  c108, f1f8, M68K);
5947fcf5ef2aSThomas Huth     BASE(addsub,    d000, f000);
5948fcf5ef2aSThomas Huth     INSN(undef,     d0c0, f0c0, CF_ISA_A);
5949fcf5ef2aSThomas Huth     INSN(addx_reg,      d180, f1f8, CF_ISA_A);
5950aece90d8SMark Cave-Ayland     INSN(addx_reg,  d100, f138, M68K);
5951aece90d8SMark Cave-Ayland     INSN(addx_mem,  d108, f138, M68K);
5952fcf5ef2aSThomas Huth     INSN(adda,      d1c0, f1c0, CF_ISA_A);
5953aece90d8SMark Cave-Ayland     INSN(adda,      d0c0, f0c0, M68K);
5954fcf5ef2aSThomas Huth     INSN(shift_im,  e080, f0f0, CF_ISA_A);
5955fcf5ef2aSThomas Huth     INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
5956aece90d8SMark Cave-Ayland     INSN(shift8_im, e000, f0f0, M68K);
5957aece90d8SMark Cave-Ayland     INSN(shift16_im, e040, f0f0, M68K);
5958aece90d8SMark Cave-Ayland     INSN(shift_im,  e080, f0f0, M68K);
5959aece90d8SMark Cave-Ayland     INSN(shift8_reg, e020, f0f0, M68K);
5960aece90d8SMark Cave-Ayland     INSN(shift16_reg, e060, f0f0, M68K);
5961aece90d8SMark Cave-Ayland     INSN(shift_reg, e0a0, f0f0, M68K);
5962aece90d8SMark Cave-Ayland     INSN(shift_mem, e0c0, fcc0, M68K);
5963aece90d8SMark Cave-Ayland     INSN(rotate_im, e090, f0f0, M68K);
5964aece90d8SMark Cave-Ayland     INSN(rotate8_im, e010, f0f0, M68K);
5965aece90d8SMark Cave-Ayland     INSN(rotate16_im, e050, f0f0, M68K);
5966aece90d8SMark Cave-Ayland     INSN(rotate_reg, e0b0, f0f0, M68K);
5967aece90d8SMark Cave-Ayland     INSN(rotate8_reg, e030, f0f0, M68K);
5968aece90d8SMark Cave-Ayland     INSN(rotate16_reg, e070, f0f0, M68K);
5969aece90d8SMark Cave-Ayland     INSN(rotate_mem, e4c0, fcc0, M68K);
5970f2224f2cSRichard Henderson     INSN(bfext_mem, e9c0, fdc0, BITFIELD);  /* bfextu & bfexts */
5971f2224f2cSRichard Henderson     INSN(bfext_reg, e9c0, fdf8, BITFIELD);
5972f2224f2cSRichard Henderson     INSN(bfins_mem, efc0, ffc0, BITFIELD);
5973ac815f46SRichard Henderson     INSN(bfins_reg, efc0, fff8, BITFIELD);
5974f2224f2cSRichard Henderson     INSN(bfop_mem, eac0, ffc0, BITFIELD);   /* bfchg */
5975ac815f46SRichard Henderson     INSN(bfop_reg, eac0, fff8, BITFIELD);   /* bfchg */
5976f2224f2cSRichard Henderson     INSN(bfop_mem, ecc0, ffc0, BITFIELD);   /* bfclr */
5977ac815f46SRichard Henderson     INSN(bfop_reg, ecc0, fff8, BITFIELD);   /* bfclr */
5978a45f1763SRichard Henderson     INSN(bfop_mem, edc0, ffc0, BITFIELD);   /* bfffo */
5979a45f1763SRichard Henderson     INSN(bfop_reg, edc0, fff8, BITFIELD);   /* bfffo */
5980f2224f2cSRichard Henderson     INSN(bfop_mem, eec0, ffc0, BITFIELD);   /* bfset */
5981ac815f46SRichard Henderson     INSN(bfop_reg, eec0, fff8, BITFIELD);   /* bfset */
5982f2224f2cSRichard Henderson     INSN(bfop_mem, e8c0, ffc0, BITFIELD);   /* bftst */
5983ac815f46SRichard Henderson     INSN(bfop_reg, e8c0, fff8, BITFIELD);   /* bftst */
5984f83311e4SLaurent Vivier     BASE(undef_fpu, f000, f000);
5985fcf5ef2aSThomas Huth     INSN(fpu,       f200, ffc0, CF_FPU);
5986fcf5ef2aSThomas Huth     INSN(fbcc,      f280, ffc0, CF_FPU);
5987f83311e4SLaurent Vivier     INSN(fpu,       f200, ffc0, FPU);
5988dd337bf8SLaurent Vivier     INSN(fscc,      f240, ffc0, FPU);
5989cc1cc264SRichard Henderson     INSN(ftrapcc,   f27a, fffe, FPU);       /* opmode 010, 011 */
5990cc1cc264SRichard Henderson     INSN(ftrapcc,   f27c, ffff, FPU);       /* opmode 100 */
5991f83311e4SLaurent Vivier     INSN(fbcc,      f280, ff80, FPU);
59926a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
59936ad25764SLaurent Vivier     INSN(frestore,  f340, ffc0, CF_FPU);
59946ad25764SLaurent Vivier     INSN(fsave,     f300, ffc0, CF_FPU);
5995f83311e4SLaurent Vivier     INSN(frestore,  f340, ffc0, FPU);
5996f83311e4SLaurent Vivier     INSN(fsave,     f300, ffc0, FPU);
5997fcf5ef2aSThomas Huth     INSN(intouch,   f340, ffc0, CF_ISA_A);
5998fcf5ef2aSThomas Huth     INSN(cpushl,    f428, ff38, CF_ISA_A);
5999f58ed1c5SLaurent Vivier     INSN(cpush,     f420, ff20, M68040);
6000f58ed1c5SLaurent Vivier     INSN(cinv,      f400, ff20, M68040);
6001e55886c3SLaurent Vivier     INSN(pflush,    f500, ffe0, M68040);
6002e55886c3SLaurent Vivier     INSN(ptest,     f548, ffd8, M68040);
6003fcf5ef2aSThomas Huth     INSN(wddata,    fb00, ff00, CF_ISA_A);
6004fcf5ef2aSThomas Huth     INSN(wdebug,    fbc0, ffc0, CF_ISA_A);
60056ad25764SLaurent Vivier #endif
60066ad25764SLaurent Vivier     INSN(move16_mem, f600, ffe0, M68040);
60076ad25764SLaurent Vivier     INSN(move16_reg, f620, fff8, M68040);
6008fcf5ef2aSThomas Huth #undef INSN
6009fcf5ef2aSThomas Huth }
6010fcf5ef2aSThomas Huth 
m68k_tr_init_disas_context(DisasContextBase * dcbase,CPUState * cpu)601111ab74b0SRichard Henderson static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
6012fcf5ef2aSThomas Huth {
601311ab74b0SRichard Henderson     DisasContext *dc = container_of(dcbase, DisasContext, base);
6014b77af26eSRichard Henderson     CPUM68KState *env = cpu_env(cpu);
6015fcf5ef2aSThomas Huth 
6016fcf5ef2aSThomas Huth     dc->env = env;
601711ab74b0SRichard Henderson     dc->pc = dc->base.pc_first;
60188115fc93SRichard Henderson     /* This value will always be filled in properly before m68k_tr_tb_stop. */
60198115fc93SRichard Henderson     dc->pc_prev = 0xdeadbeef;
6020fcf5ef2aSThomas Huth     dc->cc_op = CC_OP_DYNAMIC;
6021fcf5ef2aSThomas Huth     dc->cc_op_synced = 1;
6022fcf5ef2aSThomas Huth     dc->done_mac = 0;
60238a1e52b6SRichard Henderson     dc->writeback_mask = 0;
60245e50c6c7SMark Cave-Ayland 
60255e50c6c7SMark Cave-Ayland     dc->ss_active = (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS);
60265e50c6c7SMark Cave-Ayland     /* If architectural single step active, limit to 1 */
6027661da0f6SRichard Henderson     if (dc->ss_active) {
60285e50c6c7SMark Cave-Ayland         dc->base.max_insns = 1;
60295e50c6c7SMark Cave-Ayland     }
603011ab74b0SRichard Henderson }
6031ecc207d2SLaurent Vivier 
m68k_tr_tb_start(DisasContextBase * dcbase,CPUState * cpu)603211ab74b0SRichard Henderson static void m68k_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
603311ab74b0SRichard Henderson {
603411ab74b0SRichard Henderson }
6035fcf5ef2aSThomas Huth 
m68k_tr_insn_start(DisasContextBase * dcbase,CPUState * cpu)603611ab74b0SRichard Henderson static void m68k_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
603711ab74b0SRichard Henderson {
603811ab74b0SRichard Henderson     DisasContext *dc = container_of(dcbase, DisasContext, base);
603911ab74b0SRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
604011ab74b0SRichard Henderson }
604111ab74b0SRichard Henderson 
m68k_tr_translate_insn(DisasContextBase * dcbase,CPUState * cpu)604211ab74b0SRichard Henderson static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
604311ab74b0SRichard Henderson {
604411ab74b0SRichard Henderson     DisasContext *dc = container_of(dcbase, DisasContext, base);
6045b77af26eSRichard Henderson     CPUM68KState *env = cpu_env(cpu);
6046a56f36c1SRichard Henderson     uint16_t insn = read_im16(env, dc);
6047fcf5ef2aSThomas Huth 
6048a56f36c1SRichard Henderson     opcode_table[insn](env, dc, insn);
6049a56f36c1SRichard Henderson     do_writebacks(dc);
6050a56f36c1SRichard Henderson 
60518115fc93SRichard Henderson     dc->pc_prev = dc->base.pc_next;
6052a575cbe0SRichard Henderson     dc->base.pc_next = dc->pc;
6053fcf5ef2aSThomas Huth 
60544c7a0f6fSRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT) {
6055808d77bcSLucien Murray-Pitts         /*
6056808d77bcSLucien Murray-Pitts          * Stop translation when the next insn might touch a new page.
60574c7a0f6fSRichard Henderson          * This ensures that prefetch aborts at the right place.
60584c7a0f6fSRichard Henderson          *
60594c7a0f6fSRichard Henderson          * We cannot determine the size of the next insn without
60604c7a0f6fSRichard Henderson          * completely decoding it.  However, the maximum insn size
60614c7a0f6fSRichard Henderson          * is 32 bytes, so end if we do not have that much remaining.
60624c7a0f6fSRichard Henderson          * This may produce several small TBs at the end of each page,
60634c7a0f6fSRichard Henderson          * but they will all be linked with goto_tb.
60644c7a0f6fSRichard Henderson          *
60654c7a0f6fSRichard Henderson          * ??? ColdFire maximum is 4 bytes; MC68000's maximum is also
60664c7a0f6fSRichard Henderson          * smaller than MC68020's.
60674c7a0f6fSRichard Henderson          */
60684c7a0f6fSRichard Henderson         target_ulong start_page_offset
60694c7a0f6fSRichard Henderson             = dc->pc - (dc->base.pc_first & TARGET_PAGE_MASK);
60704c7a0f6fSRichard Henderson 
60714c7a0f6fSRichard Henderson         if (start_page_offset >= TARGET_PAGE_SIZE - 32) {
607211ab74b0SRichard Henderson             dc->base.is_jmp = DISAS_TOO_MANY;
6073fcf5ef2aSThomas Huth         }
607411ab74b0SRichard Henderson     }
60754c7a0f6fSRichard Henderson }
607611ab74b0SRichard Henderson 
m68k_tr_tb_stop(DisasContextBase * dcbase,CPUState * cpu)607711ab74b0SRichard Henderson static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
607811ab74b0SRichard Henderson {
607911ab74b0SRichard Henderson     DisasContext *dc = container_of(dcbase, DisasContext, base);
608011ab74b0SRichard Henderson 
6081a575cbe0SRichard Henderson     switch (dc->base.is_jmp) {
6082322f244aSLaurent Vivier     case DISAS_NORETURN:
6083322f244aSLaurent Vivier         break;
608411ab74b0SRichard Henderson     case DISAS_TOO_MANY:
6085fcf5ef2aSThomas Huth         update_cc_op(dc);
60868115fc93SRichard Henderson         gen_jmp_tb(dc, 0, dc->pc, dc->pc_prev);
6087fcf5ef2aSThomas Huth         break;
6088fcf5ef2aSThomas Huth     case DISAS_JUMP:
60898aaf7da9SRichard Henderson         /* We updated CC_OP and PC in gen_jmp/gen_jmp_im.  */
6090661da0f6SRichard Henderson         if (dc->ss_active) {
60918115fc93SRichard Henderson             gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev);
6092322f244aSLaurent Vivier         } else {
60938aaf7da9SRichard Henderson             tcg_gen_lookup_and_goto_ptr();
6094322f244aSLaurent Vivier         }
60958aaf7da9SRichard Henderson         break;
60964106f26eSRichard Henderson     case DISAS_EXIT:
6097808d77bcSLucien Murray-Pitts         /*
6098808d77bcSLucien Murray-Pitts          * We updated CC_OP and PC in gen_exit_tb, but also modified
6099808d77bcSLucien Murray-Pitts          * other state that may require returning to the main loop.
6100808d77bcSLucien Murray-Pitts          */
6101661da0f6SRichard Henderson         if (dc->ss_active) {
61028115fc93SRichard Henderson             gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev);
6103322f244aSLaurent Vivier         } else {
610407ea28b4SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
6105322f244aSLaurent Vivier         }
6106fcf5ef2aSThomas Huth         break;
610711ab74b0SRichard Henderson     default:
610811ab74b0SRichard Henderson         g_assert_not_reached();
6109fcf5ef2aSThomas Huth     }
6110fcf5ef2aSThomas Huth }
6111fcf5ef2aSThomas Huth 
611211ab74b0SRichard Henderson static const TranslatorOps m68k_tr_ops = {
611311ab74b0SRichard Henderson     .init_disas_context = m68k_tr_init_disas_context,
611411ab74b0SRichard Henderson     .tb_start           = m68k_tr_tb_start,
611511ab74b0SRichard Henderson     .insn_start         = m68k_tr_insn_start,
611611ab74b0SRichard Henderson     .translate_insn     = m68k_tr_translate_insn,
611711ab74b0SRichard Henderson     .tb_stop            = m68k_tr_tb_stop,
611811ab74b0SRichard Henderson };
611911ab74b0SRichard Henderson 
gen_intermediate_code(CPUState * cpu,TranslationBlock * tb,int * max_insns,vaddr pc,void * host_pc)6120597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
612132f0c394SAnton Johansson                            vaddr pc, void *host_pc)
612211ab74b0SRichard Henderson {
612311ab74b0SRichard Henderson     DisasContext dc;
6124306c8721SRichard Henderson     translator_loop(cpu, tb, max_insns, pc, host_pc, &m68k_tr_ops, &dc.base);
6125fcf5ef2aSThomas Huth }
6126fcf5ef2aSThomas Huth 
floatx80_to_double(CPUM68KState * env,uint16_t high,uint64_t low)6127f83311e4SLaurent Vivier static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low)
6128f83311e4SLaurent Vivier {
6129f83311e4SLaurent Vivier     floatx80 a = { .high = high, .low = low };
6130f83311e4SLaurent Vivier     union {
6131f83311e4SLaurent Vivier         float64 f64;
6132f83311e4SLaurent Vivier         double d;
6133f83311e4SLaurent Vivier     } u;
6134f83311e4SLaurent Vivier 
6135f83311e4SLaurent Vivier     u.f64 = floatx80_to_float64(a, &env->fp_status);
6136f83311e4SLaurent Vivier     return u.d;
6137f83311e4SLaurent Vivier }
6138f83311e4SLaurent Vivier 
m68k_cpu_dump_state(CPUState * cs,FILE * f,int flags)613990c84c56SMarkus Armbruster void m68k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
6140fcf5ef2aSThomas Huth {
6141e22a4560SPhilippe Mathieu-Daudé     CPUM68KState *env = cpu_env(cs);
6142fcf5ef2aSThomas Huth     int i;
6143fcf5ef2aSThomas Huth     uint16_t sr;
6144f83311e4SLaurent Vivier     for (i = 0; i < 8; i++) {
614590c84c56SMarkus Armbruster         qemu_fprintf(f, "D%d = %08x   A%d = %08x   "
6146f83311e4SLaurent Vivier                      "F%d = %04x %016"PRIx64"  (%12g)\n",
6147fcf5ef2aSThomas Huth                      i, env->dregs[i], i, env->aregs[i],
6148f83311e4SLaurent Vivier                      i, env->fregs[i].l.upper, env->fregs[i].l.lower,
6149f83311e4SLaurent Vivier                      floatx80_to_double(env, env->fregs[i].l.upper,
6150f83311e4SLaurent Vivier                                         env->fregs[i].l.lower));
6151fcf5ef2aSThomas Huth     }
615290c84c56SMarkus Armbruster     qemu_fprintf(f, "PC = %08x   ", env->pc);
6153fcf5ef2aSThomas Huth     sr = env->sr | cpu_m68k_get_ccr(env);
615490c84c56SMarkus Armbruster     qemu_fprintf(f, "SR = %04x T:%x I:%x %c%c %c%c%c%c%c\n",
6155cc523026SLaurent Vivier                  sr, (sr & SR_T) >> SR_T_SHIFT, (sr & SR_I) >> SR_I_SHIFT,
6156cc523026SLaurent Vivier                  (sr & SR_S) ? 'S' : 'U', (sr & SR_M) ? '%' : 'I',
6157cc523026SLaurent Vivier                  (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-',
6158cc523026SLaurent Vivier                  (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-',
6159cc523026SLaurent Vivier                  (sr & CCF_C) ? 'C' : '-');
616090c84c56SMarkus Armbruster     qemu_fprintf(f, "FPSR = %08x %c%c%c%c ", env->fpsr,
6161ba624944SLaurent Vivier                  (env->fpsr & FPSR_CC_A) ? 'A' : '-',
6162ba624944SLaurent Vivier                  (env->fpsr & FPSR_CC_I) ? 'I' : '-',
6163ba624944SLaurent Vivier                  (env->fpsr & FPSR_CC_Z) ? 'Z' : '-',
6164ba624944SLaurent Vivier                  (env->fpsr & FPSR_CC_N) ? 'N' : '-');
616590c84c56SMarkus Armbruster     qemu_fprintf(f, "\n                                "
6166ba624944SLaurent Vivier                  "FPCR =     %04x ", env->fpcr);
6167ba624944SLaurent Vivier     switch (env->fpcr & FPCR_PREC_MASK) {
6168ba624944SLaurent Vivier     case FPCR_PREC_X:
616990c84c56SMarkus Armbruster         qemu_fprintf(f, "X ");
6170ba624944SLaurent Vivier         break;
6171ba624944SLaurent Vivier     case FPCR_PREC_S:
617290c84c56SMarkus Armbruster         qemu_fprintf(f, "S ");
6173ba624944SLaurent Vivier         break;
6174ba624944SLaurent Vivier     case FPCR_PREC_D:
617590c84c56SMarkus Armbruster         qemu_fprintf(f, "D ");
6176ba624944SLaurent Vivier         break;
6177ba624944SLaurent Vivier     }
6178ba624944SLaurent Vivier     switch (env->fpcr & FPCR_RND_MASK) {
6179ba624944SLaurent Vivier     case FPCR_RND_N:
618090c84c56SMarkus Armbruster         qemu_fprintf(f, "RN ");
6181ba624944SLaurent Vivier         break;
6182ba624944SLaurent Vivier     case FPCR_RND_Z:
618390c84c56SMarkus Armbruster         qemu_fprintf(f, "RZ ");
6184ba624944SLaurent Vivier         break;
6185ba624944SLaurent Vivier     case FPCR_RND_M:
618690c84c56SMarkus Armbruster         qemu_fprintf(f, "RM ");
6187ba624944SLaurent Vivier         break;
6188ba624944SLaurent Vivier     case FPCR_RND_P:
618990c84c56SMarkus Armbruster         qemu_fprintf(f, "RP ");
6190ba624944SLaurent Vivier         break;
6191ba624944SLaurent Vivier     }
619290c84c56SMarkus Armbruster     qemu_fprintf(f, "\n");
61936a140586SPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY
619490c84c56SMarkus Armbruster     qemu_fprintf(f, "%sA7(MSP) = %08x %sA7(USP) = %08x %sA7(ISP) = %08x\n",
61956e22b28eSLaurent Vivier                  env->current_sp == M68K_SSP ? "->" : "  ", env->sp[M68K_SSP],
61966e22b28eSLaurent Vivier                  env->current_sp == M68K_USP ? "->" : "  ", env->sp[M68K_USP],
61976e22b28eSLaurent Vivier                  env->current_sp == M68K_ISP ? "->" : "  ", env->sp[M68K_ISP]);
619890c84c56SMarkus Armbruster     qemu_fprintf(f, "VBR = 0x%08x\n", env->vbr);
619990c84c56SMarkus Armbruster     qemu_fprintf(f, "SFC = %x DFC %x\n", env->sfc, env->dfc);
620090c84c56SMarkus Armbruster     qemu_fprintf(f, "SSW %08x TCR %08x URP %08x SRP %08x\n",
620188b2fef6SLaurent Vivier                  env->mmu.ssw, env->mmu.tcr, env->mmu.urp, env->mmu.srp);
620290c84c56SMarkus Armbruster     qemu_fprintf(f, "DTTR0/1: %08x/%08x ITTR0/1: %08x/%08x\n",
6203c05c73b0SLaurent Vivier                  env->mmu.ttr[M68K_DTTR0], env->mmu.ttr[M68K_DTTR1],
6204c05c73b0SLaurent Vivier                  env->mmu.ttr[M68K_ITTR0], env->mmu.ttr[M68K_ITTR1]);
620590c84c56SMarkus Armbruster     qemu_fprintf(f, "MMUSR %08x, fault at %08x\n",
6206e55886c3SLaurent Vivier                  env->mmu.mmusr, env->mmu.ar);
62076a140586SPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */
6208fcf5ef2aSThomas Huth }
6209