PSW_T enables a trap on taken branches, at the very end of the execution of the branch instruction.
Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- target/hppa/cpu.c | 4 +-- target/hppa/translate.c | 55 +++++++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index b3f3f070d3..42c413211a 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -76,10 +76,10 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, cs_base |= env->iaoq_b & ~TARGET_PAGE_MASK; } - /* ??? E, T, H, L bits need to be here, when implemented. */ + /* ??? E, H, L bits need to be here, when implemented. */ flags |= env->psw_n * PSW_N; flags |= env->psw_xb; - flags |= env->psw & (PSW_W | PSW_C | PSW_D | PSW_P); + flags |= env->psw & (PSW_W | PSW_C | PSW_D | PSW_P | PSW_T); #ifdef CONFIG_USER_ONLY flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; diff --git a/target/hppa/translate.c b/target/hppa/translate.c index b2cc81c685..7ad7aa675d 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -1872,6 +1872,23 @@ static bool do_fop_dedd(DisasContext *ctx, unsigned rt, return nullify_end(ctx); } +static bool do_taken_branch_trap(DisasContext *ctx, DisasIAQE *next, bool n) +{ + if (unlikely(ctx->tb_flags & PSW_T)) { + /* + * The X, B and N bits are updated, and the instruction queue + * is advanced before the trap is recognized. + */ + nullify_set(ctx, n); + store_psw_xb(ctx, PSW_B); + install_iaq_entries(ctx, &ctx->iaq_b, next); + gen_excp_1(EXCP_TB); + ctx->base.is_jmp = DISAS_NORETURN; + return true; + } + return false; +} + /* Emit an unconditional branch to a direct target, which may or may not have already had nullification handled. */ static bool do_dbranch(DisasContext *ctx, int64_t disp, @@ -1881,6 +1898,9 @@ static bool do_dbranch(DisasContext *ctx, int64_t disp, if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { install_link(ctx, link, false); + if (do_taken_branch_trap(ctx, &ctx->iaq_j, is_n)) { + return true; + } if (is_n) { if (use_nullify_skip(ctx)) { nullify_set(ctx, 0); @@ -1897,7 +1917,9 @@ static bool do_dbranch(DisasContext *ctx, int64_t disp, nullify_over(ctx); install_link(ctx, link, false); - if (is_n && use_nullify_skip(ctx)) { + if (do_taken_branch_trap(ctx, &ctx->iaq_j, is_n)) { + /* done */ + } else if (is_n && use_nullify_skip(ctx)) { nullify_set(ctx, 0); store_psw_xb(ctx, 0); gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL); @@ -1959,7 +1981,9 @@ static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, n = is_n && disp >= 0; next = iaqe_branchi(ctx, disp); - if (n && use_nullify_skip(ctx)) { + if (do_taken_branch_trap(ctx, &next, is_n)) { + /* done */ + } else if (n && use_nullify_skip(ctx)) { nullify_set(ctx, 0); store_psw_xb(ctx, 0); gen_goto_tb(ctx, 1, &next, NULL); @@ -1989,6 +2013,9 @@ static bool do_ibranch(DisasContext *ctx, unsigned link, { if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { install_link(ctx, link, with_sr0); + if (do_taken_branch_trap(ctx, &ctx->iaq_j, is_n)) { + return true; + } if (is_n) { if (use_nullify_skip(ctx)) { install_iaq_entries(ctx, &ctx->iaq_j, NULL); @@ -2004,20 +2031,22 @@ static bool do_ibranch(DisasContext *ctx, unsigned link, } nullify_over(ctx); - install_link(ctx, link, with_sr0); - if (is_n && use_nullify_skip(ctx)) { - install_iaq_entries(ctx, &ctx->iaq_j, NULL); - nullify_set(ctx, 0); - store_psw_xb(ctx, 0); - } else { - install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j); - nullify_set(ctx, is_n); - store_psw_xb(ctx, PSW_B); + + if (!do_taken_branch_trap(ctx, &ctx->iaq_j, is_n)) { + if (is_n && use_nullify_skip(ctx)) { + install_iaq_entries(ctx, &ctx->iaq_j, NULL); + nullify_set(ctx, 0); + store_psw_xb(ctx, 0); + } else { + install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j); + nullify_set(ctx, is_n); + store_psw_xb(ctx, PSW_B); + } + tcg_gen_lookup_and_goto_ptr(); + ctx->base.is_jmp = DISAS_NORETURN; } - tcg_gen_lookup_and_goto_ptr(); - ctx->base.is_jmp = DISAS_NORETURN; return nullify_end(ctx); } -- 2.34.1