* [Qemu-devel] [PATCH v2 0/5] target/sh4 updates
@ 2017-09-07 18:50 Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 1/5] target/sh4: Use cmpxchg for movco when parallel_cpus Richard Henderson
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Richard Henderson @ 2017-09-07 18:50 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
Mostly the update for TranslatorOps.
But also a new implementation of movco using cmpxchg.
Aurelien had previously requested the change exclude
system mode. I've made the change only for parallel_cpus.
r~
Richard Henderson (5):
target/sh4: Use cmpxchg for movco when parallel_cpus
target/sh4: Convert to DisasJumpType
target/sh4: Do not singlestep after exceptions
target/sh4: Convert to DisasContextBase
target/sh4: Convert to TranslatorOps
linux-user/main.c | 19 +-
target/sh4/cpu.h | 4 +-
target/sh4/helper.c | 1 +
target/sh4/translate.c | 490 +++++++++++++++++++++++++++----------------------
4 files changed, 291 insertions(+), 223 deletions(-)
--
2.13.5
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v2 1/5] target/sh4: Use cmpxchg for movco when parallel_cpus
2017-09-07 18:50 [Qemu-devel] [PATCH v2 0/5] target/sh4 updates Richard Henderson
@ 2017-09-07 18:50 ` Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 2/5] target/sh4: Convert to DisasJumpType Richard Henderson
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2017-09-07 18:50 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien, Richard Henderson
From: Richard Henderson <rth@twiddle.net>
As for other targets, cmpxchg isn't quite right for ll/sc,
suffering from an ABA race, but is sufficient to implement
portable atomic operations.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
linux-user/main.c | 19 +++++++++---
target/sh4/cpu.h | 4 ++-
target/sh4/helper.c | 1 +
target/sh4/translate.c | 81 ++++++++++++++++++++++++++++++++++++--------------
4 files changed, 78 insertions(+), 27 deletions(-)
diff --git a/linux-user/main.c b/linux-user/main.c
index 03666ef657..22b3bdafc5 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2665,6 +2665,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);
@@ -2696,13 +2698,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:
@@ -2713,9 +2716,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);
@@ -2723,6 +2726,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
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index 79f85d3365..603614a2d8 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -184,7 +184,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;
diff --git a/target/sh4/helper.c b/target/sh4/helper.c
index 28d93c2543..680b583e53 100644
--- a/target/sh4/helper.c
+++ b/target/sh4/helper.c
@@ -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. */
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 10191073b2..4365b21624 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -70,7 +70,8 @@ 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 */
@@ -156,8 +157,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,
@@ -1558,31 +1563,63 @@ 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 (parallel_cpus) {
+ 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 (parallel_cpus) {
+ 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 */
{
--
2.13.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v2 2/5] target/sh4: Convert to DisasJumpType
2017-09-07 18:50 [Qemu-devel] [PATCH v2 0/5] target/sh4 updates Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 1/5] target/sh4: Use cmpxchg for movco when parallel_cpus Richard Henderson
@ 2017-09-07 18:50 ` Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 3/5] target/sh4: Do not singlestep after exceptions Richard Henderson
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2017-09-07 18:50 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien, Richard Henderson
From: Richard Henderson <rth@twiddle.net>
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
target/sh4/translate.c | 65 +++++++++++++++++++++++---------------------------
1 file changed, 30 insertions(+), 35 deletions(-)
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 4365b21624..6e03370871 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -25,10 +25,9 @@
#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"
@@ -39,7 +38,7 @@ typedef struct DisasContext {
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;
+ DisasJumpType bstate;
int memidx;
int gbank;
int fbank;
@@ -55,14 +54,10 @@ 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->bstate. */
+/* 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_env cpu_env;
@@ -269,6 +264,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
tcg_gen_lookup_and_goto_ptr(cpu_pc);
}
}
+ ctx->bstate = DISAS_NORETURN;
}
static void gen_jump(DisasContext * ctx)
@@ -315,7 +311,7 @@ static void gen_conditional_jump(DisasContext *ctx, target_ulong dest,
gen_goto_tb(ctx, 0, dest);
gen_set_label(l1);
gen_goto_tb(ctx, 1, ctx->pc + 2);
- ctx->bstate = BS_BRANCH;
+ ctx->bstate = DISAS_NORETURN;
}
/* Delayed conditional jump (bt or bf) */
@@ -338,6 +334,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
gen_jump(ctx);
gen_set_label(l1);
+ ctx->bstate = DISAS_NEXT;
return;
}
@@ -479,7 +476,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->bstate = DISAS_STOP;
return;
case 0x0058: /* sets */
tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S));
@@ -490,17 +487,17 @@ 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->bstate = 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->bstate = DISAS_STOP;
return;
case 0xf7fd: /* fpchg */
CHECK_SH4A
tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_PR);
- ctx->bstate = BS_STOP;
+ ctx->bstate = DISAS_STOP;
return;
case 0x0009: /* nop */
return;
@@ -535,7 +532,7 @@ static void _decode_opc(DisasContext * ctx)
region (stored in R0) in the next TB. */
if (B11_8 == 15 && B7_0s < 0 && parallel_cpus) {
ctx->envflags = deposit32(ctx->envflags, GUSA_SHIFT, 8, B7_0s);
- ctx->bstate = BS_STOP;
+ ctx->bstate = DISAS_STOP;
}
#endif
tcg_gen_movi_i32(REG(B11_8), B7_0s);
@@ -1320,7 +1317,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->bstate = DISAS_NORETURN;
}
return;
case 0xc800: /* tst #imm,R0 */
@@ -1429,7 +1426,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->bstate = DISAS_STOP;
}
return;
case 0x4007: /* ldc.l @Rm+,SR */
@@ -1441,7 +1438,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->bstate = DISAS_STOP;
}
return;
case 0x0002: /* stc SR,Rn */
@@ -1503,7 +1500,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->bstate = DISAS_STOP;
return;
case 0x4066: /* lds.l @Rm+,FPSCR */
CHECK_FPU_ENABLED
@@ -1513,7 +1510,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->bstate = DISAS_STOP;
}
return;
case 0x006a: /* sts FPSCR,Rn */
@@ -1849,7 +1846,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->bstate = DISAS_NORETURN;
return;
do_fpu_disabled:
@@ -1859,7 +1856,7 @@ static void _decode_opc(DisasContext * ctx)
} else {
gen_helper_raise_fpu_disable(cpu_env);
}
- ctx->bstate = BS_EXCP;
+ ctx->bstate = DISAS_NORETURN;
return;
}
@@ -1885,7 +1882,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 {
@@ -2256,7 +2252,7 @@ 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->bstate = 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
@@ -2279,7 +2275,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
ctx.pc = pc_start;
ctx.tbflags = (uint32_t)tb->flags;
ctx.envflags = tb->flags & TB_FLAG_ENVFLAGS_MASK;
- ctx.bstate = BS_NONE;
+ ctx.bstate = 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. */
@@ -2317,7 +2313,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
}
#endif
- while (ctx.bstate == BS_NONE
+ while (ctx.bstate == DISAS_NEXT
&& num_insns < max_insns
&& !tcg_op_buf_full()) {
tcg_gen_insn_start(ctx.pc, ctx.envflags);
@@ -2327,7 +2323,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
/* 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.bstate = 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
@@ -2358,19 +2354,18 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
gen_helper_debug(cpu_env);
} else {
switch (ctx.bstate) {
- case BS_STOP:
+ case DISAS_STOP:
gen_save_cpu_state(&ctx, true);
tcg_gen_exit_tb(0);
break;
- case BS_NONE:
+ case DISAS_NEXT:
gen_save_cpu_state(&ctx, false);
gen_goto_tb(&ctx, 0, ctx.pc);
break;
- case BS_EXCP:
- /* fall through */
- case BS_BRANCH:
- default:
+ case DISAS_NORETURN:
break;
+ default:
+ g_assert_not_reached();
}
}
--
2.13.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v2 3/5] target/sh4: Do not singlestep after exceptions
2017-09-07 18:50 [Qemu-devel] [PATCH v2 0/5] target/sh4 updates Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 1/5] target/sh4: Use cmpxchg for movco when parallel_cpus Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 2/5] target/sh4: Convert to DisasJumpType Richard Henderson
@ 2017-09-07 18:50 ` Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 4/5] target/sh4: Convert to DisasContextBase Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 5/5] target/sh4: Convert to TranslatorOps Richard Henderson
4 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2017-09-07 18:50 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien, Richard Henderson
From: Richard Henderson <rth@twiddle.net>
If we've already raised an exception (and set NORETURN),
do not emit unreachable code to raise a debug exception.
Note that gen_goto_tb takes single-stepping into account.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
target/sh4/translate.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 6e03370871..5cda27cc0a 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -281,6 +281,7 @@ static void gen_jump(DisasContext * ctx)
} else {
tcg_gen_lookup_and_goto_ptr(cpu_pc);
}
+ ctx->bstate = DISAS_NORETURN;
} else {
gen_goto_tb(ctx, 0, ctx->delayed_pc);
}
@@ -2349,24 +2350,23 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
ctx.envflags &= ~GUSA_MASK;
}
- if (cs->singlestep_enabled) {
+ switch (ctx.bstate) {
+ case DISAS_STOP:
gen_save_cpu_state(&ctx, true);
- gen_helper_debug(cpu_env);
- } else {
- switch (ctx.bstate) {
- case DISAS_STOP:
- gen_save_cpu_state(&ctx, true);
+ if (cs->singlestep_enabled) {
+ gen_helper_debug(cpu_env);
+ } else {
tcg_gen_exit_tb(0);
- break;
- case DISAS_NEXT:
- gen_save_cpu_state(&ctx, false);
- gen_goto_tb(&ctx, 0, ctx.pc);
- break;
- case DISAS_NORETURN:
- break;
- default:
- g_assert_not_reached();
- }
+ }
+ break;
+ case DISAS_NEXT:
+ gen_save_cpu_state(&ctx, false);
+ gen_goto_tb(&ctx, 0, ctx.pc);
+ break;
+ case DISAS_NORETURN:
+ break;
+ default:
+ g_assert_not_reached();
}
gen_tb_end(tb, num_insns);
--
2.13.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v2 4/5] target/sh4: Convert to DisasContextBase
2017-09-07 18:50 [Qemu-devel] [PATCH v2 0/5] target/sh4 updates Richard Henderson
` (2 preceding siblings ...)
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 3/5] target/sh4: Do not singlestep after exceptions Richard Henderson
@ 2017-09-07 18:50 ` Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 5/5] target/sh4: Convert to TranslatorOps Richard Henderson
4 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2017-09-07 18:50 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien, Richard Henderson
From: Richard Henderson <rth@twiddle.net>
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
target/sh4/translate.c | 146 ++++++++++++++++++++++++-------------------------
1 file changed, 73 insertions(+), 73 deletions(-)
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 5cda27cc0a..ed462bab12 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -33,19 +33,19 @@
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 */
- DisasJumpType 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)
@@ -54,7 +54,7 @@ typedef struct DisasContext {
#define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD)))
#endif
-/* Target-specific values for ctx->bstate. */
+/* 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
@@ -220,7 +220,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);
@@ -238,11 +238,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
@@ -253,10 +253,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);
@@ -264,7 +264,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
tcg_gen_lookup_and_goto_ptr(cpu_pc);
}
}
- ctx->bstate = DISAS_NORETURN;
+ ctx->base.is_jmp = DISAS_NORETURN;
}
static void gen_jump(DisasContext * ctx)
@@ -274,14 +274,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(cpu_pc);
}
- ctx->bstate = DISAS_NORETURN;
+ ctx->base.is_jmp = DISAS_NORETURN;
} else {
gen_goto_tb(ctx, 0, ctx->delayed_pc);
}
@@ -311,8 +311,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 = DISAS_NORETURN;
+ gen_goto_tb(ctx, 1, ctx->base.pc_next + 2);
+ ctx->base.is_jmp = DISAS_NORETURN;
}
/* Delayed conditional jump (bt or bf) */
@@ -335,12 +335,12 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
gen_jump(ctx);
gen_set_label(l1);
- ctx->bstate = DISAS_NEXT;
+ 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);
}
@@ -477,7 +477,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 = DISAS_STOP;
+ ctx->base.is_jmp = DISAS_STOP;
return;
case 0x0058: /* sets */
tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S));
@@ -488,23 +488,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 = DISAS_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 = DISAS_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 = DISAS_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;
}
@@ -533,21 +533,21 @@ static void _decode_opc(DisasContext * ctx)
region (stored in R0) in the next TB. */
if (B11_8 == 15 && B7_0s < 0 && parallel_cpus) {
ctx->envflags = deposit32(ctx->envflags, GUSA_SHIFT, 8, B7_0s);
- ctx->bstate = DISAS_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);
}
@@ -557,13 +557,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;
}
@@ -1190,22 +1190,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 */
@@ -1292,7 +1292,7 @@ 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);
@@ -1318,7 +1318,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 = DISAS_NORETURN;
+ ctx->base.is_jmp = DISAS_NORETURN;
}
return;
case 0xc800: /* tst #imm,R0 */
@@ -1386,13 +1386,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;
@@ -1415,7 +1415,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;
@@ -1427,7 +1427,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 = DISAS_STOP;
+ ctx->base.is_jmp = DISAS_STOP;
}
return;
case 0x4007: /* ldc.l @Rm+,SR */
@@ -1439,7 +1439,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 = DISAS_STOP;
+ ctx->base.is_jmp = DISAS_STOP;
}
return;
case 0x0002: /* stc SR,Rn */
@@ -1501,7 +1501,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 = DISAS_STOP;
+ ctx->base.is_jmp = DISAS_STOP;
return;
case 0x4066: /* lds.l @Rm+,FPSCR */
CHECK_FPU_ENABLED
@@ -1511,7 +1511,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 = DISAS_STOP;
+ ctx->base.is_jmp = DISAS_STOP;
}
return;
case 0x006a: /* sts FPSCR,Rn */
@@ -1835,7 +1835,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:
@@ -1847,7 +1847,7 @@ static void _decode_opc(DisasContext * ctx)
gen_save_cpu_state(ctx, true);
gen_helper_raise_illegal_instruction(cpu_env);
}
- ctx->bstate = DISAS_NORETURN;
+ ctx->base.is_jmp = DISAS_NORETURN;
return;
do_fpu_disabled:
@@ -1857,7 +1857,7 @@ static void _decode_opc(DisasContext * ctx)
} else {
gen_helper_raise_fpu_disable(cpu_env);
}
- ctx->bstate = DISAS_NORETURN;
+ ctx->base.is_jmp = DISAS_NORETURN;
return;
}
@@ -1909,8 +1909,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;
@@ -2240,7 +2240,7 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
/* The entire region has been translated. */
ctx->envflags &= ~GUSA_MASK;
- ctx->pc = pc_end;
+ ctx->base.pc_next = pc_end;
return max_insns;
fail:
@@ -2253,13 +2253,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 = DISAS_NORETURN;
+ 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
@@ -2273,16 +2273,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 = DISAS_NEXT;
+ 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)) &&
@@ -2297,11 +2297,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;
}
@@ -2314,22 +2314,22 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
}
#endif
- while (ctx.bstate == DISAS_NEXT
+ 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 = DISAS_NORETURN;
+ 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;
}
@@ -2337,9 +2337,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 & CF_LAST_IO) {
gen_io_end();
@@ -2350,10 +2350,10 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
ctx.envflags &= ~GUSA_MASK;
}
- switch (ctx.bstate) {
+ switch (ctx.base.is_jmp) {
case DISAS_STOP:
gen_save_cpu_state(&ctx, true);
- if (cs->singlestep_enabled) {
+ if (ctx.base.singlestep_enabled) {
gen_helper_debug(cpu_env);
} else {
tcg_gen_exit_tb(0);
@@ -2361,7 +2361,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
break;
case DISAS_NEXT:
gen_save_cpu_state(&ctx, false);
- gen_goto_tb(&ctx, 0, ctx.pc);
+ gen_goto_tb(&ctx, 0, ctx.base.pc_next);
break;
case DISAS_NORETURN:
break;
@@ -2371,7 +2371,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
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
@@ -2379,7 +2379,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, 0);
+ log_target_disas(cs, pc_start, ctx.base.pc_next - pc_start, 0);
qemu_log("\n");
qemu_log_unlock();
}
--
2.13.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v2 5/5] target/sh4: Convert to TranslatorOps
2017-09-07 18:50 [Qemu-devel] [PATCH v2 0/5] target/sh4 updates Richard Henderson
` (3 preceding siblings ...)
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 4/5] target/sh4: Convert to DisasContextBase Richard Henderson
@ 2017-09-07 18:50 ` Richard Henderson
4 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2017-09-07 18:50 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien, Richard Henderson
From: Richard Henderson <rth@twiddle.net>
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
target/sh4/translate.c | 272 ++++++++++++++++++++++++++-----------------------
1 file changed, 147 insertions(+), 125 deletions(-)
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index ed462bab12..ca6589047b 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -34,6 +34,9 @@
typedef struct DisasContext {
DisasContextBase base;
+#ifdef CONFIG_USER_ONLY
+ TranslatorOps ops;
+#endif
uint32_t tbflags; /* should stay unmodified during the TB translation */
uint32_t envflags; /* should stay in sync with env->flags using TCG ops */
@@ -1892,6 +1895,100 @@ static void decode_opc(DisasContext * ctx)
}
#ifdef CONFIG_USER_ONLY
+static void sh4_tr_translate_gusa(DisasContextBase *dcbase, CPUState *cpu);
+#endif
+
+static int sh4_tr_init_disas_context(DisasContextBase *dcbase,
+ CPUState *cpu, int max_insns)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ CPUSH4State *env = cpu->env_ptr;
+ uint32_t pc = ctx->base.pc_next;
+ uint32_t tbflags = ctx->base.tb->flags;
+ int bound;
+
+ ctx->tbflags = tbflags;
+ ctx->envflags = tbflags & TB_FLAG_ENVFLAGS_MASK;
+ ctx->memidx = (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->features = env->features;
+ ctx->has_movcal = (tbflags & TB_FLAG_PENDING_MOVCA) != 0;
+ ctx->gbank = ((tbflags & (1 << SR_MD)) &&
+ (tbflags & (1 << SR_RB))) * 0x10;
+ ctx->fbank = tbflags & FPSCR_FR ? 0x10 : 0;
+
+ /* Since the ISA is fixed-width, we can bound by the number
+ of instructions remaining on the page. */
+ bound = -(pc | TARGET_PAGE_MASK) / 2;
+ max_insns = MIN(max_insns, bound);
+
+#ifdef CONFIG_USER_ONLY
+ if (tbflags & GUSA_MASK) {
+ uint32_t pc_end = ctx->base.tb->cs_base;
+ int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8);
+ int gusa_insns = -backup / 2;
+
+ if (pc != pc_end + backup || gusa_insns < 2) {
+ /* This is a malformed gUSA region. Don't do anything special,
+ since the interpreter is likely to get confused. */
+ ctx->envflags &= ~GUSA_MASK;
+ } else if (tbflags & GUSA_EXCLUSIVE) {
+ /* Regardless of single-stepping or the end of the page,
+ we must complete execution of the gUSA region while
+ holding the exclusive lock. */
+ max_insns = gusa_insns;
+ } else {
+ /* Attempt to translate to an atomic insn. */
+ ctx->ops.translate_insn = sh4_tr_translate_gusa;
+ }
+ }
+#endif
+
+ return max_insns;
+}
+
+static void sh4_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
+{
+}
+
+static void sh4_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+
+ tcg_gen_insn_start(ctx->base.pc_next, ctx->envflags);
+}
+
+static bool sh4_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
+ const CPUBreakpoint *bp)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+
+ /* We have hit a breakpoint - make sure PC is up-to-date */
+ gen_save_cpu_state(ctx, true);
+ gen_helper_debug(cpu_env);
+ 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->base.pc_next += 2;
+ return true;
+}
+
+static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ CPUSH4State *env = cpu->env_ptr;
+
+ ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next);
+ decode_opc(ctx);
+ ctx->base.pc_next += 2;
+}
+
+#ifdef CONFIG_USER_ONLY
/* For uniprocessors, SH4 uses optimistic restartable atomic sequences.
Upon an interrupt, a real kernel would simply notice magic values in
the registers and reset the PC to the start of the sequence.
@@ -1901,35 +1998,23 @@ static void decode_opc(DisasContext * ctx)
any sequence via cpu_exec_step_atomic, we can recognize the "normal"
sequences and transform them into atomic operations as seen by the host.
*/
-static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
+static void sh4_tr_translate_gusa(DisasContextBase *dcbase, CPUState *cpu)
{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ CPUSH4State *env = cpu->env_ptr;
+
+ int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8);
+ int max_insns = -backup / 2;
+ uint32_t pc = ctx->base.pc_next;
+ uint32_t pc_end = ctx->base.tb->cs_base;
+
uint16_t insns[5];
int ld_adr, ld_dst, ld_mop;
int op_dst, op_src, op_opc;
int mv_src, mt_dst, st_src, st_mop;
TCGv op_arg;
-
- 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;
- if (pc != pc_end + backup || max_insns < 2) {
- /* This is a malformed gUSA region. Don't do anything special,
- since the interpreter is likely to get confused. */
- ctx->envflags &= ~GUSA_MASK;
- return 0;
- }
-
- if (ctx->tbflags & GUSA_EXCLUSIVE) {
- /* Regardless of single-stepping or the end of the page,
- we must complete execution of the gUSA region while
- holding the exclusive lock. */
- *pmax_insns = max_insns;
- return 0;
- }
-
/* The state machine below will consume only a few insns.
If there are more than that in a region, fail now. */
if (max_insns > ARRAY_SIZE(insns)) {
@@ -2146,7 +2231,6 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
/*
* Emit the operation.
*/
- tcg_gen_insn_start(pc, ctx->envflags);
switch (op_opc) {
case -1:
/* No operation found. Look for exchange pattern. */
@@ -2239,9 +2323,13 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
}
/* The entire region has been translated. */
- ctx->envflags &= ~GUSA_MASK;
ctx->base.pc_next = pc_end;
- return max_insns;
+ ctx->base.num_insns = max_insns;
+
+ /* Revert to normal parsing for the rest of the TB. */
+ ctx->envflags &= ~GUSA_MASK;
+ ctx->ops.translate_insn = sh4_tr_translate_insn;
+ return;
fail:
qemu_log_mask(LOG_UNIMP, "Unrecognized gUSA sequence %08x-%08x\n",
@@ -2249,7 +2337,6 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
/* Restart with the EXCLUSIVE bit set, within a TB run via
cpu_exec_step_atomic holding the exclusive lock. */
- tcg_gen_insn_start(pc, ctx->envflags);
ctx->envflags |= GUSA_EXCLUSIVE;
gen_save_cpu_state(ctx, false);
gen_helper_exclusive(cpu_env);
@@ -2260,129 +2347,64 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns)
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
-void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
+static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
{
- CPUSH4State *env = cs->env_ptr;
- DisasContext ctx;
- target_ulong pc_start;
- int num_insns;
- int max_insns;
-
- pc_start = tb->pc;
- ctx.base.pc_next = pc_start;
- ctx.tbflags = (uint32_t)tb->flags;
- ctx.envflags = tb->flags & TB_FLAG_ENVFLAGS_MASK;
- 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.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)) &&
- (ctx.tbflags & (1 << SR_RB))) * 0x10;
- ctx.fbank = ctx.tbflags & FPSCR_FR ? 0x10 : 0;
-
- max_insns = tb->cflags & CF_COUNT_MASK;
- if (max_insns == 0) {
- max_insns = CF_COUNT_MASK;
- }
- max_insns = MIN(max_insns, TCG_MAX_INSNS);
-
- /* Since the ISA is fixed-width, we can bound by the number
- of instructions remaining on the page. */
- num_insns = -(ctx.base.pc_next | TARGET_PAGE_MASK) / 2;
- max_insns = MIN(max_insns, num_insns);
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
- /* Single stepping means just that. */
- if (ctx.base.singlestep_enabled || singlestep) {
- max_insns = 1;
- }
-
- gen_tb_start(tb);
- num_insns = 0;
-
-#ifdef CONFIG_USER_ONLY
- if (ctx.tbflags & GUSA_MASK) {
- num_insns = decode_gusa(&ctx, env, &max_insns);
- }
-#endif
-
- while (ctx.base.is_jmp == DISAS_NEXT
- && num_insns < max_insns
- && !tcg_op_buf_full()) {
- tcg_gen_insn_start(ctx.base.pc_next, ctx.envflags);
- num_insns++;
-
- 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.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.base.pc_next += 2;
- break;
- }
-
- if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
- gen_io_start();
- }
-
- ctx.opcode = cpu_lduw_code(env, ctx.base.pc_next);
- decode_opc(&ctx);
- ctx.base.pc_next += 2;
- }
- if (tb->cflags & CF_LAST_IO) {
- gen_io_end();
- }
-
- if (ctx.tbflags & GUSA_EXCLUSIVE) {
+ if (ctx->tbflags & GUSA_EXCLUSIVE) {
/* Ending the region of exclusivity. Clear the bits. */
- ctx.envflags &= ~GUSA_MASK;
+ ctx->envflags &= ~GUSA_MASK;
}
- switch (ctx.base.is_jmp) {
+ switch (ctx->base.is_jmp) {
case DISAS_STOP:
- gen_save_cpu_state(&ctx, true);
- if (ctx.base.singlestep_enabled) {
+ gen_save_cpu_state(ctx, true);
+ if (ctx->base.singlestep_enabled) {
gen_helper_debug(cpu_env);
} else {
tcg_gen_exit_tb(0);
}
break;
- case DISAS_NEXT:
- gen_save_cpu_state(&ctx, false);
- gen_goto_tb(&ctx, 0, ctx.base.pc_next);
+ case DISAS_TOO_MANY:
+ 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);
+static void sh4_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
+{
+ qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
+ log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size, 0);
+}
- tb->size = ctx.base.pc_next - pc_start;
- tb->icount = num_insns;
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
+{
+ static const TranslatorOps ops = {
+ .init_disas_context = sh4_tr_init_disas_context,
+ .tb_start = sh4_tr_tb_start,
+ .insn_start = sh4_tr_insn_start,
+ .breakpoint_check = sh4_tr_breakpoint_check,
+ .translate_insn = sh4_tr_translate_insn,
+ .tb_stop = sh4_tr_tb_stop,
+ .disas_log = sh4_tr_disas_log,
+ };
+ DisasContext ctx;
-#ifdef DEBUG_DISAS
- if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
- && 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.base.pc_next - pc_start, 0);
- qemu_log("\n");
- qemu_log_unlock();
- }
+#ifdef CONFIG_USER_ONLY
+ /* We may switch the translate_insn hook in init_disas_context
+ and within translate_insn itself. */
+ ctx.ops = ops;
+ translator_loop(&ctx.ops, &ctx.base, cpu, tb);
+#else
+ translator_loop(&ops, &ctx.base, cpu, tb);
#endif
}
--
2.13.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2017-09-07 18:51 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-09-07 18:50 [Qemu-devel] [PATCH v2 0/5] target/sh4 updates Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 1/5] target/sh4: Use cmpxchg for movco when parallel_cpus Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 2/5] target/sh4: Convert to DisasJumpType Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 3/5] target/sh4: Do not singlestep after exceptions Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 4/5] target/sh4: Convert to DisasContextBase Richard Henderson
2017-09-07 18:50 ` [Qemu-devel] [PATCH v2 5/5] target/sh4: Convert to TranslatorOps Richard Henderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).