blob: 88098d7c23bcfd31db145929e4921db9303a178a [file] [log] [blame]
bellardfdf9b3e2006-04-27 21:07:38 +00001/*
2 * SH4 translation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellardfdf9b3e2006-04-27 21:07:38 +00004 * Copyright (c) 2005 Samuel Tardieu
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellardfdf9b3e2006-04-27 21:07:38 +000018 */
19#include <stdarg.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
bellardfdf9b3e2006-04-27 21:07:38 +000024
25#define DEBUG_DISAS
26#define SH4_DEBUG_DISAS
27//#define SH4_SINGLE_STEP
28
29#include "cpu.h"
30#include "exec-all.h"
31#include "disas.h"
bellard57fec1f2008-02-01 10:50:11 +000032#include "tcg-op.h"
aurel32ca10f862008-04-11 21:35:42 +000033#include "qemu-common.h"
bellardfdf9b3e2006-04-27 21:07:38 +000034
pbrooka7812ae2008-11-17 14:43:54 +000035#include "helper.h"
36#define GEN_HELPER 1
37#include "helper.h"
38
bellardfdf9b3e2006-04-27 21:07:38 +000039typedef struct DisasContext {
40 struct TranslationBlock *tb;
41 target_ulong pc;
42 uint32_t sr;
bellardeda9b092006-06-14 15:02:05 +000043 uint32_t fpscr;
bellardfdf9b3e2006-04-27 21:07:38 +000044 uint16_t opcode;
45 uint32_t flags;
ths823029f2007-12-02 06:10:04 +000046 int bstate;
bellardfdf9b3e2006-04-27 21:07:38 +000047 int memidx;
48 uint32_t delayed_pc;
49 int singlestep_enabled;
aurel3271968fa2008-12-13 18:57:37 +000050 uint32_t features;
edgar_igl852d4812009-04-01 23:10:46 +000051 int has_movcal;
bellardfdf9b3e2006-04-27 21:07:38 +000052} DisasContext;
53
aurel32fe255912008-09-15 08:49:15 +000054#if defined(CONFIG_USER_ONLY)
55#define IS_USER(ctx) 1
56#else
57#define IS_USER(ctx) (!(ctx->sr & SR_MD))
58#endif
59
ths823029f2007-12-02 06:10:04 +000060enum {
61 BS_NONE = 0, /* We go out of the TB without reaching a branch or an
62 * exception condition
63 */
64 BS_STOP = 1, /* We want to stop translation for any reason */
65 BS_BRANCH = 2, /* We reached a branch condition */
66 BS_EXCP = 3, /* We reached an exception condition */
67};
68
aurel321e8864f2008-08-29 00:48:50 +000069/* global register indexes */
pbrooka7812ae2008-11-17 14:43:54 +000070static TCGv_ptr cpu_env;
aurel321e8864f2008-08-29 00:48:50 +000071static TCGv cpu_gregs[24];
aurel323a8a44c2008-08-29 16:32:18 +000072static TCGv cpu_pc, cpu_sr, cpu_ssr, cpu_spc, cpu_gbr;
73static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl;
aurel3266c7c802009-03-02 17:13:21 +000074static TCGv cpu_pr, cpu_fpscr, cpu_fpul, cpu_ldst;
aurel3266ba3172008-11-19 18:00:47 +000075static TCGv cpu_fregs[32];
aurel3210008222008-08-29 22:32:32 +000076
77/* internal register indexes */
78static TCGv cpu_flags, cpu_delayed_pc;
aurel321e8864f2008-08-29 00:48:50 +000079
Paolo Bonzini1a7ff922010-03-31 16:54:11 +020080static uint32_t gen_opc_hflags[OPC_BUF_SIZE];
81
pbrook2e70f6e2008-06-29 01:03:05 +000082#include "gen-icount.h"
83
blueswir1a5f1b962008-08-17 20:21:51 +000084static void sh4_translate_init(void)
pbrook2e70f6e2008-06-29 01:03:05 +000085{
aurel321e8864f2008-08-29 00:48:50 +000086 int i;
pbrook2e70f6e2008-06-29 01:03:05 +000087 static int done_init = 0;
aurel32559dd742008-08-29 10:05:12 +000088 static const char * const gregnames[24] = {
aurel321e8864f2008-08-29 00:48:50 +000089 "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0",
90 "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0",
91 "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
92 "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1",
93 "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1"
94 };
aurel3266ba3172008-11-19 18:00:47 +000095 static const char * const fregnames[32] = {
96 "FPR0_BANK0", "FPR1_BANK0", "FPR2_BANK0", "FPR3_BANK0",
97 "FPR4_BANK0", "FPR5_BANK0", "FPR6_BANK0", "FPR7_BANK0",
98 "FPR8_BANK0", "FPR9_BANK0", "FPR10_BANK0", "FPR11_BANK0",
99 "FPR12_BANK0", "FPR13_BANK0", "FPR14_BANK0", "FPR15_BANK0",
100 "FPR0_BANK1", "FPR1_BANK1", "FPR2_BANK1", "FPR3_BANK1",
101 "FPR4_BANK1", "FPR5_BANK1", "FPR6_BANK1", "FPR7_BANK1",
102 "FPR8_BANK1", "FPR9_BANK1", "FPR10_BANK1", "FPR11_BANK1",
103 "FPR12_BANK1", "FPR13_BANK1", "FPR14_BANK1", "FPR15_BANK1",
104 };
aurel321e8864f2008-08-29 00:48:50 +0000105
pbrook2e70f6e2008-06-29 01:03:05 +0000106 if (done_init)
107 return;
aurel321e8864f2008-08-29 00:48:50 +0000108
pbrooka7812ae2008-11-17 14:43:54 +0000109 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
aurel321e8864f2008-08-29 00:48:50 +0000110
111 for (i = 0; i < 24; i++)
pbrooka7812ae2008-11-17 14:43:54 +0000112 cpu_gregs[i] = tcg_global_mem_new_i32(TCG_AREG0,
aurel3266ba3172008-11-19 18:00:47 +0000113 offsetof(CPUState, gregs[i]),
114 gregnames[i]);
aurel32988d7ea2008-08-28 21:02:00 +0000115
pbrooka7812ae2008-11-17 14:43:54 +0000116 cpu_pc = tcg_global_mem_new_i32(TCG_AREG0,
117 offsetof(CPUState, pc), "PC");
118 cpu_sr = tcg_global_mem_new_i32(TCG_AREG0,
119 offsetof(CPUState, sr), "SR");
120 cpu_ssr = tcg_global_mem_new_i32(TCG_AREG0,
121 offsetof(CPUState, ssr), "SSR");
122 cpu_spc = tcg_global_mem_new_i32(TCG_AREG0,
123 offsetof(CPUState, spc), "SPC");
124 cpu_gbr = tcg_global_mem_new_i32(TCG_AREG0,
125 offsetof(CPUState, gbr), "GBR");
126 cpu_vbr = tcg_global_mem_new_i32(TCG_AREG0,
127 offsetof(CPUState, vbr), "VBR");
128 cpu_sgr = tcg_global_mem_new_i32(TCG_AREG0,
129 offsetof(CPUState, sgr), "SGR");
130 cpu_dbr = tcg_global_mem_new_i32(TCG_AREG0,
131 offsetof(CPUState, dbr), "DBR");
132 cpu_mach = tcg_global_mem_new_i32(TCG_AREG0,
133 offsetof(CPUState, mach), "MACH");
134 cpu_macl = tcg_global_mem_new_i32(TCG_AREG0,
135 offsetof(CPUState, macl), "MACL");
136 cpu_pr = tcg_global_mem_new_i32(TCG_AREG0,
137 offsetof(CPUState, pr), "PR");
138 cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
139 offsetof(CPUState, fpscr), "FPSCR");
140 cpu_fpul = tcg_global_mem_new_i32(TCG_AREG0,
141 offsetof(CPUState, fpul), "FPUL");
aurel323a8a44c2008-08-29 16:32:18 +0000142
pbrooka7812ae2008-11-17 14:43:54 +0000143 cpu_flags = tcg_global_mem_new_i32(TCG_AREG0,
144 offsetof(CPUState, flags), "_flags_");
145 cpu_delayed_pc = tcg_global_mem_new_i32(TCG_AREG0,
146 offsetof(CPUState, delayed_pc),
147 "_delayed_pc_");
aurel3266c7c802009-03-02 17:13:21 +0000148 cpu_ldst = tcg_global_mem_new_i32(TCG_AREG0,
149 offsetof(CPUState, ldst), "_ldst_");
aurel3210008222008-08-29 22:32:32 +0000150
aurel3266ba3172008-11-19 18:00:47 +0000151 for (i = 0; i < 32; i++)
152 cpu_fregs[i] = tcg_global_mem_new_i32(TCG_AREG0,
153 offsetof(CPUState, fregs[i]),
154 fregnames[i]);
155
aurel32988d7ea2008-08-28 21:02:00 +0000156 /* register helpers */
pbrooka7812ae2008-11-17 14:43:54 +0000157#define GEN_HELPER 2
aurel32988d7ea2008-08-28 21:02:00 +0000158#include "helper.h"
159
pbrook2e70f6e2008-06-29 01:03:05 +0000160 done_init = 1;
161}
162
bellardfdf9b3e2006-04-27 21:07:38 +0000163void cpu_dump_state(CPUState * env, FILE * f,
164 int (*cpu_fprintf) (FILE * f, const char *fmt, ...),
165 int flags)
166{
167 int i;
bellardeda9b092006-06-14 15:02:05 +0000168 cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n",
169 env->pc, env->sr, env->pr, env->fpscr);
aurel32274a9e72008-08-22 08:57:35 +0000170 cpu_fprintf(f, "spc=0x%08x ssr=0x%08x gbr=0x%08x vbr=0x%08x\n",
171 env->spc, env->ssr, env->gbr, env->vbr);
172 cpu_fprintf(f, "sgr=0x%08x dbr=0x%08x delayed_pc=0x%08x fpul=0x%08x\n",
173 env->sgr, env->dbr, env->delayed_pc, env->fpul);
bellardfdf9b3e2006-04-27 21:07:38 +0000174 for (i = 0; i < 24; i += 4) {
175 cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n",
176 i, env->gregs[i], i + 1, env->gregs[i + 1],
177 i + 2, env->gregs[i + 2], i + 3, env->gregs[i + 3]);
178 }
179 if (env->flags & DELAY_SLOT) {
180 cpu_fprintf(f, "in delay slot (delayed_pc=0x%08x)\n",
181 env->delayed_pc);
182 } else if (env->flags & DELAY_SLOT_CONDITIONAL) {
183 cpu_fprintf(f, "in conditional delay slot (delayed_pc=0x%08x)\n",
184 env->delayed_pc);
185 }
186}
187
Aurelien Jarno4f6493f2011-01-14 20:39:18 +0100188void cpu_reset(CPUSH4State * env)
bellardfdf9b3e2006-04-27 21:07:38 +0000189{
aliguorieca1bdf2009-01-26 19:54:31 +0000190 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
191 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
192 log_cpu_state(env, 0);
193 }
194
Aurelien Jarno4f6493f2011-01-14 20:39:18 +0100195 memset(env, 0, offsetof(CPUSH4State, breakpoints));
196 tlb_flush(env, 1);
197
bellardfdf9b3e2006-04-27 21:07:38 +0000198 env->pc = 0xA0000000;
thsea6cf6b2007-06-22 11:12:01 +0000199#if defined(CONFIG_USER_ONLY)
200 env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */
bellardb0b3de82007-11-11 19:49:51 +0000201 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */
thsea6cf6b2007-06-22 11:12:01 +0000202#else
Aurelien Jarno4f6493f2011-01-14 20:39:18 +0100203 env->sr = SR_MD | SR_RB | SR_BL | SR_I3 | SR_I2 | SR_I1 | SR_I0;
Aurelien Jarno26ac1ea2011-01-14 20:39:18 +0100204 env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */
bellardb0b3de82007-11-11 19:49:51 +0000205 set_float_rounding_mode(float_round_to_zero, &env->fp_status);
Aurelien Jarnoa0d4ac32011-01-14 20:39:18 +0100206 set_flush_to_zero(1, &env->fp_status);
thsea6cf6b2007-06-22 11:12:01 +0000207#endif
Aurelien Jarno26ac1ea2011-01-14 20:39:18 +0100208 set_default_nan_mode(1, &env->fp_status);
bellardfdf9b3e2006-04-27 21:07:38 +0000209}
210
aurel320fd3ca32008-09-02 16:18:28 +0000211typedef struct {
blueswir1b55266b2008-09-20 08:07:15 +0000212 const char *name;
aurel320fd3ca32008-09-02 16:18:28 +0000213 int id;
214 uint32_t pvr;
215 uint32_t prr;
216 uint32_t cvr;
aurel3271968fa2008-12-13 18:57:37 +0000217 uint32_t features;
aurel320fd3ca32008-09-02 16:18:28 +0000218} sh4_def_t;
219
220static sh4_def_t sh4_defs[] = {
221 {
222 .name = "SH7750R",
223 .id = SH_CPU_SH7750R,
224 .pvr = 0x00050000,
225 .prr = 0x00000100,
226 .cvr = 0x00110000,
aurel32c2432a42009-02-07 15:18:14 +0000227 .features = SH_FEATURE_BCR3_AND_BCR4,
aurel320fd3ca32008-09-02 16:18:28 +0000228 }, {
229 .name = "SH7751R",
230 .id = SH_CPU_SH7751R,
231 .pvr = 0x04050005,
232 .prr = 0x00000113,
233 .cvr = 0x00110000, /* Neutered caches, should be 0x20480000 */
aurel32c2432a42009-02-07 15:18:14 +0000234 .features = SH_FEATURE_BCR3_AND_BCR4,
aurel32a9c43f82008-12-13 18:57:28 +0000235 }, {
236 .name = "SH7785",
237 .id = SH_CPU_SH7785,
238 .pvr = 0x10300700,
239 .prr = 0x00000200,
240 .cvr = 0x71440211,
aurel3271968fa2008-12-13 18:57:37 +0000241 .features = SH_FEATURE_SH4A,
aurel32a9c43f82008-12-13 18:57:28 +0000242 },
aurel320fd3ca32008-09-02 16:18:28 +0000243};
244
blueswir1b55266b2008-09-20 08:07:15 +0000245static const sh4_def_t *cpu_sh4_find_by_name(const char *name)
aurel320fd3ca32008-09-02 16:18:28 +0000246{
247 int i;
248
249 if (strcasecmp(name, "any") == 0)
250 return &sh4_defs[0];
251
malcb1503cd2008-12-22 20:33:55 +0000252 for (i = 0; i < ARRAY_SIZE(sh4_defs); i++)
aurel320fd3ca32008-09-02 16:18:28 +0000253 if (strcasecmp(name, sh4_defs[i].name) == 0)
254 return &sh4_defs[i];
255
256 return NULL;
257}
258
Stefan Weil9a78eea2010-10-22 23:03:33 +0200259void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf)
aurel320fd3ca32008-09-02 16:18:28 +0000260{
261 int i;
262
malcb1503cd2008-12-22 20:33:55 +0000263 for (i = 0; i < ARRAY_SIZE(sh4_defs); i++)
aurel320fd3ca32008-09-02 16:18:28 +0000264 (*cpu_fprintf)(f, "%s\n", sh4_defs[i].name);
265}
266
Aurelien Jarno4f6493f2011-01-14 20:39:18 +0100267static void cpu_register(CPUSH4State *env, const sh4_def_t *def)
aurel320fd3ca32008-09-02 16:18:28 +0000268{
269 env->pvr = def->pvr;
270 env->prr = def->prr;
271 env->cvr = def->cvr;
272 env->id = def->id;
273}
274
bellardaaed9092007-11-10 15:15:54 +0000275CPUSH4State *cpu_sh4_init(const char *cpu_model)
bellardfdf9b3e2006-04-27 21:07:38 +0000276{
277 CPUSH4State *env;
aurel320fd3ca32008-09-02 16:18:28 +0000278 const sh4_def_t *def;
bellardfdf9b3e2006-04-27 21:07:38 +0000279
aurel320fd3ca32008-09-02 16:18:28 +0000280 def = cpu_sh4_find_by_name(cpu_model);
281 if (!def)
282 return NULL;
bellardfdf9b3e2006-04-27 21:07:38 +0000283 env = qemu_mallocz(sizeof(CPUSH4State));
aurel3271968fa2008-12-13 18:57:37 +0000284 env->features = def->features;
bellardfdf9b3e2006-04-27 21:07:38 +0000285 cpu_exec_init(env);
edgar_igl852d4812009-04-01 23:10:46 +0000286 env->movcal_backup_tail = &(env->movcal_backup);
pbrook2e70f6e2008-06-29 01:03:05 +0000287 sh4_translate_init();
aurel3274787572008-09-15 07:34:45 +0000288 env->cpu_model_str = cpu_model;
Aurelien Jarno4f6493f2011-01-14 20:39:18 +0100289 cpu_reset(env);
290 cpu_register(env, def);
aliguori0bf46a42009-04-24 18:03:41 +0000291 qemu_init_vcpu(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000292 return env;
293}
294
bellardfdf9b3e2006-04-27 21:07:38 +0000295static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
296{
297 TranslationBlock *tb;
298 tb = ctx->tb;
299
300 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
301 !ctx->singlestep_enabled) {
302 /* Use a direct jump if in same page and singlestep not enabled */
bellard57fec1f2008-02-01 10:50:11 +0000303 tcg_gen_goto_tb(n);
aurel323a8a44c2008-08-29 16:32:18 +0000304 tcg_gen_movi_i32(cpu_pc, dest);
Stefan Weil4b4a72e2011-04-02 13:36:31 +0200305 tcg_gen_exit_tb((tcg_target_long)tb + n);
bellardfdf9b3e2006-04-27 21:07:38 +0000306 } else {
aurel323a8a44c2008-08-29 16:32:18 +0000307 tcg_gen_movi_i32(cpu_pc, dest);
bellard57fec1f2008-02-01 10:50:11 +0000308 if (ctx->singlestep_enabled)
pbrooka7812ae2008-11-17 14:43:54 +0000309 gen_helper_debug();
bellard57fec1f2008-02-01 10:50:11 +0000310 tcg_gen_exit_tb(0);
bellardfdf9b3e2006-04-27 21:07:38 +0000311 }
bellardfdf9b3e2006-04-27 21:07:38 +0000312}
313
bellardfdf9b3e2006-04-27 21:07:38 +0000314static void gen_jump(DisasContext * ctx)
315{
316 if (ctx->delayed_pc == (uint32_t) - 1) {
317 /* Target is not statically known, it comes necessarily from a
318 delayed jump as immediate jump are conditinal jumps */
aurel3210008222008-08-29 22:32:32 +0000319 tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc);
bellardfdf9b3e2006-04-27 21:07:38 +0000320 if (ctx->singlestep_enabled)
pbrooka7812ae2008-11-17 14:43:54 +0000321 gen_helper_debug();
bellard57fec1f2008-02-01 10:50:11 +0000322 tcg_gen_exit_tb(0);
bellardfdf9b3e2006-04-27 21:07:38 +0000323 } else {
324 gen_goto_tb(ctx, 0, ctx->delayed_pc);
325 }
326}
327
aurel3210008222008-08-29 22:32:32 +0000328static inline void gen_branch_slot(uint32_t delayed_pc, int t)
329{
aurel32c55497e2008-09-01 13:09:21 +0000330 TCGv sr;
aurel3210008222008-08-29 22:32:32 +0000331 int label = gen_new_label();
332 tcg_gen_movi_i32(cpu_delayed_pc, delayed_pc);
pbrooka7812ae2008-11-17 14:43:54 +0000333 sr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000334 tcg_gen_andi_i32(sr, cpu_sr, SR_T);
Aurelien Jarno6f396c82011-01-14 20:39:18 +0100335 tcg_gen_brcondi_i32(t ? TCG_COND_EQ:TCG_COND_NE, sr, 0, label);
aurel3210008222008-08-29 22:32:32 +0000336 tcg_gen_ori_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE);
337 gen_set_label(label);
338}
339
bellardfdf9b3e2006-04-27 21:07:38 +0000340/* Immediate conditional jump (bt or bf) */
341static void gen_conditional_jump(DisasContext * ctx,
342 target_ulong ift, target_ulong ifnott)
343{
344 int l1;
aurel32c55497e2008-09-01 13:09:21 +0000345 TCGv sr;
bellardfdf9b3e2006-04-27 21:07:38 +0000346
347 l1 = gen_new_label();
pbrooka7812ae2008-11-17 14:43:54 +0000348 sr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000349 tcg_gen_andi_i32(sr, cpu_sr, SR_T);
Aurelien Jarno6f396c82011-01-14 20:39:18 +0100350 tcg_gen_brcondi_i32(TCG_COND_NE, sr, 0, l1);
bellardfdf9b3e2006-04-27 21:07:38 +0000351 gen_goto_tb(ctx, 0, ifnott);
352 gen_set_label(l1);
353 gen_goto_tb(ctx, 1, ift);
354}
355
356/* Delayed conditional jump (bt or bf) */
357static void gen_delayed_conditional_jump(DisasContext * ctx)
358{
359 int l1;
aurel32c55497e2008-09-01 13:09:21 +0000360 TCGv ds;
bellardfdf9b3e2006-04-27 21:07:38 +0000361
362 l1 = gen_new_label();
pbrooka7812ae2008-11-17 14:43:54 +0000363 ds = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000364 tcg_gen_andi_i32(ds, cpu_flags, DELAY_SLOT_TRUE);
Aurelien Jarno6f396c82011-01-14 20:39:18 +0100365 tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1);
ths823029f2007-12-02 06:10:04 +0000366 gen_goto_tb(ctx, 1, ctx->pc + 2);
bellardfdf9b3e2006-04-27 21:07:38 +0000367 gen_set_label(l1);
aurel3210008222008-08-29 22:32:32 +0000368 tcg_gen_andi_i32(cpu_flags, cpu_flags, ~DELAY_SLOT_TRUE);
pbrook9c2a9ea2006-06-18 19:12:54 +0000369 gen_jump(ctx);
bellardfdf9b3e2006-04-27 21:07:38 +0000370}
371
aurel32a4625612008-08-29 20:12:18 +0000372static inline void gen_set_t(void)
373{
374 tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_T);
375}
376
377static inline void gen_clr_t(void)
378{
379 tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
380}
381
382static inline void gen_cmp(int cond, TCGv t0, TCGv t1)
383{
Aurelien Jarnoc5c19132011-01-14 20:39:18 +0100384 TCGv t;
385
386 t = tcg_temp_new();
387 tcg_gen_setcond_i32(cond, t, t1, t0);
388 tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
389 tcg_gen_or_i32(cpu_sr, cpu_sr, t);
390
391 tcg_temp_free(t);
aurel32a4625612008-08-29 20:12:18 +0000392}
393
394static inline void gen_cmp_imm(int cond, TCGv t0, int32_t imm)
395{
Aurelien Jarnoc5c19132011-01-14 20:39:18 +0100396 TCGv t;
397
398 t = tcg_temp_new();
399 tcg_gen_setcondi_i32(cond, t, t0, imm);
400 tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
401 tcg_gen_or_i32(cpu_sr, cpu_sr, t);
402
403 tcg_temp_free(t);
aurel32a4625612008-08-29 20:12:18 +0000404}
405
aurel3210008222008-08-29 22:32:32 +0000406static inline void gen_store_flags(uint32_t flags)
407{
408 tcg_gen_andi_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE);
409 tcg_gen_ori_i32(cpu_flags, cpu_flags, flags);
410}
411
aurel3269d62752008-09-01 13:09:06 +0000412static inline void gen_copy_bit_i32(TCGv t0, int p0, TCGv t1, int p1)
413{
pbrooka7812ae2008-11-17 14:43:54 +0000414 TCGv tmp = tcg_temp_new();
aurel3269d62752008-09-01 13:09:06 +0000415
416 p0 &= 0x1f;
417 p1 &= 0x1f;
418
419 tcg_gen_andi_i32(tmp, t1, (1 << p1));
420 tcg_gen_andi_i32(t0, t0, ~(1 << p0));
421 if (p0 < p1)
422 tcg_gen_shri_i32(tmp, tmp, p1 - p0);
423 else if (p0 > p1)
424 tcg_gen_shli_i32(tmp, tmp, p0 - p1);
425 tcg_gen_or_i32(t0, t0, tmp);
426
427 tcg_temp_free(tmp);
428}
429
pbrooka7812ae2008-11-17 14:43:54 +0000430static inline void gen_load_fpr64(TCGv_i64 t, int reg)
aurel32cc4ba6a2008-09-01 22:11:56 +0000431{
aurel3266ba3172008-11-19 18:00:47 +0000432 tcg_gen_concat_i32_i64(t, cpu_fregs[reg + 1], cpu_fregs[reg]);
aurel32cc4ba6a2008-09-01 22:11:56 +0000433}
434
pbrooka7812ae2008-11-17 14:43:54 +0000435static inline void gen_store_fpr64 (TCGv_i64 t, int reg)
aurel32cc4ba6a2008-09-01 22:11:56 +0000436{
pbrooka7812ae2008-11-17 14:43:54 +0000437 TCGv_i32 tmp = tcg_temp_new_i32();
aurel32cc4ba6a2008-09-01 22:11:56 +0000438 tcg_gen_trunc_i64_i32(tmp, t);
aurel3266ba3172008-11-19 18:00:47 +0000439 tcg_gen_mov_i32(cpu_fregs[reg + 1], tmp);
aurel32cc4ba6a2008-09-01 22:11:56 +0000440 tcg_gen_shri_i64(t, t, 32);
441 tcg_gen_trunc_i64_i32(tmp, t);
aurel3266ba3172008-11-19 18:00:47 +0000442 tcg_gen_mov_i32(cpu_fregs[reg], tmp);
pbrooka7812ae2008-11-17 14:43:54 +0000443 tcg_temp_free_i32(tmp);
aurel32cc4ba6a2008-09-01 22:11:56 +0000444}
445
bellardfdf9b3e2006-04-27 21:07:38 +0000446#define B3_0 (ctx->opcode & 0xf)
447#define B6_4 ((ctx->opcode >> 4) & 0x7)
448#define B7_4 ((ctx->opcode >> 4) & 0xf)
449#define B7_0 (ctx->opcode & 0xff)
450#define B7_0s ((int32_t) (int8_t) (ctx->opcode & 0xff))
451#define B11_0s (ctx->opcode & 0x800 ? 0xfffff000 | (ctx->opcode & 0xfff) : \
452 (ctx->opcode & 0xfff))
453#define B11_8 ((ctx->opcode >> 8) & 0xf)
454#define B15_12 ((ctx->opcode >> 12) & 0xf)
455
456#define REG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB) ? \
aurel327efbe242008-09-01 13:09:14 +0000457 (cpu_gregs[x + 16]) : (cpu_gregs[x]))
bellardfdf9b3e2006-04-27 21:07:38 +0000458
459#define ALTREG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) != (SR_MD | SR_RB) \
aurel327efbe242008-09-01 13:09:14 +0000460 ? (cpu_gregs[x + 16]) : (cpu_gregs[x]))
bellardfdf9b3e2006-04-27 21:07:38 +0000461
bellardeda9b092006-06-14 15:02:05 +0000462#define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x))
thsf09111e2007-05-13 16:33:43 +0000463#define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe))
bellardeda9b092006-06-14 15:02:05 +0000464#define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x))
thsea6cf6b2007-06-22 11:12:01 +0000465#define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */
bellardeda9b092006-06-14 15:02:05 +0000466
bellardfdf9b3e2006-04-27 21:07:38 +0000467#define CHECK_NOT_DELAY_SLOT \
aurel32d8299bc2008-12-07 22:46:31 +0000468 if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
469 { \
aurel32d8299bc2008-12-07 22:46:31 +0000470 gen_helper_raise_slot_illegal_instruction(); \
471 ctx->bstate = BS_EXCP; \
472 return; \
473 }
bellardfdf9b3e2006-04-27 21:07:38 +0000474
Aurelien Jarno86865c52011-01-11 16:13:34 +0100475#define CHECK_PRIVILEGED \
476 if (IS_USER(ctx)) { \
Aurelien Jarno86865c52011-01-11 16:13:34 +0100477 if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \
478 gen_helper_raise_slot_illegal_instruction(); \
479 } else { \
480 gen_helper_raise_illegal_instruction(); \
481 } \
482 ctx->bstate = BS_EXCP; \
483 return; \
aurel32fe255912008-09-15 08:49:15 +0000484 }
485
aurel32d8299bc2008-12-07 22:46:31 +0000486#define CHECK_FPU_ENABLED \
487 if (ctx->flags & SR_FD) { \
488 if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \
aurel32d8299bc2008-12-07 22:46:31 +0000489 gen_helper_raise_slot_fpu_disable(); \
490 } else { \
aurel32d8299bc2008-12-07 22:46:31 +0000491 gen_helper_raise_fpu_disable(); \
492 } \
493 ctx->bstate = BS_EXCP; \
494 return; \
495 }
496
blueswir1b1d8e522008-10-26 13:43:07 +0000497static void _decode_opc(DisasContext * ctx)
bellardfdf9b3e2006-04-27 21:07:38 +0000498{
edgar_igl852d4812009-04-01 23:10:46 +0000499 /* This code tries to make movcal emulation sufficiently
500 accurate for Linux purposes. This instruction writes
501 memory, and prior to that, always allocates a cache line.
502 It is used in two contexts:
503 - in memcpy, where data is copied in blocks, the first write
504 of to a block uses movca.l for performance.
505 - in arch/sh/mm/cache-sh4.c, movcal.l + ocbi combination is used
506 to flush the cache. Here, the data written by movcal.l is never
507 written to memory, and the data written is just bogus.
508
509 To simulate this, we simulate movcal.l, we store the value to memory,
510 but we also remember the previous content. If we see ocbi, we check
511 if movcal.l for that address was done previously. If so, the write should
512 not have hit the memory, so we restore the previous content.
513 When we see an instruction that is neither movca.l
514 nor ocbi, the previous content is discarded.
515
516 To optimize, we only try to flush stores when we're at the start of
517 TB, or if we already saw movca.l in this TB and did not flush stores
518 yet. */
519 if (ctx->has_movcal)
520 {
521 int opcode = ctx->opcode & 0xf0ff;
522 if (opcode != 0x0093 /* ocbi */
523 && opcode != 0x00c3 /* movca.l */)
524 {
525 gen_helper_discard_movcal_backup ();
526 ctx->has_movcal = 0;
527 }
528 }
529
bellardfdf9b3e2006-04-27 21:07:38 +0000530#if 0
531 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode);
532#endif
aurel32f6198372008-12-10 17:31:43 +0000533
bellardfdf9b3e2006-04-27 21:07:38 +0000534 switch (ctx->opcode) {
535 case 0x0019: /* div0u */
aurel323a8a44c2008-08-29 16:32:18 +0000536 tcg_gen_andi_i32(cpu_sr, cpu_sr, ~(SR_M | SR_Q | SR_T));
bellardfdf9b3e2006-04-27 21:07:38 +0000537 return;
538 case 0x000b: /* rts */
aurel3210008222008-08-29 22:32:32 +0000539 CHECK_NOT_DELAY_SLOT
540 tcg_gen_mov_i32(cpu_delayed_pc, cpu_pr);
bellardfdf9b3e2006-04-27 21:07:38 +0000541 ctx->flags |= DELAY_SLOT;
542 ctx->delayed_pc = (uint32_t) - 1;
543 return;
544 case 0x0028: /* clrmac */
aurel323a8a44c2008-08-29 16:32:18 +0000545 tcg_gen_movi_i32(cpu_mach, 0);
546 tcg_gen_movi_i32(cpu_macl, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000547 return;
548 case 0x0048: /* clrs */
aurel323a8a44c2008-08-29 16:32:18 +0000549 tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_S);
bellardfdf9b3e2006-04-27 21:07:38 +0000550 return;
551 case 0x0008: /* clrt */
aurel32a4625612008-08-29 20:12:18 +0000552 gen_clr_t();
bellardfdf9b3e2006-04-27 21:07:38 +0000553 return;
554 case 0x0038: /* ldtlb */
aurel32fe255912008-09-15 08:49:15 +0000555 CHECK_PRIVILEGED
pbrooka7812ae2008-11-17 14:43:54 +0000556 gen_helper_ldtlb();
bellardfdf9b3e2006-04-27 21:07:38 +0000557 return;
thsc5e814b2007-09-29 19:52:22 +0000558 case 0x002b: /* rte */
aurel32fe255912008-09-15 08:49:15 +0000559 CHECK_PRIVILEGED
aurel3210008222008-08-29 22:32:32 +0000560 CHECK_NOT_DELAY_SLOT
561 tcg_gen_mov_i32(cpu_sr, cpu_ssr);
562 tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc);
bellardfdf9b3e2006-04-27 21:07:38 +0000563 ctx->flags |= DELAY_SLOT;
564 ctx->delayed_pc = (uint32_t) - 1;
565 return;
566 case 0x0058: /* sets */
aurel323a8a44c2008-08-29 16:32:18 +0000567 tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_S);
bellardfdf9b3e2006-04-27 21:07:38 +0000568 return;
569 case 0x0018: /* sett */
aurel32a4625612008-08-29 20:12:18 +0000570 gen_set_t();
bellardfdf9b3e2006-04-27 21:07:38 +0000571 return;
aurel3224988dc2008-03-11 23:22:37 +0000572 case 0xfbfd: /* frchg */
aurel326f069392008-08-30 13:55:14 +0000573 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR);
ths823029f2007-12-02 06:10:04 +0000574 ctx->bstate = BS_STOP;
bellardfdf9b3e2006-04-27 21:07:38 +0000575 return;
aurel3224988dc2008-03-11 23:22:37 +0000576 case 0xf3fd: /* fschg */
aurel326f069392008-08-30 13:55:14 +0000577 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ);
ths823029f2007-12-02 06:10:04 +0000578 ctx->bstate = BS_STOP;
bellardfdf9b3e2006-04-27 21:07:38 +0000579 return;
580 case 0x0009: /* nop */
581 return;
582 case 0x001b: /* sleep */
aurel32fe255912008-09-15 08:49:15 +0000583 CHECK_PRIVILEGED
pbrooka7812ae2008-11-17 14:43:54 +0000584 gen_helper_sleep(tcg_const_i32(ctx->pc + 2));
bellardfdf9b3e2006-04-27 21:07:38 +0000585 return;
586 }
587
588 switch (ctx->opcode & 0xf000) {
589 case 0x1000: /* mov.l Rm,@(disp,Rn) */
aurel32c55497e2008-09-01 13:09:21 +0000590 {
pbrooka7812ae2008-11-17 14:43:54 +0000591 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000592 tcg_gen_addi_i32(addr, REG(B11_8), B3_0 * 4);
593 tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx);
594 tcg_temp_free(addr);
595 }
bellardfdf9b3e2006-04-27 21:07:38 +0000596 return;
597 case 0x5000: /* mov.l @(disp,Rm),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000598 {
pbrooka7812ae2008-11-17 14:43:54 +0000599 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000600 tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 4);
601 tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx);
602 tcg_temp_free(addr);
603 }
bellardfdf9b3e2006-04-27 21:07:38 +0000604 return;
aurel3224988dc2008-03-11 23:22:37 +0000605 case 0xe000: /* mov #imm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000606 tcg_gen_movi_i32(REG(B11_8), B7_0s);
bellardfdf9b3e2006-04-27 21:07:38 +0000607 return;
608 case 0x9000: /* mov.w @(disp,PC),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000609 {
610 TCGv addr = tcg_const_i32(ctx->pc + 4 + B7_0 * 2);
611 tcg_gen_qemu_ld16s(REG(B11_8), addr, ctx->memidx);
612 tcg_temp_free(addr);
613 }
bellardfdf9b3e2006-04-27 21:07:38 +0000614 return;
615 case 0xd000: /* mov.l @(disp,PC),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000616 {
617 TCGv addr = tcg_const_i32((ctx->pc + 4 + B7_0 * 4) & ~3);
618 tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx);
619 tcg_temp_free(addr);
620 }
bellardfdf9b3e2006-04-27 21:07:38 +0000621 return;
aurel3224988dc2008-03-11 23:22:37 +0000622 case 0x7000: /* add #imm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000623 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), B7_0s);
bellardfdf9b3e2006-04-27 21:07:38 +0000624 return;
625 case 0xa000: /* bra disp */
626 CHECK_NOT_DELAY_SLOT
aurel3210008222008-08-29 22:32:32 +0000627 ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2;
628 tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc);
bellardfdf9b3e2006-04-27 21:07:38 +0000629 ctx->flags |= DELAY_SLOT;
630 return;
631 case 0xb000: /* bsr disp */
632 CHECK_NOT_DELAY_SLOT
aurel3210008222008-08-29 22:32:32 +0000633 tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
634 ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2;
635 tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc);
bellardfdf9b3e2006-04-27 21:07:38 +0000636 ctx->flags |= DELAY_SLOT;
637 return;
638 }
639
640 switch (ctx->opcode & 0xf00f) {
641 case 0x6003: /* mov Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000642 tcg_gen_mov_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000643 return;
644 case 0x2000: /* mov.b Rm,@Rn */
aurel327efbe242008-09-01 13:09:14 +0000645 tcg_gen_qemu_st8(REG(B7_4), REG(B11_8), ctx->memidx);
bellardfdf9b3e2006-04-27 21:07:38 +0000646 return;
647 case 0x2001: /* mov.w Rm,@Rn */
aurel327efbe242008-09-01 13:09:14 +0000648 tcg_gen_qemu_st16(REG(B7_4), REG(B11_8), ctx->memidx);
bellardfdf9b3e2006-04-27 21:07:38 +0000649 return;
650 case 0x2002: /* mov.l Rm,@Rn */
aurel327efbe242008-09-01 13:09:14 +0000651 tcg_gen_qemu_st32(REG(B7_4), REG(B11_8), ctx->memidx);
bellardfdf9b3e2006-04-27 21:07:38 +0000652 return;
653 case 0x6000: /* mov.b @Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000654 tcg_gen_qemu_ld8s(REG(B11_8), REG(B7_4), ctx->memidx);
bellardfdf9b3e2006-04-27 21:07:38 +0000655 return;
656 case 0x6001: /* mov.w @Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000657 tcg_gen_qemu_ld16s(REG(B11_8), REG(B7_4), ctx->memidx);
bellardfdf9b3e2006-04-27 21:07:38 +0000658 return;
659 case 0x6002: /* mov.l @Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000660 tcg_gen_qemu_ld32s(REG(B11_8), REG(B7_4), ctx->memidx);
bellardfdf9b3e2006-04-27 21:07:38 +0000661 return;
662 case 0x2004: /* mov.b Rm,@-Rn */
aurel32c55497e2008-09-01 13:09:21 +0000663 {
pbrooka7812ae2008-11-17 14:43:54 +0000664 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000665 tcg_gen_subi_i32(addr, REG(B11_8), 1);
666 tcg_gen_qemu_st8(REG(B7_4), addr, ctx->memidx); /* might cause re-execution */
Aurelien Jarno3101e992010-01-31 01:07:25 +0100667 tcg_gen_mov_i32(REG(B11_8), addr); /* modify register status */
aurel32c55497e2008-09-01 13:09:21 +0000668 tcg_temp_free(addr);
669 }
bellardfdf9b3e2006-04-27 21:07:38 +0000670 return;
671 case 0x2005: /* mov.w Rm,@-Rn */
aurel32c55497e2008-09-01 13:09:21 +0000672 {
pbrooka7812ae2008-11-17 14:43:54 +0000673 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000674 tcg_gen_subi_i32(addr, REG(B11_8), 2);
675 tcg_gen_qemu_st16(REG(B7_4), addr, ctx->memidx);
Aurelien Jarno3101e992010-01-31 01:07:25 +0100676 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32c55497e2008-09-01 13:09:21 +0000677 tcg_temp_free(addr);
678 }
bellardfdf9b3e2006-04-27 21:07:38 +0000679 return;
680 case 0x2006: /* mov.l Rm,@-Rn */
aurel32c55497e2008-09-01 13:09:21 +0000681 {
pbrooka7812ae2008-11-17 14:43:54 +0000682 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000683 tcg_gen_subi_i32(addr, REG(B11_8), 4);
684 tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx);
Aurelien Jarno3101e992010-01-31 01:07:25 +0100685 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32c55497e2008-09-01 13:09:21 +0000686 }
bellardfdf9b3e2006-04-27 21:07:38 +0000687 return;
bellardeda9b092006-06-14 15:02:05 +0000688 case 0x6004: /* mov.b @Rm+,Rn */
aurel327efbe242008-09-01 13:09:14 +0000689 tcg_gen_qemu_ld8s(REG(B11_8), REG(B7_4), ctx->memidx);
aurel3224988dc2008-03-11 23:22:37 +0000690 if ( B11_8 != B7_4 )
aurel327efbe242008-09-01 13:09:14 +0000691 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 1);
bellardfdf9b3e2006-04-27 21:07:38 +0000692 return;
693 case 0x6005: /* mov.w @Rm+,Rn */
aurel327efbe242008-09-01 13:09:14 +0000694 tcg_gen_qemu_ld16s(REG(B11_8), REG(B7_4), ctx->memidx);
aurel3224988dc2008-03-11 23:22:37 +0000695 if ( B11_8 != B7_4 )
aurel327efbe242008-09-01 13:09:14 +0000696 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
bellardfdf9b3e2006-04-27 21:07:38 +0000697 return;
698 case 0x6006: /* mov.l @Rm+,Rn */
aurel327efbe242008-09-01 13:09:14 +0000699 tcg_gen_qemu_ld32s(REG(B11_8), REG(B7_4), ctx->memidx);
aurel3224988dc2008-03-11 23:22:37 +0000700 if ( B11_8 != B7_4 )
aurel327efbe242008-09-01 13:09:14 +0000701 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
bellardfdf9b3e2006-04-27 21:07:38 +0000702 return;
703 case 0x0004: /* mov.b Rm,@(R0,Rn) */
aurel32c55497e2008-09-01 13:09:21 +0000704 {
pbrooka7812ae2008-11-17 14:43:54 +0000705 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000706 tcg_gen_add_i32(addr, REG(B11_8), REG(0));
707 tcg_gen_qemu_st8(REG(B7_4), addr, ctx->memidx);
708 tcg_temp_free(addr);
709 }
bellardfdf9b3e2006-04-27 21:07:38 +0000710 return;
711 case 0x0005: /* mov.w Rm,@(R0,Rn) */
aurel32c55497e2008-09-01 13:09:21 +0000712 {
pbrooka7812ae2008-11-17 14:43:54 +0000713 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000714 tcg_gen_add_i32(addr, REG(B11_8), REG(0));
715 tcg_gen_qemu_st16(REG(B7_4), addr, ctx->memidx);
716 tcg_temp_free(addr);
717 }
bellardfdf9b3e2006-04-27 21:07:38 +0000718 return;
719 case 0x0006: /* mov.l Rm,@(R0,Rn) */
aurel32c55497e2008-09-01 13:09:21 +0000720 {
pbrooka7812ae2008-11-17 14:43:54 +0000721 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000722 tcg_gen_add_i32(addr, REG(B11_8), REG(0));
723 tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx);
724 tcg_temp_free(addr);
725 }
bellardfdf9b3e2006-04-27 21:07:38 +0000726 return;
727 case 0x000c: /* mov.b @(R0,Rm),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000728 {
pbrooka7812ae2008-11-17 14:43:54 +0000729 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000730 tcg_gen_add_i32(addr, REG(B7_4), REG(0));
731 tcg_gen_qemu_ld8s(REG(B11_8), addr, ctx->memidx);
732 tcg_temp_free(addr);
733 }
bellardfdf9b3e2006-04-27 21:07:38 +0000734 return;
735 case 0x000d: /* mov.w @(R0,Rm),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000736 {
pbrooka7812ae2008-11-17 14:43:54 +0000737 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000738 tcg_gen_add_i32(addr, REG(B7_4), REG(0));
739 tcg_gen_qemu_ld16s(REG(B11_8), addr, ctx->memidx);
740 tcg_temp_free(addr);
741 }
bellardfdf9b3e2006-04-27 21:07:38 +0000742 return;
743 case 0x000e: /* mov.l @(R0,Rm),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000744 {
pbrooka7812ae2008-11-17 14:43:54 +0000745 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000746 tcg_gen_add_i32(addr, REG(B7_4), REG(0));
747 tcg_gen_qemu_ld32s(REG(B11_8), addr, ctx->memidx);
748 tcg_temp_free(addr);
749 }
bellardfdf9b3e2006-04-27 21:07:38 +0000750 return;
751 case 0x6008: /* swap.b Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000752 {
Aurelien Jarno3101e992010-01-31 01:07:25 +0100753 TCGv high, low;
pbrooka7812ae2008-11-17 14:43:54 +0000754 high = tcg_temp_new();
Aurelien Jarno3101e992010-01-31 01:07:25 +0100755 tcg_gen_andi_i32(high, REG(B7_4), 0xffff0000);
pbrooka7812ae2008-11-17 14:43:54 +0000756 low = tcg_temp_new();
Aurelien Jarno3101e992010-01-31 01:07:25 +0100757 tcg_gen_ext16u_i32(low, REG(B7_4));
758 tcg_gen_bswap16_i32(low, low);
aurel32c55497e2008-09-01 13:09:21 +0000759 tcg_gen_or_i32(REG(B11_8), high, low);
760 tcg_temp_free(low);
761 tcg_temp_free(high);
762 }
bellardfdf9b3e2006-04-27 21:07:38 +0000763 return;
764 case 0x6009: /* swap.w Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000765 {
766 TCGv high, low;
pbrooka7812ae2008-11-17 14:43:54 +0000767 high = tcg_temp_new();
Aurelien Jarno3101e992010-01-31 01:07:25 +0100768 tcg_gen_shli_i32(high, REG(B7_4), 16);
pbrooka7812ae2008-11-17 14:43:54 +0000769 low = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000770 tcg_gen_shri_i32(low, REG(B7_4), 16);
771 tcg_gen_ext16u_i32(low, low);
772 tcg_gen_or_i32(REG(B11_8), high, low);
773 tcg_temp_free(low);
774 tcg_temp_free(high);
775 }
bellardfdf9b3e2006-04-27 21:07:38 +0000776 return;
777 case 0x200d: /* xtrct Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000778 {
779 TCGv high, low;
pbrooka7812ae2008-11-17 14:43:54 +0000780 high = tcg_temp_new();
Aurelien Jarno3101e992010-01-31 01:07:25 +0100781 tcg_gen_shli_i32(high, REG(B7_4), 16);
pbrooka7812ae2008-11-17 14:43:54 +0000782 low = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000783 tcg_gen_shri_i32(low, REG(B11_8), 16);
784 tcg_gen_ext16u_i32(low, low);
785 tcg_gen_or_i32(REG(B11_8), high, low);
786 tcg_temp_free(low);
787 tcg_temp_free(high);
788 }
bellardfdf9b3e2006-04-27 21:07:38 +0000789 return;
790 case 0x300c: /* add Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000791 tcg_gen_add_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000792 return;
793 case 0x300e: /* addc Rm,Rn */
pbrooka7812ae2008-11-17 14:43:54 +0000794 gen_helper_addc(REG(B11_8), REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000795 return;
796 case 0x300f: /* addv Rm,Rn */
pbrooka7812ae2008-11-17 14:43:54 +0000797 gen_helper_addv(REG(B11_8), REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000798 return;
799 case 0x2009: /* and Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000800 tcg_gen_and_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000801 return;
802 case 0x3000: /* cmp/eq Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000803 gen_cmp(TCG_COND_EQ, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000804 return;
805 case 0x3003: /* cmp/ge Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000806 gen_cmp(TCG_COND_GE, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000807 return;
808 case 0x3007: /* cmp/gt Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000809 gen_cmp(TCG_COND_GT, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000810 return;
811 case 0x3006: /* cmp/hi Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000812 gen_cmp(TCG_COND_GTU, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000813 return;
814 case 0x3002: /* cmp/hs Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000815 gen_cmp(TCG_COND_GEU, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000816 return;
817 case 0x200c: /* cmp/str Rm,Rn */
aurel3269d62752008-09-01 13:09:06 +0000818 {
Aurelien Jarnoc5c19132011-01-14 20:39:18 +0100819 TCGv cmp1 = tcg_temp_new();
820 TCGv cmp2 = tcg_temp_new();
821 tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
aurel32c55497e2008-09-01 13:09:21 +0000822 tcg_gen_xor_i32(cmp1, REG(B7_4), REG(B11_8));
823 tcg_gen_andi_i32(cmp2, cmp1, 0xff000000);
Aurelien Jarnoc5c19132011-01-14 20:39:18 +0100824 tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
825 tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
aurel32c55497e2008-09-01 13:09:21 +0000826 tcg_gen_andi_i32(cmp2, cmp1, 0x00ff0000);
Aurelien Jarnoc5c19132011-01-14 20:39:18 +0100827 tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
828 tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
aurel32c55497e2008-09-01 13:09:21 +0000829 tcg_gen_andi_i32(cmp2, cmp1, 0x0000ff00);
Aurelien Jarnoc5c19132011-01-14 20:39:18 +0100830 tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
831 tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
aurel32c55497e2008-09-01 13:09:21 +0000832 tcg_gen_andi_i32(cmp2, cmp1, 0x000000ff);
Aurelien Jarnoc5c19132011-01-14 20:39:18 +0100833 tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
834 tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
aurel32c55497e2008-09-01 13:09:21 +0000835 tcg_temp_free(cmp2);
836 tcg_temp_free(cmp1);
aurel3269d62752008-09-01 13:09:06 +0000837 }
bellardfdf9b3e2006-04-27 21:07:38 +0000838 return;
839 case 0x2007: /* div0s Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000840 {
841 gen_copy_bit_i32(cpu_sr, 8, REG(B11_8), 31); /* SR_Q */
842 gen_copy_bit_i32(cpu_sr, 9, REG(B7_4), 31); /* SR_M */
pbrooka7812ae2008-11-17 14:43:54 +0000843 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000844 tcg_gen_xor_i32(val, REG(B7_4), REG(B11_8));
845 gen_copy_bit_i32(cpu_sr, 0, val, 31); /* SR_T */
846 tcg_temp_free(val);
847 }
bellardfdf9b3e2006-04-27 21:07:38 +0000848 return;
849 case 0x3004: /* div1 Rm,Rn */
pbrooka7812ae2008-11-17 14:43:54 +0000850 gen_helper_div1(REG(B11_8), REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000851 return;
852 case 0x300d: /* dmuls.l Rm,Rn */
aurel326f069392008-08-30 13:55:14 +0000853 {
pbrooka7812ae2008-11-17 14:43:54 +0000854 TCGv_i64 tmp1 = tcg_temp_new_i64();
855 TCGv_i64 tmp2 = tcg_temp_new_i64();
aurel326f069392008-08-30 13:55:14 +0000856
aurel327efbe242008-09-01 13:09:14 +0000857 tcg_gen_ext_i32_i64(tmp1, REG(B7_4));
858 tcg_gen_ext_i32_i64(tmp2, REG(B11_8));
aurel326f069392008-08-30 13:55:14 +0000859 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
860 tcg_gen_trunc_i64_i32(cpu_macl, tmp1);
861 tcg_gen_shri_i64(tmp1, tmp1, 32);
862 tcg_gen_trunc_i64_i32(cpu_mach, tmp1);
863
pbrooka7812ae2008-11-17 14:43:54 +0000864 tcg_temp_free_i64(tmp2);
865 tcg_temp_free_i64(tmp1);
aurel326f069392008-08-30 13:55:14 +0000866 }
bellardfdf9b3e2006-04-27 21:07:38 +0000867 return;
868 case 0x3005: /* dmulu.l Rm,Rn */
aurel326f069392008-08-30 13:55:14 +0000869 {
pbrooka7812ae2008-11-17 14:43:54 +0000870 TCGv_i64 tmp1 = tcg_temp_new_i64();
871 TCGv_i64 tmp2 = tcg_temp_new_i64();
aurel326f069392008-08-30 13:55:14 +0000872
aurel327efbe242008-09-01 13:09:14 +0000873 tcg_gen_extu_i32_i64(tmp1, REG(B7_4));
874 tcg_gen_extu_i32_i64(tmp2, REG(B11_8));
aurel326f069392008-08-30 13:55:14 +0000875 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
876 tcg_gen_trunc_i64_i32(cpu_macl, tmp1);
877 tcg_gen_shri_i64(tmp1, tmp1, 32);
878 tcg_gen_trunc_i64_i32(cpu_mach, tmp1);
879
pbrooka7812ae2008-11-17 14:43:54 +0000880 tcg_temp_free_i64(tmp2);
881 tcg_temp_free_i64(tmp1);
aurel326f069392008-08-30 13:55:14 +0000882 }
bellardfdf9b3e2006-04-27 21:07:38 +0000883 return;
884 case 0x600e: /* exts.b Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000885 tcg_gen_ext8s_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000886 return;
887 case 0x600f: /* exts.w Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000888 tcg_gen_ext16s_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000889 return;
890 case 0x600c: /* extu.b Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000891 tcg_gen_ext8u_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000892 return;
893 case 0x600d: /* extu.w Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000894 tcg_gen_ext16u_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000895 return;
aurel3224988dc2008-03-11 23:22:37 +0000896 case 0x000f: /* mac.l @Rm+,@Rn+ */
aurel32c55497e2008-09-01 13:09:21 +0000897 {
898 TCGv arg0, arg1;
pbrooka7812ae2008-11-17 14:43:54 +0000899 arg0 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000900 tcg_gen_qemu_ld32s(arg0, REG(B7_4), ctx->memidx);
pbrooka7812ae2008-11-17 14:43:54 +0000901 arg1 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000902 tcg_gen_qemu_ld32s(arg1, REG(B11_8), ctx->memidx);
pbrooka7812ae2008-11-17 14:43:54 +0000903 gen_helper_macl(arg0, arg1);
aurel32c55497e2008-09-01 13:09:21 +0000904 tcg_temp_free(arg1);
905 tcg_temp_free(arg0);
906 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
907 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
908 }
bellardfdf9b3e2006-04-27 21:07:38 +0000909 return;
910 case 0x400f: /* mac.w @Rm+,@Rn+ */
aurel32c55497e2008-09-01 13:09:21 +0000911 {
912 TCGv arg0, arg1;
pbrooka7812ae2008-11-17 14:43:54 +0000913 arg0 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000914 tcg_gen_qemu_ld32s(arg0, REG(B7_4), ctx->memidx);
pbrooka7812ae2008-11-17 14:43:54 +0000915 arg1 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000916 tcg_gen_qemu_ld32s(arg1, REG(B11_8), ctx->memidx);
pbrooka7812ae2008-11-17 14:43:54 +0000917 gen_helper_macw(arg0, arg1);
aurel32c55497e2008-09-01 13:09:21 +0000918 tcg_temp_free(arg1);
919 tcg_temp_free(arg0);
920 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2);
921 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
922 }
bellardfdf9b3e2006-04-27 21:07:38 +0000923 return;
924 case 0x0007: /* mul.l Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000925 tcg_gen_mul_i32(cpu_macl, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000926 return;
927 case 0x200f: /* muls.w Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000928 {
929 TCGv arg0, arg1;
pbrooka7812ae2008-11-17 14:43:54 +0000930 arg0 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000931 tcg_gen_ext16s_i32(arg0, REG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +0000932 arg1 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000933 tcg_gen_ext16s_i32(arg1, REG(B11_8));
934 tcg_gen_mul_i32(cpu_macl, arg0, arg1);
935 tcg_temp_free(arg1);
936 tcg_temp_free(arg0);
937 }
bellardfdf9b3e2006-04-27 21:07:38 +0000938 return;
939 case 0x200e: /* mulu.w Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000940 {
941 TCGv arg0, arg1;
pbrooka7812ae2008-11-17 14:43:54 +0000942 arg0 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000943 tcg_gen_ext16u_i32(arg0, REG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +0000944 arg1 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000945 tcg_gen_ext16u_i32(arg1, REG(B11_8));
946 tcg_gen_mul_i32(cpu_macl, arg0, arg1);
947 tcg_temp_free(arg1);
948 tcg_temp_free(arg0);
949 }
bellardfdf9b3e2006-04-27 21:07:38 +0000950 return;
951 case 0x600b: /* neg Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000952 tcg_gen_neg_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000953 return;
954 case 0x600a: /* negc Rm,Rn */
Aurelien Jarnob2d9eda2011-01-13 08:20:39 +0100955 {
956 TCGv t0, t1;
957 t0 = tcg_temp_new();
958 tcg_gen_neg_i32(t0, REG(B7_4));
959 t1 = tcg_temp_new();
960 tcg_gen_andi_i32(t1, cpu_sr, SR_T);
961 tcg_gen_sub_i32(REG(B11_8), t0, t1);
962 tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
Aurelien Jarno70262592011-02-04 20:19:33 +0100963 tcg_gen_setcondi_i32(TCG_COND_GTU, t1, t0, 0);
Aurelien Jarnob2d9eda2011-01-13 08:20:39 +0100964 tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
Aurelien Jarno70262592011-02-04 20:19:33 +0100965 tcg_gen_setcond_i32(TCG_COND_GTU, t1, REG(B11_8), t0);
Aurelien Jarnob2d9eda2011-01-13 08:20:39 +0100966 tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
967 tcg_temp_free(t0);
968 tcg_temp_free(t1);
969 }
bellardfdf9b3e2006-04-27 21:07:38 +0000970 return;
971 case 0x6007: /* not Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000972 tcg_gen_not_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000973 return;
974 case 0x200b: /* or Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000975 tcg_gen_or_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000976 return;
977 case 0x400c: /* shad Rm,Rn */
aurel3269d62752008-09-01 13:09:06 +0000978 {
979 int label1 = gen_new_label();
980 int label2 = gen_new_label();
981 int label3 = gen_new_label();
982 int label4 = gen_new_label();
Aurelien Jarno3101e992010-01-31 01:07:25 +0100983 TCGv shift;
aurel327efbe242008-09-01 13:09:14 +0000984 tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1);
aurel3269d62752008-09-01 13:09:06 +0000985 /* Rm positive, shift to the left */
Aurelien Jarno3101e992010-01-31 01:07:25 +0100986 shift = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000987 tcg_gen_andi_i32(shift, REG(B7_4), 0x1f);
988 tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift);
Aurelien Jarno3101e992010-01-31 01:07:25 +0100989 tcg_temp_free(shift);
aurel3269d62752008-09-01 13:09:06 +0000990 tcg_gen_br(label4);
991 /* Rm negative, shift to the right */
992 gen_set_label(label1);
Aurelien Jarno3101e992010-01-31 01:07:25 +0100993 shift = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000994 tcg_gen_andi_i32(shift, REG(B7_4), 0x1f);
995 tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2);
996 tcg_gen_not_i32(shift, REG(B7_4));
997 tcg_gen_andi_i32(shift, shift, 0x1f);
998 tcg_gen_addi_i32(shift, shift, 1);
999 tcg_gen_sar_i32(REG(B11_8), REG(B11_8), shift);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001000 tcg_temp_free(shift);
aurel3269d62752008-09-01 13:09:06 +00001001 tcg_gen_br(label4);
1002 /* Rm = -32 */
1003 gen_set_label(label2);
aurel327efbe242008-09-01 13:09:14 +00001004 tcg_gen_brcondi_i32(TCG_COND_LT, REG(B11_8), 0, label3);
1005 tcg_gen_movi_i32(REG(B11_8), 0);
aurel3269d62752008-09-01 13:09:06 +00001006 tcg_gen_br(label4);
1007 gen_set_label(label3);
aurel327efbe242008-09-01 13:09:14 +00001008 tcg_gen_movi_i32(REG(B11_8), 0xffffffff);
aurel3269d62752008-09-01 13:09:06 +00001009 gen_set_label(label4);
1010 }
bellardfdf9b3e2006-04-27 21:07:38 +00001011 return;
1012 case 0x400d: /* shld Rm,Rn */
aurel3269d62752008-09-01 13:09:06 +00001013 {
1014 int label1 = gen_new_label();
1015 int label2 = gen_new_label();
1016 int label3 = gen_new_label();
Aurelien Jarno3101e992010-01-31 01:07:25 +01001017 TCGv shift;
aurel327efbe242008-09-01 13:09:14 +00001018 tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1);
aurel3269d62752008-09-01 13:09:06 +00001019 /* Rm positive, shift to the left */
Aurelien Jarno3101e992010-01-31 01:07:25 +01001020 shift = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001021 tcg_gen_andi_i32(shift, REG(B7_4), 0x1f);
1022 tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001023 tcg_temp_free(shift);
aurel3269d62752008-09-01 13:09:06 +00001024 tcg_gen_br(label3);
1025 /* Rm negative, shift to the right */
1026 gen_set_label(label1);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001027 shift = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001028 tcg_gen_andi_i32(shift, REG(B7_4), 0x1f);
1029 tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2);
1030 tcg_gen_not_i32(shift, REG(B7_4));
1031 tcg_gen_andi_i32(shift, shift, 0x1f);
1032 tcg_gen_addi_i32(shift, shift, 1);
1033 tcg_gen_shr_i32(REG(B11_8), REG(B11_8), shift);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001034 tcg_temp_free(shift);
aurel3269d62752008-09-01 13:09:06 +00001035 tcg_gen_br(label3);
1036 /* Rm = -32 */
1037 gen_set_label(label2);
aurel327efbe242008-09-01 13:09:14 +00001038 tcg_gen_movi_i32(REG(B11_8), 0);
aurel3269d62752008-09-01 13:09:06 +00001039 gen_set_label(label3);
1040 }
bellardfdf9b3e2006-04-27 21:07:38 +00001041 return;
1042 case 0x3008: /* sub Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +00001043 tcg_gen_sub_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +00001044 return;
1045 case 0x300a: /* subc Rm,Rn */
pbrooka7812ae2008-11-17 14:43:54 +00001046 gen_helper_subc(REG(B11_8), REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +00001047 return;
1048 case 0x300b: /* subv Rm,Rn */
pbrooka7812ae2008-11-17 14:43:54 +00001049 gen_helper_subv(REG(B11_8), REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +00001050 return;
1051 case 0x2008: /* tst Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +00001052 {
pbrooka7812ae2008-11-17 14:43:54 +00001053 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001054 tcg_gen_and_i32(val, REG(B7_4), REG(B11_8));
1055 gen_cmp_imm(TCG_COND_EQ, val, 0);
1056 tcg_temp_free(val);
1057 }
bellardfdf9b3e2006-04-27 21:07:38 +00001058 return;
1059 case 0x200a: /* xor Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +00001060 tcg_gen_xor_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +00001061 return;
thse67888a2007-06-22 11:44:41 +00001062 case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001063 CHECK_FPU_ENABLED
ths022a22c2007-06-22 11:47:05 +00001064 if (ctx->fpscr & FPSCR_SZ) {
pbrooka7812ae2008-11-17 14:43:54 +00001065 TCGv_i64 fp = tcg_temp_new_i64();
aurel32cc4ba6a2008-09-01 22:11:56 +00001066 gen_load_fpr64(fp, XREG(B7_4));
1067 gen_store_fpr64(fp, XREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001068 tcg_temp_free_i64(fp);
bellardeda9b092006-06-14 15:02:05 +00001069 } else {
aurel3266ba3172008-11-19 18:00:47 +00001070 tcg_gen_mov_i32(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
bellardeda9b092006-06-14 15:02:05 +00001071 }
1072 return;
thse67888a2007-06-22 11:44:41 +00001073 case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001074 CHECK_FPU_ENABLED
ths022a22c2007-06-22 11:47:05 +00001075 if (ctx->fpscr & FPSCR_SZ) {
aurel3211bb09f2008-11-22 10:09:27 +00001076 TCGv addr_hi = tcg_temp_new();
1077 int fr = XREG(B7_4);
1078 tcg_gen_addi_i32(addr_hi, REG(B11_8), 4);
1079 tcg_gen_qemu_st32(cpu_fregs[fr ], REG(B11_8), ctx->memidx);
1080 tcg_gen_qemu_st32(cpu_fregs[fr+1], addr_hi, ctx->memidx);
1081 tcg_temp_free(addr_hi);
bellardeda9b092006-06-14 15:02:05 +00001082 } else {
aurel3266ba3172008-11-19 18:00:47 +00001083 tcg_gen_qemu_st32(cpu_fregs[FREG(B7_4)], REG(B11_8), ctx->memidx);
bellardeda9b092006-06-14 15:02:05 +00001084 }
1085 return;
thse67888a2007-06-22 11:44:41 +00001086 case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001087 CHECK_FPU_ENABLED
ths022a22c2007-06-22 11:47:05 +00001088 if (ctx->fpscr & FPSCR_SZ) {
aurel3211bb09f2008-11-22 10:09:27 +00001089 TCGv addr_hi = tcg_temp_new();
1090 int fr = XREG(B11_8);
1091 tcg_gen_addi_i32(addr_hi, REG(B7_4), 4);
1092 tcg_gen_qemu_ld32u(cpu_fregs[fr ], REG(B7_4), ctx->memidx);
1093 tcg_gen_qemu_ld32u(cpu_fregs[fr+1], addr_hi, ctx->memidx);
1094 tcg_temp_free(addr_hi);
bellardeda9b092006-06-14 15:02:05 +00001095 } else {
aurel3266ba3172008-11-19 18:00:47 +00001096 tcg_gen_qemu_ld32u(cpu_fregs[FREG(B11_8)], REG(B7_4), ctx->memidx);
bellardeda9b092006-06-14 15:02:05 +00001097 }
1098 return;
thse67888a2007-06-22 11:44:41 +00001099 case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001100 CHECK_FPU_ENABLED
ths022a22c2007-06-22 11:47:05 +00001101 if (ctx->fpscr & FPSCR_SZ) {
aurel3211bb09f2008-11-22 10:09:27 +00001102 TCGv addr_hi = tcg_temp_new();
1103 int fr = XREG(B11_8);
1104 tcg_gen_addi_i32(addr_hi, REG(B7_4), 4);
1105 tcg_gen_qemu_ld32u(cpu_fregs[fr ], REG(B7_4), ctx->memidx);
1106 tcg_gen_qemu_ld32u(cpu_fregs[fr+1], addr_hi, ctx->memidx);
1107 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 8);
1108 tcg_temp_free(addr_hi);
bellardeda9b092006-06-14 15:02:05 +00001109 } else {
aurel3266ba3172008-11-19 18:00:47 +00001110 tcg_gen_qemu_ld32u(cpu_fregs[FREG(B11_8)], REG(B7_4), ctx->memidx);
aurel32cc4ba6a2008-09-01 22:11:56 +00001111 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
bellardeda9b092006-06-14 15:02:05 +00001112 }
1113 return;
thse67888a2007-06-22 11:44:41 +00001114 case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001115 CHECK_FPU_ENABLED
ths022a22c2007-06-22 11:47:05 +00001116 if (ctx->fpscr & FPSCR_SZ) {
aurel3211bb09f2008-11-22 10:09:27 +00001117 TCGv addr = tcg_temp_new_i32();
1118 int fr = XREG(B7_4);
1119 tcg_gen_subi_i32(addr, REG(B11_8), 4);
1120 tcg_gen_qemu_st32(cpu_fregs[fr+1], addr, ctx->memidx);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001121 tcg_gen_subi_i32(addr, addr, 4);
aurel3211bb09f2008-11-22 10:09:27 +00001122 tcg_gen_qemu_st32(cpu_fregs[fr ], addr, ctx->memidx);
1123 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32cc4ba6a2008-09-01 22:11:56 +00001124 tcg_temp_free(addr);
bellardeda9b092006-06-14 15:02:05 +00001125 } else {
pbrooka7812ae2008-11-17 14:43:54 +00001126 TCGv addr;
pbrooka7812ae2008-11-17 14:43:54 +00001127 addr = tcg_temp_new_i32();
aurel32cc4ba6a2008-09-01 22:11:56 +00001128 tcg_gen_subi_i32(addr, REG(B11_8), 4);
aurel3266ba3172008-11-19 18:00:47 +00001129 tcg_gen_qemu_st32(cpu_fregs[FREG(B7_4)], addr, ctx->memidx);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001130 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32cc4ba6a2008-09-01 22:11:56 +00001131 tcg_temp_free(addr);
bellardeda9b092006-06-14 15:02:05 +00001132 }
1133 return;
thse67888a2007-06-22 11:44:41 +00001134 case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001135 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001136 {
pbrooka7812ae2008-11-17 14:43:54 +00001137 TCGv addr = tcg_temp_new_i32();
aurel32cc4ba6a2008-09-01 22:11:56 +00001138 tcg_gen_add_i32(addr, REG(B7_4), REG(0));
1139 if (ctx->fpscr & FPSCR_SZ) {
aurel3211bb09f2008-11-22 10:09:27 +00001140 int fr = XREG(B11_8);
1141 tcg_gen_qemu_ld32u(cpu_fregs[fr ], addr, ctx->memidx);
1142 tcg_gen_addi_i32(addr, addr, 4);
1143 tcg_gen_qemu_ld32u(cpu_fregs[fr+1], addr, ctx->memidx);
aurel32cc4ba6a2008-09-01 22:11:56 +00001144 } else {
aurel3266ba3172008-11-19 18:00:47 +00001145 tcg_gen_qemu_ld32u(cpu_fregs[FREG(B11_8)], addr, ctx->memidx);
aurel32cc4ba6a2008-09-01 22:11:56 +00001146 }
1147 tcg_temp_free(addr);
bellardeda9b092006-06-14 15:02:05 +00001148 }
1149 return;
thse67888a2007-06-22 11:44:41 +00001150 case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001151 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001152 {
pbrooka7812ae2008-11-17 14:43:54 +00001153 TCGv addr = tcg_temp_new();
aurel32cc4ba6a2008-09-01 22:11:56 +00001154 tcg_gen_add_i32(addr, REG(B11_8), REG(0));
1155 if (ctx->fpscr & FPSCR_SZ) {
aurel3211bb09f2008-11-22 10:09:27 +00001156 int fr = XREG(B7_4);
1157 tcg_gen_qemu_ld32u(cpu_fregs[fr ], addr, ctx->memidx);
1158 tcg_gen_addi_i32(addr, addr, 4);
1159 tcg_gen_qemu_ld32u(cpu_fregs[fr+1], addr, ctx->memidx);
aurel32cc4ba6a2008-09-01 22:11:56 +00001160 } else {
aurel3266ba3172008-11-19 18:00:47 +00001161 tcg_gen_qemu_st32(cpu_fregs[FREG(B7_4)], addr, ctx->memidx);
aurel32cc4ba6a2008-09-01 22:11:56 +00001162 }
1163 tcg_temp_free(addr);
bellardeda9b092006-06-14 15:02:05 +00001164 }
1165 return;
thse67888a2007-06-22 11:44:41 +00001166 case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
1167 case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
1168 case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
1169 case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
1170 case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
1171 case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
aurel32cc4ba6a2008-09-01 22:11:56 +00001172 {
aurel32f6198372008-12-10 17:31:43 +00001173 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001174 if (ctx->fpscr & FPSCR_PR) {
pbrooka7812ae2008-11-17 14:43:54 +00001175 TCGv_i64 fp0, fp1;
1176
aurel32cc4ba6a2008-09-01 22:11:56 +00001177 if (ctx->opcode & 0x0110)
1178 break; /* illegal instruction */
pbrooka7812ae2008-11-17 14:43:54 +00001179 fp0 = tcg_temp_new_i64();
1180 fp1 = tcg_temp_new_i64();
aurel32cc4ba6a2008-09-01 22:11:56 +00001181 gen_load_fpr64(fp0, DREG(B11_8));
1182 gen_load_fpr64(fp1, DREG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +00001183 switch (ctx->opcode & 0xf00f) {
1184 case 0xf000: /* fadd Rm,Rn */
1185 gen_helper_fadd_DT(fp0, fp0, fp1);
1186 break;
1187 case 0xf001: /* fsub Rm,Rn */
1188 gen_helper_fsub_DT(fp0, fp0, fp1);
1189 break;
1190 case 0xf002: /* fmul Rm,Rn */
1191 gen_helper_fmul_DT(fp0, fp0, fp1);
1192 break;
1193 case 0xf003: /* fdiv Rm,Rn */
1194 gen_helper_fdiv_DT(fp0, fp0, fp1);
1195 break;
1196 case 0xf004: /* fcmp/eq Rm,Rn */
1197 gen_helper_fcmp_eq_DT(fp0, fp1);
1198 return;
1199 case 0xf005: /* fcmp/gt Rm,Rn */
1200 gen_helper_fcmp_gt_DT(fp0, fp1);
1201 return;
1202 }
1203 gen_store_fpr64(fp0, DREG(B11_8));
1204 tcg_temp_free_i64(fp0);
1205 tcg_temp_free_i64(fp1);
1206 } else {
pbrooka7812ae2008-11-17 14:43:54 +00001207 switch (ctx->opcode & 0xf00f) {
1208 case 0xf000: /* fadd Rm,Rn */
aurel3266ba3172008-11-19 18:00:47 +00001209 gen_helper_fadd_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
pbrooka7812ae2008-11-17 14:43:54 +00001210 break;
1211 case 0xf001: /* fsub Rm,Rn */
aurel3266ba3172008-11-19 18:00:47 +00001212 gen_helper_fsub_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
pbrooka7812ae2008-11-17 14:43:54 +00001213 break;
1214 case 0xf002: /* fmul Rm,Rn */
aurel3266ba3172008-11-19 18:00:47 +00001215 gen_helper_fmul_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
pbrooka7812ae2008-11-17 14:43:54 +00001216 break;
1217 case 0xf003: /* fdiv Rm,Rn */
aurel3266ba3172008-11-19 18:00:47 +00001218 gen_helper_fdiv_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
pbrooka7812ae2008-11-17 14:43:54 +00001219 break;
1220 case 0xf004: /* fcmp/eq Rm,Rn */
aurel3266ba3172008-11-19 18:00:47 +00001221 gen_helper_fcmp_eq_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
pbrooka7812ae2008-11-17 14:43:54 +00001222 return;
1223 case 0xf005: /* fcmp/gt Rm,Rn */
aurel3266ba3172008-11-19 18:00:47 +00001224 gen_helper_fcmp_gt_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]);
pbrooka7812ae2008-11-17 14:43:54 +00001225 return;
1226 }
aurel32cc4ba6a2008-09-01 22:11:56 +00001227 }
thsea6cf6b2007-06-22 11:12:01 +00001228 }
1229 return;
aurel325b7141a2009-01-14 21:02:59 +00001230 case 0xf00e: /* fmac FR0,RM,Rn */
1231 {
1232 CHECK_FPU_ENABLED
1233 if (ctx->fpscr & FPSCR_PR) {
1234 break; /* illegal instruction */
1235 } else {
1236 gen_helper_fmac_FT(cpu_fregs[FREG(B11_8)],
1237 cpu_fregs[FREG(0)], cpu_fregs[FREG(B7_4)], cpu_fregs[FREG(B11_8)]);
1238 return;
1239 }
1240 }
bellardfdf9b3e2006-04-27 21:07:38 +00001241 }
1242
1243 switch (ctx->opcode & 0xff00) {
1244 case 0xc900: /* and #imm,R0 */
aurel327efbe242008-09-01 13:09:14 +00001245 tcg_gen_andi_i32(REG(0), REG(0), B7_0);
bellardfdf9b3e2006-04-27 21:07:38 +00001246 return;
aurel3224988dc2008-03-11 23:22:37 +00001247 case 0xcd00: /* and.b #imm,@(R0,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001248 {
1249 TCGv addr, val;
pbrooka7812ae2008-11-17 14:43:54 +00001250 addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001251 tcg_gen_add_i32(addr, REG(0), cpu_gbr);
pbrooka7812ae2008-11-17 14:43:54 +00001252 val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001253 tcg_gen_qemu_ld8u(val, addr, ctx->memidx);
1254 tcg_gen_andi_i32(val, val, B7_0);
1255 tcg_gen_qemu_st8(val, addr, ctx->memidx);
1256 tcg_temp_free(val);
1257 tcg_temp_free(addr);
1258 }
bellardfdf9b3e2006-04-27 21:07:38 +00001259 return;
1260 case 0x8b00: /* bf label */
1261 CHECK_NOT_DELAY_SLOT
1262 gen_conditional_jump(ctx, ctx->pc + 2,
1263 ctx->pc + 4 + B7_0s * 2);
ths823029f2007-12-02 06:10:04 +00001264 ctx->bstate = BS_BRANCH;
bellardfdf9b3e2006-04-27 21:07:38 +00001265 return;
1266 case 0x8f00: /* bf/s label */
1267 CHECK_NOT_DELAY_SLOT
aurel3210008222008-08-29 22:32:32 +00001268 gen_branch_slot(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001269 ctx->flags |= DELAY_SLOT_CONDITIONAL;
1270 return;
1271 case 0x8900: /* bt label */
1272 CHECK_NOT_DELAY_SLOT
1273 gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2,
1274 ctx->pc + 2);
ths823029f2007-12-02 06:10:04 +00001275 ctx->bstate = BS_BRANCH;
bellardfdf9b3e2006-04-27 21:07:38 +00001276 return;
1277 case 0x8d00: /* bt/s label */
1278 CHECK_NOT_DELAY_SLOT
aurel3210008222008-08-29 22:32:32 +00001279 gen_branch_slot(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2, 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001280 ctx->flags |= DELAY_SLOT_CONDITIONAL;
1281 return;
1282 case 0x8800: /* cmp/eq #imm,R0 */
aurel327efbe242008-09-01 13:09:14 +00001283 gen_cmp_imm(TCG_COND_EQ, REG(0), B7_0s);
bellardfdf9b3e2006-04-27 21:07:38 +00001284 return;
1285 case 0xc400: /* mov.b @(disp,GBR),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001286 {
pbrooka7812ae2008-11-17 14:43:54 +00001287 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001288 tcg_gen_addi_i32(addr, cpu_gbr, B7_0);
1289 tcg_gen_qemu_ld8s(REG(0), addr, ctx->memidx);
1290 tcg_temp_free(addr);
1291 }
bellardfdf9b3e2006-04-27 21:07:38 +00001292 return;
1293 case 0xc500: /* mov.w @(disp,GBR),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001294 {
pbrooka7812ae2008-11-17 14:43:54 +00001295 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001296 tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2);
1297 tcg_gen_qemu_ld16s(REG(0), addr, ctx->memidx);
1298 tcg_temp_free(addr);
1299 }
bellardfdf9b3e2006-04-27 21:07:38 +00001300 return;
1301 case 0xc600: /* mov.l @(disp,GBR),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001302 {
pbrooka7812ae2008-11-17 14:43:54 +00001303 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001304 tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4);
1305 tcg_gen_qemu_ld32s(REG(0), addr, ctx->memidx);
1306 tcg_temp_free(addr);
1307 }
bellardfdf9b3e2006-04-27 21:07:38 +00001308 return;
1309 case 0xc000: /* mov.b R0,@(disp,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001310 {
pbrooka7812ae2008-11-17 14:43:54 +00001311 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001312 tcg_gen_addi_i32(addr, cpu_gbr, B7_0);
1313 tcg_gen_qemu_st8(REG(0), addr, ctx->memidx);
1314 tcg_temp_free(addr);
1315 }
bellardfdf9b3e2006-04-27 21:07:38 +00001316 return;
1317 case 0xc100: /* mov.w R0,@(disp,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001318 {
pbrooka7812ae2008-11-17 14:43:54 +00001319 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001320 tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2);
1321 tcg_gen_qemu_st16(REG(0), addr, ctx->memidx);
1322 tcg_temp_free(addr);
1323 }
bellardfdf9b3e2006-04-27 21:07:38 +00001324 return;
1325 case 0xc200: /* mov.l R0,@(disp,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001326 {
pbrooka7812ae2008-11-17 14:43:54 +00001327 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001328 tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4);
1329 tcg_gen_qemu_st32(REG(0), addr, ctx->memidx);
1330 tcg_temp_free(addr);
1331 }
bellardfdf9b3e2006-04-27 21:07:38 +00001332 return;
1333 case 0x8000: /* mov.b R0,@(disp,Rn) */
aurel32c55497e2008-09-01 13:09:21 +00001334 {
pbrooka7812ae2008-11-17 14:43:54 +00001335 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001336 tcg_gen_addi_i32(addr, REG(B7_4), B3_0);
1337 tcg_gen_qemu_st8(REG(0), addr, ctx->memidx);
1338 tcg_temp_free(addr);
1339 }
bellardfdf9b3e2006-04-27 21:07:38 +00001340 return;
1341 case 0x8100: /* mov.w R0,@(disp,Rn) */
aurel32c55497e2008-09-01 13:09:21 +00001342 {
pbrooka7812ae2008-11-17 14:43:54 +00001343 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001344 tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2);
1345 tcg_gen_qemu_st16(REG(0), addr, ctx->memidx);
1346 tcg_temp_free(addr);
1347 }
bellardfdf9b3e2006-04-27 21:07:38 +00001348 return;
1349 case 0x8400: /* mov.b @(disp,Rn),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001350 {
pbrooka7812ae2008-11-17 14:43:54 +00001351 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001352 tcg_gen_addi_i32(addr, REG(B7_4), B3_0);
1353 tcg_gen_qemu_ld8s(REG(0), addr, ctx->memidx);
1354 tcg_temp_free(addr);
1355 }
bellardfdf9b3e2006-04-27 21:07:38 +00001356 return;
1357 case 0x8500: /* mov.w @(disp,Rn),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001358 {
pbrooka7812ae2008-11-17 14:43:54 +00001359 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001360 tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2);
1361 tcg_gen_qemu_ld16s(REG(0), addr, ctx->memidx);
1362 tcg_temp_free(addr);
1363 }
bellardfdf9b3e2006-04-27 21:07:38 +00001364 return;
1365 case 0xc700: /* mova @(disp,PC),R0 */
aurel327efbe242008-09-01 13:09:14 +00001366 tcg_gen_movi_i32(REG(0), ((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3);
bellardfdf9b3e2006-04-27 21:07:38 +00001367 return;
1368 case 0xcb00: /* or #imm,R0 */
aurel327efbe242008-09-01 13:09:14 +00001369 tcg_gen_ori_i32(REG(0), REG(0), B7_0);
bellardfdf9b3e2006-04-27 21:07:38 +00001370 return;
aurel3224988dc2008-03-11 23:22:37 +00001371 case 0xcf00: /* or.b #imm,@(R0,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001372 {
1373 TCGv addr, val;
pbrooka7812ae2008-11-17 14:43:54 +00001374 addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001375 tcg_gen_add_i32(addr, REG(0), cpu_gbr);
pbrooka7812ae2008-11-17 14:43:54 +00001376 val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001377 tcg_gen_qemu_ld8u(val, addr, ctx->memidx);
1378 tcg_gen_ori_i32(val, val, B7_0);
1379 tcg_gen_qemu_st8(val, addr, ctx->memidx);
1380 tcg_temp_free(val);
1381 tcg_temp_free(addr);
1382 }
bellardfdf9b3e2006-04-27 21:07:38 +00001383 return;
1384 case 0xc300: /* trapa #imm */
aurel32c55497e2008-09-01 13:09:21 +00001385 {
1386 TCGv imm;
1387 CHECK_NOT_DELAY_SLOT
aurel32c55497e2008-09-01 13:09:21 +00001388 imm = tcg_const_i32(B7_0);
pbrooka7812ae2008-11-17 14:43:54 +00001389 gen_helper_trapa(imm);
aurel32c55497e2008-09-01 13:09:21 +00001390 tcg_temp_free(imm);
1391 ctx->bstate = BS_BRANCH;
1392 }
bellardfdf9b3e2006-04-27 21:07:38 +00001393 return;
1394 case 0xc800: /* tst #imm,R0 */
aurel32c55497e2008-09-01 13:09:21 +00001395 {
pbrooka7812ae2008-11-17 14:43:54 +00001396 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001397 tcg_gen_andi_i32(val, REG(0), B7_0);
1398 gen_cmp_imm(TCG_COND_EQ, val, 0);
1399 tcg_temp_free(val);
1400 }
bellardfdf9b3e2006-04-27 21:07:38 +00001401 return;
aurel3224988dc2008-03-11 23:22:37 +00001402 case 0xcc00: /* tst.b #imm,@(R0,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001403 {
pbrooka7812ae2008-11-17 14:43:54 +00001404 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001405 tcg_gen_add_i32(val, REG(0), cpu_gbr);
1406 tcg_gen_qemu_ld8u(val, val, ctx->memidx);
1407 tcg_gen_andi_i32(val, val, B7_0);
1408 gen_cmp_imm(TCG_COND_EQ, val, 0);
1409 tcg_temp_free(val);
1410 }
bellardfdf9b3e2006-04-27 21:07:38 +00001411 return;
1412 case 0xca00: /* xor #imm,R0 */
aurel327efbe242008-09-01 13:09:14 +00001413 tcg_gen_xori_i32(REG(0), REG(0), B7_0);
bellardfdf9b3e2006-04-27 21:07:38 +00001414 return;
aurel3224988dc2008-03-11 23:22:37 +00001415 case 0xce00: /* xor.b #imm,@(R0,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001416 {
1417 TCGv addr, val;
pbrooka7812ae2008-11-17 14:43:54 +00001418 addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001419 tcg_gen_add_i32(addr, REG(0), cpu_gbr);
pbrooka7812ae2008-11-17 14:43:54 +00001420 val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001421 tcg_gen_qemu_ld8u(val, addr, ctx->memidx);
1422 tcg_gen_xori_i32(val, val, B7_0);
1423 tcg_gen_qemu_st8(val, addr, ctx->memidx);
1424 tcg_temp_free(val);
1425 tcg_temp_free(addr);
1426 }
bellardfdf9b3e2006-04-27 21:07:38 +00001427 return;
1428 }
1429
1430 switch (ctx->opcode & 0xf08f) {
1431 case 0x408e: /* ldc Rm,Rn_BANK */
aurel32fe255912008-09-15 08:49:15 +00001432 CHECK_PRIVILEGED
aurel327efbe242008-09-01 13:09:14 +00001433 tcg_gen_mov_i32(ALTREG(B6_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +00001434 return;
1435 case 0x4087: /* ldc.l @Rm+,Rn_BANK */
aurel32fe255912008-09-15 08:49:15 +00001436 CHECK_PRIVILEGED
aurel327efbe242008-09-01 13:09:14 +00001437 tcg_gen_qemu_ld32s(ALTREG(B6_4), REG(B11_8), ctx->memidx);
1438 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
bellardfdf9b3e2006-04-27 21:07:38 +00001439 return;
1440 case 0x0082: /* stc Rm_BANK,Rn */
aurel32fe255912008-09-15 08:49:15 +00001441 CHECK_PRIVILEGED
aurel327efbe242008-09-01 13:09:14 +00001442 tcg_gen_mov_i32(REG(B11_8), ALTREG(B6_4));
bellardfdf9b3e2006-04-27 21:07:38 +00001443 return;
1444 case 0x4083: /* stc.l Rm_BANK,@-Rn */
aurel32fe255912008-09-15 08:49:15 +00001445 CHECK_PRIVILEGED
aurel32c55497e2008-09-01 13:09:21 +00001446 {
pbrooka7812ae2008-11-17 14:43:54 +00001447 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001448 tcg_gen_subi_i32(addr, REG(B11_8), 4);
1449 tcg_gen_qemu_st32(ALTREG(B6_4), addr, ctx->memidx);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001450 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32c55497e2008-09-01 13:09:21 +00001451 tcg_temp_free(addr);
aurel32c55497e2008-09-01 13:09:21 +00001452 }
bellardfdf9b3e2006-04-27 21:07:38 +00001453 return;
1454 }
1455
1456 switch (ctx->opcode & 0xf0ff) {
1457 case 0x0023: /* braf Rn */
aurel327efbe242008-09-01 13:09:14 +00001458 CHECK_NOT_DELAY_SLOT
1459 tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->pc + 4);
bellardfdf9b3e2006-04-27 21:07:38 +00001460 ctx->flags |= DELAY_SLOT;
1461 ctx->delayed_pc = (uint32_t) - 1;
1462 return;
1463 case 0x0003: /* bsrf Rn */
aurel327efbe242008-09-01 13:09:14 +00001464 CHECK_NOT_DELAY_SLOT
aurel3210008222008-08-29 22:32:32 +00001465 tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
aurel327efbe242008-09-01 13:09:14 +00001466 tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr);
bellardfdf9b3e2006-04-27 21:07:38 +00001467 ctx->flags |= DELAY_SLOT;
1468 ctx->delayed_pc = (uint32_t) - 1;
1469 return;
1470 case 0x4015: /* cmp/pl Rn */
aurel327efbe242008-09-01 13:09:14 +00001471 gen_cmp_imm(TCG_COND_GT, REG(B11_8), 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001472 return;
1473 case 0x4011: /* cmp/pz Rn */
aurel327efbe242008-09-01 13:09:14 +00001474 gen_cmp_imm(TCG_COND_GE, REG(B11_8), 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001475 return;
1476 case 0x4010: /* dt Rn */
aurel327efbe242008-09-01 13:09:14 +00001477 tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 1);
1478 gen_cmp_imm(TCG_COND_EQ, REG(B11_8), 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001479 return;
1480 case 0x402b: /* jmp @Rn */
aurel327efbe242008-09-01 13:09:14 +00001481 CHECK_NOT_DELAY_SLOT
1482 tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +00001483 ctx->flags |= DELAY_SLOT;
1484 ctx->delayed_pc = (uint32_t) - 1;
1485 return;
1486 case 0x400b: /* jsr @Rn */
aurel327efbe242008-09-01 13:09:14 +00001487 CHECK_NOT_DELAY_SLOT
aurel3210008222008-08-29 22:32:32 +00001488 tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
aurel327efbe242008-09-01 13:09:14 +00001489 tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +00001490 ctx->flags |= DELAY_SLOT;
1491 ctx->delayed_pc = (uint32_t) - 1;
1492 return;
aurel32fe255912008-09-15 08:49:15 +00001493 case 0x400e: /* ldc Rm,SR */
1494 CHECK_PRIVILEGED
aurel327efbe242008-09-01 13:09:14 +00001495 tcg_gen_andi_i32(cpu_sr, REG(B11_8), 0x700083f3);
aurel32390af822008-08-30 22:07:52 +00001496 ctx->bstate = BS_STOP;
1497 return;
aurel32fe255912008-09-15 08:49:15 +00001498 case 0x4007: /* ldc.l @Rm+,SR */
1499 CHECK_PRIVILEGED
aurel32c55497e2008-09-01 13:09:21 +00001500 {
pbrooka7812ae2008-11-17 14:43:54 +00001501 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001502 tcg_gen_qemu_ld32s(val, REG(B11_8), ctx->memidx);
1503 tcg_gen_andi_i32(cpu_sr, val, 0x700083f3);
1504 tcg_temp_free(val);
1505 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
1506 ctx->bstate = BS_STOP;
1507 }
aurel32390af822008-08-30 22:07:52 +00001508 return;
aurel32fe255912008-09-15 08:49:15 +00001509 case 0x0002: /* stc SR,Rn */
1510 CHECK_PRIVILEGED
aurel327efbe242008-09-01 13:09:14 +00001511 tcg_gen_mov_i32(REG(B11_8), cpu_sr);
aurel32390af822008-08-30 22:07:52 +00001512 return;
aurel32fe255912008-09-15 08:49:15 +00001513 case 0x4003: /* stc SR,@-Rn */
1514 CHECK_PRIVILEGED
aurel32c55497e2008-09-01 13:09:21 +00001515 {
pbrooka7812ae2008-11-17 14:43:54 +00001516 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001517 tcg_gen_subi_i32(addr, REG(B11_8), 4);
1518 tcg_gen_qemu_st32(cpu_sr, addr, ctx->memidx);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001519 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32c55497e2008-09-01 13:09:21 +00001520 tcg_temp_free(addr);
aurel32c55497e2008-09-01 13:09:21 +00001521 }
aurel32390af822008-08-30 22:07:52 +00001522 return;
Alexandre Courbot8e9b0672010-07-12 14:05:31 +09001523#define LD(reg,ldnum,ldpnum,prechk) \
bellardfdf9b3e2006-04-27 21:07:38 +00001524 case ldnum: \
aurel32fe255912008-09-15 08:49:15 +00001525 prechk \
aurel327efbe242008-09-01 13:09:14 +00001526 tcg_gen_mov_i32 (cpu_##reg, REG(B11_8)); \
bellardfdf9b3e2006-04-27 21:07:38 +00001527 return; \
1528 case ldpnum: \
aurel32fe255912008-09-15 08:49:15 +00001529 prechk \
aurel327efbe242008-09-01 13:09:14 +00001530 tcg_gen_qemu_ld32s (cpu_##reg, REG(B11_8), ctx->memidx); \
1531 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); \
Alexandre Courbot8e9b0672010-07-12 14:05:31 +09001532 return;
1533#define ST(reg,stnum,stpnum,prechk) \
bellardfdf9b3e2006-04-27 21:07:38 +00001534 case stnum: \
aurel32fe255912008-09-15 08:49:15 +00001535 prechk \
aurel327efbe242008-09-01 13:09:14 +00001536 tcg_gen_mov_i32 (REG(B11_8), cpu_##reg); \
bellardfdf9b3e2006-04-27 21:07:38 +00001537 return; \
1538 case stpnum: \
aurel32fe255912008-09-15 08:49:15 +00001539 prechk \
aurel32c55497e2008-09-01 13:09:21 +00001540 { \
Aurelien Jarno3101e992010-01-31 01:07:25 +01001541 TCGv addr = tcg_temp_new(); \
aurel32c55497e2008-09-01 13:09:21 +00001542 tcg_gen_subi_i32(addr, REG(B11_8), 4); \
1543 tcg_gen_qemu_st32 (cpu_##reg, addr, ctx->memidx); \
Aurelien Jarno3101e992010-01-31 01:07:25 +01001544 tcg_gen_mov_i32(REG(B11_8), addr); \
aurel32c55497e2008-09-01 13:09:21 +00001545 tcg_temp_free(addr); \
aurel3286e0abc2008-09-02 08:42:16 +00001546 } \
bellardfdf9b3e2006-04-27 21:07:38 +00001547 return;
Alexandre Courbot8e9b0672010-07-12 14:05:31 +09001548#define LDST(reg,ldnum,ldpnum,stnum,stpnum,prechk) \
1549 LD(reg,ldnum,ldpnum,prechk) \
1550 ST(reg,stnum,stpnum,prechk)
aurel32fe255912008-09-15 08:49:15 +00001551 LDST(gbr, 0x401e, 0x4017, 0x0012, 0x4013, {})
1552 LDST(vbr, 0x402e, 0x4027, 0x0022, 0x4023, CHECK_PRIVILEGED)
1553 LDST(ssr, 0x403e, 0x4037, 0x0032, 0x4033, CHECK_PRIVILEGED)
1554 LDST(spc, 0x404e, 0x4047, 0x0042, 0x4043, CHECK_PRIVILEGED)
Alexandre Courbot935fc172010-07-12 14:05:32 +09001555 ST(sgr, 0x003a, 0x4032, CHECK_PRIVILEGED)
1556 LD(sgr, 0x403a, 0x4036, CHECK_PRIVILEGED if (!(ctx->features & SH_FEATURE_SH4A)) break;)
aurel32fe255912008-09-15 08:49:15 +00001557 LDST(dbr, 0x40fa, 0x40f6, 0x00fa, 0x40f2, CHECK_PRIVILEGED)
1558 LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {})
1559 LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {})
1560 LDST(pr, 0x402a, 0x4026, 0x002a, 0x4022, {})
aurel32d8299bc2008-12-07 22:46:31 +00001561 LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {CHECK_FPU_ENABLED})
aurel32390af822008-08-30 22:07:52 +00001562 case 0x406a: /* lds Rm,FPSCR */
aurel32d8299bc2008-12-07 22:46:31 +00001563 CHECK_FPU_ENABLED
pbrooka7812ae2008-11-17 14:43:54 +00001564 gen_helper_ld_fpscr(REG(B11_8));
aurel32390af822008-08-30 22:07:52 +00001565 ctx->bstate = BS_STOP;
1566 return;
1567 case 0x4066: /* lds.l @Rm+,FPSCR */
aurel32d8299bc2008-12-07 22:46:31 +00001568 CHECK_FPU_ENABLED
aurel32c55497e2008-09-01 13:09:21 +00001569 {
pbrooka7812ae2008-11-17 14:43:54 +00001570 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001571 tcg_gen_qemu_ld32s(addr, REG(B11_8), ctx->memidx);
1572 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
pbrooka7812ae2008-11-17 14:43:54 +00001573 gen_helper_ld_fpscr(addr);
aurel32c55497e2008-09-01 13:09:21 +00001574 tcg_temp_free(addr);
1575 ctx->bstate = BS_STOP;
1576 }
aurel32390af822008-08-30 22:07:52 +00001577 return;
1578 case 0x006a: /* sts FPSCR,Rn */
aurel32d8299bc2008-12-07 22:46:31 +00001579 CHECK_FPU_ENABLED
aurel32c55497e2008-09-01 13:09:21 +00001580 tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff);
aurel32390af822008-08-30 22:07:52 +00001581 return;
1582 case 0x4062: /* sts FPSCR,@-Rn */
aurel32d8299bc2008-12-07 22:46:31 +00001583 CHECK_FPU_ENABLED
aurel32c55497e2008-09-01 13:09:21 +00001584 {
1585 TCGv addr, val;
pbrooka7812ae2008-11-17 14:43:54 +00001586 val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001587 tcg_gen_andi_i32(val, cpu_fpscr, 0x003fffff);
pbrooka7812ae2008-11-17 14:43:54 +00001588 addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001589 tcg_gen_subi_i32(addr, REG(B11_8), 4);
1590 tcg_gen_qemu_st32(val, addr, ctx->memidx);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001591 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32c55497e2008-09-01 13:09:21 +00001592 tcg_temp_free(addr);
1593 tcg_temp_free(val);
aurel32c55497e2008-09-01 13:09:21 +00001594 }
aurel32390af822008-08-30 22:07:52 +00001595 return;
bellardfdf9b3e2006-04-27 21:07:38 +00001596 case 0x00c3: /* movca.l R0,@Rm */
edgar_igl852d4812009-04-01 23:10:46 +00001597 {
1598 TCGv val = tcg_temp_new();
1599 tcg_gen_qemu_ld32u(val, REG(B11_8), ctx->memidx);
1600 gen_helper_movcal (REG(B11_8), val);
1601 tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx);
1602 }
1603 ctx->has_movcal = 1;
bellardfdf9b3e2006-04-27 21:07:38 +00001604 return;
aurel327526aa22008-10-12 23:32:59 +00001605 case 0x40a9:
1606 /* MOVUA.L @Rm,R0 (Rm) -> R0
1607 Load non-boundary-aligned data */
1608 tcg_gen_qemu_ld32u(REG(0), REG(B11_8), ctx->memidx);
1609 return;
1610 case 0x40e9:
1611 /* MOVUA.L @Rm+,R0 (Rm) -> R0, Rm + 4 -> Rm
1612 Load non-boundary-aligned data */
1613 tcg_gen_qemu_ld32u(REG(0), REG(B11_8), ctx->memidx);
1614 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
1615 return;
bellardfdf9b3e2006-04-27 21:07:38 +00001616 case 0x0029: /* movt Rn */
aurel327efbe242008-09-01 13:09:14 +00001617 tcg_gen_andi_i32(REG(B11_8), cpu_sr, SR_T);
bellardfdf9b3e2006-04-27 21:07:38 +00001618 return;
aurel3266c7c802009-03-02 17:13:21 +00001619 case 0x0073:
1620 /* MOVCO.L
1621 LDST -> T
1622 If (T == 1) R0 -> (Rn)
1623 0 -> LDST
1624 */
1625 if (ctx->features & SH_FEATURE_SH4A) {
1626 int label = gen_new_label();
1627 gen_clr_t();
1628 tcg_gen_or_i32(cpu_sr, cpu_sr, cpu_ldst);
1629 tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ldst, 0, label);
1630 tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx);
1631 gen_set_label(label);
1632 tcg_gen_movi_i32(cpu_ldst, 0);
1633 return;
1634 } else
1635 break;
1636 case 0x0063:
1637 /* MOVLI.L @Rm,R0
1638 1 -> LDST
1639 (Rm) -> R0
1640 When interrupt/exception
1641 occurred 0 -> LDST
1642 */
1643 if (ctx->features & SH_FEATURE_SH4A) {
1644 tcg_gen_movi_i32(cpu_ldst, 0);
1645 tcg_gen_qemu_ld32s(REG(0), REG(B11_8), ctx->memidx);
1646 tcg_gen_movi_i32(cpu_ldst, 1);
1647 return;
1648 } else
1649 break;
bellardfdf9b3e2006-04-27 21:07:38 +00001650 case 0x0093: /* ocbi @Rn */
aurel32c55497e2008-09-01 13:09:21 +00001651 {
edgar_igl852d4812009-04-01 23:10:46 +00001652 gen_helper_ocbi (REG(B11_8));
aurel32c55497e2008-09-01 13:09:21 +00001653 }
bellardfdf9b3e2006-04-27 21:07:38 +00001654 return;
aurel3224988dc2008-03-11 23:22:37 +00001655 case 0x00a3: /* ocbp @Rn */
aurel32c55497e2008-09-01 13:09:21 +00001656 {
pbrooka7812ae2008-11-17 14:43:54 +00001657 TCGv dummy = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001658 tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
1659 tcg_temp_free(dummy);
1660 }
bellardfdf9b3e2006-04-27 21:07:38 +00001661 return;
1662 case 0x00b3: /* ocbwb @Rn */
aurel32c55497e2008-09-01 13:09:21 +00001663 {
pbrooka7812ae2008-11-17 14:43:54 +00001664 TCGv dummy = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001665 tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
1666 tcg_temp_free(dummy);
1667 }
bellardfdf9b3e2006-04-27 21:07:38 +00001668 return;
1669 case 0x0083: /* pref @Rn */
1670 return;
aurel3271968fa2008-12-13 18:57:37 +00001671 case 0x00d3: /* prefi @Rn */
1672 if (ctx->features & SH_FEATURE_SH4A)
1673 return;
1674 else
1675 break;
1676 case 0x00e3: /* icbi @Rn */
1677 if (ctx->features & SH_FEATURE_SH4A)
1678 return;
1679 else
1680 break;
1681 case 0x00ab: /* synco */
1682 if (ctx->features & SH_FEATURE_SH4A)
1683 return;
1684 else
1685 break;
bellardfdf9b3e2006-04-27 21:07:38 +00001686 case 0x4024: /* rotcl Rn */
aurel32c55497e2008-09-01 13:09:21 +00001687 {
pbrooka7812ae2008-11-17 14:43:54 +00001688 TCGv tmp = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001689 tcg_gen_mov_i32(tmp, cpu_sr);
1690 gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31);
1691 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1);
1692 gen_copy_bit_i32(REG(B11_8), 0, tmp, 0);
1693 tcg_temp_free(tmp);
1694 }
bellardfdf9b3e2006-04-27 21:07:38 +00001695 return;
1696 case 0x4025: /* rotcr Rn */
aurel32c55497e2008-09-01 13:09:21 +00001697 {
pbrooka7812ae2008-11-17 14:43:54 +00001698 TCGv tmp = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001699 tcg_gen_mov_i32(tmp, cpu_sr);
1700 gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
1701 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1);
1702 gen_copy_bit_i32(REG(B11_8), 31, tmp, 0);
1703 tcg_temp_free(tmp);
1704 }
bellardfdf9b3e2006-04-27 21:07:38 +00001705 return;
1706 case 0x4004: /* rotl Rn */
Aurelien Jarno2411fde2011-01-13 08:20:39 +01001707 tcg_gen_rotli_i32(REG(B11_8), REG(B11_8), 1);
1708 gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001709 return;
1710 case 0x4005: /* rotr Rn */
aurel327efbe242008-09-01 13:09:14 +00001711 gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
Aurelien Jarno2411fde2011-01-13 08:20:39 +01001712 tcg_gen_rotri_i32(REG(B11_8), REG(B11_8), 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001713 return;
1714 case 0x4000: /* shll Rn */
1715 case 0x4020: /* shal Rn */
aurel327efbe242008-09-01 13:09:14 +00001716 gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31);
1717 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001718 return;
1719 case 0x4021: /* shar Rn */
aurel327efbe242008-09-01 13:09:14 +00001720 gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
1721 tcg_gen_sari_i32(REG(B11_8), REG(B11_8), 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001722 return;
1723 case 0x4001: /* shlr Rn */
aurel327efbe242008-09-01 13:09:14 +00001724 gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
1725 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001726 return;
1727 case 0x4008: /* shll2 Rn */
aurel327efbe242008-09-01 13:09:14 +00001728 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 2);
bellardfdf9b3e2006-04-27 21:07:38 +00001729 return;
1730 case 0x4018: /* shll8 Rn */
aurel327efbe242008-09-01 13:09:14 +00001731 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 8);
bellardfdf9b3e2006-04-27 21:07:38 +00001732 return;
1733 case 0x4028: /* shll16 Rn */
aurel327efbe242008-09-01 13:09:14 +00001734 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 16);
bellardfdf9b3e2006-04-27 21:07:38 +00001735 return;
1736 case 0x4009: /* shlr2 Rn */
aurel327efbe242008-09-01 13:09:14 +00001737 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 2);
bellardfdf9b3e2006-04-27 21:07:38 +00001738 return;
1739 case 0x4019: /* shlr8 Rn */
aurel327efbe242008-09-01 13:09:14 +00001740 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 8);
bellardfdf9b3e2006-04-27 21:07:38 +00001741 return;
1742 case 0x4029: /* shlr16 Rn */
aurel327efbe242008-09-01 13:09:14 +00001743 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 16);
bellardfdf9b3e2006-04-27 21:07:38 +00001744 return;
1745 case 0x401b: /* tas.b @Rn */
aurel32c55497e2008-09-01 13:09:21 +00001746 {
1747 TCGv addr, val;
aurel32df9247b2009-01-01 14:09:05 +00001748 addr = tcg_temp_local_new();
aurel32c55497e2008-09-01 13:09:21 +00001749 tcg_gen_mov_i32(addr, REG(B11_8));
aurel32df9247b2009-01-01 14:09:05 +00001750 val = tcg_temp_local_new();
aurel32c55497e2008-09-01 13:09:21 +00001751 tcg_gen_qemu_ld8u(val, addr, ctx->memidx);
1752 gen_cmp_imm(TCG_COND_EQ, val, 0);
1753 tcg_gen_ori_i32(val, val, 0x80);
1754 tcg_gen_qemu_st8(val, addr, ctx->memidx);
1755 tcg_temp_free(val);
1756 tcg_temp_free(addr);
1757 }
bellardfdf9b3e2006-04-27 21:07:38 +00001758 return;
thse67888a2007-06-22 11:44:41 +00001759 case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001760 CHECK_FPU_ENABLED
1761 tcg_gen_mov_i32(cpu_fregs[FREG(B11_8)], cpu_fpul);
bellardeda9b092006-06-14 15:02:05 +00001762 return;
thse67888a2007-06-22 11:44:41 +00001763 case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001764 CHECK_FPU_ENABLED
1765 tcg_gen_mov_i32(cpu_fpul, cpu_fregs[FREG(B11_8)]);
bellardeda9b092006-06-14 15:02:05 +00001766 return;
thse67888a2007-06-22 11:44:41 +00001767 case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */
aurel32f6198372008-12-10 17:31:43 +00001768 CHECK_FPU_ENABLED
thsea6cf6b2007-06-22 11:12:01 +00001769 if (ctx->fpscr & FPSCR_PR) {
pbrooka7812ae2008-11-17 14:43:54 +00001770 TCGv_i64 fp;
thsea6cf6b2007-06-22 11:12:01 +00001771 if (ctx->opcode & 0x0100)
1772 break; /* illegal instruction */
pbrooka7812ae2008-11-17 14:43:54 +00001773 fp = tcg_temp_new_i64();
1774 gen_helper_float_DT(fp, cpu_fpul);
aurel32cc4ba6a2008-09-01 22:11:56 +00001775 gen_store_fpr64(fp, DREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001776 tcg_temp_free_i64(fp);
thsea6cf6b2007-06-22 11:12:01 +00001777 }
1778 else {
aurel3266ba3172008-11-19 18:00:47 +00001779 gen_helper_float_FT(cpu_fregs[FREG(B11_8)], cpu_fpul);
thsea6cf6b2007-06-22 11:12:01 +00001780 }
1781 return;
thse67888a2007-06-22 11:44:41 +00001782 case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
aurel32f6198372008-12-10 17:31:43 +00001783 CHECK_FPU_ENABLED
thsea6cf6b2007-06-22 11:12:01 +00001784 if (ctx->fpscr & FPSCR_PR) {
pbrooka7812ae2008-11-17 14:43:54 +00001785 TCGv_i64 fp;
thsea6cf6b2007-06-22 11:12:01 +00001786 if (ctx->opcode & 0x0100)
1787 break; /* illegal instruction */
pbrooka7812ae2008-11-17 14:43:54 +00001788 fp = tcg_temp_new_i64();
aurel32cc4ba6a2008-09-01 22:11:56 +00001789 gen_load_fpr64(fp, DREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001790 gen_helper_ftrc_DT(cpu_fpul, fp);
1791 tcg_temp_free_i64(fp);
thsea6cf6b2007-06-22 11:12:01 +00001792 }
1793 else {
aurel3266ba3172008-11-19 18:00:47 +00001794 gen_helper_ftrc_FT(cpu_fpul, cpu_fregs[FREG(B11_8)]);
thsea6cf6b2007-06-22 11:12:01 +00001795 }
1796 return;
aurel3224988dc2008-03-11 23:22:37 +00001797 case 0xf04d: /* fneg FRn/DRn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001798 CHECK_FPU_ENABLED
aurel327fdf9242008-09-01 22:12:06 +00001799 {
aurel3266ba3172008-11-19 18:00:47 +00001800 gen_helper_fneg_T(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]);
aurel327fdf9242008-09-01 22:12:06 +00001801 }
aurel3224988dc2008-03-11 23:22:37 +00001802 return;
1803 case 0xf05d: /* fabs FRn/DRn */
aurel32f6198372008-12-10 17:31:43 +00001804 CHECK_FPU_ENABLED
aurel3224988dc2008-03-11 23:22:37 +00001805 if (ctx->fpscr & FPSCR_PR) {
1806 if (ctx->opcode & 0x0100)
1807 break; /* illegal instruction */
pbrooka7812ae2008-11-17 14:43:54 +00001808 TCGv_i64 fp = tcg_temp_new_i64();
aurel32cc4ba6a2008-09-01 22:11:56 +00001809 gen_load_fpr64(fp, DREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001810 gen_helper_fabs_DT(fp, fp);
aurel32cc4ba6a2008-09-01 22:11:56 +00001811 gen_store_fpr64(fp, DREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001812 tcg_temp_free_i64(fp);
aurel3224988dc2008-03-11 23:22:37 +00001813 } else {
aurel3266ba3172008-11-19 18:00:47 +00001814 gen_helper_fabs_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]);
aurel3224988dc2008-03-11 23:22:37 +00001815 }
1816 return;
1817 case 0xf06d: /* fsqrt FRn */
aurel32f6198372008-12-10 17:31:43 +00001818 CHECK_FPU_ENABLED
aurel3224988dc2008-03-11 23:22:37 +00001819 if (ctx->fpscr & FPSCR_PR) {
1820 if (ctx->opcode & 0x0100)
1821 break; /* illegal instruction */
pbrooka7812ae2008-11-17 14:43:54 +00001822 TCGv_i64 fp = tcg_temp_new_i64();
aurel32cc4ba6a2008-09-01 22:11:56 +00001823 gen_load_fpr64(fp, DREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001824 gen_helper_fsqrt_DT(fp, fp);
aurel32cc4ba6a2008-09-01 22:11:56 +00001825 gen_store_fpr64(fp, DREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001826 tcg_temp_free_i64(fp);
aurel3224988dc2008-03-11 23:22:37 +00001827 } else {
aurel3266ba3172008-11-19 18:00:47 +00001828 gen_helper_fsqrt_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]);
aurel3224988dc2008-03-11 23:22:37 +00001829 }
1830 return;
1831 case 0xf07d: /* fsrra FRn */
aurel32f6198372008-12-10 17:31:43 +00001832 CHECK_FPU_ENABLED
aurel3224988dc2008-03-11 23:22:37 +00001833 break;
thse67888a2007-06-22 11:44:41 +00001834 case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */
aurel32f6198372008-12-10 17:31:43 +00001835 CHECK_FPU_ENABLED
thsea6cf6b2007-06-22 11:12:01 +00001836 if (!(ctx->fpscr & FPSCR_PR)) {
aurel3266ba3172008-11-19 18:00:47 +00001837 tcg_gen_movi_i32(cpu_fregs[FREG(B11_8)], 0);
thsea6cf6b2007-06-22 11:12:01 +00001838 }
aurel3212d96132008-11-20 06:41:29 +00001839 return;
thse67888a2007-06-22 11:44:41 +00001840 case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */
aurel32f6198372008-12-10 17:31:43 +00001841 CHECK_FPU_ENABLED
thsea6cf6b2007-06-22 11:12:01 +00001842 if (!(ctx->fpscr & FPSCR_PR)) {
aurel3266ba3172008-11-19 18:00:47 +00001843 tcg_gen_movi_i32(cpu_fregs[FREG(B11_8)], 0x3f800000);
thsea6cf6b2007-06-22 11:12:01 +00001844 }
aurel3212d96132008-11-20 06:41:29 +00001845 return;
aurel3224988dc2008-03-11 23:22:37 +00001846 case 0xf0ad: /* fcnvsd FPUL,DRn */
aurel32f6198372008-12-10 17:31:43 +00001847 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001848 {
pbrooka7812ae2008-11-17 14:43:54 +00001849 TCGv_i64 fp = tcg_temp_new_i64();
1850 gen_helper_fcnvsd_FT_DT(fp, cpu_fpul);
aurel32cc4ba6a2008-09-01 22:11:56 +00001851 gen_store_fpr64(fp, DREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001852 tcg_temp_free_i64(fp);
aurel32cc4ba6a2008-09-01 22:11:56 +00001853 }
aurel3224988dc2008-03-11 23:22:37 +00001854 return;
1855 case 0xf0bd: /* fcnvds DRn,FPUL */
aurel32f6198372008-12-10 17:31:43 +00001856 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001857 {
pbrooka7812ae2008-11-17 14:43:54 +00001858 TCGv_i64 fp = tcg_temp_new_i64();
aurel32cc4ba6a2008-09-01 22:11:56 +00001859 gen_load_fpr64(fp, DREG(B11_8));
pbrooka7812ae2008-11-17 14:43:54 +00001860 gen_helper_fcnvds_DT_FT(cpu_fpul, fp);
1861 tcg_temp_free_i64(fp);
aurel32cc4ba6a2008-09-01 22:11:56 +00001862 }
aurel3224988dc2008-03-11 23:22:37 +00001863 return;
Aurelien Jarnoaf8c2bd2011-01-14 20:39:18 +01001864 case 0xf0ed: /* fipr FVm,FVn */
1865 CHECK_FPU_ENABLED
1866 if ((ctx->fpscr & FPSCR_PR) == 0) {
1867 TCGv m, n;
1868 m = tcg_const_i32((ctx->opcode >> 16) & 3);
1869 n = tcg_const_i32((ctx->opcode >> 18) & 3);
1870 gen_helper_fipr(m, n);
1871 tcg_temp_free(m);
1872 tcg_temp_free(n);
1873 return;
1874 }
1875 break;
Aurelien Jarno17075f12011-01-14 20:39:18 +01001876 case 0xf0fd: /* ftrv XMTRX,FVn */
1877 CHECK_FPU_ENABLED
1878 if ((ctx->opcode & 0x0300) == 0x0100 &&
1879 (ctx->fpscr & FPSCR_PR) == 0) {
1880 TCGv n;
1881 n = tcg_const_i32((ctx->opcode >> 18) & 3);
1882 gen_helper_ftrv(n);
1883 tcg_temp_free(n);
1884 return;
1885 }
1886 break;
bellardfdf9b3e2006-04-27 21:07:38 +00001887 }
aurel32bacc6372008-12-13 18:57:46 +00001888#if 0
bellardfdf9b3e2006-04-27 21:07:38 +00001889 fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
1890 ctx->opcode, ctx->pc);
aurel32bacc6372008-12-13 18:57:46 +00001891 fflush(stderr);
1892#endif
Aurelien Jarno86865c52011-01-11 16:13:34 +01001893 if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
1894 gen_helper_raise_slot_illegal_instruction();
1895 } else {
1896 gen_helper_raise_illegal_instruction();
1897 }
ths823029f2007-12-02 06:10:04 +00001898 ctx->bstate = BS_EXCP;
1899}
1900
blueswir1b1d8e522008-10-26 13:43:07 +00001901static void decode_opc(DisasContext * ctx)
ths823029f2007-12-02 06:10:04 +00001902{
1903 uint32_t old_flags = ctx->flags;
1904
Aurelien Jarnobe15c502011-01-14 20:39:18 +01001905 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
1906 tcg_gen_debug_insn_start(ctx->pc);
1907 }
1908
ths823029f2007-12-02 06:10:04 +00001909 _decode_opc(ctx);
1910
1911 if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
1912 if (ctx->flags & DELAY_SLOT_CLEARME) {
aurel3210008222008-08-29 22:32:32 +00001913 gen_store_flags(0);
aurel32274a9e72008-08-22 08:57:35 +00001914 } else {
1915 /* go out of the delay slot */
1916 uint32_t new_flags = ctx->flags;
1917 new_flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
aurel3210008222008-08-29 22:32:32 +00001918 gen_store_flags(new_flags);
ths823029f2007-12-02 06:10:04 +00001919 }
1920 ctx->flags = 0;
1921 ctx->bstate = BS_BRANCH;
1922 if (old_flags & DELAY_SLOT_CONDITIONAL) {
1923 gen_delayed_conditional_jump(ctx);
1924 } else if (old_flags & DELAY_SLOT) {
1925 gen_jump(ctx);
1926 }
1927
1928 }
aurel32274a9e72008-08-22 08:57:35 +00001929
1930 /* go into a delay slot */
1931 if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL))
aurel3210008222008-08-29 22:32:32 +00001932 gen_store_flags(ctx->flags);
bellardfdf9b3e2006-04-27 21:07:38 +00001933}
1934
ths2cfc5f12008-07-18 18:01:29 +00001935static inline void
ths820e00f2007-03-19 21:46:06 +00001936gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
1937 int search_pc)
bellardfdf9b3e2006-04-27 21:07:38 +00001938{
1939 DisasContext ctx;
1940 target_ulong pc_start;
1941 static uint16_t *gen_opc_end;
aliguoria1d1bb32008-11-18 20:07:32 +00001942 CPUBreakpoint *bp;
pbrook355fb232006-06-17 19:58:25 +00001943 int i, ii;
pbrook2e70f6e2008-06-29 01:03:05 +00001944 int num_insns;
1945 int max_insns;
bellardfdf9b3e2006-04-27 21:07:38 +00001946
1947 pc_start = tb->pc;
bellardfdf9b3e2006-04-27 21:07:38 +00001948 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
bellardfdf9b3e2006-04-27 21:07:38 +00001949 ctx.pc = pc_start;
ths823029f2007-12-02 06:10:04 +00001950 ctx.flags = (uint32_t)tb->flags;
1951 ctx.bstate = BS_NONE;
bellardfdf9b3e2006-04-27 21:07:38 +00001952 ctx.sr = env->sr;
bellardeda9b092006-06-14 15:02:05 +00001953 ctx.fpscr = env->fpscr;
Aurelien Jarno1f486812010-02-01 19:58:46 +01001954 ctx.memidx = (env->sr & SR_MD) == 0 ? 1 : 0;
pbrook9854bc42006-06-17 18:48:31 +00001955 /* We don't know if the delayed pc came from a dynamic or static branch,
1956 so assume it is a dynamic branch. */
ths823029f2007-12-02 06:10:04 +00001957 ctx.delayed_pc = -1; /* use delayed pc from env pointer */
bellardfdf9b3e2006-04-27 21:07:38 +00001958 ctx.tb = tb;
1959 ctx.singlestep_enabled = env->singlestep_enabled;
aurel3271968fa2008-12-13 18:57:37 +00001960 ctx.features = env->features;
edgar_igl852d4812009-04-01 23:10:46 +00001961 ctx.has_movcal = (tb->flags & TB_FLAG_PENDING_MOVCA);
bellardfdf9b3e2006-04-27 21:07:38 +00001962
pbrook355fb232006-06-17 19:58:25 +00001963 ii = -1;
pbrook2e70f6e2008-06-29 01:03:05 +00001964 num_insns = 0;
1965 max_insns = tb->cflags & CF_COUNT_MASK;
1966 if (max_insns == 0)
1967 max_insns = CF_COUNT_MASK;
1968 gen_icount_start();
ths823029f2007-12-02 06:10:04 +00001969 while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
Blue Swirl72cf2d42009-09-12 07:36:22 +00001970 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
1971 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00001972 if (ctx.pc == bp->pc) {
bellardfdf9b3e2006-04-27 21:07:38 +00001973 /* We have hit a breakpoint - make sure PC is up-to-date */
aurel323a8a44c2008-08-29 16:32:18 +00001974 tcg_gen_movi_i32(cpu_pc, ctx.pc);
pbrooka7812ae2008-11-17 14:43:54 +00001975 gen_helper_debug();
ths823029f2007-12-02 06:10:04 +00001976 ctx.bstate = BS_EXCP;
bellardfdf9b3e2006-04-27 21:07:38 +00001977 break;
1978 }
1979 }
1980 }
pbrook355fb232006-06-17 19:58:25 +00001981 if (search_pc) {
1982 i = gen_opc_ptr - gen_opc_buf;
1983 if (ii < i) {
1984 ii++;
1985 while (ii < i)
1986 gen_opc_instr_start[ii++] = 0;
1987 }
1988 gen_opc_pc[ii] = ctx.pc;
ths823029f2007-12-02 06:10:04 +00001989 gen_opc_hflags[ii] = ctx.flags;
pbrook355fb232006-06-17 19:58:25 +00001990 gen_opc_instr_start[ii] = 1;
pbrook2e70f6e2008-06-29 01:03:05 +00001991 gen_opc_icount[ii] = num_insns;
pbrook355fb232006-06-17 19:58:25 +00001992 }
pbrook2e70f6e2008-06-29 01:03:05 +00001993 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
1994 gen_io_start();
bellardfdf9b3e2006-04-27 21:07:38 +00001995#if 0
1996 fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc);
1997 fflush(stderr);
1998#endif
1999 ctx.opcode = lduw_code(ctx.pc);
2000 decode_opc(&ctx);
pbrook2e70f6e2008-06-29 01:03:05 +00002001 num_insns++;
bellardfdf9b3e2006-04-27 21:07:38 +00002002 ctx.pc += 2;
2003 if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
2004 break;
2005 if (env->singlestep_enabled)
2006 break;
pbrook2e70f6e2008-06-29 01:03:05 +00002007 if (num_insns >= max_insns)
2008 break;
aurel321b530a62009-04-05 20:08:59 +00002009 if (singlestep)
2010 break;
bellardfdf9b3e2006-04-27 21:07:38 +00002011 }
pbrook2e70f6e2008-06-29 01:03:05 +00002012 if (tb->cflags & CF_LAST_IO)
2013 gen_io_end();
bellardfdf9b3e2006-04-27 21:07:38 +00002014 if (env->singlestep_enabled) {
aurel32bdbf22e2008-10-12 23:32:48 +00002015 tcg_gen_movi_i32(cpu_pc, ctx.pc);
pbrooka7812ae2008-11-17 14:43:54 +00002016 gen_helper_debug();
ths823029f2007-12-02 06:10:04 +00002017 } else {
2018 switch (ctx.bstate) {
2019 case BS_STOP:
2020 /* gen_op_interrupt_restart(); */
2021 /* fall through */
2022 case BS_NONE:
2023 if (ctx.flags) {
aurel3210008222008-08-29 22:32:32 +00002024 gen_store_flags(ctx.flags | DELAY_SLOT_CLEARME);
ths823029f2007-12-02 06:10:04 +00002025 }
2026 gen_goto_tb(&ctx, 0, ctx.pc);
2027 break;
2028 case BS_EXCP:
2029 /* gen_op_interrupt_restart(); */
bellard57fec1f2008-02-01 10:50:11 +00002030 tcg_gen_exit_tb(0);
ths823029f2007-12-02 06:10:04 +00002031 break;
2032 case BS_BRANCH:
2033 default:
2034 break;
2035 }
bellardfdf9b3e2006-04-27 21:07:38 +00002036 }
ths823029f2007-12-02 06:10:04 +00002037
pbrook2e70f6e2008-06-29 01:03:05 +00002038 gen_icount_end(tb, num_insns);
bellardfdf9b3e2006-04-27 21:07:38 +00002039 *gen_opc_ptr = INDEX_op_end;
pbrook355fb232006-06-17 19:58:25 +00002040 if (search_pc) {
2041 i = gen_opc_ptr - gen_opc_buf;
2042 ii++;
2043 while (ii <= i)
2044 gen_opc_instr_start[ii++] = 0;
pbrook355fb232006-06-17 19:58:25 +00002045 } else {
2046 tb->size = ctx.pc - pc_start;
pbrook2e70f6e2008-06-29 01:03:05 +00002047 tb->icount = num_insns;
pbrook355fb232006-06-17 19:58:25 +00002048 }
bellardfdf9b3e2006-04-27 21:07:38 +00002049
2050#ifdef DEBUG_DISAS
2051#ifdef SH4_DEBUG_DISAS
aliguori93fcfe32009-01-15 22:34:14 +00002052 qemu_log_mask(CPU_LOG_TB_IN_ASM, "\n");
bellardfdf9b3e2006-04-27 21:07:38 +00002053#endif
aliguori8fec2b82009-01-15 22:36:53 +00002054 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
aliguori93fcfe32009-01-15 22:34:14 +00002055 qemu_log("IN:\n"); /* , lookup_symbol(pc_start)); */
2056 log_target_disas(pc_start, ctx.pc - pc_start, 0);
2057 qemu_log("\n");
bellardfdf9b3e2006-04-27 21:07:38 +00002058 }
bellardfdf9b3e2006-04-27 21:07:38 +00002059#endif
bellardfdf9b3e2006-04-27 21:07:38 +00002060}
2061
ths2cfc5f12008-07-18 18:01:29 +00002062void gen_intermediate_code(CPUState * env, struct TranslationBlock *tb)
bellardfdf9b3e2006-04-27 21:07:38 +00002063{
ths2cfc5f12008-07-18 18:01:29 +00002064 gen_intermediate_code_internal(env, tb, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00002065}
2066
ths2cfc5f12008-07-18 18:01:29 +00002067void gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb)
bellardfdf9b3e2006-04-27 21:07:38 +00002068{
ths2cfc5f12008-07-18 18:01:29 +00002069 gen_intermediate_code_internal(env, tb, 1);
bellardfdf9b3e2006-04-27 21:07:38 +00002070}
aurel32d2856f12008-04-28 00:32:32 +00002071
2072void gen_pc_load(CPUState *env, TranslationBlock *tb,
2073 unsigned long searched_pc, int pc_pos, void *puc)
2074{
2075 env->pc = gen_opc_pc[pc_pos];
2076 env->flags = gen_opc_hflags[pc_pos];
2077}