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