blob: 5a7d8c45355e6dca3ad4c5814fa850d75f38c5d6 [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
Thomas Huth6faf2b62019-02-13 14:52:50 +01009 * version 2.1 of the License, or (at your option) any later version.
bellardfdf9b3e2006-04-27 21:07:38 +000010 *
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 */
bellardfdf9b3e2006-04-27 21:07:38 +000019
20#define DEBUG_DISAS
bellardfdf9b3e2006-04-27 21:07:38 +000021
Peter Maydell9d4c9942016-01-26 18:17:20 +000022#include "qemu/osdep.h"
bellardfdf9b3e2006-04-27 21:07:38 +000023#include "cpu.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +020024#include "disas/disas.h"
Paolo Bonzini63c91552016-03-15 13:18:37 +010025#include "exec/exec-all.h"
bellard57fec1f2008-02-01 10:50:11 +000026#include "tcg-op.h"
Paolo Bonzinif08b6172014-03-28 19:42:10 +010027#include "exec/cpu_ldst.h"
Richard Henderson2ef61752014-04-07 22:31:41 -070028#include "exec/helper-proto.h"
29#include "exec/helper-gen.h"
Richard Henderson48348712017-09-07 11:50:54 -070030#include "exec/translator.h"
Lluís Vilanovaa7e30d82014-05-30 14:12:25 +020031#include "trace-tcg.h"
Paolo Bonzini508127e2016-01-07 16:55:28 +030032#include "exec/log.h"
Markus Armbruster90c84c52019-04-17 21:18:02 +020033#include "qemu/qemu-print.h"
Lluís Vilanovaa7e30d82014-05-30 14:12:25 +020034
35
bellardfdf9b3e2006-04-27 21:07:38 +000036typedef struct DisasContext {
Richard Henderson6f1c2af2017-09-07 11:50:56 -070037 DisasContextBase base;
38
39 uint32_t tbflags; /* should stay unmodified during the TB translation */
40 uint32_t envflags; /* should stay in sync with env->flags using TCG ops */
bellardfdf9b3e2006-04-27 21:07:38 +000041 int memidx;
Richard Henderson3a3bb8d2017-07-18 10:02:35 -100042 int gbank;
Richard Henderson5c13bad2017-07-18 10:02:38 -100043 int fbank;
bellardfdf9b3e2006-04-27 21:07:38 +000044 uint32_t delayed_pc;
aurel3271968fa2008-12-13 18:57:37 +000045 uint32_t features;
Richard Henderson6f1c2af2017-09-07 11:50:56 -070046
47 uint16_t opcode;
48
49 bool has_movcal;
bellardfdf9b3e2006-04-27 21:07:38 +000050} DisasContext;
51
aurel32fe255912008-09-15 08:49:15 +000052#if defined(CONFIG_USER_ONLY)
53#define IS_USER(ctx) 1
54#else
Aurelien Jarnoa6215742017-05-01 23:20:43 +020055#define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD)))
aurel32fe255912008-09-15 08:49:15 +000056#endif
57
Richard Henderson6f1c2af2017-09-07 11:50:56 -070058/* Target-specific values for ctx->base.is_jmp. */
Richard Henderson48348712017-09-07 11:50:54 -070059/* We want to exit back to the cpu loop for some reason.
60 Usually this is to recognize interrupts immediately. */
61#define DISAS_STOP DISAS_TARGET_0
ths823029f2007-12-02 06:10:04 +000062
aurel321e8864f2008-08-29 00:48:50 +000063/* global register indexes */
Richard Henderson3a3bb8d2017-07-18 10:02:35 -100064static TCGv cpu_gregs[32];
Aurelien Jarno1d565b22015-05-25 01:28:56 +020065static TCGv cpu_sr, cpu_sr_m, cpu_sr_q, cpu_sr_t;
66static TCGv cpu_pc, cpu_ssr, cpu_spc, cpu_gbr;
aurel323a8a44c2008-08-29 16:32:18 +000067static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl;
Richard Hendersonf85da302017-09-07 11:50:53 -070068static TCGv cpu_pr, cpu_fpscr, cpu_fpul;
69static TCGv cpu_lock_addr, cpu_lock_value;
aurel3266ba3172008-11-19 18:00:47 +000070static TCGv cpu_fregs[32];
aurel3210008222008-08-29 22:32:32 +000071
72/* internal register indexes */
Aurelien Jarno47b9f4d2017-05-01 23:20:43 +020073static TCGv cpu_flags, cpu_delayed_pc, cpu_delayed_cond;
aurel321e8864f2008-08-29 00:48:50 +000074
Paolo Bonzini022c62c2012-12-17 18:19:49 +010075#include "exec/gen-icount.h"
pbrook2e70f6e2008-06-29 01:03:05 +000076
Andreas Färberaa7408e2013-01-20 01:30:32 +010077void sh4_translate_init(void)
pbrook2e70f6e2008-06-29 01:03:05 +000078{
aurel321e8864f2008-08-29 00:48:50 +000079 int i;
aurel32559dd742008-08-29 10:05:12 +000080 static const char * const gregnames[24] = {
aurel321e8864f2008-08-29 00:48:50 +000081 "R0_BANK0", "R1_BANK0", "R2_BANK0", "R3_BANK0",
82 "R4_BANK0", "R5_BANK0", "R6_BANK0", "R7_BANK0",
83 "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
84 "R0_BANK1", "R1_BANK1", "R2_BANK1", "R3_BANK1",
85 "R4_BANK1", "R5_BANK1", "R6_BANK1", "R7_BANK1"
86 };
aurel3266ba3172008-11-19 18:00:47 +000087 static const char * const fregnames[32] = {
88 "FPR0_BANK0", "FPR1_BANK0", "FPR2_BANK0", "FPR3_BANK0",
89 "FPR4_BANK0", "FPR5_BANK0", "FPR6_BANK0", "FPR7_BANK0",
90 "FPR8_BANK0", "FPR9_BANK0", "FPR10_BANK0", "FPR11_BANK0",
91 "FPR12_BANK0", "FPR13_BANK0", "FPR14_BANK0", "FPR15_BANK0",
92 "FPR0_BANK1", "FPR1_BANK1", "FPR2_BANK1", "FPR3_BANK1",
93 "FPR4_BANK1", "FPR5_BANK1", "FPR6_BANK1", "FPR7_BANK1",
94 "FPR8_BANK1", "FPR9_BANK1", "FPR10_BANK1", "FPR11_BANK1",
95 "FPR12_BANK1", "FPR13_BANK1", "FPR14_BANK1", "FPR15_BANK1",
96 };
aurel321e8864f2008-08-29 00:48:50 +000097
Richard Henderson3a3bb8d2017-07-18 10:02:35 -100098 for (i = 0; i < 24; i++) {
Richard Hendersone1ccc052013-09-18 12:53:09 -070099 cpu_gregs[i] = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100100 offsetof(CPUSH4State, gregs[i]),
aurel3266ba3172008-11-19 18:00:47 +0000101 gregnames[i]);
Richard Henderson3a3bb8d2017-07-18 10:02:35 -1000102 }
103 memcpy(cpu_gregs + 24, cpu_gregs + 8, 8 * sizeof(TCGv));
aurel32988d7ea2008-08-28 21:02:00 +0000104
Richard Hendersone1ccc052013-09-18 12:53:09 -0700105 cpu_pc = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100106 offsetof(CPUSH4State, pc), "PC");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700107 cpu_sr = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100108 offsetof(CPUSH4State, sr), "SR");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700109 cpu_sr_m = tcg_global_mem_new_i32(cpu_env,
110 offsetof(CPUSH4State, sr_m), "SR_M");
111 cpu_sr_q = tcg_global_mem_new_i32(cpu_env,
112 offsetof(CPUSH4State, sr_q), "SR_Q");
113 cpu_sr_t = tcg_global_mem_new_i32(cpu_env,
114 offsetof(CPUSH4State, sr_t), "SR_T");
115 cpu_ssr = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100116 offsetof(CPUSH4State, ssr), "SSR");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700117 cpu_spc = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100118 offsetof(CPUSH4State, spc), "SPC");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700119 cpu_gbr = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100120 offsetof(CPUSH4State, gbr), "GBR");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700121 cpu_vbr = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100122 offsetof(CPUSH4State, vbr), "VBR");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700123 cpu_sgr = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100124 offsetof(CPUSH4State, sgr), "SGR");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700125 cpu_dbr = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100126 offsetof(CPUSH4State, dbr), "DBR");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700127 cpu_mach = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100128 offsetof(CPUSH4State, mach), "MACH");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700129 cpu_macl = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100130 offsetof(CPUSH4State, macl), "MACL");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700131 cpu_pr = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100132 offsetof(CPUSH4State, pr), "PR");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700133 cpu_fpscr = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100134 offsetof(CPUSH4State, fpscr), "FPSCR");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700135 cpu_fpul = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100136 offsetof(CPUSH4State, fpul), "FPUL");
aurel323a8a44c2008-08-29 16:32:18 +0000137
Richard Hendersone1ccc052013-09-18 12:53:09 -0700138 cpu_flags = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100139 offsetof(CPUSH4State, flags), "_flags_");
Richard Hendersone1ccc052013-09-18 12:53:09 -0700140 cpu_delayed_pc = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100141 offsetof(CPUSH4State, delayed_pc),
pbrooka7812ae2008-11-17 14:43:54 +0000142 "_delayed_pc_");
Aurelien Jarno47b9f4d2017-05-01 23:20:43 +0200143 cpu_delayed_cond = tcg_global_mem_new_i32(cpu_env,
144 offsetof(CPUSH4State,
145 delayed_cond),
146 "_delayed_cond_");
Richard Hendersonf85da302017-09-07 11:50:53 -0700147 cpu_lock_addr = tcg_global_mem_new_i32(cpu_env,
148 offsetof(CPUSH4State, lock_addr),
149 "_lock_addr_");
150 cpu_lock_value = tcg_global_mem_new_i32(cpu_env,
151 offsetof(CPUSH4State, lock_value),
152 "_lock_value_");
aurel3210008222008-08-29 22:32:32 +0000153
aurel3266ba3172008-11-19 18:00:47 +0000154 for (i = 0; i < 32; i++)
Richard Hendersone1ccc052013-09-18 12:53:09 -0700155 cpu_fregs[i] = tcg_global_mem_new_i32(cpu_env,
Andreas Färber73e57162012-03-14 01:38:22 +0100156 offsetof(CPUSH4State, fregs[i]),
aurel3266ba3172008-11-19 18:00:47 +0000157 fregnames[i]);
pbrook2e70f6e2008-06-29 01:03:05 +0000158}
159
Markus Armbruster90c84c52019-04-17 21:18:02 +0200160void superh_cpu_dump_state(CPUState *cs, FILE *f, int flags)
bellardfdf9b3e2006-04-27 21:07:38 +0000161{
Andreas Färber878096e2013-05-27 01:33:50 +0200162 SuperHCPU *cpu = SUPERH_CPU(cs);
163 CPUSH4State *env = &cpu->env;
bellardfdf9b3e2006-04-27 21:07:38 +0000164 int i;
Markus Armbruster90c84c52019-04-17 21:18:02 +0200165
166 qemu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n",
167 env->pc, cpu_read_sr(env), env->pr, env->fpscr);
168 qemu_fprintf(f, "spc=0x%08x ssr=0x%08x gbr=0x%08x vbr=0x%08x\n",
169 env->spc, env->ssr, env->gbr, env->vbr);
170 qemu_fprintf(f, "sgr=0x%08x dbr=0x%08x delayed_pc=0x%08x fpul=0x%08x\n",
171 env->sgr, env->dbr, env->delayed_pc, env->fpul);
bellardfdf9b3e2006-04-27 21:07:38 +0000172 for (i = 0; i < 24; i += 4) {
Markus Armbruster90c84c52019-04-17 21:18:02 +0200173 qemu_printf("r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n",
bellardfdf9b3e2006-04-27 21:07:38 +0000174 i, env->gregs[i], i + 1, env->gregs[i + 1],
175 i + 2, env->gregs[i + 2], i + 3, env->gregs[i + 3]);
176 }
177 if (env->flags & DELAY_SLOT) {
Markus Armbruster90c84c52019-04-17 21:18:02 +0200178 qemu_printf("in delay slot (delayed_pc=0x%08x)\n",
bellardfdf9b3e2006-04-27 21:07:38 +0000179 env->delayed_pc);
180 } else if (env->flags & DELAY_SLOT_CONDITIONAL) {
Markus Armbruster90c84c52019-04-17 21:18:02 +0200181 qemu_printf("in conditional delay slot (delayed_pc=0x%08x)\n",
bellardfdf9b3e2006-04-27 21:07:38 +0000182 env->delayed_pc);
Aurelien Jarnobe530812017-05-17 00:48:18 +0200183 } else if (env->flags & DELAY_SLOT_RTE) {
Markus Armbruster90c84c52019-04-17 21:18:02 +0200184 qemu_fprintf(f, "in rte delay slot (delayed_pc=0x%08x)\n",
185 env->delayed_pc);
bellardfdf9b3e2006-04-27 21:07:38 +0000186 }
187}
188
Aurelien Jarno34086942015-05-25 01:28:56 +0200189static void gen_read_sr(TCGv dst)
190{
Aurelien Jarno1d565b22015-05-25 01:28:56 +0200191 TCGv t0 = tcg_temp_new();
192 tcg_gen_shli_i32(t0, cpu_sr_q, SR_Q);
193 tcg_gen_or_i32(dst, dst, t0);
194 tcg_gen_shli_i32(t0, cpu_sr_m, SR_M);
195 tcg_gen_or_i32(dst, dst, t0);
196 tcg_gen_shli_i32(t0, cpu_sr_t, SR_T);
197 tcg_gen_or_i32(dst, cpu_sr, t0);
198 tcg_temp_free_i32(t0);
Aurelien Jarno34086942015-05-25 01:28:56 +0200199}
200
201static void gen_write_sr(TCGv src)
202{
Aurelien Jarno1d565b22015-05-25 01:28:56 +0200203 tcg_gen_andi_i32(cpu_sr, src,
204 ~((1u << SR_Q) | (1u << SR_M) | (1u << SR_T)));
Aurelien Jarnoa380f9d2017-05-01 23:20:43 +0200205 tcg_gen_extract_i32(cpu_sr_q, src, SR_Q, 1);
206 tcg_gen_extract_i32(cpu_sr_m, src, SR_M, 1);
207 tcg_gen_extract_i32(cpu_sr_t, src, SR_T, 1);
Aurelien Jarno34086942015-05-25 01:28:56 +0200208}
209
Aurelien Jarnoac9707e2017-05-01 23:20:43 +0200210static inline void gen_save_cpu_state(DisasContext *ctx, bool save_pc)
211{
212 if (save_pc) {
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700213 tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
Aurelien Jarnoac9707e2017-05-01 23:20:43 +0200214 }
215 if (ctx->delayed_pc != (uint32_t) -1) {
216 tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc);
217 }
Richard Hendersone1933d12017-07-18 10:02:28 -1000218 if ((ctx->tbflags & TB_FLAG_ENVFLAGS_MASK) != ctx->envflags) {
Aurelien Jarnoac9707e2017-05-01 23:20:43 +0200219 tcg_gen_movi_i32(cpu_flags, ctx->envflags);
220 }
221}
222
Richard Hendersonec2eb222017-07-18 10:02:52 -1000223static inline bool use_exit_tb(DisasContext *ctx)
224{
225 return (ctx->tbflags & GUSA_EXCLUSIVE) != 0;
226}
227
Sergey Fedorov90aa39a2016-04-09 01:00:23 +0300228static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
bellardfdf9b3e2006-04-27 21:07:38 +0000229{
Richard Hendersonec2eb222017-07-18 10:02:52 -1000230 /* Use a direct jump if in same page and singlestep not enabled */
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700231 if (unlikely(ctx->base.singlestep_enabled || use_exit_tb(ctx))) {
Richard Henderson4bfa6022017-07-18 10:02:31 -1000232 return false;
233 }
Sergey Fedorov90aa39a2016-04-09 01:00:23 +0300234#ifndef CONFIG_USER_ONLY
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700235 return (ctx->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
Sergey Fedorov90aa39a2016-04-09 01:00:23 +0300236#else
237 return true;
238#endif
239}
240
241static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
242{
243 if (use_goto_tb(ctx, dest)) {
bellard57fec1f2008-02-01 10:50:11 +0000244 tcg_gen_goto_tb(n);
aurel323a8a44c2008-08-29 16:32:18 +0000245 tcg_gen_movi_i32(cpu_pc, dest);
Richard Henderson07ea28b2018-05-30 18:06:23 -0700246 tcg_gen_exit_tb(ctx->base.tb, n);
bellardfdf9b3e2006-04-27 21:07:38 +0000247 } else {
aurel323a8a44c2008-08-29 16:32:18 +0000248 tcg_gen_movi_i32(cpu_pc, dest);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700249 if (ctx->base.singlestep_enabled) {
Blue Swirl485d0032012-09-02 10:37:06 +0000250 gen_helper_debug(cpu_env);
Richard Hendersonec2eb222017-07-18 10:02:52 -1000251 } else if (use_exit_tb(ctx)) {
Richard Henderson07ea28b2018-05-30 18:06:23 -0700252 tcg_gen_exit_tb(NULL, 0);
Richard Hendersonec2eb222017-07-18 10:02:52 -1000253 } else {
Emilio G. Cota7f116362017-07-11 17:06:48 -0400254 tcg_gen_lookup_and_goto_ptr();
Richard Hendersonec2eb222017-07-18 10:02:52 -1000255 }
bellardfdf9b3e2006-04-27 21:07:38 +0000256 }
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700257 ctx->base.is_jmp = DISAS_NORETURN;
bellardfdf9b3e2006-04-27 21:07:38 +0000258}
259
bellardfdf9b3e2006-04-27 21:07:38 +0000260static void gen_jump(DisasContext * ctx)
261{
Richard Hendersonec2eb222017-07-18 10:02:52 -1000262 if (ctx->delayed_pc == -1) {
bellardfdf9b3e2006-04-27 21:07:38 +0000263 /* Target is not statically known, it comes necessarily from a
264 delayed jump as immediate jump are conditinal jumps */
aurel3210008222008-08-29 22:32:32 +0000265 tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc);
Aurelien Jarnoac9707e2017-05-01 23:20:43 +0200266 tcg_gen_discard_i32(cpu_delayed_pc);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700267 if (ctx->base.singlestep_enabled) {
Blue Swirl485d0032012-09-02 10:37:06 +0000268 gen_helper_debug(cpu_env);
Richard Hendersonec2eb222017-07-18 10:02:52 -1000269 } else if (use_exit_tb(ctx)) {
Richard Henderson07ea28b2018-05-30 18:06:23 -0700270 tcg_gen_exit_tb(NULL, 0);
Richard Hendersonec2eb222017-07-18 10:02:52 -1000271 } else {
Emilio G. Cota7f116362017-07-11 17:06:48 -0400272 tcg_gen_lookup_and_goto_ptr();
Richard Hendersonec2eb222017-07-18 10:02:52 -1000273 }
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700274 ctx->base.is_jmp = DISAS_NORETURN;
bellardfdf9b3e2006-04-27 21:07:38 +0000275 } else {
276 gen_goto_tb(ctx, 0, ctx->delayed_pc);
277 }
278}
279
280/* Immediate conditional jump (bt or bf) */
Richard Henderson4bfa6022017-07-18 10:02:31 -1000281static void gen_conditional_jump(DisasContext *ctx, target_ulong dest,
282 bool jump_if_true)
bellardfdf9b3e2006-04-27 21:07:38 +0000283{
Aurelien Jarno34086942015-05-25 01:28:56 +0200284 TCGLabel *l1 = gen_new_label();
Richard Henderson4bfa6022017-07-18 10:02:31 -1000285 TCGCond cond_not_taken = jump_if_true ? TCG_COND_EQ : TCG_COND_NE;
286
287 if (ctx->tbflags & GUSA_EXCLUSIVE) {
288 /* When in an exclusive region, we must continue to the end.
289 Therefore, exit the region on a taken branch, but otherwise
290 fall through to the next instruction. */
291 tcg_gen_brcondi_i32(cond_not_taken, cpu_sr_t, 0, l1);
292 tcg_gen_movi_i32(cpu_flags, ctx->envflags & ~GUSA_MASK);
293 /* Note that this won't actually use a goto_tb opcode because we
294 disallow it in use_goto_tb, but it handles exit + singlestep. */
295 gen_goto_tb(ctx, 0, dest);
296 gen_set_label(l1);
Laurent Vivier5b38d022018-08-11 10:23:28 +0200297 ctx->base.is_jmp = DISAS_NEXT;
Richard Henderson4bfa6022017-07-18 10:02:31 -1000298 return;
299 }
300
Aurelien Jarnoac9707e2017-05-01 23:20:43 +0200301 gen_save_cpu_state(ctx, false);
Richard Henderson4bfa6022017-07-18 10:02:31 -1000302 tcg_gen_brcondi_i32(cond_not_taken, cpu_sr_t, 0, l1);
303 gen_goto_tb(ctx, 0, dest);
bellardfdf9b3e2006-04-27 21:07:38 +0000304 gen_set_label(l1);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700305 gen_goto_tb(ctx, 1, ctx->base.pc_next + 2);
306 ctx->base.is_jmp = DISAS_NORETURN;
bellardfdf9b3e2006-04-27 21:07:38 +0000307}
308
309/* Delayed conditional jump (bt or bf) */
310static void gen_delayed_conditional_jump(DisasContext * ctx)
311{
Richard Henderson4bfa6022017-07-18 10:02:31 -1000312 TCGLabel *l1 = gen_new_label();
313 TCGv ds = tcg_temp_new();
bellardfdf9b3e2006-04-27 21:07:38 +0000314
Aurelien Jarno47b9f4d2017-05-01 23:20:43 +0200315 tcg_gen_mov_i32(ds, cpu_delayed_cond);
316 tcg_gen_discard_i32(cpu_delayed_cond);
Richard Henderson4bfa6022017-07-18 10:02:31 -1000317
318 if (ctx->tbflags & GUSA_EXCLUSIVE) {
319 /* When in an exclusive region, we must continue to the end.
320 Therefore, exit the region on a taken branch, but otherwise
321 fall through to the next instruction. */
322 tcg_gen_brcondi_i32(TCG_COND_EQ, ds, 0, l1);
323
324 /* Leave the gUSA region. */
325 tcg_gen_movi_i32(cpu_flags, ctx->envflags & ~GUSA_MASK);
326 gen_jump(ctx);
327
328 gen_set_label(l1);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700329 ctx->base.is_jmp = DISAS_NEXT;
Richard Henderson4bfa6022017-07-18 10:02:31 -1000330 return;
331 }
332
Aurelien Jarno6f396c82011-01-14 20:39:18 +0100333 tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700334 gen_goto_tb(ctx, 1, ctx->base.pc_next + 2);
bellardfdf9b3e2006-04-27 21:07:38 +0000335 gen_set_label(l1);
pbrook9c2a9ea2006-06-18 19:12:54 +0000336 gen_jump(ctx);
bellardfdf9b3e2006-04-27 21:07:38 +0000337}
338
Richard Hendersone5d80532017-07-18 10:02:37 -1000339static inline void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg)
aurel32cc4ba6a2008-09-01 22:11:56 +0000340{
Richard Henderson1e0b21d2017-07-18 10:02:40 -1000341 /* We have already signaled illegal instruction for odd Dr. */
342 tcg_debug_assert((reg & 1) == 0);
343 reg ^= ctx->fbank;
aurel3266ba3172008-11-19 18:00:47 +0000344 tcg_gen_concat_i32_i64(t, cpu_fregs[reg + 1], cpu_fregs[reg]);
aurel32cc4ba6a2008-09-01 22:11:56 +0000345}
346
Richard Hendersone5d80532017-07-18 10:02:37 -1000347static inline void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg)
aurel32cc4ba6a2008-09-01 22:11:56 +0000348{
Richard Henderson1e0b21d2017-07-18 10:02:40 -1000349 /* We have already signaled illegal instruction for odd Dr. */
350 tcg_debug_assert((reg & 1) == 0);
351 reg ^= ctx->fbank;
Aurelien Jarno58d2a9a2017-05-01 23:20:43 +0200352 tcg_gen_extr_i64_i32(cpu_fregs[reg + 1], cpu_fregs[reg], t);
aurel32cc4ba6a2008-09-01 22:11:56 +0000353}
354
bellardfdf9b3e2006-04-27 21:07:38 +0000355#define B3_0 (ctx->opcode & 0xf)
356#define B6_4 ((ctx->opcode >> 4) & 0x7)
357#define B7_4 ((ctx->opcode >> 4) & 0xf)
358#define B7_0 (ctx->opcode & 0xff)
359#define B7_0s ((int32_t) (int8_t) (ctx->opcode & 0xff))
360#define B11_0s (ctx->opcode & 0x800 ? 0xfffff000 | (ctx->opcode & 0xfff) : \
361 (ctx->opcode & 0xfff))
362#define B11_8 ((ctx->opcode >> 8) & 0xf)
363#define B15_12 ((ctx->opcode >> 12) & 0xf)
364
Richard Henderson3a3bb8d2017-07-18 10:02:35 -1000365#define REG(x) cpu_gregs[(x) ^ ctx->gbank]
366#define ALTREG(x) cpu_gregs[(x) ^ ctx->gbank ^ 0x10]
Richard Henderson5c13bad2017-07-18 10:02:38 -1000367#define FREG(x) cpu_fregs[(x) ^ ctx->fbank]
bellardfdf9b3e2006-04-27 21:07:38 +0000368
thsf09111e2007-05-13 16:33:43 +0000369#define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe))
bellardeda9b092006-06-14 15:02:05 +0000370
bellardfdf9b3e2006-04-27 21:07:38 +0000371#define CHECK_NOT_DELAY_SLOT \
Richard Hendersondec16c62017-07-18 10:02:43 -1000372 if (ctx->envflags & DELAY_SLOT_MASK) { \
373 goto do_illegal_slot; \
Aurelien Jarnoa6215742017-05-01 23:20:43 +0200374 }
bellardfdf9b3e2006-04-27 21:07:38 +0000375
Richard Henderson6b982132017-07-18 10:02:44 -1000376#define CHECK_PRIVILEGED \
377 if (IS_USER(ctx)) { \
378 goto do_illegal; \
Aurelien Jarnoa6215742017-05-01 23:20:43 +0200379 }
aurel32fe255912008-09-15 08:49:15 +0000380
Richard Hendersondec4f042017-07-18 10:02:45 -1000381#define CHECK_FPU_ENABLED \
382 if (ctx->tbflags & (1u << SR_FD)) { \
383 goto do_fpu_disabled; \
Aurelien Jarnoa6215742017-05-01 23:20:43 +0200384 }
aurel32d8299bc2008-12-07 22:46:31 +0000385
Richard Henderson7e9f7ca2017-07-18 10:02:47 -1000386#define CHECK_FPSCR_PR_0 \
387 if (ctx->tbflags & FPSCR_PR) { \
388 goto do_illegal; \
389 }
390
391#define CHECK_FPSCR_PR_1 \
392 if (!(ctx->tbflags & FPSCR_PR)) { \
393 goto do_illegal; \
394 }
395
Richard Hendersonccae24d2017-07-18 10:02:48 -1000396#define CHECK_SH4A \
397 if (!(ctx->features & SH_FEATURE_SH4A)) { \
398 goto do_illegal; \
399 }
400
blueswir1b1d8e522008-10-26 13:43:07 +0000401static void _decode_opc(DisasContext * ctx)
bellardfdf9b3e2006-04-27 21:07:38 +0000402{
edgar_igl852d4812009-04-01 23:10:46 +0000403 /* This code tries to make movcal emulation sufficiently
404 accurate for Linux purposes. This instruction writes
405 memory, and prior to that, always allocates a cache line.
406 It is used in two contexts:
407 - in memcpy, where data is copied in blocks, the first write
408 of to a block uses movca.l for performance.
409 - in arch/sh/mm/cache-sh4.c, movcal.l + ocbi combination is used
410 to flush the cache. Here, the data written by movcal.l is never
411 written to memory, and the data written is just bogus.
412
413 To simulate this, we simulate movcal.l, we store the value to memory,
414 but we also remember the previous content. If we see ocbi, we check
415 if movcal.l for that address was done previously. If so, the write should
416 not have hit the memory, so we restore the previous content.
417 When we see an instruction that is neither movca.l
418 nor ocbi, the previous content is discarded.
419
420 To optimize, we only try to flush stores when we're at the start of
421 TB, or if we already saw movca.l in this TB and did not flush stores
422 yet. */
423 if (ctx->has_movcal)
424 {
425 int opcode = ctx->opcode & 0xf0ff;
426 if (opcode != 0x0093 /* ocbi */
427 && opcode != 0x00c3 /* movca.l */)
428 {
Blue Swirl485d0032012-09-02 10:37:06 +0000429 gen_helper_discard_movcal_backup(cpu_env);
edgar_igl852d4812009-04-01 23:10:46 +0000430 ctx->has_movcal = 0;
431 }
432 }
433
bellardfdf9b3e2006-04-27 21:07:38 +0000434#if 0
435 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode);
436#endif
aurel32f6198372008-12-10 17:31:43 +0000437
bellardfdf9b3e2006-04-27 21:07:38 +0000438 switch (ctx->opcode) {
439 case 0x0019: /* div0u */
Aurelien Jarno1d565b22015-05-25 01:28:56 +0200440 tcg_gen_movi_i32(cpu_sr_m, 0);
441 tcg_gen_movi_i32(cpu_sr_q, 0);
Aurelien Jarno34086942015-05-25 01:28:56 +0200442 tcg_gen_movi_i32(cpu_sr_t, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000443 return;
444 case 0x000b: /* rts */
aurel3210008222008-08-29 22:32:32 +0000445 CHECK_NOT_DELAY_SLOT
446 tcg_gen_mov_i32(cpu_delayed_pc, cpu_pr);
Aurelien Jarnoa6215742017-05-01 23:20:43 +0200447 ctx->envflags |= DELAY_SLOT;
bellardfdf9b3e2006-04-27 21:07:38 +0000448 ctx->delayed_pc = (uint32_t) - 1;
449 return;
450 case 0x0028: /* clrmac */
aurel323a8a44c2008-08-29 16:32:18 +0000451 tcg_gen_movi_i32(cpu_mach, 0);
452 tcg_gen_movi_i32(cpu_macl, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000453 return;
454 case 0x0048: /* clrs */
Aurelien Jarno5ed9a252015-05-25 01:28:56 +0200455 tcg_gen_andi_i32(cpu_sr, cpu_sr, ~(1u << SR_S));
bellardfdf9b3e2006-04-27 21:07:38 +0000456 return;
457 case 0x0008: /* clrt */
Aurelien Jarno34086942015-05-25 01:28:56 +0200458 tcg_gen_movi_i32(cpu_sr_t, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000459 return;
460 case 0x0038: /* ldtlb */
aurel32fe255912008-09-15 08:49:15 +0000461 CHECK_PRIVILEGED
Blue Swirl485d0032012-09-02 10:37:06 +0000462 gen_helper_ldtlb(cpu_env);
bellardfdf9b3e2006-04-27 21:07:38 +0000463 return;
thsc5e814b2007-09-29 19:52:22 +0000464 case 0x002b: /* rte */
aurel32fe255912008-09-15 08:49:15 +0000465 CHECK_PRIVILEGED
aurel3210008222008-08-29 22:32:32 +0000466 CHECK_NOT_DELAY_SLOT
Aurelien Jarno34086942015-05-25 01:28:56 +0200467 gen_write_sr(cpu_ssr);
aurel3210008222008-08-29 22:32:32 +0000468 tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc);
Aurelien Jarnobe530812017-05-17 00:48:18 +0200469 ctx->envflags |= DELAY_SLOT_RTE;
bellardfdf9b3e2006-04-27 21:07:38 +0000470 ctx->delayed_pc = (uint32_t) - 1;
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700471 ctx->base.is_jmp = DISAS_STOP;
bellardfdf9b3e2006-04-27 21:07:38 +0000472 return;
473 case 0x0058: /* sets */
Aurelien Jarno5ed9a252015-05-25 01:28:56 +0200474 tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S));
bellardfdf9b3e2006-04-27 21:07:38 +0000475 return;
476 case 0x0018: /* sett */
Aurelien Jarno34086942015-05-25 01:28:56 +0200477 tcg_gen_movi_i32(cpu_sr_t, 1);
bellardfdf9b3e2006-04-27 21:07:38 +0000478 return;
aurel3224988dc2008-03-11 23:22:37 +0000479 case 0xfbfd: /* frchg */
Richard Henderson61dedf22017-07-18 10:02:50 -1000480 CHECK_FPSCR_PR_0
aurel326f069392008-08-30 13:55:14 +0000481 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700482 ctx->base.is_jmp = DISAS_STOP;
bellardfdf9b3e2006-04-27 21:07:38 +0000483 return;
aurel3224988dc2008-03-11 23:22:37 +0000484 case 0xf3fd: /* fschg */
Richard Henderson61dedf22017-07-18 10:02:50 -1000485 CHECK_FPSCR_PR_0
Aurelien Jarno7a642442012-09-16 13:12:21 +0200486 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700487 ctx->base.is_jmp = DISAS_STOP;
bellardfdf9b3e2006-04-27 21:07:38 +0000488 return;
Richard Henderson907759f2017-07-18 10:02:49 -1000489 case 0xf7fd: /* fpchg */
490 CHECK_SH4A
491 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_PR);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700492 ctx->base.is_jmp = DISAS_STOP;
Richard Henderson907759f2017-07-18 10:02:49 -1000493 return;
bellardfdf9b3e2006-04-27 21:07:38 +0000494 case 0x0009: /* nop */
495 return;
496 case 0x001b: /* sleep */
aurel32fe255912008-09-15 08:49:15 +0000497 CHECK_PRIVILEGED
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700498 tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next + 2);
Aurelien Jarno10127402012-09-16 13:12:21 +0200499 gen_helper_sleep(cpu_env);
bellardfdf9b3e2006-04-27 21:07:38 +0000500 return;
501 }
502
503 switch (ctx->opcode & 0xf000) {
504 case 0x1000: /* mov.l Rm,@(disp,Rn) */
aurel32c55497e2008-09-01 13:09:21 +0000505 {
pbrooka7812ae2008-11-17 14:43:54 +0000506 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000507 tcg_gen_addi_i32(addr, REG(B11_8), B3_0 * 4);
Aurelien Jarno3376f412013-12-11 07:56:47 +0100508 tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL);
aurel32c55497e2008-09-01 13:09:21 +0000509 tcg_temp_free(addr);
510 }
bellardfdf9b3e2006-04-27 21:07:38 +0000511 return;
512 case 0x5000: /* mov.l @(disp,Rm),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000513 {
pbrooka7812ae2008-11-17 14:43:54 +0000514 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000515 tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 4);
Aurelien Jarno3376f412013-12-11 07:56:47 +0100516 tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
aurel32c55497e2008-09-01 13:09:21 +0000517 tcg_temp_free(addr);
518 }
bellardfdf9b3e2006-04-27 21:07:38 +0000519 return;
aurel3224988dc2008-03-11 23:22:37 +0000520 case 0xe000: /* mov #imm,Rn */
Richard Henderson4bfa6022017-07-18 10:02:31 -1000521#ifdef CONFIG_USER_ONLY
522 /* Detect the start of a gUSA region. If so, update envflags
523 and end the TB. This will allow us to see the end of the
524 region (stored in R0) in the next TB. */
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700525 if (B11_8 == 15 && B7_0s < 0 &&
526 (tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
Richard Henderson4bfa6022017-07-18 10:02:31 -1000527 ctx->envflags = deposit32(ctx->envflags, GUSA_SHIFT, 8, B7_0s);
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700528 ctx->base.is_jmp = DISAS_STOP;
Richard Henderson4bfa6022017-07-18 10:02:31 -1000529 }
530#endif
aurel327efbe242008-09-01 13:09:14 +0000531 tcg_gen_movi_i32(REG(B11_8), B7_0s);
bellardfdf9b3e2006-04-27 21:07:38 +0000532 return;
533 case 0x9000: /* mov.w @(disp,PC),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000534 {
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700535 TCGv addr = tcg_const_i32(ctx->base.pc_next + 4 + B7_0 * 2);
Aurelien Jarno3376f412013-12-11 07:56:47 +0100536 tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW);
aurel32c55497e2008-09-01 13:09:21 +0000537 tcg_temp_free(addr);
538 }
bellardfdf9b3e2006-04-27 21:07:38 +0000539 return;
540 case 0xd000: /* mov.l @(disp,PC),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000541 {
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700542 TCGv addr = tcg_const_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3);
Aurelien Jarno3376f412013-12-11 07:56:47 +0100543 tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
aurel32c55497e2008-09-01 13:09:21 +0000544 tcg_temp_free(addr);
545 }
bellardfdf9b3e2006-04-27 21:07:38 +0000546 return;
aurel3224988dc2008-03-11 23:22:37 +0000547 case 0x7000: /* add #imm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000548 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), B7_0s);
bellardfdf9b3e2006-04-27 21:07:38 +0000549 return;
550 case 0xa000: /* bra disp */
551 CHECK_NOT_DELAY_SLOT
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700552 ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2;
Aurelien Jarnoa6215742017-05-01 23:20:43 +0200553 ctx->envflags |= DELAY_SLOT;
bellardfdf9b3e2006-04-27 21:07:38 +0000554 return;
555 case 0xb000: /* bsr disp */
556 CHECK_NOT_DELAY_SLOT
Richard Henderson6f1c2af2017-09-07 11:50:56 -0700557 tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
558 ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2;
Aurelien Jarnoa6215742017-05-01 23:20:43 +0200559 ctx->envflags |= DELAY_SLOT;
bellardfdf9b3e2006-04-27 21:07:38 +0000560 return;
561 }
562
563 switch (ctx->opcode & 0xf00f) {
564 case 0x6003: /* mov Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000565 tcg_gen_mov_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000566 return;
567 case 0x2000: /* mov.b Rm,@Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100568 tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_UB);
bellardfdf9b3e2006-04-27 21:07:38 +0000569 return;
570 case 0x2001: /* mov.w Rm,@Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100571 tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_TEUW);
bellardfdf9b3e2006-04-27 21:07:38 +0000572 return;
573 case 0x2002: /* mov.l Rm,@Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100574 tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_TEUL);
bellardfdf9b3e2006-04-27 21:07:38 +0000575 return;
576 case 0x6000: /* mov.b @Rm,Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100577 tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_SB);
bellardfdf9b3e2006-04-27 21:07:38 +0000578 return;
579 case 0x6001: /* mov.w @Rm,Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100580 tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESW);
bellardfdf9b3e2006-04-27 21:07:38 +0000581 return;
582 case 0x6002: /* mov.l @Rm,Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100583 tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESL);
bellardfdf9b3e2006-04-27 21:07:38 +0000584 return;
585 case 0x2004: /* mov.b Rm,@-Rn */
aurel32c55497e2008-09-01 13:09:21 +0000586 {
pbrooka7812ae2008-11-17 14:43:54 +0000587 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000588 tcg_gen_subi_i32(addr, REG(B11_8), 1);
Aurelien Jarno3376f412013-12-11 07:56:47 +0100589 /* might cause re-execution */
590 tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_UB);
Aurelien Jarno3101e992010-01-31 01:07:25 +0100591 tcg_gen_mov_i32(REG(B11_8), addr); /* modify register status */
aurel32c55497e2008-09-01 13:09:21 +0000592 tcg_temp_free(addr);
593 }
bellardfdf9b3e2006-04-27 21:07:38 +0000594 return;
595 case 0x2005: /* mov.w Rm,@-Rn */
aurel32c55497e2008-09-01 13:09:21 +0000596 {
pbrooka7812ae2008-11-17 14:43:54 +0000597 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000598 tcg_gen_subi_i32(addr, REG(B11_8), 2);
Aurelien Jarno3376f412013-12-11 07:56:47 +0100599 tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUW);
Aurelien Jarno3101e992010-01-31 01:07:25 +0100600 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32c55497e2008-09-01 13:09:21 +0000601 tcg_temp_free(addr);
602 }
bellardfdf9b3e2006-04-27 21:07:38 +0000603 return;
604 case 0x2006: /* mov.l Rm,@-Rn */
aurel32c55497e2008-09-01 13:09:21 +0000605 {
pbrooka7812ae2008-11-17 14:43:54 +0000606 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000607 tcg_gen_subi_i32(addr, REG(B11_8), 4);
Aurelien Jarno3376f412013-12-11 07:56:47 +0100608 tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL);
Aurelien Jarno3101e992010-01-31 01:07:25 +0100609 tcg_gen_mov_i32(REG(B11_8), addr);
Philippe Mathieu-Daudée691e0e2017-12-05 14:00:13 -0300610 tcg_temp_free(addr);
aurel32c55497e2008-09-01 13:09:21 +0000611 }
bellardfdf9b3e2006-04-27 21:07:38 +0000612 return;
bellardeda9b092006-06-14 15:02:05 +0000613 case 0x6004: /* mov.b @Rm+,Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100614 tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_SB);
aurel3224988dc2008-03-11 23:22:37 +0000615 if ( B11_8 != B7_4 )
aurel327efbe242008-09-01 13:09:14 +0000616 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 1);
bellardfdf9b3e2006-04-27 21:07:38 +0000617 return;
618 case 0x6005: /* mov.w @Rm+,Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100619 tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESW);
aurel3224988dc2008-03-11 23:22:37 +0000620 if ( B11_8 != B7_4 )
aurel327efbe242008-09-01 13:09:14 +0000621 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
bellardfdf9b3e2006-04-27 21:07:38 +0000622 return;
623 case 0x6006: /* mov.l @Rm+,Rn */
Aurelien Jarno3376f412013-12-11 07:56:47 +0100624 tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESL);
aurel3224988dc2008-03-11 23:22:37 +0000625 if ( B11_8 != B7_4 )
aurel327efbe242008-09-01 13:09:14 +0000626 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
bellardfdf9b3e2006-04-27 21:07:38 +0000627 return;
628 case 0x0004: /* mov.b Rm,@(R0,Rn) */
aurel32c55497e2008-09-01 13:09:21 +0000629 {
pbrooka7812ae2008-11-17 14:43:54 +0000630 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000631 tcg_gen_add_i32(addr, REG(B11_8), REG(0));
Aurelien Jarno3376f412013-12-11 07:56:47 +0100632 tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +0000633 tcg_temp_free(addr);
634 }
bellardfdf9b3e2006-04-27 21:07:38 +0000635 return;
636 case 0x0005: /* mov.w Rm,@(R0,Rn) */
aurel32c55497e2008-09-01 13:09:21 +0000637 {
pbrooka7812ae2008-11-17 14:43:54 +0000638 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000639 tcg_gen_add_i32(addr, REG(B11_8), REG(0));
Aurelien Jarno3376f412013-12-11 07:56:47 +0100640 tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUW);
aurel32c55497e2008-09-01 13:09:21 +0000641 tcg_temp_free(addr);
642 }
bellardfdf9b3e2006-04-27 21:07:38 +0000643 return;
644 case 0x0006: /* mov.l Rm,@(R0,Rn) */
aurel32c55497e2008-09-01 13:09:21 +0000645 {
pbrooka7812ae2008-11-17 14:43:54 +0000646 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000647 tcg_gen_add_i32(addr, REG(B11_8), REG(0));
Aurelien Jarno3376f412013-12-11 07:56:47 +0100648 tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL);
aurel32c55497e2008-09-01 13:09:21 +0000649 tcg_temp_free(addr);
650 }
bellardfdf9b3e2006-04-27 21:07:38 +0000651 return;
652 case 0x000c: /* mov.b @(R0,Rm),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000653 {
pbrooka7812ae2008-11-17 14:43:54 +0000654 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000655 tcg_gen_add_i32(addr, REG(B7_4), REG(0));
Aurelien Jarno3376f412013-12-11 07:56:47 +0100656 tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_SB);
aurel32c55497e2008-09-01 13:09:21 +0000657 tcg_temp_free(addr);
658 }
bellardfdf9b3e2006-04-27 21:07:38 +0000659 return;
660 case 0x000d: /* mov.w @(R0,Rm),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000661 {
pbrooka7812ae2008-11-17 14:43:54 +0000662 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000663 tcg_gen_add_i32(addr, REG(B7_4), REG(0));
Aurelien Jarno3376f412013-12-11 07:56:47 +0100664 tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW);
aurel32c55497e2008-09-01 13:09:21 +0000665 tcg_temp_free(addr);
666 }
bellardfdf9b3e2006-04-27 21:07:38 +0000667 return;
668 case 0x000e: /* mov.l @(R0,Rm),Rn */
aurel32c55497e2008-09-01 13:09:21 +0000669 {
pbrooka7812ae2008-11-17 14:43:54 +0000670 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000671 tcg_gen_add_i32(addr, REG(B7_4), REG(0));
Aurelien Jarno3376f412013-12-11 07:56:47 +0100672 tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
aurel32c55497e2008-09-01 13:09:21 +0000673 tcg_temp_free(addr);
674 }
bellardfdf9b3e2006-04-27 21:07:38 +0000675 return;
676 case 0x6008: /* swap.b Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000677 {
Ladi Prosek3c254ab2017-10-17 16:40:51 +0200678 TCGv low = tcg_temp_new();
Aurelien Jarno3101e992010-01-31 01:07:25 +0100679 tcg_gen_ext16u_i32(low, REG(B7_4));
680 tcg_gen_bswap16_i32(low, low);
Aurelien Jarno218fd732015-07-05 17:05:08 +0200681 tcg_gen_deposit_i32(REG(B11_8), REG(B7_4), low, 0, 16);
aurel32c55497e2008-09-01 13:09:21 +0000682 tcg_temp_free(low);
aurel32c55497e2008-09-01 13:09:21 +0000683 }
bellardfdf9b3e2006-04-27 21:07:38 +0000684 return;
685 case 0x6009: /* swap.w Rm,Rn */
Aurelien Jarnoc53b36d2012-09-16 13:12:20 +0200686 tcg_gen_rotli_i32(REG(B11_8), REG(B7_4), 16);
bellardfdf9b3e2006-04-27 21:07:38 +0000687 return;
688 case 0x200d: /* xtrct Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000689 {
690 TCGv high, low;
pbrooka7812ae2008-11-17 14:43:54 +0000691 high = tcg_temp_new();
Aurelien Jarno3101e992010-01-31 01:07:25 +0100692 tcg_gen_shli_i32(high, REG(B7_4), 16);
pbrooka7812ae2008-11-17 14:43:54 +0000693 low = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000694 tcg_gen_shri_i32(low, REG(B11_8), 16);
aurel32c55497e2008-09-01 13:09:21 +0000695 tcg_gen_or_i32(REG(B11_8), high, low);
696 tcg_temp_free(low);
697 tcg_temp_free(high);
698 }
bellardfdf9b3e2006-04-27 21:07:38 +0000699 return;
700 case 0x300c: /* add Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000701 tcg_gen_add_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000702 return;
703 case 0x300e: /* addc Rm,Rn */
Aurelien Jarno22b88fd2012-09-16 13:12:20 +0200704 {
Aurelien Jarno34086942015-05-25 01:28:56 +0200705 TCGv t0, t1;
Aurelien Jarnoa2368e02015-05-25 01:28:56 +0200706 t0 = tcg_const_tl(0);
Aurelien Jarno22b88fd2012-09-16 13:12:20 +0200707 t1 = tcg_temp_new();
Aurelien Jarnoa2368e02015-05-25 01:28:56 +0200708 tcg_gen_add2_i32(t1, cpu_sr_t, cpu_sr_t, t0, REG(B7_4), t0);
709 tcg_gen_add2_i32(REG(B11_8), cpu_sr_t,
710 REG(B11_8), t0, t1, cpu_sr_t);
Aurelien Jarno22b88fd2012-09-16 13:12:20 +0200711 tcg_temp_free(t0);
Aurelien Jarno34086942015-05-25 01:28:56 +0200712 tcg_temp_free(t1);
Aurelien Jarno22b88fd2012-09-16 13:12:20 +0200713 }
bellardfdf9b3e2006-04-27 21:07:38 +0000714 return;
715 case 0x300f: /* addv Rm,Rn */
Aurelien Jarnoad8d25a2012-09-16 13:12:20 +0200716 {
717 TCGv t0, t1, t2;
718 t0 = tcg_temp_new();
719 tcg_gen_add_i32(t0, REG(B7_4), REG(B11_8));
720 t1 = tcg_temp_new();
721 tcg_gen_xor_i32(t1, t0, REG(B11_8));
722 t2 = tcg_temp_new();
723 tcg_gen_xor_i32(t2, REG(B7_4), REG(B11_8));
Aurelien Jarno34086942015-05-25 01:28:56 +0200724 tcg_gen_andc_i32(cpu_sr_t, t1, t2);
Aurelien Jarnoad8d25a2012-09-16 13:12:20 +0200725 tcg_temp_free(t2);
Aurelien Jarno34086942015-05-25 01:28:56 +0200726 tcg_gen_shri_i32(cpu_sr_t, cpu_sr_t, 31);
Aurelien Jarnoad8d25a2012-09-16 13:12:20 +0200727 tcg_temp_free(t1);
728 tcg_gen_mov_i32(REG(B7_4), t0);
729 tcg_temp_free(t0);
730 }
bellardfdf9b3e2006-04-27 21:07:38 +0000731 return;
732 case 0x2009: /* and Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000733 tcg_gen_and_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000734 return;
735 case 0x3000: /* cmp/eq Rm,Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +0200736 tcg_gen_setcond_i32(TCG_COND_EQ, cpu_sr_t, REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000737 return;
738 case 0x3003: /* cmp/ge Rm,Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +0200739 tcg_gen_setcond_i32(TCG_COND_GE, cpu_sr_t, REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000740 return;
741 case 0x3007: /* cmp/gt Rm,Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +0200742 tcg_gen_setcond_i32(TCG_COND_GT, cpu_sr_t, REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000743 return;
744 case 0x3006: /* cmp/hi Rm,Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +0200745 tcg_gen_setcond_i32(TCG_COND_GTU, cpu_sr_t, REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000746 return;
747 case 0x3002: /* cmp/hs Rm,Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +0200748 tcg_gen_setcond_i32(TCG_COND_GEU, cpu_sr_t, REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000749 return;
750 case 0x200c: /* cmp/str Rm,Rn */
aurel3269d62752008-09-01 13:09:06 +0000751 {
Aurelien Jarnoc5c19132011-01-14 20:39:18 +0100752 TCGv cmp1 = tcg_temp_new();
753 TCGv cmp2 = tcg_temp_new();
Aurelien Jarnoeb6ca2b2015-07-05 18:50:09 +0200754 tcg_gen_xor_i32(cmp2, REG(B7_4), REG(B11_8));
755 tcg_gen_subi_i32(cmp1, cmp2, 0x01010101);
756 tcg_gen_andc_i32(cmp1, cmp1, cmp2);
757 tcg_gen_andi_i32(cmp1, cmp1, 0x80808080);
758 tcg_gen_setcondi_i32(TCG_COND_NE, cpu_sr_t, cmp1, 0);
aurel32c55497e2008-09-01 13:09:21 +0000759 tcg_temp_free(cmp2);
760 tcg_temp_free(cmp1);
aurel3269d62752008-09-01 13:09:06 +0000761 }
bellardfdf9b3e2006-04-27 21:07:38 +0000762 return;
763 case 0x2007: /* div0s Rm,Rn */
Aurelien Jarno1d565b22015-05-25 01:28:56 +0200764 tcg_gen_shri_i32(cpu_sr_q, REG(B11_8), 31); /* SR_Q */
765 tcg_gen_shri_i32(cpu_sr_m, REG(B7_4), 31); /* SR_M */
766 tcg_gen_xor_i32(cpu_sr_t, cpu_sr_q, cpu_sr_m); /* SR_T */
bellardfdf9b3e2006-04-27 21:07:38 +0000767 return;
768 case 0x3004: /* div1 Rm,Rn */
Aurelien Jarno1d565b22015-05-25 01:28:56 +0200769 {
770 TCGv t0 = tcg_temp_new();
771 TCGv t1 = tcg_temp_new();
772 TCGv t2 = tcg_temp_new();
773 TCGv zero = tcg_const_i32(0);
774
775 /* shift left arg1, saving the bit being pushed out and inserting
776 T on the right */
777 tcg_gen_shri_i32(t0, REG(B11_8), 31);
778 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1);
779 tcg_gen_or_i32(REG(B11_8), REG(B11_8), cpu_sr_t);
780
781 /* Add or subtract arg0 from arg1 depending if Q == M. To avoid
782 using 64-bit temps, we compute arg0's high part from q ^ m, so
783 that it is 0x00000000 when adding the value or 0xffffffff when
784 subtracting it. */
785 tcg_gen_xor_i32(t1, cpu_sr_q, cpu_sr_m);
786 tcg_gen_subi_i32(t1, t1, 1);
787 tcg_gen_neg_i32(t2, REG(B7_4));
788 tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, zero, REG(B7_4), t2);
789 tcg_gen_add2_i32(REG(B11_8), t1, REG(B11_8), zero, t2, t1);
790
791 /* compute T and Q depending on carry */
792 tcg_gen_andi_i32(t1, t1, 1);
793 tcg_gen_xor_i32(t1, t1, t0);
794 tcg_gen_xori_i32(cpu_sr_t, t1, 1);
795 tcg_gen_xor_i32(cpu_sr_q, cpu_sr_m, t1);
796
797 tcg_temp_free(zero);
798 tcg_temp_free(t2);
799 tcg_temp_free(t1);
800 tcg_temp_free(t0);
801 }
bellardfdf9b3e2006-04-27 21:07:38 +0000802 return;
803 case 0x300d: /* dmuls.l Rm,Rn */
Richard Henderson1d3b7082013-02-19 23:52:23 -0800804 tcg_gen_muls2_i32(cpu_macl, cpu_mach, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000805 return;
806 case 0x3005: /* dmulu.l Rm,Rn */
Richard Henderson1d3b7082013-02-19 23:52:23 -0800807 tcg_gen_mulu2_i32(cpu_macl, cpu_mach, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000808 return;
809 case 0x600e: /* exts.b Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000810 tcg_gen_ext8s_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000811 return;
812 case 0x600f: /* exts.w Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000813 tcg_gen_ext16s_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000814 return;
815 case 0x600c: /* extu.b Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000816 tcg_gen_ext8u_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000817 return;
818 case 0x600d: /* extu.w Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000819 tcg_gen_ext16u_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000820 return;
aurel3224988dc2008-03-11 23:22:37 +0000821 case 0x000f: /* mac.l @Rm+,@Rn+ */
aurel32c55497e2008-09-01 13:09:21 +0000822 {
823 TCGv arg0, arg1;
pbrooka7812ae2008-11-17 14:43:54 +0000824 arg0 = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +0100825 tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx, MO_TESL);
pbrooka7812ae2008-11-17 14:43:54 +0000826 arg1 = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +0100827 tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx, MO_TESL);
Blue Swirl485d0032012-09-02 10:37:06 +0000828 gen_helper_macl(cpu_env, arg0, arg1);
aurel32c55497e2008-09-01 13:09:21 +0000829 tcg_temp_free(arg1);
830 tcg_temp_free(arg0);
831 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
832 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
833 }
bellardfdf9b3e2006-04-27 21:07:38 +0000834 return;
835 case 0x400f: /* mac.w @Rm+,@Rn+ */
aurel32c55497e2008-09-01 13:09:21 +0000836 {
837 TCGv arg0, arg1;
pbrooka7812ae2008-11-17 14:43:54 +0000838 arg0 = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +0100839 tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx, MO_TESL);
pbrooka7812ae2008-11-17 14:43:54 +0000840 arg1 = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +0100841 tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx, MO_TESL);
Blue Swirl485d0032012-09-02 10:37:06 +0000842 gen_helper_macw(cpu_env, arg0, arg1);
aurel32c55497e2008-09-01 13:09:21 +0000843 tcg_temp_free(arg1);
844 tcg_temp_free(arg0);
845 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2);
846 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
847 }
bellardfdf9b3e2006-04-27 21:07:38 +0000848 return;
849 case 0x0007: /* mul.l Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000850 tcg_gen_mul_i32(cpu_macl, REG(B7_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +0000851 return;
852 case 0x200f: /* muls.w Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000853 {
854 TCGv arg0, arg1;
pbrooka7812ae2008-11-17 14:43:54 +0000855 arg0 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000856 tcg_gen_ext16s_i32(arg0, REG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +0000857 arg1 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000858 tcg_gen_ext16s_i32(arg1, REG(B11_8));
859 tcg_gen_mul_i32(cpu_macl, arg0, arg1);
860 tcg_temp_free(arg1);
861 tcg_temp_free(arg0);
862 }
bellardfdf9b3e2006-04-27 21:07:38 +0000863 return;
864 case 0x200e: /* mulu.w Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000865 {
866 TCGv arg0, arg1;
pbrooka7812ae2008-11-17 14:43:54 +0000867 arg0 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000868 tcg_gen_ext16u_i32(arg0, REG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +0000869 arg1 = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000870 tcg_gen_ext16u_i32(arg1, REG(B11_8));
871 tcg_gen_mul_i32(cpu_macl, arg0, arg1);
872 tcg_temp_free(arg1);
873 tcg_temp_free(arg0);
874 }
bellardfdf9b3e2006-04-27 21:07:38 +0000875 return;
876 case 0x600b: /* neg Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000877 tcg_gen_neg_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000878 return;
879 case 0x600a: /* negc Rm,Rn */
Aurelien Jarnob2d9eda2011-01-13 08:20:39 +0100880 {
Aurelien Jarno60eb27f2015-05-25 01:28:56 +0200881 TCGv t0 = tcg_const_i32(0);
882 tcg_gen_add2_i32(REG(B11_8), cpu_sr_t,
883 REG(B7_4), t0, cpu_sr_t, t0);
884 tcg_gen_sub2_i32(REG(B11_8), cpu_sr_t,
885 t0, t0, REG(B11_8), cpu_sr_t);
886 tcg_gen_andi_i32(cpu_sr_t, cpu_sr_t, 1);
Aurelien Jarnob2d9eda2011-01-13 08:20:39 +0100887 tcg_temp_free(t0);
Aurelien Jarnob2d9eda2011-01-13 08:20:39 +0100888 }
bellardfdf9b3e2006-04-27 21:07:38 +0000889 return;
890 case 0x6007: /* not Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000891 tcg_gen_not_i32(REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000892 return;
893 case 0x200b: /* or Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000894 tcg_gen_or_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000895 return;
896 case 0x400c: /* shad Rm,Rn */
aurel3269d62752008-09-01 13:09:06 +0000897 {
Aurelien Jarnobe654c82015-07-05 22:39:03 +0200898 TCGv t0 = tcg_temp_new();
899 TCGv t1 = tcg_temp_new();
900 TCGv t2 = tcg_temp_new();
901
902 tcg_gen_andi_i32(t0, REG(B7_4), 0x1f);
903
904 /* positive case: shift to the left */
905 tcg_gen_shl_i32(t1, REG(B11_8), t0);
906
907 /* negative case: shift to the right in two steps to
908 correctly handle the -32 case */
909 tcg_gen_xori_i32(t0, t0, 0x1f);
910 tcg_gen_sar_i32(t2, REG(B11_8), t0);
911 tcg_gen_sari_i32(t2, t2, 1);
912
913 /* select between the two cases */
914 tcg_gen_movi_i32(t0, 0);
915 tcg_gen_movcond_i32(TCG_COND_GE, REG(B11_8), REG(B7_4), t0, t1, t2);
916
917 tcg_temp_free(t0);
918 tcg_temp_free(t1);
919 tcg_temp_free(t2);
aurel3269d62752008-09-01 13:09:06 +0000920 }
bellardfdf9b3e2006-04-27 21:07:38 +0000921 return;
922 case 0x400d: /* shld Rm,Rn */
aurel3269d62752008-09-01 13:09:06 +0000923 {
Aurelien Jarno57760162015-07-05 22:37:18 +0200924 TCGv t0 = tcg_temp_new();
925 TCGv t1 = tcg_temp_new();
926 TCGv t2 = tcg_temp_new();
927
928 tcg_gen_andi_i32(t0, REG(B7_4), 0x1f);
929
930 /* positive case: shift to the left */
931 tcg_gen_shl_i32(t1, REG(B11_8), t0);
932
933 /* negative case: shift to the right in two steps to
934 correctly handle the -32 case */
935 tcg_gen_xori_i32(t0, t0, 0x1f);
936 tcg_gen_shr_i32(t2, REG(B11_8), t0);
937 tcg_gen_shri_i32(t2, t2, 1);
938
939 /* select between the two cases */
940 tcg_gen_movi_i32(t0, 0);
941 tcg_gen_movcond_i32(TCG_COND_GE, REG(B11_8), REG(B7_4), t0, t1, t2);
942
943 tcg_temp_free(t0);
944 tcg_temp_free(t1);
945 tcg_temp_free(t2);
aurel3269d62752008-09-01 13:09:06 +0000946 }
bellardfdf9b3e2006-04-27 21:07:38 +0000947 return;
948 case 0x3008: /* sub Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000949 tcg_gen_sub_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000950 return;
951 case 0x300a: /* subc Rm,Rn */
Aurelien Jarno22b88fd2012-09-16 13:12:20 +0200952 {
Aurelien Jarnod0f44a52015-05-25 01:28:56 +0200953 TCGv t0, t1;
954 t0 = tcg_const_tl(0);
Aurelien Jarno22b88fd2012-09-16 13:12:20 +0200955 t1 = tcg_temp_new();
Aurelien Jarnod0f44a52015-05-25 01:28:56 +0200956 tcg_gen_add2_i32(t1, cpu_sr_t, cpu_sr_t, t0, REG(B7_4), t0);
957 tcg_gen_sub2_i32(REG(B11_8), cpu_sr_t,
958 REG(B11_8), t0, t1, cpu_sr_t);
959 tcg_gen_andi_i32(cpu_sr_t, cpu_sr_t, 1);
Aurelien Jarno22b88fd2012-09-16 13:12:20 +0200960 tcg_temp_free(t0);
Aurelien Jarnod0f44a52015-05-25 01:28:56 +0200961 tcg_temp_free(t1);
Aurelien Jarno22b88fd2012-09-16 13:12:20 +0200962 }
bellardfdf9b3e2006-04-27 21:07:38 +0000963 return;
964 case 0x300b: /* subv Rm,Rn */
Aurelien Jarnoad8d25a2012-09-16 13:12:20 +0200965 {
966 TCGv t0, t1, t2;
967 t0 = tcg_temp_new();
968 tcg_gen_sub_i32(t0, REG(B11_8), REG(B7_4));
969 t1 = tcg_temp_new();
970 tcg_gen_xor_i32(t1, t0, REG(B7_4));
971 t2 = tcg_temp_new();
972 tcg_gen_xor_i32(t2, REG(B11_8), REG(B7_4));
973 tcg_gen_and_i32(t1, t1, t2);
974 tcg_temp_free(t2);
Aurelien Jarno34086942015-05-25 01:28:56 +0200975 tcg_gen_shri_i32(cpu_sr_t, t1, 31);
Aurelien Jarnoad8d25a2012-09-16 13:12:20 +0200976 tcg_temp_free(t1);
977 tcg_gen_mov_i32(REG(B11_8), t0);
978 tcg_temp_free(t0);
979 }
bellardfdf9b3e2006-04-27 21:07:38 +0000980 return;
981 case 0x2008: /* tst Rm,Rn */
aurel32c55497e2008-09-01 13:09:21 +0000982 {
pbrooka7812ae2008-11-17 14:43:54 +0000983 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +0000984 tcg_gen_and_i32(val, REG(B7_4), REG(B11_8));
Aurelien Jarno34086942015-05-25 01:28:56 +0200985 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0);
aurel32c55497e2008-09-01 13:09:21 +0000986 tcg_temp_free(val);
987 }
bellardfdf9b3e2006-04-27 21:07:38 +0000988 return;
989 case 0x200a: /* xor Rm,Rn */
aurel327efbe242008-09-01 13:09:14 +0000990 tcg_gen_xor_i32(REG(B11_8), REG(B11_8), REG(B7_4));
bellardfdf9b3e2006-04-27 21:07:38 +0000991 return;
thse67888a2007-06-22 11:44:41 +0000992 case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +0000993 CHECK_FPU_ENABLED
Aurelien Jarnoa6215742017-05-01 23:20:43 +0200994 if (ctx->tbflags & FPSCR_SZ) {
Richard Hendersonbdcb3732017-07-18 10:02:42 -1000995 int xsrc = XHACK(B7_4);
996 int xdst = XHACK(B11_8);
997 tcg_gen_mov_i32(FREG(xdst), FREG(xsrc));
998 tcg_gen_mov_i32(FREG(xdst + 1), FREG(xsrc + 1));
bellardeda9b092006-06-14 15:02:05 +0000999 } else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001000 tcg_gen_mov_i32(FREG(B11_8), FREG(B7_4));
bellardeda9b092006-06-14 15:02:05 +00001001 }
1002 return;
thse67888a2007-06-22 11:44:41 +00001003 case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001004 CHECK_FPU_ENABLED
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001005 if (ctx->tbflags & FPSCR_SZ) {
Richard Henderson4d57fa52017-07-18 10:02:41 -10001006 TCGv_i64 fp = tcg_temp_new_i64();
1007 gen_load_fpr64(ctx, fp, XHACK(B7_4));
1008 tcg_gen_qemu_st_i64(fp, REG(B11_8), ctx->memidx, MO_TEQ);
1009 tcg_temp_free_i64(fp);
bellardeda9b092006-06-14 15:02:05 +00001010 } else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001011 tcg_gen_qemu_st_i32(FREG(B7_4), REG(B11_8), ctx->memidx, MO_TEUL);
bellardeda9b092006-06-14 15:02:05 +00001012 }
1013 return;
thse67888a2007-06-22 11:44:41 +00001014 case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001015 CHECK_FPU_ENABLED
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001016 if (ctx->tbflags & FPSCR_SZ) {
Richard Henderson4d57fa52017-07-18 10:02:41 -10001017 TCGv_i64 fp = tcg_temp_new_i64();
1018 tcg_gen_qemu_ld_i64(fp, REG(B7_4), ctx->memidx, MO_TEQ);
1019 gen_store_fpr64(ctx, fp, XHACK(B11_8));
1020 tcg_temp_free_i64(fp);
bellardeda9b092006-06-14 15:02:05 +00001021 } else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001022 tcg_gen_qemu_ld_i32(FREG(B11_8), REG(B7_4), ctx->memidx, MO_TEUL);
bellardeda9b092006-06-14 15:02:05 +00001023 }
1024 return;
thse67888a2007-06-22 11:44:41 +00001025 case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001026 CHECK_FPU_ENABLED
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001027 if (ctx->tbflags & FPSCR_SZ) {
Richard Henderson4d57fa52017-07-18 10:02:41 -10001028 TCGv_i64 fp = tcg_temp_new_i64();
1029 tcg_gen_qemu_ld_i64(fp, REG(B7_4), ctx->memidx, MO_TEQ);
1030 gen_store_fpr64(ctx, fp, XHACK(B11_8));
1031 tcg_temp_free_i64(fp);
1032 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 8);
bellardeda9b092006-06-14 15:02:05 +00001033 } else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001034 tcg_gen_qemu_ld_i32(FREG(B11_8), REG(B7_4), ctx->memidx, MO_TEUL);
aurel32cc4ba6a2008-09-01 22:11:56 +00001035 tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
bellardeda9b092006-06-14 15:02:05 +00001036 }
1037 return;
thse67888a2007-06-22 11:44:41 +00001038 case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001039 CHECK_FPU_ENABLED
Richard Henderson4d57fa52017-07-18 10:02:41 -10001040 {
1041 TCGv addr = tcg_temp_new_i32();
1042 if (ctx->tbflags & FPSCR_SZ) {
1043 TCGv_i64 fp = tcg_temp_new_i64();
1044 gen_load_fpr64(ctx, fp, XHACK(B7_4));
1045 tcg_gen_subi_i32(addr, REG(B11_8), 8);
1046 tcg_gen_qemu_st_i64(fp, addr, ctx->memidx, MO_TEQ);
1047 tcg_temp_free_i64(fp);
1048 } else {
1049 tcg_gen_subi_i32(addr, REG(B11_8), 4);
1050 tcg_gen_qemu_st_i32(FREG(B7_4), addr, ctx->memidx, MO_TEUL);
1051 }
1052 tcg_gen_mov_i32(REG(B11_8), addr);
1053 tcg_temp_free(addr);
1054 }
bellardeda9b092006-06-14 15:02:05 +00001055 return;
thse67888a2007-06-22 11:44:41 +00001056 case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001057 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001058 {
pbrooka7812ae2008-11-17 14:43:54 +00001059 TCGv addr = tcg_temp_new_i32();
aurel32cc4ba6a2008-09-01 22:11:56 +00001060 tcg_gen_add_i32(addr, REG(B7_4), REG(0));
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001061 if (ctx->tbflags & FPSCR_SZ) {
Richard Henderson4d57fa52017-07-18 10:02:41 -10001062 TCGv_i64 fp = tcg_temp_new_i64();
1063 tcg_gen_qemu_ld_i64(fp, addr, ctx->memidx, MO_TEQ);
1064 gen_store_fpr64(ctx, fp, XHACK(B11_8));
1065 tcg_temp_free_i64(fp);
aurel32cc4ba6a2008-09-01 22:11:56 +00001066 } else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001067 tcg_gen_qemu_ld_i32(FREG(B11_8), addr, ctx->memidx, MO_TEUL);
aurel32cc4ba6a2008-09-01 22:11:56 +00001068 }
1069 tcg_temp_free(addr);
bellardeda9b092006-06-14 15:02:05 +00001070 }
1071 return;
thse67888a2007-06-22 11:44:41 +00001072 case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001073 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001074 {
pbrooka7812ae2008-11-17 14:43:54 +00001075 TCGv addr = tcg_temp_new();
aurel32cc4ba6a2008-09-01 22:11:56 +00001076 tcg_gen_add_i32(addr, REG(B11_8), REG(0));
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001077 if (ctx->tbflags & FPSCR_SZ) {
Richard Henderson4d57fa52017-07-18 10:02:41 -10001078 TCGv_i64 fp = tcg_temp_new_i64();
1079 gen_load_fpr64(ctx, fp, XHACK(B7_4));
1080 tcg_gen_qemu_st_i64(fp, addr, ctx->memidx, MO_TEQ);
1081 tcg_temp_free_i64(fp);
aurel32cc4ba6a2008-09-01 22:11:56 +00001082 } else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001083 tcg_gen_qemu_st_i32(FREG(B7_4), addr, ctx->memidx, MO_TEUL);
aurel32cc4ba6a2008-09-01 22:11:56 +00001084 }
1085 tcg_temp_free(addr);
bellardeda9b092006-06-14 15:02:05 +00001086 }
1087 return;
thse67888a2007-06-22 11:44:41 +00001088 case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
1089 case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
1090 case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
1091 case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
1092 case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
1093 case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
aurel32cc4ba6a2008-09-01 22:11:56 +00001094 {
aurel32f6198372008-12-10 17:31:43 +00001095 CHECK_FPU_ENABLED
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001096 if (ctx->tbflags & FPSCR_PR) {
pbrooka7812ae2008-11-17 14:43:54 +00001097 TCGv_i64 fp0, fp1;
1098
Richard Henderson93dc9c82017-07-18 10:02:46 -10001099 if (ctx->opcode & 0x0110) {
1100 goto do_illegal;
1101 }
pbrooka7812ae2008-11-17 14:43:54 +00001102 fp0 = tcg_temp_new_i64();
1103 fp1 = tcg_temp_new_i64();
Richard Henderson1e0b21d2017-07-18 10:02:40 -10001104 gen_load_fpr64(ctx, fp0, B11_8);
1105 gen_load_fpr64(ctx, fp1, B7_4);
pbrooka7812ae2008-11-17 14:43:54 +00001106 switch (ctx->opcode & 0xf00f) {
1107 case 0xf000: /* fadd Rm,Rn */
Blue Swirl485d0032012-09-02 10:37:06 +00001108 gen_helper_fadd_DT(fp0, cpu_env, fp0, fp1);
pbrooka7812ae2008-11-17 14:43:54 +00001109 break;
1110 case 0xf001: /* fsub Rm,Rn */
Blue Swirl485d0032012-09-02 10:37:06 +00001111 gen_helper_fsub_DT(fp0, cpu_env, fp0, fp1);
pbrooka7812ae2008-11-17 14:43:54 +00001112 break;
1113 case 0xf002: /* fmul Rm,Rn */
Blue Swirl485d0032012-09-02 10:37:06 +00001114 gen_helper_fmul_DT(fp0, cpu_env, fp0, fp1);
pbrooka7812ae2008-11-17 14:43:54 +00001115 break;
1116 case 0xf003: /* fdiv Rm,Rn */
Blue Swirl485d0032012-09-02 10:37:06 +00001117 gen_helper_fdiv_DT(fp0, cpu_env, fp0, fp1);
pbrooka7812ae2008-11-17 14:43:54 +00001118 break;
1119 case 0xf004: /* fcmp/eq Rm,Rn */
Aurelien Jarno92f1f832017-07-02 21:31:25 +02001120 gen_helper_fcmp_eq_DT(cpu_sr_t, cpu_env, fp0, fp1);
pbrooka7812ae2008-11-17 14:43:54 +00001121 return;
1122 case 0xf005: /* fcmp/gt Rm,Rn */
Aurelien Jarno92f1f832017-07-02 21:31:25 +02001123 gen_helper_fcmp_gt_DT(cpu_sr_t, cpu_env, fp0, fp1);
pbrooka7812ae2008-11-17 14:43:54 +00001124 return;
1125 }
Richard Henderson1e0b21d2017-07-18 10:02:40 -10001126 gen_store_fpr64(ctx, fp0, B11_8);
pbrooka7812ae2008-11-17 14:43:54 +00001127 tcg_temp_free_i64(fp0);
1128 tcg_temp_free_i64(fp1);
1129 } else {
pbrooka7812ae2008-11-17 14:43:54 +00001130 switch (ctx->opcode & 0xf00f) {
1131 case 0xf000: /* fadd Rm,Rn */
Richard Henderson7c9f7032017-07-18 10:02:36 -10001132 gen_helper_fadd_FT(FREG(B11_8), cpu_env,
1133 FREG(B11_8), FREG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +00001134 break;
1135 case 0xf001: /* fsub Rm,Rn */
Richard Henderson7c9f7032017-07-18 10:02:36 -10001136 gen_helper_fsub_FT(FREG(B11_8), cpu_env,
1137 FREG(B11_8), FREG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +00001138 break;
1139 case 0xf002: /* fmul Rm,Rn */
Richard Henderson7c9f7032017-07-18 10:02:36 -10001140 gen_helper_fmul_FT(FREG(B11_8), cpu_env,
1141 FREG(B11_8), FREG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +00001142 break;
1143 case 0xf003: /* fdiv Rm,Rn */
Richard Henderson7c9f7032017-07-18 10:02:36 -10001144 gen_helper_fdiv_FT(FREG(B11_8), cpu_env,
1145 FREG(B11_8), FREG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +00001146 break;
1147 case 0xf004: /* fcmp/eq Rm,Rn */
Aurelien Jarno92f1f832017-07-02 21:31:25 +02001148 gen_helper_fcmp_eq_FT(cpu_sr_t, cpu_env,
Richard Henderson7c9f7032017-07-18 10:02:36 -10001149 FREG(B11_8), FREG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +00001150 return;
1151 case 0xf005: /* fcmp/gt Rm,Rn */
Aurelien Jarno92f1f832017-07-02 21:31:25 +02001152 gen_helper_fcmp_gt_FT(cpu_sr_t, cpu_env,
Richard Henderson7c9f7032017-07-18 10:02:36 -10001153 FREG(B11_8), FREG(B7_4));
pbrooka7812ae2008-11-17 14:43:54 +00001154 return;
1155 }
aurel32cc4ba6a2008-09-01 22:11:56 +00001156 }
thsea6cf6b2007-06-22 11:12:01 +00001157 }
1158 return;
aurel325b7141a2009-01-14 21:02:59 +00001159 case 0xf00e: /* fmac FR0,RM,Rn */
Richard Henderson7e9f7ca2017-07-18 10:02:47 -10001160 CHECK_FPU_ENABLED
1161 CHECK_FPSCR_PR_0
1162 gen_helper_fmac_FT(FREG(B11_8), cpu_env,
1163 FREG(0), FREG(B7_4), FREG(B11_8));
1164 return;
bellardfdf9b3e2006-04-27 21:07:38 +00001165 }
1166
1167 switch (ctx->opcode & 0xff00) {
1168 case 0xc900: /* and #imm,R0 */
aurel327efbe242008-09-01 13:09:14 +00001169 tcg_gen_andi_i32(REG(0), REG(0), B7_0);
bellardfdf9b3e2006-04-27 21:07:38 +00001170 return;
aurel3224988dc2008-03-11 23:22:37 +00001171 case 0xcd00: /* and.b #imm,@(R0,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001172 {
1173 TCGv addr, val;
pbrooka7812ae2008-11-17 14:43:54 +00001174 addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001175 tcg_gen_add_i32(addr, REG(0), cpu_gbr);
pbrooka7812ae2008-11-17 14:43:54 +00001176 val = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +01001177 tcg_gen_qemu_ld_i32(val, addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001178 tcg_gen_andi_i32(val, val, B7_0);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001179 tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001180 tcg_temp_free(val);
1181 tcg_temp_free(addr);
1182 }
bellardfdf9b3e2006-04-27 21:07:38 +00001183 return;
1184 case 0x8b00: /* bf label */
1185 CHECK_NOT_DELAY_SLOT
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001186 gen_conditional_jump(ctx, ctx->base.pc_next + 4 + B7_0s * 2, false);
bellardfdf9b3e2006-04-27 21:07:38 +00001187 return;
1188 case 0x8f00: /* bf/s label */
1189 CHECK_NOT_DELAY_SLOT
Aurelien Jarnoac9707e2017-05-01 23:20:43 +02001190 tcg_gen_xori_i32(cpu_delayed_cond, cpu_sr_t, 1);
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001191 ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2;
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001192 ctx->envflags |= DELAY_SLOT_CONDITIONAL;
bellardfdf9b3e2006-04-27 21:07:38 +00001193 return;
1194 case 0x8900: /* bt label */
1195 CHECK_NOT_DELAY_SLOT
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001196 gen_conditional_jump(ctx, ctx->base.pc_next + 4 + B7_0s * 2, true);
bellardfdf9b3e2006-04-27 21:07:38 +00001197 return;
1198 case 0x8d00: /* bt/s label */
1199 CHECK_NOT_DELAY_SLOT
Aurelien Jarnoac9707e2017-05-01 23:20:43 +02001200 tcg_gen_mov_i32(cpu_delayed_cond, cpu_sr_t);
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001201 ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2;
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001202 ctx->envflags |= DELAY_SLOT_CONDITIONAL;
bellardfdf9b3e2006-04-27 21:07:38 +00001203 return;
1204 case 0x8800: /* cmp/eq #imm,R0 */
Aurelien Jarno34086942015-05-25 01:28:56 +02001205 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, REG(0), B7_0s);
bellardfdf9b3e2006-04-27 21:07:38 +00001206 return;
1207 case 0xc400: /* mov.b @(disp,GBR),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001208 {
pbrooka7812ae2008-11-17 14:43:54 +00001209 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001210 tcg_gen_addi_i32(addr, cpu_gbr, B7_0);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001211 tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_SB);
aurel32c55497e2008-09-01 13:09:21 +00001212 tcg_temp_free(addr);
1213 }
bellardfdf9b3e2006-04-27 21:07:38 +00001214 return;
1215 case 0xc500: /* mov.w @(disp,GBR),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001216 {
pbrooka7812ae2008-11-17 14:43:54 +00001217 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001218 tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001219 tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_TESW);
aurel32c55497e2008-09-01 13:09:21 +00001220 tcg_temp_free(addr);
1221 }
bellardfdf9b3e2006-04-27 21:07:38 +00001222 return;
1223 case 0xc600: /* mov.l @(disp,GBR),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001224 {
pbrooka7812ae2008-11-17 14:43:54 +00001225 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001226 tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001227 tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_TESL);
aurel32c55497e2008-09-01 13:09:21 +00001228 tcg_temp_free(addr);
1229 }
bellardfdf9b3e2006-04-27 21:07:38 +00001230 return;
1231 case 0xc000: /* mov.b R0,@(disp,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001232 {
pbrooka7812ae2008-11-17 14:43:54 +00001233 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001234 tcg_gen_addi_i32(addr, cpu_gbr, B7_0);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001235 tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001236 tcg_temp_free(addr);
1237 }
bellardfdf9b3e2006-04-27 21:07:38 +00001238 return;
1239 case 0xc100: /* mov.w R0,@(disp,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001240 {
pbrooka7812ae2008-11-17 14:43:54 +00001241 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001242 tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 2);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001243 tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_TEUW);
aurel32c55497e2008-09-01 13:09:21 +00001244 tcg_temp_free(addr);
1245 }
bellardfdf9b3e2006-04-27 21:07:38 +00001246 return;
1247 case 0xc200: /* mov.l R0,@(disp,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001248 {
pbrooka7812ae2008-11-17 14:43:54 +00001249 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001250 tcg_gen_addi_i32(addr, cpu_gbr, B7_0 * 4);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001251 tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_TEUL);
aurel32c55497e2008-09-01 13:09:21 +00001252 tcg_temp_free(addr);
1253 }
bellardfdf9b3e2006-04-27 21:07:38 +00001254 return;
1255 case 0x8000: /* mov.b R0,@(disp,Rn) */
aurel32c55497e2008-09-01 13:09:21 +00001256 {
pbrooka7812ae2008-11-17 14:43:54 +00001257 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001258 tcg_gen_addi_i32(addr, REG(B7_4), B3_0);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001259 tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001260 tcg_temp_free(addr);
1261 }
bellardfdf9b3e2006-04-27 21:07:38 +00001262 return;
1263 case 0x8100: /* mov.w R0,@(disp,Rn) */
aurel32c55497e2008-09-01 13:09:21 +00001264 {
pbrooka7812ae2008-11-17 14:43:54 +00001265 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001266 tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001267 tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_TEUW);
aurel32c55497e2008-09-01 13:09:21 +00001268 tcg_temp_free(addr);
1269 }
bellardfdf9b3e2006-04-27 21:07:38 +00001270 return;
1271 case 0x8400: /* mov.b @(disp,Rn),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001272 {
pbrooka7812ae2008-11-17 14:43:54 +00001273 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001274 tcg_gen_addi_i32(addr, REG(B7_4), B3_0);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001275 tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_SB);
aurel32c55497e2008-09-01 13:09:21 +00001276 tcg_temp_free(addr);
1277 }
bellardfdf9b3e2006-04-27 21:07:38 +00001278 return;
1279 case 0x8500: /* mov.w @(disp,Rn),R0 */
aurel32c55497e2008-09-01 13:09:21 +00001280 {
pbrooka7812ae2008-11-17 14:43:54 +00001281 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001282 tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001283 tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_TESW);
aurel32c55497e2008-09-01 13:09:21 +00001284 tcg_temp_free(addr);
1285 }
bellardfdf9b3e2006-04-27 21:07:38 +00001286 return;
1287 case 0xc700: /* mova @(disp,PC),R0 */
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001288 tcg_gen_movi_i32(REG(0), ((ctx->base.pc_next & 0xfffffffc) +
1289 4 + B7_0 * 4) & ~3);
bellardfdf9b3e2006-04-27 21:07:38 +00001290 return;
1291 case 0xcb00: /* or #imm,R0 */
aurel327efbe242008-09-01 13:09:14 +00001292 tcg_gen_ori_i32(REG(0), REG(0), B7_0);
bellardfdf9b3e2006-04-27 21:07:38 +00001293 return;
aurel3224988dc2008-03-11 23:22:37 +00001294 case 0xcf00: /* or.b #imm,@(R0,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001295 {
1296 TCGv addr, val;
pbrooka7812ae2008-11-17 14:43:54 +00001297 addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001298 tcg_gen_add_i32(addr, REG(0), cpu_gbr);
pbrooka7812ae2008-11-17 14:43:54 +00001299 val = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +01001300 tcg_gen_qemu_ld_i32(val, addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001301 tcg_gen_ori_i32(val, val, B7_0);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001302 tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001303 tcg_temp_free(val);
1304 tcg_temp_free(addr);
1305 }
bellardfdf9b3e2006-04-27 21:07:38 +00001306 return;
1307 case 0xc300: /* trapa #imm */
aurel32c55497e2008-09-01 13:09:21 +00001308 {
1309 TCGv imm;
1310 CHECK_NOT_DELAY_SLOT
Aurelien Jarnoac9707e2017-05-01 23:20:43 +02001311 gen_save_cpu_state(ctx, true);
aurel32c55497e2008-09-01 13:09:21 +00001312 imm = tcg_const_i32(B7_0);
Blue Swirl485d0032012-09-02 10:37:06 +00001313 gen_helper_trapa(cpu_env, imm);
aurel32c55497e2008-09-01 13:09:21 +00001314 tcg_temp_free(imm);
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001315 ctx->base.is_jmp = DISAS_NORETURN;
aurel32c55497e2008-09-01 13:09:21 +00001316 }
bellardfdf9b3e2006-04-27 21:07:38 +00001317 return;
1318 case 0xc800: /* tst #imm,R0 */
aurel32c55497e2008-09-01 13:09:21 +00001319 {
pbrooka7812ae2008-11-17 14:43:54 +00001320 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001321 tcg_gen_andi_i32(val, REG(0), B7_0);
Aurelien Jarno34086942015-05-25 01:28:56 +02001322 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0);
aurel32c55497e2008-09-01 13:09:21 +00001323 tcg_temp_free(val);
1324 }
bellardfdf9b3e2006-04-27 21:07:38 +00001325 return;
aurel3224988dc2008-03-11 23:22:37 +00001326 case 0xcc00: /* tst.b #imm,@(R0,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001327 {
pbrooka7812ae2008-11-17 14:43:54 +00001328 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001329 tcg_gen_add_i32(val, REG(0), cpu_gbr);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001330 tcg_gen_qemu_ld_i32(val, val, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001331 tcg_gen_andi_i32(val, val, B7_0);
Aurelien Jarno34086942015-05-25 01:28:56 +02001332 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0);
aurel32c55497e2008-09-01 13:09:21 +00001333 tcg_temp_free(val);
1334 }
bellardfdf9b3e2006-04-27 21:07:38 +00001335 return;
1336 case 0xca00: /* xor #imm,R0 */
aurel327efbe242008-09-01 13:09:14 +00001337 tcg_gen_xori_i32(REG(0), REG(0), B7_0);
bellardfdf9b3e2006-04-27 21:07:38 +00001338 return;
aurel3224988dc2008-03-11 23:22:37 +00001339 case 0xce00: /* xor.b #imm,@(R0,GBR) */
aurel32c55497e2008-09-01 13:09:21 +00001340 {
1341 TCGv addr, val;
pbrooka7812ae2008-11-17 14:43:54 +00001342 addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001343 tcg_gen_add_i32(addr, REG(0), cpu_gbr);
pbrooka7812ae2008-11-17 14:43:54 +00001344 val = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +01001345 tcg_gen_qemu_ld_i32(val, addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001346 tcg_gen_xori_i32(val, val, B7_0);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001347 tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_UB);
aurel32c55497e2008-09-01 13:09:21 +00001348 tcg_temp_free(val);
1349 tcg_temp_free(addr);
1350 }
bellardfdf9b3e2006-04-27 21:07:38 +00001351 return;
1352 }
1353
1354 switch (ctx->opcode & 0xf08f) {
1355 case 0x408e: /* ldc Rm,Rn_BANK */
aurel32fe255912008-09-15 08:49:15 +00001356 CHECK_PRIVILEGED
aurel327efbe242008-09-01 13:09:14 +00001357 tcg_gen_mov_i32(ALTREG(B6_4), REG(B11_8));
bellardfdf9b3e2006-04-27 21:07:38 +00001358 return;
1359 case 0x4087: /* ldc.l @Rm+,Rn_BANK */
aurel32fe255912008-09-15 08:49:15 +00001360 CHECK_PRIVILEGED
Aurelien Jarno3376f412013-12-11 07:56:47 +01001361 tcg_gen_qemu_ld_i32(ALTREG(B6_4), REG(B11_8), ctx->memidx, MO_TESL);
aurel327efbe242008-09-01 13:09:14 +00001362 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
bellardfdf9b3e2006-04-27 21:07:38 +00001363 return;
1364 case 0x0082: /* stc Rm_BANK,Rn */
aurel32fe255912008-09-15 08:49:15 +00001365 CHECK_PRIVILEGED
aurel327efbe242008-09-01 13:09:14 +00001366 tcg_gen_mov_i32(REG(B11_8), ALTREG(B6_4));
bellardfdf9b3e2006-04-27 21:07:38 +00001367 return;
1368 case 0x4083: /* stc.l Rm_BANK,@-Rn */
aurel32fe255912008-09-15 08:49:15 +00001369 CHECK_PRIVILEGED
aurel32c55497e2008-09-01 13:09:21 +00001370 {
pbrooka7812ae2008-11-17 14:43:54 +00001371 TCGv addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001372 tcg_gen_subi_i32(addr, REG(B11_8), 4);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001373 tcg_gen_qemu_st_i32(ALTREG(B6_4), addr, ctx->memidx, MO_TEUL);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001374 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32c55497e2008-09-01 13:09:21 +00001375 tcg_temp_free(addr);
aurel32c55497e2008-09-01 13:09:21 +00001376 }
bellardfdf9b3e2006-04-27 21:07:38 +00001377 return;
1378 }
1379
1380 switch (ctx->opcode & 0xf0ff) {
1381 case 0x0023: /* braf Rn */
aurel327efbe242008-09-01 13:09:14 +00001382 CHECK_NOT_DELAY_SLOT
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001383 tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->base.pc_next + 4);
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001384 ctx->envflags |= DELAY_SLOT;
bellardfdf9b3e2006-04-27 21:07:38 +00001385 ctx->delayed_pc = (uint32_t) - 1;
1386 return;
1387 case 0x0003: /* bsrf Rn */
aurel327efbe242008-09-01 13:09:14 +00001388 CHECK_NOT_DELAY_SLOT
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001389 tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
aurel327efbe242008-09-01 13:09:14 +00001390 tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr);
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001391 ctx->envflags |= DELAY_SLOT;
bellardfdf9b3e2006-04-27 21:07:38 +00001392 ctx->delayed_pc = (uint32_t) - 1;
1393 return;
1394 case 0x4015: /* cmp/pl Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +02001395 tcg_gen_setcondi_i32(TCG_COND_GT, cpu_sr_t, REG(B11_8), 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001396 return;
1397 case 0x4011: /* cmp/pz Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +02001398 tcg_gen_setcondi_i32(TCG_COND_GE, cpu_sr_t, REG(B11_8), 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001399 return;
1400 case 0x4010: /* dt Rn */
aurel327efbe242008-09-01 13:09:14 +00001401 tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 1);
Aurelien Jarno34086942015-05-25 01:28:56 +02001402 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, REG(B11_8), 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001403 return;
1404 case 0x402b: /* jmp @Rn */
aurel327efbe242008-09-01 13:09:14 +00001405 CHECK_NOT_DELAY_SLOT
1406 tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8));
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001407 ctx->envflags |= DELAY_SLOT;
bellardfdf9b3e2006-04-27 21:07:38 +00001408 ctx->delayed_pc = (uint32_t) - 1;
1409 return;
1410 case 0x400b: /* jsr @Rn */
aurel327efbe242008-09-01 13:09:14 +00001411 CHECK_NOT_DELAY_SLOT
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001412 tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
aurel327efbe242008-09-01 13:09:14 +00001413 tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8));
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001414 ctx->envflags |= DELAY_SLOT;
bellardfdf9b3e2006-04-27 21:07:38 +00001415 ctx->delayed_pc = (uint32_t) - 1;
1416 return;
aurel32fe255912008-09-15 08:49:15 +00001417 case 0x400e: /* ldc Rm,SR */
1418 CHECK_PRIVILEGED
Aurelien Jarno34086942015-05-25 01:28:56 +02001419 {
1420 TCGv val = tcg_temp_new();
1421 tcg_gen_andi_i32(val, REG(B11_8), 0x700083f3);
1422 gen_write_sr(val);
1423 tcg_temp_free(val);
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001424 ctx->base.is_jmp = DISAS_STOP;
Aurelien Jarno34086942015-05-25 01:28:56 +02001425 }
aurel32390af822008-08-30 22:07:52 +00001426 return;
aurel32fe255912008-09-15 08:49:15 +00001427 case 0x4007: /* ldc.l @Rm+,SR */
1428 CHECK_PRIVILEGED
aurel32c55497e2008-09-01 13:09:21 +00001429 {
pbrooka7812ae2008-11-17 14:43:54 +00001430 TCGv val = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +01001431 tcg_gen_qemu_ld_i32(val, REG(B11_8), ctx->memidx, MO_TESL);
Aurelien Jarno34086942015-05-25 01:28:56 +02001432 tcg_gen_andi_i32(val, val, 0x700083f3);
1433 gen_write_sr(val);
aurel32c55497e2008-09-01 13:09:21 +00001434 tcg_temp_free(val);
1435 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001436 ctx->base.is_jmp = DISAS_STOP;
aurel32c55497e2008-09-01 13:09:21 +00001437 }
aurel32390af822008-08-30 22:07:52 +00001438 return;
aurel32fe255912008-09-15 08:49:15 +00001439 case 0x0002: /* stc SR,Rn */
1440 CHECK_PRIVILEGED
Aurelien Jarno34086942015-05-25 01:28:56 +02001441 gen_read_sr(REG(B11_8));
aurel32390af822008-08-30 22:07:52 +00001442 return;
aurel32fe255912008-09-15 08:49:15 +00001443 case 0x4003: /* stc SR,@-Rn */
1444 CHECK_PRIVILEGED
aurel32c55497e2008-09-01 13:09:21 +00001445 {
pbrooka7812ae2008-11-17 14:43:54 +00001446 TCGv addr = tcg_temp_new();
Aurelien Jarno34086942015-05-25 01:28:56 +02001447 TCGv val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001448 tcg_gen_subi_i32(addr, REG(B11_8), 4);
Aurelien Jarno34086942015-05-25 01:28:56 +02001449 gen_read_sr(val);
1450 tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_TEUL);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001451 tcg_gen_mov_i32(REG(B11_8), addr);
Aurelien Jarno34086942015-05-25 01:28:56 +02001452 tcg_temp_free(val);
aurel32c55497e2008-09-01 13:09:21 +00001453 tcg_temp_free(addr);
aurel32c55497e2008-09-01 13:09:21 +00001454 }
aurel32390af822008-08-30 22:07:52 +00001455 return;
Alexandre Courbot8e9b0672010-07-12 14:05:31 +09001456#define LD(reg,ldnum,ldpnum,prechk) \
bellardfdf9b3e2006-04-27 21:07:38 +00001457 case ldnum: \
aurel32fe255912008-09-15 08:49:15 +00001458 prechk \
aurel327efbe242008-09-01 13:09:14 +00001459 tcg_gen_mov_i32 (cpu_##reg, REG(B11_8)); \
bellardfdf9b3e2006-04-27 21:07:38 +00001460 return; \
1461 case ldpnum: \
aurel32fe255912008-09-15 08:49:15 +00001462 prechk \
Aurelien Jarno3376f412013-12-11 07:56:47 +01001463 tcg_gen_qemu_ld_i32(cpu_##reg, REG(B11_8), ctx->memidx, MO_TESL); \
aurel327efbe242008-09-01 13:09:14 +00001464 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); \
Alexandre Courbot8e9b0672010-07-12 14:05:31 +09001465 return;
1466#define ST(reg,stnum,stpnum,prechk) \
bellardfdf9b3e2006-04-27 21:07:38 +00001467 case stnum: \
aurel32fe255912008-09-15 08:49:15 +00001468 prechk \
aurel327efbe242008-09-01 13:09:14 +00001469 tcg_gen_mov_i32 (REG(B11_8), cpu_##reg); \
bellardfdf9b3e2006-04-27 21:07:38 +00001470 return; \
1471 case stpnum: \
aurel32fe255912008-09-15 08:49:15 +00001472 prechk \
aurel32c55497e2008-09-01 13:09:21 +00001473 { \
Aurelien Jarno3101e992010-01-31 01:07:25 +01001474 TCGv addr = tcg_temp_new(); \
aurel32c55497e2008-09-01 13:09:21 +00001475 tcg_gen_subi_i32(addr, REG(B11_8), 4); \
Aurelien Jarno3376f412013-12-11 07:56:47 +01001476 tcg_gen_qemu_st_i32(cpu_##reg, addr, ctx->memidx, MO_TEUL); \
Aurelien Jarno3101e992010-01-31 01:07:25 +01001477 tcg_gen_mov_i32(REG(B11_8), addr); \
aurel32c55497e2008-09-01 13:09:21 +00001478 tcg_temp_free(addr); \
aurel3286e0abc2008-09-02 08:42:16 +00001479 } \
bellardfdf9b3e2006-04-27 21:07:38 +00001480 return;
Alexandre Courbot8e9b0672010-07-12 14:05:31 +09001481#define LDST(reg,ldnum,ldpnum,stnum,stpnum,prechk) \
1482 LD(reg,ldnum,ldpnum,prechk) \
1483 ST(reg,stnum,stpnum,prechk)
aurel32fe255912008-09-15 08:49:15 +00001484 LDST(gbr, 0x401e, 0x4017, 0x0012, 0x4013, {})
1485 LDST(vbr, 0x402e, 0x4027, 0x0022, 0x4023, CHECK_PRIVILEGED)
1486 LDST(ssr, 0x403e, 0x4037, 0x0032, 0x4033, CHECK_PRIVILEGED)
1487 LDST(spc, 0x404e, 0x4047, 0x0042, 0x4043, CHECK_PRIVILEGED)
Alexandre Courbot935fc172010-07-12 14:05:32 +09001488 ST(sgr, 0x003a, 0x4032, CHECK_PRIVILEGED)
Richard Hendersonccae24d2017-07-18 10:02:48 -10001489 LD(sgr, 0x403a, 0x4036, CHECK_PRIVILEGED CHECK_SH4A)
aurel32fe255912008-09-15 08:49:15 +00001490 LDST(dbr, 0x40fa, 0x40f6, 0x00fa, 0x40f2, CHECK_PRIVILEGED)
1491 LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {})
1492 LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {})
1493 LDST(pr, 0x402a, 0x4026, 0x002a, 0x4022, {})
aurel32d8299bc2008-12-07 22:46:31 +00001494 LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {CHECK_FPU_ENABLED})
aurel32390af822008-08-30 22:07:52 +00001495 case 0x406a: /* lds Rm,FPSCR */
aurel32d8299bc2008-12-07 22:46:31 +00001496 CHECK_FPU_ENABLED
Blue Swirl485d0032012-09-02 10:37:06 +00001497 gen_helper_ld_fpscr(cpu_env, REG(B11_8));
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001498 ctx->base.is_jmp = DISAS_STOP;
aurel32390af822008-08-30 22:07:52 +00001499 return;
1500 case 0x4066: /* lds.l @Rm+,FPSCR */
aurel32d8299bc2008-12-07 22:46:31 +00001501 CHECK_FPU_ENABLED
aurel32c55497e2008-09-01 13:09:21 +00001502 {
pbrooka7812ae2008-11-17 14:43:54 +00001503 TCGv addr = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +01001504 tcg_gen_qemu_ld_i32(addr, REG(B11_8), ctx->memidx, MO_TESL);
aurel32c55497e2008-09-01 13:09:21 +00001505 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
Blue Swirl485d0032012-09-02 10:37:06 +00001506 gen_helper_ld_fpscr(cpu_env, addr);
aurel32c55497e2008-09-01 13:09:21 +00001507 tcg_temp_free(addr);
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001508 ctx->base.is_jmp = DISAS_STOP;
aurel32c55497e2008-09-01 13:09:21 +00001509 }
aurel32390af822008-08-30 22:07:52 +00001510 return;
1511 case 0x006a: /* sts FPSCR,Rn */
aurel32d8299bc2008-12-07 22:46:31 +00001512 CHECK_FPU_ENABLED
aurel32c55497e2008-09-01 13:09:21 +00001513 tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff);
aurel32390af822008-08-30 22:07:52 +00001514 return;
1515 case 0x4062: /* sts FPSCR,@-Rn */
aurel32d8299bc2008-12-07 22:46:31 +00001516 CHECK_FPU_ENABLED
aurel32c55497e2008-09-01 13:09:21 +00001517 {
1518 TCGv addr, val;
pbrooka7812ae2008-11-17 14:43:54 +00001519 val = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001520 tcg_gen_andi_i32(val, cpu_fpscr, 0x003fffff);
pbrooka7812ae2008-11-17 14:43:54 +00001521 addr = tcg_temp_new();
aurel32c55497e2008-09-01 13:09:21 +00001522 tcg_gen_subi_i32(addr, REG(B11_8), 4);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001523 tcg_gen_qemu_st_i32(val, addr, ctx->memidx, MO_TEUL);
Aurelien Jarno3101e992010-01-31 01:07:25 +01001524 tcg_gen_mov_i32(REG(B11_8), addr);
aurel32c55497e2008-09-01 13:09:21 +00001525 tcg_temp_free(addr);
1526 tcg_temp_free(val);
aurel32c55497e2008-09-01 13:09:21 +00001527 }
aurel32390af822008-08-30 22:07:52 +00001528 return;
bellardfdf9b3e2006-04-27 21:07:38 +00001529 case 0x00c3: /* movca.l R0,@Rm */
edgar_igl852d4812009-04-01 23:10:46 +00001530 {
1531 TCGv val = tcg_temp_new();
Aurelien Jarno3376f412013-12-11 07:56:47 +01001532 tcg_gen_qemu_ld_i32(val, REG(B11_8), ctx->memidx, MO_TEUL);
Blue Swirl485d0032012-09-02 10:37:06 +00001533 gen_helper_movcal(cpu_env, REG(B11_8), val);
Aurelien Jarno3376f412013-12-11 07:56:47 +01001534 tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL);
Philippe Mathieu-Daudée691e0e2017-12-05 14:00:13 -03001535 tcg_temp_free(val);
edgar_igl852d4812009-04-01 23:10:46 +00001536 }
1537 ctx->has_movcal = 1;
bellardfdf9b3e2006-04-27 21:07:38 +00001538 return;
Aurelien Jarno143021b2017-05-01 23:20:43 +02001539 case 0x40a9: /* movua.l @Rm,R0 */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001540 CHECK_SH4A
Aurelien Jarno143021b2017-05-01 23:20:43 +02001541 /* Load non-boundary-aligned data */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001542 tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx,
1543 MO_TEUL | MO_UNALN);
1544 return;
Aurelien Jarno143021b2017-05-01 23:20:43 +02001545 break;
1546 case 0x40e9: /* movua.l @Rm+,R0 */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001547 CHECK_SH4A
Aurelien Jarno143021b2017-05-01 23:20:43 +02001548 /* Load non-boundary-aligned data */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001549 tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx,
1550 MO_TEUL | MO_UNALN);
1551 tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
1552 return;
Aurelien Jarno143021b2017-05-01 23:20:43 +02001553 break;
bellardfdf9b3e2006-04-27 21:07:38 +00001554 case 0x0029: /* movt Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +02001555 tcg_gen_mov_i32(REG(B11_8), cpu_sr_t);
bellardfdf9b3e2006-04-27 21:07:38 +00001556 return;
aurel3266c7c802009-03-02 17:13:21 +00001557 case 0x0073:
1558 /* MOVCO.L
Richard Hendersonf85da302017-09-07 11:50:53 -07001559 * LDST -> T
1560 * If (T == 1) R0 -> (Rn)
1561 * 0 -> LDST
1562 *
1563 * The above description doesn't work in a parallel context.
1564 * Since we currently support no smp boards, this implies user-mode.
1565 * But we can still support the official mechanism while user-mode
1566 * is single-threaded. */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001567 CHECK_SH4A
1568 {
Richard Hendersonf85da302017-09-07 11:50:53 -07001569 TCGLabel *fail = gen_new_label();
1570 TCGLabel *done = gen_new_label();
1571
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001572 if ((tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
Richard Hendersonf85da302017-09-07 11:50:53 -07001573 TCGv tmp;
1574
1575 tcg_gen_brcond_i32(TCG_COND_NE, REG(B11_8),
1576 cpu_lock_addr, fail);
1577 tmp = tcg_temp_new();
1578 tcg_gen_atomic_cmpxchg_i32(tmp, REG(B11_8), cpu_lock_value,
1579 REG(0), ctx->memidx, MO_TEUL);
1580 tcg_gen_setcond_i32(TCG_COND_EQ, cpu_sr_t, tmp, cpu_lock_value);
1581 tcg_temp_free(tmp);
1582 } else {
1583 tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_lock_addr, -1, fail);
1584 tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL);
1585 tcg_gen_movi_i32(cpu_sr_t, 1);
1586 }
1587 tcg_gen_br(done);
1588
1589 gen_set_label(fail);
1590 tcg_gen_movi_i32(cpu_sr_t, 0);
1591
1592 gen_set_label(done);
1593 tcg_gen_movi_i32(cpu_lock_addr, -1);
Richard Hendersonccae24d2017-07-18 10:02:48 -10001594 }
Richard Hendersonf85da302017-09-07 11:50:53 -07001595 return;
aurel3266c7c802009-03-02 17:13:21 +00001596 case 0x0063:
1597 /* MOVLI.L @Rm,R0
Richard Hendersonf85da302017-09-07 11:50:53 -07001598 * 1 -> LDST
1599 * (Rm) -> R0
1600 * When interrupt/exception
1601 * occurred 0 -> LDST
1602 *
1603 * In a parallel context, we must also save the loaded value
1604 * for use with the cmpxchg that we'll use with movco.l. */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001605 CHECK_SH4A
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001606 if ((tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
Richard Hendersonf85da302017-09-07 11:50:53 -07001607 TCGv tmp = tcg_temp_new();
1608 tcg_gen_mov_i32(tmp, REG(B11_8));
1609 tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL);
1610 tcg_gen_mov_i32(cpu_lock_value, REG(0));
1611 tcg_gen_mov_i32(cpu_lock_addr, tmp);
1612 tcg_temp_free(tmp);
1613 } else {
1614 tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL);
1615 tcg_gen_movi_i32(cpu_lock_addr, 0);
1616 }
Richard Hendersonccae24d2017-07-18 10:02:48 -10001617 return;
bellardfdf9b3e2006-04-27 21:07:38 +00001618 case 0x0093: /* ocbi @Rn */
aurel32c55497e2008-09-01 13:09:21 +00001619 {
Blue Swirl485d0032012-09-02 10:37:06 +00001620 gen_helper_ocbi(cpu_env, REG(B11_8));
aurel32c55497e2008-09-01 13:09:21 +00001621 }
bellardfdf9b3e2006-04-27 21:07:38 +00001622 return;
aurel3224988dc2008-03-11 23:22:37 +00001623 case 0x00a3: /* ocbp @Rn */
bellardfdf9b3e2006-04-27 21:07:38 +00001624 case 0x00b3: /* ocbwb @Rn */
Aurelien Jarno0cdb9552012-01-07 15:20:12 +01001625 /* These instructions are supposed to do nothing in case of
1626 a cache miss. Given that we only partially emulate caches
1627 it is safe to simply ignore them. */
bellardfdf9b3e2006-04-27 21:07:38 +00001628 return;
1629 case 0x0083: /* pref @Rn */
1630 return;
aurel3271968fa2008-12-13 18:57:37 +00001631 case 0x00d3: /* prefi @Rn */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001632 CHECK_SH4A
1633 return;
aurel3271968fa2008-12-13 18:57:37 +00001634 case 0x00e3: /* icbi @Rn */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001635 CHECK_SH4A
1636 return;
aurel3271968fa2008-12-13 18:57:37 +00001637 case 0x00ab: /* synco */
Richard Hendersonccae24d2017-07-18 10:02:48 -10001638 CHECK_SH4A
1639 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
1640 return;
Aurelien Jarnoaa351312017-05-01 23:20:43 +02001641 break;
bellardfdf9b3e2006-04-27 21:07:38 +00001642 case 0x4024: /* rotcl Rn */
aurel32c55497e2008-09-01 13:09:21 +00001643 {
pbrooka7812ae2008-11-17 14:43:54 +00001644 TCGv tmp = tcg_temp_new();
Aurelien Jarno34086942015-05-25 01:28:56 +02001645 tcg_gen_mov_i32(tmp, cpu_sr_t);
1646 tcg_gen_shri_i32(cpu_sr_t, REG(B11_8), 31);
aurel32c55497e2008-09-01 13:09:21 +00001647 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1);
Aurelien Jarno34086942015-05-25 01:28:56 +02001648 tcg_gen_or_i32(REG(B11_8), REG(B11_8), tmp);
aurel32c55497e2008-09-01 13:09:21 +00001649 tcg_temp_free(tmp);
1650 }
bellardfdf9b3e2006-04-27 21:07:38 +00001651 return;
1652 case 0x4025: /* rotcr Rn */
aurel32c55497e2008-09-01 13:09:21 +00001653 {
pbrooka7812ae2008-11-17 14:43:54 +00001654 TCGv tmp = tcg_temp_new();
Aurelien Jarno34086942015-05-25 01:28:56 +02001655 tcg_gen_shli_i32(tmp, cpu_sr_t, 31);
1656 tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 1);
aurel32c55497e2008-09-01 13:09:21 +00001657 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1);
Aurelien Jarno34086942015-05-25 01:28:56 +02001658 tcg_gen_or_i32(REG(B11_8), REG(B11_8), tmp);
aurel32c55497e2008-09-01 13:09:21 +00001659 tcg_temp_free(tmp);
1660 }
bellardfdf9b3e2006-04-27 21:07:38 +00001661 return;
1662 case 0x4004: /* rotl Rn */
Aurelien Jarno2411fde2011-01-13 08:20:39 +01001663 tcg_gen_rotli_i32(REG(B11_8), REG(B11_8), 1);
Aurelien Jarno34086942015-05-25 01:28:56 +02001664 tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001665 return;
1666 case 0x4005: /* rotr Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +02001667 tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 0);
Aurelien Jarno2411fde2011-01-13 08:20:39 +01001668 tcg_gen_rotri_i32(REG(B11_8), REG(B11_8), 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001669 return;
1670 case 0x4000: /* shll Rn */
1671 case 0x4020: /* shal Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +02001672 tcg_gen_shri_i32(cpu_sr_t, REG(B11_8), 31);
aurel327efbe242008-09-01 13:09:14 +00001673 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001674 return;
1675 case 0x4021: /* shar Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +02001676 tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 1);
aurel327efbe242008-09-01 13:09:14 +00001677 tcg_gen_sari_i32(REG(B11_8), REG(B11_8), 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001678 return;
1679 case 0x4001: /* shlr Rn */
Aurelien Jarno34086942015-05-25 01:28:56 +02001680 tcg_gen_andi_i32(cpu_sr_t, REG(B11_8), 1);
aurel327efbe242008-09-01 13:09:14 +00001681 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1);
bellardfdf9b3e2006-04-27 21:07:38 +00001682 return;
1683 case 0x4008: /* shll2 Rn */
aurel327efbe242008-09-01 13:09:14 +00001684 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 2);
bellardfdf9b3e2006-04-27 21:07:38 +00001685 return;
1686 case 0x4018: /* shll8 Rn */
aurel327efbe242008-09-01 13:09:14 +00001687 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 8);
bellardfdf9b3e2006-04-27 21:07:38 +00001688 return;
1689 case 0x4028: /* shll16 Rn */
aurel327efbe242008-09-01 13:09:14 +00001690 tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 16);
bellardfdf9b3e2006-04-27 21:07:38 +00001691 return;
1692 case 0x4009: /* shlr2 Rn */
aurel327efbe242008-09-01 13:09:14 +00001693 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 2);
bellardfdf9b3e2006-04-27 21:07:38 +00001694 return;
1695 case 0x4019: /* shlr8 Rn */
aurel327efbe242008-09-01 13:09:14 +00001696 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 8);
bellardfdf9b3e2006-04-27 21:07:38 +00001697 return;
1698 case 0x4029: /* shlr16 Rn */
aurel327efbe242008-09-01 13:09:14 +00001699 tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 16);
bellardfdf9b3e2006-04-27 21:07:38 +00001700 return;
1701 case 0x401b: /* tas.b @Rn */
Aurelien Jarnocb32f172017-05-01 23:20:43 +02001702 {
1703 TCGv val = tcg_const_i32(0x80);
1704 tcg_gen_atomic_fetch_or_i32(val, REG(B11_8), val,
1705 ctx->memidx, MO_UB);
Aurelien Jarno34086942015-05-25 01:28:56 +02001706 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, val, 0);
Aurelien Jarnocb32f172017-05-01 23:20:43 +02001707 tcg_temp_free(val);
1708 }
1709 return;
thse67888a2007-06-22 11:44:41 +00001710 case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001711 CHECK_FPU_ENABLED
Richard Henderson7c9f7032017-07-18 10:02:36 -10001712 tcg_gen_mov_i32(FREG(B11_8), cpu_fpul);
bellardeda9b092006-06-14 15:02:05 +00001713 return;
thse67888a2007-06-22 11:44:41 +00001714 case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001715 CHECK_FPU_ENABLED
Richard Henderson7c9f7032017-07-18 10:02:36 -10001716 tcg_gen_mov_i32(cpu_fpul, FREG(B11_8));
bellardeda9b092006-06-14 15:02:05 +00001717 return;
thse67888a2007-06-22 11:44:41 +00001718 case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */
aurel32f6198372008-12-10 17:31:43 +00001719 CHECK_FPU_ENABLED
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001720 if (ctx->tbflags & FPSCR_PR) {
pbrooka7812ae2008-11-17 14:43:54 +00001721 TCGv_i64 fp;
Richard Henderson93dc9c82017-07-18 10:02:46 -10001722 if (ctx->opcode & 0x0100) {
1723 goto do_illegal;
1724 }
pbrooka7812ae2008-11-17 14:43:54 +00001725 fp = tcg_temp_new_i64();
Blue Swirl485d0032012-09-02 10:37:06 +00001726 gen_helper_float_DT(fp, cpu_env, cpu_fpul);
Richard Henderson1e0b21d2017-07-18 10:02:40 -10001727 gen_store_fpr64(ctx, fp, B11_8);
pbrooka7812ae2008-11-17 14:43:54 +00001728 tcg_temp_free_i64(fp);
thsea6cf6b2007-06-22 11:12:01 +00001729 }
1730 else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001731 gen_helper_float_FT(FREG(B11_8), cpu_env, cpu_fpul);
thsea6cf6b2007-06-22 11:12:01 +00001732 }
1733 return;
thse67888a2007-06-22 11:44:41 +00001734 case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
aurel32f6198372008-12-10 17:31:43 +00001735 CHECK_FPU_ENABLED
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001736 if (ctx->tbflags & FPSCR_PR) {
pbrooka7812ae2008-11-17 14:43:54 +00001737 TCGv_i64 fp;
Richard Henderson93dc9c82017-07-18 10:02:46 -10001738 if (ctx->opcode & 0x0100) {
1739 goto do_illegal;
1740 }
pbrooka7812ae2008-11-17 14:43:54 +00001741 fp = tcg_temp_new_i64();
Richard Henderson1e0b21d2017-07-18 10:02:40 -10001742 gen_load_fpr64(ctx, fp, B11_8);
Blue Swirl485d0032012-09-02 10:37:06 +00001743 gen_helper_ftrc_DT(cpu_fpul, cpu_env, fp);
pbrooka7812ae2008-11-17 14:43:54 +00001744 tcg_temp_free_i64(fp);
thsea6cf6b2007-06-22 11:12:01 +00001745 }
1746 else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001747 gen_helper_ftrc_FT(cpu_fpul, cpu_env, FREG(B11_8));
thsea6cf6b2007-06-22 11:12:01 +00001748 }
1749 return;
aurel3224988dc2008-03-11 23:22:37 +00001750 case 0xf04d: /* fneg FRn/DRn - FPSCR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001751 CHECK_FPU_ENABLED
Richard Henderson7c9f7032017-07-18 10:02:36 -10001752 tcg_gen_xori_i32(FREG(B11_8), FREG(B11_8), 0x80000000);
aurel3224988dc2008-03-11 23:22:37 +00001753 return;
Aurelien Jarno57f5c1b2017-07-02 18:18:14 +02001754 case 0xf05d: /* fabs FRn/DRn - FPCSR: Nothing */
aurel32f6198372008-12-10 17:31:43 +00001755 CHECK_FPU_ENABLED
Richard Henderson7c9f7032017-07-18 10:02:36 -10001756 tcg_gen_andi_i32(FREG(B11_8), FREG(B11_8), 0x7fffffff);
aurel3224988dc2008-03-11 23:22:37 +00001757 return;
1758 case 0xf06d: /* fsqrt FRn */
aurel32f6198372008-12-10 17:31:43 +00001759 CHECK_FPU_ENABLED
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001760 if (ctx->tbflags & FPSCR_PR) {
Richard Henderson93dc9c82017-07-18 10:02:46 -10001761 if (ctx->opcode & 0x0100) {
1762 goto do_illegal;
1763 }
pbrooka7812ae2008-11-17 14:43:54 +00001764 TCGv_i64 fp = tcg_temp_new_i64();
Richard Henderson1e0b21d2017-07-18 10:02:40 -10001765 gen_load_fpr64(ctx, fp, B11_8);
Blue Swirl485d0032012-09-02 10:37:06 +00001766 gen_helper_fsqrt_DT(fp, cpu_env, fp);
Richard Henderson1e0b21d2017-07-18 10:02:40 -10001767 gen_store_fpr64(ctx, fp, B11_8);
pbrooka7812ae2008-11-17 14:43:54 +00001768 tcg_temp_free_i64(fp);
aurel3224988dc2008-03-11 23:22:37 +00001769 } else {
Richard Henderson7c9f7032017-07-18 10:02:36 -10001770 gen_helper_fsqrt_FT(FREG(B11_8), cpu_env, FREG(B11_8));
aurel3224988dc2008-03-11 23:22:37 +00001771 }
1772 return;
1773 case 0xf07d: /* fsrra FRn */
aurel32f6198372008-12-10 17:31:43 +00001774 CHECK_FPU_ENABLED
Richard Henderson11b7aa22017-07-18 10:02:51 -10001775 CHECK_FPSCR_PR_0
1776 gen_helper_fsrra_FT(FREG(B11_8), cpu_env, FREG(B11_8));
aurel3224988dc2008-03-11 23:22:37 +00001777 break;
thse67888a2007-06-22 11:44:41 +00001778 case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */
aurel32f6198372008-12-10 17:31:43 +00001779 CHECK_FPU_ENABLED
Richard Henderson7e9f7ca2017-07-18 10:02:47 -10001780 CHECK_FPSCR_PR_0
1781 tcg_gen_movi_i32(FREG(B11_8), 0);
1782 return;
thse67888a2007-06-22 11:44:41 +00001783 case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */
aurel32f6198372008-12-10 17:31:43 +00001784 CHECK_FPU_ENABLED
Richard Henderson7e9f7ca2017-07-18 10:02:47 -10001785 CHECK_FPSCR_PR_0
1786 tcg_gen_movi_i32(FREG(B11_8), 0x3f800000);
1787 return;
aurel3224988dc2008-03-11 23:22:37 +00001788 case 0xf0ad: /* fcnvsd FPUL,DRn */
aurel32f6198372008-12-10 17:31:43 +00001789 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001790 {
pbrooka7812ae2008-11-17 14:43:54 +00001791 TCGv_i64 fp = tcg_temp_new_i64();
Blue Swirl485d0032012-09-02 10:37:06 +00001792 gen_helper_fcnvsd_FT_DT(fp, cpu_env, cpu_fpul);
Richard Henderson1e0b21d2017-07-18 10:02:40 -10001793 gen_store_fpr64(ctx, fp, B11_8);
pbrooka7812ae2008-11-17 14:43:54 +00001794 tcg_temp_free_i64(fp);
aurel32cc4ba6a2008-09-01 22:11:56 +00001795 }
aurel3224988dc2008-03-11 23:22:37 +00001796 return;
1797 case 0xf0bd: /* fcnvds DRn,FPUL */
aurel32f6198372008-12-10 17:31:43 +00001798 CHECK_FPU_ENABLED
aurel32cc4ba6a2008-09-01 22:11:56 +00001799 {
pbrooka7812ae2008-11-17 14:43:54 +00001800 TCGv_i64 fp = tcg_temp_new_i64();
Richard Henderson1e0b21d2017-07-18 10:02:40 -10001801 gen_load_fpr64(ctx, fp, B11_8);
Blue Swirl485d0032012-09-02 10:37:06 +00001802 gen_helper_fcnvds_DT_FT(cpu_fpul, cpu_env, fp);
pbrooka7812ae2008-11-17 14:43:54 +00001803 tcg_temp_free_i64(fp);
aurel32cc4ba6a2008-09-01 22:11:56 +00001804 }
aurel3224988dc2008-03-11 23:22:37 +00001805 return;
Aurelien Jarnoaf8c2bd2011-01-14 20:39:18 +01001806 case 0xf0ed: /* fipr FVm,FVn */
1807 CHECK_FPU_ENABLED
Richard Henderson7e9f7ca2017-07-18 10:02:47 -10001808 CHECK_FPSCR_PR_1
1809 {
1810 TCGv m = tcg_const_i32((ctx->opcode >> 8) & 3);
1811 TCGv n = tcg_const_i32((ctx->opcode >> 10) & 3);
Blue Swirl485d0032012-09-02 10:37:06 +00001812 gen_helper_fipr(cpu_env, m, n);
Aurelien Jarnoaf8c2bd2011-01-14 20:39:18 +01001813 tcg_temp_free(m);
1814 tcg_temp_free(n);
1815 return;
1816 }
1817 break;
Aurelien Jarno17075f12011-01-14 20:39:18 +01001818 case 0xf0fd: /* ftrv XMTRX,FVn */
1819 CHECK_FPU_ENABLED
Richard Henderson7e9f7ca2017-07-18 10:02:47 -10001820 CHECK_FPSCR_PR_1
1821 {
1822 if ((ctx->opcode & 0x0300) != 0x0100) {
1823 goto do_illegal;
1824 }
1825 TCGv n = tcg_const_i32((ctx->opcode >> 10) & 3);
Blue Swirl485d0032012-09-02 10:37:06 +00001826 gen_helper_ftrv(cpu_env, n);
Aurelien Jarno17075f12011-01-14 20:39:18 +01001827 tcg_temp_free(n);
1828 return;
1829 }
1830 break;
bellardfdf9b3e2006-04-27 21:07:38 +00001831 }
aurel32bacc6372008-12-13 18:57:46 +00001832#if 0
bellardfdf9b3e2006-04-27 21:07:38 +00001833 fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001834 ctx->opcode, ctx->base.pc_next);
aurel32bacc6372008-12-13 18:57:46 +00001835 fflush(stderr);
1836#endif
Richard Henderson6b982132017-07-18 10:02:44 -10001837 do_illegal:
Aurelien Jarno9a562ae2017-05-17 00:48:18 +02001838 if (ctx->envflags & DELAY_SLOT_MASK) {
Richard Hendersondec16c62017-07-18 10:02:43 -10001839 do_illegal_slot:
1840 gen_save_cpu_state(ctx, true);
Blue Swirl485d0032012-09-02 10:37:06 +00001841 gen_helper_raise_slot_illegal_instruction(cpu_env);
Aurelien Jarno86865c52011-01-11 16:13:34 +01001842 } else {
Richard Hendersondec16c62017-07-18 10:02:43 -10001843 gen_save_cpu_state(ctx, true);
Blue Swirl485d0032012-09-02 10:37:06 +00001844 gen_helper_raise_illegal_instruction(cpu_env);
Aurelien Jarno86865c52011-01-11 16:13:34 +01001845 }
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001846 ctx->base.is_jmp = DISAS_NORETURN;
Richard Hendersondec4f042017-07-18 10:02:45 -10001847 return;
1848
1849 do_fpu_disabled:
1850 gen_save_cpu_state(ctx, true);
1851 if (ctx->envflags & DELAY_SLOT_MASK) {
1852 gen_helper_raise_slot_fpu_disable(cpu_env);
1853 } else {
1854 gen_helper_raise_fpu_disable(cpu_env);
1855 }
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001856 ctx->base.is_jmp = DISAS_NORETURN;
Richard Hendersondec4f042017-07-18 10:02:45 -10001857 return;
ths823029f2007-12-02 06:10:04 +00001858}
1859
blueswir1b1d8e522008-10-26 13:43:07 +00001860static void decode_opc(DisasContext * ctx)
ths823029f2007-12-02 06:10:04 +00001861{
Aurelien Jarnoa6215742017-05-01 23:20:43 +02001862 uint32_t old_flags = ctx->envflags;
ths823029f2007-12-02 06:10:04 +00001863
1864 _decode_opc(ctx);
1865
Aurelien Jarno9a562ae2017-05-17 00:48:18 +02001866 if (old_flags & DELAY_SLOT_MASK) {
Aurelien Jarno39682602017-05-01 23:20:43 +02001867 /* go out of the delay slot */
Aurelien Jarno9a562ae2017-05-17 00:48:18 +02001868 ctx->envflags &= ~DELAY_SLOT_MASK;
Richard Henderson4bfa6022017-07-18 10:02:31 -10001869
1870 /* When in an exclusive region, we must continue to the end
1871 for conditional branches. */
1872 if (ctx->tbflags & GUSA_EXCLUSIVE
1873 && old_flags & DELAY_SLOT_CONDITIONAL) {
1874 gen_delayed_conditional_jump(ctx);
1875 return;
1876 }
1877 /* Otherwise this is probably an invalid gUSA region.
1878 Drop the GUSA bits so the next TB doesn't see them. */
1879 ctx->envflags &= ~GUSA_MASK;
1880
Aurelien Jarnoac9707e2017-05-01 23:20:43 +02001881 tcg_gen_movi_i32(cpu_flags, ctx->envflags);
ths823029f2007-12-02 06:10:04 +00001882 if (old_flags & DELAY_SLOT_CONDITIONAL) {
1883 gen_delayed_conditional_jump(ctx);
Aurelien Jarnobe530812017-05-17 00:48:18 +02001884 } else {
ths823029f2007-12-02 06:10:04 +00001885 gen_jump(ctx);
1886 }
ths823029f2007-12-02 06:10:04 +00001887 }
bellardfdf9b3e2006-04-27 21:07:38 +00001888}
1889
Richard Henderson4bfa6022017-07-18 10:02:31 -10001890#ifdef CONFIG_USER_ONLY
1891/* For uniprocessors, SH4 uses optimistic restartable atomic sequences.
1892 Upon an interrupt, a real kernel would simply notice magic values in
1893 the registers and reset the PC to the start of the sequence.
1894
1895 For QEMU, we cannot do this in quite the same way. Instead, we notice
1896 the normal start of such a sequence (mov #-x,r15). While we can handle
1897 any sequence via cpu_exec_step_atomic, we can recognize the "normal"
1898 sequences and transform them into atomic operations as seen by the host.
1899*/
Richard Hendersonbe0e3d72018-06-01 16:55:52 -07001900static void decode_gusa(DisasContext *ctx, CPUSH4State *env)
Richard Henderson4bfa6022017-07-18 10:02:31 -10001901{
Richard Hendersond6a6cff2017-07-18 10:02:32 -10001902 uint16_t insns[5];
1903 int ld_adr, ld_dst, ld_mop;
1904 int op_dst, op_src, op_opc;
1905 int mv_src, mt_dst, st_src, st_mop;
1906 TCGv op_arg;
Richard Henderson6f1c2af2017-09-07 11:50:56 -07001907 uint32_t pc = ctx->base.pc_next;
1908 uint32_t pc_end = ctx->base.tb->cs_base;
Richard Henderson4bfa6022017-07-18 10:02:31 -10001909 int max_insns = (pc_end - pc) / 2;
Richard Hendersond6a6cff2017-07-18 10:02:32 -10001910 int i;
Richard Henderson4bfa6022017-07-18 10:02:31 -10001911
Richard Hendersond6a6cff2017-07-18 10:02:32 -10001912 /* The state machine below will consume only a few insns.
1913 If there are more than that in a region, fail now. */
1914 if (max_insns > ARRAY_SIZE(insns)) {
1915 goto fail;
1916 }
1917
1918 /* Read all of the insns for the region. */
1919 for (i = 0; i < max_insns; ++i) {
1920 insns[i] = cpu_lduw_code(env, pc + i * 2);
1921 }
1922
1923 ld_adr = ld_dst = ld_mop = -1;
1924 mv_src = -1;
1925 op_dst = op_src = op_opc = -1;
1926 mt_dst = -1;
1927 st_src = st_mop = -1;
Richard Hendersonf7647182017-11-02 12:47:37 +01001928 op_arg = NULL;
Richard Hendersond6a6cff2017-07-18 10:02:32 -10001929 i = 0;
1930
1931#define NEXT_INSN \
1932 do { if (i >= max_insns) goto fail; ctx->opcode = insns[i++]; } while (0)
1933
1934 /*
1935 * Expect a load to begin the region.
1936 */
1937 NEXT_INSN;
1938 switch (ctx->opcode & 0xf00f) {
1939 case 0x6000: /* mov.b @Rm,Rn */
1940 ld_mop = MO_SB;
1941 break;
1942 case 0x6001: /* mov.w @Rm,Rn */
1943 ld_mop = MO_TESW;
1944 break;
1945 case 0x6002: /* mov.l @Rm,Rn */
1946 ld_mop = MO_TESL;
1947 break;
1948 default:
1949 goto fail;
1950 }
1951 ld_adr = B7_4;
1952 ld_dst = B11_8;
1953 if (ld_adr == ld_dst) {
1954 goto fail;
1955 }
1956 /* Unless we see a mov, any two-operand operation must use ld_dst. */
1957 op_dst = ld_dst;
1958
1959 /*
1960 * Expect an optional register move.
1961 */
1962 NEXT_INSN;
1963 switch (ctx->opcode & 0xf00f) {
1964 case 0x6003: /* mov Rm,Rn */
1965 /* Here we want to recognize ld_dst being saved for later consumtion,
1966 or for another input register being copied so that ld_dst need not
1967 be clobbered during the operation. */
1968 op_dst = B11_8;
1969 mv_src = B7_4;
1970 if (op_dst == ld_dst) {
1971 /* Overwriting the load output. */
1972 goto fail;
1973 }
1974 if (mv_src != ld_dst) {
1975 /* Copying a new input; constrain op_src to match the load. */
1976 op_src = ld_dst;
1977 }
1978 break;
1979
1980 default:
1981 /* Put back and re-examine as operation. */
1982 --i;
1983 }
1984
1985 /*
1986 * Expect the operation.
1987 */
1988 NEXT_INSN;
1989 switch (ctx->opcode & 0xf00f) {
1990 case 0x300c: /* add Rm,Rn */
1991 op_opc = INDEX_op_add_i32;
1992 goto do_reg_op;
1993 case 0x2009: /* and Rm,Rn */
1994 op_opc = INDEX_op_and_i32;
1995 goto do_reg_op;
1996 case 0x200a: /* xor Rm,Rn */
1997 op_opc = INDEX_op_xor_i32;
1998 goto do_reg_op;
1999 case 0x200b: /* or Rm,Rn */
2000 op_opc = INDEX_op_or_i32;
2001 do_reg_op:
2002 /* The operation register should be as expected, and the
2003 other input cannot depend on the load. */
2004 if (op_dst != B11_8) {
2005 goto fail;
2006 }
2007 if (op_src < 0) {
2008 /* Unconstrainted input. */
2009 op_src = B7_4;
2010 } else if (op_src == B7_4) {
2011 /* Constrained input matched load. All operations are
2012 commutative; "swap" them by "moving" the load output
2013 to the (implicit) first argument and the move source
2014 to the (explicit) second argument. */
2015 op_src = mv_src;
2016 } else {
2017 goto fail;
2018 }
2019 op_arg = REG(op_src);
2020 break;
2021
2022 case 0x6007: /* not Rm,Rn */
2023 if (ld_dst != B7_4 || mv_src >= 0) {
2024 goto fail;
2025 }
2026 op_dst = B11_8;
2027 op_opc = INDEX_op_xor_i32;
2028 op_arg = tcg_const_i32(-1);
2029 break;
2030
2031 case 0x7000 ... 0x700f: /* add #imm,Rn */
2032 if (op_dst != B11_8 || mv_src >= 0) {
2033 goto fail;
2034 }
2035 op_opc = INDEX_op_add_i32;
2036 op_arg = tcg_const_i32(B7_0s);
2037 break;
2038
2039 case 0x3000: /* cmp/eq Rm,Rn */
2040 /* Looking for the middle of a compare-and-swap sequence,
2041 beginning with the compare. Operands can be either order,
2042 but with only one overlapping the load. */
2043 if ((ld_dst == B11_8) + (ld_dst == B7_4) != 1 || mv_src >= 0) {
2044 goto fail;
2045 }
2046 op_opc = INDEX_op_setcond_i32; /* placeholder */
2047 op_src = (ld_dst == B11_8 ? B7_4 : B11_8);
2048 op_arg = REG(op_src);
2049
2050 NEXT_INSN;
2051 switch (ctx->opcode & 0xff00) {
2052 case 0x8b00: /* bf label */
2053 case 0x8f00: /* bf/s label */
2054 if (pc + (i + 1 + B7_0s) * 2 != pc_end) {
2055 goto fail;
2056 }
2057 if ((ctx->opcode & 0xff00) == 0x8b00) { /* bf label */
2058 break;
2059 }
2060 /* We're looking to unconditionally modify Rn with the
2061 result of the comparison, within the delay slot of
2062 the branch. This is used by older gcc. */
2063 NEXT_INSN;
2064 if ((ctx->opcode & 0xf0ff) == 0x0029) { /* movt Rn */
2065 mt_dst = B11_8;
2066 } else {
2067 goto fail;
2068 }
2069 break;
2070
2071 default:
2072 goto fail;
2073 }
2074 break;
2075
2076 case 0x2008: /* tst Rm,Rn */
2077 /* Looking for a compare-and-swap against zero. */
2078 if (ld_dst != B11_8 || ld_dst != B7_4 || mv_src >= 0) {
2079 goto fail;
2080 }
2081 op_opc = INDEX_op_setcond_i32;
2082 op_arg = tcg_const_i32(0);
2083
2084 NEXT_INSN;
2085 if ((ctx->opcode & 0xff00) != 0x8900 /* bt label */
2086 || pc + (i + 1 + B7_0s) * 2 != pc_end) {
2087 goto fail;
2088 }
2089 break;
2090
2091 default:
2092 /* Put back and re-examine as store. */
2093 --i;
2094 }
2095
2096 /*
2097 * Expect the store.
2098 */
2099 /* The store must be the last insn. */
2100 if (i != max_insns - 1) {
2101 goto fail;
2102 }
2103 NEXT_INSN;
2104 switch (ctx->opcode & 0xf00f) {
2105 case 0x2000: /* mov.b Rm,@Rn */
2106 st_mop = MO_UB;
2107 break;
2108 case 0x2001: /* mov.w Rm,@Rn */
2109 st_mop = MO_UW;
2110 break;
2111 case 0x2002: /* mov.l Rm,@Rn */
2112 st_mop = MO_UL;
2113 break;
2114 default:
2115 goto fail;
2116 }
2117 /* The store must match the load. */
2118 if (ld_adr != B11_8 || st_mop != (ld_mop & MO_SIZE)) {
2119 goto fail;
2120 }
2121 st_src = B7_4;
2122
2123#undef NEXT_INSN
2124
2125 /*
2126 * Emit the operation.
2127 */
Richard Hendersond6a6cff2017-07-18 10:02:32 -10002128 switch (op_opc) {
2129 case -1:
2130 /* No operation found. Look for exchange pattern. */
2131 if (st_src == ld_dst || mv_src >= 0) {
2132 goto fail;
2133 }
2134 tcg_gen_atomic_xchg_i32(REG(ld_dst), REG(ld_adr), REG(st_src),
2135 ctx->memidx, ld_mop);
2136 break;
2137
2138 case INDEX_op_add_i32:
2139 if (op_dst != st_src) {
2140 goto fail;
2141 }
2142 if (op_dst == ld_dst && st_mop == MO_UL) {
2143 tcg_gen_atomic_add_fetch_i32(REG(ld_dst), REG(ld_adr),
2144 op_arg, ctx->memidx, ld_mop);
2145 } else {
2146 tcg_gen_atomic_fetch_add_i32(REG(ld_dst), REG(ld_adr),
2147 op_arg, ctx->memidx, ld_mop);
2148 if (op_dst != ld_dst) {
2149 /* Note that mop sizes < 4 cannot use add_fetch
2150 because it won't carry into the higher bits. */
2151 tcg_gen_add_i32(REG(op_dst), REG(ld_dst), op_arg);
2152 }
2153 }
2154 break;
2155
2156 case INDEX_op_and_i32:
2157 if (op_dst != st_src) {
2158 goto fail;
2159 }
2160 if (op_dst == ld_dst) {
2161 tcg_gen_atomic_and_fetch_i32(REG(ld_dst), REG(ld_adr),
2162 op_arg, ctx->memidx, ld_mop);
2163 } else {
2164 tcg_gen_atomic_fetch_and_i32(REG(ld_dst), REG(ld_adr),
2165 op_arg, ctx->memidx, ld_mop);
2166 tcg_gen_and_i32(REG(op_dst), REG(ld_dst), op_arg);
2167 }
2168 break;
2169
2170 case INDEX_op_or_i32:
2171 if (op_dst != st_src) {
2172 goto fail;
2173 }
2174 if (op_dst == ld_dst) {
2175 tcg_gen_atomic_or_fetch_i32(REG(ld_dst), REG(ld_adr),
2176 op_arg, ctx->memidx, ld_mop);
2177 } else {
2178 tcg_gen_atomic_fetch_or_i32(REG(ld_dst), REG(ld_adr),
2179 op_arg, ctx->memidx, ld_mop);
2180 tcg_gen_or_i32(REG(op_dst), REG(ld_dst), op_arg);
2181 }
2182 break;
2183
2184 case INDEX_op_xor_i32:
2185 if (op_dst != st_src) {
2186 goto fail;
2187 }
2188 if (op_dst == ld_dst) {
2189 tcg_gen_atomic_xor_fetch_i32(REG(ld_dst), REG(ld_adr),
2190 op_arg, ctx->memidx, ld_mop);
2191 } else {
2192 tcg_gen_atomic_fetch_xor_i32(REG(ld_dst), REG(ld_adr),
2193 op_arg, ctx->memidx, ld_mop);
2194 tcg_gen_xor_i32(REG(op_dst), REG(ld_dst), op_arg);
2195 }
2196 break;
2197
2198 case INDEX_op_setcond_i32:
2199 if (st_src == ld_dst) {
2200 goto fail;
2201 }
2202 tcg_gen_atomic_cmpxchg_i32(REG(ld_dst), REG(ld_adr), op_arg,
2203 REG(st_src), ctx->memidx, ld_mop);
2204 tcg_gen_setcond_i32(TCG_COND_EQ, cpu_sr_t, REG(ld_dst), op_arg);
2205 if (mt_dst >= 0) {
2206 tcg_gen_mov_i32(REG(mt_dst), cpu_sr_t);
2207 }
2208 break;
2209
2210 default:
2211 g_assert_not_reached();
2212 }
2213
2214 /* If op_src is not a valid register, then op_arg was a constant. */
Richard Hendersonf7647182017-11-02 12:47:37 +01002215 if (op_src < 0 && op_arg) {
Richard Hendersond6a6cff2017-07-18 10:02:32 -10002216 tcg_temp_free_i32(op_arg);
2217 }
2218
2219 /* The entire region has been translated. */
2220 ctx->envflags &= ~GUSA_MASK;
Richard Henderson6f1c2af2017-09-07 11:50:56 -07002221 ctx->base.pc_next = pc_end;
Richard Hendersonbe0e3d72018-06-01 16:55:52 -07002222 ctx->base.num_insns += max_insns - 1;
2223 return;
Richard Hendersond6a6cff2017-07-18 10:02:32 -10002224
2225 fail:
Richard Henderson4bfa6022017-07-18 10:02:31 -10002226 qemu_log_mask(LOG_UNIMP, "Unrecognized gUSA sequence %08x-%08x\n",
2227 pc, pc_end);
2228
2229 /* Restart with the EXCLUSIVE bit set, within a TB run via
2230 cpu_exec_step_atomic holding the exclusive lock. */
Richard Henderson4bfa6022017-07-18 10:02:31 -10002231 ctx->envflags |= GUSA_EXCLUSIVE;
2232 gen_save_cpu_state(ctx, false);
2233 gen_helper_exclusive(cpu_env);
Richard Henderson6f1c2af2017-09-07 11:50:56 -07002234 ctx->base.is_jmp = DISAS_NORETURN;
Richard Henderson4bfa6022017-07-18 10:02:31 -10002235
2236 /* We're not executing an instruction, but we must report one for the
2237 purposes of accounting within the TB. We might as well report the
Richard Henderson6f1c2af2017-09-07 11:50:56 -07002238 entire region consumed via ctx->base.pc_next so that it's immediately
2239 available in the disassembly dump. */
2240 ctx->base.pc_next = pc_end;
Richard Hendersonbe0e3d72018-06-01 16:55:52 -07002241 ctx->base.num_insns += max_insns - 1;
Richard Henderson4bfa6022017-07-18 10:02:31 -10002242}
2243#endif
2244
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002245static void sh4_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
bellardfdf9b3e2006-04-27 21:07:38 +00002246{
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002247 DisasContext *ctx = container_of(dcbase, DisasContext, base);
Lluís Vilanova9c489ea2017-07-14 11:17:35 +03002248 CPUSH4State *env = cs->env_ptr;
Richard Hendersonbe0e3d72018-06-01 16:55:52 -07002249 uint32_t tbflags;
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002250 int bound;
bellardfdf9b3e2006-04-27 21:07:38 +00002251
Richard Hendersonbe0e3d72018-06-01 16:55:52 -07002252 ctx->tbflags = tbflags = ctx->base.tb->flags;
2253 ctx->envflags = tbflags & TB_FLAG_ENVFLAGS_MASK;
2254 ctx->memidx = (tbflags & (1u << SR_MD)) == 0 ? 1 : 0;
pbrook9854bc42006-06-17 18:48:31 +00002255 /* We don't know if the delayed pc came from a dynamic or static branch,
2256 so assume it is a dynamic branch. */
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002257 ctx->delayed_pc = -1; /* use delayed pc from env pointer */
2258 ctx->features = env->features;
Richard Hendersonbe0e3d72018-06-01 16:55:52 -07002259 ctx->has_movcal = (tbflags & TB_FLAG_PENDING_MOVCA);
2260 ctx->gbank = ((tbflags & (1 << SR_MD)) &&
2261 (tbflags & (1 << SR_RB))) * 0x10;
2262 ctx->fbank = tbflags & FPSCR_FR ? 0x10 : 0;
2263
2264 if (tbflags & GUSA_MASK) {
2265 uint32_t pc = ctx->base.pc_next;
2266 uint32_t pc_end = ctx->base.tb->cs_base;
2267 int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8);
2268 int max_insns = (pc_end - pc) / 2;
2269
2270 if (pc != pc_end + backup || max_insns < 2) {
2271 /* This is a malformed gUSA region. Don't do anything special,
2272 since the interpreter is likely to get confused. */
2273 ctx->envflags &= ~GUSA_MASK;
2274 } else if (tbflags & GUSA_EXCLUSIVE) {
2275 /* Regardless of single-stepping or the end of the page,
2276 we must complete execution of the gUSA region while
2277 holding the exclusive lock. */
2278 ctx->base.max_insns = max_insns;
2279 return;
2280 }
2281 }
Richard Henderson4448a832017-07-18 10:02:27 -10002282
2283 /* Since the ISA is fixed-width, we can bound by the number
2284 of instructions remaining on the page. */
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002285 bound = -(ctx->base.pc_next | TARGET_PAGE_MASK) / 2;
2286 ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
2287}
Richard Henderson4448a832017-07-18 10:02:27 -10002288
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002289static void sh4_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
2290{
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002291}
Richard Henderson4bfa6022017-07-18 10:02:31 -10002292
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002293static void sh4_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
2294{
2295 DisasContext *ctx = container_of(dcbase, DisasContext, base);
Richard Henderson667b8e22015-08-29 12:59:29 -07002296
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002297 tcg_gen_insn_start(ctx->base.pc_next, ctx->envflags);
2298}
Richard Hendersonb9330662015-09-17 15:58:10 -07002299
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002300static bool sh4_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
2301 const CPUBreakpoint *bp)
2302{
2303 DisasContext *ctx = container_of(dcbase, DisasContext, base);
Richard Henderson667b8e22015-08-29 12:59:29 -07002304
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002305 /* We have hit a breakpoint - make sure PC is up-to-date */
2306 gen_save_cpu_state(ctx, true);
2307 gen_helper_debug(cpu_env);
2308 ctx->base.is_jmp = DISAS_NORETURN;
2309 /* The address covered by the breakpoint must be included in
2310 [tb->pc, tb->pc + tb->size) in order to for it to be
2311 properly cleared -- thus we increment the PC here so that
2312 the logic setting tb->size below does the right thing. */
2313 ctx->base.pc_next += 2;
2314 return true;
2315}
Richard Henderson4bfa6022017-07-18 10:02:31 -10002316
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002317static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
2318{
2319 CPUSH4State *env = cs->env_ptr;
2320 DisasContext *ctx = container_of(dcbase, DisasContext, base);
2321
Richard Hendersonbe0e3d72018-06-01 16:55:52 -07002322#ifdef CONFIG_USER_ONLY
2323 if (unlikely(ctx->envflags & GUSA_MASK)
2324 && !(ctx->envflags & GUSA_EXCLUSIVE)) {
2325 /* We're in an gUSA region, and we have not already fallen
2326 back on using an exclusive region. Attempt to parse the
2327 region into a single supported atomic operation. Failure
2328 is handled within the parser by raising an exception to
2329 retry using an exclusive region. */
2330 decode_gusa(ctx, env);
2331 return;
2332 }
2333#endif
2334
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002335 ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next);
2336 decode_opc(ctx);
2337 ctx->base.pc_next += 2;
2338}
2339
2340static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
2341{
2342 DisasContext *ctx = container_of(dcbase, DisasContext, base);
2343
2344 if (ctx->tbflags & GUSA_EXCLUSIVE) {
Richard Henderson4bfa6022017-07-18 10:02:31 -10002345 /* Ending the region of exclusivity. Clear the bits. */
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002346 ctx->envflags &= ~GUSA_MASK;
Richard Henderson4bfa6022017-07-18 10:02:31 -10002347 }
2348
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002349 switch (ctx->base.is_jmp) {
Richard Henderson34cf5672017-09-07 11:50:55 -07002350 case DISAS_STOP:
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002351 gen_save_cpu_state(ctx, true);
2352 if (ctx->base.singlestep_enabled) {
Richard Henderson34cf5672017-09-07 11:50:55 -07002353 gen_helper_debug(cpu_env);
2354 } else {
Richard Henderson07ea28b2018-05-30 18:06:23 -07002355 tcg_gen_exit_tb(NULL, 0);
Richard Henderson34cf5672017-09-07 11:50:55 -07002356 }
2357 break;
2358 case DISAS_NEXT:
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002359 case DISAS_TOO_MANY:
2360 gen_save_cpu_state(ctx, false);
2361 gen_goto_tb(ctx, 0, ctx->base.pc_next);
Richard Henderson34cf5672017-09-07 11:50:55 -07002362 break;
2363 case DISAS_NORETURN:
2364 break;
2365 default:
2366 g_assert_not_reached();
bellardfdf9b3e2006-04-27 21:07:38 +00002367 }
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002368}
ths823029f2007-12-02 06:10:04 +00002369
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002370static void sh4_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
2371{
2372 qemu_log("IN:\n"); /* , lookup_symbol(dcbase->pc_first)); */
2373 log_target_disas(cs, dcbase->pc_first, dcbase->tb->size);
2374}
Richard Henderson0a7df5d2014-03-30 14:50:30 -07002375
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002376static const TranslatorOps sh4_tr_ops = {
2377 .init_disas_context = sh4_tr_init_disas_context,
2378 .tb_start = sh4_tr_tb_start,
2379 .insn_start = sh4_tr_insn_start,
2380 .breakpoint_check = sh4_tr_breakpoint_check,
2381 .translate_insn = sh4_tr_translate_insn,
2382 .tb_stop = sh4_tr_tb_stop,
2383 .disas_log = sh4_tr_disas_log,
2384};
bellardfdf9b3e2006-04-27 21:07:38 +00002385
Richard Henderson8b86d6d2019-04-15 20:54:54 -10002386void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
Emilio G. Cotafd1b3d32018-02-15 21:15:25 -05002387{
2388 DisasContext ctx;
2389
Richard Henderson8b86d6d2019-04-15 20:54:54 -10002390 translator_loop(&sh4_tr_ops, &ctx.base, cs, tb, max_insns);
bellardfdf9b3e2006-04-27 21:07:38 +00002391}
2392
Richard Hendersonbad729e2015-09-01 15:51:12 -07002393void restore_state_to_opc(CPUSH4State *env, TranslationBlock *tb,
2394 target_ulong *data)
aurel32d2856f12008-04-28 00:32:32 +00002395{
Richard Hendersonbad729e2015-09-01 15:51:12 -07002396 env->pc = data[0];
2397 env->flags = data[1];
Aurelien Jarnoac9707e2017-05-01 23:20:43 +02002398 /* Theoretically delayed_pc should also be restored. In practice the
2399 branch instruction is re-executed after exception, so the delayed
2400 branch target will be recomputed. */
aurel32d2856f12008-04-28 00:32:32 +00002401}