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 "disas/disas.h"
24fcf5ef2aSThomas Huth #include "exec/exec-all.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
26fcf5ef2aSThomas Huth #include "qemu/log.h"
2790c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
2877fc6f5eSLluís Vilanova #include "exec/translator.h"
29fcf5ef2aSThomas Huth
30fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
31fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
32fcf5ef2aSThomas Huth
33fcf5ef2aSThomas Huth #include "exec/log.h"
3424f91e81SAlex Bennée #include "fpu/softfloat.h"
3524f91e81SAlex Bennée
36d53106c9SRichard Henderson #define HELPER_H "helper.h"
37d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
38d53106c9SRichard Henderson #undef HELPER_H
39fcf5ef2aSThomas Huth
40fcf5ef2aSThomas Huth //#define DEBUG_DISPATCH 1
41fcf5ef2aSThomas Huth
42fcf5ef2aSThomas Huth #define DEFO32(name, offset) static TCGv QREG_##name;
43fcf5ef2aSThomas Huth #define DEFO64(name, offset) static TCGv_i64 QREG_##name;
440f208a97SPhilippe Mathieu-Daudé #include "qregs.h.inc"
45fcf5ef2aSThomas Huth #undef DEFO32
46fcf5ef2aSThomas Huth #undef DEFO64
47fcf5ef2aSThomas Huth
48fcf5ef2aSThomas Huth static TCGv_i32 cpu_halted;
49fcf5ef2aSThomas Huth static TCGv_i32 cpu_exception_index;
50fcf5ef2aSThomas Huth
51f83311e4SLaurent Vivier static char cpu_reg_names[2 * 8 * 3 + 5 * 4];
52fcf5ef2aSThomas Huth static TCGv cpu_dregs[8];
53fcf5ef2aSThomas Huth static TCGv cpu_aregs[8];
54fcf5ef2aSThomas Huth static TCGv_i64 cpu_macc[4];
55fcf5ef2aSThomas Huth
56fcf5ef2aSThomas Huth #define REG(insn, pos) (((insn) >> (pos)) & 7)
57fcf5ef2aSThomas Huth #define DREG(insn, pos) cpu_dregs[REG(insn, pos)]
588a1e52b6SRichard Henderson #define AREG(insn, pos) get_areg(s, REG(insn, pos))
59fcf5ef2aSThomas Huth #define MACREG(acc) cpu_macc[acc]
608a1e52b6SRichard Henderson #define QREG_SP get_areg(s, 7)
61fcf5ef2aSThomas Huth
62fcf5ef2aSThomas Huth static TCGv NULL_QREG;
6311f4e8f8SRichard Henderson #define IS_NULL_QREG(t) (t == NULL_QREG)
64fcf5ef2aSThomas Huth /* Used to distinguish stores from bad addressing modes. */
65fcf5ef2aSThomas Huth static TCGv store_dummy;
66fcf5ef2aSThomas Huth
m68k_tcg_init(void)67fcf5ef2aSThomas Huth void m68k_tcg_init(void)
68fcf5ef2aSThomas Huth {
69fcf5ef2aSThomas Huth char *p;
70fcf5ef2aSThomas Huth int i;
71fcf5ef2aSThomas Huth
72fcf5ef2aSThomas Huth #define DEFO32(name, offset) \
73ad75a51eSRichard Henderson QREG_##name = tcg_global_mem_new_i32(tcg_env, \
74fcf5ef2aSThomas Huth offsetof(CPUM68KState, offset), #name);
75fcf5ef2aSThomas Huth #define DEFO64(name, offset) \
76ad75a51eSRichard Henderson QREG_##name = tcg_global_mem_new_i64(tcg_env, \
77fcf5ef2aSThomas Huth offsetof(CPUM68KState, offset), #name);
780f208a97SPhilippe Mathieu-Daudé #include "qregs.h.inc"
79fcf5ef2aSThomas Huth #undef DEFO32
80fcf5ef2aSThomas Huth #undef DEFO64
81fcf5ef2aSThomas Huth
82ad75a51eSRichard Henderson cpu_halted = tcg_global_mem_new_i32(tcg_env,
83fcf5ef2aSThomas Huth -offsetof(M68kCPU, env) +
84fcf5ef2aSThomas Huth offsetof(CPUState, halted), "HALTED");
85ad75a51eSRichard Henderson cpu_exception_index = tcg_global_mem_new_i32(tcg_env,
86fcf5ef2aSThomas Huth -offsetof(M68kCPU, env) +
87fcf5ef2aSThomas Huth offsetof(CPUState, exception_index),
88fcf5ef2aSThomas Huth "EXCEPTION");
89fcf5ef2aSThomas Huth
90fcf5ef2aSThomas Huth p = cpu_reg_names;
91fcf5ef2aSThomas Huth for (i = 0; i < 8; i++) {
92fcf5ef2aSThomas Huth sprintf(p, "D%d", i);
93ad75a51eSRichard Henderson cpu_dregs[i] = tcg_global_mem_new(tcg_env,
94fcf5ef2aSThomas Huth offsetof(CPUM68KState, dregs[i]), p);
95fcf5ef2aSThomas Huth p += 3;
96fcf5ef2aSThomas Huth sprintf(p, "A%d", i);
97ad75a51eSRichard Henderson cpu_aregs[i] = tcg_global_mem_new(tcg_env,
98fcf5ef2aSThomas Huth offsetof(CPUM68KState, aregs[i]), p);
99fcf5ef2aSThomas Huth p += 3;
100fcf5ef2aSThomas Huth }
101fcf5ef2aSThomas Huth for (i = 0; i < 4; i++) {
102fcf5ef2aSThomas Huth sprintf(p, "ACC%d", i);
103ad75a51eSRichard Henderson cpu_macc[i] = tcg_global_mem_new_i64(tcg_env,
104fcf5ef2aSThomas Huth offsetof(CPUM68KState, macc[i]), p);
105fcf5ef2aSThomas Huth p += 5;
106fcf5ef2aSThomas Huth }
107fcf5ef2aSThomas Huth
108ad75a51eSRichard Henderson NULL_QREG = tcg_global_mem_new(tcg_env, -4, "NULL");
109ad75a51eSRichard Henderson store_dummy = tcg_global_mem_new(tcg_env, -8, "NULL");
110fcf5ef2aSThomas Huth }
111fcf5ef2aSThomas Huth
112fcf5ef2aSThomas Huth /* internal defines */
113fcf5ef2aSThomas Huth typedef struct DisasContext {
114a575cbe0SRichard Henderson DisasContextBase base;
115fcf5ef2aSThomas Huth CPUM68KState *env;
116fcf5ef2aSThomas Huth target_ulong pc;
1178115fc93SRichard Henderson target_ulong pc_prev;
118fcf5ef2aSThomas Huth CCOp cc_op; /* Current CC operation */
119fcf5ef2aSThomas Huth int cc_op_synced;
120fcf5ef2aSThomas Huth TCGv_i64 mactmp;
121fcf5ef2aSThomas Huth int done_mac;
1228a1e52b6SRichard Henderson int writeback_mask;
1238a1e52b6SRichard Henderson TCGv writeback[8];
1245e50c6c7SMark Cave-Ayland bool ss_active;
125fcf5ef2aSThomas Huth } DisasContext;
126fcf5ef2aSThomas Huth
get_areg(DisasContext * s,unsigned regno)1278a1e52b6SRichard Henderson static TCGv get_areg(DisasContext *s, unsigned regno)
1288a1e52b6SRichard Henderson {
1298a1e52b6SRichard Henderson if (s->writeback_mask & (1 << regno)) {
1308a1e52b6SRichard Henderson return s->writeback[regno];
1318a1e52b6SRichard Henderson } else {
1328a1e52b6SRichard Henderson return cpu_aregs[regno];
1338a1e52b6SRichard Henderson }
1348a1e52b6SRichard Henderson }
1358a1e52b6SRichard Henderson
delay_set_areg(DisasContext * s,unsigned regno,TCGv val,bool give_temp)1368a1e52b6SRichard Henderson static void delay_set_areg(DisasContext *s, unsigned regno,
1378a1e52b6SRichard Henderson TCGv val, bool give_temp)
1388a1e52b6SRichard Henderson {
1398a1e52b6SRichard Henderson if (s->writeback_mask & (1 << regno)) {
1408a1e52b6SRichard Henderson if (give_temp) {
1418a1e52b6SRichard Henderson s->writeback[regno] = val;
1428a1e52b6SRichard Henderson } else {
1438a1e52b6SRichard Henderson tcg_gen_mov_i32(s->writeback[regno], val);
1448a1e52b6SRichard Henderson }
1458a1e52b6SRichard Henderson } else {
1468a1e52b6SRichard Henderson s->writeback_mask |= 1 << regno;
1478a1e52b6SRichard Henderson if (give_temp) {
1488a1e52b6SRichard Henderson s->writeback[regno] = val;
1498a1e52b6SRichard Henderson } else {
1508a1e52b6SRichard Henderson TCGv tmp = tcg_temp_new();
1518a1e52b6SRichard Henderson s->writeback[regno] = tmp;
1528a1e52b6SRichard Henderson tcg_gen_mov_i32(tmp, val);
1538a1e52b6SRichard Henderson }
1548a1e52b6SRichard Henderson }
1558a1e52b6SRichard Henderson }
1568a1e52b6SRichard Henderson
do_writebacks(DisasContext * s)1578a1e52b6SRichard Henderson static void do_writebacks(DisasContext *s)
1588a1e52b6SRichard Henderson {
1598a1e52b6SRichard Henderson unsigned mask = s->writeback_mask;
1608a1e52b6SRichard Henderson if (mask) {
1618a1e52b6SRichard Henderson s->writeback_mask = 0;
1628a1e52b6SRichard Henderson do {
1638a1e52b6SRichard Henderson unsigned regno = ctz32(mask);
1648a1e52b6SRichard Henderson tcg_gen_mov_i32(cpu_aregs[regno], s->writeback[regno]);
1658a1e52b6SRichard Henderson mask &= mask - 1;
1668a1e52b6SRichard Henderson } while (mask);
1678a1e52b6SRichard Henderson }
1688a1e52b6SRichard Henderson }
1698a1e52b6SRichard Henderson
17077fc6f5eSLluís Vilanova /* is_jmp field values */
17177fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
1724106f26eSRichard Henderson #define DISAS_EXIT DISAS_TARGET_1 /* cpu state was modified dynamically */
173fcf5ef2aSThomas Huth
174fcf5ef2aSThomas Huth #if defined(CONFIG_USER_ONLY)
175fcf5ef2aSThomas Huth #define IS_USER(s) 1
176fcf5ef2aSThomas Huth #else
177a575cbe0SRichard Henderson #define IS_USER(s) (!(s->base.tb->flags & TB_FLAGS_MSR_S))
178a575cbe0SRichard Henderson #define SFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_SFC_S) ? \
1795fa9f1f2SLaurent Vivier MMU_KERNEL_IDX : MMU_USER_IDX)
180a575cbe0SRichard Henderson #define DFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_DFC_S) ? \
1815fa9f1f2SLaurent Vivier MMU_KERNEL_IDX : MMU_USER_IDX)
182fcf5ef2aSThomas Huth #endif
183fcf5ef2aSThomas Huth
184fcf5ef2aSThomas Huth typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn);
185fcf5ef2aSThomas Huth
186fcf5ef2aSThomas Huth #ifdef DEBUG_DISPATCH
187fcf5ef2aSThomas Huth #define DISAS_INSN(name) \
188fcf5ef2aSThomas Huth static void real_disas_##name(CPUM68KState *env, DisasContext *s, \
189fcf5ef2aSThomas Huth uint16_t insn); \
190fcf5ef2aSThomas Huth static void disas_##name(CPUM68KState *env, DisasContext *s, \
191fcf5ef2aSThomas Huth uint16_t insn) \
192fcf5ef2aSThomas Huth { \
193fcf5ef2aSThomas Huth qemu_log("Dispatch " #name "\n"); \
194fcf5ef2aSThomas Huth real_disas_##name(env, s, insn); \
195fcf5ef2aSThomas Huth } \
196fcf5ef2aSThomas Huth static void real_disas_##name(CPUM68KState *env, DisasContext *s, \
197fcf5ef2aSThomas Huth uint16_t insn)
198fcf5ef2aSThomas Huth #else
199fcf5ef2aSThomas Huth #define DISAS_INSN(name) \
200fcf5ef2aSThomas Huth static void disas_##name(CPUM68KState *env, DisasContext *s, \
201fcf5ef2aSThomas Huth uint16_t insn)
202fcf5ef2aSThomas Huth #endif
203fcf5ef2aSThomas Huth
204fcf5ef2aSThomas Huth static const uint8_t cc_op_live[CC_OP_NB] = {
2057deddf96SLaurent Vivier [CC_OP_DYNAMIC] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
206fcf5ef2aSThomas Huth [CC_OP_FLAGS] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X,
207fcf5ef2aSThomas Huth [CC_OP_ADDB ... CC_OP_ADDL] = CCF_X | CCF_N | CCF_V,
208fcf5ef2aSThomas Huth [CC_OP_SUBB ... CC_OP_SUBL] = CCF_X | CCF_N | CCF_V,
209fcf5ef2aSThomas Huth [CC_OP_CMPB ... CC_OP_CMPL] = CCF_X | CCF_N | CCF_V,
210fcf5ef2aSThomas Huth [CC_OP_LOGIC] = CCF_X | CCF_N
211fcf5ef2aSThomas Huth };
212fcf5ef2aSThomas Huth
set_cc_op(DisasContext * s,CCOp op)213fcf5ef2aSThomas Huth static void set_cc_op(DisasContext *s, CCOp op)
214fcf5ef2aSThomas Huth {
215fcf5ef2aSThomas Huth CCOp old_op = s->cc_op;
216fcf5ef2aSThomas Huth int dead;
217fcf5ef2aSThomas Huth
218fcf5ef2aSThomas Huth if (old_op == op) {
219fcf5ef2aSThomas Huth return;
220fcf5ef2aSThomas Huth }
221fcf5ef2aSThomas Huth s->cc_op = op;
222fcf5ef2aSThomas Huth s->cc_op_synced = 0;
223fcf5ef2aSThomas Huth
224808d77bcSLucien Murray-Pitts /*
225808d77bcSLucien Murray-Pitts * Discard CC computation that will no longer be used.
226808d77bcSLucien Murray-Pitts * Note that X and N are never dead.
227808d77bcSLucien Murray-Pitts */
228fcf5ef2aSThomas Huth dead = cc_op_live[old_op] & ~cc_op_live[op];
229fcf5ef2aSThomas Huth if (dead & CCF_C) {
230fcf5ef2aSThomas Huth tcg_gen_discard_i32(QREG_CC_C);
231fcf5ef2aSThomas Huth }
232fcf5ef2aSThomas Huth if (dead & CCF_Z) {
233fcf5ef2aSThomas Huth tcg_gen_discard_i32(QREG_CC_Z);
234fcf5ef2aSThomas Huth }
235fcf5ef2aSThomas Huth if (dead & CCF_V) {
236fcf5ef2aSThomas Huth tcg_gen_discard_i32(QREG_CC_V);
237fcf5ef2aSThomas Huth }
238fcf5ef2aSThomas Huth }
239fcf5ef2aSThomas Huth
240fcf5ef2aSThomas Huth /* Update the CPU env CC_OP state. */
update_cc_op(DisasContext * s)241fcf5ef2aSThomas Huth static void update_cc_op(DisasContext *s)
242fcf5ef2aSThomas Huth {
243fcf5ef2aSThomas Huth if (!s->cc_op_synced) {
244fcf5ef2aSThomas Huth s->cc_op_synced = 1;
245fcf5ef2aSThomas Huth tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
246fcf5ef2aSThomas Huth }
247fcf5ef2aSThomas Huth }
248fcf5ef2aSThomas Huth
249f83311e4SLaurent Vivier /* Generate a jump to an immediate address. */
gen_jmp_im(DisasContext * s,uint32_t dest)250f83311e4SLaurent Vivier static void gen_jmp_im(DisasContext *s, uint32_t dest)
251f83311e4SLaurent Vivier {
252f83311e4SLaurent Vivier update_cc_op(s);
253f83311e4SLaurent Vivier tcg_gen_movi_i32(QREG_PC, dest);
254a575cbe0SRichard Henderson s->base.is_jmp = DISAS_JUMP;
255f83311e4SLaurent Vivier }
256f83311e4SLaurent Vivier
257f83311e4SLaurent Vivier /* Generate a jump to the address in qreg DEST. */
gen_jmp(DisasContext * s,TCGv dest)258f83311e4SLaurent Vivier static void gen_jmp(DisasContext *s, TCGv dest)
259f83311e4SLaurent Vivier {
260f83311e4SLaurent Vivier update_cc_op(s);
261f83311e4SLaurent Vivier tcg_gen_mov_i32(QREG_PC, dest);
262a575cbe0SRichard Henderson s->base.is_jmp = DISAS_JUMP;
263f83311e4SLaurent Vivier }
264f83311e4SLaurent Vivier
gen_raise_exception(int nr)265322f244aSLaurent Vivier static void gen_raise_exception(int nr)
266f83311e4SLaurent Vivier {
267ad75a51eSRichard Henderson gen_helper_raise_exception(tcg_env, tcg_constant_i32(nr));
268322f244aSLaurent Vivier }
269322f244aSLaurent Vivier
gen_raise_exception_format2(DisasContext * s,int nr,target_ulong this_pc)2708115fc93SRichard Henderson static void gen_raise_exception_format2(DisasContext *s, int nr,
2718115fc93SRichard Henderson target_ulong this_pc)
2728115fc93SRichard Henderson {
2738115fc93SRichard Henderson /*
2748115fc93SRichard Henderson * Pass the address of the insn to the exception handler,
2758115fc93SRichard Henderson * for recording in the Format $2 (6-word) stack frame.
2768115fc93SRichard Henderson * Re-use mmu.ar for the purpose, since that's only valid
2778115fc93SRichard Henderson * after tlb_fill.
2788115fc93SRichard Henderson */
279ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(this_pc), tcg_env,
2808115fc93SRichard Henderson offsetof(CPUM68KState, mmu.ar));
2818115fc93SRichard Henderson gen_raise_exception(nr);
2828115fc93SRichard Henderson s->base.is_jmp = DISAS_NORETURN;
2838115fc93SRichard Henderson }
2848115fc93SRichard Henderson
gen_exception(DisasContext * s,uint32_t dest,int nr)285322f244aSLaurent Vivier static void gen_exception(DisasContext *s, uint32_t dest, int nr)
286322f244aSLaurent Vivier {
287322f244aSLaurent Vivier update_cc_op(s);
288322f244aSLaurent Vivier tcg_gen_movi_i32(QREG_PC, dest);
289322f244aSLaurent Vivier
290322f244aSLaurent Vivier gen_raise_exception(nr);
291f83311e4SLaurent Vivier
292a575cbe0SRichard Henderson s->base.is_jmp = DISAS_NORETURN;
293f83311e4SLaurent Vivier }
294f83311e4SLaurent Vivier
gen_addr_fault(DisasContext * s)295f83311e4SLaurent Vivier static inline void gen_addr_fault(DisasContext *s)
296f83311e4SLaurent Vivier {
297a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ADDRESS);
298f83311e4SLaurent Vivier }
299f83311e4SLaurent Vivier
300808d77bcSLucien Murray-Pitts /*
301808d77bcSLucien Murray-Pitts * Generate a load from the specified address. Narrow values are
302808d77bcSLucien Murray-Pitts * sign extended to full register width.
303808d77bcSLucien Murray-Pitts */
gen_load(DisasContext * s,int opsize,TCGv addr,int sign,int index)30454e1e0b5SLaurent Vivier static inline TCGv gen_load(DisasContext *s, int opsize, TCGv addr,
30554e1e0b5SLaurent Vivier int sign, int index)
306fcf5ef2aSThomas Huth {
307b7a94da9SRichard Henderson TCGv tmp = tcg_temp_new_i32();
308b7a94da9SRichard Henderson
309fcf5ef2aSThomas Huth switch (opsize) {
310fcf5ef2aSThomas Huth case OS_BYTE:
311fcf5ef2aSThomas Huth case OS_WORD:
312fcf5ef2aSThomas Huth case OS_LONG:
313b7a94da9SRichard Henderson tcg_gen_qemu_ld_tl(tmp, addr, index,
314b7a94da9SRichard Henderson opsize | (sign ? MO_SIGN : 0) | MO_TE);
315fcf5ef2aSThomas Huth break;
316fcf5ef2aSThomas Huth default:
317fcf5ef2aSThomas Huth g_assert_not_reached();
318fcf5ef2aSThomas Huth }
319fcf5ef2aSThomas Huth return tmp;
320fcf5ef2aSThomas Huth }
321fcf5ef2aSThomas Huth
322fcf5ef2aSThomas Huth /* Generate a store. */
gen_store(DisasContext * s,int opsize,TCGv addr,TCGv val,int index)32354e1e0b5SLaurent Vivier static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val,
32454e1e0b5SLaurent Vivier int index)
325fcf5ef2aSThomas Huth {
326fcf5ef2aSThomas Huth switch (opsize) {
327fcf5ef2aSThomas Huth case OS_BYTE:
328fcf5ef2aSThomas Huth case OS_WORD:
329fcf5ef2aSThomas Huth case OS_LONG:
330b7a94da9SRichard Henderson tcg_gen_qemu_st_tl(val, addr, index, opsize | MO_TE);
331fcf5ef2aSThomas Huth break;
332fcf5ef2aSThomas Huth default:
333fcf5ef2aSThomas Huth g_assert_not_reached();
334fcf5ef2aSThomas Huth }
335fcf5ef2aSThomas Huth }
336fcf5ef2aSThomas Huth
337fcf5ef2aSThomas Huth typedef enum {
338fcf5ef2aSThomas Huth EA_STORE,
339fcf5ef2aSThomas Huth EA_LOADU,
340fcf5ef2aSThomas Huth EA_LOADS
341fcf5ef2aSThomas Huth } ea_what;
342fcf5ef2aSThomas Huth
343808d77bcSLucien Murray-Pitts /*
344808d77bcSLucien Murray-Pitts * Generate an unsigned load if VAL is 0 a signed load if val is -1,
345808d77bcSLucien Murray-Pitts * otherwise generate a store.
346808d77bcSLucien Murray-Pitts */
gen_ldst(DisasContext * s,int opsize,TCGv addr,TCGv val,ea_what what,int index)347fcf5ef2aSThomas Huth static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
34854e1e0b5SLaurent Vivier ea_what what, int index)
349fcf5ef2aSThomas Huth {
350fcf5ef2aSThomas Huth if (what == EA_STORE) {
35154e1e0b5SLaurent Vivier gen_store(s, opsize, addr, val, index);
352fcf5ef2aSThomas Huth return store_dummy;
353fcf5ef2aSThomas Huth } else {
35454dc8d2fSRichard Henderson return gen_load(s, opsize, addr, what == EA_LOADS, index);
355fcf5ef2aSThomas Huth }
356fcf5ef2aSThomas Huth }
357fcf5ef2aSThomas Huth
358fcf5ef2aSThomas Huth /* Read a 16-bit immediate constant */
read_im16(CPUM68KState * env,DisasContext * s)359fcf5ef2aSThomas Huth static inline uint16_t read_im16(CPUM68KState *env, DisasContext *s)
360fcf5ef2aSThomas Huth {
361fcf5ef2aSThomas Huth uint16_t im;
3624e116893SIlya Leoshkevich im = translator_lduw(env, &s->base, s->pc);
363fcf5ef2aSThomas Huth s->pc += 2;
364fcf5ef2aSThomas Huth return im;
365fcf5ef2aSThomas Huth }
366fcf5ef2aSThomas Huth
367fcf5ef2aSThomas Huth /* Read an 8-bit immediate constant */
read_im8(CPUM68KState * env,DisasContext * s)368fcf5ef2aSThomas Huth static inline uint8_t read_im8(CPUM68KState *env, DisasContext *s)
369fcf5ef2aSThomas Huth {
370fcf5ef2aSThomas Huth return read_im16(env, s);
371fcf5ef2aSThomas Huth }
372fcf5ef2aSThomas Huth
373fcf5ef2aSThomas Huth /* Read a 32-bit immediate constant. */
read_im32(CPUM68KState * env,DisasContext * s)374fcf5ef2aSThomas Huth static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s)
375fcf5ef2aSThomas Huth {
376fcf5ef2aSThomas Huth uint32_t im;
377fcf5ef2aSThomas Huth im = read_im16(env, s) << 16;
378fcf5ef2aSThomas Huth im |= 0xffff & read_im16(env, s);
379fcf5ef2aSThomas Huth return im;
380fcf5ef2aSThomas Huth }
381fcf5ef2aSThomas Huth
382f83311e4SLaurent Vivier /* Read a 64-bit immediate constant. */
read_im64(CPUM68KState * env,DisasContext * s)383f83311e4SLaurent Vivier static inline uint64_t read_im64(CPUM68KState *env, DisasContext *s)
384f83311e4SLaurent Vivier {
385f83311e4SLaurent Vivier uint64_t im;
386f83311e4SLaurent Vivier im = (uint64_t)read_im32(env, s) << 32;
387f83311e4SLaurent Vivier im |= (uint64_t)read_im32(env, s);
388f83311e4SLaurent Vivier return im;
389f83311e4SLaurent Vivier }
390f83311e4SLaurent Vivier
391fcf5ef2aSThomas Huth /* Calculate and address index. */
gen_addr_index(DisasContext * s,uint16_t ext,TCGv tmp)3928a1e52b6SRichard Henderson static TCGv gen_addr_index(DisasContext *s, uint16_t ext, TCGv tmp)
393fcf5ef2aSThomas Huth {
394fcf5ef2aSThomas Huth TCGv add;
395fcf5ef2aSThomas Huth int scale;
396fcf5ef2aSThomas Huth
397fcf5ef2aSThomas Huth add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
398fcf5ef2aSThomas Huth if ((ext & 0x800) == 0) {
399fcf5ef2aSThomas Huth tcg_gen_ext16s_i32(tmp, add);
400fcf5ef2aSThomas Huth add = tmp;
401fcf5ef2aSThomas Huth }
402fcf5ef2aSThomas Huth scale = (ext >> 9) & 3;
403fcf5ef2aSThomas Huth if (scale != 0) {
404fcf5ef2aSThomas Huth tcg_gen_shli_i32(tmp, add, scale);
405fcf5ef2aSThomas Huth add = tmp;
406fcf5ef2aSThomas Huth }
407fcf5ef2aSThomas Huth return add;
408fcf5ef2aSThomas Huth }
409fcf5ef2aSThomas Huth
410808d77bcSLucien Murray-Pitts /*
411ce00ff72Szhaolichang * Handle a base + index + displacement effective address.
412808d77bcSLucien Murray-Pitts * A NULL_QREG base means pc-relative.
413808d77bcSLucien Murray-Pitts */
gen_lea_indexed(CPUM68KState * env,DisasContext * s,TCGv base)414fcf5ef2aSThomas Huth static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base)
415fcf5ef2aSThomas Huth {
416fcf5ef2aSThomas Huth uint32_t offset;
417fcf5ef2aSThomas Huth uint16_t ext;
418fcf5ef2aSThomas Huth TCGv add;
419fcf5ef2aSThomas Huth TCGv tmp;
420fcf5ef2aSThomas Huth uint32_t bd, od;
421fcf5ef2aSThomas Huth
422fcf5ef2aSThomas Huth offset = s->pc;
423fcf5ef2aSThomas Huth ext = read_im16(env, s);
424fcf5ef2aSThomas Huth
425fcf5ef2aSThomas Huth if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
426fcf5ef2aSThomas Huth return NULL_QREG;
427fcf5ef2aSThomas Huth
428aece90d8SMark Cave-Ayland if (m68k_feature(s->env, M68K_FEATURE_M68K) &&
429fcf5ef2aSThomas Huth !m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX)) {
430fcf5ef2aSThomas Huth ext &= ~(3 << 9);
431fcf5ef2aSThomas Huth }
432fcf5ef2aSThomas Huth
433fcf5ef2aSThomas Huth if (ext & 0x100) {
434fcf5ef2aSThomas Huth /* full extension word format */
435fcf5ef2aSThomas Huth if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
436fcf5ef2aSThomas Huth return NULL_QREG;
437fcf5ef2aSThomas Huth
438fcf5ef2aSThomas Huth if ((ext & 0x30) > 0x10) {
439fcf5ef2aSThomas Huth /* base displacement */
440fcf5ef2aSThomas Huth if ((ext & 0x30) == 0x20) {
441fcf5ef2aSThomas Huth bd = (int16_t)read_im16(env, s);
442fcf5ef2aSThomas Huth } else {
443fcf5ef2aSThomas Huth bd = read_im32(env, s);
444fcf5ef2aSThomas Huth }
445fcf5ef2aSThomas Huth } else {
446fcf5ef2aSThomas Huth bd = 0;
447fcf5ef2aSThomas Huth }
44854dc8d2fSRichard Henderson tmp = tcg_temp_new();
449fcf5ef2aSThomas Huth if ((ext & 0x44) == 0) {
450fcf5ef2aSThomas Huth /* pre-index */
4518a1e52b6SRichard Henderson add = gen_addr_index(s, ext, tmp);
452fcf5ef2aSThomas Huth } else {
453fcf5ef2aSThomas Huth add = NULL_QREG;
454fcf5ef2aSThomas Huth }
455fcf5ef2aSThomas Huth if ((ext & 0x80) == 0) {
456fcf5ef2aSThomas Huth /* base not suppressed */
457fcf5ef2aSThomas Huth if (IS_NULL_QREG(base)) {
4581852ce5aSRichard Henderson base = tcg_constant_i32(offset + bd);
459fcf5ef2aSThomas Huth bd = 0;
460fcf5ef2aSThomas Huth }
461fcf5ef2aSThomas Huth if (!IS_NULL_QREG(add)) {
462fcf5ef2aSThomas Huth tcg_gen_add_i32(tmp, add, base);
463fcf5ef2aSThomas Huth add = tmp;
464fcf5ef2aSThomas Huth } else {
465fcf5ef2aSThomas Huth add = base;
466fcf5ef2aSThomas Huth }
467fcf5ef2aSThomas Huth }
468fcf5ef2aSThomas Huth if (!IS_NULL_QREG(add)) {
469fcf5ef2aSThomas Huth if (bd != 0) {
470fcf5ef2aSThomas Huth tcg_gen_addi_i32(tmp, add, bd);
471fcf5ef2aSThomas Huth add = tmp;
472fcf5ef2aSThomas Huth }
473fcf5ef2aSThomas Huth } else {
4741852ce5aSRichard Henderson add = tcg_constant_i32(bd);
475fcf5ef2aSThomas Huth }
476fcf5ef2aSThomas Huth if ((ext & 3) != 0) {
477fcf5ef2aSThomas Huth /* memory indirect */
47854dc8d2fSRichard Henderson base = gen_load(s, OS_LONG, add, 0, IS_USER(s));
479fcf5ef2aSThomas Huth if ((ext & 0x44) == 4) {
4808a1e52b6SRichard Henderson add = gen_addr_index(s, ext, tmp);
481fcf5ef2aSThomas Huth tcg_gen_add_i32(tmp, add, base);
482fcf5ef2aSThomas Huth add = tmp;
483fcf5ef2aSThomas Huth } else {
484fcf5ef2aSThomas Huth add = base;
485fcf5ef2aSThomas Huth }
486fcf5ef2aSThomas Huth if ((ext & 3) > 1) {
487fcf5ef2aSThomas Huth /* outer displacement */
488fcf5ef2aSThomas Huth if ((ext & 3) == 2) {
489fcf5ef2aSThomas Huth od = (int16_t)read_im16(env, s);
490fcf5ef2aSThomas Huth } else {
491fcf5ef2aSThomas Huth od = read_im32(env, s);
492fcf5ef2aSThomas Huth }
493fcf5ef2aSThomas Huth } else {
494fcf5ef2aSThomas Huth od = 0;
495fcf5ef2aSThomas Huth }
496fcf5ef2aSThomas Huth if (od != 0) {
497fcf5ef2aSThomas Huth tcg_gen_addi_i32(tmp, add, od);
498fcf5ef2aSThomas Huth add = tmp;
499fcf5ef2aSThomas Huth }
500fcf5ef2aSThomas Huth }
501fcf5ef2aSThomas Huth } else {
502fcf5ef2aSThomas Huth /* brief extension word format */
50354dc8d2fSRichard Henderson tmp = tcg_temp_new();
5048a1e52b6SRichard Henderson add = gen_addr_index(s, ext, tmp);
505fcf5ef2aSThomas Huth if (!IS_NULL_QREG(base)) {
506fcf5ef2aSThomas Huth tcg_gen_add_i32(tmp, add, base);
507fcf5ef2aSThomas Huth if ((int8_t)ext)
508fcf5ef2aSThomas Huth tcg_gen_addi_i32(tmp, tmp, (int8_t)ext);
509fcf5ef2aSThomas Huth } else {
510fcf5ef2aSThomas Huth tcg_gen_addi_i32(tmp, add, offset + (int8_t)ext);
511fcf5ef2aSThomas Huth }
512fcf5ef2aSThomas Huth add = tmp;
513fcf5ef2aSThomas Huth }
514fcf5ef2aSThomas Huth return add;
515fcf5ef2aSThomas Huth }
516fcf5ef2aSThomas Huth
517fcf5ef2aSThomas Huth /* Sign or zero extend a value. */
518fcf5ef2aSThomas Huth
gen_ext(TCGv res,TCGv val,int opsize,int sign)519fcf5ef2aSThomas Huth static inline void gen_ext(TCGv res, TCGv val, int opsize, int sign)
520fcf5ef2aSThomas Huth {
521fcf5ef2aSThomas Huth switch (opsize) {
522fcf5ef2aSThomas Huth case OS_BYTE:
523fcf5ef2aSThomas Huth case OS_WORD:
524fcf5ef2aSThomas Huth case OS_LONG:
525*443025e4SRichard Henderson tcg_gen_ext_i32(res, val, opsize | (sign ? MO_SIGN : 0));
526fcf5ef2aSThomas Huth break;
527fcf5ef2aSThomas Huth default:
528fcf5ef2aSThomas Huth g_assert_not_reached();
529fcf5ef2aSThomas Huth }
530fcf5ef2aSThomas Huth }
531fcf5ef2aSThomas Huth
532fcf5ef2aSThomas Huth /* Evaluate all the CC flags. */
533fcf5ef2aSThomas Huth
gen_flush_flags(DisasContext * s)534fcf5ef2aSThomas Huth static void gen_flush_flags(DisasContext *s)
535fcf5ef2aSThomas Huth {
536fcf5ef2aSThomas Huth TCGv t0, t1;
537fcf5ef2aSThomas Huth
538fcf5ef2aSThomas Huth switch (s->cc_op) {
539fcf5ef2aSThomas Huth case CC_OP_FLAGS:
540fcf5ef2aSThomas Huth return;
541fcf5ef2aSThomas Huth
542fcf5ef2aSThomas Huth case CC_OP_ADDB:
543fcf5ef2aSThomas Huth case CC_OP_ADDW:
544fcf5ef2aSThomas Huth case CC_OP_ADDL:
545fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
546fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
547fcf5ef2aSThomas Huth /* Compute signed overflow for addition. */
548fcf5ef2aSThomas Huth t0 = tcg_temp_new();
549fcf5ef2aSThomas Huth t1 = tcg_temp_new();
550fcf5ef2aSThomas Huth tcg_gen_sub_i32(t0, QREG_CC_N, QREG_CC_V);
551fcf5ef2aSThomas Huth gen_ext(t0, t0, s->cc_op - CC_OP_ADDB, 1);
552fcf5ef2aSThomas Huth tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V);
553fcf5ef2aSThomas Huth tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
554fcf5ef2aSThomas Huth tcg_gen_andc_i32(QREG_CC_V, t1, QREG_CC_V);
555fcf5ef2aSThomas Huth break;
556fcf5ef2aSThomas Huth
557fcf5ef2aSThomas Huth case CC_OP_SUBB:
558fcf5ef2aSThomas Huth case CC_OP_SUBW:
559fcf5ef2aSThomas Huth case CC_OP_SUBL:
560fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
561fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
562fcf5ef2aSThomas Huth /* Compute signed overflow for subtraction. */
563fcf5ef2aSThomas Huth t0 = tcg_temp_new();
564fcf5ef2aSThomas Huth t1 = tcg_temp_new();
565fcf5ef2aSThomas Huth tcg_gen_add_i32(t0, QREG_CC_N, QREG_CC_V);
566fcf5ef2aSThomas Huth gen_ext(t0, t0, s->cc_op - CC_OP_SUBB, 1);
567043b936eSLaurent Vivier tcg_gen_xor_i32(t1, QREG_CC_N, t0);
568fcf5ef2aSThomas Huth tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
569fcf5ef2aSThomas Huth tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t1);
570fcf5ef2aSThomas Huth break;
571fcf5ef2aSThomas Huth
572fcf5ef2aSThomas Huth case CC_OP_CMPB:
573fcf5ef2aSThomas Huth case CC_OP_CMPW:
574fcf5ef2aSThomas Huth case CC_OP_CMPL:
575fcf5ef2aSThomas Huth tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_C, QREG_CC_N, QREG_CC_V);
576fcf5ef2aSThomas Huth tcg_gen_sub_i32(QREG_CC_Z, QREG_CC_N, QREG_CC_V);
577fcf5ef2aSThomas Huth gen_ext(QREG_CC_Z, QREG_CC_Z, s->cc_op - CC_OP_CMPB, 1);
578fcf5ef2aSThomas Huth /* Compute signed overflow for subtraction. */
579fcf5ef2aSThomas Huth t0 = tcg_temp_new();
580fcf5ef2aSThomas Huth tcg_gen_xor_i32(t0, QREG_CC_Z, QREG_CC_N);
581fcf5ef2aSThomas Huth tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, QREG_CC_N);
582fcf5ef2aSThomas Huth tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t0);
583fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_N, QREG_CC_Z);
584fcf5ef2aSThomas Huth break;
585fcf5ef2aSThomas Huth
586fcf5ef2aSThomas Huth case CC_OP_LOGIC:
587fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
588fcf5ef2aSThomas Huth tcg_gen_movi_i32(QREG_CC_C, 0);
589fcf5ef2aSThomas Huth tcg_gen_movi_i32(QREG_CC_V, 0);
590fcf5ef2aSThomas Huth break;
591fcf5ef2aSThomas Huth
592fcf5ef2aSThomas Huth case CC_OP_DYNAMIC:
593ad75a51eSRichard Henderson gen_helper_flush_flags(tcg_env, QREG_CC_OP);
594695576dbSLaurent Vivier s->cc_op_synced = 1;
595fcf5ef2aSThomas Huth break;
596fcf5ef2aSThomas Huth
597fcf5ef2aSThomas Huth default:
598ad75a51eSRichard Henderson gen_helper_flush_flags(tcg_env, tcg_constant_i32(s->cc_op));
599695576dbSLaurent Vivier s->cc_op_synced = 1;
600fcf5ef2aSThomas Huth break;
601fcf5ef2aSThomas Huth }
602fcf5ef2aSThomas Huth
603fcf5ef2aSThomas Huth /* Note that flush_flags also assigned to env->cc_op. */
604fcf5ef2aSThomas Huth s->cc_op = CC_OP_FLAGS;
605fcf5ef2aSThomas Huth }
606fcf5ef2aSThomas Huth
gen_extend(DisasContext * s,TCGv val,int opsize,int sign)6073f215a14SLaurent Vivier static inline TCGv gen_extend(DisasContext *s, TCGv val, int opsize, int sign)
608fcf5ef2aSThomas Huth {
609fcf5ef2aSThomas Huth TCGv tmp;
610fcf5ef2aSThomas Huth
611fcf5ef2aSThomas Huth if (opsize == OS_LONG) {
612fcf5ef2aSThomas Huth tmp = val;
613fcf5ef2aSThomas Huth } else {
61454dc8d2fSRichard Henderson tmp = tcg_temp_new();
615fcf5ef2aSThomas Huth gen_ext(tmp, val, opsize, sign);
616fcf5ef2aSThomas Huth }
617fcf5ef2aSThomas Huth
618fcf5ef2aSThomas Huth return tmp;
619fcf5ef2aSThomas Huth }
620fcf5ef2aSThomas Huth
gen_logic_cc(DisasContext * s,TCGv val,int opsize)621fcf5ef2aSThomas Huth static void gen_logic_cc(DisasContext *s, TCGv val, int opsize)
622fcf5ef2aSThomas Huth {
623fcf5ef2aSThomas Huth gen_ext(QREG_CC_N, val, opsize, 1);
624fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_LOGIC);
625fcf5ef2aSThomas Huth }
626fcf5ef2aSThomas Huth
gen_update_cc_cmp(DisasContext * s,TCGv dest,TCGv src,int opsize)627fcf5ef2aSThomas Huth static void gen_update_cc_cmp(DisasContext *s, TCGv dest, TCGv src, int opsize)
628fcf5ef2aSThomas Huth {
629fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_N, dest);
630fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_V, src);
631fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_CMPB + opsize);
632fcf5ef2aSThomas Huth }
633fcf5ef2aSThomas Huth
gen_update_cc_add(TCGv dest,TCGv src,int opsize)634fcf5ef2aSThomas Huth static void gen_update_cc_add(TCGv dest, TCGv src, int opsize)
635fcf5ef2aSThomas Huth {
636fcf5ef2aSThomas Huth gen_ext(QREG_CC_N, dest, opsize, 1);
637fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_V, src);
638fcf5ef2aSThomas Huth }
639fcf5ef2aSThomas Huth
opsize_bytes(int opsize)640fcf5ef2aSThomas Huth static inline int opsize_bytes(int opsize)
641fcf5ef2aSThomas Huth {
642fcf5ef2aSThomas Huth switch (opsize) {
643fcf5ef2aSThomas Huth case OS_BYTE: return 1;
644fcf5ef2aSThomas Huth case OS_WORD: return 2;
645fcf5ef2aSThomas Huth case OS_LONG: return 4;
646fcf5ef2aSThomas Huth case OS_SINGLE: return 4;
647fcf5ef2aSThomas Huth case OS_DOUBLE: return 8;
648fcf5ef2aSThomas Huth case OS_EXTENDED: return 12;
649fcf5ef2aSThomas Huth case OS_PACKED: return 12;
650fcf5ef2aSThomas Huth default:
651fcf5ef2aSThomas Huth g_assert_not_reached();
652fcf5ef2aSThomas Huth }
653fcf5ef2aSThomas Huth }
654fcf5ef2aSThomas Huth
insn_opsize(int insn)655fcf5ef2aSThomas Huth static inline int insn_opsize(int insn)
656fcf5ef2aSThomas Huth {
657fcf5ef2aSThomas Huth switch ((insn >> 6) & 3) {
658fcf5ef2aSThomas Huth case 0: return OS_BYTE;
659fcf5ef2aSThomas Huth case 1: return OS_WORD;
660fcf5ef2aSThomas Huth case 2: return OS_LONG;
661fcf5ef2aSThomas Huth default:
662fcf5ef2aSThomas Huth g_assert_not_reached();
663fcf5ef2aSThomas Huth }
664fcf5ef2aSThomas Huth }
665fcf5ef2aSThomas Huth
ext_opsize(int ext,int pos)66669e69822SLaurent Vivier static inline int ext_opsize(int ext, int pos)
66769e69822SLaurent Vivier {
66869e69822SLaurent Vivier switch ((ext >> pos) & 7) {
66969e69822SLaurent Vivier case 0: return OS_LONG;
67069e69822SLaurent Vivier case 1: return OS_SINGLE;
67169e69822SLaurent Vivier case 2: return OS_EXTENDED;
67269e69822SLaurent Vivier case 3: return OS_PACKED;
67369e69822SLaurent Vivier case 4: return OS_WORD;
67469e69822SLaurent Vivier case 5: return OS_DOUBLE;
67569e69822SLaurent Vivier case 6: return OS_BYTE;
67669e69822SLaurent Vivier default:
67769e69822SLaurent Vivier g_assert_not_reached();
67869e69822SLaurent Vivier }
67969e69822SLaurent Vivier }
68069e69822SLaurent Vivier
681808d77bcSLucien Murray-Pitts /*
682808d77bcSLucien Murray-Pitts * Assign value to a register. If the width is less than the register width
683808d77bcSLucien Murray-Pitts * only the low part of the register is set.
684808d77bcSLucien Murray-Pitts */
gen_partset_reg(int opsize,TCGv reg,TCGv val)685fcf5ef2aSThomas Huth static void gen_partset_reg(int opsize, TCGv reg, TCGv val)
686fcf5ef2aSThomas Huth {
687fcf5ef2aSThomas Huth switch (opsize) {
688fcf5ef2aSThomas Huth case OS_BYTE:
68964919f71SRichard Henderson tcg_gen_deposit_i32(reg, reg, val, 0, 8);
690fcf5ef2aSThomas Huth break;
691fcf5ef2aSThomas Huth case OS_WORD:
69264919f71SRichard Henderson tcg_gen_deposit_i32(reg, reg, val, 0, 16);
693fcf5ef2aSThomas Huth break;
694fcf5ef2aSThomas Huth case OS_LONG:
695fcf5ef2aSThomas Huth case OS_SINGLE:
696fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, val);
697fcf5ef2aSThomas Huth break;
698fcf5ef2aSThomas Huth default:
699fcf5ef2aSThomas Huth g_assert_not_reached();
700fcf5ef2aSThomas Huth }
701fcf5ef2aSThomas Huth }
702fcf5ef2aSThomas Huth
703808d77bcSLucien Murray-Pitts /*
704808d77bcSLucien Murray-Pitts * Generate code for an "effective address". Does not adjust the base
705808d77bcSLucien Murray-Pitts * register for autoincrement addressing modes.
706808d77bcSLucien Murray-Pitts */
gen_lea_mode(CPUM68KState * env,DisasContext * s,int mode,int reg0,int opsize)707f84aab26SRichard Henderson static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
708f84aab26SRichard Henderson int mode, int reg0, int opsize)
709fcf5ef2aSThomas Huth {
710fcf5ef2aSThomas Huth TCGv reg;
711fcf5ef2aSThomas Huth TCGv tmp;
712fcf5ef2aSThomas Huth uint16_t ext;
713fcf5ef2aSThomas Huth uint32_t offset;
714fcf5ef2aSThomas Huth
715f84aab26SRichard Henderson switch (mode) {
716fcf5ef2aSThomas Huth case 0: /* Data register direct. */
717fcf5ef2aSThomas Huth case 1: /* Address register direct. */
718fcf5ef2aSThomas Huth return NULL_QREG;
719fcf5ef2aSThomas Huth case 3: /* Indirect postincrement. */
720f2224f2cSRichard Henderson if (opsize == OS_UNSIZED) {
721f2224f2cSRichard Henderson return NULL_QREG;
722f2224f2cSRichard Henderson }
723f2224f2cSRichard Henderson /* fallthru */
724f2224f2cSRichard Henderson case 2: /* Indirect register */
725f84aab26SRichard Henderson return get_areg(s, reg0);
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);
7521852ce5aSRichard Henderson return tcg_constant_i32(offset);
753fcf5ef2aSThomas Huth case 1: /* Absolute long. */
754fcf5ef2aSThomas Huth offset = read_im32(env, s);
7551852ce5aSRichard Henderson return tcg_constant_i32(offset);
756fcf5ef2aSThomas Huth case 2: /* pc displacement */
757fcf5ef2aSThomas Huth offset = s->pc;
758fcf5ef2aSThomas Huth offset += (int16_t)read_im16(env, s);
7591852ce5aSRichard Henderson return tcg_constant_i32(offset);
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 }
766fcf5ef2aSThomas Huth }
767fcf5ef2aSThomas Huth /* Should never happen. */
768fcf5ef2aSThomas Huth return NULL_QREG;
769fcf5ef2aSThomas Huth }
770fcf5ef2aSThomas Huth
gen_lea(CPUM68KState * env,DisasContext * s,uint16_t insn,int opsize)771f84aab26SRichard Henderson static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn,
772f84aab26SRichard Henderson int opsize)
773fcf5ef2aSThomas Huth {
774f84aab26SRichard Henderson int mode = extract32(insn, 3, 3);
775f84aab26SRichard Henderson int reg0 = REG(insn, 0);
776f84aab26SRichard Henderson return gen_lea_mode(env, s, mode, reg0, opsize);
777fcf5ef2aSThomas Huth }
778fcf5ef2aSThomas Huth
779808d77bcSLucien Murray-Pitts /*
780808d77bcSLucien Murray-Pitts * Generate code to load/store a value from/into an EA. If WHAT > 0 this is
781808d77bcSLucien Murray-Pitts * a write otherwise it is a read (0 == sign extend, -1 == zero extend).
782808d77bcSLucien Murray-Pitts * ADDRP is non-null for readwrite operands.
783808d77bcSLucien Murray-Pitts */
gen_ea_mode(CPUM68KState * env,DisasContext * s,int mode,int reg0,int opsize,TCGv val,TCGv * addrp,ea_what what,int index)784f84aab26SRichard Henderson static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0,
78554e1e0b5SLaurent Vivier int opsize, TCGv val, TCGv *addrp, ea_what what,
78654e1e0b5SLaurent Vivier int index)
787fcf5ef2aSThomas Huth {
788f84aab26SRichard Henderson TCGv reg, tmp, result;
789f84aab26SRichard Henderson int32_t offset;
790fcf5ef2aSThomas Huth
791f84aab26SRichard Henderson switch (mode) {
792fcf5ef2aSThomas Huth case 0: /* Data register direct. */
793f84aab26SRichard Henderson reg = cpu_dregs[reg0];
794fcf5ef2aSThomas Huth if (what == EA_STORE) {
795fcf5ef2aSThomas Huth gen_partset_reg(opsize, reg, val);
796fcf5ef2aSThomas Huth return store_dummy;
797fcf5ef2aSThomas Huth } else {
7983f215a14SLaurent Vivier return gen_extend(s, reg, opsize, what == EA_LOADS);
799fcf5ef2aSThomas Huth }
800fcf5ef2aSThomas Huth case 1: /* Address register direct. */
801f84aab26SRichard Henderson reg = get_areg(s, reg0);
802fcf5ef2aSThomas Huth if (what == EA_STORE) {
803fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, val);
804fcf5ef2aSThomas Huth return store_dummy;
805fcf5ef2aSThomas Huth } else {
8063f215a14SLaurent Vivier return gen_extend(s, reg, opsize, what == EA_LOADS);
807fcf5ef2aSThomas Huth }
808fcf5ef2aSThomas Huth case 2: /* Indirect register */
809f84aab26SRichard Henderson reg = get_areg(s, reg0);
81054e1e0b5SLaurent Vivier return gen_ldst(s, opsize, reg, val, what, index);
811fcf5ef2aSThomas Huth case 3: /* Indirect postincrement. */
812f84aab26SRichard Henderson reg = get_areg(s, reg0);
81354e1e0b5SLaurent Vivier result = gen_ldst(s, opsize, reg, val, what, index);
8148a1e52b6SRichard Henderson if (what == EA_STORE || !addrp) {
815574d5725SPhilippe Mathieu-Daudé tmp = tcg_temp_new();
816727d937bSLaurent Vivier if (reg0 == 7 && opsize == OS_BYTE &&
817aece90d8SMark Cave-Ayland m68k_feature(s->env, M68K_FEATURE_M68K)) {
818727d937bSLaurent Vivier tcg_gen_addi_i32(tmp, reg, 2);
819727d937bSLaurent Vivier } else {
8208a1e52b6SRichard Henderson tcg_gen_addi_i32(tmp, reg, opsize_bytes(opsize));
821727d937bSLaurent Vivier }
822f84aab26SRichard Henderson delay_set_areg(s, reg0, tmp, true);
8238a1e52b6SRichard Henderson }
824fcf5ef2aSThomas Huth return result;
825fcf5ef2aSThomas Huth case 4: /* Indirect predecrememnt. */
826fcf5ef2aSThomas Huth if (addrp && what == EA_STORE) {
827fcf5ef2aSThomas Huth tmp = *addrp;
828fcf5ef2aSThomas Huth } else {
829f84aab26SRichard Henderson tmp = gen_lea_mode(env, s, mode, reg0, opsize);
830f84aab26SRichard Henderson if (IS_NULL_QREG(tmp)) {
831fcf5ef2aSThomas Huth return tmp;
832f84aab26SRichard Henderson }
833f84aab26SRichard Henderson if (addrp) {
834fcf5ef2aSThomas Huth *addrp = tmp;
835fcf5ef2aSThomas Huth }
836f84aab26SRichard Henderson }
83754e1e0b5SLaurent Vivier result = gen_ldst(s, opsize, tmp, val, what, index);
838fcf5ef2aSThomas Huth if (what == EA_STORE || !addrp) {
839f84aab26SRichard Henderson delay_set_areg(s, reg0, tmp, false);
840fcf5ef2aSThomas Huth }
841fcf5ef2aSThomas Huth return result;
842fcf5ef2aSThomas Huth case 5: /* Indirect displacement. */
843fcf5ef2aSThomas Huth case 6: /* Indirect index + displacement. */
844f84aab26SRichard Henderson do_indirect:
845f84aab26SRichard Henderson if (addrp && what == EA_STORE) {
846f84aab26SRichard Henderson tmp = *addrp;
847f84aab26SRichard Henderson } else {
848f84aab26SRichard Henderson tmp = gen_lea_mode(env, s, mode, reg0, opsize);
849f84aab26SRichard Henderson if (IS_NULL_QREG(tmp)) {
850f84aab26SRichard Henderson return tmp;
851f84aab26SRichard Henderson }
852f84aab26SRichard Henderson if (addrp) {
853f84aab26SRichard Henderson *addrp = tmp;
854f84aab26SRichard Henderson }
855f84aab26SRichard Henderson }
85654e1e0b5SLaurent Vivier return gen_ldst(s, opsize, tmp, val, what, index);
857fcf5ef2aSThomas Huth case 7: /* Other */
858f84aab26SRichard Henderson switch (reg0) {
859fcf5ef2aSThomas Huth case 0: /* Absolute short. */
860fcf5ef2aSThomas Huth case 1: /* Absolute long. */
861fcf5ef2aSThomas Huth case 2: /* pc displacement */
862fcf5ef2aSThomas Huth case 3: /* pc index+displacement. */
863f84aab26SRichard Henderson goto do_indirect;
864fcf5ef2aSThomas Huth case 4: /* Immediate. */
865fcf5ef2aSThomas Huth /* Sign extend values for consistency. */
866fcf5ef2aSThomas Huth switch (opsize) {
867fcf5ef2aSThomas Huth case OS_BYTE:
868fcf5ef2aSThomas Huth if (what == EA_LOADS) {
869fcf5ef2aSThomas Huth offset = (int8_t)read_im8(env, s);
870fcf5ef2aSThomas Huth } else {
871fcf5ef2aSThomas Huth offset = read_im8(env, s);
872fcf5ef2aSThomas Huth }
873fcf5ef2aSThomas Huth break;
874fcf5ef2aSThomas Huth case OS_WORD:
875fcf5ef2aSThomas Huth if (what == EA_LOADS) {
876fcf5ef2aSThomas Huth offset = (int16_t)read_im16(env, s);
877fcf5ef2aSThomas Huth } else {
878fcf5ef2aSThomas Huth offset = read_im16(env, s);
879fcf5ef2aSThomas Huth }
880fcf5ef2aSThomas Huth break;
881fcf5ef2aSThomas Huth case OS_LONG:
882fcf5ef2aSThomas Huth offset = read_im32(env, s);
883fcf5ef2aSThomas Huth break;
884fcf5ef2aSThomas Huth default:
885fcf5ef2aSThomas Huth g_assert_not_reached();
886fcf5ef2aSThomas Huth }
887999b7c26SRichard Henderson return tcg_constant_i32(offset);
888fcf5ef2aSThomas Huth default:
889fcf5ef2aSThomas Huth return NULL_QREG;
890fcf5ef2aSThomas Huth }
891fcf5ef2aSThomas Huth }
892fcf5ef2aSThomas Huth /* Should never happen. */
893fcf5ef2aSThomas Huth return NULL_QREG;
894fcf5ef2aSThomas Huth }
895fcf5ef2aSThomas Huth
gen_ea(CPUM68KState * env,DisasContext * s,uint16_t insn,int opsize,TCGv val,TCGv * addrp,ea_what what,int index)896f84aab26SRichard Henderson static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn,
89754e1e0b5SLaurent Vivier int opsize, TCGv val, TCGv *addrp, ea_what what, int index)
898f84aab26SRichard Henderson {
899f84aab26SRichard Henderson int mode = extract32(insn, 3, 3);
900f84aab26SRichard Henderson int reg0 = REG(insn, 0);
90154e1e0b5SLaurent Vivier return gen_ea_mode(env, s, mode, reg0, opsize, val, addrp, what, index);
902f84aab26SRichard Henderson }
903f84aab26SRichard Henderson
gen_fp_ptr(int freg)904f83311e4SLaurent Vivier static TCGv_ptr gen_fp_ptr(int freg)
905f83311e4SLaurent Vivier {
906f83311e4SLaurent Vivier TCGv_ptr fp = tcg_temp_new_ptr();
907ad75a51eSRichard Henderson tcg_gen_addi_ptr(fp, tcg_env, offsetof(CPUM68KState, fregs[freg]));
908f83311e4SLaurent Vivier return fp;
909f83311e4SLaurent Vivier }
910f83311e4SLaurent Vivier
gen_fp_result_ptr(void)911f83311e4SLaurent Vivier static TCGv_ptr gen_fp_result_ptr(void)
912f83311e4SLaurent Vivier {
913f83311e4SLaurent Vivier TCGv_ptr fp = tcg_temp_new_ptr();
914ad75a51eSRichard Henderson tcg_gen_addi_ptr(fp, tcg_env, offsetof(CPUM68KState, fp_result));
915f83311e4SLaurent Vivier return fp;
916f83311e4SLaurent Vivier }
917f83311e4SLaurent Vivier
gen_fp_move(TCGv_ptr dest,TCGv_ptr src)918f83311e4SLaurent Vivier static void gen_fp_move(TCGv_ptr dest, TCGv_ptr src)
919f83311e4SLaurent Vivier {
920f83311e4SLaurent Vivier TCGv t32;
921f83311e4SLaurent Vivier TCGv_i64 t64;
922f83311e4SLaurent Vivier
923f83311e4SLaurent Vivier t32 = tcg_temp_new();
924f83311e4SLaurent Vivier tcg_gen_ld16u_i32(t32, src, offsetof(FPReg, l.upper));
925f83311e4SLaurent Vivier tcg_gen_st16_i32(t32, dest, offsetof(FPReg, l.upper));
926f83311e4SLaurent Vivier
927f83311e4SLaurent Vivier t64 = tcg_temp_new_i64();
928f83311e4SLaurent Vivier tcg_gen_ld_i64(t64, src, offsetof(FPReg, l.lower));
929f83311e4SLaurent Vivier tcg_gen_st_i64(t64, dest, offsetof(FPReg, l.lower));
930f83311e4SLaurent Vivier }
931f83311e4SLaurent Vivier
gen_load_fp(DisasContext * s,int opsize,TCGv addr,TCGv_ptr fp,int index)93254e1e0b5SLaurent Vivier static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
93354e1e0b5SLaurent Vivier int index)
934f83311e4SLaurent Vivier {
935f83311e4SLaurent Vivier TCGv tmp;
936f83311e4SLaurent Vivier TCGv_i64 t64;
937f83311e4SLaurent Vivier
938f83311e4SLaurent Vivier t64 = tcg_temp_new_i64();
939f83311e4SLaurent Vivier tmp = tcg_temp_new();
940f83311e4SLaurent Vivier switch (opsize) {
941f83311e4SLaurent Vivier case OS_BYTE:
942f83311e4SLaurent Vivier case OS_WORD:
943a0f06a62SRichard Henderson case OS_LONG:
944b7a94da9SRichard Henderson tcg_gen_qemu_ld_tl(tmp, addr, index, opsize | MO_SIGN | MO_TE);
945ad75a51eSRichard Henderson gen_helper_exts32(tcg_env, fp, tmp);
946f83311e4SLaurent Vivier break;
947f83311e4SLaurent Vivier case OS_SINGLE:
948b7a94da9SRichard Henderson tcg_gen_qemu_ld_tl(tmp, addr, index, MO_TEUL);
949ad75a51eSRichard Henderson gen_helper_extf32(tcg_env, fp, tmp);
950f83311e4SLaurent Vivier break;
951f83311e4SLaurent Vivier case OS_DOUBLE:
952b7a94da9SRichard Henderson tcg_gen_qemu_ld_i64(t64, addr, index, MO_TEUQ);
953ad75a51eSRichard Henderson gen_helper_extf64(tcg_env, fp, t64);
954f83311e4SLaurent Vivier break;
955f83311e4SLaurent Vivier case OS_EXTENDED:
956f83311e4SLaurent Vivier if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
957a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
958f83311e4SLaurent Vivier break;
959f83311e4SLaurent Vivier }
960b7a94da9SRichard Henderson tcg_gen_qemu_ld_i32(tmp, addr, index, MO_TEUL);
961f83311e4SLaurent Vivier tcg_gen_shri_i32(tmp, tmp, 16);
962f83311e4SLaurent Vivier tcg_gen_st16_i32(tmp, fp, offsetof(FPReg, l.upper));
963f83311e4SLaurent Vivier tcg_gen_addi_i32(tmp, addr, 4);
964b7a94da9SRichard Henderson tcg_gen_qemu_ld_i64(t64, tmp, index, MO_TEUQ);
965f83311e4SLaurent Vivier tcg_gen_st_i64(t64, fp, offsetof(FPReg, l.lower));
966f83311e4SLaurent Vivier break;
967f83311e4SLaurent Vivier case OS_PACKED:
968808d77bcSLucien Murray-Pitts /*
969808d77bcSLucien Murray-Pitts * unimplemented data type on 68040/ColdFire
970f83311e4SLaurent Vivier * FIXME if needed for another FPU
971f83311e4SLaurent Vivier */
972a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
973f83311e4SLaurent Vivier break;
974f83311e4SLaurent Vivier default:
975f83311e4SLaurent Vivier g_assert_not_reached();
976f83311e4SLaurent Vivier }
977f83311e4SLaurent Vivier }
978f83311e4SLaurent Vivier
gen_store_fp(DisasContext * s,int opsize,TCGv addr,TCGv_ptr fp,int index)97954e1e0b5SLaurent Vivier static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
98054e1e0b5SLaurent Vivier int index)
981f83311e4SLaurent Vivier {
982f83311e4SLaurent Vivier TCGv tmp;
983f83311e4SLaurent Vivier TCGv_i64 t64;
984f83311e4SLaurent Vivier
985f83311e4SLaurent Vivier t64 = tcg_temp_new_i64();
986f83311e4SLaurent Vivier tmp = tcg_temp_new();
987f83311e4SLaurent Vivier switch (opsize) {
988f83311e4SLaurent Vivier case OS_BYTE:
989f83311e4SLaurent Vivier case OS_WORD:
990f83311e4SLaurent Vivier case OS_LONG:
991ad75a51eSRichard Henderson gen_helper_reds32(tmp, tcg_env, fp);
992b7a94da9SRichard Henderson tcg_gen_qemu_st_tl(tmp, addr, index, opsize | MO_TE);
993f83311e4SLaurent Vivier break;
994f83311e4SLaurent Vivier case OS_SINGLE:
995ad75a51eSRichard Henderson gen_helper_redf32(tmp, tcg_env, fp);
996b7a94da9SRichard Henderson tcg_gen_qemu_st_tl(tmp, addr, index, MO_TEUL);
997f83311e4SLaurent Vivier break;
998f83311e4SLaurent Vivier case OS_DOUBLE:
999ad75a51eSRichard Henderson gen_helper_redf64(t64, tcg_env, fp);
1000b7a94da9SRichard Henderson tcg_gen_qemu_st_i64(t64, addr, index, MO_TEUQ);
1001f83311e4SLaurent Vivier break;
1002f83311e4SLaurent Vivier case OS_EXTENDED:
1003f83311e4SLaurent Vivier if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1004a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1005f83311e4SLaurent Vivier break;
1006f83311e4SLaurent Vivier }
1007f83311e4SLaurent Vivier tcg_gen_ld16u_i32(tmp, fp, offsetof(FPReg, l.upper));
1008f83311e4SLaurent Vivier tcg_gen_shli_i32(tmp, tmp, 16);
1009b7a94da9SRichard Henderson tcg_gen_qemu_st_i32(tmp, addr, index, MO_TEUL);
1010f83311e4SLaurent Vivier tcg_gen_addi_i32(tmp, addr, 4);
1011f83311e4SLaurent Vivier tcg_gen_ld_i64(t64, fp, offsetof(FPReg, l.lower));
1012b7a94da9SRichard Henderson tcg_gen_qemu_st_i64(t64, tmp, index, MO_TEUQ);
1013f83311e4SLaurent Vivier break;
1014f83311e4SLaurent Vivier case OS_PACKED:
1015808d77bcSLucien Murray-Pitts /*
1016808d77bcSLucien Murray-Pitts * unimplemented data type on 68040/ColdFire
1017f83311e4SLaurent Vivier * FIXME if needed for another FPU
1018f83311e4SLaurent Vivier */
1019a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1020f83311e4SLaurent Vivier break;
1021f83311e4SLaurent Vivier default:
1022f83311e4SLaurent Vivier g_assert_not_reached();
1023f83311e4SLaurent Vivier }
1024f83311e4SLaurent Vivier }
1025f83311e4SLaurent Vivier
gen_ldst_fp(DisasContext * s,int opsize,TCGv addr,TCGv_ptr fp,ea_what what,int index)1026f83311e4SLaurent Vivier static void gen_ldst_fp(DisasContext *s, int opsize, TCGv addr,
102754e1e0b5SLaurent Vivier TCGv_ptr fp, ea_what what, int index)
1028f83311e4SLaurent Vivier {
1029f83311e4SLaurent Vivier if (what == EA_STORE) {
103054e1e0b5SLaurent Vivier gen_store_fp(s, opsize, addr, fp, index);
1031f83311e4SLaurent Vivier } else {
103254e1e0b5SLaurent Vivier gen_load_fp(s, opsize, addr, fp, index);
1033f83311e4SLaurent Vivier }
1034f83311e4SLaurent Vivier }
1035f83311e4SLaurent Vivier
gen_ea_mode_fp(CPUM68KState * env,DisasContext * s,int mode,int reg0,int opsize,TCGv_ptr fp,ea_what what,int index)1036f83311e4SLaurent Vivier static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
103754e1e0b5SLaurent Vivier int reg0, int opsize, TCGv_ptr fp, ea_what what,
103854e1e0b5SLaurent Vivier int index)
1039f83311e4SLaurent Vivier {
1040f83311e4SLaurent Vivier TCGv reg, addr, tmp;
1041f83311e4SLaurent Vivier TCGv_i64 t64;
1042f83311e4SLaurent Vivier
1043f83311e4SLaurent Vivier switch (mode) {
1044f83311e4SLaurent Vivier case 0: /* Data register direct. */
1045f83311e4SLaurent Vivier reg = cpu_dregs[reg0];
1046f83311e4SLaurent Vivier if (what == EA_STORE) {
1047f83311e4SLaurent Vivier switch (opsize) {
1048f83311e4SLaurent Vivier case OS_BYTE:
1049f83311e4SLaurent Vivier case OS_WORD:
1050f83311e4SLaurent Vivier case OS_LONG:
1051ad75a51eSRichard Henderson gen_helper_reds32(reg, tcg_env, fp);
1052f83311e4SLaurent Vivier break;
1053f83311e4SLaurent Vivier case OS_SINGLE:
1054ad75a51eSRichard Henderson gen_helper_redf32(reg, tcg_env, fp);
1055f83311e4SLaurent Vivier break;
1056f83311e4SLaurent Vivier default:
1057f83311e4SLaurent Vivier g_assert_not_reached();
1058f83311e4SLaurent Vivier }
1059f83311e4SLaurent Vivier } else {
1060f83311e4SLaurent Vivier tmp = tcg_temp_new();
1061f83311e4SLaurent Vivier switch (opsize) {
1062f83311e4SLaurent Vivier case OS_BYTE:
1063f83311e4SLaurent Vivier case OS_WORD:
1064f83311e4SLaurent Vivier case OS_LONG:
1065*443025e4SRichard Henderson tcg_gen_ext_i32(tmp, reg, opsize | MO_SIGN);
1066*443025e4SRichard Henderson gen_helper_exts32(tcg_env, fp, tmp);
1067f83311e4SLaurent Vivier break;
1068f83311e4SLaurent Vivier case OS_SINGLE:
1069ad75a51eSRichard Henderson gen_helper_extf32(tcg_env, fp, reg);
1070f83311e4SLaurent Vivier break;
1071f83311e4SLaurent Vivier default:
1072f83311e4SLaurent Vivier g_assert_not_reached();
1073f83311e4SLaurent Vivier }
1074f83311e4SLaurent Vivier }
1075f83311e4SLaurent Vivier return 0;
1076f83311e4SLaurent Vivier case 1: /* Address register direct. */
1077f83311e4SLaurent Vivier return -1;
1078f83311e4SLaurent Vivier case 2: /* Indirect register */
1079f83311e4SLaurent Vivier addr = get_areg(s, reg0);
108054e1e0b5SLaurent Vivier gen_ldst_fp(s, opsize, addr, fp, what, index);
1081f83311e4SLaurent Vivier return 0;
1082f83311e4SLaurent Vivier case 3: /* Indirect postincrement. */
1083f83311e4SLaurent Vivier addr = cpu_aregs[reg0];
108454e1e0b5SLaurent Vivier gen_ldst_fp(s, opsize, addr, fp, what, index);
1085f83311e4SLaurent Vivier tcg_gen_addi_i32(addr, addr, opsize_bytes(opsize));
1086f83311e4SLaurent Vivier return 0;
1087f83311e4SLaurent Vivier case 4: /* Indirect predecrememnt. */
1088f83311e4SLaurent Vivier addr = gen_lea_mode(env, s, mode, reg0, opsize);
1089f83311e4SLaurent Vivier if (IS_NULL_QREG(addr)) {
1090f83311e4SLaurent Vivier return -1;
1091f83311e4SLaurent Vivier }
109254e1e0b5SLaurent Vivier gen_ldst_fp(s, opsize, addr, fp, what, index);
1093f83311e4SLaurent Vivier tcg_gen_mov_i32(cpu_aregs[reg0], addr);
1094f83311e4SLaurent Vivier return 0;
1095f83311e4SLaurent Vivier case 5: /* Indirect displacement. */
1096f83311e4SLaurent Vivier case 6: /* Indirect index + displacement. */
1097f83311e4SLaurent Vivier do_indirect:
1098f83311e4SLaurent Vivier addr = gen_lea_mode(env, s, mode, reg0, opsize);
1099f83311e4SLaurent Vivier if (IS_NULL_QREG(addr)) {
1100f83311e4SLaurent Vivier return -1;
1101f83311e4SLaurent Vivier }
110254e1e0b5SLaurent Vivier gen_ldst_fp(s, opsize, addr, fp, what, index);
1103f83311e4SLaurent Vivier return 0;
1104f83311e4SLaurent Vivier case 7: /* Other */
1105f83311e4SLaurent Vivier switch (reg0) {
1106f83311e4SLaurent Vivier case 0: /* Absolute short. */
1107f83311e4SLaurent Vivier case 1: /* Absolute long. */
1108f83311e4SLaurent Vivier case 2: /* pc displacement */
1109f83311e4SLaurent Vivier case 3: /* pc index+displacement. */
1110f83311e4SLaurent Vivier goto do_indirect;
1111f83311e4SLaurent Vivier case 4: /* Immediate. */
1112f83311e4SLaurent Vivier if (what == EA_STORE) {
1113f83311e4SLaurent Vivier return -1;
1114f83311e4SLaurent Vivier }
1115f83311e4SLaurent Vivier switch (opsize) {
1116f83311e4SLaurent Vivier case OS_BYTE:
11171852ce5aSRichard Henderson tmp = tcg_constant_i32((int8_t)read_im8(env, s));
1118ad75a51eSRichard Henderson gen_helper_exts32(tcg_env, fp, tmp);
1119f83311e4SLaurent Vivier break;
1120f83311e4SLaurent Vivier case OS_WORD:
11211852ce5aSRichard Henderson tmp = tcg_constant_i32((int16_t)read_im16(env, s));
1122ad75a51eSRichard Henderson gen_helper_exts32(tcg_env, fp, tmp);
1123f83311e4SLaurent Vivier break;
1124f83311e4SLaurent Vivier case OS_LONG:
11251852ce5aSRichard Henderson tmp = tcg_constant_i32(read_im32(env, s));
1126ad75a51eSRichard Henderson gen_helper_exts32(tcg_env, fp, tmp);
1127f83311e4SLaurent Vivier break;
1128f83311e4SLaurent Vivier case OS_SINGLE:
11291852ce5aSRichard Henderson tmp = tcg_constant_i32(read_im32(env, s));
1130ad75a51eSRichard Henderson gen_helper_extf32(tcg_env, fp, tmp);
1131f83311e4SLaurent Vivier break;
1132f83311e4SLaurent Vivier case OS_DOUBLE:
11331852ce5aSRichard Henderson t64 = tcg_constant_i64(read_im64(env, s));
1134ad75a51eSRichard Henderson gen_helper_extf64(tcg_env, fp, t64);
1135f83311e4SLaurent Vivier break;
1136f83311e4SLaurent Vivier case OS_EXTENDED:
1137f83311e4SLaurent Vivier if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
1138a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1139f83311e4SLaurent Vivier break;
1140f83311e4SLaurent Vivier }
11411852ce5aSRichard Henderson tmp = tcg_constant_i32(read_im32(env, s) >> 16);
1142f83311e4SLaurent Vivier tcg_gen_st16_i32(tmp, fp, offsetof(FPReg, l.upper));
11431852ce5aSRichard Henderson t64 = tcg_constant_i64(read_im64(env, s));
1144f83311e4SLaurent Vivier tcg_gen_st_i64(t64, fp, offsetof(FPReg, l.lower));
1145f83311e4SLaurent Vivier break;
1146f83311e4SLaurent Vivier case OS_PACKED:
1147808d77bcSLucien Murray-Pitts /*
1148808d77bcSLucien Murray-Pitts * unimplemented data type on 68040/ColdFire
1149f83311e4SLaurent Vivier * FIXME if needed for another FPU
1150f83311e4SLaurent Vivier */
1151a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
1152f83311e4SLaurent Vivier break;
1153f83311e4SLaurent Vivier default:
1154f83311e4SLaurent Vivier g_assert_not_reached();
1155f83311e4SLaurent Vivier }
1156f83311e4SLaurent Vivier return 0;
1157f83311e4SLaurent Vivier default:
1158f83311e4SLaurent Vivier return -1;
1159f83311e4SLaurent Vivier }
1160f83311e4SLaurent Vivier }
1161f83311e4SLaurent Vivier return -1;
1162f83311e4SLaurent Vivier }
1163f83311e4SLaurent Vivier
gen_ea_fp(CPUM68KState * env,DisasContext * s,uint16_t insn,int opsize,TCGv_ptr fp,ea_what what,int index)1164f83311e4SLaurent Vivier static int gen_ea_fp(CPUM68KState *env, DisasContext *s, uint16_t insn,
116554e1e0b5SLaurent Vivier int opsize, TCGv_ptr fp, ea_what what, int index)
1166f83311e4SLaurent Vivier {
1167f83311e4SLaurent Vivier int mode = extract32(insn, 3, 3);
1168f83311e4SLaurent Vivier int reg0 = REG(insn, 0);
116954e1e0b5SLaurent Vivier return gen_ea_mode_fp(env, s, mode, reg0, opsize, fp, what, index);
1170f83311e4SLaurent Vivier }
1171f83311e4SLaurent Vivier
1172fcf5ef2aSThomas Huth typedef struct {
1173fcf5ef2aSThomas Huth TCGCond tcond;
1174fcf5ef2aSThomas Huth TCGv v1;
1175fcf5ef2aSThomas Huth TCGv v2;
1176fcf5ef2aSThomas Huth } DisasCompare;
1177fcf5ef2aSThomas Huth
gen_cc_cond(DisasCompare * c,DisasContext * s,int cond)1178fcf5ef2aSThomas Huth static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond)
1179fcf5ef2aSThomas Huth {
1180fcf5ef2aSThomas Huth TCGv tmp, tmp2;
1181fcf5ef2aSThomas Huth TCGCond tcond;
1182fcf5ef2aSThomas Huth CCOp op = s->cc_op;
1183fcf5ef2aSThomas Huth
1184fcf5ef2aSThomas Huth /* The CC_OP_CMP form can handle most normal comparisons directly. */
1185fcf5ef2aSThomas Huth if (op == CC_OP_CMPB || op == CC_OP_CMPW || op == CC_OP_CMPL) {
1186fcf5ef2aSThomas Huth c->v1 = QREG_CC_N;
1187fcf5ef2aSThomas Huth c->v2 = QREG_CC_V;
1188fcf5ef2aSThomas Huth switch (cond) {
1189fcf5ef2aSThomas Huth case 2: /* HI */
1190fcf5ef2aSThomas Huth case 3: /* LS */
1191fcf5ef2aSThomas Huth tcond = TCG_COND_LEU;
1192fcf5ef2aSThomas Huth goto done;
1193fcf5ef2aSThomas Huth case 4: /* CC */
1194fcf5ef2aSThomas Huth case 5: /* CS */
1195fcf5ef2aSThomas Huth tcond = TCG_COND_LTU;
1196fcf5ef2aSThomas Huth goto done;
1197fcf5ef2aSThomas Huth case 6: /* NE */
1198fcf5ef2aSThomas Huth case 7: /* EQ */
1199fcf5ef2aSThomas Huth tcond = TCG_COND_EQ;
1200fcf5ef2aSThomas Huth goto done;
1201fcf5ef2aSThomas Huth case 10: /* PL */
1202fcf5ef2aSThomas Huth case 11: /* MI */
12031852ce5aSRichard Henderson c->v2 = tcg_constant_i32(0);
1204fcf5ef2aSThomas Huth c->v1 = tmp = tcg_temp_new();
1205fcf5ef2aSThomas Huth tcg_gen_sub_i32(tmp, QREG_CC_N, QREG_CC_V);
1206fcf5ef2aSThomas Huth gen_ext(tmp, tmp, op - CC_OP_CMPB, 1);
1207fcf5ef2aSThomas Huth /* fallthru */
1208fcf5ef2aSThomas Huth case 12: /* GE */
1209fcf5ef2aSThomas Huth case 13: /* LT */
1210fcf5ef2aSThomas Huth tcond = TCG_COND_LT;
1211fcf5ef2aSThomas Huth goto done;
1212fcf5ef2aSThomas Huth case 14: /* GT */
1213fcf5ef2aSThomas Huth case 15: /* LE */
1214fcf5ef2aSThomas Huth tcond = TCG_COND_LE;
1215fcf5ef2aSThomas Huth goto done;
1216fcf5ef2aSThomas Huth }
1217fcf5ef2aSThomas Huth }
1218fcf5ef2aSThomas Huth
12191852ce5aSRichard Henderson c->v2 = tcg_constant_i32(0);
1220fcf5ef2aSThomas Huth
1221fcf5ef2aSThomas Huth switch (cond) {
1222fcf5ef2aSThomas Huth case 0: /* T */
1223fcf5ef2aSThomas Huth case 1: /* F */
1224fcf5ef2aSThomas Huth c->v1 = c->v2;
1225fcf5ef2aSThomas Huth tcond = TCG_COND_NEVER;
1226fcf5ef2aSThomas Huth goto done;
1227fcf5ef2aSThomas Huth case 14: /* GT (!(Z || (N ^ V))) */
1228fcf5ef2aSThomas Huth case 15: /* LE (Z || (N ^ V)) */
1229808d77bcSLucien Murray-Pitts /*
1230808d77bcSLucien Murray-Pitts * Logic operations clear V, which simplifies LE to (Z || N),
1231808d77bcSLucien Murray-Pitts * and since Z and N are co-located, this becomes a normal
1232808d77bcSLucien Murray-Pitts * comparison vs N.
1233808d77bcSLucien Murray-Pitts */
1234fcf5ef2aSThomas Huth if (op == CC_OP_LOGIC) {
1235fcf5ef2aSThomas Huth c->v1 = QREG_CC_N;
1236fcf5ef2aSThomas Huth tcond = TCG_COND_LE;
1237fcf5ef2aSThomas Huth goto done;
1238fcf5ef2aSThomas Huth }
1239fcf5ef2aSThomas Huth break;
1240fcf5ef2aSThomas Huth case 12: /* GE (!(N ^ V)) */
1241fcf5ef2aSThomas Huth case 13: /* LT (N ^ V) */
1242fcf5ef2aSThomas Huth /* Logic operations clear V, which simplifies this to N. */
1243fcf5ef2aSThomas Huth if (op != CC_OP_LOGIC) {
1244fcf5ef2aSThomas Huth break;
1245fcf5ef2aSThomas Huth }
1246fcf5ef2aSThomas Huth /* fallthru */
1247fcf5ef2aSThomas Huth case 10: /* PL (!N) */
1248fcf5ef2aSThomas Huth case 11: /* MI (N) */
1249fcf5ef2aSThomas Huth /* Several cases represent N normally. */
1250fcf5ef2aSThomas Huth if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1251fcf5ef2aSThomas Huth op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
1252fcf5ef2aSThomas Huth op == CC_OP_LOGIC) {
1253fcf5ef2aSThomas Huth c->v1 = QREG_CC_N;
1254fcf5ef2aSThomas Huth tcond = TCG_COND_LT;
1255fcf5ef2aSThomas Huth goto done;
1256fcf5ef2aSThomas Huth }
1257fcf5ef2aSThomas Huth break;
1258fcf5ef2aSThomas Huth case 6: /* NE (!Z) */
1259fcf5ef2aSThomas Huth case 7: /* EQ (Z) */
1260fcf5ef2aSThomas Huth /* Some cases fold Z into N. */
1261fcf5ef2aSThomas Huth if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
1262fcf5ef2aSThomas Huth op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL ||
1263fcf5ef2aSThomas Huth op == CC_OP_LOGIC) {
1264fcf5ef2aSThomas Huth tcond = TCG_COND_EQ;
1265fcf5ef2aSThomas Huth c->v1 = QREG_CC_N;
1266fcf5ef2aSThomas Huth goto done;
1267fcf5ef2aSThomas Huth }
1268fcf5ef2aSThomas Huth break;
1269fcf5ef2aSThomas Huth case 4: /* CC (!C) */
1270fcf5ef2aSThomas Huth case 5: /* CS (C) */
1271fcf5ef2aSThomas Huth /* Some cases fold C into X. */
1272fcf5ef2aSThomas Huth if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL ||
12734b5660e4SPhilippe Mathieu-Daudé op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL) {
1274fcf5ef2aSThomas Huth tcond = TCG_COND_NE;
1275fcf5ef2aSThomas Huth c->v1 = QREG_CC_X;
1276fcf5ef2aSThomas Huth goto done;
1277fcf5ef2aSThomas Huth }
1278fcf5ef2aSThomas Huth /* fallthru */
1279fcf5ef2aSThomas Huth case 8: /* VC (!V) */
1280fcf5ef2aSThomas Huth case 9: /* VS (V) */
1281fcf5ef2aSThomas Huth /* Logic operations clear V and C. */
1282fcf5ef2aSThomas Huth if (op == CC_OP_LOGIC) {
1283fcf5ef2aSThomas Huth tcond = TCG_COND_NEVER;
1284fcf5ef2aSThomas Huth c->v1 = c->v2;
1285fcf5ef2aSThomas Huth goto done;
1286fcf5ef2aSThomas Huth }
1287fcf5ef2aSThomas Huth break;
1288fcf5ef2aSThomas Huth }
1289fcf5ef2aSThomas Huth
1290fcf5ef2aSThomas Huth /* Otherwise, flush flag state to CC_OP_FLAGS. */
1291fcf5ef2aSThomas Huth gen_flush_flags(s);
1292fcf5ef2aSThomas Huth
1293fcf5ef2aSThomas Huth switch (cond) {
1294fcf5ef2aSThomas Huth case 0: /* T */
1295fcf5ef2aSThomas Huth case 1: /* F */
1296fcf5ef2aSThomas Huth default:
1297fcf5ef2aSThomas Huth /* Invalid, or handled above. */
1298fcf5ef2aSThomas Huth abort();
1299fcf5ef2aSThomas Huth case 2: /* HI (!C && !Z) -> !(C || Z)*/
1300fcf5ef2aSThomas Huth case 3: /* LS (C || Z) */
1301fcf5ef2aSThomas Huth c->v1 = tmp = tcg_temp_new();
1302fcf5ef2aSThomas Huth tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
1303fcf5ef2aSThomas Huth tcg_gen_or_i32(tmp, tmp, QREG_CC_C);
1304fcf5ef2aSThomas Huth tcond = TCG_COND_NE;
1305fcf5ef2aSThomas Huth break;
1306fcf5ef2aSThomas Huth case 4: /* CC (!C) */
1307fcf5ef2aSThomas Huth case 5: /* CS (C) */
1308fcf5ef2aSThomas Huth c->v1 = QREG_CC_C;
1309fcf5ef2aSThomas Huth tcond = TCG_COND_NE;
1310fcf5ef2aSThomas Huth break;
1311fcf5ef2aSThomas Huth case 6: /* NE (!Z) */
1312fcf5ef2aSThomas Huth case 7: /* EQ (Z) */
1313fcf5ef2aSThomas Huth c->v1 = QREG_CC_Z;
1314fcf5ef2aSThomas Huth tcond = TCG_COND_EQ;
1315fcf5ef2aSThomas Huth break;
1316fcf5ef2aSThomas Huth case 8: /* VC (!V) */
1317fcf5ef2aSThomas Huth case 9: /* VS (V) */
1318fcf5ef2aSThomas Huth c->v1 = QREG_CC_V;
1319fcf5ef2aSThomas Huth tcond = TCG_COND_LT;
1320fcf5ef2aSThomas Huth break;
1321fcf5ef2aSThomas Huth case 10: /* PL (!N) */
1322fcf5ef2aSThomas Huth case 11: /* MI (N) */
1323fcf5ef2aSThomas Huth c->v1 = QREG_CC_N;
1324fcf5ef2aSThomas Huth tcond = TCG_COND_LT;
1325fcf5ef2aSThomas Huth break;
1326fcf5ef2aSThomas Huth case 12: /* GE (!(N ^ V)) */
1327fcf5ef2aSThomas Huth case 13: /* LT (N ^ V) */
1328fcf5ef2aSThomas Huth c->v1 = tmp = tcg_temp_new();
1329fcf5ef2aSThomas Huth tcg_gen_xor_i32(tmp, QREG_CC_N, QREG_CC_V);
1330fcf5ef2aSThomas Huth tcond = TCG_COND_LT;
1331fcf5ef2aSThomas Huth break;
1332fcf5ef2aSThomas Huth case 14: /* GT (!(Z || (N ^ V))) */
1333fcf5ef2aSThomas Huth case 15: /* LE (Z || (N ^ V)) */
1334fcf5ef2aSThomas Huth c->v1 = tmp = tcg_temp_new();
133527f9af76SRichard Henderson tcg_gen_negsetcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2);
1336fcf5ef2aSThomas Huth tmp2 = tcg_temp_new();
1337fcf5ef2aSThomas Huth tcg_gen_xor_i32(tmp2, QREG_CC_N, QREG_CC_V);
1338fcf5ef2aSThomas Huth tcg_gen_or_i32(tmp, tmp, tmp2);
1339fcf5ef2aSThomas Huth tcond = TCG_COND_LT;
1340fcf5ef2aSThomas Huth break;
1341fcf5ef2aSThomas Huth }
1342fcf5ef2aSThomas Huth
1343fcf5ef2aSThomas Huth done:
1344fcf5ef2aSThomas Huth if ((cond & 1) == 0) {
1345fcf5ef2aSThomas Huth tcond = tcg_invert_cond(tcond);
1346fcf5ef2aSThomas Huth }
1347fcf5ef2aSThomas Huth c->tcond = tcond;
1348fcf5ef2aSThomas Huth }
1349fcf5ef2aSThomas Huth
gen_jmpcc(DisasContext * s,int cond,TCGLabel * l1)1350fcf5ef2aSThomas Huth static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1)
1351fcf5ef2aSThomas Huth {
1352fcf5ef2aSThomas Huth DisasCompare c;
1353fcf5ef2aSThomas Huth
1354fcf5ef2aSThomas Huth gen_cc_cond(&c, s, cond);
1355fcf5ef2aSThomas Huth update_cc_op(s);
1356fcf5ef2aSThomas Huth tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
1357fcf5ef2aSThomas Huth }
1358fcf5ef2aSThomas Huth
1359fcf5ef2aSThomas Huth /* Force a TB lookup after an instruction that changes the CPU state. */
gen_exit_tb(DisasContext * s)13604106f26eSRichard Henderson static void gen_exit_tb(DisasContext *s)
1361fcf5ef2aSThomas Huth {
1362fcf5ef2aSThomas Huth update_cc_op(s);
1363fcf5ef2aSThomas Huth tcg_gen_movi_i32(QREG_PC, s->pc);
1364a575cbe0SRichard Henderson s->base.is_jmp = DISAS_EXIT;
1365fcf5ef2aSThomas Huth }
1366fcf5ef2aSThomas Huth
1367fcf5ef2aSThomas Huth #define SRC_EA(env, result, opsize, op_sign, addrp) do { \
1368fcf5ef2aSThomas Huth result = gen_ea(env, s, insn, opsize, NULL_QREG, addrp, \
136954e1e0b5SLaurent Vivier op_sign ? EA_LOADS : EA_LOADU, IS_USER(s)); \
1370fcf5ef2aSThomas Huth if (IS_NULL_QREG(result)) { \
1371fcf5ef2aSThomas Huth gen_addr_fault(s); \
1372fcf5ef2aSThomas Huth return; \
1373fcf5ef2aSThomas Huth } \
1374fcf5ef2aSThomas Huth } while (0)
1375fcf5ef2aSThomas Huth
1376fcf5ef2aSThomas Huth #define DEST_EA(env, insn, opsize, val, addrp) do { \
137754e1e0b5SLaurent Vivier TCGv ea_result = gen_ea(env, s, insn, opsize, val, addrp, \
137854e1e0b5SLaurent Vivier EA_STORE, IS_USER(s)); \
1379fcf5ef2aSThomas Huth if (IS_NULL_QREG(ea_result)) { \
1380fcf5ef2aSThomas Huth gen_addr_fault(s); \
1381fcf5ef2aSThomas Huth return; \
1382fcf5ef2aSThomas Huth } \
1383fcf5ef2aSThomas Huth } while (0)
1384fcf5ef2aSThomas Huth
1385fcf5ef2aSThomas Huth /* Generate a jump to an immediate address. */
gen_jmp_tb(DisasContext * s,int n,target_ulong dest,target_ulong src)13868115fc93SRichard Henderson static void gen_jmp_tb(DisasContext *s, int n, target_ulong dest,
13878115fc93SRichard Henderson target_ulong src)
1388fcf5ef2aSThomas Huth {
1389661da0f6SRichard Henderson if (unlikely(s->ss_active)) {
13904f2b21efSMark Cave-Ayland update_cc_op(s);
13914f2b21efSMark Cave-Ayland tcg_gen_movi_i32(QREG_PC, dest);
13928115fc93SRichard Henderson gen_raise_exception_format2(s, EXCP_TRACE, src);
1393fbf565c4SRichard Henderson } else if (translator_use_goto_tb(&s->base, dest)) {
1394fcf5ef2aSThomas Huth tcg_gen_goto_tb(n);
1395fcf5ef2aSThomas Huth tcg_gen_movi_i32(QREG_PC, dest);
1396a575cbe0SRichard Henderson tcg_gen_exit_tb(s->base.tb, n);
1397fcf5ef2aSThomas Huth } else {
1398fcf5ef2aSThomas Huth gen_jmp_im(s, dest);
139907ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0);
1400fcf5ef2aSThomas Huth }
1401a575cbe0SRichard Henderson s->base.is_jmp = DISAS_NORETURN;
1402fcf5ef2aSThomas Huth }
1403fcf5ef2aSThomas Huth
DISAS_INSN(scc)1404fcf5ef2aSThomas Huth DISAS_INSN(scc)
1405fcf5ef2aSThomas Huth {
1406fcf5ef2aSThomas Huth DisasCompare c;
1407fcf5ef2aSThomas Huth int cond;
1408fcf5ef2aSThomas Huth TCGv tmp;
1409fcf5ef2aSThomas Huth
1410fcf5ef2aSThomas Huth cond = (insn >> 8) & 0xf;
1411fcf5ef2aSThomas Huth gen_cc_cond(&c, s, cond);
1412fcf5ef2aSThomas Huth
1413fcf5ef2aSThomas Huth tmp = tcg_temp_new();
141427f9af76SRichard Henderson tcg_gen_negsetcond_i32(c.tcond, tmp, c.v1, c.v2);
1415fcf5ef2aSThomas Huth
1416fcf5ef2aSThomas Huth DEST_EA(env, insn, OS_BYTE, tmp, NULL);
1417fcf5ef2aSThomas Huth }
1418fcf5ef2aSThomas Huth
DISAS_INSN(dbcc)1419fcf5ef2aSThomas Huth DISAS_INSN(dbcc)
1420fcf5ef2aSThomas Huth {
1421fcf5ef2aSThomas Huth TCGLabel *l1;
1422fcf5ef2aSThomas Huth TCGv reg;
1423fcf5ef2aSThomas Huth TCGv tmp;
1424fcf5ef2aSThomas Huth int16_t offset;
1425fcf5ef2aSThomas Huth uint32_t base;
1426fcf5ef2aSThomas Huth
1427fcf5ef2aSThomas Huth reg = DREG(insn, 0);
1428fcf5ef2aSThomas Huth base = s->pc;
1429fcf5ef2aSThomas Huth offset = (int16_t)read_im16(env, s);
1430fcf5ef2aSThomas Huth l1 = gen_new_label();
1431fcf5ef2aSThomas Huth gen_jmpcc(s, (insn >> 8) & 0xf, l1);
1432fcf5ef2aSThomas Huth
1433fcf5ef2aSThomas Huth tmp = tcg_temp_new();
1434fcf5ef2aSThomas Huth tcg_gen_ext16s_i32(tmp, reg);
1435fcf5ef2aSThomas Huth tcg_gen_addi_i32(tmp, tmp, -1);
1436fcf5ef2aSThomas Huth gen_partset_reg(OS_WORD, reg, tmp);
1437fcf5ef2aSThomas Huth tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1);
14388115fc93SRichard Henderson gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
1439fcf5ef2aSThomas Huth gen_set_label(l1);
14408115fc93SRichard Henderson gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
1441fcf5ef2aSThomas Huth }
1442fcf5ef2aSThomas Huth
DISAS_INSN(undef_mac)1443fcf5ef2aSThomas Huth DISAS_INSN(undef_mac)
1444fcf5ef2aSThomas Huth {
1445a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_LINEA);
1446fcf5ef2aSThomas Huth }
1447fcf5ef2aSThomas Huth
DISAS_INSN(undef_fpu)1448fcf5ef2aSThomas Huth DISAS_INSN(undef_fpu)
1449fcf5ef2aSThomas Huth {
1450a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_LINEF);
1451fcf5ef2aSThomas Huth }
1452fcf5ef2aSThomas Huth
DISAS_INSN(undef)1453fcf5ef2aSThomas Huth DISAS_INSN(undef)
1454fcf5ef2aSThomas Huth {
1455808d77bcSLucien Murray-Pitts /*
1456808d77bcSLucien Murray-Pitts * ??? This is both instructions that are as yet unimplemented
1457808d77bcSLucien Murray-Pitts * for the 680x0 series, as well as those that are implemented
1458808d77bcSLucien Murray-Pitts * but actually illegal for CPU32 or pre-68020.
1459808d77bcSLucien Murray-Pitts */
146021528149SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n",
1461a575cbe0SRichard Henderson insn, s->base.pc_next);
1462b9f8e55bSLaurent Vivier gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
1463fcf5ef2aSThomas Huth }
1464fcf5ef2aSThomas Huth
DISAS_INSN(mulw)1465fcf5ef2aSThomas Huth DISAS_INSN(mulw)
1466fcf5ef2aSThomas Huth {
1467fcf5ef2aSThomas Huth TCGv reg;
1468fcf5ef2aSThomas Huth TCGv tmp;
1469fcf5ef2aSThomas Huth TCGv src;
1470fcf5ef2aSThomas Huth int sign;
1471fcf5ef2aSThomas Huth
1472fcf5ef2aSThomas Huth sign = (insn & 0x100) != 0;
1473fcf5ef2aSThomas Huth reg = DREG(insn, 9);
1474fcf5ef2aSThomas Huth tmp = tcg_temp_new();
1475fcf5ef2aSThomas Huth if (sign)
1476fcf5ef2aSThomas Huth tcg_gen_ext16s_i32(tmp, reg);
1477fcf5ef2aSThomas Huth else
1478fcf5ef2aSThomas Huth tcg_gen_ext16u_i32(tmp, reg);
1479fcf5ef2aSThomas Huth SRC_EA(env, src, OS_WORD, sign, NULL);
1480fcf5ef2aSThomas Huth tcg_gen_mul_i32(tmp, tmp, src);
1481fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, tmp);
1482fcf5ef2aSThomas Huth gen_logic_cc(s, tmp, OS_LONG);
1483fcf5ef2aSThomas Huth }
1484fcf5ef2aSThomas Huth
DISAS_INSN(divw)1485fcf5ef2aSThomas Huth DISAS_INSN(divw)
1486fcf5ef2aSThomas Huth {
1487fcf5ef2aSThomas Huth int sign;
14880ccb9c1dSLaurent Vivier TCGv src;
14890ccb9c1dSLaurent Vivier TCGv destr;
1490710d747bSRichard Henderson TCGv ilen;
14910ccb9c1dSLaurent Vivier
14920ccb9c1dSLaurent Vivier /* divX.w <EA>,Dn 32/16 -> 16r:16q */
1493fcf5ef2aSThomas Huth
1494fcf5ef2aSThomas Huth sign = (insn & 0x100) != 0;
1495fcf5ef2aSThomas Huth
14960ccb9c1dSLaurent Vivier /* dest.l / src.w */
14970ccb9c1dSLaurent Vivier
14980ccb9c1dSLaurent Vivier SRC_EA(env, src, OS_WORD, sign, NULL);
1499710d747bSRichard Henderson destr = tcg_constant_i32(REG(insn, 9));
1500710d747bSRichard Henderson ilen = tcg_constant_i32(s->pc - s->base.pc_next);
15010ccb9c1dSLaurent Vivier if (sign) {
1502ad75a51eSRichard Henderson gen_helper_divsw(tcg_env, destr, src, ilen);
15030ccb9c1dSLaurent Vivier } else {
1504ad75a51eSRichard Henderson gen_helper_divuw(tcg_env, destr, src, ilen);
15050ccb9c1dSLaurent Vivier }
1506fcf5ef2aSThomas Huth
1507fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_FLAGS);
1508fcf5ef2aSThomas Huth }
1509fcf5ef2aSThomas Huth
DISAS_INSN(divl)1510fcf5ef2aSThomas Huth DISAS_INSN(divl)
1511fcf5ef2aSThomas Huth {
1512710d747bSRichard Henderson TCGv num, reg, den, ilen;
15130ccb9c1dSLaurent Vivier int sign;
1514fcf5ef2aSThomas Huth uint16_t ext;
1515fcf5ef2aSThomas Huth
1516fcf5ef2aSThomas Huth ext = read_im16(env, s);
15170ccb9c1dSLaurent Vivier
15180ccb9c1dSLaurent Vivier sign = (ext & 0x0800) != 0;
15190ccb9c1dSLaurent Vivier
15200ccb9c1dSLaurent Vivier if (ext & 0x400) {
15210ccb9c1dSLaurent Vivier if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
1522a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
1523fcf5ef2aSThomas Huth return;
1524fcf5ef2aSThomas Huth }
15250ccb9c1dSLaurent Vivier
15260ccb9c1dSLaurent Vivier /* divX.l <EA>, Dr:Dq 64/32 -> 32r:32q */
15270ccb9c1dSLaurent Vivier
1528fcf5ef2aSThomas Huth SRC_EA(env, den, OS_LONG, 0, NULL);
1529710d747bSRichard Henderson num = tcg_constant_i32(REG(ext, 12));
1530710d747bSRichard Henderson reg = tcg_constant_i32(REG(ext, 0));
1531710d747bSRichard Henderson ilen = tcg_constant_i32(s->pc - s->base.pc_next);
15320ccb9c1dSLaurent Vivier if (sign) {
1533ad75a51eSRichard Henderson gen_helper_divsll(tcg_env, num, reg, den, ilen);
1534fcf5ef2aSThomas Huth } else {
1535ad75a51eSRichard Henderson gen_helper_divull(tcg_env, num, reg, den, ilen);
1536fcf5ef2aSThomas Huth }
15370ccb9c1dSLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
15380ccb9c1dSLaurent Vivier return;
15390ccb9c1dSLaurent Vivier }
15400ccb9c1dSLaurent Vivier
15410ccb9c1dSLaurent Vivier /* divX.l <EA>, Dq 32/32 -> 32q */
15420ccb9c1dSLaurent Vivier /* divXl.l <EA>, Dr:Dq 32/32 -> 32r:32q */
15430ccb9c1dSLaurent Vivier
15440ccb9c1dSLaurent Vivier SRC_EA(env, den, OS_LONG, 0, NULL);
1545710d747bSRichard Henderson num = tcg_constant_i32(REG(ext, 12));
1546710d747bSRichard Henderson reg = tcg_constant_i32(REG(ext, 0));
1547710d747bSRichard Henderson ilen = tcg_constant_i32(s->pc - s->base.pc_next);
15480ccb9c1dSLaurent Vivier if (sign) {
1549ad75a51eSRichard Henderson gen_helper_divsl(tcg_env, num, reg, den, ilen);
1550fcf5ef2aSThomas Huth } else {
1551ad75a51eSRichard Henderson gen_helper_divul(tcg_env, num, reg, den, ilen);
1552fcf5ef2aSThomas Huth }
15530ccb9c1dSLaurent Vivier
1554fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_FLAGS);
1555fcf5ef2aSThomas Huth }
1556fcf5ef2aSThomas Huth
bcd_add(TCGv dest,TCGv src)1557fb5543d8SLaurent Vivier static void bcd_add(TCGv dest, TCGv src)
1558fb5543d8SLaurent Vivier {
1559fb5543d8SLaurent Vivier TCGv t0, t1;
1560fb5543d8SLaurent Vivier
1561808d77bcSLucien Murray-Pitts /*
1562808d77bcSLucien Murray-Pitts * dest10 = dest10 + src10 + X
1563fb5543d8SLaurent Vivier *
1564fb5543d8SLaurent Vivier * t1 = src
1565fb5543d8SLaurent Vivier * t2 = t1 + 0x066
1566fb5543d8SLaurent Vivier * t3 = t2 + dest + X
1567fb5543d8SLaurent Vivier * t4 = t2 ^ dest
1568fb5543d8SLaurent Vivier * t5 = t3 ^ t4
1569fb5543d8SLaurent Vivier * t6 = ~t5 & 0x110
1570fb5543d8SLaurent Vivier * t7 = (t6 >> 2) | (t6 >> 3)
1571fb5543d8SLaurent Vivier * return t3 - t7
1572fb5543d8SLaurent Vivier */
1573fb5543d8SLaurent Vivier
1574808d77bcSLucien Murray-Pitts /*
1575808d77bcSLucien Murray-Pitts * t1 = (src + 0x066) + dest + X
1576ce00ff72Szhaolichang * = result with some possible exceeding 0x6
1577fb5543d8SLaurent Vivier */
1578fb5543d8SLaurent Vivier
1579b32a07d4SRichard Henderson t0 = tcg_temp_new();
1580b32a07d4SRichard Henderson tcg_gen_addi_i32(t0, src, 0x066);
1581fb5543d8SLaurent Vivier
1582fb5543d8SLaurent Vivier t1 = tcg_temp_new();
1583fb5543d8SLaurent Vivier tcg_gen_add_i32(t1, t0, dest);
1584fb5543d8SLaurent Vivier tcg_gen_add_i32(t1, t1, QREG_CC_X);
1585fb5543d8SLaurent Vivier
1586ce00ff72Szhaolichang /* we will remove exceeding 0x6 where there is no carry */
1587fb5543d8SLaurent Vivier
1588808d77bcSLucien Murray-Pitts /*
1589808d77bcSLucien Murray-Pitts * t0 = (src + 0x0066) ^ dest
1590fb5543d8SLaurent Vivier * = t1 without carries
1591fb5543d8SLaurent Vivier */
1592fb5543d8SLaurent Vivier
1593fb5543d8SLaurent Vivier tcg_gen_xor_i32(t0, t0, dest);
1594fb5543d8SLaurent Vivier
1595808d77bcSLucien Murray-Pitts /*
1596808d77bcSLucien Murray-Pitts * extract the carries
1597fb5543d8SLaurent Vivier * t0 = t0 ^ t1
1598fb5543d8SLaurent Vivier * = only the carries
1599fb5543d8SLaurent Vivier */
1600fb5543d8SLaurent Vivier
1601fb5543d8SLaurent Vivier tcg_gen_xor_i32(t0, t0, t1);
1602fb5543d8SLaurent Vivier
1603808d77bcSLucien Murray-Pitts /*
1604808d77bcSLucien Murray-Pitts * generate 0x1 where there is no carry
1605fb5543d8SLaurent Vivier * and for each 0x10, generate a 0x6
1606fb5543d8SLaurent Vivier */
1607fb5543d8SLaurent Vivier
1608fb5543d8SLaurent Vivier tcg_gen_shri_i32(t0, t0, 3);
1609fb5543d8SLaurent Vivier tcg_gen_not_i32(t0, t0);
1610fb5543d8SLaurent Vivier tcg_gen_andi_i32(t0, t0, 0x22);
1611fb5543d8SLaurent Vivier tcg_gen_add_i32(dest, t0, t0);
1612fb5543d8SLaurent Vivier tcg_gen_add_i32(dest, dest, t0);
1613fb5543d8SLaurent Vivier
1614808d77bcSLucien Murray-Pitts /*
1615ce00ff72Szhaolichang * remove the exceeding 0x6
1616fb5543d8SLaurent Vivier * for digits that have not generated a carry
1617fb5543d8SLaurent Vivier */
1618fb5543d8SLaurent Vivier
1619fb5543d8SLaurent Vivier tcg_gen_sub_i32(dest, t1, dest);
1620fb5543d8SLaurent Vivier }
1621fb5543d8SLaurent Vivier
bcd_sub(TCGv dest,TCGv src)1622fb5543d8SLaurent Vivier static void bcd_sub(TCGv dest, TCGv src)
1623fb5543d8SLaurent Vivier {
1624fb5543d8SLaurent Vivier TCGv t0, t1, t2;
1625fb5543d8SLaurent Vivier
1626808d77bcSLucien Murray-Pitts /*
1627808d77bcSLucien Murray-Pitts * dest10 = dest10 - src10 - X
1628fb5543d8SLaurent Vivier * = bcd_add(dest + 1 - X, 0x199 - src)
1629fb5543d8SLaurent Vivier */
1630fb5543d8SLaurent Vivier
1631fb5543d8SLaurent Vivier /* t0 = 0x066 + (0x199 - src) */
1632fb5543d8SLaurent Vivier
1633fb5543d8SLaurent Vivier t0 = tcg_temp_new();
1634fb5543d8SLaurent Vivier tcg_gen_subfi_i32(t0, 0x1ff, src);
1635fb5543d8SLaurent Vivier
1636fb5543d8SLaurent Vivier /* t1 = t0 + dest + 1 - X*/
1637fb5543d8SLaurent Vivier
1638fb5543d8SLaurent Vivier t1 = tcg_temp_new();
1639fb5543d8SLaurent Vivier tcg_gen_add_i32(t1, t0, dest);
1640fb5543d8SLaurent Vivier tcg_gen_addi_i32(t1, t1, 1);
1641fb5543d8SLaurent Vivier tcg_gen_sub_i32(t1, t1, QREG_CC_X);
1642fb5543d8SLaurent Vivier
1643fb5543d8SLaurent Vivier /* t2 = t0 ^ dest */
1644fb5543d8SLaurent Vivier
1645fb5543d8SLaurent Vivier t2 = tcg_temp_new();
1646fb5543d8SLaurent Vivier tcg_gen_xor_i32(t2, t0, dest);
1647fb5543d8SLaurent Vivier
1648fb5543d8SLaurent Vivier /* t0 = t1 ^ t2 */
1649fb5543d8SLaurent Vivier
1650fb5543d8SLaurent Vivier tcg_gen_xor_i32(t0, t1, t2);
1651fb5543d8SLaurent Vivier
1652808d77bcSLucien Murray-Pitts /*
1653808d77bcSLucien Murray-Pitts * t2 = ~t0 & 0x110
1654fb5543d8SLaurent Vivier * t0 = (t2 >> 2) | (t2 >> 3)
1655fb5543d8SLaurent Vivier *
1656fb5543d8SLaurent Vivier * to fit on 8bit operands, changed in:
1657fb5543d8SLaurent Vivier *
1658fb5543d8SLaurent Vivier * t2 = ~(t0 >> 3) & 0x22
1659fb5543d8SLaurent Vivier * t0 = t2 + t2
1660fb5543d8SLaurent Vivier * t0 = t0 + t2
1661fb5543d8SLaurent Vivier */
1662fb5543d8SLaurent Vivier
1663fb5543d8SLaurent Vivier tcg_gen_shri_i32(t2, t0, 3);
1664fb5543d8SLaurent Vivier tcg_gen_not_i32(t2, t2);
1665fb5543d8SLaurent Vivier tcg_gen_andi_i32(t2, t2, 0x22);
1666fb5543d8SLaurent Vivier tcg_gen_add_i32(t0, t2, t2);
1667fb5543d8SLaurent Vivier tcg_gen_add_i32(t0, t0, t2);
1668fb5543d8SLaurent Vivier
1669fb5543d8SLaurent Vivier /* return t1 - t0 */
1670fb5543d8SLaurent Vivier
1671fb5543d8SLaurent Vivier tcg_gen_sub_i32(dest, t1, t0);
1672fb5543d8SLaurent Vivier }
1673fb5543d8SLaurent Vivier
bcd_flags(TCGv val)1674fb5543d8SLaurent Vivier static void bcd_flags(TCGv val)
1675fb5543d8SLaurent Vivier {
1676fb5543d8SLaurent Vivier tcg_gen_andi_i32(QREG_CC_C, val, 0x0ff);
1677fb5543d8SLaurent Vivier tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_C);
1678fb5543d8SLaurent Vivier
16790d9acef2SPhilippe Mathieu-Daudé tcg_gen_extract_i32(QREG_CC_C, val, 8, 1);
1680fb5543d8SLaurent Vivier
1681fb5543d8SLaurent Vivier tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
1682fb5543d8SLaurent Vivier }
1683fb5543d8SLaurent Vivier
DISAS_INSN(abcd_reg)1684fb5543d8SLaurent Vivier DISAS_INSN(abcd_reg)
1685fb5543d8SLaurent Vivier {
1686fb5543d8SLaurent Vivier TCGv src;
1687fb5543d8SLaurent Vivier TCGv dest;
1688fb5543d8SLaurent Vivier
1689fb5543d8SLaurent Vivier gen_flush_flags(s); /* !Z is sticky */
1690fb5543d8SLaurent Vivier
16913f215a14SLaurent Vivier src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
16923f215a14SLaurent Vivier dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
1693fb5543d8SLaurent Vivier bcd_add(dest, src);
1694fb5543d8SLaurent Vivier gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1695fb5543d8SLaurent Vivier
1696fb5543d8SLaurent Vivier bcd_flags(dest);
1697fb5543d8SLaurent Vivier }
1698fb5543d8SLaurent Vivier
DISAS_INSN(abcd_mem)1699fb5543d8SLaurent Vivier DISAS_INSN(abcd_mem)
1700fb5543d8SLaurent Vivier {
1701fb5543d8SLaurent Vivier TCGv src, dest, addr;
1702fb5543d8SLaurent Vivier
1703fb5543d8SLaurent Vivier gen_flush_flags(s); /* !Z is sticky */
1704fb5543d8SLaurent Vivier
1705fb5543d8SLaurent Vivier /* Indirect pre-decrement load (mode 4) */
1706fb5543d8SLaurent Vivier
1707fb5543d8SLaurent Vivier src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
170854e1e0b5SLaurent Vivier NULL_QREG, NULL, EA_LOADU, IS_USER(s));
1709fb5543d8SLaurent Vivier dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
171054e1e0b5SLaurent Vivier NULL_QREG, &addr, EA_LOADU, IS_USER(s));
1711fb5543d8SLaurent Vivier
1712fb5543d8SLaurent Vivier bcd_add(dest, src);
1713fb5543d8SLaurent Vivier
171454e1e0b5SLaurent Vivier gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr,
171554e1e0b5SLaurent Vivier EA_STORE, IS_USER(s));
1716fb5543d8SLaurent Vivier
1717fb5543d8SLaurent Vivier bcd_flags(dest);
1718fb5543d8SLaurent Vivier }
1719fb5543d8SLaurent Vivier
DISAS_INSN(sbcd_reg)1720fb5543d8SLaurent Vivier DISAS_INSN(sbcd_reg)
1721fb5543d8SLaurent Vivier {
1722fb5543d8SLaurent Vivier TCGv src, dest;
1723fb5543d8SLaurent Vivier
1724fb5543d8SLaurent Vivier gen_flush_flags(s); /* !Z is sticky */
1725fb5543d8SLaurent Vivier
17263f215a14SLaurent Vivier src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
17273f215a14SLaurent Vivier dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
1728fb5543d8SLaurent Vivier
1729fb5543d8SLaurent Vivier bcd_sub(dest, src);
1730fb5543d8SLaurent Vivier
1731fb5543d8SLaurent Vivier gen_partset_reg(OS_BYTE, DREG(insn, 9), dest);
1732fb5543d8SLaurent Vivier
1733fb5543d8SLaurent Vivier bcd_flags(dest);
1734fb5543d8SLaurent Vivier }
1735fb5543d8SLaurent Vivier
DISAS_INSN(sbcd_mem)1736fb5543d8SLaurent Vivier DISAS_INSN(sbcd_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_sub(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(nbcd)1757fb5543d8SLaurent Vivier DISAS_INSN(nbcd)
1758fb5543d8SLaurent Vivier {
1759fb5543d8SLaurent Vivier TCGv src, dest;
1760fb5543d8SLaurent Vivier TCGv addr;
1761fb5543d8SLaurent Vivier
1762fb5543d8SLaurent Vivier gen_flush_flags(s); /* !Z is sticky */
1763fb5543d8SLaurent Vivier
1764fb5543d8SLaurent Vivier SRC_EA(env, src, OS_BYTE, 0, &addr);
1765fb5543d8SLaurent Vivier
1766b32a07d4SRichard Henderson dest = tcg_temp_new();
1767b32a07d4SRichard Henderson tcg_gen_movi_i32(dest, 0);
1768fb5543d8SLaurent Vivier bcd_sub(dest, src);
1769fb5543d8SLaurent Vivier
1770fb5543d8SLaurent Vivier DEST_EA(env, insn, OS_BYTE, dest, &addr);
1771fb5543d8SLaurent Vivier
1772fb5543d8SLaurent Vivier bcd_flags(dest);
1773fb5543d8SLaurent Vivier }
1774fb5543d8SLaurent Vivier
DISAS_INSN(addsub)1775fcf5ef2aSThomas Huth DISAS_INSN(addsub)
1776fcf5ef2aSThomas Huth {
1777fcf5ef2aSThomas Huth TCGv reg;
1778fcf5ef2aSThomas Huth TCGv dest;
1779fcf5ef2aSThomas Huth TCGv src;
1780fcf5ef2aSThomas Huth TCGv tmp;
1781fcf5ef2aSThomas Huth TCGv addr;
1782fcf5ef2aSThomas Huth int add;
1783fcf5ef2aSThomas Huth int opsize;
1784fcf5ef2aSThomas Huth
1785fcf5ef2aSThomas Huth add = (insn & 0x4000) != 0;
1786fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
17873f215a14SLaurent Vivier reg = gen_extend(s, DREG(insn, 9), opsize, 1);
1788fcf5ef2aSThomas Huth dest = tcg_temp_new();
1789fcf5ef2aSThomas Huth if (insn & 0x100) {
1790fcf5ef2aSThomas Huth SRC_EA(env, tmp, opsize, 1, &addr);
1791fcf5ef2aSThomas Huth src = reg;
1792fcf5ef2aSThomas Huth } else {
1793fcf5ef2aSThomas Huth tmp = reg;
1794fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 1, NULL);
1795fcf5ef2aSThomas Huth }
1796fcf5ef2aSThomas Huth if (add) {
1797fcf5ef2aSThomas Huth tcg_gen_add_i32(dest, tmp, src);
1798fcf5ef2aSThomas Huth tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src);
1799fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_ADDB + opsize);
1800fcf5ef2aSThomas Huth } else {
1801fcf5ef2aSThomas Huth tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src);
1802fcf5ef2aSThomas Huth tcg_gen_sub_i32(dest, tmp, src);
1803fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_SUBB + opsize);
1804fcf5ef2aSThomas Huth }
1805fcf5ef2aSThomas Huth gen_update_cc_add(dest, src, opsize);
1806fcf5ef2aSThomas Huth if (insn & 0x100) {
1807fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, dest, &addr);
1808fcf5ef2aSThomas Huth } else {
1809fcf5ef2aSThomas Huth gen_partset_reg(opsize, DREG(insn, 9), dest);
1810fcf5ef2aSThomas Huth }
1811fcf5ef2aSThomas Huth }
1812fcf5ef2aSThomas Huth
1813fcf5ef2aSThomas Huth /* Reverse the order of the bits in REG. */
DISAS_INSN(bitrev)1814fcf5ef2aSThomas Huth DISAS_INSN(bitrev)
1815fcf5ef2aSThomas Huth {
1816fcf5ef2aSThomas Huth TCGv reg;
1817fcf5ef2aSThomas Huth reg = DREG(insn, 0);
1818fcf5ef2aSThomas Huth gen_helper_bitrev(reg, reg);
1819fcf5ef2aSThomas Huth }
1820fcf5ef2aSThomas Huth
DISAS_INSN(bitop_reg)1821fcf5ef2aSThomas Huth DISAS_INSN(bitop_reg)
1822fcf5ef2aSThomas Huth {
1823fcf5ef2aSThomas Huth int opsize;
1824fcf5ef2aSThomas Huth int op;
1825fcf5ef2aSThomas Huth TCGv src1;
1826fcf5ef2aSThomas Huth TCGv src2;
1827fcf5ef2aSThomas Huth TCGv tmp;
1828fcf5ef2aSThomas Huth TCGv addr;
1829fcf5ef2aSThomas Huth TCGv dest;
1830fcf5ef2aSThomas Huth
1831fcf5ef2aSThomas Huth if ((insn & 0x38) != 0)
1832fcf5ef2aSThomas Huth opsize = OS_BYTE;
1833fcf5ef2aSThomas Huth else
1834fcf5ef2aSThomas Huth opsize = OS_LONG;
1835fcf5ef2aSThomas Huth op = (insn >> 6) & 3;
1836fcf5ef2aSThomas Huth SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
1837fcf5ef2aSThomas Huth
1838fcf5ef2aSThomas Huth gen_flush_flags(s);
1839fcf5ef2aSThomas Huth src2 = tcg_temp_new();
1840fcf5ef2aSThomas Huth if (opsize == OS_BYTE)
1841fcf5ef2aSThomas Huth tcg_gen_andi_i32(src2, DREG(insn, 9), 7);
1842fcf5ef2aSThomas Huth else
1843fcf5ef2aSThomas Huth tcg_gen_andi_i32(src2, DREG(insn, 9), 31);
1844fcf5ef2aSThomas Huth
1845b32a07d4SRichard Henderson tmp = tcg_temp_new();
1846b32a07d4SRichard Henderson tcg_gen_shl_i32(tmp, tcg_constant_i32(1), src2);
1847fcf5ef2aSThomas Huth
1848fcf5ef2aSThomas Huth tcg_gen_and_i32(QREG_CC_Z, src1, tmp);
1849fcf5ef2aSThomas Huth
1850fcf5ef2aSThomas Huth dest = tcg_temp_new();
1851fcf5ef2aSThomas Huth switch (op) {
1852fcf5ef2aSThomas Huth case 1: /* bchg */
1853fcf5ef2aSThomas Huth tcg_gen_xor_i32(dest, src1, tmp);
1854fcf5ef2aSThomas Huth break;
1855fcf5ef2aSThomas Huth case 2: /* bclr */
1856fcf5ef2aSThomas Huth tcg_gen_andc_i32(dest, src1, tmp);
1857fcf5ef2aSThomas Huth break;
1858fcf5ef2aSThomas Huth case 3: /* bset */
1859fcf5ef2aSThomas Huth tcg_gen_or_i32(dest, src1, tmp);
1860fcf5ef2aSThomas Huth break;
1861fcf5ef2aSThomas Huth default: /* btst */
1862fcf5ef2aSThomas Huth break;
1863fcf5ef2aSThomas Huth }
1864fcf5ef2aSThomas Huth if (op) {
1865fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, dest, &addr);
1866fcf5ef2aSThomas Huth }
1867fcf5ef2aSThomas Huth }
1868fcf5ef2aSThomas Huth
DISAS_INSN(sats)1869fcf5ef2aSThomas Huth DISAS_INSN(sats)
1870fcf5ef2aSThomas Huth {
1871fcf5ef2aSThomas Huth TCGv reg;
1872fcf5ef2aSThomas Huth reg = DREG(insn, 0);
1873fcf5ef2aSThomas Huth gen_flush_flags(s);
1874fcf5ef2aSThomas Huth gen_helper_sats(reg, reg, QREG_CC_V);
1875fcf5ef2aSThomas Huth gen_logic_cc(s, reg, OS_LONG);
1876fcf5ef2aSThomas Huth }
1877fcf5ef2aSThomas Huth
gen_push(DisasContext * s,TCGv val)1878fcf5ef2aSThomas Huth static void gen_push(DisasContext *s, TCGv val)
1879fcf5ef2aSThomas Huth {
1880fcf5ef2aSThomas Huth TCGv tmp;
1881fcf5ef2aSThomas Huth
1882fcf5ef2aSThomas Huth tmp = tcg_temp_new();
1883fcf5ef2aSThomas Huth tcg_gen_subi_i32(tmp, QREG_SP, 4);
188454e1e0b5SLaurent Vivier gen_store(s, OS_LONG, tmp, val, IS_USER(s));
1885fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_SP, tmp);
1886fcf5ef2aSThomas Huth }
1887fcf5ef2aSThomas Huth
mreg(int reg)18887b542eb9SLaurent Vivier static TCGv mreg(int reg)
18897b542eb9SLaurent Vivier {
18907b542eb9SLaurent Vivier if (reg < 8) {
18917b542eb9SLaurent Vivier /* Dx */
18927b542eb9SLaurent Vivier return cpu_dregs[reg];
18937b542eb9SLaurent Vivier }
18947b542eb9SLaurent Vivier /* Ax */
18957b542eb9SLaurent Vivier return cpu_aregs[reg & 7];
18967b542eb9SLaurent Vivier }
18977b542eb9SLaurent Vivier
DISAS_INSN(movem)1898fcf5ef2aSThomas Huth DISAS_INSN(movem)
1899fcf5ef2aSThomas Huth {
19007b542eb9SLaurent Vivier TCGv addr, incr, tmp, r[16];
19017b542eb9SLaurent Vivier int is_load = (insn & 0x0400) != 0;
19027b542eb9SLaurent Vivier int opsize = (insn & 0x40) != 0 ? OS_LONG : OS_WORD;
19037b542eb9SLaurent Vivier uint16_t mask = read_im16(env, s);
19047b542eb9SLaurent Vivier int mode = extract32(insn, 3, 3);
19057b542eb9SLaurent Vivier int reg0 = REG(insn, 0);
1906fcf5ef2aSThomas Huth int i;
1907fcf5ef2aSThomas Huth
19087b542eb9SLaurent Vivier tmp = cpu_aregs[reg0];
19097b542eb9SLaurent Vivier
19107b542eb9SLaurent Vivier switch (mode) {
19117b542eb9SLaurent Vivier case 0: /* data register direct */
19127b542eb9SLaurent Vivier case 1: /* addr register direct */
19137b542eb9SLaurent Vivier do_addr_fault:
1914fcf5ef2aSThomas Huth gen_addr_fault(s);
1915fcf5ef2aSThomas Huth return;
19167b542eb9SLaurent Vivier
19177b542eb9SLaurent Vivier case 2: /* indirect */
19187b542eb9SLaurent Vivier break;
19197b542eb9SLaurent Vivier
19207b542eb9SLaurent Vivier case 3: /* indirect post-increment */
19217b542eb9SLaurent Vivier if (!is_load) {
19227b542eb9SLaurent Vivier /* post-increment is not allowed */
19237b542eb9SLaurent Vivier goto do_addr_fault;
1924fcf5ef2aSThomas Huth }
19257b542eb9SLaurent Vivier break;
19267b542eb9SLaurent Vivier
19277b542eb9SLaurent Vivier case 4: /* indirect pre-decrement */
19287b542eb9SLaurent Vivier if (is_load) {
19297b542eb9SLaurent Vivier /* pre-decrement is not allowed */
19307b542eb9SLaurent Vivier goto do_addr_fault;
19317b542eb9SLaurent Vivier }
1932808d77bcSLucien Murray-Pitts /*
1933808d77bcSLucien Murray-Pitts * We want a bare copy of the address reg, without any pre-decrement
1934808d77bcSLucien Murray-Pitts * adjustment, as gen_lea would provide.
1935808d77bcSLucien Murray-Pitts */
19367b542eb9SLaurent Vivier break;
19377b542eb9SLaurent Vivier
19387b542eb9SLaurent Vivier default:
19397b542eb9SLaurent Vivier tmp = gen_lea_mode(env, s, mode, reg0, opsize);
19407b542eb9SLaurent Vivier if (IS_NULL_QREG(tmp)) {
19417b542eb9SLaurent Vivier goto do_addr_fault;
19427b542eb9SLaurent Vivier }
19437b542eb9SLaurent Vivier break;
19447b542eb9SLaurent Vivier }
19457b542eb9SLaurent Vivier
1946fcf5ef2aSThomas Huth addr = tcg_temp_new();
1947fcf5ef2aSThomas Huth tcg_gen_mov_i32(addr, tmp);
19481852ce5aSRichard Henderson incr = tcg_constant_i32(opsize_bytes(opsize));
19497b542eb9SLaurent Vivier
1950fcf5ef2aSThomas Huth if (is_load) {
19517b542eb9SLaurent Vivier /* memory to register */
19527b542eb9SLaurent Vivier for (i = 0; i < 16; i++) {
19537b542eb9SLaurent Vivier if (mask & (1 << i)) {
195454e1e0b5SLaurent Vivier r[i] = gen_load(s, opsize, addr, 1, IS_USER(s));
19557b542eb9SLaurent Vivier tcg_gen_add_i32(addr, addr, incr);
19567b542eb9SLaurent Vivier }
19577b542eb9SLaurent Vivier }
19587b542eb9SLaurent Vivier for (i = 0; i < 16; i++) {
19597b542eb9SLaurent Vivier if (mask & (1 << i)) {
19607b542eb9SLaurent Vivier tcg_gen_mov_i32(mreg(i), r[i]);
19617b542eb9SLaurent Vivier }
19627b542eb9SLaurent Vivier }
19637b542eb9SLaurent Vivier if (mode == 3) {
19647b542eb9SLaurent Vivier /* post-increment: movem (An)+,X */
19657b542eb9SLaurent Vivier tcg_gen_mov_i32(cpu_aregs[reg0], addr);
19667b542eb9SLaurent Vivier }
1967fcf5ef2aSThomas Huth } else {
19687b542eb9SLaurent Vivier /* register to memory */
19697b542eb9SLaurent Vivier if (mode == 4) {
19707b542eb9SLaurent Vivier /* pre-decrement: movem X,-(An) */
19717b542eb9SLaurent Vivier for (i = 15; i >= 0; i--) {
19727b542eb9SLaurent Vivier if ((mask << i) & 0x8000) {
19737b542eb9SLaurent Vivier tcg_gen_sub_i32(addr, addr, incr);
19747b542eb9SLaurent Vivier if (reg0 + 8 == i &&
19757b542eb9SLaurent Vivier m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) {
1976808d77bcSLucien Murray-Pitts /*
1977808d77bcSLucien Murray-Pitts * M68020+: if the addressing register is the
19787b542eb9SLaurent Vivier * register moved to memory, the value written
19797b542eb9SLaurent Vivier * is the initial value decremented by the size of
19807b542eb9SLaurent Vivier * the operation, regardless of how many actual
19817b542eb9SLaurent Vivier * stores have been performed until this point.
19827b542eb9SLaurent Vivier * M68000/M68010: the value is the initial value.
19837b542eb9SLaurent Vivier */
19847b542eb9SLaurent Vivier tmp = tcg_temp_new();
19857b542eb9SLaurent Vivier tcg_gen_sub_i32(tmp, cpu_aregs[reg0], incr);
198654e1e0b5SLaurent Vivier gen_store(s, opsize, addr, tmp, IS_USER(s));
19877b542eb9SLaurent Vivier } else {
198854e1e0b5SLaurent Vivier gen_store(s, opsize, addr, mreg(i), IS_USER(s));
1989fcf5ef2aSThomas Huth }
1990fcf5ef2aSThomas Huth }
1991fcf5ef2aSThomas Huth }
19927b542eb9SLaurent Vivier tcg_gen_mov_i32(cpu_aregs[reg0], addr);
19937b542eb9SLaurent Vivier } else {
19947b542eb9SLaurent Vivier for (i = 0; i < 16; i++) {
19957b542eb9SLaurent Vivier if (mask & (1 << i)) {
199654e1e0b5SLaurent Vivier gen_store(s, opsize, addr, mreg(i), IS_USER(s));
19977b542eb9SLaurent Vivier tcg_gen_add_i32(addr, addr, incr);
19987b542eb9SLaurent Vivier }
19997b542eb9SLaurent Vivier }
20007b542eb9SLaurent Vivier }
20017b542eb9SLaurent Vivier }
20027b542eb9SLaurent Vivier }
2003fcf5ef2aSThomas Huth
DISAS_INSN(movep)20041226e212SPavel Dovgalyuk DISAS_INSN(movep)
20051226e212SPavel Dovgalyuk {
20061226e212SPavel Dovgalyuk uint8_t i;
20071226e212SPavel Dovgalyuk int16_t displ;
20081226e212SPavel Dovgalyuk TCGv reg;
20091226e212SPavel Dovgalyuk TCGv addr;
20101226e212SPavel Dovgalyuk TCGv abuf;
20111226e212SPavel Dovgalyuk TCGv dbuf;
20121226e212SPavel Dovgalyuk
20131226e212SPavel Dovgalyuk displ = read_im16(env, s);
20141226e212SPavel Dovgalyuk
20151226e212SPavel Dovgalyuk addr = AREG(insn, 0);
20161226e212SPavel Dovgalyuk reg = DREG(insn, 9);
20171226e212SPavel Dovgalyuk
20181226e212SPavel Dovgalyuk abuf = tcg_temp_new();
20191226e212SPavel Dovgalyuk tcg_gen_addi_i32(abuf, addr, displ);
20201226e212SPavel Dovgalyuk dbuf = tcg_temp_new();
20211226e212SPavel Dovgalyuk
20221226e212SPavel Dovgalyuk if (insn & 0x40) {
20231226e212SPavel Dovgalyuk i = 4;
20241226e212SPavel Dovgalyuk } else {
20251226e212SPavel Dovgalyuk i = 2;
20261226e212SPavel Dovgalyuk }
20271226e212SPavel Dovgalyuk
20281226e212SPavel Dovgalyuk if (insn & 0x80) {
20291226e212SPavel Dovgalyuk for ( ; i > 0 ; i--) {
20301226e212SPavel Dovgalyuk tcg_gen_shri_i32(dbuf, reg, (i - 1) * 8);
2031b7a94da9SRichard Henderson tcg_gen_qemu_st_i32(dbuf, abuf, IS_USER(s), MO_UB);
20321226e212SPavel Dovgalyuk if (i > 1) {
20331226e212SPavel Dovgalyuk tcg_gen_addi_i32(abuf, abuf, 2);
20341226e212SPavel Dovgalyuk }
20351226e212SPavel Dovgalyuk }
20361226e212SPavel Dovgalyuk } else {
20371226e212SPavel Dovgalyuk for ( ; i > 0 ; i--) {
2038b7a94da9SRichard Henderson tcg_gen_qemu_ld_tl(dbuf, abuf, IS_USER(s), MO_UB);
20391226e212SPavel Dovgalyuk tcg_gen_deposit_i32(reg, reg, dbuf, (i - 1) * 8, 8);
20401226e212SPavel Dovgalyuk if (i > 1) {
20411226e212SPavel Dovgalyuk tcg_gen_addi_i32(abuf, abuf, 2);
20421226e212SPavel Dovgalyuk }
20431226e212SPavel Dovgalyuk }
20441226e212SPavel Dovgalyuk }
20451226e212SPavel Dovgalyuk }
20461226e212SPavel Dovgalyuk
DISAS_INSN(bitop_im)2047fcf5ef2aSThomas Huth DISAS_INSN(bitop_im)
2048fcf5ef2aSThomas Huth {
2049fcf5ef2aSThomas Huth int opsize;
2050fcf5ef2aSThomas Huth int op;
2051fcf5ef2aSThomas Huth TCGv src1;
2052fcf5ef2aSThomas Huth uint32_t mask;
2053fcf5ef2aSThomas Huth int bitnum;
2054fcf5ef2aSThomas Huth TCGv tmp;
2055fcf5ef2aSThomas Huth TCGv addr;
2056fcf5ef2aSThomas Huth
2057fcf5ef2aSThomas Huth if ((insn & 0x38) != 0)
2058fcf5ef2aSThomas Huth opsize = OS_BYTE;
2059fcf5ef2aSThomas Huth else
2060fcf5ef2aSThomas Huth opsize = OS_LONG;
2061fcf5ef2aSThomas Huth op = (insn >> 6) & 3;
2062fcf5ef2aSThomas Huth
2063fcf5ef2aSThomas Huth bitnum = read_im16(env, s);
2064aece90d8SMark Cave-Ayland if (m68k_feature(s->env, M68K_FEATURE_M68K)) {
2065fe53c2beSLaurent Vivier if (bitnum & 0xfe00) {
2066fe53c2beSLaurent Vivier disas_undef(env, s, insn);
2067fe53c2beSLaurent Vivier return;
2068fe53c2beSLaurent Vivier }
2069fe53c2beSLaurent Vivier } else {
2070fcf5ef2aSThomas Huth if (bitnum & 0xff00) {
2071fcf5ef2aSThomas Huth disas_undef(env, s, insn);
2072fcf5ef2aSThomas Huth return;
2073fcf5ef2aSThomas Huth }
2074fe53c2beSLaurent Vivier }
2075fcf5ef2aSThomas Huth
2076fcf5ef2aSThomas Huth SRC_EA(env, src1, opsize, 0, op ? &addr: NULL);
2077fcf5ef2aSThomas Huth
2078fcf5ef2aSThomas Huth gen_flush_flags(s);
2079fcf5ef2aSThomas Huth if (opsize == OS_BYTE)
2080fcf5ef2aSThomas Huth bitnum &= 7;
2081fcf5ef2aSThomas Huth else
2082fcf5ef2aSThomas Huth bitnum &= 31;
2083fcf5ef2aSThomas Huth mask = 1 << bitnum;
2084fcf5ef2aSThomas Huth
2085fcf5ef2aSThomas Huth tcg_gen_andi_i32(QREG_CC_Z, src1, mask);
2086fcf5ef2aSThomas Huth
2087fcf5ef2aSThomas Huth if (op) {
2088fcf5ef2aSThomas Huth tmp = tcg_temp_new();
2089fcf5ef2aSThomas Huth switch (op) {
2090fcf5ef2aSThomas Huth case 1: /* bchg */
2091fcf5ef2aSThomas Huth tcg_gen_xori_i32(tmp, src1, mask);
2092fcf5ef2aSThomas Huth break;
2093fcf5ef2aSThomas Huth case 2: /* bclr */
2094fcf5ef2aSThomas Huth tcg_gen_andi_i32(tmp, src1, ~mask);
2095fcf5ef2aSThomas Huth break;
2096fcf5ef2aSThomas Huth case 3: /* bset */
2097fcf5ef2aSThomas Huth tcg_gen_ori_i32(tmp, src1, mask);
2098fcf5ef2aSThomas Huth break;
2099fcf5ef2aSThomas Huth default: /* btst */
2100fcf5ef2aSThomas Huth break;
2101fcf5ef2aSThomas Huth }
2102fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, tmp, &addr);
2103fcf5ef2aSThomas Huth }
2104fcf5ef2aSThomas Huth }
2105fcf5ef2aSThomas Huth
gen_get_ccr(DisasContext * s)210601490ea8SLaurent Vivier static TCGv gen_get_ccr(DisasContext *s)
210701490ea8SLaurent Vivier {
210801490ea8SLaurent Vivier TCGv dest;
210901490ea8SLaurent Vivier
211001490ea8SLaurent Vivier update_cc_op(s);
211101490ea8SLaurent Vivier dest = tcg_temp_new();
2112ad75a51eSRichard Henderson gen_helper_get_ccr(dest, tcg_env);
211301490ea8SLaurent Vivier return dest;
211401490ea8SLaurent Vivier }
211501490ea8SLaurent Vivier
gen_get_sr(DisasContext * s)211601490ea8SLaurent Vivier static TCGv gen_get_sr(DisasContext *s)
211701490ea8SLaurent Vivier {
211801490ea8SLaurent Vivier TCGv ccr;
211901490ea8SLaurent Vivier TCGv sr;
212001490ea8SLaurent Vivier
212101490ea8SLaurent Vivier ccr = gen_get_ccr(s);
212201490ea8SLaurent Vivier sr = tcg_temp_new();
212301490ea8SLaurent Vivier tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
212401490ea8SLaurent Vivier tcg_gen_or_i32(sr, sr, ccr);
212501490ea8SLaurent Vivier return sr;
212601490ea8SLaurent Vivier }
212701490ea8SLaurent Vivier
gen_set_sr_im(DisasContext * s,uint16_t val,int ccr_only)212801490ea8SLaurent Vivier static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
212901490ea8SLaurent Vivier {
213001490ea8SLaurent Vivier if (ccr_only) {
213101490ea8SLaurent Vivier tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0);
213201490ea8SLaurent Vivier tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0);
213301490ea8SLaurent Vivier tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1);
213401490ea8SLaurent Vivier tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0);
213501490ea8SLaurent Vivier tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0);
213601490ea8SLaurent Vivier } else {
2137214c6002SRichard Henderson /* Must writeback before changing security state. */
2138214c6002SRichard Henderson do_writebacks(s);
2139ad75a51eSRichard Henderson gen_helper_set_sr(tcg_env, tcg_constant_i32(val));
214001490ea8SLaurent Vivier }
214101490ea8SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
214201490ea8SLaurent Vivier }
214301490ea8SLaurent Vivier
gen_set_sr(DisasContext * s,TCGv val,int ccr_only)2144b6a21d8dSLaurent Vivier static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only)
214501490ea8SLaurent Vivier {
214601490ea8SLaurent Vivier if (ccr_only) {
2147ad75a51eSRichard Henderson gen_helper_set_ccr(tcg_env, val);
214801490ea8SLaurent Vivier } else {
2149214c6002SRichard Henderson /* Must writeback before changing security state. */
2150214c6002SRichard Henderson do_writebacks(s);
2151ad75a51eSRichard Henderson gen_helper_set_sr(tcg_env, val);
215201490ea8SLaurent Vivier }
215301490ea8SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
2154b6a21d8dSLaurent Vivier }
2155b6a21d8dSLaurent Vivier
gen_move_to_sr(CPUM68KState * env,DisasContext * s,uint16_t insn,bool ccr_only)2156b6a21d8dSLaurent Vivier static void gen_move_to_sr(CPUM68KState *env, DisasContext *s, uint16_t insn,
2157b6a21d8dSLaurent Vivier bool ccr_only)
2158b6a21d8dSLaurent Vivier {
2159b6a21d8dSLaurent Vivier if ((insn & 0x3f) == 0x3c) {
216001490ea8SLaurent Vivier uint16_t val;
216101490ea8SLaurent Vivier val = read_im16(env, s);
216201490ea8SLaurent Vivier gen_set_sr_im(s, val, ccr_only);
216301490ea8SLaurent Vivier } else {
2164b6a21d8dSLaurent Vivier TCGv src;
2165b6a21d8dSLaurent Vivier SRC_EA(env, src, OS_WORD, 0, NULL);
2166b6a21d8dSLaurent Vivier gen_set_sr(s, src, ccr_only);
216701490ea8SLaurent Vivier }
216801490ea8SLaurent Vivier }
216901490ea8SLaurent Vivier
DISAS_INSN(arith_im)2170fcf5ef2aSThomas Huth DISAS_INSN(arith_im)
2171fcf5ef2aSThomas Huth {
2172fcf5ef2aSThomas Huth int op;
2173fcf5ef2aSThomas Huth TCGv im;
2174fcf5ef2aSThomas Huth TCGv src1;
2175fcf5ef2aSThomas Huth TCGv dest;
2176fcf5ef2aSThomas Huth TCGv addr;
2177fcf5ef2aSThomas Huth int opsize;
2178b5ae1edcSLaurent Vivier bool with_SR = ((insn & 0x3f) == 0x3c);
2179fcf5ef2aSThomas Huth
2180fcf5ef2aSThomas Huth op = (insn >> 9) & 7;
2181fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
2182fcf5ef2aSThomas Huth switch (opsize) {
2183fcf5ef2aSThomas Huth case OS_BYTE:
21841852ce5aSRichard Henderson im = tcg_constant_i32((int8_t)read_im8(env, s));
2185fcf5ef2aSThomas Huth break;
2186fcf5ef2aSThomas Huth case OS_WORD:
21871852ce5aSRichard Henderson im = tcg_constant_i32((int16_t)read_im16(env, s));
2188fcf5ef2aSThomas Huth break;
2189fcf5ef2aSThomas Huth case OS_LONG:
21901852ce5aSRichard Henderson im = tcg_constant_i32(read_im32(env, s));
2191fcf5ef2aSThomas Huth break;
2192fcf5ef2aSThomas Huth default:
21935cbc6111SRichard Henderson g_assert_not_reached();
2194fcf5ef2aSThomas Huth }
2195b5ae1edcSLaurent Vivier
2196b5ae1edcSLaurent Vivier if (with_SR) {
2197b5ae1edcSLaurent Vivier /* SR/CCR can only be used with andi/eori/ori */
2198b5ae1edcSLaurent Vivier if (op == 2 || op == 3 || op == 6) {
2199b5ae1edcSLaurent Vivier disas_undef(env, s, insn);
2200b5ae1edcSLaurent Vivier return;
2201b5ae1edcSLaurent Vivier }
2202b5ae1edcSLaurent Vivier switch (opsize) {
2203b5ae1edcSLaurent Vivier case OS_BYTE:
2204b5ae1edcSLaurent Vivier src1 = gen_get_ccr(s);
2205b5ae1edcSLaurent Vivier break;
2206b5ae1edcSLaurent Vivier case OS_WORD:
2207b5ae1edcSLaurent Vivier if (IS_USER(s)) {
2208a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
2209b5ae1edcSLaurent Vivier return;
2210b5ae1edcSLaurent Vivier }
2211b5ae1edcSLaurent Vivier src1 = gen_get_sr(s);
2212b5ae1edcSLaurent Vivier break;
22135cbc6111SRichard Henderson default:
22145cbc6111SRichard Henderson /* OS_LONG; others already g_assert_not_reached. */
2215b5ae1edcSLaurent Vivier disas_undef(env, s, insn);
2216b5ae1edcSLaurent Vivier return;
2217b5ae1edcSLaurent Vivier }
2218b5ae1edcSLaurent Vivier } else {
2219fcf5ef2aSThomas Huth SRC_EA(env, src1, opsize, 1, (op == 6) ? NULL : &addr);
2220b5ae1edcSLaurent Vivier }
2221fcf5ef2aSThomas Huth dest = tcg_temp_new();
2222fcf5ef2aSThomas Huth switch (op) {
2223fcf5ef2aSThomas Huth case 0: /* ori */
2224fcf5ef2aSThomas Huth tcg_gen_or_i32(dest, src1, im);
2225b5ae1edcSLaurent Vivier if (with_SR) {
2226b5ae1edcSLaurent Vivier gen_set_sr(s, dest, opsize == OS_BYTE);
2227c7546abfSMark Cave-Ayland gen_exit_tb(s);
2228b5ae1edcSLaurent Vivier } else {
2229b5ae1edcSLaurent Vivier DEST_EA(env, insn, opsize, dest, &addr);
2230fcf5ef2aSThomas Huth gen_logic_cc(s, dest, opsize);
2231b5ae1edcSLaurent Vivier }
2232fcf5ef2aSThomas Huth break;
2233fcf5ef2aSThomas Huth case 1: /* andi */
2234fcf5ef2aSThomas Huth tcg_gen_and_i32(dest, src1, im);
2235b5ae1edcSLaurent Vivier if (with_SR) {
2236b5ae1edcSLaurent Vivier gen_set_sr(s, dest, opsize == OS_BYTE);
2237c7546abfSMark Cave-Ayland gen_exit_tb(s);
2238b5ae1edcSLaurent Vivier } else {
2239b5ae1edcSLaurent Vivier DEST_EA(env, insn, opsize, dest, &addr);
2240fcf5ef2aSThomas Huth gen_logic_cc(s, dest, opsize);
2241b5ae1edcSLaurent Vivier }
2242fcf5ef2aSThomas Huth break;
2243fcf5ef2aSThomas Huth case 2: /* subi */
2244fcf5ef2aSThomas Huth tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, src1, im);
2245fcf5ef2aSThomas Huth tcg_gen_sub_i32(dest, src1, im);
2246fcf5ef2aSThomas Huth gen_update_cc_add(dest, im, opsize);
2247fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_SUBB + opsize);
2248b5ae1edcSLaurent Vivier DEST_EA(env, insn, opsize, dest, &addr);
2249fcf5ef2aSThomas Huth break;
2250fcf5ef2aSThomas Huth case 3: /* addi */
2251fcf5ef2aSThomas Huth tcg_gen_add_i32(dest, src1, im);
2252fcf5ef2aSThomas Huth gen_update_cc_add(dest, im, opsize);
2253fcf5ef2aSThomas Huth tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, im);
2254fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_ADDB + opsize);
2255b5ae1edcSLaurent Vivier DEST_EA(env, insn, opsize, dest, &addr);
2256fcf5ef2aSThomas Huth break;
2257fcf5ef2aSThomas Huth case 5: /* eori */
2258fcf5ef2aSThomas Huth tcg_gen_xor_i32(dest, src1, im);
2259b5ae1edcSLaurent Vivier if (with_SR) {
2260b5ae1edcSLaurent Vivier gen_set_sr(s, dest, opsize == OS_BYTE);
2261c7546abfSMark Cave-Ayland gen_exit_tb(s);
2262b5ae1edcSLaurent Vivier } else {
2263b5ae1edcSLaurent Vivier DEST_EA(env, insn, opsize, dest, &addr);
2264fcf5ef2aSThomas Huth gen_logic_cc(s, dest, opsize);
2265b5ae1edcSLaurent Vivier }
2266fcf5ef2aSThomas Huth break;
2267fcf5ef2aSThomas Huth case 6: /* cmpi */
2268fcf5ef2aSThomas Huth gen_update_cc_cmp(s, src1, im, opsize);
2269fcf5ef2aSThomas Huth break;
2270fcf5ef2aSThomas Huth default:
2271fcf5ef2aSThomas Huth abort();
2272fcf5ef2aSThomas Huth }
2273fcf5ef2aSThomas Huth }
2274fcf5ef2aSThomas Huth
DISAS_INSN(cas)227514f94406SLaurent Vivier DISAS_INSN(cas)
227614f94406SLaurent Vivier {
227714f94406SLaurent Vivier int opsize;
227814f94406SLaurent Vivier TCGv addr;
227914f94406SLaurent Vivier uint16_t ext;
228014f94406SLaurent Vivier TCGv load;
228114f94406SLaurent Vivier TCGv cmp;
228214776ab5STony Nguyen MemOp opc;
228314f94406SLaurent Vivier
228414f94406SLaurent Vivier switch ((insn >> 9) & 3) {
228514f94406SLaurent Vivier case 1:
228614f94406SLaurent Vivier opsize = OS_BYTE;
228714f94406SLaurent Vivier opc = MO_SB;
228814f94406SLaurent Vivier break;
228914f94406SLaurent Vivier case 2:
229014f94406SLaurent Vivier opsize = OS_WORD;
229114f94406SLaurent Vivier opc = MO_TESW;
229214f94406SLaurent Vivier break;
229314f94406SLaurent Vivier case 3:
229414f94406SLaurent Vivier opsize = OS_LONG;
229514f94406SLaurent Vivier opc = MO_TESL;
229614f94406SLaurent Vivier break;
229714f94406SLaurent Vivier default:
229814f94406SLaurent Vivier g_assert_not_reached();
229914f94406SLaurent Vivier }
230014f94406SLaurent Vivier
230114f94406SLaurent Vivier ext = read_im16(env, s);
230214f94406SLaurent Vivier
230314f94406SLaurent Vivier /* cas Dc,Du,<EA> */
230414f94406SLaurent Vivier
230514f94406SLaurent Vivier addr = gen_lea(env, s, insn, opsize);
230614f94406SLaurent Vivier if (IS_NULL_QREG(addr)) {
230714f94406SLaurent Vivier gen_addr_fault(s);
230814f94406SLaurent Vivier return;
230914f94406SLaurent Vivier }
231014f94406SLaurent Vivier
23113f215a14SLaurent Vivier cmp = gen_extend(s, DREG(ext, 0), opsize, 1);
231214f94406SLaurent Vivier
2313808d77bcSLucien Murray-Pitts /*
2314808d77bcSLucien Murray-Pitts * if <EA> == Dc then
231514f94406SLaurent Vivier * <EA> = Du
231614f94406SLaurent Vivier * Dc = <EA> (because <EA> == Dc)
231714f94406SLaurent Vivier * else
231814f94406SLaurent Vivier * Dc = <EA>
231914f94406SLaurent Vivier */
232014f94406SLaurent Vivier
232114f94406SLaurent Vivier load = tcg_temp_new();
232214f94406SLaurent Vivier tcg_gen_atomic_cmpxchg_i32(load, addr, cmp, DREG(ext, 6),
232314f94406SLaurent Vivier IS_USER(s), opc);
232414f94406SLaurent Vivier /* update flags before setting cmp to load */
232514f94406SLaurent Vivier gen_update_cc_cmp(s, load, cmp, opsize);
232614f94406SLaurent Vivier gen_partset_reg(opsize, DREG(ext, 0), load);
232714f94406SLaurent Vivier
2328308feb93SLaurent Vivier switch (extract32(insn, 3, 3)) {
2329308feb93SLaurent Vivier case 3: /* Indirect postincrement. */
2330308feb93SLaurent Vivier tcg_gen_addi_i32(AREG(insn, 0), addr, opsize_bytes(opsize));
2331308feb93SLaurent Vivier break;
2332308feb93SLaurent Vivier case 4: /* Indirect predecrememnt. */
2333308feb93SLaurent Vivier tcg_gen_mov_i32(AREG(insn, 0), addr);
2334308feb93SLaurent Vivier break;
2335308feb93SLaurent Vivier }
233614f94406SLaurent Vivier }
233714f94406SLaurent Vivier
DISAS_INSN(cas2w)233814f94406SLaurent Vivier DISAS_INSN(cas2w)
233914f94406SLaurent Vivier {
234014f94406SLaurent Vivier uint16_t ext1, ext2;
234114f94406SLaurent Vivier TCGv addr1, addr2;
234214f94406SLaurent Vivier
234314f94406SLaurent Vivier /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
234414f94406SLaurent Vivier
234514f94406SLaurent Vivier ext1 = read_im16(env, s);
234614f94406SLaurent Vivier
234714f94406SLaurent Vivier if (ext1 & 0x8000) {
234814f94406SLaurent Vivier /* Address Register */
234914f94406SLaurent Vivier addr1 = AREG(ext1, 12);
235014f94406SLaurent Vivier } else {
235114f94406SLaurent Vivier /* Data Register */
235214f94406SLaurent Vivier addr1 = DREG(ext1, 12);
235314f94406SLaurent Vivier }
235414f94406SLaurent Vivier
235514f94406SLaurent Vivier ext2 = read_im16(env, s);
235614f94406SLaurent Vivier if (ext2 & 0x8000) {
235714f94406SLaurent Vivier /* Address Register */
235814f94406SLaurent Vivier addr2 = AREG(ext2, 12);
235914f94406SLaurent Vivier } else {
236014f94406SLaurent Vivier /* Data Register */
236114f94406SLaurent Vivier addr2 = DREG(ext2, 12);
236214f94406SLaurent Vivier }
236314f94406SLaurent Vivier
2364808d77bcSLucien Murray-Pitts /*
2365808d77bcSLucien Murray-Pitts * if (R1) == Dc1 && (R2) == Dc2 then
236614f94406SLaurent Vivier * (R1) = Du1
236714f94406SLaurent Vivier * (R2) = Du2
236814f94406SLaurent Vivier * else
236914f94406SLaurent Vivier * Dc1 = (R1)
237014f94406SLaurent Vivier * Dc2 = (R2)
237114f94406SLaurent Vivier */
237214f94406SLaurent Vivier
2373a575cbe0SRichard Henderson if (tb_cflags(s->base.tb) & CF_PARALLEL) {
2374ad75a51eSRichard Henderson gen_helper_exit_atomic(tcg_env);
2375f0ddf11bSEmilio G. Cota } else {
23761852ce5aSRichard Henderson TCGv regs = tcg_constant_i32(REG(ext2, 6) |
23771852ce5aSRichard Henderson (REG(ext1, 6) << 3) |
23781852ce5aSRichard Henderson (REG(ext2, 0) << 6) |
23791852ce5aSRichard Henderson (REG(ext1, 0) << 9));
2380ad75a51eSRichard Henderson gen_helper_cas2w(tcg_env, regs, addr1, addr2);
2381f0ddf11bSEmilio G. Cota }
238214f94406SLaurent Vivier
238314f94406SLaurent Vivier /* Note that cas2w also assigned to env->cc_op. */
238414f94406SLaurent Vivier s->cc_op = CC_OP_CMPW;
238514f94406SLaurent Vivier s->cc_op_synced = 1;
238614f94406SLaurent Vivier }
238714f94406SLaurent Vivier
DISAS_INSN(cas2l)238814f94406SLaurent Vivier DISAS_INSN(cas2l)
238914f94406SLaurent Vivier {
239014f94406SLaurent Vivier uint16_t ext1, ext2;
239114f94406SLaurent Vivier TCGv addr1, addr2, regs;
239214f94406SLaurent Vivier
239314f94406SLaurent Vivier /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */
239414f94406SLaurent Vivier
239514f94406SLaurent Vivier ext1 = read_im16(env, s);
239614f94406SLaurent Vivier
239714f94406SLaurent Vivier if (ext1 & 0x8000) {
239814f94406SLaurent Vivier /* Address Register */
239914f94406SLaurent Vivier addr1 = AREG(ext1, 12);
240014f94406SLaurent Vivier } else {
240114f94406SLaurent Vivier /* Data Register */
240214f94406SLaurent Vivier addr1 = DREG(ext1, 12);
240314f94406SLaurent Vivier }
240414f94406SLaurent Vivier
240514f94406SLaurent Vivier ext2 = read_im16(env, s);
240614f94406SLaurent Vivier if (ext2 & 0x8000) {
240714f94406SLaurent Vivier /* Address Register */
240814f94406SLaurent Vivier addr2 = AREG(ext2, 12);
240914f94406SLaurent Vivier } else {
241014f94406SLaurent Vivier /* Data Register */
241114f94406SLaurent Vivier addr2 = DREG(ext2, 12);
241214f94406SLaurent Vivier }
241314f94406SLaurent Vivier
2414808d77bcSLucien Murray-Pitts /*
2415808d77bcSLucien Murray-Pitts * if (R1) == Dc1 && (R2) == Dc2 then
241614f94406SLaurent Vivier * (R1) = Du1
241714f94406SLaurent Vivier * (R2) = Du2
241814f94406SLaurent Vivier * else
241914f94406SLaurent Vivier * Dc1 = (R1)
242014f94406SLaurent Vivier * Dc2 = (R2)
242114f94406SLaurent Vivier */
242214f94406SLaurent Vivier
24231852ce5aSRichard Henderson regs = tcg_constant_i32(REG(ext2, 6) |
242414f94406SLaurent Vivier (REG(ext1, 6) << 3) |
242514f94406SLaurent Vivier (REG(ext2, 0) << 6) |
242614f94406SLaurent Vivier (REG(ext1, 0) << 9));
2427a575cbe0SRichard Henderson if (tb_cflags(s->base.tb) & CF_PARALLEL) {
2428ad75a51eSRichard Henderson gen_helper_cas2l_parallel(tcg_env, regs, addr1, addr2);
2429f0ddf11bSEmilio G. Cota } else {
2430ad75a51eSRichard Henderson gen_helper_cas2l(tcg_env, regs, addr1, addr2);
2431f0ddf11bSEmilio G. Cota }
243214f94406SLaurent Vivier
243314f94406SLaurent Vivier /* Note that cas2l also assigned to env->cc_op. */
243414f94406SLaurent Vivier s->cc_op = CC_OP_CMPL;
243514f94406SLaurent Vivier s->cc_op_synced = 1;
243614f94406SLaurent Vivier }
243714f94406SLaurent Vivier
DISAS_INSN(byterev)2438fcf5ef2aSThomas Huth DISAS_INSN(byterev)
2439fcf5ef2aSThomas Huth {
2440fcf5ef2aSThomas Huth TCGv reg;
2441fcf5ef2aSThomas Huth
2442fcf5ef2aSThomas Huth reg = DREG(insn, 0);
2443fcf5ef2aSThomas Huth tcg_gen_bswap32_i32(reg, reg);
2444fcf5ef2aSThomas Huth }
2445fcf5ef2aSThomas Huth
DISAS_INSN(move)2446fcf5ef2aSThomas Huth DISAS_INSN(move)
2447fcf5ef2aSThomas Huth {
2448fcf5ef2aSThomas Huth TCGv src;
2449fcf5ef2aSThomas Huth TCGv dest;
2450fcf5ef2aSThomas Huth int op;
2451fcf5ef2aSThomas Huth int opsize;
2452fcf5ef2aSThomas Huth
2453fcf5ef2aSThomas Huth switch (insn >> 12) {
2454fcf5ef2aSThomas Huth case 1: /* move.b */
2455fcf5ef2aSThomas Huth opsize = OS_BYTE;
2456fcf5ef2aSThomas Huth break;
2457fcf5ef2aSThomas Huth case 2: /* move.l */
2458fcf5ef2aSThomas Huth opsize = OS_LONG;
2459fcf5ef2aSThomas Huth break;
2460fcf5ef2aSThomas Huth case 3: /* move.w */
2461fcf5ef2aSThomas Huth opsize = OS_WORD;
2462fcf5ef2aSThomas Huth break;
2463fcf5ef2aSThomas Huth default:
2464fcf5ef2aSThomas Huth abort();
2465fcf5ef2aSThomas Huth }
2466fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 1, NULL);
2467fcf5ef2aSThomas Huth op = (insn >> 6) & 7;
2468fcf5ef2aSThomas Huth if (op == 1) {
2469fcf5ef2aSThomas Huth /* movea */
2470fcf5ef2aSThomas Huth /* The value will already have been sign extended. */
2471fcf5ef2aSThomas Huth dest = AREG(insn, 9);
2472fcf5ef2aSThomas Huth tcg_gen_mov_i32(dest, src);
2473fcf5ef2aSThomas Huth } else {
2474fcf5ef2aSThomas Huth /* normal move */
2475fcf5ef2aSThomas Huth uint16_t dest_ea;
2476fcf5ef2aSThomas Huth dest_ea = ((insn >> 9) & 7) | (op << 3);
2477fcf5ef2aSThomas Huth DEST_EA(env, dest_ea, opsize, src, NULL);
2478fcf5ef2aSThomas Huth /* This will be correct because loads sign extend. */
2479fcf5ef2aSThomas Huth gen_logic_cc(s, src, opsize);
2480fcf5ef2aSThomas Huth }
2481fcf5ef2aSThomas Huth }
2482fcf5ef2aSThomas Huth
DISAS_INSN(negx)2483fcf5ef2aSThomas Huth DISAS_INSN(negx)
2484fcf5ef2aSThomas Huth {
2485fcf5ef2aSThomas Huth TCGv z;
2486fcf5ef2aSThomas Huth TCGv src;
2487fcf5ef2aSThomas Huth TCGv addr;
2488fcf5ef2aSThomas Huth int opsize;
2489fcf5ef2aSThomas Huth
2490fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
2491fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 1, &addr);
2492fcf5ef2aSThomas Huth
2493fcf5ef2aSThomas Huth gen_flush_flags(s); /* compute old Z */
2494fcf5ef2aSThomas Huth
2495808d77bcSLucien Murray-Pitts /*
2496ce00ff72Szhaolichang * Perform subtract with borrow.
2497fcf5ef2aSThomas Huth * (X, N) = -(src + X);
2498fcf5ef2aSThomas Huth */
2499fcf5ef2aSThomas Huth
25001852ce5aSRichard Henderson z = tcg_constant_i32(0);
2501fcf5ef2aSThomas Huth tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z);
2502fcf5ef2aSThomas Huth tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X);
2503fcf5ef2aSThomas Huth gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
2504fcf5ef2aSThomas Huth
2505fcf5ef2aSThomas Huth tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
2506fcf5ef2aSThomas Huth
2507808d77bcSLucien Murray-Pitts /*
2508808d77bcSLucien Murray-Pitts * Compute signed-overflow for negation. The normal formula for
2509fcf5ef2aSThomas Huth * subtraction is (res ^ src) & (src ^ dest), but with dest==0
2510ce00ff72Szhaolichang * this simplifies to res & src.
2511fcf5ef2aSThomas Huth */
2512fcf5ef2aSThomas Huth
2513fcf5ef2aSThomas Huth tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, src);
2514fcf5ef2aSThomas Huth
2515fcf5ef2aSThomas Huth /* Copy the rest of the results into place. */
2516fcf5ef2aSThomas Huth tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
2517fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
2518fcf5ef2aSThomas Huth
2519fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_FLAGS);
2520fcf5ef2aSThomas Huth
2521fcf5ef2aSThomas Huth /* result is in QREG_CC_N */
2522fcf5ef2aSThomas Huth
2523fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, QREG_CC_N, &addr);
2524fcf5ef2aSThomas Huth }
2525fcf5ef2aSThomas Huth
DISAS_INSN(lea)2526fcf5ef2aSThomas Huth DISAS_INSN(lea)
2527fcf5ef2aSThomas Huth {
2528fcf5ef2aSThomas Huth TCGv reg;
2529fcf5ef2aSThomas Huth TCGv tmp;
2530fcf5ef2aSThomas Huth
2531fcf5ef2aSThomas Huth reg = AREG(insn, 9);
2532fcf5ef2aSThomas Huth tmp = gen_lea(env, s, insn, OS_LONG);
2533fcf5ef2aSThomas Huth if (IS_NULL_QREG(tmp)) {
2534fcf5ef2aSThomas Huth gen_addr_fault(s);
2535fcf5ef2aSThomas Huth return;
2536fcf5ef2aSThomas Huth }
2537fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, tmp);
2538fcf5ef2aSThomas Huth }
2539fcf5ef2aSThomas Huth
DISAS_INSN(clr)2540fcf5ef2aSThomas Huth DISAS_INSN(clr)
2541fcf5ef2aSThomas Huth {
2542fcf5ef2aSThomas Huth int opsize;
25432b5e2170SLaurent Vivier TCGv zero;
25442b5e2170SLaurent Vivier
25451852ce5aSRichard Henderson zero = tcg_constant_i32(0);
2546fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
25472b5e2170SLaurent Vivier DEST_EA(env, insn, opsize, zero, NULL);
25482b5e2170SLaurent Vivier gen_logic_cc(s, zero, opsize);
2549fcf5ef2aSThomas Huth }
2550fcf5ef2aSThomas Huth
DISAS_INSN(move_from_ccr)2551fcf5ef2aSThomas Huth DISAS_INSN(move_from_ccr)
2552fcf5ef2aSThomas Huth {
2553fcf5ef2aSThomas Huth TCGv ccr;
2554fcf5ef2aSThomas Huth
2555fcf5ef2aSThomas Huth ccr = gen_get_ccr(s);
2556fcf5ef2aSThomas Huth DEST_EA(env, insn, OS_WORD, ccr, NULL);
2557fcf5ef2aSThomas Huth }
2558fcf5ef2aSThomas Huth
DISAS_INSN(neg)2559fcf5ef2aSThomas Huth DISAS_INSN(neg)
2560fcf5ef2aSThomas Huth {
2561fcf5ef2aSThomas Huth TCGv src1;
2562fcf5ef2aSThomas Huth TCGv dest;
2563fcf5ef2aSThomas Huth TCGv addr;
2564fcf5ef2aSThomas Huth int opsize;
2565fcf5ef2aSThomas Huth
2566fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
2567fcf5ef2aSThomas Huth SRC_EA(env, src1, opsize, 1, &addr);
2568fcf5ef2aSThomas Huth dest = tcg_temp_new();
2569fcf5ef2aSThomas Huth tcg_gen_neg_i32(dest, src1);
2570fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_SUBB + opsize);
2571fcf5ef2aSThomas Huth gen_update_cc_add(dest, src1, opsize);
2572fcf5ef2aSThomas Huth tcg_gen_setcondi_i32(TCG_COND_NE, QREG_CC_X, dest, 0);
2573fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, dest, &addr);
2574fcf5ef2aSThomas Huth }
2575fcf5ef2aSThomas Huth
DISAS_INSN(move_to_ccr)2576fcf5ef2aSThomas Huth DISAS_INSN(move_to_ccr)
2577fcf5ef2aSThomas Huth {
2578b6a21d8dSLaurent Vivier gen_move_to_sr(env, s, insn, true);
2579fcf5ef2aSThomas Huth }
2580fcf5ef2aSThomas Huth
DISAS_INSN(not)2581fcf5ef2aSThomas Huth DISAS_INSN(not)
2582fcf5ef2aSThomas Huth {
2583fcf5ef2aSThomas Huth TCGv src1;
2584fcf5ef2aSThomas Huth TCGv dest;
2585fcf5ef2aSThomas Huth TCGv addr;
2586fcf5ef2aSThomas Huth int opsize;
2587fcf5ef2aSThomas Huth
2588fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
2589fcf5ef2aSThomas Huth SRC_EA(env, src1, opsize, 1, &addr);
2590fcf5ef2aSThomas Huth dest = tcg_temp_new();
2591fcf5ef2aSThomas Huth tcg_gen_not_i32(dest, src1);
2592fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, dest, &addr);
2593fcf5ef2aSThomas Huth gen_logic_cc(s, dest, opsize);
2594fcf5ef2aSThomas Huth }
2595fcf5ef2aSThomas Huth
DISAS_INSN(swap)2596fcf5ef2aSThomas Huth DISAS_INSN(swap)
2597fcf5ef2aSThomas Huth {
2598fcf5ef2aSThomas Huth TCGv src1;
2599fcf5ef2aSThomas Huth TCGv src2;
2600fcf5ef2aSThomas Huth TCGv reg;
2601fcf5ef2aSThomas Huth
2602fcf5ef2aSThomas Huth src1 = tcg_temp_new();
2603fcf5ef2aSThomas Huth src2 = tcg_temp_new();
2604fcf5ef2aSThomas Huth reg = DREG(insn, 0);
2605fcf5ef2aSThomas Huth tcg_gen_shli_i32(src1, reg, 16);
2606fcf5ef2aSThomas Huth tcg_gen_shri_i32(src2, reg, 16);
2607fcf5ef2aSThomas Huth tcg_gen_or_i32(reg, src1, src2);
2608fcf5ef2aSThomas Huth gen_logic_cc(s, reg, OS_LONG);
2609fcf5ef2aSThomas Huth }
2610fcf5ef2aSThomas Huth
DISAS_INSN(bkpt)2611fcf5ef2aSThomas Huth DISAS_INSN(bkpt)
2612fcf5ef2aSThomas Huth {
26136a140586SPhilippe Mathieu-Daudé #if defined(CONFIG_USER_ONLY)
2614a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_DEBUG);
26156a140586SPhilippe Mathieu-Daudé #else
26166a140586SPhilippe Mathieu-Daudé gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
2617c1fc91b8SLaurent Vivier #endif
2618fcf5ef2aSThomas Huth }
2619fcf5ef2aSThomas Huth
DISAS_INSN(pea)2620fcf5ef2aSThomas Huth DISAS_INSN(pea)
2621fcf5ef2aSThomas Huth {
2622fcf5ef2aSThomas Huth TCGv tmp;
2623fcf5ef2aSThomas Huth
2624fcf5ef2aSThomas Huth tmp = gen_lea(env, s, insn, OS_LONG);
2625fcf5ef2aSThomas Huth if (IS_NULL_QREG(tmp)) {
2626fcf5ef2aSThomas Huth gen_addr_fault(s);
2627fcf5ef2aSThomas Huth return;
2628fcf5ef2aSThomas Huth }
2629fcf5ef2aSThomas Huth gen_push(s, tmp);
2630fcf5ef2aSThomas Huth }
2631fcf5ef2aSThomas Huth
DISAS_INSN(ext)2632fcf5ef2aSThomas Huth DISAS_INSN(ext)
2633fcf5ef2aSThomas Huth {
2634fcf5ef2aSThomas Huth int op;
2635fcf5ef2aSThomas Huth TCGv reg;
2636fcf5ef2aSThomas Huth TCGv tmp;
2637fcf5ef2aSThomas Huth
2638fcf5ef2aSThomas Huth reg = DREG(insn, 0);
2639fcf5ef2aSThomas Huth op = (insn >> 6) & 7;
2640fcf5ef2aSThomas Huth tmp = tcg_temp_new();
2641fcf5ef2aSThomas Huth if (op == 3)
2642fcf5ef2aSThomas Huth tcg_gen_ext16s_i32(tmp, reg);
2643fcf5ef2aSThomas Huth else
2644fcf5ef2aSThomas Huth tcg_gen_ext8s_i32(tmp, reg);
2645fcf5ef2aSThomas Huth if (op == 2)
2646fcf5ef2aSThomas Huth gen_partset_reg(OS_WORD, reg, tmp);
2647fcf5ef2aSThomas Huth else
2648fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, tmp);
2649fcf5ef2aSThomas Huth gen_logic_cc(s, tmp, OS_LONG);
2650fcf5ef2aSThomas Huth }
2651fcf5ef2aSThomas Huth
DISAS_INSN(tst)2652fcf5ef2aSThomas Huth DISAS_INSN(tst)
2653fcf5ef2aSThomas Huth {
2654fcf5ef2aSThomas Huth int opsize;
2655fcf5ef2aSThomas Huth TCGv tmp;
2656fcf5ef2aSThomas Huth
2657fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
2658fcf5ef2aSThomas Huth SRC_EA(env, tmp, opsize, 1, NULL);
2659fcf5ef2aSThomas Huth gen_logic_cc(s, tmp, opsize);
2660fcf5ef2aSThomas Huth }
2661fcf5ef2aSThomas Huth
DISAS_INSN(pulse)2662fcf5ef2aSThomas Huth DISAS_INSN(pulse)
2663fcf5ef2aSThomas Huth {
2664fcf5ef2aSThomas Huth /* Implemented as a NOP. */
2665fcf5ef2aSThomas Huth }
2666fcf5ef2aSThomas Huth
DISAS_INSN(illegal)2667fcf5ef2aSThomas Huth DISAS_INSN(illegal)
2668fcf5ef2aSThomas Huth {
2669a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
2670fcf5ef2aSThomas Huth }
2671fcf5ef2aSThomas Huth
DISAS_INSN(tas)2672fcf5ef2aSThomas Huth DISAS_INSN(tas)
2673fcf5ef2aSThomas Huth {
26745934dae7SRichard Henderson int mode = extract32(insn, 3, 3);
26755934dae7SRichard Henderson int reg0 = REG(insn, 0);
2676fcf5ef2aSThomas Huth
26775934dae7SRichard Henderson if (mode == 0) {
26785934dae7SRichard Henderson /* data register direct */
26795934dae7SRichard Henderson TCGv dest = cpu_dregs[reg0];
26805934dae7SRichard Henderson gen_logic_cc(s, dest, OS_BYTE);
26815934dae7SRichard Henderson tcg_gen_ori_tl(dest, dest, 0x80);
26825934dae7SRichard Henderson } else {
26835934dae7SRichard Henderson TCGv src1, addr;
26845934dae7SRichard Henderson
26855934dae7SRichard Henderson addr = gen_lea_mode(env, s, mode, reg0, OS_BYTE);
26865934dae7SRichard Henderson if (IS_NULL_QREG(addr)) {
26875934dae7SRichard Henderson gen_addr_fault(s);
26885934dae7SRichard Henderson return;
26895934dae7SRichard Henderson }
26905934dae7SRichard Henderson src1 = tcg_temp_new();
26915934dae7SRichard Henderson tcg_gen_atomic_fetch_or_tl(src1, addr, tcg_constant_tl(0x80),
26925934dae7SRichard Henderson IS_USER(s), MO_SB);
2693fcf5ef2aSThomas Huth gen_logic_cc(s, src1, OS_BYTE);
26945934dae7SRichard Henderson
26955934dae7SRichard Henderson switch (mode) {
26965934dae7SRichard Henderson case 3: /* Indirect postincrement. */
26975934dae7SRichard Henderson tcg_gen_addi_i32(AREG(insn, 0), addr, 1);
26985934dae7SRichard Henderson break;
26995934dae7SRichard Henderson case 4: /* Indirect predecrememnt. */
27005934dae7SRichard Henderson tcg_gen_mov_i32(AREG(insn, 0), addr);
27015934dae7SRichard Henderson break;
27025934dae7SRichard Henderson }
27035934dae7SRichard Henderson }
2704fcf5ef2aSThomas Huth }
2705fcf5ef2aSThomas Huth
DISAS_INSN(mull)2706fcf5ef2aSThomas Huth DISAS_INSN(mull)
2707fcf5ef2aSThomas Huth {
2708fcf5ef2aSThomas Huth uint16_t ext;
2709fcf5ef2aSThomas Huth TCGv src1;
27108be95defSLaurent Vivier int sign;
2711fcf5ef2aSThomas Huth
2712fcf5ef2aSThomas Huth ext = read_im16(env, s);
27138be95defSLaurent Vivier
27148be95defSLaurent Vivier sign = ext & 0x800;
27158be95defSLaurent Vivier
27168be95defSLaurent Vivier if (ext & 0x400) {
27178be95defSLaurent Vivier if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
2718b9f8e55bSLaurent Vivier gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
2719fcf5ef2aSThomas Huth return;
2720fcf5ef2aSThomas Huth }
27218be95defSLaurent Vivier
2722fcf5ef2aSThomas Huth SRC_EA(env, src1, OS_LONG, 0, NULL);
27238be95defSLaurent Vivier
27248be95defSLaurent Vivier if (sign) {
27258be95defSLaurent Vivier tcg_gen_muls2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
27268be95defSLaurent Vivier } else {
27278be95defSLaurent Vivier tcg_gen_mulu2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12));
27288be95defSLaurent Vivier }
27298be95defSLaurent Vivier /* if Dl == Dh, 68040 returns low word */
27308be95defSLaurent Vivier tcg_gen_mov_i32(DREG(ext, 0), QREG_CC_N);
27318be95defSLaurent Vivier tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_Z);
27328be95defSLaurent Vivier tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N);
27338be95defSLaurent Vivier
27348be95defSLaurent Vivier tcg_gen_movi_i32(QREG_CC_V, 0);
27358be95defSLaurent Vivier tcg_gen_movi_i32(QREG_CC_C, 0);
27368be95defSLaurent Vivier
27378be95defSLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
27388be95defSLaurent Vivier return;
27398be95defSLaurent Vivier }
27408be95defSLaurent Vivier SRC_EA(env, src1, OS_LONG, 0, NULL);
2741aece90d8SMark Cave-Ayland if (m68k_feature(s->env, M68K_FEATURE_M68K)) {
27428be95defSLaurent Vivier tcg_gen_movi_i32(QREG_CC_C, 0);
27438be95defSLaurent Vivier if (sign) {
27448be95defSLaurent Vivier tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
27458be95defSLaurent Vivier /* QREG_CC_V is -(QREG_CC_V != (QREG_CC_N >> 31)) */
27468be95defSLaurent Vivier tcg_gen_sari_i32(QREG_CC_Z, QREG_CC_N, 31);
274727f9af76SRichard Henderson tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V,
274827f9af76SRichard Henderson QREG_CC_V, QREG_CC_Z);
27498be95defSLaurent Vivier } else {
27508be95defSLaurent Vivier tcg_gen_mulu2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12));
27518be95defSLaurent Vivier /* QREG_CC_V is -(QREG_CC_V != 0), use QREG_CC_C as 0 */
275227f9af76SRichard Henderson tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V,
275327f9af76SRichard Henderson QREG_CC_V, QREG_CC_C);
27548be95defSLaurent Vivier }
27558be95defSLaurent Vivier tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_N);
27568be95defSLaurent Vivier
27578be95defSLaurent Vivier tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
27588be95defSLaurent Vivier
27598be95defSLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
27608be95defSLaurent Vivier } else {
2761808d77bcSLucien Murray-Pitts /*
2762808d77bcSLucien Murray-Pitts * The upper 32 bits of the product are discarded, so
2763808d77bcSLucien Murray-Pitts * muls.l and mulu.l are functionally equivalent.
2764808d77bcSLucien Murray-Pitts */
27658be95defSLaurent Vivier tcg_gen_mul_i32(DREG(ext, 12), src1, DREG(ext, 12));
27668be95defSLaurent Vivier gen_logic_cc(s, DREG(ext, 12), OS_LONG);
27678be95defSLaurent Vivier }
2768fcf5ef2aSThomas Huth }
2769fcf5ef2aSThomas Huth
gen_link(DisasContext * s,uint16_t insn,int32_t offset)2770fcf5ef2aSThomas Huth static void gen_link(DisasContext *s, uint16_t insn, int32_t offset)
2771fcf5ef2aSThomas Huth {
2772fcf5ef2aSThomas Huth TCGv reg;
2773fcf5ef2aSThomas Huth TCGv tmp;
2774fcf5ef2aSThomas Huth
2775fcf5ef2aSThomas Huth reg = AREG(insn, 0);
2776fcf5ef2aSThomas Huth tmp = tcg_temp_new();
2777fcf5ef2aSThomas Huth tcg_gen_subi_i32(tmp, QREG_SP, 4);
277854e1e0b5SLaurent Vivier gen_store(s, OS_LONG, tmp, reg, IS_USER(s));
2779fcf5ef2aSThomas Huth if ((insn & 7) != 7) {
2780fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, tmp);
2781fcf5ef2aSThomas Huth }
2782fcf5ef2aSThomas Huth tcg_gen_addi_i32(QREG_SP, tmp, offset);
2783fcf5ef2aSThomas Huth }
2784fcf5ef2aSThomas Huth
DISAS_INSN(link)2785fcf5ef2aSThomas Huth DISAS_INSN(link)
2786fcf5ef2aSThomas Huth {
2787fcf5ef2aSThomas Huth int16_t offset;
2788fcf5ef2aSThomas Huth
2789fcf5ef2aSThomas Huth offset = read_im16(env, s);
2790fcf5ef2aSThomas Huth gen_link(s, insn, offset);
2791fcf5ef2aSThomas Huth }
2792fcf5ef2aSThomas Huth
DISAS_INSN(linkl)2793fcf5ef2aSThomas Huth DISAS_INSN(linkl)
2794fcf5ef2aSThomas Huth {
2795fcf5ef2aSThomas Huth int32_t offset;
2796fcf5ef2aSThomas Huth
2797fcf5ef2aSThomas Huth offset = read_im32(env, s);
2798fcf5ef2aSThomas Huth gen_link(s, insn, offset);
2799fcf5ef2aSThomas Huth }
2800fcf5ef2aSThomas Huth
DISAS_INSN(unlk)2801fcf5ef2aSThomas Huth DISAS_INSN(unlk)
2802fcf5ef2aSThomas Huth {
2803fcf5ef2aSThomas Huth TCGv src;
2804fcf5ef2aSThomas Huth TCGv reg;
2805fcf5ef2aSThomas Huth TCGv tmp;
2806fcf5ef2aSThomas Huth
2807fcf5ef2aSThomas Huth src = tcg_temp_new();
2808fcf5ef2aSThomas Huth reg = AREG(insn, 0);
2809fcf5ef2aSThomas Huth tcg_gen_mov_i32(src, reg);
281054e1e0b5SLaurent Vivier tmp = gen_load(s, OS_LONG, src, 0, IS_USER(s));
2811fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, tmp);
2812fcf5ef2aSThomas Huth tcg_gen_addi_i32(QREG_SP, src, 4);
2813fcf5ef2aSThomas Huth }
2814fcf5ef2aSThomas Huth
28156a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
DISAS_INSN(reset)28160bdb2b3bSLaurent Vivier DISAS_INSN(reset)
28170bdb2b3bSLaurent Vivier {
28180bdb2b3bSLaurent Vivier if (IS_USER(s)) {
2819a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
28200bdb2b3bSLaurent Vivier return;
28210bdb2b3bSLaurent Vivier }
28220bdb2b3bSLaurent Vivier
2823ad75a51eSRichard Henderson gen_helper_reset(tcg_env);
28240bdb2b3bSLaurent Vivier }
28250bdb2b3bSLaurent Vivier #endif
28260bdb2b3bSLaurent Vivier
DISAS_INSN(nop)2827fcf5ef2aSThomas Huth DISAS_INSN(nop)
2828fcf5ef2aSThomas Huth {
2829fcf5ef2aSThomas Huth }
2830fcf5ef2aSThomas Huth
DISAS_INSN(rtd)283118059c9eSLaurent Vivier DISAS_INSN(rtd)
283218059c9eSLaurent Vivier {
283318059c9eSLaurent Vivier TCGv tmp;
283418059c9eSLaurent Vivier int16_t offset = read_im16(env, s);
283518059c9eSLaurent Vivier
283654e1e0b5SLaurent Vivier tmp = gen_load(s, OS_LONG, QREG_SP, 0, IS_USER(s));
283718059c9eSLaurent Vivier tcg_gen_addi_i32(QREG_SP, QREG_SP, offset + 4);
283818059c9eSLaurent Vivier gen_jmp(s, tmp);
283918059c9eSLaurent Vivier }
284018059c9eSLaurent Vivier
DISAS_INSN(rtr)28416abcec36SLaurent Vivier DISAS_INSN(rtr)
28426abcec36SLaurent Vivier {
28436abcec36SLaurent Vivier TCGv tmp;
28446abcec36SLaurent Vivier TCGv ccr;
28456abcec36SLaurent Vivier TCGv sp;
28466abcec36SLaurent Vivier
28476abcec36SLaurent Vivier sp = tcg_temp_new();
28486abcec36SLaurent Vivier ccr = gen_load(s, OS_WORD, QREG_SP, 0, IS_USER(s));
28496abcec36SLaurent Vivier tcg_gen_addi_i32(sp, QREG_SP, 2);
28506abcec36SLaurent Vivier tmp = gen_load(s, OS_LONG, sp, 0, IS_USER(s));
28516abcec36SLaurent Vivier tcg_gen_addi_i32(QREG_SP, sp, 4);
28526abcec36SLaurent Vivier
28536abcec36SLaurent Vivier gen_set_sr(s, ccr, true);
28546abcec36SLaurent Vivier
28556abcec36SLaurent Vivier gen_jmp(s, tmp);
28566abcec36SLaurent Vivier }
28576abcec36SLaurent Vivier
DISAS_INSN(rts)2858fcf5ef2aSThomas Huth DISAS_INSN(rts)
2859fcf5ef2aSThomas Huth {
2860fcf5ef2aSThomas Huth TCGv tmp;
2861fcf5ef2aSThomas Huth
286254e1e0b5SLaurent Vivier tmp = gen_load(s, OS_LONG, QREG_SP, 0, IS_USER(s));
2863fcf5ef2aSThomas Huth tcg_gen_addi_i32(QREG_SP, QREG_SP, 4);
2864fcf5ef2aSThomas Huth gen_jmp(s, tmp);
2865fcf5ef2aSThomas Huth }
2866fcf5ef2aSThomas Huth
DISAS_INSN(jump)2867fcf5ef2aSThomas Huth DISAS_INSN(jump)
2868fcf5ef2aSThomas Huth {
2869fcf5ef2aSThomas Huth TCGv tmp;
2870fcf5ef2aSThomas Huth
2871808d77bcSLucien Murray-Pitts /*
2872808d77bcSLucien Murray-Pitts * Load the target address first to ensure correct exception
2873808d77bcSLucien Murray-Pitts * behavior.
2874808d77bcSLucien Murray-Pitts */
2875fcf5ef2aSThomas Huth tmp = gen_lea(env, s, insn, OS_LONG);
2876fcf5ef2aSThomas Huth if (IS_NULL_QREG(tmp)) {
2877fcf5ef2aSThomas Huth gen_addr_fault(s);
2878fcf5ef2aSThomas Huth return;
2879fcf5ef2aSThomas Huth }
2880fcf5ef2aSThomas Huth if ((insn & 0x40) == 0) {
2881fcf5ef2aSThomas Huth /* jsr */
28821852ce5aSRichard Henderson gen_push(s, tcg_constant_i32(s->pc));
2883fcf5ef2aSThomas Huth }
2884fcf5ef2aSThomas Huth gen_jmp(s, tmp);
2885fcf5ef2aSThomas Huth }
2886fcf5ef2aSThomas Huth
DISAS_INSN(addsubq)2887fcf5ef2aSThomas Huth DISAS_INSN(addsubq)
2888fcf5ef2aSThomas Huth {
2889fcf5ef2aSThomas Huth TCGv src;
2890fcf5ef2aSThomas Huth TCGv dest;
2891fcf5ef2aSThomas Huth TCGv val;
2892fcf5ef2aSThomas Huth int imm;
2893fcf5ef2aSThomas Huth TCGv addr;
2894fcf5ef2aSThomas Huth int opsize;
2895fcf5ef2aSThomas Huth
2896fcf5ef2aSThomas Huth if ((insn & 070) == 010) {
2897fcf5ef2aSThomas Huth /* Operation on address register is always long. */
2898fcf5ef2aSThomas Huth opsize = OS_LONG;
2899fcf5ef2aSThomas Huth } else {
2900fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
2901fcf5ef2aSThomas Huth }
2902fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 1, &addr);
2903fcf5ef2aSThomas Huth imm = (insn >> 9) & 7;
2904fcf5ef2aSThomas Huth if (imm == 0) {
2905fcf5ef2aSThomas Huth imm = 8;
2906fcf5ef2aSThomas Huth }
29071852ce5aSRichard Henderson val = tcg_constant_i32(imm);
2908fcf5ef2aSThomas Huth dest = tcg_temp_new();
2909fcf5ef2aSThomas Huth tcg_gen_mov_i32(dest, src);
2910fcf5ef2aSThomas Huth if ((insn & 0x38) == 0x08) {
2911808d77bcSLucien Murray-Pitts /*
2912808d77bcSLucien Murray-Pitts * Don't update condition codes if the destination is an
2913808d77bcSLucien Murray-Pitts * address register.
2914808d77bcSLucien Murray-Pitts */
2915fcf5ef2aSThomas Huth if (insn & 0x0100) {
2916fcf5ef2aSThomas Huth tcg_gen_sub_i32(dest, dest, val);
2917fcf5ef2aSThomas Huth } else {
2918fcf5ef2aSThomas Huth tcg_gen_add_i32(dest, dest, val);
2919fcf5ef2aSThomas Huth }
2920fcf5ef2aSThomas Huth } else {
2921fcf5ef2aSThomas Huth if (insn & 0x0100) {
2922fcf5ef2aSThomas Huth tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2923fcf5ef2aSThomas Huth tcg_gen_sub_i32(dest, dest, val);
2924fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_SUBB + opsize);
2925fcf5ef2aSThomas Huth } else {
2926fcf5ef2aSThomas Huth tcg_gen_add_i32(dest, dest, val);
2927fcf5ef2aSThomas Huth tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, val);
2928fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_ADDB + opsize);
2929fcf5ef2aSThomas Huth }
2930fcf5ef2aSThomas Huth gen_update_cc_add(dest, val, opsize);
2931fcf5ef2aSThomas Huth }
2932fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, dest, &addr);
2933fcf5ef2aSThomas Huth }
2934fcf5ef2aSThomas Huth
DISAS_INSN(branch)2935fcf5ef2aSThomas Huth DISAS_INSN(branch)
2936fcf5ef2aSThomas Huth {
2937fcf5ef2aSThomas Huth int32_t offset;
2938fcf5ef2aSThomas Huth uint32_t base;
2939fcf5ef2aSThomas Huth int op;
2940fcf5ef2aSThomas Huth
2941fcf5ef2aSThomas Huth base = s->pc;
2942fcf5ef2aSThomas Huth op = (insn >> 8) & 0xf;
2943fcf5ef2aSThomas Huth offset = (int8_t)insn;
2944fcf5ef2aSThomas Huth if (offset == 0) {
2945fcf5ef2aSThomas Huth offset = (int16_t)read_im16(env, s);
2946fcf5ef2aSThomas Huth } else if (offset == -1) {
2947fcf5ef2aSThomas Huth offset = read_im32(env, s);
2948fcf5ef2aSThomas Huth }
2949fcf5ef2aSThomas Huth if (op == 1) {
2950fcf5ef2aSThomas Huth /* bsr */
29511852ce5aSRichard Henderson gen_push(s, tcg_constant_i32(s->pc));
2952fcf5ef2aSThomas Huth }
2953fcf5ef2aSThomas Huth if (op > 1) {
2954fcf5ef2aSThomas Huth /* Bcc */
295589fa312bSPhilippe Mathieu-Daudé TCGLabel *l1 = gen_new_label();
2956fcf5ef2aSThomas Huth gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
29578115fc93SRichard Henderson gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
2958fcf5ef2aSThomas Huth gen_set_label(l1);
29598115fc93SRichard Henderson gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
2960fcf5ef2aSThomas Huth } else {
2961fcf5ef2aSThomas Huth /* Unconditional branch. */
29627cd7b5caSLaurent Vivier update_cc_op(s);
29638115fc93SRichard Henderson gen_jmp_tb(s, 0, base + offset, s->base.pc_next);
2964fcf5ef2aSThomas Huth }
2965fcf5ef2aSThomas Huth }
2966fcf5ef2aSThomas Huth
DISAS_INSN(moveq)2967fcf5ef2aSThomas Huth DISAS_INSN(moveq)
2968fcf5ef2aSThomas Huth {
29692b5e2170SLaurent Vivier tcg_gen_movi_i32(DREG(insn, 9), (int8_t)insn);
29702b5e2170SLaurent Vivier gen_logic_cc(s, DREG(insn, 9), OS_LONG);
2971fcf5ef2aSThomas Huth }
2972fcf5ef2aSThomas Huth
DISAS_INSN(mvzs)2973fcf5ef2aSThomas Huth DISAS_INSN(mvzs)
2974fcf5ef2aSThomas Huth {
2975fcf5ef2aSThomas Huth int opsize;
2976fcf5ef2aSThomas Huth TCGv src;
2977fcf5ef2aSThomas Huth TCGv reg;
2978fcf5ef2aSThomas Huth
2979fcf5ef2aSThomas Huth if (insn & 0x40)
2980fcf5ef2aSThomas Huth opsize = OS_WORD;
2981fcf5ef2aSThomas Huth else
2982fcf5ef2aSThomas Huth opsize = OS_BYTE;
2983fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, (insn & 0x80) == 0, NULL);
2984fcf5ef2aSThomas Huth reg = DREG(insn, 9);
2985fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, src);
2986fcf5ef2aSThomas Huth gen_logic_cc(s, src, opsize);
2987fcf5ef2aSThomas Huth }
2988fcf5ef2aSThomas Huth
DISAS_INSN(or)2989fcf5ef2aSThomas Huth DISAS_INSN(or)
2990fcf5ef2aSThomas Huth {
2991fcf5ef2aSThomas Huth TCGv reg;
2992fcf5ef2aSThomas Huth TCGv dest;
2993fcf5ef2aSThomas Huth TCGv src;
2994fcf5ef2aSThomas Huth TCGv addr;
2995fcf5ef2aSThomas Huth int opsize;
2996fcf5ef2aSThomas Huth
2997fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
29983f215a14SLaurent Vivier reg = gen_extend(s, DREG(insn, 9), opsize, 0);
2999fcf5ef2aSThomas Huth dest = tcg_temp_new();
3000fcf5ef2aSThomas Huth if (insn & 0x100) {
3001fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 0, &addr);
3002fcf5ef2aSThomas Huth tcg_gen_or_i32(dest, src, reg);
3003fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, dest, &addr);
3004fcf5ef2aSThomas Huth } else {
3005fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 0, NULL);
3006fcf5ef2aSThomas Huth tcg_gen_or_i32(dest, src, reg);
3007fcf5ef2aSThomas Huth gen_partset_reg(opsize, DREG(insn, 9), dest);
3008fcf5ef2aSThomas Huth }
3009fcf5ef2aSThomas Huth gen_logic_cc(s, dest, opsize);
3010fcf5ef2aSThomas Huth }
3011fcf5ef2aSThomas Huth
DISAS_INSN(suba)3012fcf5ef2aSThomas Huth DISAS_INSN(suba)
3013fcf5ef2aSThomas Huth {
3014fcf5ef2aSThomas Huth TCGv src;
3015fcf5ef2aSThomas Huth TCGv reg;
3016fcf5ef2aSThomas Huth
3017fcf5ef2aSThomas Huth SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
3018fcf5ef2aSThomas Huth reg = AREG(insn, 9);
3019fcf5ef2aSThomas Huth tcg_gen_sub_i32(reg, reg, src);
3020fcf5ef2aSThomas Huth }
3021fcf5ef2aSThomas Huth
gen_subx(DisasContext * s,TCGv src,TCGv dest,int opsize)3022fcf5ef2aSThomas Huth static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
3023fcf5ef2aSThomas Huth {
3024b32a07d4SRichard Henderson TCGv tmp, zero;
3025fcf5ef2aSThomas Huth
3026fcf5ef2aSThomas Huth gen_flush_flags(s); /* compute old Z */
3027fcf5ef2aSThomas Huth
3028808d77bcSLucien Murray-Pitts /*
3029ce00ff72Szhaolichang * Perform subtract with borrow.
3030fcf5ef2aSThomas Huth * (X, N) = dest - (src + X);
3031fcf5ef2aSThomas Huth */
3032fcf5ef2aSThomas Huth
3033b32a07d4SRichard Henderson zero = tcg_constant_i32(0);
3034b32a07d4SRichard Henderson tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, zero, QREG_CC_X, zero);
3035b32a07d4SRichard Henderson tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, dest, zero, QREG_CC_N, QREG_CC_X);
3036fcf5ef2aSThomas Huth gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3037fcf5ef2aSThomas Huth tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
3038fcf5ef2aSThomas Huth
3039ce00ff72Szhaolichang /* Compute signed-overflow for subtract. */
3040fcf5ef2aSThomas Huth
3041b32a07d4SRichard Henderson tmp = tcg_temp_new();
3042fcf5ef2aSThomas Huth tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, dest);
3043fcf5ef2aSThomas Huth tcg_gen_xor_i32(tmp, dest, src);
3044fcf5ef2aSThomas Huth tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, tmp);
3045fcf5ef2aSThomas Huth
3046fcf5ef2aSThomas Huth /* Copy the rest of the results into place. */
3047fcf5ef2aSThomas Huth tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
3048fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
3049fcf5ef2aSThomas Huth
3050fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_FLAGS);
3051fcf5ef2aSThomas Huth
3052fcf5ef2aSThomas Huth /* result is in QREG_CC_N */
3053fcf5ef2aSThomas Huth }
3054fcf5ef2aSThomas Huth
DISAS_INSN(subx_reg)3055fcf5ef2aSThomas Huth DISAS_INSN(subx_reg)
3056fcf5ef2aSThomas Huth {
3057fcf5ef2aSThomas Huth TCGv dest;
3058fcf5ef2aSThomas Huth TCGv src;
3059fcf5ef2aSThomas Huth int opsize;
3060fcf5ef2aSThomas Huth
3061fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
3062fcf5ef2aSThomas Huth
30633f215a14SLaurent Vivier src = gen_extend(s, DREG(insn, 0), opsize, 1);
30643f215a14SLaurent Vivier dest = gen_extend(s, DREG(insn, 9), opsize, 1);
3065fcf5ef2aSThomas Huth
3066fcf5ef2aSThomas Huth gen_subx(s, src, dest, opsize);
3067fcf5ef2aSThomas Huth
3068fcf5ef2aSThomas Huth gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
3069fcf5ef2aSThomas Huth }
3070fcf5ef2aSThomas Huth
DISAS_INSN(subx_mem)3071fcf5ef2aSThomas Huth DISAS_INSN(subx_mem)
3072fcf5ef2aSThomas Huth {
3073fcf5ef2aSThomas Huth TCGv src;
3074fcf5ef2aSThomas Huth TCGv addr_src;
3075fcf5ef2aSThomas Huth TCGv dest;
3076fcf5ef2aSThomas Huth TCGv addr_dest;
3077fcf5ef2aSThomas Huth int opsize;
3078fcf5ef2aSThomas Huth
3079fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
3080fcf5ef2aSThomas Huth
3081fcf5ef2aSThomas Huth addr_src = AREG(insn, 0);
3082355d4d1cSPavel Dovgalyuk tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
308354e1e0b5SLaurent Vivier src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
3084fcf5ef2aSThomas Huth
3085fcf5ef2aSThomas Huth addr_dest = AREG(insn, 9);
3086355d4d1cSPavel Dovgalyuk tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
308754e1e0b5SLaurent Vivier dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
3088fcf5ef2aSThomas Huth
3089fcf5ef2aSThomas Huth gen_subx(s, src, dest, opsize);
3090fcf5ef2aSThomas Huth
309154e1e0b5SLaurent Vivier gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
3092fcf5ef2aSThomas Huth }
3093fcf5ef2aSThomas Huth
DISAS_INSN(mov3q)3094fcf5ef2aSThomas Huth DISAS_INSN(mov3q)
3095fcf5ef2aSThomas Huth {
3096fcf5ef2aSThomas Huth TCGv src;
3097fcf5ef2aSThomas Huth int val;
3098fcf5ef2aSThomas Huth
3099fcf5ef2aSThomas Huth val = (insn >> 9) & 7;
31001852ce5aSRichard Henderson if (val == 0) {
3101fcf5ef2aSThomas Huth val = -1;
31021852ce5aSRichard Henderson }
31031852ce5aSRichard Henderson src = tcg_constant_i32(val);
3104fcf5ef2aSThomas Huth gen_logic_cc(s, src, OS_LONG);
3105fcf5ef2aSThomas Huth DEST_EA(env, insn, OS_LONG, src, NULL);
3106fcf5ef2aSThomas Huth }
3107fcf5ef2aSThomas Huth
DISAS_INSN(cmp)3108fcf5ef2aSThomas Huth DISAS_INSN(cmp)
3109fcf5ef2aSThomas Huth {
3110fcf5ef2aSThomas Huth TCGv src;
3111fcf5ef2aSThomas Huth TCGv reg;
3112fcf5ef2aSThomas Huth int opsize;
3113fcf5ef2aSThomas Huth
3114fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
3115fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 1, NULL);
31163f215a14SLaurent Vivier reg = gen_extend(s, DREG(insn, 9), opsize, 1);
3117fcf5ef2aSThomas Huth gen_update_cc_cmp(s, reg, src, opsize);
3118fcf5ef2aSThomas Huth }
3119fcf5ef2aSThomas Huth
DISAS_INSN(cmpa)3120fcf5ef2aSThomas Huth DISAS_INSN(cmpa)
3121fcf5ef2aSThomas Huth {
3122fcf5ef2aSThomas Huth int opsize;
3123fcf5ef2aSThomas Huth TCGv src;
3124fcf5ef2aSThomas Huth TCGv reg;
3125fcf5ef2aSThomas Huth
3126fcf5ef2aSThomas Huth if (insn & 0x100) {
3127fcf5ef2aSThomas Huth opsize = OS_LONG;
3128fcf5ef2aSThomas Huth } else {
3129fcf5ef2aSThomas Huth opsize = OS_WORD;
3130fcf5ef2aSThomas Huth }
3131fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 1, NULL);
3132fcf5ef2aSThomas Huth reg = AREG(insn, 9);
3133fcf5ef2aSThomas Huth gen_update_cc_cmp(s, reg, src, OS_LONG);
3134fcf5ef2aSThomas Huth }
3135fcf5ef2aSThomas Huth
DISAS_INSN(cmpm)3136817af1c7SLaurent Vivier DISAS_INSN(cmpm)
3137817af1c7SLaurent Vivier {
3138817af1c7SLaurent Vivier int opsize = insn_opsize(insn);
3139817af1c7SLaurent Vivier TCGv src, dst;
3140817af1c7SLaurent Vivier
3141817af1c7SLaurent Vivier /* Post-increment load (mode 3) from Ay. */
3142817af1c7SLaurent Vivier src = gen_ea_mode(env, s, 3, REG(insn, 0), opsize,
314354e1e0b5SLaurent Vivier NULL_QREG, NULL, EA_LOADS, IS_USER(s));
3144817af1c7SLaurent Vivier /* Post-increment load (mode 3) from Ax. */
3145817af1c7SLaurent Vivier dst = gen_ea_mode(env, s, 3, REG(insn, 9), opsize,
314654e1e0b5SLaurent Vivier NULL_QREG, NULL, EA_LOADS, IS_USER(s));
3147817af1c7SLaurent Vivier
3148817af1c7SLaurent Vivier gen_update_cc_cmp(s, dst, src, opsize);
3149817af1c7SLaurent Vivier }
3150817af1c7SLaurent Vivier
DISAS_INSN(eor)3151fcf5ef2aSThomas Huth DISAS_INSN(eor)
3152fcf5ef2aSThomas Huth {
3153fcf5ef2aSThomas Huth TCGv src;
3154fcf5ef2aSThomas Huth TCGv dest;
3155fcf5ef2aSThomas Huth TCGv addr;
3156fcf5ef2aSThomas Huth int opsize;
3157fcf5ef2aSThomas Huth
3158fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
3159fcf5ef2aSThomas Huth
3160fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 0, &addr);
3161fcf5ef2aSThomas Huth dest = tcg_temp_new();
3162fcf5ef2aSThomas Huth tcg_gen_xor_i32(dest, src, DREG(insn, 9));
3163fcf5ef2aSThomas Huth gen_logic_cc(s, dest, opsize);
3164fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, dest, &addr);
3165fcf5ef2aSThomas Huth }
3166fcf5ef2aSThomas Huth
do_exg(TCGv reg1,TCGv reg2)3167fcf5ef2aSThomas Huth static void do_exg(TCGv reg1, TCGv reg2)
3168fcf5ef2aSThomas Huth {
3169fcf5ef2aSThomas Huth TCGv temp = tcg_temp_new();
3170fcf5ef2aSThomas Huth tcg_gen_mov_i32(temp, reg1);
3171fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg1, reg2);
3172fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg2, temp);
3173fcf5ef2aSThomas Huth }
3174fcf5ef2aSThomas Huth
DISAS_INSN(exg_dd)3175fcf5ef2aSThomas Huth DISAS_INSN(exg_dd)
3176fcf5ef2aSThomas Huth {
3177fcf5ef2aSThomas Huth /* exchange Dx and Dy */
3178fcf5ef2aSThomas Huth do_exg(DREG(insn, 9), DREG(insn, 0));
3179fcf5ef2aSThomas Huth }
3180fcf5ef2aSThomas Huth
DISAS_INSN(exg_aa)3181fcf5ef2aSThomas Huth DISAS_INSN(exg_aa)
3182fcf5ef2aSThomas Huth {
3183fcf5ef2aSThomas Huth /* exchange Ax and Ay */
3184fcf5ef2aSThomas Huth do_exg(AREG(insn, 9), AREG(insn, 0));
3185fcf5ef2aSThomas Huth }
3186fcf5ef2aSThomas Huth
DISAS_INSN(exg_da)3187fcf5ef2aSThomas Huth DISAS_INSN(exg_da)
3188fcf5ef2aSThomas Huth {
3189fcf5ef2aSThomas Huth /* exchange Dx and Ay */
3190fcf5ef2aSThomas Huth do_exg(DREG(insn, 9), AREG(insn, 0));
3191fcf5ef2aSThomas Huth }
3192fcf5ef2aSThomas Huth
DISAS_INSN(and)3193fcf5ef2aSThomas Huth DISAS_INSN(and)
3194fcf5ef2aSThomas Huth {
3195fcf5ef2aSThomas Huth TCGv src;
3196fcf5ef2aSThomas Huth TCGv reg;
3197fcf5ef2aSThomas Huth TCGv dest;
3198fcf5ef2aSThomas Huth TCGv addr;
3199fcf5ef2aSThomas Huth int opsize;
3200fcf5ef2aSThomas Huth
3201fcf5ef2aSThomas Huth dest = tcg_temp_new();
3202fcf5ef2aSThomas Huth
3203fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
3204fcf5ef2aSThomas Huth reg = DREG(insn, 9);
3205fcf5ef2aSThomas Huth if (insn & 0x100) {
3206fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 0, &addr);
3207fcf5ef2aSThomas Huth tcg_gen_and_i32(dest, src, reg);
3208fcf5ef2aSThomas Huth DEST_EA(env, insn, opsize, dest, &addr);
3209fcf5ef2aSThomas Huth } else {
3210fcf5ef2aSThomas Huth SRC_EA(env, src, opsize, 0, NULL);
3211fcf5ef2aSThomas Huth tcg_gen_and_i32(dest, src, reg);
3212fcf5ef2aSThomas Huth gen_partset_reg(opsize, reg, dest);
3213fcf5ef2aSThomas Huth }
3214fcf5ef2aSThomas Huth gen_logic_cc(s, dest, opsize);
3215fcf5ef2aSThomas Huth }
3216fcf5ef2aSThomas Huth
DISAS_INSN(adda)3217fcf5ef2aSThomas Huth DISAS_INSN(adda)
3218fcf5ef2aSThomas Huth {
3219fcf5ef2aSThomas Huth TCGv src;
3220fcf5ef2aSThomas Huth TCGv reg;
3221fcf5ef2aSThomas Huth
3222fcf5ef2aSThomas Huth SRC_EA(env, src, (insn & 0x100) ? OS_LONG : OS_WORD, 1, NULL);
3223fcf5ef2aSThomas Huth reg = AREG(insn, 9);
3224fcf5ef2aSThomas Huth tcg_gen_add_i32(reg, reg, src);
3225fcf5ef2aSThomas Huth }
3226fcf5ef2aSThomas Huth
gen_addx(DisasContext * s,TCGv src,TCGv dest,int opsize)3227fcf5ef2aSThomas Huth static inline void gen_addx(DisasContext *s, TCGv src, TCGv dest, int opsize)
3228fcf5ef2aSThomas Huth {
3229b32a07d4SRichard Henderson TCGv tmp, zero;
3230fcf5ef2aSThomas Huth
3231fcf5ef2aSThomas Huth gen_flush_flags(s); /* compute old Z */
3232fcf5ef2aSThomas Huth
3233808d77bcSLucien Murray-Pitts /*
3234808d77bcSLucien Murray-Pitts * Perform addition with carry.
3235fcf5ef2aSThomas Huth * (X, N) = src + dest + X;
3236fcf5ef2aSThomas Huth */
3237fcf5ef2aSThomas Huth
3238b32a07d4SRichard Henderson zero = tcg_constant_i32(0);
3239b32a07d4SRichard Henderson tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_X, zero, dest, zero);
3240b32a07d4SRichard Henderson tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, zero);
3241fcf5ef2aSThomas Huth gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3242fcf5ef2aSThomas Huth
3243fcf5ef2aSThomas Huth /* Compute signed-overflow for addition. */
3244fcf5ef2aSThomas Huth
3245b32a07d4SRichard Henderson tmp = tcg_temp_new();
3246fcf5ef2aSThomas Huth tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
3247fcf5ef2aSThomas Huth tcg_gen_xor_i32(tmp, dest, src);
3248fcf5ef2aSThomas Huth tcg_gen_andc_i32(QREG_CC_V, QREG_CC_V, tmp);
3249fcf5ef2aSThomas Huth
3250fcf5ef2aSThomas Huth /* Copy the rest of the results into place. */
3251fcf5ef2aSThomas Huth tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
3252fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
3253fcf5ef2aSThomas Huth
3254fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_FLAGS);
3255fcf5ef2aSThomas Huth
3256fcf5ef2aSThomas Huth /* result is in QREG_CC_N */
3257fcf5ef2aSThomas Huth }
3258fcf5ef2aSThomas Huth
DISAS_INSN(addx_reg)3259fcf5ef2aSThomas Huth DISAS_INSN(addx_reg)
3260fcf5ef2aSThomas Huth {
3261fcf5ef2aSThomas Huth TCGv dest;
3262fcf5ef2aSThomas Huth TCGv src;
3263fcf5ef2aSThomas Huth int opsize;
3264fcf5ef2aSThomas Huth
3265fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
3266fcf5ef2aSThomas Huth
32673f215a14SLaurent Vivier dest = gen_extend(s, DREG(insn, 9), opsize, 1);
32683f215a14SLaurent Vivier src = gen_extend(s, DREG(insn, 0), opsize, 1);
3269fcf5ef2aSThomas Huth
3270fcf5ef2aSThomas Huth gen_addx(s, src, dest, opsize);
3271fcf5ef2aSThomas Huth
3272fcf5ef2aSThomas Huth gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
3273fcf5ef2aSThomas Huth }
3274fcf5ef2aSThomas Huth
DISAS_INSN(addx_mem)3275fcf5ef2aSThomas Huth DISAS_INSN(addx_mem)
3276fcf5ef2aSThomas Huth {
3277fcf5ef2aSThomas Huth TCGv src;
3278fcf5ef2aSThomas Huth TCGv addr_src;
3279fcf5ef2aSThomas Huth TCGv dest;
3280fcf5ef2aSThomas Huth TCGv addr_dest;
3281fcf5ef2aSThomas Huth int opsize;
3282fcf5ef2aSThomas Huth
3283fcf5ef2aSThomas Huth opsize = insn_opsize(insn);
3284fcf5ef2aSThomas Huth
3285fcf5ef2aSThomas Huth addr_src = AREG(insn, 0);
3286fcf5ef2aSThomas Huth tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
328754e1e0b5SLaurent Vivier src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
3288fcf5ef2aSThomas Huth
3289fcf5ef2aSThomas Huth addr_dest = AREG(insn, 9);
3290fcf5ef2aSThomas Huth tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
329154e1e0b5SLaurent Vivier dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
3292fcf5ef2aSThomas Huth
3293fcf5ef2aSThomas Huth gen_addx(s, src, dest, opsize);
3294fcf5ef2aSThomas Huth
329554e1e0b5SLaurent Vivier gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
3296fcf5ef2aSThomas Huth }
3297fcf5ef2aSThomas Huth
shift_im(DisasContext * s,uint16_t insn,int opsize)3298367790ccSRichard Henderson static inline void shift_im(DisasContext *s, uint16_t insn, int opsize)
3299367790ccSRichard Henderson {
3300367790ccSRichard Henderson int count = (insn >> 9) & 7;
3301367790ccSRichard Henderson int logical = insn & 8;
3302367790ccSRichard Henderson int left = insn & 0x100;
3303367790ccSRichard Henderson int bits = opsize_bytes(opsize) * 8;
33043f215a14SLaurent Vivier TCGv reg = gen_extend(s, DREG(insn, 0), opsize, !logical);
3305367790ccSRichard Henderson
3306367790ccSRichard Henderson if (count == 0) {
3307367790ccSRichard Henderson count = 8;
3308367790ccSRichard Henderson }
3309367790ccSRichard Henderson
3310367790ccSRichard Henderson tcg_gen_movi_i32(QREG_CC_V, 0);
3311367790ccSRichard Henderson if (left) {
3312367790ccSRichard Henderson tcg_gen_shri_i32(QREG_CC_C, reg, bits - count);
3313367790ccSRichard Henderson tcg_gen_shli_i32(QREG_CC_N, reg, count);
3314367790ccSRichard Henderson
3315808d77bcSLucien Murray-Pitts /*
3316808d77bcSLucien Murray-Pitts * Note that ColdFire always clears V (done above),
3317808d77bcSLucien Murray-Pitts * while M68000 sets if the most significant bit is changed at
3318808d77bcSLucien Murray-Pitts * any time during the shift operation.
3319808d77bcSLucien Murray-Pitts */
3320aece90d8SMark Cave-Ayland if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) {
3321367790ccSRichard Henderson /* if shift count >= bits, V is (reg != 0) */
3322367790ccSRichard Henderson if (count >= bits) {
332327f9af76SRichard Henderson tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V, reg, QREG_CC_V);
3324367790ccSRichard Henderson } else {
3325367790ccSRichard Henderson TCGv t0 = tcg_temp_new();
3326367790ccSRichard Henderson tcg_gen_sari_i32(QREG_CC_V, reg, bits - 1);
3327367790ccSRichard Henderson tcg_gen_sari_i32(t0, reg, bits - count - 1);
332827f9af76SRichard Henderson tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, t0);
3329367790ccSRichard Henderson }
3330367790ccSRichard Henderson }
3331367790ccSRichard Henderson } else {
3332367790ccSRichard Henderson tcg_gen_shri_i32(QREG_CC_C, reg, count - 1);
3333367790ccSRichard Henderson if (logical) {
3334367790ccSRichard Henderson tcg_gen_shri_i32(QREG_CC_N, reg, count);
3335367790ccSRichard Henderson } else {
3336367790ccSRichard Henderson tcg_gen_sari_i32(QREG_CC_N, reg, count);
3337367790ccSRichard Henderson }
3338367790ccSRichard Henderson }
3339367790ccSRichard Henderson
3340367790ccSRichard Henderson gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3341367790ccSRichard Henderson tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3342367790ccSRichard Henderson tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3343367790ccSRichard Henderson tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
3344367790ccSRichard Henderson
3345367790ccSRichard Henderson gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N);
3346367790ccSRichard Henderson set_cc_op(s, CC_OP_FLAGS);
3347367790ccSRichard Henderson }
3348367790ccSRichard Henderson
shift_reg(DisasContext * s,uint16_t insn,int opsize)3349367790ccSRichard Henderson static inline void shift_reg(DisasContext *s, uint16_t insn, int opsize)
3350367790ccSRichard Henderson {
3351367790ccSRichard Henderson int logical = insn & 8;
3352367790ccSRichard Henderson int left = insn & 0x100;
3353367790ccSRichard Henderson int bits = opsize_bytes(opsize) * 8;
33543f215a14SLaurent Vivier TCGv reg = gen_extend(s, DREG(insn, 0), opsize, !logical);
3355367790ccSRichard Henderson TCGv s32;
3356367790ccSRichard Henderson TCGv_i64 t64, s64;
3357367790ccSRichard Henderson
3358367790ccSRichard Henderson t64 = tcg_temp_new_i64();
3359367790ccSRichard Henderson s64 = tcg_temp_new_i64();
3360367790ccSRichard Henderson s32 = tcg_temp_new();
3361367790ccSRichard Henderson
3362808d77bcSLucien Murray-Pitts /*
3363808d77bcSLucien Murray-Pitts * Note that m68k truncates the shift count modulo 64, not 32.
3364808d77bcSLucien Murray-Pitts * In addition, a 64-bit shift makes it easy to find "the last
3365808d77bcSLucien Murray-Pitts * bit shifted out", for the carry flag.
3366808d77bcSLucien Murray-Pitts */
3367367790ccSRichard Henderson tcg_gen_andi_i32(s32, DREG(insn, 9), 63);
3368367790ccSRichard Henderson tcg_gen_extu_i32_i64(s64, s32);
3369367790ccSRichard Henderson tcg_gen_extu_i32_i64(t64, reg);
3370367790ccSRichard Henderson
3371367790ccSRichard Henderson /* Optimistically set V=0. Also used as a zero source below. */
3372367790ccSRichard Henderson tcg_gen_movi_i32(QREG_CC_V, 0);
3373367790ccSRichard Henderson if (left) {
3374367790ccSRichard Henderson tcg_gen_shl_i64(t64, t64, s64);
3375367790ccSRichard Henderson
3376367790ccSRichard Henderson if (opsize == OS_LONG) {
3377367790ccSRichard Henderson tcg_gen_extr_i64_i32(QREG_CC_N, QREG_CC_C, t64);
3378367790ccSRichard Henderson /* Note that C=0 if shift count is 0, and we get that for free. */
3379367790ccSRichard Henderson } else {
33801852ce5aSRichard Henderson TCGv zero = tcg_constant_i32(0);
3381367790ccSRichard Henderson tcg_gen_extrl_i64_i32(QREG_CC_N, t64);
3382367790ccSRichard Henderson tcg_gen_shri_i32(QREG_CC_C, QREG_CC_N, bits);
3383367790ccSRichard Henderson tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
3384367790ccSRichard Henderson s32, zero, zero, QREG_CC_C);
3385367790ccSRichard Henderson }
3386367790ccSRichard Henderson tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3387367790ccSRichard Henderson
3388367790ccSRichard Henderson /* X = C, but only if the shift count was non-zero. */
3389367790ccSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V,
3390367790ccSRichard Henderson QREG_CC_C, QREG_CC_X);
3391367790ccSRichard Henderson
3392808d77bcSLucien Murray-Pitts /*
3393808d77bcSLucien Murray-Pitts * M68000 sets V if the most significant bit is changed at
3394367790ccSRichard Henderson * any time during the shift operation. Do this via creating
3395367790ccSRichard Henderson * an extension of the sign bit, comparing, and discarding
3396367790ccSRichard Henderson * the bits below the sign bit. I.e.
3397367790ccSRichard Henderson * int64_t s = (intN_t)reg;
3398367790ccSRichard Henderson * int64_t t = (int64_t)(intN_t)reg << count;
3399367790ccSRichard Henderson * V = ((s ^ t) & (-1 << (bits - 1))) != 0
3400367790ccSRichard Henderson */
3401aece90d8SMark Cave-Ayland if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) {
34021852ce5aSRichard Henderson TCGv_i64 tt = tcg_constant_i64(32);
3403367790ccSRichard Henderson /* if shift is greater than 32, use 32 */
3404367790ccSRichard Henderson tcg_gen_movcond_i64(TCG_COND_GT, s64, s64, tt, tt, s64);
3405367790ccSRichard Henderson /* Sign extend the input to 64 bits; re-do the shift. */
3406367790ccSRichard Henderson tcg_gen_ext_i32_i64(t64, reg);
3407367790ccSRichard Henderson tcg_gen_shl_i64(s64, t64, s64);
3408367790ccSRichard Henderson /* Clear all bits that are unchanged. */
3409367790ccSRichard Henderson tcg_gen_xor_i64(t64, t64, s64);
3410367790ccSRichard Henderson /* Ignore the bits below the sign bit. */
3411367790ccSRichard Henderson tcg_gen_andi_i64(t64, t64, -1ULL << (bits - 1));
3412367790ccSRichard Henderson /* If any bits remain set, we have overflow. */
341327f9af76SRichard Henderson tcg_gen_negsetcond_i64(TCG_COND_NE, t64, t64, tcg_constant_i64(0));
3414367790ccSRichard Henderson tcg_gen_extrl_i64_i32(QREG_CC_V, t64);
3415367790ccSRichard Henderson }
3416367790ccSRichard Henderson } else {
3417367790ccSRichard Henderson tcg_gen_shli_i64(t64, t64, 32);
3418367790ccSRichard Henderson if (logical) {
3419367790ccSRichard Henderson tcg_gen_shr_i64(t64, t64, s64);
3420367790ccSRichard Henderson } else {
3421367790ccSRichard Henderson tcg_gen_sar_i64(t64, t64, s64);
3422367790ccSRichard Henderson }
3423367790ccSRichard Henderson tcg_gen_extr_i64_i32(QREG_CC_C, QREG_CC_N, t64);
3424367790ccSRichard Henderson
3425367790ccSRichard Henderson /* Note that C=0 if shift count is 0, and we get that for free. */
3426367790ccSRichard Henderson tcg_gen_shri_i32(QREG_CC_C, QREG_CC_C, 31);
3427367790ccSRichard Henderson
3428367790ccSRichard Henderson /* X = C, but only if the shift count was non-zero. */
3429367790ccSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V,
3430367790ccSRichard Henderson QREG_CC_C, QREG_CC_X);
3431367790ccSRichard Henderson }
3432367790ccSRichard Henderson gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
3433367790ccSRichard Henderson tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3434367790ccSRichard Henderson
3435367790ccSRichard Henderson /* Write back the result. */
3436367790ccSRichard Henderson gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N);
3437367790ccSRichard Henderson set_cc_op(s, CC_OP_FLAGS);
3438367790ccSRichard Henderson }
3439367790ccSRichard Henderson
DISAS_INSN(shift8_im)3440367790ccSRichard Henderson DISAS_INSN(shift8_im)
3441367790ccSRichard Henderson {
3442367790ccSRichard Henderson shift_im(s, insn, OS_BYTE);
3443367790ccSRichard Henderson }
3444367790ccSRichard Henderson
DISAS_INSN(shift16_im)3445367790ccSRichard Henderson DISAS_INSN(shift16_im)
3446367790ccSRichard Henderson {
3447367790ccSRichard Henderson shift_im(s, insn, OS_WORD);
3448367790ccSRichard Henderson }
3449367790ccSRichard Henderson
DISAS_INSN(shift_im)3450fcf5ef2aSThomas Huth DISAS_INSN(shift_im)
3451fcf5ef2aSThomas Huth {
3452367790ccSRichard Henderson shift_im(s, insn, OS_LONG);
3453fcf5ef2aSThomas Huth }
3454367790ccSRichard Henderson
DISAS_INSN(shift8_reg)3455367790ccSRichard Henderson DISAS_INSN(shift8_reg)
3456367790ccSRichard Henderson {
3457367790ccSRichard Henderson shift_reg(s, insn, OS_BYTE);
3458fcf5ef2aSThomas Huth }
3459367790ccSRichard Henderson
DISAS_INSN(shift16_reg)3460367790ccSRichard Henderson DISAS_INSN(shift16_reg)
3461367790ccSRichard Henderson {
3462367790ccSRichard Henderson shift_reg(s, insn, OS_WORD);
3463fcf5ef2aSThomas Huth }
3464fcf5ef2aSThomas Huth
DISAS_INSN(shift_reg)3465fcf5ef2aSThomas Huth DISAS_INSN(shift_reg)
3466fcf5ef2aSThomas Huth {
3467367790ccSRichard Henderson shift_reg(s, insn, OS_LONG);
3468367790ccSRichard Henderson }
3469fcf5ef2aSThomas Huth
DISAS_INSN(shift_mem)3470367790ccSRichard Henderson DISAS_INSN(shift_mem)
3471367790ccSRichard Henderson {
3472367790ccSRichard Henderson int logical = insn & 8;
3473367790ccSRichard Henderson int left = insn & 0x100;
3474367790ccSRichard Henderson TCGv src;
3475367790ccSRichard Henderson TCGv addr;
3476367790ccSRichard Henderson
3477367790ccSRichard Henderson SRC_EA(env, src, OS_WORD, !logical, &addr);
3478367790ccSRichard Henderson tcg_gen_movi_i32(QREG_CC_V, 0);
3479367790ccSRichard Henderson if (left) {
3480367790ccSRichard Henderson tcg_gen_shri_i32(QREG_CC_C, src, 15);
3481367790ccSRichard Henderson tcg_gen_shli_i32(QREG_CC_N, src, 1);
3482367790ccSRichard Henderson
3483808d77bcSLucien Murray-Pitts /*
3484808d77bcSLucien Murray-Pitts * Note that ColdFire always clears V,
3485808d77bcSLucien Murray-Pitts * while M68000 sets if the most significant bit is changed at
3486808d77bcSLucien Murray-Pitts * any time during the shift operation
3487808d77bcSLucien Murray-Pitts */
3488aece90d8SMark Cave-Ayland if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) {
34893f215a14SLaurent Vivier src = gen_extend(s, src, OS_WORD, 1);
3490367790ccSRichard Henderson tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
3491367790ccSRichard Henderson }
3492fcf5ef2aSThomas Huth } else {
3493367790ccSRichard Henderson tcg_gen_mov_i32(QREG_CC_C, src);
3494367790ccSRichard Henderson if (logical) {
3495367790ccSRichard Henderson tcg_gen_shri_i32(QREG_CC_N, src, 1);
3496fcf5ef2aSThomas Huth } else {
3497367790ccSRichard Henderson tcg_gen_sari_i32(QREG_CC_N, src, 1);
3498fcf5ef2aSThomas Huth }
3499fcf5ef2aSThomas Huth }
3500367790ccSRichard Henderson
3501367790ccSRichard Henderson gen_ext(QREG_CC_N, QREG_CC_N, OS_WORD, 1);
3502367790ccSRichard Henderson tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1);
3503367790ccSRichard Henderson tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N);
3504367790ccSRichard Henderson tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C);
3505367790ccSRichard Henderson
3506367790ccSRichard Henderson DEST_EA(env, insn, OS_WORD, QREG_CC_N, &addr);
3507fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_FLAGS);
3508fcf5ef2aSThomas Huth }
3509fcf5ef2aSThomas Huth
rotate(TCGv reg,TCGv shift,int left,int size)35100194cf31SLaurent Vivier static void rotate(TCGv reg, TCGv shift, int left, int size)
35110194cf31SLaurent Vivier {
35120194cf31SLaurent Vivier switch (size) {
35130194cf31SLaurent Vivier case 8:
35140194cf31SLaurent Vivier /* Replicate the 8-bit input so that a 32-bit rotate works. */
35150194cf31SLaurent Vivier tcg_gen_ext8u_i32(reg, reg);
35160194cf31SLaurent Vivier tcg_gen_muli_i32(reg, reg, 0x01010101);
35170194cf31SLaurent Vivier goto do_long;
35180194cf31SLaurent Vivier case 16:
35190194cf31SLaurent Vivier /* Replicate the 16-bit input so that a 32-bit rotate works. */
35200194cf31SLaurent Vivier tcg_gen_deposit_i32(reg, reg, reg, 16, 16);
35210194cf31SLaurent Vivier goto do_long;
35220194cf31SLaurent Vivier do_long:
35230194cf31SLaurent Vivier default:
35240194cf31SLaurent Vivier if (left) {
35250194cf31SLaurent Vivier tcg_gen_rotl_i32(reg, reg, shift);
35260194cf31SLaurent Vivier } else {
35270194cf31SLaurent Vivier tcg_gen_rotr_i32(reg, reg, shift);
35280194cf31SLaurent Vivier }
35290194cf31SLaurent Vivier }
35300194cf31SLaurent Vivier
35310194cf31SLaurent Vivier /* compute flags */
35320194cf31SLaurent Vivier
35330194cf31SLaurent Vivier switch (size) {
35340194cf31SLaurent Vivier case 8:
35350194cf31SLaurent Vivier tcg_gen_ext8s_i32(reg, reg);
35360194cf31SLaurent Vivier break;
35370194cf31SLaurent Vivier case 16:
35380194cf31SLaurent Vivier tcg_gen_ext16s_i32(reg, reg);
35390194cf31SLaurent Vivier break;
35400194cf31SLaurent Vivier default:
35410194cf31SLaurent Vivier break;
35420194cf31SLaurent Vivier }
35430194cf31SLaurent Vivier
35440194cf31SLaurent Vivier /* QREG_CC_X is not affected */
35450194cf31SLaurent Vivier
35460194cf31SLaurent Vivier tcg_gen_mov_i32(QREG_CC_N, reg);
35470194cf31SLaurent Vivier tcg_gen_mov_i32(QREG_CC_Z, reg);
35480194cf31SLaurent Vivier
35490194cf31SLaurent Vivier if (left) {
35500194cf31SLaurent Vivier tcg_gen_andi_i32(QREG_CC_C, reg, 1);
35510194cf31SLaurent Vivier } else {
35520194cf31SLaurent Vivier tcg_gen_shri_i32(QREG_CC_C, reg, 31);
35530194cf31SLaurent Vivier }
35540194cf31SLaurent Vivier
35550194cf31SLaurent Vivier tcg_gen_movi_i32(QREG_CC_V, 0); /* always cleared */
35560194cf31SLaurent Vivier }
35570194cf31SLaurent Vivier
rotate_x_flags(TCGv reg,TCGv X,int size)35580194cf31SLaurent Vivier static void rotate_x_flags(TCGv reg, TCGv X, int size)
35590194cf31SLaurent Vivier {
35600194cf31SLaurent Vivier switch (size) {
35610194cf31SLaurent Vivier case 8:
35620194cf31SLaurent Vivier tcg_gen_ext8s_i32(reg, reg);
35630194cf31SLaurent Vivier break;
35640194cf31SLaurent Vivier case 16:
35650194cf31SLaurent Vivier tcg_gen_ext16s_i32(reg, reg);
35660194cf31SLaurent Vivier break;
35670194cf31SLaurent Vivier default:
35680194cf31SLaurent Vivier break;
35690194cf31SLaurent Vivier }
35700194cf31SLaurent Vivier tcg_gen_mov_i32(QREG_CC_N, reg);
35710194cf31SLaurent Vivier tcg_gen_mov_i32(QREG_CC_Z, reg);
35720194cf31SLaurent Vivier tcg_gen_mov_i32(QREG_CC_X, X);
35730194cf31SLaurent Vivier tcg_gen_mov_i32(QREG_CC_C, X);
35740194cf31SLaurent Vivier tcg_gen_movi_i32(QREG_CC_V, 0);
35750194cf31SLaurent Vivier }
35760194cf31SLaurent Vivier
35770194cf31SLaurent Vivier /* Result of rotate_x() is valid if 0 <= shift <= size */
rotate_x(TCGv reg,TCGv shift,int left,int size)35780194cf31SLaurent Vivier static TCGv rotate_x(TCGv reg, TCGv shift, int left, int size)
35790194cf31SLaurent Vivier {
35800194cf31SLaurent Vivier TCGv X, shl, shr, shx, sz, zero;
35810194cf31SLaurent Vivier
35821852ce5aSRichard Henderson sz = tcg_constant_i32(size);
35830194cf31SLaurent Vivier
35840194cf31SLaurent Vivier shr = tcg_temp_new();
35850194cf31SLaurent Vivier shl = tcg_temp_new();
35860194cf31SLaurent Vivier shx = tcg_temp_new();
35870194cf31SLaurent Vivier if (left) {
35880194cf31SLaurent Vivier tcg_gen_mov_i32(shl, shift); /* shl = shift */
35890194cf31SLaurent Vivier tcg_gen_movi_i32(shr, size + 1);
35900194cf31SLaurent Vivier tcg_gen_sub_i32(shr, shr, shift); /* shr = size + 1 - shift */
35910194cf31SLaurent Vivier tcg_gen_subi_i32(shx, shift, 1); /* shx = shift - 1 */
35920194cf31SLaurent Vivier /* shx = shx < 0 ? size : shx; */
35931852ce5aSRichard Henderson zero = tcg_constant_i32(0);
35940194cf31SLaurent Vivier tcg_gen_movcond_i32(TCG_COND_LT, shx, shx, zero, sz, shx);
35950194cf31SLaurent Vivier } else {
35960194cf31SLaurent Vivier tcg_gen_mov_i32(shr, shift); /* shr = shift */
35970194cf31SLaurent Vivier tcg_gen_movi_i32(shl, size + 1);
35980194cf31SLaurent Vivier tcg_gen_sub_i32(shl, shl, shift); /* shl = size + 1 - shift */
35990194cf31SLaurent Vivier tcg_gen_sub_i32(shx, sz, shift); /* shx = size - shift */
36000194cf31SLaurent Vivier }
36010194cf31SLaurent Vivier
36020194cf31SLaurent Vivier /* reg = (reg << shl) | (reg >> shr) | (x << shx); */
36030194cf31SLaurent Vivier
36040194cf31SLaurent Vivier tcg_gen_shl_i32(shl, reg, shl);
36050194cf31SLaurent Vivier tcg_gen_shr_i32(shr, reg, shr);
36060194cf31SLaurent Vivier tcg_gen_or_i32(reg, shl, shr);
36070194cf31SLaurent Vivier tcg_gen_shl_i32(shx, QREG_CC_X, shx);
36080194cf31SLaurent Vivier tcg_gen_or_i32(reg, reg, shx);
36090194cf31SLaurent Vivier
36100194cf31SLaurent Vivier /* X = (reg >> size) & 1 */
36110194cf31SLaurent Vivier
36120194cf31SLaurent Vivier X = tcg_temp_new();
361360d3d0cfSPhilippe Mathieu-Daudé tcg_gen_extract_i32(X, reg, size, 1);
36140194cf31SLaurent Vivier
36150194cf31SLaurent Vivier return X;
36160194cf31SLaurent Vivier }
36170194cf31SLaurent Vivier
36180194cf31SLaurent Vivier /* Result of rotate32_x() is valid if 0 <= shift < 33 */
rotate32_x(TCGv reg,TCGv shift,int left)36190194cf31SLaurent Vivier static TCGv rotate32_x(TCGv reg, TCGv shift, int left)
36200194cf31SLaurent Vivier {
36210194cf31SLaurent Vivier TCGv_i64 t0, shift64;
36220194cf31SLaurent Vivier TCGv X, lo, hi, zero;
36230194cf31SLaurent Vivier
36240194cf31SLaurent Vivier shift64 = tcg_temp_new_i64();
36250194cf31SLaurent Vivier tcg_gen_extu_i32_i64(shift64, shift);
36260194cf31SLaurent Vivier
36270194cf31SLaurent Vivier t0 = tcg_temp_new_i64();
36280194cf31SLaurent Vivier
36290194cf31SLaurent Vivier X = tcg_temp_new();
36300194cf31SLaurent Vivier lo = tcg_temp_new();
36310194cf31SLaurent Vivier hi = tcg_temp_new();
36320194cf31SLaurent Vivier
36330194cf31SLaurent Vivier if (left) {
36340194cf31SLaurent Vivier /* create [reg:X:..] */
36350194cf31SLaurent Vivier
36360194cf31SLaurent Vivier tcg_gen_shli_i32(lo, QREG_CC_X, 31);
36370194cf31SLaurent Vivier tcg_gen_concat_i32_i64(t0, lo, reg);
36380194cf31SLaurent Vivier
36390194cf31SLaurent Vivier /* rotate */
36400194cf31SLaurent Vivier
36410194cf31SLaurent Vivier tcg_gen_rotl_i64(t0, t0, shift64);
36420194cf31SLaurent Vivier
36430194cf31SLaurent Vivier /* result is [reg:..:reg:X] */
36440194cf31SLaurent Vivier
36450194cf31SLaurent Vivier tcg_gen_extr_i64_i32(lo, hi, t0);
36460194cf31SLaurent Vivier tcg_gen_andi_i32(X, lo, 1);
36470194cf31SLaurent Vivier
36480194cf31SLaurent Vivier tcg_gen_shri_i32(lo, lo, 1);
36490194cf31SLaurent Vivier } else {
36500194cf31SLaurent Vivier /* create [..:X:reg] */
36510194cf31SLaurent Vivier
36520194cf31SLaurent Vivier tcg_gen_concat_i32_i64(t0, reg, QREG_CC_X);
36530194cf31SLaurent Vivier
36540194cf31SLaurent Vivier tcg_gen_rotr_i64(t0, t0, shift64);
36550194cf31SLaurent Vivier
36560194cf31SLaurent Vivier /* result is value: [X:reg:..:reg] */
36570194cf31SLaurent Vivier
36580194cf31SLaurent Vivier tcg_gen_extr_i64_i32(lo, hi, t0);
36590194cf31SLaurent Vivier
36600194cf31SLaurent Vivier /* extract X */
36610194cf31SLaurent Vivier
36620194cf31SLaurent Vivier tcg_gen_shri_i32(X, hi, 31);
36630194cf31SLaurent Vivier
36640194cf31SLaurent Vivier /* extract result */
36650194cf31SLaurent Vivier
36660194cf31SLaurent Vivier tcg_gen_shli_i32(hi, hi, 1);
36670194cf31SLaurent Vivier }
36680194cf31SLaurent Vivier tcg_gen_or_i32(lo, lo, hi);
36690194cf31SLaurent Vivier
36700194cf31SLaurent Vivier /* if shift == 0, register and X are not affected */
36710194cf31SLaurent Vivier
36721852ce5aSRichard Henderson zero = tcg_constant_i32(0);
36730194cf31SLaurent Vivier tcg_gen_movcond_i32(TCG_COND_EQ, X, shift, zero, QREG_CC_X, X);
36740194cf31SLaurent Vivier tcg_gen_movcond_i32(TCG_COND_EQ, reg, shift, zero, reg, lo);
36750194cf31SLaurent Vivier
36760194cf31SLaurent Vivier return X;
36770194cf31SLaurent Vivier }
36780194cf31SLaurent Vivier
DISAS_INSN(rotate_im)36790194cf31SLaurent Vivier DISAS_INSN(rotate_im)
36800194cf31SLaurent Vivier {
36810194cf31SLaurent Vivier TCGv shift;
36820194cf31SLaurent Vivier int tmp;
36830194cf31SLaurent Vivier int left = (insn & 0x100);
36840194cf31SLaurent Vivier
36850194cf31SLaurent Vivier tmp = (insn >> 9) & 7;
36860194cf31SLaurent Vivier if (tmp == 0) {
36870194cf31SLaurent Vivier tmp = 8;
36880194cf31SLaurent Vivier }
36890194cf31SLaurent Vivier
36901852ce5aSRichard Henderson shift = tcg_constant_i32(tmp);
36910194cf31SLaurent Vivier if (insn & 8) {
36920194cf31SLaurent Vivier rotate(DREG(insn, 0), shift, left, 32);
36930194cf31SLaurent Vivier } else {
36940194cf31SLaurent Vivier TCGv X = rotate32_x(DREG(insn, 0), shift, left);
36950194cf31SLaurent Vivier rotate_x_flags(DREG(insn, 0), X, 32);
36960194cf31SLaurent Vivier }
36970194cf31SLaurent Vivier
36980194cf31SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
36990194cf31SLaurent Vivier }
37000194cf31SLaurent Vivier
DISAS_INSN(rotate8_im)37010194cf31SLaurent Vivier DISAS_INSN(rotate8_im)
37020194cf31SLaurent Vivier {
37030194cf31SLaurent Vivier int left = (insn & 0x100);
37040194cf31SLaurent Vivier TCGv reg;
37050194cf31SLaurent Vivier TCGv shift;
37060194cf31SLaurent Vivier int tmp;
37070194cf31SLaurent Vivier
37083f215a14SLaurent Vivier reg = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
37090194cf31SLaurent Vivier
37100194cf31SLaurent Vivier tmp = (insn >> 9) & 7;
37110194cf31SLaurent Vivier if (tmp == 0) {
37120194cf31SLaurent Vivier tmp = 8;
37130194cf31SLaurent Vivier }
37140194cf31SLaurent Vivier
37151852ce5aSRichard Henderson shift = tcg_constant_i32(tmp);
37160194cf31SLaurent Vivier if (insn & 8) {
37170194cf31SLaurent Vivier rotate(reg, shift, left, 8);
37180194cf31SLaurent Vivier } else {
37190194cf31SLaurent Vivier TCGv X = rotate_x(reg, shift, left, 8);
37200194cf31SLaurent Vivier rotate_x_flags(reg, X, 8);
37210194cf31SLaurent Vivier }
37220194cf31SLaurent Vivier gen_partset_reg(OS_BYTE, DREG(insn, 0), reg);
37230194cf31SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
37240194cf31SLaurent Vivier }
37250194cf31SLaurent Vivier
DISAS_INSN(rotate16_im)37260194cf31SLaurent Vivier DISAS_INSN(rotate16_im)
37270194cf31SLaurent Vivier {
37280194cf31SLaurent Vivier int left = (insn & 0x100);
37290194cf31SLaurent Vivier TCGv reg;
37300194cf31SLaurent Vivier TCGv shift;
37310194cf31SLaurent Vivier int tmp;
37320194cf31SLaurent Vivier
37333f215a14SLaurent Vivier reg = gen_extend(s, DREG(insn, 0), OS_WORD, 0);
37340194cf31SLaurent Vivier tmp = (insn >> 9) & 7;
37350194cf31SLaurent Vivier if (tmp == 0) {
37360194cf31SLaurent Vivier tmp = 8;
37370194cf31SLaurent Vivier }
37380194cf31SLaurent Vivier
37391852ce5aSRichard Henderson shift = tcg_constant_i32(tmp);
37400194cf31SLaurent Vivier if (insn & 8) {
37410194cf31SLaurent Vivier rotate(reg, shift, left, 16);
37420194cf31SLaurent Vivier } else {
37430194cf31SLaurent Vivier TCGv X = rotate_x(reg, shift, left, 16);
37440194cf31SLaurent Vivier rotate_x_flags(reg, X, 16);
37450194cf31SLaurent Vivier }
37460194cf31SLaurent Vivier gen_partset_reg(OS_WORD, DREG(insn, 0), reg);
37470194cf31SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
37480194cf31SLaurent Vivier }
37490194cf31SLaurent Vivier
DISAS_INSN(rotate_reg)37500194cf31SLaurent Vivier DISAS_INSN(rotate_reg)
37510194cf31SLaurent Vivier {
37520194cf31SLaurent Vivier TCGv reg;
37530194cf31SLaurent Vivier TCGv src;
37540194cf31SLaurent Vivier TCGv t0, t1;
37550194cf31SLaurent Vivier int left = (insn & 0x100);
37560194cf31SLaurent Vivier
37570194cf31SLaurent Vivier reg = DREG(insn, 0);
37580194cf31SLaurent Vivier src = DREG(insn, 9);
37590194cf31SLaurent Vivier /* shift in [0..63] */
37600194cf31SLaurent Vivier t0 = tcg_temp_new();
37610194cf31SLaurent Vivier tcg_gen_andi_i32(t0, src, 63);
37620194cf31SLaurent Vivier t1 = tcg_temp_new_i32();
37630194cf31SLaurent Vivier if (insn & 8) {
37640194cf31SLaurent Vivier tcg_gen_andi_i32(t1, src, 31);
37650194cf31SLaurent Vivier rotate(reg, t1, left, 32);
37660194cf31SLaurent Vivier /* if shift == 0, clear C */
37670194cf31SLaurent Vivier tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
37680194cf31SLaurent Vivier t0, QREG_CC_V /* 0 */,
37690194cf31SLaurent Vivier QREG_CC_V /* 0 */, QREG_CC_C);
37700194cf31SLaurent Vivier } else {
37710194cf31SLaurent Vivier TCGv X;
37720194cf31SLaurent Vivier /* modulo 33 */
37730194cf31SLaurent Vivier tcg_gen_movi_i32(t1, 33);
37740194cf31SLaurent Vivier tcg_gen_remu_i32(t1, t0, t1);
37750194cf31SLaurent Vivier X = rotate32_x(DREG(insn, 0), t1, left);
37760194cf31SLaurent Vivier rotate_x_flags(DREG(insn, 0), X, 32);
37770194cf31SLaurent Vivier }
37780194cf31SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
37790194cf31SLaurent Vivier }
37800194cf31SLaurent Vivier
DISAS_INSN(rotate8_reg)37810194cf31SLaurent Vivier DISAS_INSN(rotate8_reg)
37820194cf31SLaurent Vivier {
37830194cf31SLaurent Vivier TCGv reg;
37840194cf31SLaurent Vivier TCGv src;
37850194cf31SLaurent Vivier TCGv t0, t1;
37860194cf31SLaurent Vivier int left = (insn & 0x100);
37870194cf31SLaurent Vivier
37883f215a14SLaurent Vivier reg = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
37890194cf31SLaurent Vivier src = DREG(insn, 9);
37900194cf31SLaurent Vivier /* shift in [0..63] */
37910194cf31SLaurent Vivier t0 = tcg_temp_new_i32();
37920194cf31SLaurent Vivier tcg_gen_andi_i32(t0, src, 63);
37930194cf31SLaurent Vivier t1 = tcg_temp_new_i32();
37940194cf31SLaurent Vivier if (insn & 8) {
37950194cf31SLaurent Vivier tcg_gen_andi_i32(t1, src, 7);
37960194cf31SLaurent Vivier rotate(reg, t1, left, 8);
37970194cf31SLaurent Vivier /* if shift == 0, clear C */
37980194cf31SLaurent Vivier tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
37990194cf31SLaurent Vivier t0, QREG_CC_V /* 0 */,
38000194cf31SLaurent Vivier QREG_CC_V /* 0 */, QREG_CC_C);
38010194cf31SLaurent Vivier } else {
38020194cf31SLaurent Vivier TCGv X;
38030194cf31SLaurent Vivier /* modulo 9 */
38040194cf31SLaurent Vivier tcg_gen_movi_i32(t1, 9);
38050194cf31SLaurent Vivier tcg_gen_remu_i32(t1, t0, t1);
38060194cf31SLaurent Vivier X = rotate_x(reg, t1, left, 8);
38070194cf31SLaurent Vivier rotate_x_flags(reg, X, 8);
38080194cf31SLaurent Vivier }
38090194cf31SLaurent Vivier gen_partset_reg(OS_BYTE, DREG(insn, 0), reg);
38100194cf31SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
38110194cf31SLaurent Vivier }
38120194cf31SLaurent Vivier
DISAS_INSN(rotate16_reg)38130194cf31SLaurent Vivier DISAS_INSN(rotate16_reg)
38140194cf31SLaurent Vivier {
38150194cf31SLaurent Vivier TCGv reg;
38160194cf31SLaurent Vivier TCGv src;
38170194cf31SLaurent Vivier TCGv t0, t1;
38180194cf31SLaurent Vivier int left = (insn & 0x100);
38190194cf31SLaurent Vivier
38203f215a14SLaurent Vivier reg = gen_extend(s, DREG(insn, 0), OS_WORD, 0);
38210194cf31SLaurent Vivier src = DREG(insn, 9);
38220194cf31SLaurent Vivier /* shift in [0..63] */
38230194cf31SLaurent Vivier t0 = tcg_temp_new_i32();
38240194cf31SLaurent Vivier tcg_gen_andi_i32(t0, src, 63);
38250194cf31SLaurent Vivier t1 = tcg_temp_new_i32();
38260194cf31SLaurent Vivier if (insn & 8) {
38270194cf31SLaurent Vivier tcg_gen_andi_i32(t1, src, 15);
38280194cf31SLaurent Vivier rotate(reg, t1, left, 16);
38290194cf31SLaurent Vivier /* if shift == 0, clear C */
38300194cf31SLaurent Vivier tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C,
38310194cf31SLaurent Vivier t0, QREG_CC_V /* 0 */,
38320194cf31SLaurent Vivier QREG_CC_V /* 0 */, QREG_CC_C);
38330194cf31SLaurent Vivier } else {
38340194cf31SLaurent Vivier TCGv X;
38350194cf31SLaurent Vivier /* modulo 17 */
38360194cf31SLaurent Vivier tcg_gen_movi_i32(t1, 17);
38370194cf31SLaurent Vivier tcg_gen_remu_i32(t1, t0, t1);
38380194cf31SLaurent Vivier X = rotate_x(reg, t1, left, 16);
38390194cf31SLaurent Vivier rotate_x_flags(reg, X, 16);
38400194cf31SLaurent Vivier }
38410194cf31SLaurent Vivier gen_partset_reg(OS_WORD, DREG(insn, 0), reg);
38420194cf31SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
38430194cf31SLaurent Vivier }
38440194cf31SLaurent Vivier
DISAS_INSN(rotate_mem)38450194cf31SLaurent Vivier DISAS_INSN(rotate_mem)
38460194cf31SLaurent Vivier {
38470194cf31SLaurent Vivier TCGv src;
38480194cf31SLaurent Vivier TCGv addr;
38490194cf31SLaurent Vivier TCGv shift;
38500194cf31SLaurent Vivier int left = (insn & 0x100);
38510194cf31SLaurent Vivier
38520194cf31SLaurent Vivier SRC_EA(env, src, OS_WORD, 0, &addr);
38530194cf31SLaurent Vivier
38541852ce5aSRichard Henderson shift = tcg_constant_i32(1);
38550194cf31SLaurent Vivier if (insn & 0x0200) {
38560194cf31SLaurent Vivier rotate(src, shift, left, 16);
38570194cf31SLaurent Vivier } else {
38580194cf31SLaurent Vivier TCGv X = rotate_x(src, shift, left, 16);
38590194cf31SLaurent Vivier rotate_x_flags(src, X, 16);
38600194cf31SLaurent Vivier }
38610194cf31SLaurent Vivier DEST_EA(env, insn, OS_WORD, src, &addr);
38620194cf31SLaurent Vivier set_cc_op(s, CC_OP_FLAGS);
38630194cf31SLaurent Vivier }
38640194cf31SLaurent Vivier
DISAS_INSN(bfext_reg)3865ac815f46SRichard Henderson DISAS_INSN(bfext_reg)
3866ac815f46SRichard Henderson {
3867ac815f46SRichard Henderson int ext = read_im16(env, s);
3868ac815f46SRichard Henderson int is_sign = insn & 0x200;
3869ac815f46SRichard Henderson TCGv src = DREG(insn, 0);
3870ac815f46SRichard Henderson TCGv dst = DREG(ext, 12);
3871ac815f46SRichard Henderson int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
3872ac815f46SRichard Henderson int ofs = extract32(ext, 6, 5); /* big bit-endian */
3873ac815f46SRichard Henderson int pos = 32 - ofs - len; /* little bit-endian */
3874ac815f46SRichard Henderson TCGv tmp = tcg_temp_new();
3875ac815f46SRichard Henderson TCGv shift;
3876ac815f46SRichard Henderson
3877808d77bcSLucien Murray-Pitts /*
3878808d77bcSLucien Murray-Pitts * In general, we're going to rotate the field so that it's at the
3879808d77bcSLucien Murray-Pitts * top of the word and then right-shift by the complement of the
3880808d77bcSLucien Murray-Pitts * width to extend the field.
3881808d77bcSLucien Murray-Pitts */
3882ac815f46SRichard Henderson if (ext & 0x20) {
3883ac815f46SRichard Henderson /* Variable width. */
3884ac815f46SRichard Henderson if (ext & 0x800) {
3885ac815f46SRichard Henderson /* Variable offset. */
3886ac815f46SRichard Henderson tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
3887ac815f46SRichard Henderson tcg_gen_rotl_i32(tmp, src, tmp);
3888ac815f46SRichard Henderson } else {
3889ac815f46SRichard Henderson tcg_gen_rotli_i32(tmp, src, ofs);
3890ac815f46SRichard Henderson }
3891ac815f46SRichard Henderson
3892ac815f46SRichard Henderson shift = tcg_temp_new();
3893ac815f46SRichard Henderson tcg_gen_neg_i32(shift, DREG(ext, 0));
3894ac815f46SRichard Henderson tcg_gen_andi_i32(shift, shift, 31);
3895ac815f46SRichard Henderson tcg_gen_sar_i32(QREG_CC_N, tmp, shift);
3896ac815f46SRichard Henderson if (is_sign) {
3897ac815f46SRichard Henderson tcg_gen_mov_i32(dst, QREG_CC_N);
3898ac815f46SRichard Henderson } else {
3899ac815f46SRichard Henderson tcg_gen_shr_i32(dst, tmp, shift);
3900ac815f46SRichard Henderson }
3901ac815f46SRichard Henderson } else {
3902ac815f46SRichard Henderson /* Immediate width. */
3903ac815f46SRichard Henderson if (ext & 0x800) {
3904ac815f46SRichard Henderson /* Variable offset */
3905ac815f46SRichard Henderson tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
3906ac815f46SRichard Henderson tcg_gen_rotl_i32(tmp, src, tmp);
3907ac815f46SRichard Henderson src = tmp;
3908ac815f46SRichard Henderson pos = 32 - len;
3909ac815f46SRichard Henderson } else {
3910808d77bcSLucien Murray-Pitts /*
3911808d77bcSLucien Murray-Pitts * Immediate offset. If the field doesn't wrap around the
3912808d77bcSLucien Murray-Pitts * end of the word, rely on (s)extract completely.
3913808d77bcSLucien Murray-Pitts */
3914ac815f46SRichard Henderson if (pos < 0) {
3915ac815f46SRichard Henderson tcg_gen_rotli_i32(tmp, src, ofs);
3916ac815f46SRichard Henderson src = tmp;
3917ac815f46SRichard Henderson pos = 32 - len;
3918ac815f46SRichard Henderson }
3919ac815f46SRichard Henderson }
3920ac815f46SRichard Henderson
3921ac815f46SRichard Henderson tcg_gen_sextract_i32(QREG_CC_N, src, pos, len);
3922ac815f46SRichard Henderson if (is_sign) {
3923ac815f46SRichard Henderson tcg_gen_mov_i32(dst, QREG_CC_N);
3924ac815f46SRichard Henderson } else {
3925ac815f46SRichard Henderson tcg_gen_extract_i32(dst, src, pos, len);
3926ac815f46SRichard Henderson }
3927ac815f46SRichard Henderson }
3928ac815f46SRichard Henderson
3929ac815f46SRichard Henderson set_cc_op(s, CC_OP_LOGIC);
3930ac815f46SRichard Henderson }
3931ac815f46SRichard Henderson
DISAS_INSN(bfext_mem)3932f2224f2cSRichard Henderson DISAS_INSN(bfext_mem)
3933f2224f2cSRichard Henderson {
3934f2224f2cSRichard Henderson int ext = read_im16(env, s);
3935f2224f2cSRichard Henderson int is_sign = insn & 0x200;
3936f2224f2cSRichard Henderson TCGv dest = DREG(ext, 12);
3937f2224f2cSRichard Henderson TCGv addr, len, ofs;
3938f2224f2cSRichard Henderson
3939f2224f2cSRichard Henderson addr = gen_lea(env, s, insn, OS_UNSIZED);
3940f2224f2cSRichard Henderson if (IS_NULL_QREG(addr)) {
3941f2224f2cSRichard Henderson gen_addr_fault(s);
3942f2224f2cSRichard Henderson return;
3943f2224f2cSRichard Henderson }
3944f2224f2cSRichard Henderson
3945f2224f2cSRichard Henderson if (ext & 0x20) {
3946f2224f2cSRichard Henderson len = DREG(ext, 0);
3947f2224f2cSRichard Henderson } else {
39481852ce5aSRichard Henderson len = tcg_constant_i32(extract32(ext, 0, 5));
3949f2224f2cSRichard Henderson }
3950f2224f2cSRichard Henderson if (ext & 0x800) {
3951f2224f2cSRichard Henderson ofs = DREG(ext, 6);
3952f2224f2cSRichard Henderson } else {
39531852ce5aSRichard Henderson ofs = tcg_constant_i32(extract32(ext, 6, 5));
3954f2224f2cSRichard Henderson }
3955f2224f2cSRichard Henderson
3956f2224f2cSRichard Henderson if (is_sign) {
3957ad75a51eSRichard Henderson gen_helper_bfexts_mem(dest, tcg_env, addr, ofs, len);
3958f2224f2cSRichard Henderson tcg_gen_mov_i32(QREG_CC_N, dest);
3959f2224f2cSRichard Henderson } else {
3960f2224f2cSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64();
3961ad75a51eSRichard Henderson gen_helper_bfextu_mem(tmp, tcg_env, addr, ofs, len);
3962f2224f2cSRichard Henderson tcg_gen_extr_i64_i32(dest, QREG_CC_N, tmp);
3963f2224f2cSRichard Henderson }
3964f2224f2cSRichard Henderson set_cc_op(s, CC_OP_LOGIC);
3965f2224f2cSRichard Henderson }
3966f2224f2cSRichard Henderson
DISAS_INSN(bfop_reg)3967ac815f46SRichard Henderson DISAS_INSN(bfop_reg)
3968ac815f46SRichard Henderson {
3969ac815f46SRichard Henderson int ext = read_im16(env, s);
3970ac815f46SRichard Henderson TCGv src = DREG(insn, 0);
3971ac815f46SRichard Henderson int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
3972ac815f46SRichard Henderson int ofs = extract32(ext, 6, 5); /* big bit-endian */
39737b346e46SRichard Henderson TCGv mask, tofs = NULL, tlen = NULL;
39747b346e46SRichard Henderson bool is_bfffo = (insn & 0x0f00) == 0x0d00;
3975ac815f46SRichard Henderson
3976ac815f46SRichard Henderson if ((ext & 0x820) == 0) {
3977ac815f46SRichard Henderson /* Immediate width and offset. */
3978ac815f46SRichard Henderson uint32_t maski = 0x7fffffffu >> (len - 1);
3979ac815f46SRichard Henderson if (ofs + len <= 32) {
3980ac815f46SRichard Henderson tcg_gen_shli_i32(QREG_CC_N, src, ofs);
3981ac815f46SRichard Henderson } else {
3982ac815f46SRichard Henderson tcg_gen_rotli_i32(QREG_CC_N, src, ofs);
3983ac815f46SRichard Henderson }
3984ac815f46SRichard Henderson tcg_gen_andi_i32(QREG_CC_N, QREG_CC_N, ~maski);
39857b346e46SRichard Henderson
39867b346e46SRichard Henderson mask = tcg_constant_i32(ror32(maski, ofs));
39877b346e46SRichard Henderson if (is_bfffo) {
39887b346e46SRichard Henderson tofs = tcg_constant_i32(ofs);
39897b346e46SRichard Henderson tlen = tcg_constant_i32(len);
3990a45f1763SRichard Henderson }
3991ac815f46SRichard Henderson } else {
3992ac815f46SRichard Henderson TCGv tmp = tcg_temp_new();
39937b346e46SRichard Henderson
39947b346e46SRichard Henderson mask = tcg_temp_new();
3995ac815f46SRichard Henderson if (ext & 0x20) {
3996ac815f46SRichard Henderson /* Variable width */
3997ac815f46SRichard Henderson tcg_gen_subi_i32(tmp, DREG(ext, 0), 1);
3998ac815f46SRichard Henderson tcg_gen_andi_i32(tmp, tmp, 31);
39997b346e46SRichard Henderson tcg_gen_shr_i32(mask, tcg_constant_i32(0x7fffffffu), tmp);
40007b346e46SRichard Henderson if (is_bfffo) {
40017b346e46SRichard Henderson tlen = tcg_temp_new();
4002a45f1763SRichard Henderson tcg_gen_addi_i32(tlen, tmp, 1);
4003a45f1763SRichard Henderson }
4004ac815f46SRichard Henderson } else {
4005ac815f46SRichard Henderson /* Immediate width */
40067b346e46SRichard Henderson tcg_gen_movi_i32(mask, 0x7fffffffu >> (len - 1));
40077b346e46SRichard Henderson if (is_bfffo) {
40087b346e46SRichard Henderson tlen = tcg_constant_i32(len);
4009a45f1763SRichard Henderson }
4010ac815f46SRichard Henderson }
40117b346e46SRichard Henderson
4012ac815f46SRichard Henderson if (ext & 0x800) {
4013ac815f46SRichard Henderson /* Variable offset */
4014ac815f46SRichard Henderson tcg_gen_andi_i32(tmp, DREG(ext, 6), 31);
4015ac815f46SRichard Henderson tcg_gen_rotl_i32(QREG_CC_N, src, tmp);
4016ac815f46SRichard Henderson tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask);
4017ac815f46SRichard Henderson tcg_gen_rotr_i32(mask, mask, tmp);
40187b346e46SRichard Henderson if (is_bfffo) {
40197b346e46SRichard Henderson tofs = tmp;
4020a45f1763SRichard Henderson }
4021ac815f46SRichard Henderson } else {
4022ac815f46SRichard Henderson /* Immediate offset (and variable width) */
4023ac815f46SRichard Henderson tcg_gen_rotli_i32(QREG_CC_N, src, ofs);
4024ac815f46SRichard Henderson tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask);
4025ac815f46SRichard Henderson tcg_gen_rotri_i32(mask, mask, ofs);
40267b346e46SRichard Henderson if (is_bfffo) {
40277b346e46SRichard Henderson tofs = tcg_constant_i32(ofs);
4028a45f1763SRichard Henderson }
4029ac815f46SRichard Henderson }
4030ac815f46SRichard Henderson }
4031ac815f46SRichard Henderson set_cc_op(s, CC_OP_LOGIC);
4032ac815f46SRichard Henderson
4033ac815f46SRichard Henderson switch (insn & 0x0f00) {
4034ac815f46SRichard Henderson case 0x0a00: /* bfchg */
4035ac815f46SRichard Henderson tcg_gen_eqv_i32(src, src, mask);
4036ac815f46SRichard Henderson break;
4037ac815f46SRichard Henderson case 0x0c00: /* bfclr */
4038ac815f46SRichard Henderson tcg_gen_and_i32(src, src, mask);
4039ac815f46SRichard Henderson break;
4040a45f1763SRichard Henderson case 0x0d00: /* bfffo */
4041a45f1763SRichard Henderson gen_helper_bfffo_reg(DREG(ext, 12), QREG_CC_N, tofs, tlen);
4042a45f1763SRichard Henderson break;
4043ac815f46SRichard Henderson case 0x0e00: /* bfset */
4044ac815f46SRichard Henderson tcg_gen_orc_i32(src, src, mask);
4045ac815f46SRichard Henderson break;
4046ac815f46SRichard Henderson case 0x0800: /* bftst */
4047ac815f46SRichard Henderson /* flags already set; no other work to do. */
4048ac815f46SRichard Henderson break;
4049ac815f46SRichard Henderson default:
4050ac815f46SRichard Henderson g_assert_not_reached();
4051ac815f46SRichard Henderson }
4052ac815f46SRichard Henderson }
4053ac815f46SRichard Henderson
DISAS_INSN(bfop_mem)4054f2224f2cSRichard Henderson DISAS_INSN(bfop_mem)
4055f2224f2cSRichard Henderson {
4056f2224f2cSRichard Henderson int ext = read_im16(env, s);
4057f2224f2cSRichard Henderson TCGv addr, len, ofs;
4058a45f1763SRichard Henderson TCGv_i64 t64;
4059f2224f2cSRichard Henderson
4060f2224f2cSRichard Henderson addr = gen_lea(env, s, insn, OS_UNSIZED);
4061f2224f2cSRichard Henderson if (IS_NULL_QREG(addr)) {
4062f2224f2cSRichard Henderson gen_addr_fault(s);
4063f2224f2cSRichard Henderson return;
4064f2224f2cSRichard Henderson }
4065f2224f2cSRichard Henderson
4066f2224f2cSRichard Henderson if (ext & 0x20) {
4067f2224f2cSRichard Henderson len = DREG(ext, 0);
4068f2224f2cSRichard Henderson } else {
40691852ce5aSRichard Henderson len = tcg_constant_i32(extract32(ext, 0, 5));
4070f2224f2cSRichard Henderson }
4071f2224f2cSRichard Henderson if (ext & 0x800) {
4072f2224f2cSRichard Henderson ofs = DREG(ext, 6);
4073f2224f2cSRichard Henderson } else {
40741852ce5aSRichard Henderson ofs = tcg_constant_i32(extract32(ext, 6, 5));
4075f2224f2cSRichard Henderson }
4076f2224f2cSRichard Henderson
4077f2224f2cSRichard Henderson switch (insn & 0x0f00) {
4078f2224f2cSRichard Henderson case 0x0a00: /* bfchg */
4079ad75a51eSRichard Henderson gen_helper_bfchg_mem(QREG_CC_N, tcg_env, addr, ofs, len);
4080f2224f2cSRichard Henderson break;
4081f2224f2cSRichard Henderson case 0x0c00: /* bfclr */
4082ad75a51eSRichard Henderson gen_helper_bfclr_mem(QREG_CC_N, tcg_env, addr, ofs, len);
4083f2224f2cSRichard Henderson break;
4084a45f1763SRichard Henderson case 0x0d00: /* bfffo */
4085a45f1763SRichard Henderson t64 = tcg_temp_new_i64();
4086ad75a51eSRichard Henderson gen_helper_bfffo_mem(t64, tcg_env, addr, ofs, len);
4087a45f1763SRichard Henderson tcg_gen_extr_i64_i32(DREG(ext, 12), QREG_CC_N, t64);
4088a45f1763SRichard Henderson break;
4089f2224f2cSRichard Henderson case 0x0e00: /* bfset */
4090ad75a51eSRichard Henderson gen_helper_bfset_mem(QREG_CC_N, tcg_env, addr, ofs, len);
4091f2224f2cSRichard Henderson break;
4092f2224f2cSRichard Henderson case 0x0800: /* bftst */
4093ad75a51eSRichard Henderson gen_helper_bfexts_mem(QREG_CC_N, tcg_env, addr, ofs, len);
4094f2224f2cSRichard Henderson break;
4095f2224f2cSRichard Henderson default:
4096f2224f2cSRichard Henderson g_assert_not_reached();
4097f2224f2cSRichard Henderson }
4098f2224f2cSRichard Henderson set_cc_op(s, CC_OP_LOGIC);
4099f2224f2cSRichard Henderson }
4100f2224f2cSRichard Henderson
DISAS_INSN(bfins_reg)4101ac815f46SRichard Henderson DISAS_INSN(bfins_reg)
4102ac815f46SRichard Henderson {
4103ac815f46SRichard Henderson int ext = read_im16(env, s);
4104ac815f46SRichard Henderson TCGv dst = DREG(insn, 0);
4105ac815f46SRichard Henderson TCGv src = DREG(ext, 12);
4106ac815f46SRichard Henderson int len = ((extract32(ext, 0, 5) - 1) & 31) + 1;
4107ac815f46SRichard Henderson int ofs = extract32(ext, 6, 5); /* big bit-endian */
4108ac815f46SRichard Henderson int pos = 32 - ofs - len; /* little bit-endian */
4109ac815f46SRichard Henderson TCGv tmp;
4110ac815f46SRichard Henderson
4111ac815f46SRichard Henderson tmp = tcg_temp_new();
4112ac815f46SRichard Henderson
4113ac815f46SRichard Henderson if (ext & 0x20) {
4114ac815f46SRichard Henderson /* Variable width */
4115ac815f46SRichard Henderson tcg_gen_neg_i32(tmp, DREG(ext, 0));
4116ac815f46SRichard Henderson tcg_gen_andi_i32(tmp, tmp, 31);
4117ac815f46SRichard Henderson tcg_gen_shl_i32(QREG_CC_N, src, tmp);
4118ac815f46SRichard Henderson } else {
4119ac815f46SRichard Henderson /* Immediate width */
4120ac815f46SRichard Henderson tcg_gen_shli_i32(QREG_CC_N, src, 32 - len);
4121ac815f46SRichard Henderson }
4122ac815f46SRichard Henderson set_cc_op(s, CC_OP_LOGIC);
4123ac815f46SRichard Henderson
4124ac815f46SRichard Henderson /* Immediate width and offset */
4125ac815f46SRichard Henderson if ((ext & 0x820) == 0) {
4126ac815f46SRichard Henderson /* Check for suitability for deposit. */
4127ac815f46SRichard Henderson if (pos >= 0) {
4128ac815f46SRichard Henderson tcg_gen_deposit_i32(dst, dst, src, pos, len);
4129ac815f46SRichard Henderson } else {
4130ac815f46SRichard Henderson uint32_t maski = -2U << (len - 1);
4131ac815f46SRichard Henderson uint32_t roti = (ofs + len) & 31;
4132ac815f46SRichard Henderson tcg_gen_andi_i32(tmp, src, ~maski);
4133ac815f46SRichard Henderson tcg_gen_rotri_i32(tmp, tmp, roti);
4134ac815f46SRichard Henderson tcg_gen_andi_i32(dst, dst, ror32(maski, roti));
4135ac815f46SRichard Henderson tcg_gen_or_i32(dst, dst, tmp);
4136ac815f46SRichard Henderson }
4137ac815f46SRichard Henderson } else {
4138ac815f46SRichard Henderson TCGv mask = tcg_temp_new();
4139ac815f46SRichard Henderson TCGv rot = tcg_temp_new();
4140ac815f46SRichard Henderson
4141ac815f46SRichard Henderson if (ext & 0x20) {
4142ac815f46SRichard Henderson /* Variable width */
4143ac815f46SRichard Henderson tcg_gen_subi_i32(rot, DREG(ext, 0), 1);
4144ac815f46SRichard Henderson tcg_gen_andi_i32(rot, rot, 31);
4145ac815f46SRichard Henderson tcg_gen_movi_i32(mask, -2);
4146ac815f46SRichard Henderson tcg_gen_shl_i32(mask, mask, rot);
4147ac815f46SRichard Henderson tcg_gen_mov_i32(rot, DREG(ext, 0));
4148ac815f46SRichard Henderson tcg_gen_andc_i32(tmp, src, mask);
4149ac815f46SRichard Henderson } else {
4150ac815f46SRichard Henderson /* Immediate width (variable offset) */
4151ac815f46SRichard Henderson uint32_t maski = -2U << (len - 1);
4152ac815f46SRichard Henderson tcg_gen_andi_i32(tmp, src, ~maski);
4153ac815f46SRichard Henderson tcg_gen_movi_i32(mask, maski);
4154ac815f46SRichard Henderson tcg_gen_movi_i32(rot, len & 31);
4155ac815f46SRichard Henderson }
4156ac815f46SRichard Henderson if (ext & 0x800) {
4157ac815f46SRichard Henderson /* Variable offset */
4158ac815f46SRichard Henderson tcg_gen_add_i32(rot, rot, DREG(ext, 6));
4159ac815f46SRichard Henderson } else {
4160ac815f46SRichard Henderson /* Immediate offset (variable width) */
4161ac815f46SRichard Henderson tcg_gen_addi_i32(rot, rot, ofs);
4162ac815f46SRichard Henderson }
4163ac815f46SRichard Henderson tcg_gen_andi_i32(rot, rot, 31);
4164ac815f46SRichard Henderson tcg_gen_rotr_i32(mask, mask, rot);
4165ac815f46SRichard Henderson tcg_gen_rotr_i32(tmp, tmp, rot);
4166ac815f46SRichard Henderson tcg_gen_and_i32(dst, dst, mask);
4167ac815f46SRichard Henderson tcg_gen_or_i32(dst, dst, tmp);
4168ac815f46SRichard Henderson }
4169ac815f46SRichard Henderson }
4170ac815f46SRichard Henderson
DISAS_INSN(bfins_mem)4171f2224f2cSRichard Henderson DISAS_INSN(bfins_mem)
4172f2224f2cSRichard Henderson {
4173f2224f2cSRichard Henderson int ext = read_im16(env, s);
4174f2224f2cSRichard Henderson TCGv src = DREG(ext, 12);
4175f2224f2cSRichard Henderson TCGv addr, len, ofs;
4176f2224f2cSRichard Henderson
4177f2224f2cSRichard Henderson addr = gen_lea(env, s, insn, OS_UNSIZED);
4178f2224f2cSRichard Henderson if (IS_NULL_QREG(addr)) {
4179f2224f2cSRichard Henderson gen_addr_fault(s);
4180f2224f2cSRichard Henderson return;
4181f2224f2cSRichard Henderson }
4182f2224f2cSRichard Henderson
4183f2224f2cSRichard Henderson if (ext & 0x20) {
4184f2224f2cSRichard Henderson len = DREG(ext, 0);
4185f2224f2cSRichard Henderson } else {
41861852ce5aSRichard Henderson len = tcg_constant_i32(extract32(ext, 0, 5));
4187f2224f2cSRichard Henderson }
4188f2224f2cSRichard Henderson if (ext & 0x800) {
4189f2224f2cSRichard Henderson ofs = DREG(ext, 6);
4190f2224f2cSRichard Henderson } else {
41911852ce5aSRichard Henderson ofs = tcg_constant_i32(extract32(ext, 6, 5));
4192f2224f2cSRichard Henderson }
4193f2224f2cSRichard Henderson
4194ad75a51eSRichard Henderson gen_helper_bfins_mem(QREG_CC_N, tcg_env, addr, src, ofs, len);
4195f2224f2cSRichard Henderson set_cc_op(s, CC_OP_LOGIC);
4196f2224f2cSRichard Henderson }
4197f2224f2cSRichard Henderson
DISAS_INSN(ff1)4198fcf5ef2aSThomas Huth DISAS_INSN(ff1)
4199fcf5ef2aSThomas Huth {
4200fcf5ef2aSThomas Huth TCGv reg;
4201fcf5ef2aSThomas Huth reg = DREG(insn, 0);
4202fcf5ef2aSThomas Huth gen_logic_cc(s, reg, OS_LONG);
4203fcf5ef2aSThomas Huth gen_helper_ff1(reg, reg);
4204fcf5ef2aSThomas Huth }
4205fcf5ef2aSThomas Huth
DISAS_INSN(chk)42068bf6cbafSLaurent Vivier DISAS_INSN(chk)
4207fcf5ef2aSThomas Huth {
42088bf6cbafSLaurent Vivier TCGv src, reg;
42098bf6cbafSLaurent Vivier int opsize;
4210fcf5ef2aSThomas Huth
42118bf6cbafSLaurent Vivier switch ((insn >> 7) & 3) {
42128bf6cbafSLaurent Vivier case 3:
42138bf6cbafSLaurent Vivier opsize = OS_WORD;
42148bf6cbafSLaurent Vivier break;
42158bf6cbafSLaurent Vivier case 2:
42168bf6cbafSLaurent Vivier if (m68k_feature(env, M68K_FEATURE_CHK2)) {
42178bf6cbafSLaurent Vivier opsize = OS_LONG;
42188bf6cbafSLaurent Vivier break;
42198bf6cbafSLaurent Vivier }
42208bf6cbafSLaurent Vivier /* fallthru */
42218bf6cbafSLaurent Vivier default:
4222a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
42238bf6cbafSLaurent Vivier return;
42248bf6cbafSLaurent Vivier }
42258bf6cbafSLaurent Vivier SRC_EA(env, src, opsize, 1, NULL);
42263f215a14SLaurent Vivier reg = gen_extend(s, DREG(insn, 9), opsize, 1);
42278bf6cbafSLaurent Vivier
42288bf6cbafSLaurent Vivier gen_flush_flags(s);
4229ad75a51eSRichard Henderson gen_helper_chk(tcg_env, reg, src);
42308bf6cbafSLaurent Vivier }
42318bf6cbafSLaurent Vivier
DISAS_INSN(chk2)42328bf6cbafSLaurent Vivier DISAS_INSN(chk2)
42338bf6cbafSLaurent Vivier {
42348bf6cbafSLaurent Vivier uint16_t ext;
42358bf6cbafSLaurent Vivier TCGv addr1, addr2, bound1, bound2, reg;
42368bf6cbafSLaurent Vivier int opsize;
42378bf6cbafSLaurent Vivier
42388bf6cbafSLaurent Vivier switch ((insn >> 9) & 3) {
42398bf6cbafSLaurent Vivier case 0:
42408bf6cbafSLaurent Vivier opsize = OS_BYTE;
42418bf6cbafSLaurent Vivier break;
42428bf6cbafSLaurent Vivier case 1:
42438bf6cbafSLaurent Vivier opsize = OS_WORD;
42448bf6cbafSLaurent Vivier break;
42458bf6cbafSLaurent Vivier case 2:
42468bf6cbafSLaurent Vivier opsize = OS_LONG;
42478bf6cbafSLaurent Vivier break;
42488bf6cbafSLaurent Vivier default:
4249a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
42508bf6cbafSLaurent Vivier return;
42518bf6cbafSLaurent Vivier }
42528bf6cbafSLaurent Vivier
42538bf6cbafSLaurent Vivier ext = read_im16(env, s);
42548bf6cbafSLaurent Vivier if ((ext & 0x0800) == 0) {
4255a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
42568bf6cbafSLaurent Vivier return;
42578bf6cbafSLaurent Vivier }
42588bf6cbafSLaurent Vivier
42598bf6cbafSLaurent Vivier addr1 = gen_lea(env, s, insn, OS_UNSIZED);
42608bf6cbafSLaurent Vivier addr2 = tcg_temp_new();
42618bf6cbafSLaurent Vivier tcg_gen_addi_i32(addr2, addr1, opsize_bytes(opsize));
42628bf6cbafSLaurent Vivier
426354e1e0b5SLaurent Vivier bound1 = gen_load(s, opsize, addr1, 1, IS_USER(s));
426454e1e0b5SLaurent Vivier bound2 = gen_load(s, opsize, addr2, 1, IS_USER(s));
42658bf6cbafSLaurent Vivier
42668bf6cbafSLaurent Vivier reg = tcg_temp_new();
42678bf6cbafSLaurent Vivier if (ext & 0x8000) {
42688bf6cbafSLaurent Vivier tcg_gen_mov_i32(reg, AREG(ext, 12));
42698bf6cbafSLaurent Vivier } else {
42708bf6cbafSLaurent Vivier gen_ext(reg, DREG(ext, 12), opsize, 1);
42718bf6cbafSLaurent Vivier }
42728bf6cbafSLaurent Vivier
42738bf6cbafSLaurent Vivier gen_flush_flags(s);
4274ad75a51eSRichard Henderson gen_helper_chk2(tcg_env, reg, bound1, bound2);
42758bf6cbafSLaurent Vivier }
42768bf6cbafSLaurent Vivier
m68k_copy_line(TCGv dst,TCGv src,int index)42779d4f0429SLaurent Vivier static void m68k_copy_line(TCGv dst, TCGv src, int index)
42789d4f0429SLaurent Vivier {
42799d4f0429SLaurent Vivier TCGv addr;
42809d4f0429SLaurent Vivier TCGv_i64 t0, t1;
42819d4f0429SLaurent Vivier
42829d4f0429SLaurent Vivier addr = tcg_temp_new();
42839d4f0429SLaurent Vivier
42849d4f0429SLaurent Vivier t0 = tcg_temp_new_i64();
42859d4f0429SLaurent Vivier t1 = tcg_temp_new_i64();
42869d4f0429SLaurent Vivier
42879d4f0429SLaurent Vivier tcg_gen_andi_i32(addr, src, ~15);
4288b7a94da9SRichard Henderson tcg_gen_qemu_ld_i64(t0, addr, index, MO_TEUQ);
42899d4f0429SLaurent Vivier tcg_gen_addi_i32(addr, addr, 8);
4290b7a94da9SRichard Henderson tcg_gen_qemu_ld_i64(t1, addr, index, MO_TEUQ);
42919d4f0429SLaurent Vivier
42929d4f0429SLaurent Vivier tcg_gen_andi_i32(addr, dst, ~15);
4293b7a94da9SRichard Henderson tcg_gen_qemu_st_i64(t0, addr, index, MO_TEUQ);
42949d4f0429SLaurent Vivier tcg_gen_addi_i32(addr, addr, 8);
4295b7a94da9SRichard Henderson tcg_gen_qemu_st_i64(t1, addr, index, MO_TEUQ);
42969d4f0429SLaurent Vivier }
42979d4f0429SLaurent Vivier
DISAS_INSN(move16_reg)42989d4f0429SLaurent Vivier DISAS_INSN(move16_reg)
42999d4f0429SLaurent Vivier {
43009d4f0429SLaurent Vivier int index = IS_USER(s);
43019d4f0429SLaurent Vivier TCGv tmp;
43029d4f0429SLaurent Vivier uint16_t ext;
43039d4f0429SLaurent Vivier
43049d4f0429SLaurent Vivier ext = read_im16(env, s);
43059d4f0429SLaurent Vivier if ((ext & (1 << 15)) == 0) {
4306a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
43079d4f0429SLaurent Vivier }
43089d4f0429SLaurent Vivier
43099d4f0429SLaurent Vivier m68k_copy_line(AREG(ext, 12), AREG(insn, 0), index);
43109d4f0429SLaurent Vivier
43119d4f0429SLaurent Vivier /* Ax can be Ay, so save Ay before incrementing Ax */
43129d4f0429SLaurent Vivier tmp = tcg_temp_new();
43139d4f0429SLaurent Vivier tcg_gen_mov_i32(tmp, AREG(ext, 12));
43149d4f0429SLaurent Vivier tcg_gen_addi_i32(AREG(insn, 0), AREG(insn, 0), 16);
43159d4f0429SLaurent Vivier tcg_gen_addi_i32(AREG(ext, 12), tmp, 16);
43169d4f0429SLaurent Vivier }
43179d4f0429SLaurent Vivier
DISAS_INSN(move16_mem)43189d4f0429SLaurent Vivier DISAS_INSN(move16_mem)
43199d4f0429SLaurent Vivier {
43209d4f0429SLaurent Vivier int index = IS_USER(s);
43219d4f0429SLaurent Vivier TCGv reg, addr;
43229d4f0429SLaurent Vivier
43239d4f0429SLaurent Vivier reg = AREG(insn, 0);
43241852ce5aSRichard Henderson addr = tcg_constant_i32(read_im32(env, s));
43259d4f0429SLaurent Vivier
43269d4f0429SLaurent Vivier if ((insn >> 3) & 1) {
43279d4f0429SLaurent Vivier /* MOVE16 (xxx).L, (Ay) */
43289d4f0429SLaurent Vivier m68k_copy_line(reg, addr, index);
43299d4f0429SLaurent Vivier } else {
43309d4f0429SLaurent Vivier /* MOVE16 (Ay), (xxx).L */
43319d4f0429SLaurent Vivier m68k_copy_line(addr, reg, index);
43329d4f0429SLaurent Vivier }
43339d4f0429SLaurent Vivier
43349d4f0429SLaurent Vivier if (((insn >> 3) & 2) == 0) {
43359d4f0429SLaurent Vivier /* (Ay)+ */
43369d4f0429SLaurent Vivier tcg_gen_addi_i32(reg, reg, 16);
43379d4f0429SLaurent Vivier }
4338fcf5ef2aSThomas Huth }
4339fcf5ef2aSThomas Huth
DISAS_INSN(strldsr)4340fcf5ef2aSThomas Huth DISAS_INSN(strldsr)
4341fcf5ef2aSThomas Huth {
4342fcf5ef2aSThomas Huth uint16_t ext;
4343fcf5ef2aSThomas Huth uint32_t addr;
4344fcf5ef2aSThomas Huth
4345fcf5ef2aSThomas Huth addr = s->pc - 2;
4346fcf5ef2aSThomas Huth ext = read_im16(env, s);
4347fcf5ef2aSThomas Huth if (ext != 0x46FC) {
4348b9f8e55bSLaurent Vivier gen_exception(s, addr, EXCP_ILLEGAL);
4349fcf5ef2aSThomas Huth return;
4350fcf5ef2aSThomas Huth }
4351fcf5ef2aSThomas Huth ext = read_im16(env, s);
4352fcf5ef2aSThomas Huth if (IS_USER(s) || (ext & SR_S) == 0) {
4353fcf5ef2aSThomas Huth gen_exception(s, addr, EXCP_PRIVILEGE);
4354fcf5ef2aSThomas Huth return;
4355fcf5ef2aSThomas Huth }
4356fcf5ef2aSThomas Huth gen_push(s, gen_get_sr(s));
4357fcf5ef2aSThomas Huth gen_set_sr_im(s, ext, 0);
4358c7546abfSMark Cave-Ayland gen_exit_tb(s);
4359fcf5ef2aSThomas Huth }
4360fcf5ef2aSThomas Huth
DISAS_INSN(move_from_sr)4361fcf5ef2aSThomas Huth DISAS_INSN(move_from_sr)
4362fcf5ef2aSThomas Huth {
4363fcf5ef2aSThomas Huth TCGv sr;
4364fcf5ef2aSThomas Huth
4365b342e56bSMark Cave-Ayland if (IS_USER(s) && m68k_feature(env, M68K_FEATURE_MOVEFROMSR_PRIV)) {
4366a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4367fcf5ef2aSThomas Huth return;
4368fcf5ef2aSThomas Huth }
4369fcf5ef2aSThomas Huth sr = gen_get_sr(s);
4370fcf5ef2aSThomas Huth DEST_EA(env, insn, OS_WORD, sr, NULL);
4371fcf5ef2aSThomas Huth }
4372fcf5ef2aSThomas Huth
43736a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
DISAS_INSN(moves)43745fa9f1f2SLaurent Vivier DISAS_INSN(moves)
43755fa9f1f2SLaurent Vivier {
43765fa9f1f2SLaurent Vivier int opsize;
43775fa9f1f2SLaurent Vivier uint16_t ext;
43785fa9f1f2SLaurent Vivier TCGv reg;
43795fa9f1f2SLaurent Vivier TCGv addr;
43805fa9f1f2SLaurent Vivier int extend;
43815fa9f1f2SLaurent Vivier
43825fa9f1f2SLaurent Vivier if (IS_USER(s)) {
4383a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
43845fa9f1f2SLaurent Vivier return;
43855fa9f1f2SLaurent Vivier }
43865fa9f1f2SLaurent Vivier
43875fa9f1f2SLaurent Vivier ext = read_im16(env, s);
43885fa9f1f2SLaurent Vivier
43895fa9f1f2SLaurent Vivier opsize = insn_opsize(insn);
43905fa9f1f2SLaurent Vivier
43915fa9f1f2SLaurent Vivier if (ext & 0x8000) {
43925fa9f1f2SLaurent Vivier /* address register */
43935fa9f1f2SLaurent Vivier reg = AREG(ext, 12);
43945fa9f1f2SLaurent Vivier extend = 1;
43955fa9f1f2SLaurent Vivier } else {
43965fa9f1f2SLaurent Vivier /* data register */
43975fa9f1f2SLaurent Vivier reg = DREG(ext, 12);
43985fa9f1f2SLaurent Vivier extend = 0;
43995fa9f1f2SLaurent Vivier }
44005fa9f1f2SLaurent Vivier
44015fa9f1f2SLaurent Vivier addr = gen_lea(env, s, insn, opsize);
44025fa9f1f2SLaurent Vivier if (IS_NULL_QREG(addr)) {
44035fa9f1f2SLaurent Vivier gen_addr_fault(s);
44045fa9f1f2SLaurent Vivier return;
44055fa9f1f2SLaurent Vivier }
44065fa9f1f2SLaurent Vivier
44075fa9f1f2SLaurent Vivier if (ext & 0x0800) {
44085fa9f1f2SLaurent Vivier /* from reg to ea */
44095fa9f1f2SLaurent Vivier gen_store(s, opsize, addr, reg, DFC_INDEX(s));
44105fa9f1f2SLaurent Vivier } else {
44115fa9f1f2SLaurent Vivier /* from ea to reg */
44125fa9f1f2SLaurent Vivier TCGv tmp = gen_load(s, opsize, addr, 0, SFC_INDEX(s));
44135fa9f1f2SLaurent Vivier if (extend) {
44145fa9f1f2SLaurent Vivier gen_ext(reg, tmp, opsize, 1);
44155fa9f1f2SLaurent Vivier } else {
44165fa9f1f2SLaurent Vivier gen_partset_reg(opsize, reg, tmp);
44175fa9f1f2SLaurent Vivier }
44185fa9f1f2SLaurent Vivier }
44195fa9f1f2SLaurent Vivier switch (extract32(insn, 3, 3)) {
44205fa9f1f2SLaurent Vivier case 3: /* Indirect postincrement. */
44215fa9f1f2SLaurent Vivier tcg_gen_addi_i32(AREG(insn, 0), addr,
44225fa9f1f2SLaurent Vivier REG(insn, 0) == 7 && opsize == OS_BYTE
44235fa9f1f2SLaurent Vivier ? 2
44245fa9f1f2SLaurent Vivier : opsize_bytes(opsize));
44255fa9f1f2SLaurent Vivier break;
44265fa9f1f2SLaurent Vivier case 4: /* Indirect predecrememnt. */
44275fa9f1f2SLaurent Vivier tcg_gen_mov_i32(AREG(insn, 0), addr);
44285fa9f1f2SLaurent Vivier break;
44295fa9f1f2SLaurent Vivier }
44305fa9f1f2SLaurent Vivier }
44315fa9f1f2SLaurent Vivier
DISAS_INSN(move_to_sr)4432fcf5ef2aSThomas Huth DISAS_INSN(move_to_sr)
4433fcf5ef2aSThomas Huth {
4434fcf5ef2aSThomas Huth if (IS_USER(s)) {
4435a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4436fcf5ef2aSThomas Huth return;
4437fcf5ef2aSThomas Huth }
4438b6a21d8dSLaurent Vivier gen_move_to_sr(env, s, insn, false);
44394106f26eSRichard Henderson gen_exit_tb(s);
4440fcf5ef2aSThomas Huth }
4441fcf5ef2aSThomas Huth
DISAS_INSN(move_from_usp)4442fcf5ef2aSThomas Huth DISAS_INSN(move_from_usp)
4443fcf5ef2aSThomas Huth {
4444fcf5ef2aSThomas Huth if (IS_USER(s)) {
4445a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4446fcf5ef2aSThomas Huth return;
4447fcf5ef2aSThomas Huth }
4448ad75a51eSRichard Henderson tcg_gen_ld_i32(AREG(insn, 0), tcg_env,
4449fcf5ef2aSThomas Huth offsetof(CPUM68KState, sp[M68K_USP]));
4450fcf5ef2aSThomas Huth }
4451fcf5ef2aSThomas Huth
DISAS_INSN(move_to_usp)4452fcf5ef2aSThomas Huth DISAS_INSN(move_to_usp)
4453fcf5ef2aSThomas Huth {
4454fcf5ef2aSThomas Huth if (IS_USER(s)) {
4455a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4456fcf5ef2aSThomas Huth return;
4457fcf5ef2aSThomas Huth }
4458ad75a51eSRichard Henderson tcg_gen_st_i32(AREG(insn, 0), tcg_env,
4459fcf5ef2aSThomas Huth offsetof(CPUM68KState, sp[M68K_USP]));
4460fcf5ef2aSThomas Huth }
4461fcf5ef2aSThomas Huth
DISAS_INSN(halt)4462fcf5ef2aSThomas Huth DISAS_INSN(halt)
4463fcf5ef2aSThomas Huth {
44646ad25764SLaurent Vivier if (IS_USER(s)) {
4465a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
44666ad25764SLaurent Vivier return;
44676ad25764SLaurent Vivier }
44686ad25764SLaurent Vivier
4469fcf5ef2aSThomas Huth gen_exception(s, s->pc, EXCP_HALT_INSN);
4470fcf5ef2aSThomas Huth }
4471fcf5ef2aSThomas Huth
DISAS_INSN(stop)4472fcf5ef2aSThomas Huth DISAS_INSN(stop)
4473fcf5ef2aSThomas Huth {
4474fcf5ef2aSThomas Huth uint16_t ext;
4475fcf5ef2aSThomas Huth
4476fcf5ef2aSThomas Huth if (IS_USER(s)) {
4477a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4478fcf5ef2aSThomas Huth return;
4479fcf5ef2aSThomas Huth }
4480fcf5ef2aSThomas Huth
4481fcf5ef2aSThomas Huth ext = read_im16(env, s);
4482fcf5ef2aSThomas Huth
4483fcf5ef2aSThomas Huth gen_set_sr_im(s, ext, 0);
4484fcf5ef2aSThomas Huth tcg_gen_movi_i32(cpu_halted, 1);
4485fcf5ef2aSThomas Huth gen_exception(s, s->pc, EXCP_HLT);
4486fcf5ef2aSThomas Huth }
4487fcf5ef2aSThomas Huth
DISAS_INSN(rte)4488fcf5ef2aSThomas Huth DISAS_INSN(rte)
4489fcf5ef2aSThomas Huth {
4490fcf5ef2aSThomas Huth if (IS_USER(s)) {
4491a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4492fcf5ef2aSThomas Huth return;
4493fcf5ef2aSThomas Huth }
4494a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_RTE);
4495fcf5ef2aSThomas Huth }
4496fcf5ef2aSThomas Huth
DISAS_INSN(cf_movec)44976e22b28eSLaurent Vivier DISAS_INSN(cf_movec)
4498fcf5ef2aSThomas Huth {
4499fcf5ef2aSThomas Huth uint16_t ext;
4500fcf5ef2aSThomas Huth TCGv reg;
4501fcf5ef2aSThomas Huth
4502fcf5ef2aSThomas Huth if (IS_USER(s)) {
4503a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4504fcf5ef2aSThomas Huth return;
4505fcf5ef2aSThomas Huth }
4506fcf5ef2aSThomas Huth
4507fcf5ef2aSThomas Huth ext = read_im16(env, s);
4508fcf5ef2aSThomas Huth
4509fcf5ef2aSThomas Huth if (ext & 0x8000) {
4510fcf5ef2aSThomas Huth reg = AREG(ext, 12);
4511fcf5ef2aSThomas Huth } else {
4512fcf5ef2aSThomas Huth reg = DREG(ext, 12);
4513fcf5ef2aSThomas Huth }
4514ad75a51eSRichard Henderson gen_helper_cf_movec_to(tcg_env, tcg_constant_i32(ext & 0xfff), reg);
45154106f26eSRichard Henderson gen_exit_tb(s);
45166e22b28eSLaurent Vivier }
45176e22b28eSLaurent Vivier
DISAS_INSN(m68k_movec)45186e22b28eSLaurent Vivier DISAS_INSN(m68k_movec)
45196e22b28eSLaurent Vivier {
45206e22b28eSLaurent Vivier uint16_t ext;
45211852ce5aSRichard Henderson TCGv reg, creg;
45226e22b28eSLaurent Vivier
45236e22b28eSLaurent Vivier if (IS_USER(s)) {
4524a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
45256e22b28eSLaurent Vivier return;
45266e22b28eSLaurent Vivier }
45276e22b28eSLaurent Vivier
45286e22b28eSLaurent Vivier ext = read_im16(env, s);
45296e22b28eSLaurent Vivier
45306e22b28eSLaurent Vivier if (ext & 0x8000) {
45316e22b28eSLaurent Vivier reg = AREG(ext, 12);
45326e22b28eSLaurent Vivier } else {
45336e22b28eSLaurent Vivier reg = DREG(ext, 12);
45346e22b28eSLaurent Vivier }
45351852ce5aSRichard Henderson creg = tcg_constant_i32(ext & 0xfff);
45366e22b28eSLaurent Vivier if (insn & 1) {
4537ad75a51eSRichard Henderson gen_helper_m68k_movec_to(tcg_env, creg, reg);
45386e22b28eSLaurent Vivier } else {
4539ad75a51eSRichard Henderson gen_helper_m68k_movec_from(reg, tcg_env, creg);
45406e22b28eSLaurent Vivier }
45414106f26eSRichard Henderson gen_exit_tb(s);
4542fcf5ef2aSThomas Huth }
4543fcf5ef2aSThomas Huth
DISAS_INSN(intouch)4544fcf5ef2aSThomas Huth DISAS_INSN(intouch)
4545fcf5ef2aSThomas Huth {
4546fcf5ef2aSThomas Huth if (IS_USER(s)) {
4547a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4548fcf5ef2aSThomas Huth return;
4549fcf5ef2aSThomas Huth }
4550fcf5ef2aSThomas Huth /* ICache fetch. Implement as no-op. */
4551fcf5ef2aSThomas Huth }
4552fcf5ef2aSThomas Huth
DISAS_INSN(cpushl)4553fcf5ef2aSThomas Huth DISAS_INSN(cpushl)
4554fcf5ef2aSThomas Huth {
4555fcf5ef2aSThomas Huth if (IS_USER(s)) {
4556a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4557fcf5ef2aSThomas Huth return;
4558fcf5ef2aSThomas Huth }
4559fcf5ef2aSThomas Huth /* Cache push/invalidate. Implement as no-op. */
4560fcf5ef2aSThomas Huth }
4561fcf5ef2aSThomas Huth
DISAS_INSN(cpush)4562f58ed1c5SLaurent Vivier DISAS_INSN(cpush)
4563f58ed1c5SLaurent Vivier {
4564f58ed1c5SLaurent Vivier if (IS_USER(s)) {
4565a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4566f58ed1c5SLaurent Vivier return;
4567f58ed1c5SLaurent Vivier }
4568f58ed1c5SLaurent Vivier /* Cache push/invalidate. Implement as no-op. */
4569f58ed1c5SLaurent Vivier }
4570f58ed1c5SLaurent Vivier
DISAS_INSN(cinv)4571f58ed1c5SLaurent Vivier DISAS_INSN(cinv)
4572f58ed1c5SLaurent Vivier {
4573f58ed1c5SLaurent Vivier if (IS_USER(s)) {
4574a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4575f58ed1c5SLaurent Vivier return;
4576f58ed1c5SLaurent Vivier }
4577f58ed1c5SLaurent Vivier /* Invalidate cache line. Implement as no-op. */
4578f58ed1c5SLaurent Vivier }
4579f58ed1c5SLaurent Vivier
45806a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
DISAS_INSN(pflush)4581e55886c3SLaurent Vivier DISAS_INSN(pflush)
4582e55886c3SLaurent Vivier {
4583e55886c3SLaurent Vivier TCGv opmode;
4584e55886c3SLaurent Vivier
4585e55886c3SLaurent Vivier if (IS_USER(s)) {
4586a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4587e55886c3SLaurent Vivier return;
4588e55886c3SLaurent Vivier }
4589e55886c3SLaurent Vivier
45901852ce5aSRichard Henderson opmode = tcg_constant_i32((insn >> 3) & 3);
4591ad75a51eSRichard Henderson gen_helper_pflush(tcg_env, AREG(insn, 0), opmode);
4592e55886c3SLaurent Vivier }
4593e55886c3SLaurent Vivier
DISAS_INSN(ptest)4594e55886c3SLaurent Vivier DISAS_INSN(ptest)
4595e55886c3SLaurent Vivier {
4596e55886c3SLaurent Vivier TCGv is_read;
4597e55886c3SLaurent Vivier
4598e55886c3SLaurent Vivier if (IS_USER(s)) {
4599a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4600e55886c3SLaurent Vivier return;
4601e55886c3SLaurent Vivier }
46021852ce5aSRichard Henderson is_read = tcg_constant_i32((insn >> 5) & 1);
4603ad75a51eSRichard Henderson gen_helper_ptest(tcg_env, AREG(insn, 0), is_read);
4604e55886c3SLaurent Vivier }
4605e55886c3SLaurent Vivier #endif
4606e55886c3SLaurent Vivier
DISAS_INSN(wddata)4607fcf5ef2aSThomas Huth DISAS_INSN(wddata)
4608fcf5ef2aSThomas Huth {
4609a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4610fcf5ef2aSThomas Huth }
4611fcf5ef2aSThomas Huth
DISAS_INSN(wdebug)4612fcf5ef2aSThomas Huth DISAS_INSN(wdebug)
4613fcf5ef2aSThomas Huth {
4614fcf5ef2aSThomas Huth if (IS_USER(s)) {
4615a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
4616fcf5ef2aSThomas Huth return;
4617fcf5ef2aSThomas Huth }
4618fcf5ef2aSThomas Huth /* TODO: Implement wdebug. */
4619a8d92fd8SRichard Henderson cpu_abort(env_cpu(env), "WDEBUG not implemented");
4620fcf5ef2aSThomas Huth }
46216ad25764SLaurent Vivier #endif
4622fcf5ef2aSThomas Huth
DISAS_INSN(trap)4623fcf5ef2aSThomas Huth DISAS_INSN(trap)
4624fcf5ef2aSThomas Huth {
462579e1d527SRichard Henderson gen_exception(s, s->pc, EXCP_TRAP0 + (insn & 0xf));
4626fcf5ef2aSThomas Huth }
4627fcf5ef2aSThomas Huth
do_trapcc(DisasContext * s,DisasCompare * c)4628aeeb90afSRichard Henderson static void do_trapcc(DisasContext *s, DisasCompare *c)
4629aeeb90afSRichard Henderson {
4630aeeb90afSRichard Henderson if (c->tcond != TCG_COND_NEVER) {
4631aeeb90afSRichard Henderson TCGLabel *over = NULL;
4632aeeb90afSRichard Henderson
4633aeeb90afSRichard Henderson update_cc_op(s);
4634aeeb90afSRichard Henderson
4635aeeb90afSRichard Henderson if (c->tcond != TCG_COND_ALWAYS) {
4636aeeb90afSRichard Henderson /* Jump over if !c. */
4637aeeb90afSRichard Henderson over = gen_new_label();
4638aeeb90afSRichard Henderson tcg_gen_brcond_i32(tcg_invert_cond(c->tcond), c->v1, c->v2, over);
4639aeeb90afSRichard Henderson }
4640aeeb90afSRichard Henderson
4641aeeb90afSRichard Henderson tcg_gen_movi_i32(QREG_PC, s->pc);
4642aeeb90afSRichard Henderson gen_raise_exception_format2(s, EXCP_TRAPCC, s->base.pc_next);
4643aeeb90afSRichard Henderson
4644aeeb90afSRichard Henderson if (over != NULL) {
4645aeeb90afSRichard Henderson gen_set_label(over);
4646aeeb90afSRichard Henderson s->base.is_jmp = DISAS_NEXT;
4647aeeb90afSRichard Henderson }
4648aeeb90afSRichard Henderson }
4649aeeb90afSRichard Henderson }
4650aeeb90afSRichard Henderson
DISAS_INSN(trapcc)4651aeeb90afSRichard Henderson DISAS_INSN(trapcc)
4652aeeb90afSRichard Henderson {
4653aeeb90afSRichard Henderson DisasCompare c;
4654aeeb90afSRichard Henderson
4655aeeb90afSRichard Henderson /* Consume and discard the immediate operand. */
4656aeeb90afSRichard Henderson switch (extract32(insn, 0, 3)) {
4657aeeb90afSRichard Henderson case 2: /* trapcc.w */
4658aeeb90afSRichard Henderson (void)read_im16(env, s);
4659aeeb90afSRichard Henderson break;
4660aeeb90afSRichard Henderson case 3: /* trapcc.l */
4661aeeb90afSRichard Henderson (void)read_im32(env, s);
4662aeeb90afSRichard Henderson break;
4663aeeb90afSRichard Henderson case 4: /* trapcc (no operand) */
4664aeeb90afSRichard Henderson break;
4665aeeb90afSRichard Henderson default:
4666aeeb90afSRichard Henderson /* trapcc registered with only valid opmodes */
4667aeeb90afSRichard Henderson g_assert_not_reached();
4668aeeb90afSRichard Henderson }
4669aeeb90afSRichard Henderson
4670aeeb90afSRichard Henderson gen_cc_cond(&c, s, extract32(insn, 8, 4));
4671aeeb90afSRichard Henderson do_trapcc(s, &c);
4672aeeb90afSRichard Henderson }
4673aeeb90afSRichard Henderson
DISAS_INSN(trapv)467443accc48SRichard Henderson DISAS_INSN(trapv)
467543accc48SRichard Henderson {
467643accc48SRichard Henderson DisasCompare c;
467743accc48SRichard Henderson
467843accc48SRichard Henderson gen_cc_cond(&c, s, 9); /* V set */
467943accc48SRichard Henderson do_trapcc(s, &c);
468043accc48SRichard Henderson }
468143accc48SRichard Henderson
gen_load_fcr(DisasContext * s,TCGv res,int reg)4682ba624944SLaurent Vivier static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
4683ba624944SLaurent Vivier {
4684ba624944SLaurent Vivier switch (reg) {
4685ba624944SLaurent Vivier case M68K_FPIAR:
4686ba624944SLaurent Vivier tcg_gen_movi_i32(res, 0);
4687ba624944SLaurent Vivier break;
4688ba624944SLaurent Vivier case M68K_FPSR:
4689ad75a51eSRichard Henderson tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpsr));
4690ba624944SLaurent Vivier break;
4691ba624944SLaurent Vivier case M68K_FPCR:
4692ad75a51eSRichard Henderson tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpcr));
4693ba624944SLaurent Vivier break;
4694ba624944SLaurent Vivier }
4695ba624944SLaurent Vivier }
4696ba624944SLaurent Vivier
gen_store_fcr(DisasContext * s,TCGv val,int reg)4697ba624944SLaurent Vivier static void gen_store_fcr(DisasContext *s, TCGv val, int reg)
4698ba624944SLaurent Vivier {
4699ba624944SLaurent Vivier switch (reg) {
4700ba624944SLaurent Vivier case M68K_FPIAR:
4701ba624944SLaurent Vivier break;
4702ba624944SLaurent Vivier case M68K_FPSR:
4703ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, offsetof(CPUM68KState, fpsr));
4704ba624944SLaurent Vivier break;
4705ba624944SLaurent Vivier case M68K_FPCR:
4706ad75a51eSRichard Henderson gen_helper_set_fpcr(tcg_env, val);
4707ba624944SLaurent Vivier break;
4708ba624944SLaurent Vivier }
4709ba624944SLaurent Vivier }
4710ba624944SLaurent Vivier
gen_qemu_store_fcr(DisasContext * s,TCGv addr,int reg)4711ba624944SLaurent Vivier static void gen_qemu_store_fcr(DisasContext *s, TCGv addr, int reg)
4712ba624944SLaurent Vivier {
4713ba624944SLaurent Vivier int index = IS_USER(s);
4714ba624944SLaurent Vivier TCGv tmp;
4715ba624944SLaurent Vivier
4716ba624944SLaurent Vivier tmp = tcg_temp_new();
4717ba624944SLaurent Vivier gen_load_fcr(s, tmp, reg);
4718b7a94da9SRichard Henderson tcg_gen_qemu_st_tl(tmp, addr, index, MO_TEUL);
4719ba624944SLaurent Vivier }
4720ba624944SLaurent Vivier
gen_qemu_load_fcr(DisasContext * s,TCGv addr,int reg)4721ba624944SLaurent Vivier static void gen_qemu_load_fcr(DisasContext *s, TCGv addr, int reg)
4722ba624944SLaurent Vivier {
4723ba624944SLaurent Vivier int index = IS_USER(s);
4724ba624944SLaurent Vivier TCGv tmp;
4725ba624944SLaurent Vivier
4726ba624944SLaurent Vivier tmp = tcg_temp_new();
4727b7a94da9SRichard Henderson tcg_gen_qemu_ld_tl(tmp, addr, index, MO_TEUL);
4728ba624944SLaurent Vivier gen_store_fcr(s, tmp, reg);
4729ba624944SLaurent Vivier }
4730ba624944SLaurent Vivier
4731ba624944SLaurent Vivier
gen_op_fmove_fcr(CPUM68KState * env,DisasContext * s,uint32_t insn,uint32_t ext)4732860b9ac7SLaurent Vivier static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
4733860b9ac7SLaurent Vivier uint32_t insn, uint32_t ext)
4734860b9ac7SLaurent Vivier {
4735860b9ac7SLaurent Vivier int mask = (ext >> 10) & 7;
4736860b9ac7SLaurent Vivier int is_write = (ext >> 13) & 1;
4737ba624944SLaurent Vivier int mode = extract32(insn, 3, 3);
4738ba624944SLaurent Vivier int i;
4739ba624944SLaurent Vivier TCGv addr, tmp;
4740860b9ac7SLaurent Vivier
4741ba624944SLaurent Vivier switch (mode) {
4742ba624944SLaurent Vivier case 0: /* Dn */
4743ba624944SLaurent Vivier if (mask != M68K_FPIAR && mask != M68K_FPSR && mask != M68K_FPCR) {
4744a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4745ba624944SLaurent Vivier return;
4746860b9ac7SLaurent Vivier }
4747ba624944SLaurent Vivier if (is_write) {
4748ba624944SLaurent Vivier gen_load_fcr(s, DREG(insn, 0), mask);
4749ba624944SLaurent Vivier } else {
4750ba624944SLaurent Vivier gen_store_fcr(s, DREG(insn, 0), mask);
4751860b9ac7SLaurent Vivier }
4752860b9ac7SLaurent Vivier return;
4753ba624944SLaurent Vivier case 1: /* An, only with FPIAR */
4754ba624944SLaurent Vivier if (mask != M68K_FPIAR) {
4755a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
4756ba624944SLaurent Vivier return;
4757ba624944SLaurent Vivier }
4758ba624944SLaurent Vivier if (is_write) {
4759ba624944SLaurent Vivier gen_load_fcr(s, AREG(insn, 0), mask);
4760ba624944SLaurent Vivier } else {
4761ba624944SLaurent Vivier gen_store_fcr(s, AREG(insn, 0), mask);
4762ba624944SLaurent Vivier }
4763ba624944SLaurent Vivier return;
47646a0e8bb4SLaurent Vivier case 7: /* Immediate */
47656a0e8bb4SLaurent Vivier if (REG(insn, 0) == 4) {
47666a0e8bb4SLaurent Vivier if (is_write ||
47676a0e8bb4SLaurent Vivier (mask != M68K_FPIAR && mask != M68K_FPSR &&
47686a0e8bb4SLaurent Vivier mask != M68K_FPCR)) {
47696a0e8bb4SLaurent Vivier gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
47706a0e8bb4SLaurent Vivier return;
47716a0e8bb4SLaurent Vivier }
47721852ce5aSRichard Henderson tmp = tcg_constant_i32(read_im32(env, s));
47736a0e8bb4SLaurent Vivier gen_store_fcr(s, tmp, mask);
47746a0e8bb4SLaurent Vivier return;
47756a0e8bb4SLaurent Vivier }
47766a0e8bb4SLaurent Vivier break;
4777ba624944SLaurent Vivier default:
4778ba624944SLaurent Vivier break;
4779ba624944SLaurent Vivier }
4780ba624944SLaurent Vivier
4781ba624944SLaurent Vivier tmp = gen_lea(env, s, insn, OS_LONG);
4782ba624944SLaurent Vivier if (IS_NULL_QREG(tmp)) {
4783ba624944SLaurent Vivier gen_addr_fault(s);
4784ba624944SLaurent Vivier return;
4785ba624944SLaurent Vivier }
4786ba624944SLaurent Vivier
4787ba624944SLaurent Vivier addr = tcg_temp_new();
4788ba624944SLaurent Vivier tcg_gen_mov_i32(addr, tmp);
4789ba624944SLaurent Vivier
4790808d77bcSLucien Murray-Pitts /*
4791808d77bcSLucien Murray-Pitts * mask:
4792ba624944SLaurent Vivier *
4793ba624944SLaurent Vivier * 0b100 Floating-Point Control Register
4794ba624944SLaurent Vivier * 0b010 Floating-Point Status Register
4795ba624944SLaurent Vivier * 0b001 Floating-Point Instruction Address Register
4796ba624944SLaurent Vivier *
4797ba624944SLaurent Vivier */
4798ba624944SLaurent Vivier
4799ba624944SLaurent Vivier if (is_write && mode == 4) {
4800ba624944SLaurent Vivier for (i = 2; i >= 0; i--, mask >>= 1) {
4801ba624944SLaurent Vivier if (mask & 1) {
4802ba624944SLaurent Vivier gen_qemu_store_fcr(s, addr, 1 << i);
4803ba624944SLaurent Vivier if (mask != 1) {
4804ba624944SLaurent Vivier tcg_gen_subi_i32(addr, addr, opsize_bytes(OS_LONG));
4805ba624944SLaurent Vivier }
4806ba624944SLaurent Vivier }
4807ba624944SLaurent Vivier }
4808ba624944SLaurent Vivier tcg_gen_mov_i32(AREG(insn, 0), addr);
4809ba624944SLaurent Vivier } else {
4810ba624944SLaurent Vivier for (i = 0; i < 3; i++, mask >>= 1) {
4811ba624944SLaurent Vivier if (mask & 1) {
4812ba624944SLaurent Vivier if (is_write) {
4813ba624944SLaurent Vivier gen_qemu_store_fcr(s, addr, 1 << i);
4814ba624944SLaurent Vivier } else {
4815ba624944SLaurent Vivier gen_qemu_load_fcr(s, addr, 1 << i);
4816ba624944SLaurent Vivier }
4817ba624944SLaurent Vivier if (mask != 1 || mode == 3) {
4818ba624944SLaurent Vivier tcg_gen_addi_i32(addr, addr, opsize_bytes(OS_LONG));
4819ba624944SLaurent Vivier }
4820ba624944SLaurent Vivier }
4821ba624944SLaurent Vivier }
4822ba624944SLaurent Vivier if (mode == 3) {
4823ba624944SLaurent Vivier tcg_gen_mov_i32(AREG(insn, 0), addr);
4824ba624944SLaurent Vivier }
4825ba624944SLaurent Vivier }
4826860b9ac7SLaurent Vivier }
4827860b9ac7SLaurent Vivier
gen_op_fmovem(CPUM68KState * env,DisasContext * s,uint32_t insn,uint32_t ext)4828a1e58ddcSLaurent Vivier static void gen_op_fmovem(CPUM68KState *env, DisasContext *s,
4829a1e58ddcSLaurent Vivier uint32_t insn, uint32_t ext)
4830a1e58ddcSLaurent Vivier {
4831a1e58ddcSLaurent Vivier int opsize;
4832a1e58ddcSLaurent Vivier TCGv addr, tmp;
4833a1e58ddcSLaurent Vivier int mode = (ext >> 11) & 0x3;
4834a1e58ddcSLaurent Vivier int is_load = ((ext & 0x2000) == 0);
4835a1e58ddcSLaurent Vivier
4836a1e58ddcSLaurent Vivier if (m68k_feature(s->env, M68K_FEATURE_FPU)) {
4837a1e58ddcSLaurent Vivier opsize = OS_EXTENDED;
4838a1e58ddcSLaurent Vivier } else {
4839a1e58ddcSLaurent Vivier opsize = OS_DOUBLE; /* FIXME */
4840a1e58ddcSLaurent Vivier }
4841a1e58ddcSLaurent Vivier
4842a1e58ddcSLaurent Vivier addr = gen_lea(env, s, insn, opsize);
4843a1e58ddcSLaurent Vivier if (IS_NULL_QREG(addr)) {
4844a1e58ddcSLaurent Vivier gen_addr_fault(s);
4845a1e58ddcSLaurent Vivier return;
4846a1e58ddcSLaurent Vivier }
4847a1e58ddcSLaurent Vivier
4848a1e58ddcSLaurent Vivier tmp = tcg_temp_new();
4849a1e58ddcSLaurent Vivier if (mode & 0x1) {
4850a1e58ddcSLaurent Vivier /* Dynamic register list */
4851a1e58ddcSLaurent Vivier tcg_gen_ext8u_i32(tmp, DREG(ext, 4));
4852a1e58ddcSLaurent Vivier } else {
4853a1e58ddcSLaurent Vivier /* Static register list */
4854a1e58ddcSLaurent Vivier tcg_gen_movi_i32(tmp, ext & 0xff);
4855a1e58ddcSLaurent Vivier }
4856a1e58ddcSLaurent Vivier
4857a1e58ddcSLaurent Vivier if (!is_load && (mode & 2) == 0) {
4858808d77bcSLucien Murray-Pitts /*
4859808d77bcSLucien Murray-Pitts * predecrement addressing mode
4860a1e58ddcSLaurent Vivier * only available to store register to memory
4861a1e58ddcSLaurent Vivier */
4862a1e58ddcSLaurent Vivier if (opsize == OS_EXTENDED) {
4863ad75a51eSRichard Henderson gen_helper_fmovemx_st_predec(tmp, tcg_env, addr, tmp);
4864a1e58ddcSLaurent Vivier } else {
4865ad75a51eSRichard Henderson gen_helper_fmovemd_st_predec(tmp, tcg_env, addr, tmp);
4866a1e58ddcSLaurent Vivier }
4867a1e58ddcSLaurent Vivier } else {
4868a1e58ddcSLaurent Vivier /* postincrement addressing mode */
4869a1e58ddcSLaurent Vivier if (opsize == OS_EXTENDED) {
4870a1e58ddcSLaurent Vivier if (is_load) {
4871ad75a51eSRichard Henderson gen_helper_fmovemx_ld_postinc(tmp, tcg_env, addr, tmp);
4872a1e58ddcSLaurent Vivier } else {
4873ad75a51eSRichard Henderson gen_helper_fmovemx_st_postinc(tmp, tcg_env, addr, tmp);
4874a1e58ddcSLaurent Vivier }
4875a1e58ddcSLaurent Vivier } else {
4876a1e58ddcSLaurent Vivier if (is_load) {
4877ad75a51eSRichard Henderson gen_helper_fmovemd_ld_postinc(tmp, tcg_env, addr, tmp);
4878a1e58ddcSLaurent Vivier } else {
4879ad75a51eSRichard Henderson gen_helper_fmovemd_st_postinc(tmp, tcg_env, addr, tmp);
4880a1e58ddcSLaurent Vivier }
4881a1e58ddcSLaurent Vivier }
4882a1e58ddcSLaurent Vivier }
4883a1e58ddcSLaurent Vivier if ((insn & 070) == 030 || (insn & 070) == 040) {
4884a1e58ddcSLaurent Vivier tcg_gen_mov_i32(AREG(insn, 0), tmp);
4885a1e58ddcSLaurent Vivier }
4886a1e58ddcSLaurent Vivier }
4887a1e58ddcSLaurent Vivier
4888808d77bcSLucien Murray-Pitts /*
4889808d77bcSLucien Murray-Pitts * ??? FP exceptions are not implemented. Most exceptions are deferred until
4890808d77bcSLucien Murray-Pitts * immediately before the next FP instruction is executed.
4891808d77bcSLucien Murray-Pitts */
DISAS_INSN(fpu)4892fcf5ef2aSThomas Huth DISAS_INSN(fpu)
4893fcf5ef2aSThomas Huth {
4894fcf5ef2aSThomas Huth uint16_t ext;
4895fcf5ef2aSThomas Huth int opmode;
4896fcf5ef2aSThomas Huth int opsize;
4897f83311e4SLaurent Vivier TCGv_ptr cpu_src, cpu_dest;
4898fcf5ef2aSThomas Huth
4899fcf5ef2aSThomas Huth ext = read_im16(env, s);
4900fcf5ef2aSThomas Huth opmode = ext & 0x7f;
4901fcf5ef2aSThomas Huth switch ((ext >> 13) & 7) {
49029d403660SLaurent Vivier case 0:
4903fcf5ef2aSThomas Huth break;
4904fcf5ef2aSThomas Huth case 1:
4905fcf5ef2aSThomas Huth goto undef;
49069d403660SLaurent Vivier case 2:
49079d403660SLaurent Vivier if (insn == 0xf200 && (ext & 0xfc00) == 0x5c00) {
49089d403660SLaurent Vivier /* fmovecr */
49091852ce5aSRichard Henderson TCGv rom_offset = tcg_constant_i32(opmode);
49109d403660SLaurent Vivier cpu_dest = gen_fp_ptr(REG(ext, 7));
4911ad75a51eSRichard Henderson gen_helper_fconst(tcg_env, cpu_dest, rom_offset);
49129d403660SLaurent Vivier return;
49139d403660SLaurent Vivier }
49149d403660SLaurent Vivier break;
4915fcf5ef2aSThomas Huth case 3: /* fmove out */
4916f83311e4SLaurent Vivier cpu_src = gen_fp_ptr(REG(ext, 7));
491769e69822SLaurent Vivier opsize = ext_opsize(ext, 10);
491854e1e0b5SLaurent Vivier if (gen_ea_fp(env, s, insn, opsize, cpu_src,
491954e1e0b5SLaurent Vivier EA_STORE, IS_USER(s)) == -1) {
4920f83311e4SLaurent Vivier gen_addr_fault(s);
4921fcf5ef2aSThomas Huth }
4922ad75a51eSRichard Henderson gen_helper_ftst(tcg_env, cpu_src);
4923fcf5ef2aSThomas Huth return;
4924fcf5ef2aSThomas Huth case 4: /* fmove to control register. */
4925fcf5ef2aSThomas Huth case 5: /* fmove from control register. */
4926860b9ac7SLaurent Vivier gen_op_fmove_fcr(env, s, insn, ext);
4927860b9ac7SLaurent Vivier return;
4928fcf5ef2aSThomas Huth case 6: /* fmovem */
4929fcf5ef2aSThomas Huth case 7:
4930a1e58ddcSLaurent Vivier if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU)) {
4931fcf5ef2aSThomas Huth goto undef;
4932fcf5ef2aSThomas Huth }
4933a1e58ddcSLaurent Vivier gen_op_fmovem(env, s, insn, ext);
4934fcf5ef2aSThomas Huth return;
4935fcf5ef2aSThomas Huth }
4936fcf5ef2aSThomas Huth if (ext & (1 << 14)) {
4937fcf5ef2aSThomas Huth /* Source effective address. */
493869e69822SLaurent Vivier opsize = ext_opsize(ext, 10);
4939f83311e4SLaurent Vivier cpu_src = gen_fp_result_ptr();
494054e1e0b5SLaurent Vivier if (gen_ea_fp(env, s, insn, opsize, cpu_src,
494154e1e0b5SLaurent Vivier EA_LOADS, IS_USER(s)) == -1) {
4942f83311e4SLaurent Vivier gen_addr_fault(s);
4943f83311e4SLaurent Vivier return;
4944fcf5ef2aSThomas Huth }
4945fcf5ef2aSThomas Huth } else {
4946fcf5ef2aSThomas Huth /* Source register. */
4947f83311e4SLaurent Vivier opsize = OS_EXTENDED;
4948f83311e4SLaurent Vivier cpu_src = gen_fp_ptr(REG(ext, 10));
4949fcf5ef2aSThomas Huth }
4950f83311e4SLaurent Vivier cpu_dest = gen_fp_ptr(REG(ext, 7));
4951fcf5ef2aSThomas Huth switch (opmode) {
495277bdb229SLaurent Vivier case 0: /* fmove */
4953f83311e4SLaurent Vivier gen_fp_move(cpu_dest, cpu_src);
4954fcf5ef2aSThomas Huth break;
495577bdb229SLaurent Vivier case 0x40: /* fsmove */
4956ad75a51eSRichard Henderson gen_helper_fsround(tcg_env, cpu_dest, cpu_src);
495777bdb229SLaurent Vivier break;
495877bdb229SLaurent Vivier case 0x44: /* fdmove */
4959ad75a51eSRichard Henderson gen_helper_fdround(tcg_env, cpu_dest, cpu_src);
496077bdb229SLaurent Vivier break;
4961fcf5ef2aSThomas Huth case 1: /* fint */
4962ad75a51eSRichard Henderson gen_helper_firound(tcg_env, cpu_dest, cpu_src);
4963fcf5ef2aSThomas Huth break;
4964eee6b892SLaurent Vivier case 2: /* fsinh */
4965ad75a51eSRichard Henderson gen_helper_fsinh(tcg_env, cpu_dest, cpu_src);
4966eee6b892SLaurent Vivier break;
4967fcf5ef2aSThomas Huth case 3: /* fintrz */
4968ad75a51eSRichard Henderson gen_helper_fitrunc(tcg_env, cpu_dest, cpu_src);
4969fcf5ef2aSThomas Huth break;
4970a51b6bc3SLaurent Vivier case 4: /* fsqrt */
4971ad75a51eSRichard Henderson gen_helper_fsqrt(tcg_env, cpu_dest, cpu_src);
4972fcf5ef2aSThomas Huth break;
4973a51b6bc3SLaurent Vivier case 0x41: /* fssqrt */
4974ad75a51eSRichard Henderson gen_helper_fssqrt(tcg_env, cpu_dest, cpu_src);
4975a51b6bc3SLaurent Vivier break;
4976a51b6bc3SLaurent Vivier case 0x45: /* fdsqrt */
4977ad75a51eSRichard Henderson gen_helper_fdsqrt(tcg_env, cpu_dest, cpu_src);
4978a51b6bc3SLaurent Vivier break;
49794b5c65b8SLaurent Vivier case 0x06: /* flognp1 */
4980ad75a51eSRichard Henderson gen_helper_flognp1(tcg_env, cpu_dest, cpu_src);
49814b5c65b8SLaurent Vivier break;
4982250b1da3SLaurent Vivier case 0x08: /* fetoxm1 */
4983ad75a51eSRichard Henderson gen_helper_fetoxm1(tcg_env, cpu_dest, cpu_src);
4984250b1da3SLaurent Vivier break;
49859937b029SLaurent Vivier case 0x09: /* ftanh */
4986ad75a51eSRichard Henderson gen_helper_ftanh(tcg_env, cpu_dest, cpu_src);
49879937b029SLaurent Vivier break;
49888c992abcSLaurent Vivier case 0x0a: /* fatan */
4989ad75a51eSRichard Henderson gen_helper_fatan(tcg_env, cpu_dest, cpu_src);
49908c992abcSLaurent Vivier break;
4991bc20b34eSLaurent Vivier case 0x0c: /* fasin */
4992ad75a51eSRichard Henderson gen_helper_fasin(tcg_env, cpu_dest, cpu_src);
4993bc20b34eSLaurent Vivier break;
4994e3655afaSLaurent Vivier case 0x0d: /* fatanh */
4995ad75a51eSRichard Henderson gen_helper_fatanh(tcg_env, cpu_dest, cpu_src);
4996e3655afaSLaurent Vivier break;
49975add1ac4SLaurent Vivier case 0x0e: /* fsin */
4998ad75a51eSRichard Henderson gen_helper_fsin(tcg_env, cpu_dest, cpu_src);
49995add1ac4SLaurent Vivier break;
500027340180SLaurent Vivier case 0x0f: /* ftan */
5001ad75a51eSRichard Henderson gen_helper_ftan(tcg_env, cpu_dest, cpu_src);
500227340180SLaurent Vivier break;
500340ad0873SLaurent Vivier case 0x10: /* fetox */
5004ad75a51eSRichard Henderson gen_helper_fetox(tcg_env, cpu_dest, cpu_src);
500540ad0873SLaurent Vivier break;
5006068f1615SLaurent Vivier case 0x11: /* ftwotox */
5007ad75a51eSRichard Henderson gen_helper_ftwotox(tcg_env, cpu_dest, cpu_src);
5008068f1615SLaurent Vivier break;
50096c25be6eSLaurent Vivier case 0x12: /* ftentox */
5010ad75a51eSRichard Henderson gen_helper_ftentox(tcg_env, cpu_dest, cpu_src);
50116c25be6eSLaurent Vivier break;
501250067bd1SLaurent Vivier case 0x14: /* flogn */
5013ad75a51eSRichard Henderson gen_helper_flogn(tcg_env, cpu_dest, cpu_src);
501450067bd1SLaurent Vivier break;
5015248efb66SLaurent Vivier case 0x15: /* flog10 */
5016ad75a51eSRichard Henderson gen_helper_flog10(tcg_env, cpu_dest, cpu_src);
5017248efb66SLaurent Vivier break;
501867b453edSLaurent Vivier case 0x16: /* flog2 */
5019ad75a51eSRichard Henderson gen_helper_flog2(tcg_env, cpu_dest, cpu_src);
502067b453edSLaurent Vivier break;
502177bdb229SLaurent Vivier case 0x18: /* fabs */
5022ad75a51eSRichard Henderson gen_helper_fabs(tcg_env, cpu_dest, cpu_src);
5023fcf5ef2aSThomas Huth break;
502477bdb229SLaurent Vivier case 0x58: /* fsabs */
5025ad75a51eSRichard Henderson gen_helper_fsabs(tcg_env, cpu_dest, cpu_src);
502677bdb229SLaurent Vivier break;
502777bdb229SLaurent Vivier case 0x5c: /* fdabs */
5028ad75a51eSRichard Henderson gen_helper_fdabs(tcg_env, cpu_dest, cpu_src);
502977bdb229SLaurent Vivier break;
503002f9124eSLaurent Vivier case 0x19: /* fcosh */
5031ad75a51eSRichard Henderson gen_helper_fcosh(tcg_env, cpu_dest, cpu_src);
503202f9124eSLaurent Vivier break;
503377bdb229SLaurent Vivier case 0x1a: /* fneg */
5034ad75a51eSRichard Henderson gen_helper_fneg(tcg_env, cpu_dest, cpu_src);
503577bdb229SLaurent Vivier break;
503677bdb229SLaurent Vivier case 0x5a: /* fsneg */
5037ad75a51eSRichard Henderson gen_helper_fsneg(tcg_env, cpu_dest, cpu_src);
503877bdb229SLaurent Vivier break;
503977bdb229SLaurent Vivier case 0x5e: /* fdneg */
5040ad75a51eSRichard Henderson gen_helper_fdneg(tcg_env, cpu_dest, cpu_src);
5041fcf5ef2aSThomas Huth break;
5042c84813b8SLaurent Vivier case 0x1c: /* facos */
5043ad75a51eSRichard Henderson gen_helper_facos(tcg_env, cpu_dest, cpu_src);
5044c84813b8SLaurent Vivier break;
504568d0ed37SLaurent Vivier case 0x1d: /* fcos */
5046ad75a51eSRichard Henderson gen_helper_fcos(tcg_env, cpu_dest, cpu_src);
504768d0ed37SLaurent Vivier break;
50480d379c17SLaurent Vivier case 0x1e: /* fgetexp */
5049ad75a51eSRichard Henderson gen_helper_fgetexp(tcg_env, cpu_dest, cpu_src);
50500d379c17SLaurent Vivier break;
50510d379c17SLaurent Vivier case 0x1f: /* fgetman */
5052ad75a51eSRichard Henderson gen_helper_fgetman(tcg_env, cpu_dest, cpu_src);
50530d379c17SLaurent Vivier break;
5054a51b6bc3SLaurent Vivier case 0x20: /* fdiv */
5055ad75a51eSRichard Henderson gen_helper_fdiv(tcg_env, cpu_dest, cpu_src, cpu_dest);
5056fcf5ef2aSThomas Huth break;
5057a51b6bc3SLaurent Vivier case 0x60: /* fsdiv */
5058ad75a51eSRichard Henderson gen_helper_fsdiv(tcg_env, cpu_dest, cpu_src, cpu_dest);
5059a51b6bc3SLaurent Vivier break;
5060a51b6bc3SLaurent Vivier case 0x64: /* fddiv */
5061ad75a51eSRichard Henderson gen_helper_fddiv(tcg_env, cpu_dest, cpu_src, cpu_dest);
5062a51b6bc3SLaurent Vivier break;
5063591596b7SLaurent Vivier case 0x21: /* fmod */
5064ad75a51eSRichard Henderson gen_helper_fmod(tcg_env, cpu_dest, cpu_src, cpu_dest);
5065591596b7SLaurent Vivier break;
5066a51b6bc3SLaurent Vivier case 0x22: /* fadd */
5067ad75a51eSRichard Henderson gen_helper_fadd(tcg_env, cpu_dest, cpu_src, cpu_dest);
5068fcf5ef2aSThomas Huth break;
5069a51b6bc3SLaurent Vivier case 0x62: /* fsadd */
5070ad75a51eSRichard Henderson gen_helper_fsadd(tcg_env, cpu_dest, cpu_src, cpu_dest);
5071a51b6bc3SLaurent Vivier break;
5072a51b6bc3SLaurent Vivier case 0x66: /* fdadd */
5073ad75a51eSRichard Henderson gen_helper_fdadd(tcg_env, cpu_dest, cpu_src, cpu_dest);
5074a51b6bc3SLaurent Vivier break;
5075a51b6bc3SLaurent Vivier case 0x23: /* fmul */
5076ad75a51eSRichard Henderson gen_helper_fmul(tcg_env, cpu_dest, cpu_src, cpu_dest);
5077fcf5ef2aSThomas Huth break;
5078a51b6bc3SLaurent Vivier case 0x63: /* fsmul */
5079ad75a51eSRichard Henderson gen_helper_fsmul(tcg_env, cpu_dest, cpu_src, cpu_dest);
5080a51b6bc3SLaurent Vivier break;
5081a51b6bc3SLaurent Vivier case 0x67: /* fdmul */
5082ad75a51eSRichard Henderson gen_helper_fdmul(tcg_env, cpu_dest, cpu_src, cpu_dest);
5083a51b6bc3SLaurent Vivier break;
50842f77995cSLaurent Vivier case 0x24: /* fsgldiv */
5085ad75a51eSRichard Henderson gen_helper_fsgldiv(tcg_env, cpu_dest, cpu_src, cpu_dest);
50862f77995cSLaurent Vivier break;
5087591596b7SLaurent Vivier case 0x25: /* frem */
5088ad75a51eSRichard Henderson gen_helper_frem(tcg_env, cpu_dest, cpu_src, cpu_dest);
5089591596b7SLaurent Vivier break;
50900d379c17SLaurent Vivier case 0x26: /* fscale */
5091ad75a51eSRichard Henderson gen_helper_fscale(tcg_env, cpu_dest, cpu_src, cpu_dest);
50920d379c17SLaurent Vivier break;
50932f77995cSLaurent Vivier case 0x27: /* fsglmul */
5094ad75a51eSRichard Henderson gen_helper_fsglmul(tcg_env, cpu_dest, cpu_src, cpu_dest);
50952f77995cSLaurent Vivier break;
5096a51b6bc3SLaurent Vivier case 0x28: /* fsub */
5097ad75a51eSRichard Henderson gen_helper_fsub(tcg_env, cpu_dest, cpu_src, cpu_dest);
5098fcf5ef2aSThomas Huth break;
5099a51b6bc3SLaurent Vivier case 0x68: /* fssub */
5100ad75a51eSRichard Henderson gen_helper_fssub(tcg_env, cpu_dest, cpu_src, cpu_dest);
5101a51b6bc3SLaurent Vivier break;
5102a51b6bc3SLaurent Vivier case 0x6c: /* fdsub */
5103ad75a51eSRichard Henderson gen_helper_fdsub(tcg_env, cpu_dest, cpu_src, cpu_dest);
5104a51b6bc3SLaurent Vivier break;
510547446c9cSLaurent Vivier case 0x30: case 0x31: case 0x32:
510647446c9cSLaurent Vivier case 0x33: case 0x34: case 0x35:
510747446c9cSLaurent Vivier case 0x36: case 0x37: {
510847446c9cSLaurent Vivier TCGv_ptr cpu_dest2 = gen_fp_ptr(REG(ext, 0));
5109ad75a51eSRichard Henderson gen_helper_fsincos(tcg_env, cpu_dest, cpu_dest2, cpu_src);
511047446c9cSLaurent Vivier }
511147446c9cSLaurent Vivier break;
5112fcf5ef2aSThomas Huth case 0x38: /* fcmp */
5113ad75a51eSRichard Henderson gen_helper_fcmp(tcg_env, cpu_src, cpu_dest);
5114ba624944SLaurent Vivier return;
5115fcf5ef2aSThomas Huth case 0x3a: /* ftst */
5116ad75a51eSRichard Henderson gen_helper_ftst(tcg_env, cpu_src);
5117ba624944SLaurent Vivier return;
5118fcf5ef2aSThomas Huth default:
5119fcf5ef2aSThomas Huth goto undef;
5120fcf5ef2aSThomas Huth }
5121ad75a51eSRichard Henderson gen_helper_ftst(tcg_env, cpu_dest);
5122fcf5ef2aSThomas Huth return;
5123fcf5ef2aSThomas Huth undef:
5124fcf5ef2aSThomas Huth /* FIXME: Is this right for offset addressing modes? */
5125fcf5ef2aSThomas Huth s->pc -= 2;
5126fcf5ef2aSThomas Huth disas_undef_fpu(env, s, insn);
5127fcf5ef2aSThomas Huth }
5128fcf5ef2aSThomas Huth
gen_fcc_cond(DisasCompare * c,DisasContext * s,int cond)5129dd337bf8SLaurent Vivier static void gen_fcc_cond(DisasCompare *c, DisasContext *s, int cond)
5130dd337bf8SLaurent Vivier {
5131dd337bf8SLaurent Vivier TCGv fpsr;
5132dd337bf8SLaurent Vivier
51331852ce5aSRichard Henderson c->v2 = tcg_constant_i32(0);
5134dd337bf8SLaurent Vivier /* TODO: Raise BSUN exception. */
5135dd337bf8SLaurent Vivier fpsr = tcg_temp_new();
5136dd337bf8SLaurent Vivier gen_load_fcr(s, fpsr, M68K_FPSR);
5137dd337bf8SLaurent Vivier switch (cond) {
5138dd337bf8SLaurent Vivier case 0: /* False */
5139dd337bf8SLaurent Vivier case 16: /* Signaling False */
5140dd337bf8SLaurent Vivier c->v1 = c->v2;
5141dd337bf8SLaurent Vivier c->tcond = TCG_COND_NEVER;
5142dd337bf8SLaurent Vivier break;
5143dd337bf8SLaurent Vivier case 1: /* EQual Z */
5144dd337bf8SLaurent Vivier case 17: /* Signaling EQual Z */
5145dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5146dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5147dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5148dd337bf8SLaurent Vivier break;
5149dd337bf8SLaurent Vivier case 2: /* Ordered Greater Than !(A || Z || N) */
5150dd337bf8SLaurent Vivier case 18: /* Greater Than !(A || Z || N) */
5151dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5152dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr,
5153dd337bf8SLaurent Vivier FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
5154dd337bf8SLaurent Vivier c->tcond = TCG_COND_EQ;
5155dd337bf8SLaurent Vivier break;
5156dd337bf8SLaurent Vivier case 3: /* Ordered Greater than or Equal Z || !(A || N) */
5157dd337bf8SLaurent Vivier case 19: /* Greater than or Equal Z || !(A || N) */
5158dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5159dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5160dd337bf8SLaurent Vivier tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
5161dd337bf8SLaurent Vivier tcg_gen_andi_i32(fpsr, fpsr, FPSR_CC_Z | FPSR_CC_N);
5162dd337bf8SLaurent Vivier tcg_gen_or_i32(c->v1, c->v1, fpsr);
5163dd337bf8SLaurent Vivier tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5164dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5165dd337bf8SLaurent Vivier break;
5166dd337bf8SLaurent Vivier case 4: /* Ordered Less Than !(!N || A || Z); */
5167dd337bf8SLaurent Vivier case 20: /* Less Than !(!N || A || Z); */
5168dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5169dd337bf8SLaurent Vivier tcg_gen_xori_i32(c->v1, fpsr, FPSR_CC_N);
5170dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_N | FPSR_CC_A | FPSR_CC_Z);
5171dd337bf8SLaurent Vivier c->tcond = TCG_COND_EQ;
5172dd337bf8SLaurent Vivier break;
5173dd337bf8SLaurent Vivier case 5: /* Ordered Less than or Equal Z || (N && !A) */
5174dd337bf8SLaurent Vivier case 21: /* Less than or Equal Z || (N && !A) */
5175dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5176dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5177dd337bf8SLaurent Vivier tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
5178dd337bf8SLaurent Vivier tcg_gen_andc_i32(c->v1, fpsr, c->v1);
5179dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_Z | FPSR_CC_N);
5180dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5181dd337bf8SLaurent Vivier break;
5182dd337bf8SLaurent Vivier case 6: /* Ordered Greater or Less than !(A || Z) */
5183dd337bf8SLaurent Vivier case 22: /* Greater or Less than !(A || Z) */
5184dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5185dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z);
5186dd337bf8SLaurent Vivier c->tcond = TCG_COND_EQ;
5187dd337bf8SLaurent Vivier break;
5188dd337bf8SLaurent Vivier case 7: /* Ordered !A */
5189dd337bf8SLaurent Vivier case 23: /* Greater, Less or Equal !A */
5190dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5191dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5192dd337bf8SLaurent Vivier c->tcond = TCG_COND_EQ;
5193dd337bf8SLaurent Vivier break;
5194dd337bf8SLaurent Vivier case 8: /* Unordered A */
5195dd337bf8SLaurent Vivier case 24: /* Not Greater, Less or Equal A */
5196dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5197dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
5198dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5199dd337bf8SLaurent Vivier break;
5200dd337bf8SLaurent Vivier case 9: /* Unordered or Equal A || Z */
5201dd337bf8SLaurent Vivier case 25: /* Not Greater or Less then A || Z */
5202dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5203dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z);
5204dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5205dd337bf8SLaurent Vivier break;
5206dd337bf8SLaurent Vivier case 10: /* Unordered or Greater Than A || !(N || Z)) */
5207dd337bf8SLaurent Vivier case 26: /* Not Less or Equal A || !(N || Z)) */
5208dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5209dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5210dd337bf8SLaurent Vivier tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
5211dd337bf8SLaurent Vivier tcg_gen_andi_i32(fpsr, fpsr, FPSR_CC_A | FPSR_CC_N);
5212dd337bf8SLaurent Vivier tcg_gen_or_i32(c->v1, c->v1, fpsr);
5213dd337bf8SLaurent Vivier tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5214dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5215dd337bf8SLaurent Vivier break;
5216dd337bf8SLaurent Vivier case 11: /* Unordered or Greater or Equal A || Z || !N */
5217dd337bf8SLaurent Vivier case 27: /* Not Less Than A || Z || !N */
5218dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5219dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
5220dd337bf8SLaurent Vivier tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
5221dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5222dd337bf8SLaurent Vivier break;
5223dd337bf8SLaurent Vivier case 12: /* Unordered or Less Than A || (N && !Z) */
5224dd337bf8SLaurent Vivier case 28: /* Not Greater than or Equal A || (N && !Z) */
5225dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5226dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5227dd337bf8SLaurent Vivier tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
5228dd337bf8SLaurent Vivier tcg_gen_andc_i32(c->v1, fpsr, c->v1);
5229dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_A | FPSR_CC_N);
5230dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5231dd337bf8SLaurent Vivier break;
5232dd337bf8SLaurent Vivier case 13: /* Unordered or Less or Equal A || Z || N */
5233dd337bf8SLaurent Vivier case 29: /* Not Greater Than A || Z || N */
5234dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5235dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
5236dd337bf8SLaurent Vivier c->tcond = TCG_COND_NE;
5237dd337bf8SLaurent Vivier break;
5238dd337bf8SLaurent Vivier case 14: /* Not Equal !Z */
5239dd337bf8SLaurent Vivier case 30: /* Signaling Not Equal !Z */
5240dd337bf8SLaurent Vivier c->v1 = tcg_temp_new();
5241dd337bf8SLaurent Vivier tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
5242dd337bf8SLaurent Vivier c->tcond = TCG_COND_EQ;
5243dd337bf8SLaurent Vivier break;
5244dd337bf8SLaurent Vivier case 15: /* True */
5245dd337bf8SLaurent Vivier case 31: /* Signaling True */
5246dd337bf8SLaurent Vivier c->v1 = c->v2;
5247dd337bf8SLaurent Vivier c->tcond = TCG_COND_ALWAYS;
5248dd337bf8SLaurent Vivier break;
5249dd337bf8SLaurent Vivier }
5250dd337bf8SLaurent Vivier }
5251dd337bf8SLaurent Vivier
gen_fjmpcc(DisasContext * s,int cond,TCGLabel * l1)5252dd337bf8SLaurent Vivier static void gen_fjmpcc(DisasContext *s, int cond, TCGLabel *l1)
5253dd337bf8SLaurent Vivier {
5254dd337bf8SLaurent Vivier DisasCompare c;
5255dd337bf8SLaurent Vivier
5256dd337bf8SLaurent Vivier gen_fcc_cond(&c, s, cond);
52577cd7b5caSLaurent Vivier update_cc_op(s);
5258dd337bf8SLaurent Vivier tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1);
5259dd337bf8SLaurent Vivier }
5260dd337bf8SLaurent Vivier
DISAS_INSN(fbcc)5261fcf5ef2aSThomas Huth DISAS_INSN(fbcc)
5262fcf5ef2aSThomas Huth {
5263fcf5ef2aSThomas Huth uint32_t offset;
5264dd337bf8SLaurent Vivier uint32_t base;
5265fcf5ef2aSThomas Huth TCGLabel *l1;
5266fcf5ef2aSThomas Huth
5267dd337bf8SLaurent Vivier base = s->pc;
5268dd337bf8SLaurent Vivier offset = (int16_t)read_im16(env, s);
5269fcf5ef2aSThomas Huth if (insn & (1 << 6)) {
5270fcf5ef2aSThomas Huth offset = (offset << 16) | read_im16(env, s);
5271fcf5ef2aSThomas Huth }
5272fcf5ef2aSThomas Huth
5273fcf5ef2aSThomas Huth l1 = gen_new_label();
5274dd337bf8SLaurent Vivier update_cc_op(s);
5275dd337bf8SLaurent Vivier gen_fjmpcc(s, insn & 0x3f, l1);
52768115fc93SRichard Henderson gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
5277fcf5ef2aSThomas Huth gen_set_label(l1);
52788115fc93SRichard Henderson gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
5279dd337bf8SLaurent Vivier }
5280dd337bf8SLaurent Vivier
DISAS_INSN(fscc)5281dd337bf8SLaurent Vivier DISAS_INSN(fscc)
5282dd337bf8SLaurent Vivier {
5283dd337bf8SLaurent Vivier DisasCompare c;
5284dd337bf8SLaurent Vivier int cond;
5285dd337bf8SLaurent Vivier TCGv tmp;
5286dd337bf8SLaurent Vivier uint16_t ext;
5287dd337bf8SLaurent Vivier
5288dd337bf8SLaurent Vivier ext = read_im16(env, s);
5289dd337bf8SLaurent Vivier cond = ext & 0x3f;
5290dd337bf8SLaurent Vivier gen_fcc_cond(&c, s, cond);
5291dd337bf8SLaurent Vivier
5292dd337bf8SLaurent Vivier tmp = tcg_temp_new();
529327f9af76SRichard Henderson tcg_gen_negsetcond_i32(c.tcond, tmp, c.v1, c.v2);
5294dd337bf8SLaurent Vivier
5295dd337bf8SLaurent Vivier DEST_EA(env, insn, OS_BYTE, tmp, NULL);
5296fcf5ef2aSThomas Huth }
5297fcf5ef2aSThomas Huth
DISAS_INSN(ftrapcc)5298cc1cc264SRichard Henderson DISAS_INSN(ftrapcc)
5299cc1cc264SRichard Henderson {
5300cc1cc264SRichard Henderson DisasCompare c;
5301cc1cc264SRichard Henderson uint16_t ext;
5302cc1cc264SRichard Henderson int cond;
5303cc1cc264SRichard Henderson
5304cc1cc264SRichard Henderson ext = read_im16(env, s);
5305cc1cc264SRichard Henderson cond = ext & 0x3f;
5306cc1cc264SRichard Henderson
5307cc1cc264SRichard Henderson /* Consume and discard the immediate operand. */
5308cc1cc264SRichard Henderson switch (extract32(insn, 0, 3)) {
5309cc1cc264SRichard Henderson case 2: /* ftrapcc.w */
5310cc1cc264SRichard Henderson (void)read_im16(env, s);
5311cc1cc264SRichard Henderson break;
5312cc1cc264SRichard Henderson case 3: /* ftrapcc.l */
5313cc1cc264SRichard Henderson (void)read_im32(env, s);
5314cc1cc264SRichard Henderson break;
5315cc1cc264SRichard Henderson case 4: /* ftrapcc (no operand) */
5316cc1cc264SRichard Henderson break;
5317cc1cc264SRichard Henderson default:
5318cc1cc264SRichard Henderson /* ftrapcc registered with only valid opmodes */
5319cc1cc264SRichard Henderson g_assert_not_reached();
5320cc1cc264SRichard Henderson }
5321cc1cc264SRichard Henderson
5322cc1cc264SRichard Henderson gen_fcc_cond(&c, s, cond);
5323cc1cc264SRichard Henderson do_trapcc(s, &c);
5324cc1cc264SRichard Henderson }
5325cc1cc264SRichard Henderson
53266a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
DISAS_INSN(frestore)5327fcf5ef2aSThomas Huth DISAS_INSN(frestore)
5328fcf5ef2aSThomas Huth {
5329fff3b4b0SLaurent Vivier TCGv addr;
5330fcf5ef2aSThomas Huth
53316ad25764SLaurent Vivier if (IS_USER(s)) {
5332a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
53336ad25764SLaurent Vivier return;
53346ad25764SLaurent Vivier }
5335fff3b4b0SLaurent Vivier if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
5336fff3b4b0SLaurent Vivier SRC_EA(env, addr, OS_LONG, 0, NULL);
5337fff3b4b0SLaurent Vivier /* FIXME: check the state frame */
5338fff3b4b0SLaurent Vivier } else {
5339fff3b4b0SLaurent Vivier disas_undef(env, s, insn);
5340fff3b4b0SLaurent Vivier }
5341fcf5ef2aSThomas Huth }
5342fcf5ef2aSThomas Huth
DISAS_INSN(fsave)5343fcf5ef2aSThomas Huth DISAS_INSN(fsave)
5344fcf5ef2aSThomas Huth {
53456ad25764SLaurent Vivier if (IS_USER(s)) {
5346a575cbe0SRichard Henderson gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
53476ad25764SLaurent Vivier return;
5348fcf5ef2aSThomas Huth }
5349fcf5ef2aSThomas Huth
5350fff3b4b0SLaurent Vivier if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
5351fff3b4b0SLaurent Vivier /* always write IDLE */
53521852ce5aSRichard Henderson TCGv idle = tcg_constant_i32(0x41000000);
5353fff3b4b0SLaurent Vivier DEST_EA(env, insn, OS_LONG, idle, NULL);
5354fff3b4b0SLaurent Vivier } else {
5355fff3b4b0SLaurent Vivier disas_undef(env, s, insn);
5356fff3b4b0SLaurent Vivier }
5357fcf5ef2aSThomas Huth }
53586ad25764SLaurent Vivier #endif
5359fcf5ef2aSThomas Huth
gen_mac_extract_word(DisasContext * s,TCGv val,int upper)5360fcf5ef2aSThomas Huth static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
5361fcf5ef2aSThomas Huth {
5362fcf5ef2aSThomas Huth TCGv tmp = tcg_temp_new();
5363fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_FI) {
5364fcf5ef2aSThomas Huth if (upper)
5365fcf5ef2aSThomas Huth tcg_gen_andi_i32(tmp, val, 0xffff0000);
5366fcf5ef2aSThomas Huth else
5367fcf5ef2aSThomas Huth tcg_gen_shli_i32(tmp, val, 16);
5368fcf5ef2aSThomas Huth } else if (s->env->macsr & MACSR_SU) {
5369fcf5ef2aSThomas Huth if (upper)
5370fcf5ef2aSThomas Huth tcg_gen_sari_i32(tmp, val, 16);
5371fcf5ef2aSThomas Huth else
5372fcf5ef2aSThomas Huth tcg_gen_ext16s_i32(tmp, val);
5373fcf5ef2aSThomas Huth } else {
5374fcf5ef2aSThomas Huth if (upper)
5375fcf5ef2aSThomas Huth tcg_gen_shri_i32(tmp, val, 16);
5376fcf5ef2aSThomas Huth else
5377fcf5ef2aSThomas Huth tcg_gen_ext16u_i32(tmp, val);
5378fcf5ef2aSThomas Huth }
5379fcf5ef2aSThomas Huth return tmp;
5380fcf5ef2aSThomas Huth }
5381fcf5ef2aSThomas Huth
gen_mac_clear_flags(void)5382fcf5ef2aSThomas Huth static void gen_mac_clear_flags(void)
5383fcf5ef2aSThomas Huth {
5384fcf5ef2aSThomas Huth tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR,
5385fcf5ef2aSThomas Huth ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV));
5386fcf5ef2aSThomas Huth }
5387fcf5ef2aSThomas Huth
DISAS_INSN(mac)5388fcf5ef2aSThomas Huth DISAS_INSN(mac)
5389fcf5ef2aSThomas Huth {
5390fcf5ef2aSThomas Huth TCGv rx;
5391fcf5ef2aSThomas Huth TCGv ry;
5392fcf5ef2aSThomas Huth uint16_t ext;
5393fcf5ef2aSThomas Huth int acc;
5394fcf5ef2aSThomas Huth TCGv tmp;
5395fcf5ef2aSThomas Huth TCGv addr;
5396fcf5ef2aSThomas Huth TCGv loadval;
5397fcf5ef2aSThomas Huth int dual;
5398fcf5ef2aSThomas Huth TCGv saved_flags;
5399fcf5ef2aSThomas Huth
5400fcf5ef2aSThomas Huth if (!s->done_mac) {
5401fcf5ef2aSThomas Huth s->mactmp = tcg_temp_new_i64();
5402fcf5ef2aSThomas Huth s->done_mac = 1;
5403fcf5ef2aSThomas Huth }
5404fcf5ef2aSThomas Huth
5405fcf5ef2aSThomas Huth ext = read_im16(env, s);
5406fcf5ef2aSThomas Huth
5407fcf5ef2aSThomas Huth acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
5408fcf5ef2aSThomas Huth dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
5409fcf5ef2aSThomas Huth if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
5410fcf5ef2aSThomas Huth disas_undef(env, s, insn);
5411fcf5ef2aSThomas Huth return;
5412fcf5ef2aSThomas Huth }
5413fcf5ef2aSThomas Huth if (insn & 0x30) {
5414fcf5ef2aSThomas Huth /* MAC with load. */
5415fcf5ef2aSThomas Huth tmp = gen_lea(env, s, insn, OS_LONG);
5416fcf5ef2aSThomas Huth addr = tcg_temp_new();
5417fcf5ef2aSThomas Huth tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK);
5418808d77bcSLucien Murray-Pitts /*
5419808d77bcSLucien Murray-Pitts * Load the value now to ensure correct exception behavior.
5420808d77bcSLucien Murray-Pitts * Perform writeback after reading the MAC inputs.
5421808d77bcSLucien Murray-Pitts */
542254e1e0b5SLaurent Vivier loadval = gen_load(s, OS_LONG, addr, 0, IS_USER(s));
5423fcf5ef2aSThomas Huth
5424fcf5ef2aSThomas Huth acc ^= 1;
5425fcf5ef2aSThomas Huth rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
5426fcf5ef2aSThomas Huth ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
5427fcf5ef2aSThomas Huth } else {
5428fcf5ef2aSThomas Huth loadval = addr = NULL_QREG;
5429fcf5ef2aSThomas Huth rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
5430fcf5ef2aSThomas Huth ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5431fcf5ef2aSThomas Huth }
5432fcf5ef2aSThomas Huth
5433fcf5ef2aSThomas Huth gen_mac_clear_flags();
5434fcf5ef2aSThomas Huth #if 0
5435fcf5ef2aSThomas Huth l1 = -1;
5436fcf5ef2aSThomas Huth /* Disabled because conditional branches clobber temporary vars. */
5437fcf5ef2aSThomas Huth if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
5438fcf5ef2aSThomas Huth /* Skip the multiply if we know we will ignore it. */
5439fcf5ef2aSThomas Huth l1 = gen_new_label();
5440fcf5ef2aSThomas Huth tmp = tcg_temp_new();
5441fcf5ef2aSThomas Huth tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8));
5442fcf5ef2aSThomas Huth gen_op_jmp_nz32(tmp, l1);
5443fcf5ef2aSThomas Huth }
5444fcf5ef2aSThomas Huth #endif
5445fcf5ef2aSThomas Huth
5446fcf5ef2aSThomas Huth if ((ext & 0x0800) == 0) {
5447fcf5ef2aSThomas Huth /* Word. */
5448fcf5ef2aSThomas Huth rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
5449fcf5ef2aSThomas Huth ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
5450fcf5ef2aSThomas Huth }
5451fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_FI) {
5452ad75a51eSRichard Henderson gen_helper_macmulf(s->mactmp, tcg_env, rx, ry);
5453fcf5ef2aSThomas Huth } else {
5454fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_SU)
5455ad75a51eSRichard Henderson gen_helper_macmuls(s->mactmp, tcg_env, rx, ry);
5456fcf5ef2aSThomas Huth else
5457ad75a51eSRichard Henderson gen_helper_macmulu(s->mactmp, tcg_env, rx, ry);
5458fcf5ef2aSThomas Huth switch ((ext >> 9) & 3) {
5459fcf5ef2aSThomas Huth case 1:
5460fcf5ef2aSThomas Huth tcg_gen_shli_i64(s->mactmp, s->mactmp, 1);
5461fcf5ef2aSThomas Huth break;
5462fcf5ef2aSThomas Huth case 3:
5463fcf5ef2aSThomas Huth tcg_gen_shri_i64(s->mactmp, s->mactmp, 1);
5464fcf5ef2aSThomas Huth break;
5465fcf5ef2aSThomas Huth }
5466fcf5ef2aSThomas Huth }
5467fcf5ef2aSThomas Huth
5468fcf5ef2aSThomas Huth if (dual) {
5469fcf5ef2aSThomas Huth /* Save the overflow flag from the multiply. */
5470fcf5ef2aSThomas Huth saved_flags = tcg_temp_new();
5471fcf5ef2aSThomas Huth tcg_gen_mov_i32(saved_flags, QREG_MACSR);
5472fcf5ef2aSThomas Huth } else {
5473fcf5ef2aSThomas Huth saved_flags = NULL_QREG;
5474fcf5ef2aSThomas Huth }
5475fcf5ef2aSThomas Huth
5476fcf5ef2aSThomas Huth #if 0
5477fcf5ef2aSThomas Huth /* Disabled because conditional branches clobber temporary vars. */
5478fcf5ef2aSThomas Huth if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
5479fcf5ef2aSThomas Huth /* Skip the accumulate if the value is already saturated. */
5480fcf5ef2aSThomas Huth l1 = gen_new_label();
5481fcf5ef2aSThomas Huth tmp = tcg_temp_new();
54821852ce5aSRichard Henderson gen_op_and32(tmp, QREG_MACSR, tcg_constant_i32(MACSR_PAV0 << acc));
5483fcf5ef2aSThomas Huth gen_op_jmp_nz32(tmp, l1);
5484fcf5ef2aSThomas Huth }
5485fcf5ef2aSThomas Huth #endif
5486fcf5ef2aSThomas Huth
5487fcf5ef2aSThomas Huth if (insn & 0x100)
5488fcf5ef2aSThomas Huth tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
5489fcf5ef2aSThomas Huth else
5490fcf5ef2aSThomas Huth tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
5491fcf5ef2aSThomas Huth
5492fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_FI)
5493ad75a51eSRichard Henderson gen_helper_macsatf(tcg_env, tcg_constant_i32(acc));
5494fcf5ef2aSThomas Huth else if (s->env->macsr & MACSR_SU)
5495ad75a51eSRichard Henderson gen_helper_macsats(tcg_env, tcg_constant_i32(acc));
5496fcf5ef2aSThomas Huth else
5497ad75a51eSRichard Henderson gen_helper_macsatu(tcg_env, tcg_constant_i32(acc));
5498fcf5ef2aSThomas Huth
5499fcf5ef2aSThomas Huth #if 0
5500fcf5ef2aSThomas Huth /* Disabled because conditional branches clobber temporary vars. */
5501fcf5ef2aSThomas Huth if (l1 != -1)
5502fcf5ef2aSThomas Huth gen_set_label(l1);
5503fcf5ef2aSThomas Huth #endif
5504fcf5ef2aSThomas Huth
5505fcf5ef2aSThomas Huth if (dual) {
5506fcf5ef2aSThomas Huth /* Dual accumulate variant. */
5507fcf5ef2aSThomas Huth acc = (ext >> 2) & 3;
5508fcf5ef2aSThomas Huth /* Restore the overflow flag from the multiplier. */
5509fcf5ef2aSThomas Huth tcg_gen_mov_i32(QREG_MACSR, saved_flags);
5510fcf5ef2aSThomas Huth #if 0
5511fcf5ef2aSThomas Huth /* Disabled because conditional branches clobber temporary vars. */
5512fcf5ef2aSThomas Huth if ((s->env->macsr & MACSR_OMC) != 0) {
5513fcf5ef2aSThomas Huth /* Skip the accumulate if the value is already saturated. */
5514fcf5ef2aSThomas Huth l1 = gen_new_label();
5515fcf5ef2aSThomas Huth tmp = tcg_temp_new();
55161852ce5aSRichard Henderson gen_op_and32(tmp, QREG_MACSR, tcg_constant_i32(MACSR_PAV0 << acc));
5517fcf5ef2aSThomas Huth gen_op_jmp_nz32(tmp, l1);
5518fcf5ef2aSThomas Huth }
5519fcf5ef2aSThomas Huth #endif
5520fcf5ef2aSThomas Huth if (ext & 2)
5521fcf5ef2aSThomas Huth tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
5522fcf5ef2aSThomas Huth else
5523fcf5ef2aSThomas Huth tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
5524fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_FI)
5525ad75a51eSRichard Henderson gen_helper_macsatf(tcg_env, tcg_constant_i32(acc));
5526fcf5ef2aSThomas Huth else if (s->env->macsr & MACSR_SU)
5527ad75a51eSRichard Henderson gen_helper_macsats(tcg_env, tcg_constant_i32(acc));
5528fcf5ef2aSThomas Huth else
5529ad75a51eSRichard Henderson gen_helper_macsatu(tcg_env, tcg_constant_i32(acc));
5530fcf5ef2aSThomas Huth #if 0
5531fcf5ef2aSThomas Huth /* Disabled because conditional branches clobber temporary vars. */
5532fcf5ef2aSThomas Huth if (l1 != -1)
5533fcf5ef2aSThomas Huth gen_set_label(l1);
5534fcf5ef2aSThomas Huth #endif
5535fcf5ef2aSThomas Huth }
5536ad75a51eSRichard Henderson gen_helper_mac_set_flags(tcg_env, tcg_constant_i32(acc));
5537fcf5ef2aSThomas Huth
5538fcf5ef2aSThomas Huth if (insn & 0x30) {
5539fcf5ef2aSThomas Huth TCGv rw;
5540fcf5ef2aSThomas Huth rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
5541fcf5ef2aSThomas Huth tcg_gen_mov_i32(rw, loadval);
5542808d77bcSLucien Murray-Pitts /*
5543808d77bcSLucien Murray-Pitts * FIXME: Should address writeback happen with the masked or
5544808d77bcSLucien Murray-Pitts * unmasked value?
5545808d77bcSLucien Murray-Pitts */
5546fcf5ef2aSThomas Huth switch ((insn >> 3) & 7) {
5547fcf5ef2aSThomas Huth case 3: /* Post-increment. */
5548fcf5ef2aSThomas Huth tcg_gen_addi_i32(AREG(insn, 0), addr, 4);
5549fcf5ef2aSThomas Huth break;
5550fcf5ef2aSThomas Huth case 4: /* Pre-decrement. */
5551fcf5ef2aSThomas Huth tcg_gen_mov_i32(AREG(insn, 0), addr);
5552fcf5ef2aSThomas Huth }
5553fcf5ef2aSThomas Huth }
5554fcf5ef2aSThomas Huth }
5555fcf5ef2aSThomas Huth
DISAS_INSN(from_mac)5556fcf5ef2aSThomas Huth DISAS_INSN(from_mac)
5557fcf5ef2aSThomas Huth {
5558fcf5ef2aSThomas Huth TCGv rx;
5559fcf5ef2aSThomas Huth TCGv_i64 acc;
5560fcf5ef2aSThomas Huth int accnum;
5561fcf5ef2aSThomas Huth
5562fcf5ef2aSThomas Huth rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5563fcf5ef2aSThomas Huth accnum = (insn >> 9) & 3;
5564fcf5ef2aSThomas Huth acc = MACREG(accnum);
5565fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_FI) {
5566ad75a51eSRichard Henderson gen_helper_get_macf(rx, tcg_env, acc);
5567fcf5ef2aSThomas Huth } else if ((s->env->macsr & MACSR_OMC) == 0) {
5568fcf5ef2aSThomas Huth tcg_gen_extrl_i64_i32(rx, acc);
5569fcf5ef2aSThomas Huth } else if (s->env->macsr & MACSR_SU) {
5570fcf5ef2aSThomas Huth gen_helper_get_macs(rx, acc);
5571fcf5ef2aSThomas Huth } else {
5572fcf5ef2aSThomas Huth gen_helper_get_macu(rx, acc);
5573fcf5ef2aSThomas Huth }
5574fcf5ef2aSThomas Huth if (insn & 0x40) {
5575fcf5ef2aSThomas Huth tcg_gen_movi_i64(acc, 0);
5576fcf5ef2aSThomas Huth tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
5577fcf5ef2aSThomas Huth }
5578fcf5ef2aSThomas Huth }
5579fcf5ef2aSThomas Huth
DISAS_INSN(move_mac)5580fcf5ef2aSThomas Huth DISAS_INSN(move_mac)
5581fcf5ef2aSThomas Huth {
5582fcf5ef2aSThomas Huth /* FIXME: This can be done without a helper. */
5583fcf5ef2aSThomas Huth int src;
5584fcf5ef2aSThomas Huth TCGv dest;
5585fcf5ef2aSThomas Huth src = insn & 3;
55861852ce5aSRichard Henderson dest = tcg_constant_i32((insn >> 9) & 3);
5587ad75a51eSRichard Henderson gen_helper_mac_move(tcg_env, dest, tcg_constant_i32(src));
5588fcf5ef2aSThomas Huth gen_mac_clear_flags();
5589ad75a51eSRichard Henderson gen_helper_mac_set_flags(tcg_env, dest);
5590fcf5ef2aSThomas Huth }
5591fcf5ef2aSThomas Huth
DISAS_INSN(from_macsr)5592fcf5ef2aSThomas Huth DISAS_INSN(from_macsr)
5593fcf5ef2aSThomas Huth {
5594fcf5ef2aSThomas Huth TCGv reg;
5595fcf5ef2aSThomas Huth
5596fcf5ef2aSThomas Huth reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5597fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, QREG_MACSR);
5598fcf5ef2aSThomas Huth }
5599fcf5ef2aSThomas Huth
DISAS_INSN(from_mask)5600fcf5ef2aSThomas Huth DISAS_INSN(from_mask)
5601fcf5ef2aSThomas Huth {
5602fcf5ef2aSThomas Huth TCGv reg;
5603fcf5ef2aSThomas Huth reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
5604fcf5ef2aSThomas Huth tcg_gen_mov_i32(reg, QREG_MAC_MASK);
5605fcf5ef2aSThomas Huth }
5606fcf5ef2aSThomas Huth
DISAS_INSN(from_mext)5607fcf5ef2aSThomas Huth DISAS_INSN(from_mext)
5608fcf5ef2aSThomas Huth {
5609fcf5ef2aSThomas Huth TCGv reg;
5610fcf5ef2aSThomas Huth TCGv acc;
5611fcf5ef2aSThomas Huth reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
56121852ce5aSRichard Henderson acc = tcg_constant_i32((insn & 0x400) ? 2 : 0);
5613fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_FI)
5614ad75a51eSRichard Henderson gen_helper_get_mac_extf(reg, tcg_env, acc);
5615fcf5ef2aSThomas Huth else
5616ad75a51eSRichard Henderson gen_helper_get_mac_exti(reg, tcg_env, acc);
5617fcf5ef2aSThomas Huth }
5618fcf5ef2aSThomas Huth
DISAS_INSN(macsr_to_ccr)5619fcf5ef2aSThomas Huth DISAS_INSN(macsr_to_ccr)
5620fcf5ef2aSThomas Huth {
5621fcf5ef2aSThomas Huth TCGv tmp = tcg_temp_new();
562224ec52f9SRichard Henderson
562324ec52f9SRichard Henderson /* Note that X and C are always cleared. */
562424ec52f9SRichard Henderson tcg_gen_andi_i32(tmp, QREG_MACSR, CCF_N | CCF_Z | CCF_V);
5625ad75a51eSRichard Henderson gen_helper_set_ccr(tcg_env, tmp);
5626fcf5ef2aSThomas Huth set_cc_op(s, CC_OP_FLAGS);
5627fcf5ef2aSThomas Huth }
5628fcf5ef2aSThomas Huth
DISAS_INSN(to_mac)5629fcf5ef2aSThomas Huth DISAS_INSN(to_mac)
5630fcf5ef2aSThomas Huth {
5631fcf5ef2aSThomas Huth TCGv_i64 acc;
5632fcf5ef2aSThomas Huth TCGv val;
5633fcf5ef2aSThomas Huth int accnum;
5634fcf5ef2aSThomas Huth accnum = (insn >> 9) & 3;
5635fcf5ef2aSThomas Huth acc = MACREG(accnum);
5636fcf5ef2aSThomas Huth SRC_EA(env, val, OS_LONG, 0, NULL);
5637fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_FI) {
5638fcf5ef2aSThomas Huth tcg_gen_ext_i32_i64(acc, val);
5639fcf5ef2aSThomas Huth tcg_gen_shli_i64(acc, acc, 8);
5640fcf5ef2aSThomas Huth } else if (s->env->macsr & MACSR_SU) {
5641fcf5ef2aSThomas Huth tcg_gen_ext_i32_i64(acc, val);
5642fcf5ef2aSThomas Huth } else {
5643fcf5ef2aSThomas Huth tcg_gen_extu_i32_i64(acc, val);
5644fcf5ef2aSThomas Huth }
5645fcf5ef2aSThomas Huth tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
5646fcf5ef2aSThomas Huth gen_mac_clear_flags();
5647ad75a51eSRichard Henderson gen_helper_mac_set_flags(tcg_env, tcg_constant_i32(accnum));
5648fcf5ef2aSThomas Huth }
5649fcf5ef2aSThomas Huth
DISAS_INSN(to_macsr)5650fcf5ef2aSThomas Huth DISAS_INSN(to_macsr)
5651fcf5ef2aSThomas Huth {
5652fcf5ef2aSThomas Huth TCGv val;
5653fcf5ef2aSThomas Huth SRC_EA(env, val, OS_LONG, 0, NULL);
5654ad75a51eSRichard Henderson gen_helper_set_macsr(tcg_env, val);
56554106f26eSRichard Henderson gen_exit_tb(s);
5656fcf5ef2aSThomas Huth }
5657fcf5ef2aSThomas Huth
DISAS_INSN(to_mask)5658fcf5ef2aSThomas Huth DISAS_INSN(to_mask)
5659fcf5ef2aSThomas Huth {
5660fcf5ef2aSThomas Huth TCGv val;
5661fcf5ef2aSThomas Huth SRC_EA(env, val, OS_LONG, 0, NULL);
5662fcf5ef2aSThomas Huth tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000);
5663fcf5ef2aSThomas Huth }
5664fcf5ef2aSThomas Huth
DISAS_INSN(to_mext)5665fcf5ef2aSThomas Huth DISAS_INSN(to_mext)
5666fcf5ef2aSThomas Huth {
5667fcf5ef2aSThomas Huth TCGv val;
5668fcf5ef2aSThomas Huth TCGv acc;
5669fcf5ef2aSThomas Huth SRC_EA(env, val, OS_LONG, 0, NULL);
56701852ce5aSRichard Henderson acc = tcg_constant_i32((insn & 0x400) ? 2 : 0);
5671fcf5ef2aSThomas Huth if (s->env->macsr & MACSR_FI)
5672ad75a51eSRichard Henderson gen_helper_set_mac_extf(tcg_env, val, acc);
5673fcf5ef2aSThomas Huth else if (s->env->macsr & MACSR_SU)
5674ad75a51eSRichard Henderson gen_helper_set_mac_exts(tcg_env, val, acc);
5675fcf5ef2aSThomas Huth else
5676ad75a51eSRichard Henderson gen_helper_set_mac_extu(tcg_env, val, acc);
5677fcf5ef2aSThomas Huth }
5678fcf5ef2aSThomas Huth
5679fcf5ef2aSThomas Huth static disas_proc opcode_table[65536];
5680fcf5ef2aSThomas Huth
5681fcf5ef2aSThomas Huth static void
register_opcode(disas_proc proc,uint16_t opcode,uint16_t mask)5682fcf5ef2aSThomas Huth register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
5683fcf5ef2aSThomas Huth {
5684fcf5ef2aSThomas Huth int i;
5685fcf5ef2aSThomas Huth int from;
5686fcf5ef2aSThomas Huth int to;
5687fcf5ef2aSThomas Huth
5688fcf5ef2aSThomas Huth /* Sanity check. All set bits must be included in the mask. */
5689fcf5ef2aSThomas Huth if (opcode & ~mask) {
5690fcf5ef2aSThomas Huth fprintf(stderr,
5691fcf5ef2aSThomas Huth "qemu internal error: bogus opcode definition %04x/%04x\n",
5692fcf5ef2aSThomas Huth opcode, mask);
5693fcf5ef2aSThomas Huth abort();
5694fcf5ef2aSThomas Huth }
5695808d77bcSLucien Murray-Pitts /*
5696808d77bcSLucien Murray-Pitts * This could probably be cleverer. For now just optimize the case where
5697808d77bcSLucien Murray-Pitts * the top bits are known.
5698808d77bcSLucien Murray-Pitts */
5699fcf5ef2aSThomas Huth /* Find the first zero bit in the mask. */
5700fcf5ef2aSThomas Huth i = 0x8000;
5701fcf5ef2aSThomas Huth while ((i & mask) != 0)
5702fcf5ef2aSThomas Huth i >>= 1;
5703fcf5ef2aSThomas Huth /* Iterate over all combinations of this and lower bits. */
5704fcf5ef2aSThomas Huth if (i == 0)
5705fcf5ef2aSThomas Huth i = 1;
5706fcf5ef2aSThomas Huth else
5707fcf5ef2aSThomas Huth i <<= 1;
5708fcf5ef2aSThomas Huth from = opcode & ~(i - 1);
5709fcf5ef2aSThomas Huth to = from + i;
5710fcf5ef2aSThomas Huth for (i = from; i < to; i++) {
5711fcf5ef2aSThomas Huth if ((i & mask) == opcode)
5712fcf5ef2aSThomas Huth opcode_table[i] = proc;
5713fcf5ef2aSThomas Huth }
5714fcf5ef2aSThomas Huth }
5715fcf5ef2aSThomas Huth
5716808d77bcSLucien Murray-Pitts /*
5717808d77bcSLucien Murray-Pitts * Register m68k opcode handlers. Order is important.
5718808d77bcSLucien Murray-Pitts * Later insn override earlier ones.
5719808d77bcSLucien Murray-Pitts */
register_m68k_insns(CPUM68KState * env)5720fcf5ef2aSThomas Huth void register_m68k_insns (CPUM68KState *env)
5721fcf5ef2aSThomas Huth {
5722808d77bcSLucien Murray-Pitts /*
5723808d77bcSLucien Murray-Pitts * Build the opcode table only once to avoid
5724808d77bcSLucien Murray-Pitts * multithreading issues.
5725808d77bcSLucien Murray-Pitts */
5726fcf5ef2aSThomas Huth if (opcode_table[0] != NULL) {
5727fcf5ef2aSThomas Huth return;
5728fcf5ef2aSThomas Huth }
5729fcf5ef2aSThomas Huth
5730808d77bcSLucien Murray-Pitts /*
5731808d77bcSLucien Murray-Pitts * use BASE() for instruction available
5732fcf5ef2aSThomas Huth * for CF_ISA_A and M68000.
5733fcf5ef2aSThomas Huth */
5734fcf5ef2aSThomas Huth #define BASE(name, opcode, mask) \
5735fcf5ef2aSThomas Huth register_opcode(disas_##name, 0x##opcode, 0x##mask)
5736fcf5ef2aSThomas Huth #define INSN(name, opcode, mask, feature) do { \
5737fcf5ef2aSThomas Huth if (m68k_feature(env, M68K_FEATURE_##feature)) \
5738fcf5ef2aSThomas Huth BASE(name, opcode, mask); \
5739fcf5ef2aSThomas Huth } while(0)
5740fcf5ef2aSThomas Huth BASE(undef, 0000, 0000);
5741fcf5ef2aSThomas Huth INSN(arith_im, 0080, fff8, CF_ISA_A);
5742aece90d8SMark Cave-Ayland INSN(arith_im, 0000, ff00, M68K);
57438bf6cbafSLaurent Vivier INSN(chk2, 00c0, f9c0, CHK2);
5744fcf5ef2aSThomas Huth INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC);
5745fcf5ef2aSThomas Huth BASE(bitop_reg, 0100, f1c0);
5746fcf5ef2aSThomas Huth BASE(bitop_reg, 0140, f1c0);
5747fcf5ef2aSThomas Huth BASE(bitop_reg, 0180, f1c0);
5748fcf5ef2aSThomas Huth BASE(bitop_reg, 01c0, f1c0);
57491226e212SPavel Dovgalyuk INSN(movep, 0108, f138, MOVEP);
5750fcf5ef2aSThomas Huth INSN(arith_im, 0280, fff8, CF_ISA_A);
5751aece90d8SMark Cave-Ayland INSN(arith_im, 0200, ff00, M68K);
5752aece90d8SMark Cave-Ayland INSN(undef, 02c0, ffc0, M68K);
5753fcf5ef2aSThomas Huth INSN(byterev, 02c0, fff8, CF_ISA_APLUSC);
5754fcf5ef2aSThomas Huth INSN(arith_im, 0480, fff8, CF_ISA_A);
5755aece90d8SMark Cave-Ayland INSN(arith_im, 0400, ff00, M68K);
5756aece90d8SMark Cave-Ayland INSN(undef, 04c0, ffc0, M68K);
5757aece90d8SMark Cave-Ayland INSN(arith_im, 0600, ff00, M68K);
5758aece90d8SMark Cave-Ayland INSN(undef, 06c0, ffc0, M68K);
5759fcf5ef2aSThomas Huth INSN(ff1, 04c0, fff8, CF_ISA_APLUSC);
5760fcf5ef2aSThomas Huth INSN(arith_im, 0680, fff8, CF_ISA_A);
5761fcf5ef2aSThomas Huth INSN(arith_im, 0c00, ff38, CF_ISA_A);
5762aece90d8SMark Cave-Ayland INSN(arith_im, 0c00, ff00, M68K);
5763fcf5ef2aSThomas Huth BASE(bitop_im, 0800, ffc0);
5764fcf5ef2aSThomas Huth BASE(bitop_im, 0840, ffc0);
5765fcf5ef2aSThomas Huth BASE(bitop_im, 0880, ffc0);
5766fcf5ef2aSThomas Huth BASE(bitop_im, 08c0, ffc0);
5767fcf5ef2aSThomas Huth INSN(arith_im, 0a80, fff8, CF_ISA_A);
5768aece90d8SMark Cave-Ayland INSN(arith_im, 0a00, ff00, M68K);
57696a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
5770aece90d8SMark Cave-Ayland INSN(moves, 0e00, ff00, M68K);
57715fa9f1f2SLaurent Vivier #endif
577214f94406SLaurent Vivier INSN(cas, 0ac0, ffc0, CAS);
577314f94406SLaurent Vivier INSN(cas, 0cc0, ffc0, CAS);
577414f94406SLaurent Vivier INSN(cas, 0ec0, ffc0, CAS);
577514f94406SLaurent Vivier INSN(cas2w, 0cfc, ffff, CAS);
577614f94406SLaurent Vivier INSN(cas2l, 0efc, ffff, CAS);
5777fcf5ef2aSThomas Huth BASE(move, 1000, f000);
5778fcf5ef2aSThomas Huth BASE(move, 2000, f000);
5779fcf5ef2aSThomas Huth BASE(move, 3000, f000);
5780aece90d8SMark Cave-Ayland INSN(chk, 4000, f040, M68K);
5781fcf5ef2aSThomas Huth INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
5782fcf5ef2aSThomas Huth INSN(negx, 4080, fff8, CF_ISA_A);
5783aece90d8SMark Cave-Ayland INSN(negx, 4000, ff00, M68K);
5784aece90d8SMark Cave-Ayland INSN(undef, 40c0, ffc0, M68K);
5785fcf5ef2aSThomas Huth INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
5786aece90d8SMark Cave-Ayland INSN(move_from_sr, 40c0, ffc0, M68K);
5787fcf5ef2aSThomas Huth BASE(lea, 41c0, f1c0);
5788fcf5ef2aSThomas Huth BASE(clr, 4200, ff00);
5789fcf5ef2aSThomas Huth BASE(undef, 42c0, ffc0);
5790fcf5ef2aSThomas Huth INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
5791aece90d8SMark Cave-Ayland INSN(move_from_ccr, 42c0, ffc0, M68K);
5792fcf5ef2aSThomas Huth INSN(neg, 4480, fff8, CF_ISA_A);
5793aece90d8SMark Cave-Ayland INSN(neg, 4400, ff00, M68K);
5794aece90d8SMark Cave-Ayland INSN(undef, 44c0, ffc0, M68K);
5795fcf5ef2aSThomas Huth BASE(move_to_ccr, 44c0, ffc0);
5796fcf5ef2aSThomas Huth INSN(not, 4680, fff8, CF_ISA_A);
5797aece90d8SMark Cave-Ayland INSN(not, 4600, ff00, M68K);
57986a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
5799b6a21d8dSLaurent Vivier BASE(move_to_sr, 46c0, ffc0);
58006ad25764SLaurent Vivier #endif
5801aece90d8SMark Cave-Ayland INSN(nbcd, 4800, ffc0, M68K);
5802aece90d8SMark Cave-Ayland INSN(linkl, 4808, fff8, M68K);
5803fcf5ef2aSThomas Huth BASE(pea, 4840, ffc0);
5804fcf5ef2aSThomas Huth BASE(swap, 4840, fff8);
5805fcf5ef2aSThomas Huth INSN(bkpt, 4848, fff8, BKPT);
58067b542eb9SLaurent Vivier INSN(movem, 48d0, fbf8, CF_ISA_A);
58077b542eb9SLaurent Vivier INSN(movem, 48e8, fbf8, CF_ISA_A);
5808aece90d8SMark Cave-Ayland INSN(movem, 4880, fb80, M68K);
5809fcf5ef2aSThomas Huth BASE(ext, 4880, fff8);
5810fcf5ef2aSThomas Huth BASE(ext, 48c0, fff8);
5811fcf5ef2aSThomas Huth BASE(ext, 49c0, fff8);
5812fcf5ef2aSThomas Huth BASE(tst, 4a00, ff00);
5813fcf5ef2aSThomas Huth INSN(tas, 4ac0, ffc0, CF_ISA_B);
5814aece90d8SMark Cave-Ayland INSN(tas, 4ac0, ffc0, M68K);
58156a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
5816fcf5ef2aSThomas Huth INSN(halt, 4ac8, ffff, CF_ISA_A);
5817aece90d8SMark Cave-Ayland INSN(halt, 4ac8, ffff, M68K);
58186ad25764SLaurent Vivier #endif
5819fcf5ef2aSThomas Huth INSN(pulse, 4acc, ffff, CF_ISA_A);
5820fcf5ef2aSThomas Huth BASE(illegal, 4afc, ffff);
5821fcf5ef2aSThomas Huth INSN(mull, 4c00, ffc0, CF_ISA_A);
5822fcf5ef2aSThomas Huth INSN(mull, 4c00, ffc0, LONG_MULDIV);
5823fcf5ef2aSThomas Huth INSN(divl, 4c40, ffc0, CF_ISA_A);
5824fcf5ef2aSThomas Huth INSN(divl, 4c40, ffc0, LONG_MULDIV);
5825fcf5ef2aSThomas Huth INSN(sats, 4c80, fff8, CF_ISA_B);
5826fcf5ef2aSThomas Huth BASE(trap, 4e40, fff0);
5827fcf5ef2aSThomas Huth BASE(link, 4e50, fff8);
5828fcf5ef2aSThomas Huth BASE(unlk, 4e58, fff8);
58296a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
5830fcf5ef2aSThomas Huth INSN(move_to_usp, 4e60, fff8, USP);
5831fcf5ef2aSThomas Huth INSN(move_from_usp, 4e68, fff8, USP);
5832aece90d8SMark Cave-Ayland INSN(reset, 4e70, ffff, M68K);
5833fcf5ef2aSThomas Huth BASE(stop, 4e72, ffff);
5834fcf5ef2aSThomas Huth BASE(rte, 4e73, ffff);
58356e22b28eSLaurent Vivier INSN(cf_movec, 4e7b, ffff, CF_ISA_A);
58368df0e6aeSLucien Murray-Pitts INSN(m68k_movec, 4e7a, fffe, MOVEC);
58376ad25764SLaurent Vivier #endif
58386ad25764SLaurent Vivier BASE(nop, 4e71, ffff);
583918059c9eSLaurent Vivier INSN(rtd, 4e74, ffff, RTD);
5840fcf5ef2aSThomas Huth BASE(rts, 4e75, ffff);
5841aece90d8SMark Cave-Ayland INSN(trapv, 4e76, ffff, M68K);
5842aece90d8SMark Cave-Ayland INSN(rtr, 4e77, ffff, M68K);
5843fcf5ef2aSThomas Huth BASE(jump, 4e80, ffc0);
5844fcf5ef2aSThomas Huth BASE(jump, 4ec0, ffc0);
5845aece90d8SMark Cave-Ayland INSN(addsubq, 5000, f080, M68K);
5846fcf5ef2aSThomas Huth BASE(addsubq, 5080, f0c0);
5847fcf5ef2aSThomas Huth INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */
5848aece90d8SMark Cave-Ayland INSN(scc, 50c0, f0c0, M68K); /* Scc.B <EA> */
5849aece90d8SMark Cave-Ayland INSN(dbcc, 50c8, f0f8, M68K);
5850aeeb90afSRichard Henderson INSN(trapcc, 50fa, f0fe, TRAPCC); /* opmode 010, 011 */
5851aeeb90afSRichard Henderson INSN(trapcc, 50fc, f0ff, TRAPCC); /* opmode 100 */
5852815c6deaSRichard Henderson INSN(trapcc, 51fa, fffe, CF_ISA_A); /* TPF (trapf) opmode 010, 011 */
5853815c6deaSRichard Henderson INSN(trapcc, 51fc, ffff, CF_ISA_A); /* TPF (trapf) opmode 100 */
5854fcf5ef2aSThomas Huth
5855fcf5ef2aSThomas Huth /* Branch instructions. */
5856fcf5ef2aSThomas Huth BASE(branch, 6000, f000);
5857fcf5ef2aSThomas Huth /* Disable long branch instructions, then add back the ones we want. */
5858fcf5ef2aSThomas Huth BASE(undef, 60ff, f0ff); /* All long branches. */
5859fcf5ef2aSThomas Huth INSN(branch, 60ff, f0ff, CF_ISA_B);
5860fcf5ef2aSThomas Huth INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */
5861fcf5ef2aSThomas Huth INSN(branch, 60ff, ffff, BRAL);
5862fcf5ef2aSThomas Huth INSN(branch, 60ff, f0ff, BCCL);
5863fcf5ef2aSThomas Huth
5864fcf5ef2aSThomas Huth BASE(moveq, 7000, f100);
5865fcf5ef2aSThomas Huth INSN(mvzs, 7100, f100, CF_ISA_B);
5866fcf5ef2aSThomas Huth BASE(or, 8000, f000);
5867fcf5ef2aSThomas Huth BASE(divw, 80c0, f0c0);
5868aece90d8SMark Cave-Ayland INSN(sbcd_reg, 8100, f1f8, M68K);
5869aece90d8SMark Cave-Ayland INSN(sbcd_mem, 8108, f1f8, M68K);
5870fcf5ef2aSThomas Huth BASE(addsub, 9000, f000);
5871fcf5ef2aSThomas Huth INSN(undef, 90c0, f0c0, CF_ISA_A);
5872fcf5ef2aSThomas Huth INSN(subx_reg, 9180, f1f8, CF_ISA_A);
5873aece90d8SMark Cave-Ayland INSN(subx_reg, 9100, f138, M68K);
5874aece90d8SMark Cave-Ayland INSN(subx_mem, 9108, f138, M68K);
5875fcf5ef2aSThomas Huth INSN(suba, 91c0, f1c0, CF_ISA_A);
5876aece90d8SMark Cave-Ayland INSN(suba, 90c0, f0c0, M68K);
5877fcf5ef2aSThomas Huth
5878fcf5ef2aSThomas Huth BASE(undef_mac, a000, f000);
5879fcf5ef2aSThomas Huth INSN(mac, a000, f100, CF_EMAC);
5880fcf5ef2aSThomas Huth INSN(from_mac, a180, f9b0, CF_EMAC);
5881fcf5ef2aSThomas Huth INSN(move_mac, a110, f9fc, CF_EMAC);
5882fcf5ef2aSThomas Huth INSN(from_macsr,a980, f9f0, CF_EMAC);
5883fcf5ef2aSThomas Huth INSN(from_mask, ad80, fff0, CF_EMAC);
5884fcf5ef2aSThomas Huth INSN(from_mext, ab80, fbf0, CF_EMAC);
5885fcf5ef2aSThomas Huth INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
5886fcf5ef2aSThomas Huth INSN(to_mac, a100, f9c0, CF_EMAC);
5887fcf5ef2aSThomas Huth INSN(to_macsr, a900, ffc0, CF_EMAC);
5888fcf5ef2aSThomas Huth INSN(to_mext, ab00, fbc0, CF_EMAC);
5889fcf5ef2aSThomas Huth INSN(to_mask, ad00, ffc0, CF_EMAC);
5890fcf5ef2aSThomas Huth
5891fcf5ef2aSThomas Huth INSN(mov3q, a140, f1c0, CF_ISA_B);
5892fcf5ef2aSThomas Huth INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */
5893fcf5ef2aSThomas Huth INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */
5894fcf5ef2aSThomas Huth INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */
5895fcf5ef2aSThomas Huth INSN(cmp, b080, f1c0, CF_ISA_A);
5896fcf5ef2aSThomas Huth INSN(cmpa, b1c0, f1c0, CF_ISA_A);
5897aece90d8SMark Cave-Ayland INSN(cmp, b000, f100, M68K);
5898aece90d8SMark Cave-Ayland INSN(eor, b100, f100, M68K);
5899aece90d8SMark Cave-Ayland INSN(cmpm, b108, f138, M68K);
5900aece90d8SMark Cave-Ayland INSN(cmpa, b0c0, f0c0, M68K);
5901fcf5ef2aSThomas Huth INSN(eor, b180, f1c0, CF_ISA_A);
5902fcf5ef2aSThomas Huth BASE(and, c000, f000);
5903aece90d8SMark Cave-Ayland INSN(exg_dd, c140, f1f8, M68K);
5904aece90d8SMark Cave-Ayland INSN(exg_aa, c148, f1f8, M68K);
5905aece90d8SMark Cave-Ayland INSN(exg_da, c188, f1f8, M68K);
5906fcf5ef2aSThomas Huth BASE(mulw, c0c0, f0c0);
5907aece90d8SMark Cave-Ayland INSN(abcd_reg, c100, f1f8, M68K);
5908aece90d8SMark Cave-Ayland INSN(abcd_mem, c108, f1f8, M68K);
5909fcf5ef2aSThomas Huth BASE(addsub, d000, f000);
5910fcf5ef2aSThomas Huth INSN(undef, d0c0, f0c0, CF_ISA_A);
5911fcf5ef2aSThomas Huth INSN(addx_reg, d180, f1f8, CF_ISA_A);
5912aece90d8SMark Cave-Ayland INSN(addx_reg, d100, f138, M68K);
5913aece90d8SMark Cave-Ayland INSN(addx_mem, d108, f138, M68K);
5914fcf5ef2aSThomas Huth INSN(adda, d1c0, f1c0, CF_ISA_A);
5915aece90d8SMark Cave-Ayland INSN(adda, d0c0, f0c0, M68K);
5916fcf5ef2aSThomas Huth INSN(shift_im, e080, f0f0, CF_ISA_A);
5917fcf5ef2aSThomas Huth INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
5918aece90d8SMark Cave-Ayland INSN(shift8_im, e000, f0f0, M68K);
5919aece90d8SMark Cave-Ayland INSN(shift16_im, e040, f0f0, M68K);
5920aece90d8SMark Cave-Ayland INSN(shift_im, e080, f0f0, M68K);
5921aece90d8SMark Cave-Ayland INSN(shift8_reg, e020, f0f0, M68K);
5922aece90d8SMark Cave-Ayland INSN(shift16_reg, e060, f0f0, M68K);
5923aece90d8SMark Cave-Ayland INSN(shift_reg, e0a0, f0f0, M68K);
5924aece90d8SMark Cave-Ayland INSN(shift_mem, e0c0, fcc0, M68K);
5925aece90d8SMark Cave-Ayland INSN(rotate_im, e090, f0f0, M68K);
5926aece90d8SMark Cave-Ayland INSN(rotate8_im, e010, f0f0, M68K);
5927aece90d8SMark Cave-Ayland INSN(rotate16_im, e050, f0f0, M68K);
5928aece90d8SMark Cave-Ayland INSN(rotate_reg, e0b0, f0f0, M68K);
5929aece90d8SMark Cave-Ayland INSN(rotate8_reg, e030, f0f0, M68K);
5930aece90d8SMark Cave-Ayland INSN(rotate16_reg, e070, f0f0, M68K);
5931aece90d8SMark Cave-Ayland INSN(rotate_mem, e4c0, fcc0, M68K);
5932f2224f2cSRichard Henderson INSN(bfext_mem, e9c0, fdc0, BITFIELD); /* bfextu & bfexts */
5933f2224f2cSRichard Henderson INSN(bfext_reg, e9c0, fdf8, BITFIELD);
5934f2224f2cSRichard Henderson INSN(bfins_mem, efc0, ffc0, BITFIELD);
5935ac815f46SRichard Henderson INSN(bfins_reg, efc0, fff8, BITFIELD);
5936f2224f2cSRichard Henderson INSN(bfop_mem, eac0, ffc0, BITFIELD); /* bfchg */
5937ac815f46SRichard Henderson INSN(bfop_reg, eac0, fff8, BITFIELD); /* bfchg */
5938f2224f2cSRichard Henderson INSN(bfop_mem, ecc0, ffc0, BITFIELD); /* bfclr */
5939ac815f46SRichard Henderson INSN(bfop_reg, ecc0, fff8, BITFIELD); /* bfclr */
5940a45f1763SRichard Henderson INSN(bfop_mem, edc0, ffc0, BITFIELD); /* bfffo */
5941a45f1763SRichard Henderson INSN(bfop_reg, edc0, fff8, BITFIELD); /* bfffo */
5942f2224f2cSRichard Henderson INSN(bfop_mem, eec0, ffc0, BITFIELD); /* bfset */
5943ac815f46SRichard Henderson INSN(bfop_reg, eec0, fff8, BITFIELD); /* bfset */
5944f2224f2cSRichard Henderson INSN(bfop_mem, e8c0, ffc0, BITFIELD); /* bftst */
5945ac815f46SRichard Henderson INSN(bfop_reg, e8c0, fff8, BITFIELD); /* bftst */
5946f83311e4SLaurent Vivier BASE(undef_fpu, f000, f000);
5947fcf5ef2aSThomas Huth INSN(fpu, f200, ffc0, CF_FPU);
5948fcf5ef2aSThomas Huth INSN(fbcc, f280, ffc0, CF_FPU);
5949f83311e4SLaurent Vivier INSN(fpu, f200, ffc0, FPU);
5950dd337bf8SLaurent Vivier INSN(fscc, f240, ffc0, FPU);
5951cc1cc264SRichard Henderson INSN(ftrapcc, f27a, fffe, FPU); /* opmode 010, 011 */
5952cc1cc264SRichard Henderson INSN(ftrapcc, f27c, ffff, FPU); /* opmode 100 */
5953f83311e4SLaurent Vivier INSN(fbcc, f280, ff80, FPU);
59546a140586SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
59556ad25764SLaurent Vivier INSN(frestore, f340, ffc0, CF_FPU);
59566ad25764SLaurent Vivier INSN(fsave, f300, ffc0, CF_FPU);
5957f83311e4SLaurent Vivier INSN(frestore, f340, ffc0, FPU);
5958f83311e4SLaurent Vivier INSN(fsave, f300, ffc0, FPU);
5959fcf5ef2aSThomas Huth INSN(intouch, f340, ffc0, CF_ISA_A);
5960fcf5ef2aSThomas Huth INSN(cpushl, f428, ff38, CF_ISA_A);
5961f58ed1c5SLaurent Vivier INSN(cpush, f420, ff20, M68040);
5962f58ed1c5SLaurent Vivier INSN(cinv, f400, ff20, M68040);
5963e55886c3SLaurent Vivier INSN(pflush, f500, ffe0, M68040);
5964e55886c3SLaurent Vivier INSN(ptest, f548, ffd8, M68040);
5965fcf5ef2aSThomas Huth INSN(wddata, fb00, ff00, CF_ISA_A);
5966fcf5ef2aSThomas Huth INSN(wdebug, fbc0, ffc0, CF_ISA_A);
59676ad25764SLaurent Vivier #endif
59686ad25764SLaurent Vivier INSN(move16_mem, f600, ffe0, M68040);
59696ad25764SLaurent Vivier INSN(move16_reg, f620, fff8, M68040);
5970fcf5ef2aSThomas Huth #undef INSN
5971fcf5ef2aSThomas Huth }
5972fcf5ef2aSThomas Huth
m68k_tr_init_disas_context(DisasContextBase * dcbase,CPUState * cpu)597311ab74b0SRichard Henderson static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
5974fcf5ef2aSThomas Huth {
597511ab74b0SRichard Henderson DisasContext *dc = container_of(dcbase, DisasContext, base);
5976b77af26eSRichard Henderson CPUM68KState *env = cpu_env(cpu);
5977fcf5ef2aSThomas Huth
5978fcf5ef2aSThomas Huth dc->env = env;
597911ab74b0SRichard Henderson dc->pc = dc->base.pc_first;
59808115fc93SRichard Henderson /* This value will always be filled in properly before m68k_tr_tb_stop. */
59818115fc93SRichard Henderson dc->pc_prev = 0xdeadbeef;
5982fcf5ef2aSThomas Huth dc->cc_op = CC_OP_DYNAMIC;
5983fcf5ef2aSThomas Huth dc->cc_op_synced = 1;
5984fcf5ef2aSThomas Huth dc->done_mac = 0;
59858a1e52b6SRichard Henderson dc->writeback_mask = 0;
59865e50c6c7SMark Cave-Ayland
59875e50c6c7SMark Cave-Ayland dc->ss_active = (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS);
59885e50c6c7SMark Cave-Ayland /* If architectural single step active, limit to 1 */
5989661da0f6SRichard Henderson if (dc->ss_active) {
59905e50c6c7SMark Cave-Ayland dc->base.max_insns = 1;
59915e50c6c7SMark Cave-Ayland }
599211ab74b0SRichard Henderson }
5993ecc207d2SLaurent Vivier
m68k_tr_tb_start(DisasContextBase * dcbase,CPUState * cpu)599411ab74b0SRichard Henderson static void m68k_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
599511ab74b0SRichard Henderson {
599611ab74b0SRichard Henderson }
5997fcf5ef2aSThomas Huth
m68k_tr_insn_start(DisasContextBase * dcbase,CPUState * cpu)599811ab74b0SRichard Henderson static void m68k_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
599911ab74b0SRichard Henderson {
600011ab74b0SRichard Henderson DisasContext *dc = container_of(dcbase, DisasContext, base);
600111ab74b0SRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
600211ab74b0SRichard Henderson }
600311ab74b0SRichard Henderson
m68k_tr_translate_insn(DisasContextBase * dcbase,CPUState * cpu)600411ab74b0SRichard Henderson static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
600511ab74b0SRichard Henderson {
600611ab74b0SRichard Henderson DisasContext *dc = container_of(dcbase, DisasContext, base);
6007b77af26eSRichard Henderson CPUM68KState *env = cpu_env(cpu);
6008a56f36c1SRichard Henderson uint16_t insn = read_im16(env, dc);
6009fcf5ef2aSThomas Huth
6010a56f36c1SRichard Henderson opcode_table[insn](env, dc, insn);
6011a56f36c1SRichard Henderson do_writebacks(dc);
6012a56f36c1SRichard Henderson
60138115fc93SRichard Henderson dc->pc_prev = dc->base.pc_next;
6014a575cbe0SRichard Henderson dc->base.pc_next = dc->pc;
6015fcf5ef2aSThomas Huth
60164c7a0f6fSRichard Henderson if (dc->base.is_jmp == DISAS_NEXT) {
6017808d77bcSLucien Murray-Pitts /*
6018808d77bcSLucien Murray-Pitts * Stop translation when the next insn might touch a new page.
60194c7a0f6fSRichard Henderson * This ensures that prefetch aborts at the right place.
60204c7a0f6fSRichard Henderson *
60214c7a0f6fSRichard Henderson * We cannot determine the size of the next insn without
60224c7a0f6fSRichard Henderson * completely decoding it. However, the maximum insn size
60234c7a0f6fSRichard Henderson * is 32 bytes, so end if we do not have that much remaining.
60244c7a0f6fSRichard Henderson * This may produce several small TBs at the end of each page,
60254c7a0f6fSRichard Henderson * but they will all be linked with goto_tb.
60264c7a0f6fSRichard Henderson *
60274c7a0f6fSRichard Henderson * ??? ColdFire maximum is 4 bytes; MC68000's maximum is also
60284c7a0f6fSRichard Henderson * smaller than MC68020's.
60294c7a0f6fSRichard Henderson */
60304c7a0f6fSRichard Henderson target_ulong start_page_offset
60314c7a0f6fSRichard Henderson = dc->pc - (dc->base.pc_first & TARGET_PAGE_MASK);
60324c7a0f6fSRichard Henderson
60334c7a0f6fSRichard Henderson if (start_page_offset >= TARGET_PAGE_SIZE - 32) {
603411ab74b0SRichard Henderson dc->base.is_jmp = DISAS_TOO_MANY;
6035fcf5ef2aSThomas Huth }
603611ab74b0SRichard Henderson }
60374c7a0f6fSRichard Henderson }
603811ab74b0SRichard Henderson
m68k_tr_tb_stop(DisasContextBase * dcbase,CPUState * cpu)603911ab74b0SRichard Henderson static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
604011ab74b0SRichard Henderson {
604111ab74b0SRichard Henderson DisasContext *dc = container_of(dcbase, DisasContext, base);
604211ab74b0SRichard Henderson
6043a575cbe0SRichard Henderson switch (dc->base.is_jmp) {
6044322f244aSLaurent Vivier case DISAS_NORETURN:
6045322f244aSLaurent Vivier break;
604611ab74b0SRichard Henderson case DISAS_TOO_MANY:
6047fcf5ef2aSThomas Huth update_cc_op(dc);
60488115fc93SRichard Henderson gen_jmp_tb(dc, 0, dc->pc, dc->pc_prev);
6049fcf5ef2aSThomas Huth break;
6050fcf5ef2aSThomas Huth case DISAS_JUMP:
60518aaf7da9SRichard Henderson /* We updated CC_OP and PC in gen_jmp/gen_jmp_im. */
6052661da0f6SRichard Henderson if (dc->ss_active) {
60538115fc93SRichard Henderson gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev);
6054322f244aSLaurent Vivier } else {
60558aaf7da9SRichard Henderson tcg_gen_lookup_and_goto_ptr();
6056322f244aSLaurent Vivier }
60578aaf7da9SRichard Henderson break;
60584106f26eSRichard Henderson case DISAS_EXIT:
6059808d77bcSLucien Murray-Pitts /*
6060808d77bcSLucien Murray-Pitts * We updated CC_OP and PC in gen_exit_tb, but also modified
6061808d77bcSLucien Murray-Pitts * other state that may require returning to the main loop.
6062808d77bcSLucien Murray-Pitts */
6063661da0f6SRichard Henderson if (dc->ss_active) {
60648115fc93SRichard Henderson gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev);
6065322f244aSLaurent Vivier } else {
606607ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0);
6067322f244aSLaurent Vivier }
6068fcf5ef2aSThomas Huth break;
606911ab74b0SRichard Henderson default:
607011ab74b0SRichard Henderson g_assert_not_reached();
6071fcf5ef2aSThomas Huth }
6072fcf5ef2aSThomas Huth }
6073fcf5ef2aSThomas Huth
m68k_tr_disas_log(const DisasContextBase * dcbase,CPUState * cpu,FILE * logfile)60748eb806a7SRichard Henderson static void m68k_tr_disas_log(const DisasContextBase *dcbase,
60758eb806a7SRichard Henderson CPUState *cpu, FILE *logfile)
607611ab74b0SRichard Henderson {
60778eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
60788eb806a7SRichard Henderson target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
6079fcf5ef2aSThomas Huth }
608011ab74b0SRichard Henderson
608111ab74b0SRichard Henderson static const TranslatorOps m68k_tr_ops = {
608211ab74b0SRichard Henderson .init_disas_context = m68k_tr_init_disas_context,
608311ab74b0SRichard Henderson .tb_start = m68k_tr_tb_start,
608411ab74b0SRichard Henderson .insn_start = m68k_tr_insn_start,
608511ab74b0SRichard Henderson .translate_insn = m68k_tr_translate_insn,
608611ab74b0SRichard Henderson .tb_stop = m68k_tr_tb_stop,
608711ab74b0SRichard Henderson .disas_log = m68k_tr_disas_log,
608811ab74b0SRichard Henderson };
608911ab74b0SRichard Henderson
gen_intermediate_code(CPUState * cpu,TranslationBlock * tb,int * max_insns,target_ulong pc,void * host_pc)6090597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
6091306c8721SRichard Henderson target_ulong pc, void *host_pc)
609211ab74b0SRichard Henderson {
609311ab74b0SRichard Henderson DisasContext dc;
6094306c8721SRichard Henderson translator_loop(cpu, tb, max_insns, pc, host_pc, &m68k_tr_ops, &dc.base);
6095fcf5ef2aSThomas Huth }
6096fcf5ef2aSThomas Huth
floatx80_to_double(CPUM68KState * env,uint16_t high,uint64_t low)6097f83311e4SLaurent Vivier static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low)
6098f83311e4SLaurent Vivier {
6099f83311e4SLaurent Vivier floatx80 a = { .high = high, .low = low };
6100f83311e4SLaurent Vivier union {
6101f83311e4SLaurent Vivier float64 f64;
6102f83311e4SLaurent Vivier double d;
6103f83311e4SLaurent Vivier } u;
6104f83311e4SLaurent Vivier
6105f83311e4SLaurent Vivier u.f64 = floatx80_to_float64(a, &env->fp_status);
6106f83311e4SLaurent Vivier return u.d;
6107f83311e4SLaurent Vivier }
6108f83311e4SLaurent Vivier
m68k_cpu_dump_state(CPUState * cs,FILE * f,int flags)610990c84c56SMarkus Armbruster void m68k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
6110fcf5ef2aSThomas Huth {
6111fcf5ef2aSThomas Huth M68kCPU *cpu = M68K_CPU(cs);
6112fcf5ef2aSThomas Huth CPUM68KState *env = &cpu->env;
6113fcf5ef2aSThomas Huth int i;
6114fcf5ef2aSThomas Huth uint16_t sr;
6115f83311e4SLaurent Vivier for (i = 0; i < 8; i++) {
611690c84c56SMarkus Armbruster qemu_fprintf(f, "D%d = %08x A%d = %08x "
6117f83311e4SLaurent Vivier "F%d = %04x %016"PRIx64" (%12g)\n",
6118fcf5ef2aSThomas Huth i, env->dregs[i], i, env->aregs[i],
6119f83311e4SLaurent Vivier i, env->fregs[i].l.upper, env->fregs[i].l.lower,
6120f83311e4SLaurent Vivier floatx80_to_double(env, env->fregs[i].l.upper,
6121f83311e4SLaurent Vivier env->fregs[i].l.lower));
6122fcf5ef2aSThomas Huth }
612390c84c56SMarkus Armbruster qemu_fprintf(f, "PC = %08x ", env->pc);
6124fcf5ef2aSThomas Huth sr = env->sr | cpu_m68k_get_ccr(env);
612590c84c56SMarkus Armbruster qemu_fprintf(f, "SR = %04x T:%x I:%x %c%c %c%c%c%c%c\n",
6126cc523026SLaurent Vivier sr, (sr & SR_T) >> SR_T_SHIFT, (sr & SR_I) >> SR_I_SHIFT,
6127cc523026SLaurent Vivier (sr & SR_S) ? 'S' : 'U', (sr & SR_M) ? '%' : 'I',
6128cc523026SLaurent Vivier (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-',
6129cc523026SLaurent Vivier (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-',
6130cc523026SLaurent Vivier (sr & CCF_C) ? 'C' : '-');
613190c84c56SMarkus Armbruster qemu_fprintf(f, "FPSR = %08x %c%c%c%c ", env->fpsr,
6132ba624944SLaurent Vivier (env->fpsr & FPSR_CC_A) ? 'A' : '-',
6133ba624944SLaurent Vivier (env->fpsr & FPSR_CC_I) ? 'I' : '-',
6134ba624944SLaurent Vivier (env->fpsr & FPSR_CC_Z) ? 'Z' : '-',
6135ba624944SLaurent Vivier (env->fpsr & FPSR_CC_N) ? 'N' : '-');
613690c84c56SMarkus Armbruster qemu_fprintf(f, "\n "
6137ba624944SLaurent Vivier "FPCR = %04x ", env->fpcr);
6138ba624944SLaurent Vivier switch (env->fpcr & FPCR_PREC_MASK) {
6139ba624944SLaurent Vivier case FPCR_PREC_X:
614090c84c56SMarkus Armbruster qemu_fprintf(f, "X ");
6141ba624944SLaurent Vivier break;
6142ba624944SLaurent Vivier case FPCR_PREC_S:
614390c84c56SMarkus Armbruster qemu_fprintf(f, "S ");
6144ba624944SLaurent Vivier break;
6145ba624944SLaurent Vivier case FPCR_PREC_D:
614690c84c56SMarkus Armbruster qemu_fprintf(f, "D ");
6147ba624944SLaurent Vivier break;
6148ba624944SLaurent Vivier }
6149ba624944SLaurent Vivier switch (env->fpcr & FPCR_RND_MASK) {
6150ba624944SLaurent Vivier case FPCR_RND_N:
615190c84c56SMarkus Armbruster qemu_fprintf(f, "RN ");
6152ba624944SLaurent Vivier break;
6153ba624944SLaurent Vivier case FPCR_RND_Z:
615490c84c56SMarkus Armbruster qemu_fprintf(f, "RZ ");
6155ba624944SLaurent Vivier break;
6156ba624944SLaurent Vivier case FPCR_RND_M:
615790c84c56SMarkus Armbruster qemu_fprintf(f, "RM ");
6158ba624944SLaurent Vivier break;
6159ba624944SLaurent Vivier case FPCR_RND_P:
616090c84c56SMarkus Armbruster qemu_fprintf(f, "RP ");
6161ba624944SLaurent Vivier break;
6162ba624944SLaurent Vivier }
616390c84c56SMarkus Armbruster qemu_fprintf(f, "\n");
61646a140586SPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY
616590c84c56SMarkus Armbruster qemu_fprintf(f, "%sA7(MSP) = %08x %sA7(USP) = %08x %sA7(ISP) = %08x\n",
61666e22b28eSLaurent Vivier env->current_sp == M68K_SSP ? "->" : " ", env->sp[M68K_SSP],
61676e22b28eSLaurent Vivier env->current_sp == M68K_USP ? "->" : " ", env->sp[M68K_USP],
61686e22b28eSLaurent Vivier env->current_sp == M68K_ISP ? "->" : " ", env->sp[M68K_ISP]);
616990c84c56SMarkus Armbruster qemu_fprintf(f, "VBR = 0x%08x\n", env->vbr);
617090c84c56SMarkus Armbruster qemu_fprintf(f, "SFC = %x DFC %x\n", env->sfc, env->dfc);
617190c84c56SMarkus Armbruster qemu_fprintf(f, "SSW %08x TCR %08x URP %08x SRP %08x\n",
617288b2fef6SLaurent Vivier env->mmu.ssw, env->mmu.tcr, env->mmu.urp, env->mmu.srp);
617390c84c56SMarkus Armbruster qemu_fprintf(f, "DTTR0/1: %08x/%08x ITTR0/1: %08x/%08x\n",
6174c05c73b0SLaurent Vivier env->mmu.ttr[M68K_DTTR0], env->mmu.ttr[M68K_DTTR1],
6175c05c73b0SLaurent Vivier env->mmu.ttr[M68K_ITTR0], env->mmu.ttr[M68K_ITTR1]);
617690c84c56SMarkus Armbruster qemu_fprintf(f, "MMUSR %08x, fault at %08x\n",
6177e55886c3SLaurent Vivier env->mmu.mmusr, env->mmu.ar);
61786a140586SPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */
6179fcf5ef2aSThomas Huth }
6180