mirror of https://github.com/xemu-project/xemu.git
Queued target/sh4 patches
-----BEGIN PGP SIGNATURE----- iQJJBAABCgAzFiEEUryGlb40+QrX1Ay4E4jA+JnoM2sFAlo4QvoVHGF1cmVsaWVu QGF1cmVsMzIubmV0AAoJEBOIwPiZ6DNrUe4P/3YaM5lsq9OTgE1abOmI5NyqWQE/ l7YQwToYzt45jdXgcOOG6KqQevFfPuX24SZYmkuOhRj+UvpedFilEc4Nsx3AvejR dI5g0b9mrvcS3DjvjQsYgGC+S6BoauuQdqJrZKkWL5xkkUSq22PYNm0K3doBrNU4 rOGpNXXpZ+8jWACmeDrZ+Hj4HMokd/G35LxIr3fJHaEgN0NK0YjwlVP/LmxTJb48 gmdIWPyZaevzxPunN3aaZXo3B4u6vrSsAxhHfIYTTj6xpFb/jouSOldFMrHVx764 RbDvS9qh7FBr3dyv1ekvDZfBNFuqDWbaC6eV1sYbxpvFNjg2wwlUM2wN3afTAvG5 rWotFOrhNZJ3mV3oQ816JQsqnq1zcGuysp1IsNLz8krv0LNfaVi9dN/ILF5wF8pS l2iZXQK1d6UEPB2N7plYXZWsVT8Qs5d4nsZLIm8tiJTTEwa2lwYxOQdktV6rGv0F oIIDAQD29J3r3mjxBaLoEteM/n8h488MAWTPUgB/1++2JDFtFIIBFyBRI65RxGgQ KdrWSbhUJwqCyiItjdmq+61R/60D2XzIThOLR9brXorTkpMDI7UyxBaKuOrxjzlw ir9jHA92SZeZSN7v5apKh08x/EH1Qy3oo8kgkUEscgx5XmFZlYLa4aHgbr5M4RU/ ci6JWM/ayijrx5Pz =aG1u -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/aurel/tags/pull-target-sh4-20171218' into staging Queued target/sh4 patches # gpg: Signature made Mon 18 Dec 2017 22:36:42 GMT # gpg: using RSA key 0x1388C0F899E8336B # gpg: Good signature from "Aurelien Jarno <aurelien@aurel32.net>" # gpg: aka "Aurelien Jarno <aurelien@jarno.fr>" # gpg: aka "Aurelien Jarno <aurel32@debian.org>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 7746 2642 A9EF 94FD 0F77 196D BA9C 7806 1DDD 8C9B # Subkey fingerprint: 52BC 8695 BE34 F90A D7D4 0CB8 1388 C0F8 99E8 336B * remotes/aurel/tags/pull-target-sh4-20171218: target/sh4: Convert to DisasContextBase target/sh4: Do not singlestep after exceptions target/sh4: Convert to DisasJumpType target/sh4: Use cmpxchg for movco when parallel_cpus target/sh4: fix TCG leak during gusa sequence target/sh4: add missing tcg_temp_free() in _decode_opc() Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
af352675ef
|
@ -2679,6 +2679,8 @@ void cpu_loop(CPUSH4State *env)
|
|||
target_siginfo_t info;
|
||||
|
||||
while (1) {
|
||||
bool arch_interrupt = true;
|
||||
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
|
@ -2710,13 +2712,14 @@ void cpu_loop(CPUSH4State *env)
|
|||
int sig;
|
||||
|
||||
sig = gdb_handlesig(cs, TARGET_SIGTRAP);
|
||||
if (sig)
|
||||
{
|
||||
if (sig) {
|
||||
info.si_signo = sig;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
} else {
|
||||
arch_interrupt = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xa0:
|
||||
|
@ -2727,9 +2730,9 @@ void cpu_loop(CPUSH4State *env)
|
|||
info._sifields._sigfault._addr = env->tea;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
arch_interrupt = false;
|
||||
break;
|
||||
default:
|
||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||
|
@ -2737,6 +2740,14 @@ void cpu_loop(CPUSH4State *env)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
process_pending_signals (env);
|
||||
|
||||
/* Most of the traps imply an exception or interrupt, which
|
||||
implies an REI instruction has been executed. Which means
|
||||
that LDST (aka LOK_ADDR) should be cleared. But there are
|
||||
a few exceptions for traps internal to QEMU. */
|
||||
if (arch_interrupt) {
|
||||
env->lock_addr = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -188,7 +188,9 @@ typedef struct CPUSH4State {
|
|||
tlb_t itlb[ITLB_SIZE]; /* instruction translation table */
|
||||
tlb_t utlb[UTLB_SIZE]; /* unified translation table */
|
||||
|
||||
uint32_t ldst;
|
||||
/* LDST = LOCK_ADDR != -1. */
|
||||
uint32_t lock_addr;
|
||||
uint32_t lock_value;
|
||||
|
||||
/* Fields up to this point are cleared by a CPU reset */
|
||||
struct {} end_reset_fields;
|
||||
|
|
|
@ -171,6 +171,7 @@ void superh_cpu_do_interrupt(CPUState *cs)
|
|||
env->spc = env->pc;
|
||||
env->sgr = env->gregs[15];
|
||||
env->sr |= (1u << SR_BL) | (1u << SR_MD) | (1u << SR_RB);
|
||||
env->lock_addr = -1;
|
||||
|
||||
if (env->flags & DELAY_SLOT_MASK) {
|
||||
/* Branch instruction should be executed again before delay slot. */
|
||||
|
|
|
@ -25,28 +25,27 @@
|
|||
#include "exec/exec-all.h"
|
||||
#include "tcg-op.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
||||
#include "exec/translator.h"
|
||||
#include "trace-tcg.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
|
||||
typedef struct DisasContext {
|
||||
struct TranslationBlock *tb;
|
||||
target_ulong pc;
|
||||
uint16_t opcode;
|
||||
uint32_t tbflags; /* should stay unmodified during the TB translation */
|
||||
uint32_t envflags; /* should stay in sync with env->flags using TCG ops */
|
||||
int bstate;
|
||||
DisasContextBase base;
|
||||
|
||||
uint32_t tbflags; /* should stay unmodified during the TB translation */
|
||||
uint32_t envflags; /* should stay in sync with env->flags using TCG ops */
|
||||
int memidx;
|
||||
int gbank;
|
||||
int fbank;
|
||||
uint32_t delayed_pc;
|
||||
int singlestep_enabled;
|
||||
uint32_t features;
|
||||
int has_movcal;
|
||||
|
||||
uint16_t opcode;
|
||||
|
||||
bool has_movcal;
|
||||
} DisasContext;
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
@ -55,21 +54,18 @@ typedef struct DisasContext {
|
|||
#define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD)))
|
||||
#endif
|
||||
|
||||
enum {
|
||||
BS_NONE = 0, /* We go out of the TB without reaching a branch or an
|
||||
* exception condition
|
||||
*/
|
||||
BS_STOP = 1, /* We want to stop translation for any reason */
|
||||
BS_BRANCH = 2, /* We reached a branch condition */
|
||||
BS_EXCP = 3, /* We reached an exception condition */
|
||||
};
|
||||
/* Target-specific values for ctx->base.is_jmp. */
|
||||
/* We want to exit back to the cpu loop for some reason.
|
||||
Usually this is to recognize interrupts immediately. */
|
||||
#define DISAS_STOP DISAS_TARGET_0
|
||||
|
||||
/* global register indexes */
|
||||
static TCGv cpu_gregs[32];
|
||||
static TCGv cpu_sr, cpu_sr_m, cpu_sr_q, cpu_sr_t;
|
||||
static TCGv cpu_pc, cpu_ssr, cpu_spc, cpu_gbr;
|
||||
static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl;
|
||||
static TCGv cpu_pr, cpu_fpscr, cpu_fpul, cpu_ldst;
|
||||
static TCGv cpu_pr, cpu_fpscr, cpu_fpul;
|
||||
static TCGv cpu_lock_addr, cpu_lock_value;
|
||||
static TCGv cpu_fregs[32];
|
||||
|
||||
/* internal register indexes */
|
||||
|
@ -147,8 +143,12 @@ void sh4_translate_init(void)
|
|||
offsetof(CPUSH4State,
|
||||
delayed_cond),
|
||||
"_delayed_cond_");
|
||||
cpu_ldst = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUSH4State, ldst), "_ldst_");
|
||||
cpu_lock_addr = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUSH4State, lock_addr),
|
||||
"_lock_addr_");
|
||||
cpu_lock_value = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUSH4State, lock_value),
|
||||
"_lock_value_");
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
cpu_fregs[i] = tcg_global_mem_new_i32(cpu_env,
|
||||
|
@ -209,7 +209,7 @@ static void gen_write_sr(TCGv src)
|
|||
static inline void gen_save_cpu_state(DisasContext *ctx, bool save_pc)
|
||||
{
|
||||
if (save_pc) {
|
||||
tcg_gen_movi_i32(cpu_pc, ctx->pc);
|
||||
tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
|
||||
}
|
||||
if (ctx->delayed_pc != (uint32_t) -1) {
|
||||
tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc);
|
||||
|
@ -227,11 +227,11 @@ static inline bool use_exit_tb(DisasContext *ctx)
|
|||
static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
|
||||
{
|
||||
/* Use a direct jump if in same page and singlestep not enabled */
|
||||
if (unlikely(ctx->singlestep_enabled || use_exit_tb(ctx))) {
|
||||
if (unlikely(ctx->base.singlestep_enabled || use_exit_tb(ctx))) {
|
||||
return false;
|
||||
}
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
|
||||
return (ctx->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
@ -242,10 +242,10 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
|
|||
if (use_goto_tb(ctx, dest)) {
|
||||
tcg_gen_goto_tb(n);
|
||||
tcg_gen_movi_i32(cpu_pc, dest);
|
||||
tcg_gen_exit_tb((uintptr_t)ctx->tb + n);
|
||||
tcg_gen_exit_tb((uintptr_t)ctx->base.tb + n);
|
||||
} else {
|
||||
tcg_gen_movi_i32(cpu_pc, dest);
|
||||
if (ctx->singlestep_enabled) {
|
||||
if (ctx->base.singlestep_enabled) {
|
||||
gen_helper_debug(cpu_env);
|
||||
} else if (use_exit_tb(ctx)) {
|
||||
tcg_gen_exit_tb(0);
|
||||
|
@ -253,6 +253,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
|
|||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
}
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_jump(DisasContext * ctx)
|
||||
|
@ -262,13 +263,14 @@ static void gen_jump(DisasContext * ctx)
|
|||
delayed jump as immediate jump are conditinal jumps */
|
||||
tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc);
|
||||
tcg_gen_discard_i32(cpu_delayed_pc);
|
||||
if (ctx->singlestep_enabled) {
|
||||
if (ctx->base.singlestep_enabled) {
|
||||
gen_helper_debug(cpu_env);
|
||||
} else if (use_exit_tb(ctx)) {
|
||||
tcg_gen_exit_tb(0);
|
||||
} else {
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
} else {
|
||||
gen_goto_tb(ctx, 0, ctx->delayed_pc);
|
||||
}
|
||||
|
@ -298,8 +300,8 @@ static void gen_conditional_jump(DisasContext *ctx, target_ulong dest,
|
|||
tcg_gen_brcondi_i32(cond_not_taken, cpu_sr_t, 0, l1);
|
||||
gen_goto_tb(ctx, 0, dest);
|
||||
gen_set_label(l1);
|
||||
gen_goto_tb(ctx, 1, ctx->pc + 2);
|
||||
ctx->bstate = BS_BRANCH;
|
||||
gen_goto_tb(ctx, 1, ctx->base.pc_next + 2);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
/* Delayed conditional jump (bt or bf) */
|
||||
|
@ -322,11 +324,12 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
|
|||
gen_jump(ctx);
|
||||
|
||||
gen_set_label(l1);
|
||||
ctx->base.is_jmp = DISAS_NEXT;
|
||||
return;
|
||||
}
|
||||
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1);
|
||||
gen_goto_tb(ctx, 1, ctx->pc + 2);
|
||||
gen_goto_tb(ctx, 1, ctx->base.pc_next + 2);
|
||||
gen_set_label(l1);
|
||||
gen_jump(ctx);
|
||||
}
|
||||
|
@ -463,7 +466,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc);
|
||||
ctx->envflags |= DELAY_SLOT_RTE;
|
||||
ctx->delayed_pc = (uint32_t) - 1;
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
return;
|
||||
case 0x0058: /* sets */
|
||||
tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S));
|
||||
|
@ -474,23 +477,23 @@ static void _decode_opc(DisasContext * ctx)
|
|||
case 0xfbfd: /* frchg */
|
||||
CHECK_FPSCR_PR_0
|
||||
tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR);
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
return;
|
||||
case 0xf3fd: /* fschg */
|
||||
CHECK_FPSCR_PR_0
|
||||
tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ);
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
return;
|
||||
case 0xf7fd: /* fpchg */
|
||||
CHECK_SH4A
|
||||
tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_PR);
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
return;
|
||||
case 0x0009: /* nop */
|
||||
return;
|
||||
case 0x001b: /* sleep */
|
||||
CHECK_PRIVILEGED
|
||||
tcg_gen_movi_i32(cpu_pc, ctx->pc + 2);
|
||||
tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next + 2);
|
||||
gen_helper_sleep(cpu_env);
|
||||
return;
|
||||
}
|
||||
|
@ -517,23 +520,24 @@ static void _decode_opc(DisasContext * ctx)
|
|||
/* Detect the start of a gUSA region. If so, update envflags
|
||||
and end the TB. This will allow us to see the end of the
|
||||
region (stored in R0) in the next TB. */
|
||||
if (B11_8 == 15 && B7_0s < 0 && (tb_cflags(ctx->tb) & CF_PARALLEL)) {
|
||||
if (B11_8 == 15 && B7_0s < 0 &&
|
||||
(tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
|
||||
ctx->envflags = deposit32(ctx->envflags, GUSA_SHIFT, 8, B7_0s);
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
}
|
||||
#endif
|
||||
tcg_gen_movi_i32(REG(B11_8), B7_0s);
|
||||
return;
|
||||
case 0x9000: /* mov.w @(disp,PC),Rn */
|
||||
{
|
||||
TCGv addr = tcg_const_i32(ctx->pc + 4 + B7_0 * 2);
|
||||
TCGv addr = tcg_const_i32(ctx->base.pc_next + 4 + B7_0 * 2);
|
||||
tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW);
|
||||
tcg_temp_free(addr);
|
||||
}
|
||||
return;
|
||||
case 0xd000: /* mov.l @(disp,PC),Rn */
|
||||
{
|
||||
TCGv addr = tcg_const_i32((ctx->pc + 4 + B7_0 * 4) & ~3);
|
||||
TCGv addr = tcg_const_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3);
|
||||
tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
|
||||
tcg_temp_free(addr);
|
||||
}
|
||||
|
@ -543,13 +547,13 @@ static void _decode_opc(DisasContext * ctx)
|
|||
return;
|
||||
case 0xa000: /* bra disp */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2;
|
||||
ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2;
|
||||
ctx->envflags |= DELAY_SLOT;
|
||||
return;
|
||||
case 0xb000: /* bsr disp */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
|
||||
ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2;
|
||||
tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
|
||||
ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2;
|
||||
ctx->envflags |= DELAY_SLOT;
|
||||
return;
|
||||
}
|
||||
|
@ -601,6 +605,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
tcg_gen_subi_i32(addr, REG(B11_8), 4);
|
||||
tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL);
|
||||
tcg_gen_mov_i32(REG(B11_8), addr);
|
||||
tcg_temp_free(addr);
|
||||
}
|
||||
return;
|
||||
case 0x6004: /* mov.b @Rm+,Rn */
|
||||
|
@ -1176,22 +1181,22 @@ static void _decode_opc(DisasContext * ctx)
|
|||
return;
|
||||
case 0x8b00: /* bf label */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, false);
|
||||
gen_conditional_jump(ctx, ctx->base.pc_next + 4 + B7_0s * 2, false);
|
||||
return;
|
||||
case 0x8f00: /* bf/s label */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
tcg_gen_xori_i32(cpu_delayed_cond, cpu_sr_t, 1);
|
||||
ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2;
|
||||
ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2;
|
||||
ctx->envflags |= DELAY_SLOT_CONDITIONAL;
|
||||
return;
|
||||
case 0x8900: /* bt label */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, true);
|
||||
gen_conditional_jump(ctx, ctx->base.pc_next + 4 + B7_0s * 2, true);
|
||||
return;
|
||||
case 0x8d00: /* bt/s label */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
tcg_gen_mov_i32(cpu_delayed_cond, cpu_sr_t);
|
||||
ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2;
|
||||
ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2;
|
||||
ctx->envflags |= DELAY_SLOT_CONDITIONAL;
|
||||
return;
|
||||
case 0x8800: /* cmp/eq #imm,R0 */
|
||||
|
@ -1278,7 +1283,8 @@ static void _decode_opc(DisasContext * ctx)
|
|||
}
|
||||
return;
|
||||
case 0xc700: /* mova @(disp,PC),R0 */
|
||||
tcg_gen_movi_i32(REG(0), ((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3);
|
||||
tcg_gen_movi_i32(REG(0), ((ctx->base.pc_next & 0xfffffffc) +
|
||||
4 + B7_0 * 4) & ~3);
|
||||
return;
|
||||
case 0xcb00: /* or #imm,R0 */
|
||||
tcg_gen_ori_i32(REG(0), REG(0), B7_0);
|
||||
|
@ -1304,7 +1310,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
imm = tcg_const_i32(B7_0);
|
||||
gen_helper_trapa(cpu_env, imm);
|
||||
tcg_temp_free(imm);
|
||||
ctx->bstate = BS_EXCP;
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
return;
|
||||
case 0xc800: /* tst #imm,R0 */
|
||||
|
@ -1372,13 +1378,13 @@ static void _decode_opc(DisasContext * ctx)
|
|||
switch (ctx->opcode & 0xf0ff) {
|
||||
case 0x0023: /* braf Rn */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->pc + 4);
|
||||
tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->base.pc_next + 4);
|
||||
ctx->envflags |= DELAY_SLOT;
|
||||
ctx->delayed_pc = (uint32_t) - 1;
|
||||
return;
|
||||
case 0x0003: /* bsrf Rn */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
|
||||
tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
|
||||
tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr);
|
||||
ctx->envflags |= DELAY_SLOT;
|
||||
ctx->delayed_pc = (uint32_t) - 1;
|
||||
|
@ -1401,7 +1407,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
return;
|
||||
case 0x400b: /* jsr @Rn */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
tcg_gen_movi_i32(cpu_pr, ctx->pc + 4);
|
||||
tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4);
|
||||
tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8));
|
||||
ctx->envflags |= DELAY_SLOT;
|
||||
ctx->delayed_pc = (uint32_t) - 1;
|
||||
|
@ -1413,7 +1419,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
tcg_gen_andi_i32(val, REG(B11_8), 0x700083f3);
|
||||
gen_write_sr(val);
|
||||
tcg_temp_free(val);
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
}
|
||||
return;
|
||||
case 0x4007: /* ldc.l @Rm+,SR */
|
||||
|
@ -1425,7 +1431,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
gen_write_sr(val);
|
||||
tcg_temp_free(val);
|
||||
tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
}
|
||||
return;
|
||||
case 0x0002: /* stc SR,Rn */
|
||||
|
@ -1487,7 +1493,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
case 0x406a: /* lds Rm,FPSCR */
|
||||
CHECK_FPU_ENABLED
|
||||
gen_helper_ld_fpscr(cpu_env, REG(B11_8));
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
return;
|
||||
case 0x4066: /* lds.l @Rm+,FPSCR */
|
||||
CHECK_FPU_ENABLED
|
||||
|
@ -1497,7 +1503,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
|
||||
gen_helper_ld_fpscr(cpu_env, addr);
|
||||
tcg_temp_free(addr);
|
||||
ctx->bstate = BS_STOP;
|
||||
ctx->base.is_jmp = DISAS_STOP;
|
||||
}
|
||||
return;
|
||||
case 0x006a: /* sts FPSCR,Rn */
|
||||
|
@ -1524,6 +1530,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
tcg_gen_qemu_ld_i32(val, REG(B11_8), ctx->memidx, MO_TEUL);
|
||||
gen_helper_movcal(cpu_env, REG(B11_8), val);
|
||||
tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL);
|
||||
tcg_temp_free(val);
|
||||
}
|
||||
ctx->has_movcal = 1;
|
||||
return;
|
||||
|
@ -1547,31 +1554,64 @@ static void _decode_opc(DisasContext * ctx)
|
|||
return;
|
||||
case 0x0073:
|
||||
/* MOVCO.L
|
||||
LDST -> T
|
||||
If (T == 1) R0 -> (Rn)
|
||||
0 -> LDST
|
||||
*/
|
||||
* LDST -> T
|
||||
* If (T == 1) R0 -> (Rn)
|
||||
* 0 -> LDST
|
||||
*
|
||||
* The above description doesn't work in a parallel context.
|
||||
* Since we currently support no smp boards, this implies user-mode.
|
||||
* But we can still support the official mechanism while user-mode
|
||||
* is single-threaded. */
|
||||
CHECK_SH4A
|
||||
{
|
||||
TCGLabel *label = gen_new_label();
|
||||
tcg_gen_mov_i32(cpu_sr_t, cpu_ldst);
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ldst, 0, label);
|
||||
tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL);
|
||||
gen_set_label(label);
|
||||
tcg_gen_movi_i32(cpu_ldst, 0);
|
||||
return;
|
||||
TCGLabel *fail = gen_new_label();
|
||||
TCGLabel *done = gen_new_label();
|
||||
|
||||
if ((tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
|
||||
TCGv tmp;
|
||||
|
||||
tcg_gen_brcond_i32(TCG_COND_NE, REG(B11_8),
|
||||
cpu_lock_addr, fail);
|
||||
tmp = tcg_temp_new();
|
||||
tcg_gen_atomic_cmpxchg_i32(tmp, REG(B11_8), cpu_lock_value,
|
||||
REG(0), ctx->memidx, MO_TEUL);
|
||||
tcg_gen_setcond_i32(TCG_COND_EQ, cpu_sr_t, tmp, cpu_lock_value);
|
||||
tcg_temp_free(tmp);
|
||||
} else {
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_lock_addr, -1, fail);
|
||||
tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL);
|
||||
tcg_gen_movi_i32(cpu_sr_t, 1);
|
||||
}
|
||||
tcg_gen_br(done);
|
||||
|
||||
gen_set_label(fail);
|
||||
tcg_gen_movi_i32(cpu_sr_t, 0);
|
||||
|
||||
gen_set_label(done);
|
||||
tcg_gen_movi_i32(cpu_lock_addr, -1);
|
||||
}
|
||||
return;
|
||||
case 0x0063:
|
||||
/* MOVLI.L @Rm,R0
|
||||
1 -> LDST
|
||||
(Rm) -> R0
|
||||
When interrupt/exception
|
||||
occurred 0 -> LDST
|
||||
*/
|
||||
* 1 -> LDST
|
||||
* (Rm) -> R0
|
||||
* When interrupt/exception
|
||||
* occurred 0 -> LDST
|
||||
*
|
||||
* In a parallel context, we must also save the loaded value
|
||||
* for use with the cmpxchg that we'll use with movco.l. */
|
||||
CHECK_SH4A
|
||||
tcg_gen_movi_i32(cpu_ldst, 0);
|
||||
tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL);
|
||||
tcg_gen_movi_i32(cpu_ldst, 1);
|
||||
if ((tb_cflags(ctx->base.tb) & CF_PARALLEL)) {
|
||||
TCGv tmp = tcg_temp_new();
|
||||
tcg_gen_mov_i32(tmp, REG(B11_8));
|
||||
tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL);
|
||||
tcg_gen_mov_i32(cpu_lock_value, REG(0));
|
||||
tcg_gen_mov_i32(cpu_lock_addr, tmp);
|
||||
tcg_temp_free(tmp);
|
||||
} else {
|
||||
tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL);
|
||||
tcg_gen_movi_i32(cpu_lock_addr, 0);
|
||||
}
|
||||
return;
|
||||
case 0x0093: /* ocbi @Rn */
|
||||
{
|
||||
|
@ -1789,7 +1829,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
}
|
||||
#if 0
|
||||
fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
|
||||
ctx->opcode, ctx->pc);
|
||||
ctx->opcode, ctx->base.pc_next);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
do_illegal:
|
||||
|
@ -1801,7 +1841,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
gen_save_cpu_state(ctx, true);
|
||||
gen_helper_raise_illegal_instruction(cpu_env);
|
||||
}
|
||||
ctx->bstate = BS_EXCP;
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return;
|
||||
|
||||
do_fpu_disabled:
|
||||
|
@ -1811,7 +1851,7 @@ static void _decode_opc(DisasContext * ctx)
|
|||
} else {
|
||||
gen_helper_raise_fpu_disable(cpu_env);
|
||||
}
|
||||
ctx->bstate = BS_EXCP;
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1837,7 +1877,6 @@ static void decode_opc(DisasContext * ctx)
|
|||
ctx->envflags &= ~GUSA_MASK;
|
||||
|
||||
tcg_gen_movi_i32(cpu_flags, ctx->envflags);
|
||||
ctx->bstate = BS_BRANCH;
|
||||
if (old_flags & DELAY_SLOT_CONDITIONAL) {
|
||||
gen_delayed_conditional_jump(ctx);
|
||||
} else {
|
||||
|
@ -1864,8 +1903,8 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
|
|||
int mv_src, mt_dst, st_src, st_mop;
|
||||
TCGv op_arg;
|
||||
|
||||
uint32_t pc = ctx->pc;
|
||||
uint32_t pc_end = ctx->tb->cs_base;
|
||||
uint32_t pc = ctx->base.pc_next;
|
||||
uint32_t pc_end = ctx->base.tb->cs_base;
|
||||
int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8);
|
||||
int max_insns = (pc_end - pc) / 2;
|
||||
int i;
|
||||
|
@ -2189,13 +2228,13 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
|
|||
}
|
||||
|
||||
/* If op_src is not a valid register, then op_arg was a constant. */
|
||||
if (op_src < 0) {
|
||||
if (op_src < 0 && !TCGV_IS_UNUSED(op_arg)) {
|
||||
tcg_temp_free_i32(op_arg);
|
||||
}
|
||||
|
||||
/* The entire region has been translated. */
|
||||
ctx->envflags &= ~GUSA_MASK;
|
||||
ctx->pc = pc_end;
|
||||
ctx->base.pc_next = pc_end;
|
||||
return max_insns;
|
||||
|
||||
fail:
|
||||
|
@ -2208,13 +2247,13 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
|
|||
ctx->envflags |= GUSA_EXCLUSIVE;
|
||||
gen_save_cpu_state(ctx, false);
|
||||
gen_helper_exclusive(cpu_env);
|
||||
ctx->bstate = BS_EXCP;
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
/* We're not executing an instruction, but we must report one for the
|
||||
purposes of accounting within the TB. We might as well report the
|
||||
entire region consumed via ctx->pc so that it's immediately available
|
||||
in the disassembly dump. */
|
||||
ctx->pc = pc_end;
|
||||
entire region consumed via ctx->base.pc_next so that it's immediately
|
||||
available in the disassembly dump. */
|
||||
ctx->base.pc_next = pc_end;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
@ -2228,16 +2267,16 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
|||
int max_insns;
|
||||
|
||||
pc_start = tb->pc;
|
||||
ctx.pc = pc_start;
|
||||
ctx.base.pc_next = pc_start;
|
||||
ctx.tbflags = (uint32_t)tb->flags;
|
||||
ctx.envflags = tb->flags & TB_FLAG_ENVFLAGS_MASK;
|
||||
ctx.bstate = BS_NONE;
|
||||
ctx.base.is_jmp = DISAS_NEXT;
|
||||
ctx.memidx = (ctx.tbflags & (1u << SR_MD)) == 0 ? 1 : 0;
|
||||
/* We don't know if the delayed pc came from a dynamic or static branch,
|
||||
so assume it is a dynamic branch. */
|
||||
ctx.delayed_pc = -1; /* use delayed pc from env pointer */
|
||||
ctx.tb = tb;
|
||||
ctx.singlestep_enabled = cs->singlestep_enabled;
|
||||
ctx.base.tb = tb;
|
||||
ctx.base.singlestep_enabled = cs->singlestep_enabled;
|
||||
ctx.features = env->features;
|
||||
ctx.has_movcal = (ctx.tbflags & TB_FLAG_PENDING_MOVCA);
|
||||
ctx.gbank = ((ctx.tbflags & (1 << SR_MD)) &&
|
||||
|
@ -2252,11 +2291,11 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
|||
|
||||
/* Since the ISA is fixed-width, we can bound by the number
|
||||
of instructions remaining on the page. */
|
||||
num_insns = -(ctx.pc | TARGET_PAGE_MASK) / 2;
|
||||
num_insns = -(ctx.base.pc_next | TARGET_PAGE_MASK) / 2;
|
||||
max_insns = MIN(max_insns, num_insns);
|
||||
|
||||
/* Single stepping means just that. */
|
||||
if (ctx.singlestep_enabled || singlestep) {
|
||||
if (ctx.base.singlestep_enabled || singlestep) {
|
||||
max_insns = 1;
|
||||
}
|
||||
|
||||
|
@ -2269,22 +2308,22 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
|||
}
|
||||
#endif
|
||||
|
||||
while (ctx.bstate == BS_NONE
|
||||
while (ctx.base.is_jmp == DISAS_NEXT
|
||||
&& num_insns < max_insns
|
||||
&& !tcg_op_buf_full()) {
|
||||
tcg_gen_insn_start(ctx.pc, ctx.envflags);
|
||||
tcg_gen_insn_start(ctx.base.pc_next, ctx.envflags);
|
||||
num_insns++;
|
||||
|
||||
if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
|
||||
if (unlikely(cpu_breakpoint_test(cs, ctx.base.pc_next, BP_ANY))) {
|
||||
/* We have hit a breakpoint - make sure PC is up-to-date */
|
||||
gen_save_cpu_state(&ctx, true);
|
||||
gen_helper_debug(cpu_env);
|
||||
ctx.bstate = BS_EXCP;
|
||||
ctx.base.is_jmp = DISAS_NORETURN;
|
||||
/* The address covered by the breakpoint must be included in
|
||||
[tb->pc, tb->pc + tb->size) in order to for it to be
|
||||
properly cleared -- thus we increment the PC here so that
|
||||
the logic setting tb->size below does the right thing. */
|
||||
ctx.pc += 2;
|
||||
ctx.base.pc_next += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2292,9 +2331,9 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
|||
gen_io_start();
|
||||
}
|
||||
|
||||
ctx.opcode = cpu_lduw_code(env, ctx.pc);
|
||||
ctx.opcode = cpu_lduw_code(env, ctx.base.pc_next);
|
||||
decode_opc(&ctx);
|
||||
ctx.pc += 2;
|
||||
ctx.base.pc_next += 2;
|
||||
}
|
||||
if (tb_cflags(tb) & CF_LAST_IO) {
|
||||
gen_io_end();
|
||||
|
@ -2305,30 +2344,28 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
|||
ctx.envflags &= ~GUSA_MASK;
|
||||
}
|
||||
|
||||
if (cs->singlestep_enabled) {
|
||||
switch (ctx.base.is_jmp) {
|
||||
case DISAS_STOP:
|
||||
gen_save_cpu_state(&ctx, true);
|
||||
gen_helper_debug(cpu_env);
|
||||
} else {
|
||||
switch (ctx.bstate) {
|
||||
case BS_STOP:
|
||||
gen_save_cpu_state(&ctx, true);
|
||||
if (ctx.base.singlestep_enabled) {
|
||||
gen_helper_debug(cpu_env);
|
||||
} else {
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case BS_NONE:
|
||||
gen_save_cpu_state(&ctx, false);
|
||||
gen_goto_tb(&ctx, 0, ctx.pc);
|
||||
break;
|
||||
case BS_EXCP:
|
||||
/* fall through */
|
||||
case BS_BRANCH:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DISAS_NEXT:
|
||||
gen_save_cpu_state(&ctx, false);
|
||||
gen_goto_tb(&ctx, 0, ctx.base.pc_next);
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
gen_tb_end(tb, num_insns);
|
||||
|
||||
tb->size = ctx.pc - pc_start;
|
||||
tb->size = ctx.base.pc_next - pc_start;
|
||||
tb->icount = num_insns;
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
|
@ -2336,7 +2373,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
|||
&& qemu_log_in_addr_range(pc_start)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("IN:\n"); /* , lookup_symbol(pc_start)); */
|
||||
log_target_disas(cs, pc_start, ctx.pc - pc_start);
|
||||
log_target_disas(cs, pc_start, ctx.base.pc_next - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue