@@ -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;
@@ -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);
}
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.henderson@linaro.org> --- target/hppa/cpu.c | 4 +-- target/hppa/translate.c | 55 +++++++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 15 deletions(-)