@@ -535,6 +535,7 @@ FIELD(MSR, LE, MSR_LE, 1)
#define MMCR0_PMCjCE PPC_BIT(49) /* MMCR0 PMCj Condition Enabled */
#define MMCR0_FCP PPC_BIT(34) /* Freeze Counters/BHRB if PR=1 */
#define MMCR0_FCPC PPC_BIT(51) /* Condition for FCP bit */
+#define MMCR0_BHRBA_NR PPC_BIT_NR(42) /* BHRB Available */
/* MMCR0 userspace r/w mask */
#define MMCR0_UREG_MASK (MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE)
/* MMCR2 userspace r/w mask */
@@ -634,6 +635,7 @@ FIELD(MSR, LE, MSR_LE, 1)
/* HFSCR bits */
#define HFSCR_MSGP PPC_BIT(53) /* Privileged Message Send Facilities */
+#define HFSCR_BHRB PPC_BIT(59) /* BHRB Instructions */
#define HFSCR_IC_MSGP 0xA
#define DBCR0_ICMP (1 << 27)
@@ -820,3 +820,10 @@ DEF_HELPER_4(DSCLIQ, void, env, fprp, fprp, i32)
DEF_HELPER_1(tbegin, void, env)
DEF_HELPER_FLAGS_1(fixup_thrm, TCG_CALL_NO_RWG, void, env)
+
+#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+DEF_HELPER_1(clrbhrb, void, env)
+DEF_HELPER_FLAGS_2(mfbhrbe, TCG_CALL_NO_WG, i64, env, i32)
+#endif
+#endif
@@ -1190,3 +1190,11 @@ MSGSYNC 011111 ----- ----- ----- 1101110110 -
@X_sync ...... .. l:3 ... sc:2 ..... .......... . &X_sync
SYNC 011111 -- ... --- .. ----- 1001010110 - @X_sync
EIEIO 011111 ----- ----- ----- 1101010110 -
+
+# Branch History Rolling Buffer (BHRB) Instructions
+
+&XFX_bhrbe rt bhrbe
+@XFX_bhrbe ...... rt:5 bhrbe:10 .......... - &XFX_bhrbe
+
+MFBHRBE 011111 ..... ..... ..... 0100101110 - @XFX_bhrbe
+CLRBHRB 011111 ----- ----- ----- 0110101110 -
@@ -150,6 +150,17 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
#if !defined(CONFIG_USER_ONLY)
+#ifdef TARGET_PPC64
+static void helper_mmcr0_facility_check(CPUPPCState *env, uint32_t bit,
+ uint32_t sprn, uint32_t cause)
+{
+ if (FIELD_EX64(env->msr, MSR, PR) &&
+ !(env->spr[SPR_POWER_MMCR0] & (1ULL << bit))) {
+ raise_fu_exception(env, bit, sprn, cause, GETPC());
+ }
+}
+#endif
+
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
{
if (env->spr[SPR_SDR1] != val) {
@@ -363,3 +374,42 @@ void helper_fixup_thrm(CPUPPCState *env)
env->spr[i] = v;
}
}
+
+#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+void helper_clrbhrb(CPUPPCState *env)
+{
+ helper_hfscr_facility_check(env, HFSCR_BHRB, "clrbhrb", FSCR_IC_BHRB);
+
+ helper_mmcr0_facility_check(env, MMCR0_BHRBA_NR, 0, FSCR_IC_BHRB);
+
+ if (env->flags & POWERPC_FLAG_BHRB) {
+ memset(env->bhrb, 0, sizeof(env->bhrb));
+ }
+}
+
+uint64_t helper_mfbhrbe(CPUPPCState *env, uint32_t bhrbe)
+{
+ unsigned int index;
+
+ helper_hfscr_facility_check(env, HFSCR_BHRB, "mfbhrbe", FSCR_IC_BHRB);
+
+ helper_mmcr0_facility_check(env, MMCR0_BHRBA_NR, 0, FSCR_IC_BHRB);
+
+ if (!(env->flags & POWERPC_FLAG_BHRB) ||
+ (bhrbe >= env->bhrb_num_entries) ||
+ (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE)) {
+ return 0;
+ }
+
+ /*
+ * Note: bhrb_offset is the byte offset for writing the
+ * next entry (over the oldest entry), which is why we
+ * must offset bhrbe by 1 to get to the 0th entry.
+ */
+ index = ((env->bhrb_offset / sizeof(uint64_t)) - (bhrbe + 1)) %
+ env->bhrb_num_entries;
+ return env->bhrb[index];
+}
+#endif
+#endif
@@ -5647,6 +5647,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a)
#include "translate/misc-impl.c.inc"
+#include "translate/bhrb-impl.c.inc"
+
/* Handles lfdp */
static void gen_dform39(DisasContext *ctx)
{
new file mode 100644
@@ -0,0 +1,43 @@
+/*
+ * Power ISA Decode For BHRB Instructions
+ *
+ * Copyright IBM Corp. 2023
+ *
+ * Authors:
+ * Glenn Miles <milesg@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+
+static bool trans_MFBHRBE(DisasContext *ctx, arg_XFX_bhrbe *arg)
+{
+ REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
+ TCGv_i32 bhrbe = tcg_constant_i32(arg->bhrbe);
+ gen_helper_mfbhrbe(cpu_gpr[arg->rt], tcg_env, bhrbe);
+ return true;
+}
+
+static bool trans_CLRBHRB(DisasContext *ctx, arg_CLRBHRB *arg)
+{
+ REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
+ gen_helper_clrbhrb(tcg_env);
+ return true;
+}
+
+#else
+
+static bool trans_MFBHRBE(DisasContext *ctx, arg_XFX_bhrbe *arg)
+{
+ gen_invalid(ctx);
+ return true;
+}
+
+static bool trans_CLRBHRB(DisasContext *ctx, arg_CLRBHRB *arg)
+{
+ gen_invalid(ctx);
+ return true;
+}
+#endif