target-alpha: Emit goto_tb opcodes.
Use an ExitStatus enumeration instead of magic numbers as the return value from translate_one. Emit goto_tb opcodes when ending a TB via a direct branch. Signed-off-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
593f17e5f2
commit
4af7037462
@ -43,12 +43,13 @@
|
|||||||
|
|
||||||
typedef struct DisasContext DisasContext;
|
typedef struct DisasContext DisasContext;
|
||||||
struct DisasContext {
|
struct DisasContext {
|
||||||
|
struct TranslationBlock *tb;
|
||||||
|
CPUAlphaState *env;
|
||||||
uint64_t pc;
|
uint64_t pc;
|
||||||
int mem_idx;
|
int mem_idx;
|
||||||
#if !defined (CONFIG_USER_ONLY)
|
#if !defined (CONFIG_USER_ONLY)
|
||||||
int pal_mode;
|
int pal_mode;
|
||||||
#endif
|
#endif
|
||||||
CPUAlphaState *env;
|
|
||||||
uint32_t amask;
|
uint32_t amask;
|
||||||
|
|
||||||
/* Current rounding mode for this TB. */
|
/* Current rounding mode for this TB. */
|
||||||
@ -57,6 +58,25 @@ struct DisasContext {
|
|||||||
int tb_ftz;
|
int tb_ftz;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Return values from translate_one, indicating the state of the TB.
|
||||||
|
Note that zero indicates that we are not exiting the TB. */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NO_EXIT,
|
||||||
|
|
||||||
|
/* We have emitted one or more goto_tb. No fixup required. */
|
||||||
|
EXIT_GOTO_TB,
|
||||||
|
|
||||||
|
/* We are not using a goto_tb (for whatever reason), but have updated
|
||||||
|
the PC (for whatever reason), so there's no need to do it again on
|
||||||
|
exiting the TB. */
|
||||||
|
EXIT_PC_UPDATED,
|
||||||
|
|
||||||
|
/* We are exiting the TB, but have neither emitted a goto_tb, nor
|
||||||
|
updated the PC for the next instruction to be executed. */
|
||||||
|
EXIT_PC_STALE
|
||||||
|
} ExitStatus;
|
||||||
|
|
||||||
/* global register indexes */
|
/* global register indexes */
|
||||||
static TCGv_ptr cpu_env;
|
static TCGv_ptr cpu_env;
|
||||||
static TCGv cpu_ir[31];
|
static TCGv cpu_ir[31];
|
||||||
@ -300,77 +320,126 @@ static inline void gen_store_mem(DisasContext *ctx,
|
|||||||
tcg_temp_free(addr);
|
tcg_temp_free(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_bcond_pcload(DisasContext *ctx, int32_t disp, int lab_true)
|
static int use_goto_tb(DisasContext *ctx, uint64_t dest)
|
||||||
{
|
{
|
||||||
int lab_over = gen_new_label();
|
/* Check for the dest on the same page as the start of the TB. We
|
||||||
|
also want to suppress goto_tb in the case of single-steping and IO. */
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
return (((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0
|
||||||
tcg_gen_br(lab_over);
|
&& !ctx->env->singlestep_enabled
|
||||||
gen_set_label(lab_true);
|
&& !(ctx->tb->cflags & CF_LAST_IO));
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp << 2));
|
|
||||||
gen_set_label(lab_over);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
|
static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
|
||||||
int32_t disp, int mask)
|
|
||||||
{
|
{
|
||||||
|
uint64_t dest = ctx->pc + (disp << 2);
|
||||||
|
|
||||||
|
if (ra != 31) {
|
||||||
|
tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notice branch-to-next; used to initialize RA with the PC. */
|
||||||
|
if (disp == 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (use_goto_tb(ctx, dest)) {
|
||||||
|
tcg_gen_goto_tb(0);
|
||||||
|
tcg_gen_movi_i64(cpu_pc, dest);
|
||||||
|
tcg_gen_exit_tb((long)ctx->tb);
|
||||||
|
return EXIT_GOTO_TB;
|
||||||
|
} else {
|
||||||
|
tcg_gen_movi_i64(cpu_pc, dest);
|
||||||
|
return EXIT_PC_UPDATED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond,
|
||||||
|
TCGv cmp, int32_t disp)
|
||||||
|
{
|
||||||
|
uint64_t dest = ctx->pc + (disp << 2);
|
||||||
int lab_true = gen_new_label();
|
int lab_true = gen_new_label();
|
||||||
|
|
||||||
if (likely(ra != 31)) {
|
if (use_goto_tb(ctx, dest)) {
|
||||||
if (mask) {
|
tcg_gen_brcondi_i64(cond, cmp, 0, lab_true);
|
||||||
TCGv tmp = tcg_temp_new();
|
|
||||||
tcg_gen_andi_i64(tmp, cpu_ir[ra], 1);
|
tcg_gen_goto_tb(0);
|
||||||
tcg_gen_brcondi_i64(cond, tmp, 0, lab_true);
|
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
||||||
tcg_temp_free(tmp);
|
tcg_gen_exit_tb((long)ctx->tb);
|
||||||
} else {
|
|
||||||
tcg_gen_brcondi_i64(cond, cpu_ir[ra], 0, lab_true);
|
gen_set_label(lab_true);
|
||||||
}
|
tcg_gen_goto_tb(1);
|
||||||
|
tcg_gen_movi_i64(cpu_pc, dest);
|
||||||
|
tcg_gen_exit_tb((long)ctx->tb + 1);
|
||||||
|
|
||||||
|
return EXIT_GOTO_TB;
|
||||||
} else {
|
} else {
|
||||||
/* Very uncommon case - Do not bother to optimize. */
|
int lab_over = gen_new_label();
|
||||||
TCGv tmp = tcg_const_i64(0);
|
|
||||||
tcg_gen_brcondi_i64(cond, tmp, 0, lab_true);
|
/* ??? Consider using either
|
||||||
tcg_temp_free(tmp);
|
movi pc, next
|
||||||
|
addi tmp, pc, disp
|
||||||
|
movcond pc, cond, 0, tmp, pc
|
||||||
|
or
|
||||||
|
setcond tmp, cond, 0
|
||||||
|
movi pc, next
|
||||||
|
neg tmp, tmp
|
||||||
|
andi tmp, tmp, disp
|
||||||
|
add pc, pc, tmp
|
||||||
|
The current diamond subgraph surely isn't efficient. */
|
||||||
|
|
||||||
|
tcg_gen_brcondi_i64(cond, cmp, 0, lab_true);
|
||||||
|
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
||||||
|
tcg_gen_br(lab_over);
|
||||||
|
gen_set_label(lab_true);
|
||||||
|
tcg_gen_movi_i64(cpu_pc, dest);
|
||||||
|
gen_set_label(lab_over);
|
||||||
|
|
||||||
|
return EXIT_PC_UPDATED;
|
||||||
}
|
}
|
||||||
gen_bcond_pcload(ctx, disp, lab_true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate a forward TCG branch to LAB_TRUE if RA cmp 0.0.
|
static ExitStatus gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
|
||||||
This is complicated by the fact that -0.0 compares the same as +0.0. */
|
int32_t disp, int mask)
|
||||||
|
{
|
||||||
static void gen_fbcond_internal(TCGCond cond, TCGv src, int lab_true)
|
TCGv cmp_tmp;
|
||||||
|
|
||||||
|
if (unlikely(ra == 31)) {
|
||||||
|
cmp_tmp = tcg_const_i64(0);
|
||||||
|
} else {
|
||||||
|
cmp_tmp = tcg_temp_new();
|
||||||
|
if (mask) {
|
||||||
|
tcg_gen_andi_i64(cmp_tmp, cpu_ir[ra], 1);
|
||||||
|
} else {
|
||||||
|
tcg_gen_mov_i64(cmp_tmp, cpu_ir[ra]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gen_bcond_internal(ctx, cond, cmp_tmp, disp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fold -0.0 for comparison with COND. */
|
||||||
|
|
||||||
|
static void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src)
|
||||||
{
|
{
|
||||||
int lab_false = -1;
|
|
||||||
uint64_t mzero = 1ull << 63;
|
uint64_t mzero = 1ull << 63;
|
||||||
TCGv tmp;
|
|
||||||
|
|
||||||
switch (cond) {
|
switch (cond) {
|
||||||
case TCG_COND_LE:
|
case TCG_COND_LE:
|
||||||
case TCG_COND_GT:
|
case TCG_COND_GT:
|
||||||
/* For <= or >, the -0.0 value directly compares the way we want. */
|
/* For <= or >, the -0.0 value directly compares the way we want. */
|
||||||
tcg_gen_brcondi_i64(cond, src, 0, lab_true);
|
tcg_gen_mov_i64(dest, src);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCG_COND_EQ:
|
case TCG_COND_EQ:
|
||||||
case TCG_COND_NE:
|
case TCG_COND_NE:
|
||||||
/* For == or !=, we can simply mask off the sign bit and compare. */
|
/* For == or !=, we can simply mask off the sign bit and compare. */
|
||||||
/* ??? Assume that the temporary is reclaimed at the branch. */
|
tcg_gen_andi_i64(dest, src, mzero - 1);
|
||||||
tmp = tcg_temp_new();
|
|
||||||
tcg_gen_andi_i64(tmp, src, mzero - 1);
|
|
||||||
tcg_gen_brcondi_i64(cond, tmp, 0, lab_true);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCG_COND_GE:
|
case TCG_COND_GE:
|
||||||
/* For >=, emit two branches to the destination. */
|
|
||||||
tcg_gen_brcondi_i64(cond, src, 0, lab_true);
|
|
||||||
tcg_gen_brcondi_i64(TCG_COND_EQ, src, mzero, lab_true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TCG_COND_LT:
|
case TCG_COND_LT:
|
||||||
/* For <, first filter out -0.0 to what will be the fallthru. */
|
/* For >= or <, map -0.0 to +0.0 via comparison and mask. */
|
||||||
lab_false = gen_new_label();
|
tcg_gen_setcondi_i64(TCG_COND_NE, dest, src, mzero);
|
||||||
tcg_gen_brcondi_i64(TCG_COND_EQ, src, mzero, lab_false);
|
tcg_gen_neg_i64(dest, dest);
|
||||||
tcg_gen_brcondi_i64(cond, src, 0, lab_true);
|
tcg_gen_and_i64(dest, dest, src);
|
||||||
gen_set_label(lab_false);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -378,24 +447,24 @@ static void gen_fbcond_internal(TCGCond cond, TCGv src, int lab_true)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_fbcond(DisasContext *ctx, TCGCond cond, int ra, int32_t disp)
|
static ExitStatus gen_fbcond(DisasContext *ctx, TCGCond cond, int ra,
|
||||||
|
int32_t disp)
|
||||||
{
|
{
|
||||||
int lab_true;
|
TCGv cmp_tmp;
|
||||||
|
|
||||||
if (unlikely(ra == 31)) {
|
if (unlikely(ra == 31)) {
|
||||||
/* Very uncommon case, but easier to optimize it to an integer
|
/* Very uncommon case, but easier to optimize it to an integer
|
||||||
comparison than continuing with the floating point comparison. */
|
comparison than continuing with the floating point comparison. */
|
||||||
gen_bcond(ctx, cond, ra, disp, 0);
|
return gen_bcond(ctx, cond, ra, disp, 0);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lab_true = gen_new_label();
|
cmp_tmp = tcg_temp_new();
|
||||||
gen_fbcond_internal(cond, cpu_fir[ra], lab_true);
|
gen_fold_mzero(cond, cmp_tmp, cpu_fir[ra]);
|
||||||
gen_bcond_pcload(ctx, disp, lab_true);
|
return gen_bcond_internal(ctx, cond, cmp_tmp, disp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_cmov(TCGCond cond, int ra, int rb, int rc,
|
static void gen_cmov(TCGCond cond, int ra, int rb, int rc,
|
||||||
int islit, uint8_t lit, int mask)
|
int islit, uint8_t lit, int mask)
|
||||||
{
|
{
|
||||||
TCGCond inv_cond = tcg_invert_cond(cond);
|
TCGCond inv_cond = tcg_invert_cond(cond);
|
||||||
int l1;
|
int l1;
|
||||||
@ -429,18 +498,23 @@ static void gen_cmov(TCGCond cond, int ra, int rb, int rc,
|
|||||||
|
|
||||||
static void gen_fcmov(TCGCond cond, int ra, int rb, int rc)
|
static void gen_fcmov(TCGCond cond, int ra, int rb, int rc)
|
||||||
{
|
{
|
||||||
TCGv va = cpu_fir[ra];
|
TCGv cmp_tmp;
|
||||||
int l1;
|
int l1;
|
||||||
|
|
||||||
if (unlikely(rc == 31))
|
if (unlikely(rc == 31)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp_tmp = tcg_temp_new();
|
||||||
if (unlikely(ra == 31)) {
|
if (unlikely(ra == 31)) {
|
||||||
/* ??? Assume that the temporary is reclaimed at the branch. */
|
tcg_gen_movi_i64(cmp_tmp, 0);
|
||||||
va = tcg_const_i64(0);
|
} else {
|
||||||
|
gen_fold_mzero(cond, cmp_tmp, cpu_fir[ra]);
|
||||||
}
|
}
|
||||||
|
|
||||||
l1 = gen_new_label();
|
l1 = gen_new_label();
|
||||||
gen_fbcond_internal(tcg_invert_cond(cond), va, l1);
|
tcg_gen_brcondi_i64(tcg_invert_cond(cond), cmp_tmp, 0, l1);
|
||||||
|
tcg_temp_free(cmp_tmp);
|
||||||
|
|
||||||
if (rb != 31)
|
if (rb != 31)
|
||||||
tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[rb]);
|
tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[rb]);
|
||||||
@ -1335,14 +1409,14 @@ static void gen_rx(int ra, int set)
|
|||||||
tcg_temp_free_i32(tmp);
|
tcg_temp_free_i32(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
{
|
{
|
||||||
uint32_t palcode;
|
uint32_t palcode;
|
||||||
int32_t disp21, disp16, disp12;
|
int32_t disp21, disp16, disp12;
|
||||||
uint16_t fn11;
|
uint16_t fn11;
|
||||||
uint8_t opc, ra, rb, rc, fpfn, fn7, fn2, islit, real_islit;
|
uint8_t opc, ra, rb, rc, fpfn, fn7, fn2, islit, real_islit;
|
||||||
uint8_t lit;
|
uint8_t lit;
|
||||||
int ret;
|
ExitStatus ret;
|
||||||
|
|
||||||
/* Decode all instruction fields */
|
/* Decode all instruction fields */
|
||||||
opc = insn >> 26;
|
opc = insn >> 26;
|
||||||
@ -1363,10 +1437,10 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
|||||||
fpfn = fn11 & 0x3F;
|
fpfn = fn11 & 0x3F;
|
||||||
fn7 = (insn >> 5) & 0x0000007F;
|
fn7 = (insn >> 5) & 0x0000007F;
|
||||||
fn2 = (insn >> 5) & 0x00000003;
|
fn2 = (insn >> 5) & 0x00000003;
|
||||||
ret = 0;
|
|
||||||
LOG_DISAS("opc %02x ra %2d rb %2d rc %2d disp16 %6d\n",
|
LOG_DISAS("opc %02x ra %2d rb %2d rc %2d disp16 %6d\n",
|
||||||
opc, ra, rb, rc, disp16);
|
opc, ra, rb, rc, disp16);
|
||||||
|
|
||||||
|
ret = NO_EXIT;
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
/* CALL_PAL */
|
/* CALL_PAL */
|
||||||
@ -1384,7 +1458,8 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
|||||||
if (palcode >= 0x80 && palcode < 0xC0) {
|
if (palcode >= 0x80 && palcode < 0xC0) {
|
||||||
/* Unprivileged PAL call */
|
/* Unprivileged PAL call */
|
||||||
gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x3F) << 6), 0);
|
gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x3F) << 6), 0);
|
||||||
ret = 3;
|
/* PC updated by gen_excp. */
|
||||||
|
ret = EXIT_PC_UPDATED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
@ -2395,13 +2470,11 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
|||||||
switch ((uint16_t)disp16) {
|
switch ((uint16_t)disp16) {
|
||||||
case 0x0000:
|
case 0x0000:
|
||||||
/* TRAPB */
|
/* TRAPB */
|
||||||
/* No-op. Just exit from the current tb */
|
/* No-op. */
|
||||||
ret = 2;
|
|
||||||
break;
|
break;
|
||||||
case 0x0400:
|
case 0x0400:
|
||||||
/* EXCB */
|
/* EXCB */
|
||||||
/* No-op. Just exit from the current tb */
|
/* No-op. */
|
||||||
ret = 2;
|
|
||||||
break;
|
break;
|
||||||
case 0x4000:
|
case 0x4000:
|
||||||
/* MB */
|
/* MB */
|
||||||
@ -2465,21 +2538,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
|||||||
if (ra != 31)
|
if (ra != 31)
|
||||||
tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
|
tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
|
||||||
/* Those four jumps only differ by the branch prediction hint */
|
/* Those four jumps only differ by the branch prediction hint */
|
||||||
switch (fn2) {
|
ret = EXIT_PC_UPDATED;
|
||||||
case 0x0:
|
|
||||||
/* JMP */
|
|
||||||
break;
|
|
||||||
case 0x1:
|
|
||||||
/* JSR */
|
|
||||||
break;
|
|
||||||
case 0x2:
|
|
||||||
/* RET */
|
|
||||||
break;
|
|
||||||
case 0x3:
|
|
||||||
/* JSR_COROUTINE */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x1B:
|
case 0x1B:
|
||||||
/* HW_LD (PALcode) */
|
/* HW_LD (PALcode) */
|
||||||
@ -2770,7 +2829,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
|||||||
tcg_temp_free(tmp2);
|
tcg_temp_free(tmp2);
|
||||||
}
|
}
|
||||||
tcg_temp_free(tmp1);
|
tcg_temp_free(tmp1);
|
||||||
ret = 2;
|
ret = EXIT_PC_STALE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -2795,7 +2854,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
|||||||
gen_helper_hw_ret(tmp);
|
gen_helper_hw_ret(tmp);
|
||||||
tcg_temp_free(tmp);
|
tcg_temp_free(tmp);
|
||||||
}
|
}
|
||||||
ret = 2;
|
ret = EXIT_PC_UPDATED;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 0x1F:
|
case 0x1F:
|
||||||
@ -2956,85 +3015,66 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
|||||||
break;
|
break;
|
||||||
case 0x30:
|
case 0x30:
|
||||||
/* BR */
|
/* BR */
|
||||||
if (ra != 31)
|
ret = gen_bdirect(ctx, ra, disp21);
|
||||||
tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
|
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp21 << 2));
|
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x31: /* FBEQ */
|
case 0x31: /* FBEQ */
|
||||||
gen_fbcond(ctx, TCG_COND_EQ, ra, disp21);
|
ret = gen_fbcond(ctx, TCG_COND_EQ, ra, disp21);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x32: /* FBLT */
|
case 0x32: /* FBLT */
|
||||||
gen_fbcond(ctx, TCG_COND_LT, ra, disp21);
|
ret = gen_fbcond(ctx, TCG_COND_LT, ra, disp21);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x33: /* FBLE */
|
case 0x33: /* FBLE */
|
||||||
gen_fbcond(ctx, TCG_COND_LE, ra, disp21);
|
ret = gen_fbcond(ctx, TCG_COND_LE, ra, disp21);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x34:
|
case 0x34:
|
||||||
/* BSR */
|
/* BSR */
|
||||||
if (ra != 31)
|
ret = gen_bdirect(ctx, ra, disp21);
|
||||||
tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
|
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp21 << 2));
|
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x35: /* FBNE */
|
case 0x35: /* FBNE */
|
||||||
gen_fbcond(ctx, TCG_COND_NE, ra, disp21);
|
ret = gen_fbcond(ctx, TCG_COND_NE, ra, disp21);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x36: /* FBGE */
|
case 0x36: /* FBGE */
|
||||||
gen_fbcond(ctx, TCG_COND_GE, ra, disp21);
|
ret = gen_fbcond(ctx, TCG_COND_GE, ra, disp21);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x37: /* FBGT */
|
case 0x37: /* FBGT */
|
||||||
gen_fbcond(ctx, TCG_COND_GT, ra, disp21);
|
ret = gen_fbcond(ctx, TCG_COND_GT, ra, disp21);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x38:
|
case 0x38:
|
||||||
/* BLBC */
|
/* BLBC */
|
||||||
gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1);
|
ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x39:
|
case 0x39:
|
||||||
/* BEQ */
|
/* BEQ */
|
||||||
gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 0);
|
ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 0);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x3A:
|
case 0x3A:
|
||||||
/* BLT */
|
/* BLT */
|
||||||
gen_bcond(ctx, TCG_COND_LT, ra, disp21, 0);
|
ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21, 0);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x3B:
|
case 0x3B:
|
||||||
/* BLE */
|
/* BLE */
|
||||||
gen_bcond(ctx, TCG_COND_LE, ra, disp21, 0);
|
ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21, 0);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x3C:
|
case 0x3C:
|
||||||
/* BLBS */
|
/* BLBS */
|
||||||
gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1);
|
ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x3D:
|
case 0x3D:
|
||||||
/* BNE */
|
/* BNE */
|
||||||
gen_bcond(ctx, TCG_COND_NE, ra, disp21, 0);
|
ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 0);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x3E:
|
case 0x3E:
|
||||||
/* BGE */
|
/* BGE */
|
||||||
gen_bcond(ctx, TCG_COND_GE, ra, disp21, 0);
|
ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21, 0);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0x3F:
|
case 0x3F:
|
||||||
/* BGT */
|
/* BGT */
|
||||||
gen_bcond(ctx, TCG_COND_GT, ra, disp21, 0);
|
ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21, 0);
|
||||||
ret = 1;
|
|
||||||
break;
|
break;
|
||||||
invalid_opc:
|
invalid_opc:
|
||||||
gen_invalid(ctx);
|
gen_invalid(ctx);
|
||||||
ret = 3;
|
/* PC updated by gen_excp. */
|
||||||
|
ret = EXIT_PC_UPDATED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3051,15 +3091,17 @@ static inline void gen_intermediate_code_internal(CPUState *env,
|
|||||||
uint16_t *gen_opc_end;
|
uint16_t *gen_opc_end;
|
||||||
CPUBreakpoint *bp;
|
CPUBreakpoint *bp;
|
||||||
int j, lj = -1;
|
int j, lj = -1;
|
||||||
int ret;
|
ExitStatus ret;
|
||||||
int num_insns;
|
int num_insns;
|
||||||
int max_insns;
|
int max_insns;
|
||||||
|
|
||||||
pc_start = tb->pc;
|
pc_start = tb->pc;
|
||||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||||
|
|
||||||
|
ctx.tb = tb;
|
||||||
|
ctx.env = env;
|
||||||
ctx.pc = pc_start;
|
ctx.pc = pc_start;
|
||||||
ctx.amask = env->amask;
|
ctx.amask = env->amask;
|
||||||
ctx.env = env;
|
|
||||||
#if defined (CONFIG_USER_ONLY)
|
#if defined (CONFIG_USER_ONLY)
|
||||||
ctx.mem_idx = 0;
|
ctx.mem_idx = 0;
|
||||||
#else
|
#else
|
||||||
@ -3083,7 +3125,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
|
|||||||
max_insns = CF_COUNT_MASK;
|
max_insns = CF_COUNT_MASK;
|
||||||
|
|
||||||
gen_icount_start();
|
gen_icount_start();
|
||||||
for (ret = 0; ret == 0;) {
|
do {
|
||||||
if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
|
if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
|
||||||
QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
|
QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
|
||||||
if (bp->pc == ctx.pc) {
|
if (bp->pc == ctx.pc) {
|
||||||
@ -3114,36 +3156,39 @@ static inline void gen_intermediate_code_internal(CPUState *env,
|
|||||||
|
|
||||||
ctx.pc += 4;
|
ctx.pc += 4;
|
||||||
ret = translate_one(ctxp, insn);
|
ret = translate_one(ctxp, insn);
|
||||||
if (ret != 0)
|
|
||||||
break;
|
if (ret == NO_EXIT) {
|
||||||
/* if we reach a page boundary or are single stepping, stop
|
/* If we reach a page boundary, are single stepping,
|
||||||
* generation
|
or exhaust instruction count, stop generation. */
|
||||||
*/
|
if (env->singlestep_enabled) {
|
||||||
if (env->singlestep_enabled) {
|
gen_excp(&ctx, EXCP_DEBUG, 0);
|
||||||
gen_excp(&ctx, EXCP_DEBUG, 0);
|
ret = EXIT_PC_UPDATED;
|
||||||
break;
|
} else if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
|
||||||
|
|| gen_opc_ptr >= gen_opc_end
|
||||||
|
|| num_insns >= max_insns
|
||||||
|
|| singlestep) {
|
||||||
|
ret = EXIT_PC_STALE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} while (ret == NO_EXIT);
|
||||||
|
|
||||||
if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
|
if (tb->cflags & CF_LAST_IO) {
|
||||||
break;
|
|
||||||
|
|
||||||
if (gen_opc_ptr >= gen_opc_end)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (num_insns >= max_insns)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (singlestep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ret != 1 && ret != 3) {
|
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx.pc);
|
|
||||||
}
|
|
||||||
if (tb->cflags & CF_LAST_IO)
|
|
||||||
gen_io_end();
|
gen_io_end();
|
||||||
/* Generate the return instruction */
|
}
|
||||||
tcg_gen_exit_tb(0);
|
|
||||||
|
switch (ret) {
|
||||||
|
case EXIT_GOTO_TB:
|
||||||
|
break;
|
||||||
|
case EXIT_PC_STALE:
|
||||||
|
tcg_gen_movi_i64(cpu_pc, ctx.pc);
|
||||||
|
/* FALLTHRU */
|
||||||
|
case EXIT_PC_UPDATED:
|
||||||
|
tcg_gen_exit_tb(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
gen_icount_end(tb, num_insns);
|
gen_icount_end(tb, num_insns);
|
||||||
*gen_opc_ptr = INDEX_op_end;
|
*gen_opc_ptr = INDEX_op_end;
|
||||||
if (search_pc) {
|
if (search_pc) {
|
||||||
@ -3155,6 +3200,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
|
|||||||
tb->size = ctx.pc - pc_start;
|
tb->size = ctx.pc - pc_start;
|
||||||
tb->icount = num_insns;
|
tb->icount = num_insns;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_DISAS
|
#ifdef DEBUG_DISAS
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
|
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
|
||||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||||
|
Loading…
Reference in New Issue
Block a user