{U,G,}PCYCLE now use a shared virtual-clock counter.  This is closer to how
the real PCYCLE behaves and avoids the extra work that was being done on
every single TB.

Handle SYSCFG.PCYCLEEN and the semihosting PCYCLE read.

Remove the work-in-progress implementation that summed the TB instructions
into a counter.

Signed-off-by: Brian Cain <[email protected]>
---
 include/hw/hexagon/hexagon_globalreg.h |   6 ++
 target/hexagon/cpu.h                   |   2 -
 target/hexagon/cpu_helper.h            |   6 --
 target/hexagon/helper.h                |   2 +
 target/hexagon/translate.h             |   2 -
 hw/hexagon/hexagon_globalreg.c         | 142 ++++++++++++++++++++++++-
 target/hexagon/cpu.c                   |  10 +-
 target/hexagon/cpu_helper.c            |  79 --------------
 target/hexagon/genptr.c                |   8 ++
 target/hexagon/hexswi.c                |  10 +-
 target/hexagon/machine.c               |   2 +-
 target/hexagon/op_helper.c             |  45 ++++++++
 target/hexagon/translate.c             |  21 ----
 hw/hexagon/trace-events                |   1 +
 14 files changed, 219 insertions(+), 117 deletions(-)

diff --git a/include/hw/hexagon/hexagon_globalreg.h 
b/include/hw/hexagon/hexagon_globalreg.h
index 07437dfabb1..281a2b4f323 100644
--- a/include/hw/hexagon/hexagon_globalreg.h
+++ b/include/hw/hexagon/hexagon_globalreg.h
@@ -33,6 +33,11 @@ struct HexagonGlobalRegState {
     /* Global performance cycle counter base */
     uint64_t g_pcycle_base;
 
+    /* Global performance cycle counter clock state */
+    int64_t pcycle_start_ns;
+    bool pcycle_running;
+    uint32_t pcycle_freq_hz;
+
     /* Properties for global register reset values */
     uint32_t boot_evb;           /* Boot Exception Vector Base (HEX_SREG_EVB) 
*/
     uint64_t config_table_addr;  /* Configuration table base */
@@ -56,6 +61,7 @@ void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, 
uint32_t reg,
                                     uint32_t value);
 
 /* Global performance cycle counter access */
+uint64_t hexagon_globalreg_read_pcycle(HexagonGlobalRegState *s);
 uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s);
 void hexagon_globalreg_set_pcycle_base(HexagonGlobalRegState *s,
                                        uint64_t value);
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index df4c0182247..b11dedea42d 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -151,7 +151,6 @@ typedef struct CPUArchState {
     hex_lock_state_t k0_lock_state;
     uint32_t tlb_lock_count;
     uint32_t k0_lock_count;
-    uint64_t t_cycle_count;
 #endif
     uint32_t next_PC;
     uint32_t imprecise_exception;
@@ -227,7 +226,6 @@ static inline HexagonHVXContext *hex_hvx(CPUHexagonState 
*env)
 
 FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1)
 FIELD(TB_FLAGS, MMU_INDEX, 1, 3)
-FIELD(TB_FLAGS, PCYCLE_ENABLED, 4, 1)
 FIELD(TB_FLAGS, HVX_COPROC_ENABLED, 5, 1)
 
 G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index afb4df59f80..1c25e83b7a9 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -23,11 +23,5 @@ void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t 
cause);
 void hexagon_start_threads(CPUHexagonState *env, uint32_t mask);
 void hexagon_stop_thread(CPUHexagonState *env);
 void hexagon_resume_threads(CPUHexagonState *env, uint32_t mask);
-uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env);
-uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env);
-uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env);
-void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t val);
-void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t val);
-void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t val);
 
 #endif
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 71c8da4c46d..71bc7dd9688 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -130,6 +130,8 @@ DEF_HELPER_2(getimask, i32, env, i32)
 DEF_HELPER_3(setimask, void, env, i32, i32)
 DEF_HELPER_2(sreg_read, i32, env, i32)
 DEF_HELPER_2(sreg_read_pair, i64, env, i32)
+DEF_HELPER_2(upcycle_read, i32, env, i32)
+DEF_HELPER_1(upcycle_read_pair, i64, env)
 DEF_HELPER_2(greg_read, i32, env, i32)
 DEF_HELPER_2(greg_read_pair, i64, env, i32)
 DEF_HELPER_3(sreg_write_masked, void, env, i32, i32)
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index e17261761b2..57c82b6a70a 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -97,10 +97,8 @@ typedef struct DisasContext {
     TCGv new_pred_value[NUM_PREGS];
     TCGv branch_taken;
     TCGv dczero_addr;
-    bool pcycle_enabled;
     bool hvx_coproc_enabled;
     bool hvx_check_emitted;
-    uint32_t num_cycles;
 } DisasContext;
 
 bool is_gather_store_insn(DisasContext *ctx);
diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c
index 616cddf3048..351a390c6f1 100644
--- a/hw/hexagon/hexagon_globalreg.c
+++ b/hw/hexagon/hexagon_globalreg.c
@@ -18,6 +18,7 @@
 #include "target/hexagon/cpu.h"
 #include "target/hexagon/hex_regs.h"
 #include "qemu/log.h"
+#include "qemu/timer.h"
 #include "trace.h"
 #include "qapi/error.h"
 
@@ -157,6 +158,87 @@ static inline bool is_timer_reg(uint32_t reg)
     return reg == HEX_SREG_TIMERLO || reg == HEX_SREG_TIMERHI;
 }
 
+static inline bool is_pcycle_reg(uint32_t reg)
+{
+    return reg == HEX_SREG_PCYCLELO || reg == HEX_SREG_PCYCLEHI;
+}
+
+static inline bool modectl_any_thread_running(uint32_t modectl)
+{
+    uint32_t enabled = modectl & 0xffff;
+    uint32_t waiting = modectl >> 16;
+    return (enabled & ~waiting) != 0;
+}
+
+static uint64_t pcycle_value_now(HexagonGlobalRegState *s)
+{
+    uint64_t cycles = s->g_pcycle_base;
+
+    if (s->pcycle_running) {
+        int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        int64_t elapsed = now - s->pcycle_start_ns;
+
+        if (elapsed > 0) {
+            cycles += muldiv64(elapsed, s->pcycle_freq_hz,
+                               NANOSECONDS_PER_SECOND);
+        }
+    }
+    return cycles;
+}
+
+static void pcycle_fold(HexagonGlobalRegState *s)
+{
+    int64_t now;
+    int64_t elapsed;
+
+    if (!s->pcycle_running) {
+        return;
+    }
+
+    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    elapsed = now - s->pcycle_start_ns;
+    if (elapsed > 0) {
+        s->g_pcycle_base += muldiv64(elapsed, s->pcycle_freq_hz,
+                                     NANOSECONDS_PER_SECOND);
+    }
+    s->pcycle_start_ns = now;
+}
+
+static bool pcycle_enabled(uint32_t syscfg)
+{
+    return extract32(syscfg, reg_field_info[SYSCFG_PCYCLEEN].offset,
+                     reg_field_info[SYSCFG_PCYCLEEN].width);
+}
+
+uint64_t hexagon_globalreg_read_pcycle(HexagonGlobalRegState *s)
+{
+    g_assert(s);
+    return pcycle_enabled(s->regs[HEX_SREG_SYSCFG]) ?
+           pcycle_value_now(s) : 0;
+}
+static void pcycle_set_running(HexagonGlobalRegState *s, bool running)
+{
+    if (running == s->pcycle_running) {
+        return;
+    }
+    if (running) {
+        s->pcycle_start_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    } else {
+        s->g_pcycle_base = pcycle_value_now(s);
+    }
+    s->pcycle_running = running;
+    trace_hexagon_pcycle_run_state(s->pcycle_running, s->g_pcycle_base);
+}
+
+static void pcycle_write(HexagonGlobalRegState *s, uint32_t reg,
+                         uint32_t value)
+{
+    pcycle_fold(s);
+    s->g_pcycle_base = deposit64(s->g_pcycle_base,
+                                 reg == HEX_SREG_PCYCLELO ? 0 : 32, 32,
+                                 value);
+}
+
 static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg)
 {
     if (is_vid_reg(reg)) {
@@ -167,16 +249,38 @@ static uint32_t get_reg_value(HexagonGlobalRegState *s, 
uint32_t reg)
                 qct_qtimer_get_timer_lo(s->qtimer) :
                 qct_qtimer_get_timer_hi(s->qtimer);
     }
+    if (is_pcycle_reg(reg)) {
+        uint64_t value = hexagon_globalreg_read_pcycle(s);
+        return reg == HEX_SREG_PCYCLELO ?
+                (uint32_t)value : (uint32_t)(value >> 32);
+    }
     return s->regs[reg];
 }
 
 static void set_reg_value(HexagonGlobalRegState *s, uint32_t reg,
                           uint32_t value)
 {
+    bool pcycle_enable = reg == HEX_SREG_SYSCFG &&
+        !pcycle_enabled(s->regs[reg]) && pcycle_enabled(value);
+
+    if (is_pcycle_reg(reg)) {
+        pcycle_write(s, reg, value);
+        return;
+    }
+
     s->regs[reg] = value;
+    if (pcycle_enable) {
+        s->g_pcycle_base = 0;
+        if (s->pcycle_running) {
+            s->pcycle_start_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        }
+    }
     if (is_vid_reg(reg)) {
         l2vic_update_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1, value);
     }
+    if (reg == HEX_SREG_MODECTL) {
+        pcycle_set_running(s, modectl_any_thread_running(value));
+    }
 }
 
 uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg,
@@ -256,6 +360,7 @@ static void 
do_hexagon_globalreg_reset(HexagonGlobalRegState *s)
     memset(s->regs, 0, sizeof(s->regs));
 
     s->g_pcycle_base = 0;
+    s->pcycle_running = false;
 
     s->regs[HEX_SREG_EVB] = s->boot_evb;
     s->regs[HEX_SREG_CFGBASE] = HEXAGON_CFG_ADDR_BASE(s->config_table_addr);
@@ -275,6 +380,8 @@ static void 
do_hexagon_globalreg_reset(HexagonGlobalRegState *s)
     }
     s->regs[HEX_SREG_ISDBEN] = isdben_val;
     s->regs[HEX_SREG_MODECTL] = 0x1;
+    pcycle_set_running(s,
+                       modectl_any_thread_running(s->regs[HEX_SREG_MODECTL]));
 
     /*
      * These register indices are placeholders in these arrays
@@ -314,15 +421,46 @@ static void hexagon_globalreg_realize(DeviceState *dev, 
Error **errp)
         error_setg(errp, "hexagon_globalreg: 'qtimer' link property not set");
         return;
     }
+    if (!s->pcycle_freq_hz) {
+        error_setg(errp, "hexagon_globalreg: 'pcycle-freq-hz' must be 
nonzero");
+        return;
+    }
+}
+
+static int hexagon_globalreg_pre_save(void *opaque)
+{
+    HexagonGlobalRegState *s = opaque;
+
+    /* Migrate a stable value, not a timestamp from the source clock. */
+    pcycle_fold(s);
+    return 0;
+}
+
+static int hexagon_globalreg_post_load(void *opaque, int version_id)
+{
+    HexagonGlobalRegState *s = opaque;
+
+    if (version_id < 2) {
+        s->pcycle_running = modectl_any_thread_running(
+            s->regs[HEX_SREG_MODECTL]);
+    }
+    if (s->pcycle_running) {
+        s->pcycle_start_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    }
+    return 0;
 }
 
 static const VMStateDescription vmstate_hexagon_globalreg = {
     .name = "hexagon_globalreg",
-    .version_id = 1,
+    .version_id = 2,
     .minimum_version_id = 1,
+    .pre_save = hexagon_globalreg_pre_save,
+    .post_load = hexagon_globalreg_post_load,
     .fields = (const VMStateField[]){
         VMSTATE_UINT32_ARRAY(regs, HexagonGlobalRegState, NUM_SREGS),
         VMSTATE_UINT64(g_pcycle_base, HexagonGlobalRegState),
+        VMSTATE_INT64_V(pcycle_start_ns, HexagonGlobalRegState, 2),
+        VMSTATE_BOOL_V(pcycle_running, HexagonGlobalRegState, 2),
         VMSTATE_UINT32(boot_evb, HexagonGlobalRegState),
         VMSTATE_UINT64(config_table_addr, HexagonGlobalRegState),
         VMSTATE_UINT32(dsp_rev, HexagonGlobalRegState),
@@ -351,6 +489,8 @@ static const Property hexagon_globalreg_properties[] = {
                      isdben_trusted, false),
     DEFINE_PROP_BOOL("isdben-secure", HexagonGlobalRegState,
                      isdben_secure, false),
+    DEFINE_PROP_UINT32("pcycle-freq-hz", HexagonGlobalRegState,
+                       pcycle_freq_hz, 1000000000),
 };
 
 static void hexagon_globalreg_class_init(ObjectClass *klass, const void *data)
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 1f7d8a8df70..6628b460ce1 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -349,7 +349,6 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
     cpu = env_archcpu(env);
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
                            cpu_mmu_index(env_cpu(env), false));
-    hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1);
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, HVX_COPROC_ENABLED,
                            cpu->hvx_ctx[0] &&
                            GET_SSR_FIELD(SSR_XE, env->t_sreg[HEX_SREG_SSR]));
@@ -848,15 +847,20 @@ uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t 
reg)
 {
     uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
     int ssr_ce = GET_SSR_FIELD(SSR_CE, ssr);
+    HexagonCPU *cpu = env_archcpu(env);
 
     if (reg <= HEX_GREG_G3) {
         return env->greg[reg];
     }
     switch (reg) {
     case HEX_GREG_GPCYCLELO:
-        return ssr_ce ? hexagon_get_sys_pcycle_count_low(env) : 0;
+        return ssr_ce ?
+            hexagon_globalreg_read(cpu->globalregs, HEX_SREG_PCYCLELO,
+                                   env->threadId) : 0;
     case HEX_GREG_GPCYCLEHI:
-        return ssr_ce ? hexagon_get_sys_pcycle_count_high(env) : 0;
+        return ssr_ce ?
+            hexagon_globalreg_read(cpu->globalregs, HEX_SREG_PCYCLEHI,
+                                   env->threadId) : 0;
     default:
         qemu_log_mask(LOG_UNIMP, "reading greg %" PRId32
                 " not yet supported.\n", reg);
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index cf0762ff05f..aed3f061786 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -132,85 +132,6 @@ uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, 
int index)
     g_assert_not_reached();
 }
 
-uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env)
-{
-    uint64_t total = 0;
-    CPUState *cs;
-
-    BQL_LOCK_GUARD();
-    CPU_FOREACH(cs) {
-        CPUHexagonState *thread_env = cpu_env(cs);
-        total += thread_env->t_cycle_count;
-    }
-    return total;
-}
-
-uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env)
-{
-    return (uint32_t)(hexagon_get_sys_pcycle_count(env) >> 32);
-}
-
-uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env)
-{
-    return (uint32_t)(hexagon_get_sys_pcycle_count(env));
-}
-
-/*
- * Every function in this family takes the BQL itself, so the guard below
- * holds it across the read-modify-write.  Nested guards are no-ops.
- */
-void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t val)
-{
-    uint64_t old;
-
-    BQL_LOCK_GUARD();
-    old = hexagon_get_sys_pcycle_count(env);
-    old = deposit64(old, 32, 32, val);
-    hexagon_set_sys_pcycle_count(env, old);
-}
-
-void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t val)
-{
-    uint64_t old;
-
-    BQL_LOCK_GUARD();
-    old = hexagon_get_sys_pcycle_count(env);
-    old = deposit64(old, 0, 32, val);
-    hexagon_set_sys_pcycle_count(env, old);
-}
-
-void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t val)
-{
-    CPUState *cs;
-    uint64_t total;
-    int num_threads;
-    int64_t delta, per_thread, remainder;
-
-    BQL_LOCK_GUARD();
-    total = hexagon_get_sys_pcycle_count(env);
-
-    /* Count active threads */
-    num_threads = 0;
-    CPU_FOREACH(cs) {
-        num_threads++;
-    }
-    g_assert(num_threads > 0);
-
-    /*
-     * Distribute the delta evenly across all threads.
-     * Any remainder goes to the calling thread.
-     */
-    delta = (int64_t)(val - total);
-    per_thread = delta / num_threads;
-    remainder = delta - per_thread * num_threads;
-
-    CPU_FOREACH(cs) {
-        CPUHexagonState *thread_env = cpu_env(cs);
-        thread_env->t_cycle_count += per_thread;
-    }
-    env->t_cycle_count += remainder;
-}
-
 static void hexagon_resume_thread(CPUHexagonState *env)
 {
     CPUState *cs = env_cpu(env);
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index cd4ae2f6838..a6646dd53cd 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -443,6 +443,12 @@ static inline void gen_read_ctrl_reg(DisasContext *ctx, 
const int reg_num,
     } else if (reg_num == HEX_REG_UTIMERHI) {
         gen_helper_sreg_read(dest, tcg_env,
                              tcg_constant_i32(HEX_SREG_TIMERHI));
+    } else if (reg_num == HEX_REG_UPCYCLELO) {
+        gen_helper_upcycle_read(dest, tcg_env,
+                                tcg_constant_i32(HEX_SREG_PCYCLELO));
+    } else if (reg_num == HEX_REG_UPCYCLEHI) {
+        gen_helper_upcycle_read(dest, tcg_env,
+                                tcg_constant_i32(HEX_SREG_PCYCLEHI));
 #else
     } else if (reg_num == HEX_REG_UTIMERLO) {
         TCGv_i64 utimer = tcg_temp_new_i64();
@@ -488,6 +494,8 @@ static inline void gen_read_ctrl_reg_pair(DisasContext 
*ctx, const int reg_num,
         gen_helper_sreg_read(lo, tcg_env, tcg_constant_i32(HEX_SREG_TIMERLO));
         gen_helper_sreg_read(hi, tcg_env, tcg_constant_i32(HEX_SREG_TIMERHI));
         tcg_gen_concat_i32_i64(dest, lo, hi);
+    } else if (reg_num == HEX_REG_UPCYCLELO) {
+        gen_helper_upcycle_read_pair(dest, tcg_env);
 #else
     } else if (reg_num == HEX_REG_UTIMERLO) {
         /* One helper call, so the pair is a coherent 64-bit snapshot. */
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 4705e915aea..63588a91b65 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -692,8 +692,14 @@ static void sim_handle_trap0(CPUHexagonState *env)
 
     case HEX_SYS_READ_PCYCLES:
     {
-        env->gpr[HEX_REG_R00] = hexagon_get_sys_pcycle_count_low(env);
-        env->gpr[HEX_REG_R01] = hexagon_get_sys_pcycle_count_high(env);
+        HexagonCPU *cpu = env_archcpu(env);
+        uint64_t pcycles;
+
+        BQL_LOCK_GUARD();
+        pcycles = cpu->globalregs ?
+            hexagon_globalreg_read_pcycle(cpu->globalregs) : 0;
+        env->gpr[HEX_REG_R00] = (uint32_t)pcycles;
+        env->gpr[HEX_REG_R01] = (uint32_t)(pcycles >> 32);
         break;
     }
 
diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c
index 179b6f53a2a..70384950a40 100644
--- a/target/hexagon/machine.c
+++ b/target/hexagon/machine.c
@@ -37,7 +37,7 @@ const VMStateDescription vmstate_hexagon_cpu = {
         VMSTATE_UINT32(env.threadId, HexagonCPU),
         VMSTATE_UINT32(env.cause_code, HexagonCPU),
         VMSTATE_UINT32(env.wait_next_pc, HexagonCPU),
-        VMSTATE_UINT64(env.t_cycle_count, HexagonCPU),
+        VMSTATE_UNUSED(sizeof(uint64_t)),
         VMSTATE_UINT32(env.imprecise_exception, HexagonCPU),
 
         VMSTATE_END_OF_LIST()
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 4f00ca773f3..0830a14f2a2 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1942,27 +1942,72 @@ uint32_t HELPER(sreg_read)(CPUHexagonState *env, 
uint32_t reg)
 
 uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg)
 {
+    HexagonCPU *cpu = env_archcpu(env);
+
     BQL_LOCK_GUARD();
 
+    if (reg == HEX_SREG_PCYCLELO && cpu->globalregs) {
+        return hexagon_globalreg_read_pcycle(cpu->globalregs);
+    }
     return deposit64((uint64_t) sreg_read(env, reg), 32, 32,
         sreg_read(env, reg + 1));
 }
 
+/*
+ * UPCYCLELO/UPCYCLEHI are the user-visible alias of PCYCLELO/PCYCLEHI,
+ * readable without privilege but only once SSR[CE] is set.
+ */
+uint32_t HELPER(upcycle_read)(CPUHexagonState *env, uint32_t sreg)
+{
+    uint32_t ssr;
+
+    BQL_LOCK_GUARD();
+    ssr = env->t_sreg[HEX_SREG_SSR];
+    if (!GET_SSR_FIELD(SSR_CE, ssr)) {
+        return 0;
+    }
+    return sreg_read(env, sreg);
+}
+
+uint64_t HELPER(upcycle_read_pair)(CPUHexagonState *env)
+{
+    HexagonCPU *cpu = env_archcpu(env);
+    uint32_t ssr;
+
+    BQL_LOCK_GUARD();
+    ssr = env->t_sreg[HEX_SREG_SSR];
+    if (!GET_SSR_FIELD(SSR_CE, ssr)) {
+        return 0;
+    }
+    return cpu->globalregs ?
+           hexagon_globalreg_read_pcycle(cpu->globalregs) : 0;
+}
+
 uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg)
 
 {
+    BQL_LOCK_GUARD();
     return hexagon_greg_read(env, reg);
 }
 
 uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg)
 
 {
+    HexagonCPU *cpu = env_archcpu(env);
+
+    BQL_LOCK_GUARD();
     g_assert((reg & 1) == 0);
 
     if (reg == HEX_GREG_G0 || reg == HEX_GREG_G2) {
         return (uint64_t)(env->greg[reg]) |
                (((uint64_t)(env->greg[reg + 1])) << 32);
     }
+    if (reg == HEX_GREG_GPCYCLELO) {
+        uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
+
+        return GET_SSR_FIELD(SSR_CE, ssr) && cpu->globalregs ?
+               hexagon_globalreg_read_pcycle(cpu->globalregs) : 0;
+    }
     return (uint64_t)hexagon_greg_read(env, reg) |
            ((uint64_t)(hexagon_greg_read(env, reg + 1)) << 32);
 }
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 827859e052c..f643fc5c4c6 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -64,7 +64,6 @@ TCGv hex_llsc_addr;
 TCGv hex_llsc_val;
 TCGv_i64 hex_llsc_val_i64;
 #ifndef CONFIG_USER_ONLY
-TCGv_i64 hex_cycle_count;
 TCGv hex_imprecise_exception;
 #endif
 TCGv hex_vstore_addr[VSTORES_MAX];
@@ -145,16 +144,6 @@ static void gen_precise_exception(int cause, uint32_t PC)
                                tcg_constant_i32(PC));
 }
 
-#ifndef CONFIG_USER_ONLY
-static void gen_pcycle_counters(DisasContext *ctx)
-{
-    if (ctx->pcycle_enabled) {
-        tcg_gen_addi_i64(hex_cycle_count, hex_cycle_count, ctx->num_cycles);
-    }
-}
-#endif
-
-
 static void gen_exec_counters(DisasContext *ctx)
 {
     tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT],
@@ -163,9 +152,6 @@ static void gen_exec_counters(DisasContext *ctx)
                     hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns);
     tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_HVX_CNT],
                     hex_gpr[HEX_REG_QEMU_HVX_CNT], ctx->num_hvx_insns);
-#ifndef CONFIG_USER_ONLY
-    gen_pcycle_counters(ctx);
-#endif
 }
 
 static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
@@ -1108,8 +1094,6 @@ static void gen_commit_hvx(DisasContext *ctx)
     }
 }
 
-#define PCYCLES_PER_PACKET 1
-
 static void update_exec_counters(DisasContext *ctx)
 {
     int num_real_insns = 0;
@@ -1129,7 +1113,6 @@ static void update_exec_counters(DisasContext *ctx)
     ctx->num_packets++;
     ctx->num_insns += num_real_insns;
     ctx->num_hvx_insns += num_hvx_insns;
-    ctx->num_cycles += PCYCLES_PER_PACKET;
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -1309,8 +1292,6 @@ static void 
hexagon_tr_init_disas_context(DisasContextBase *dcbase,
     ctx->hex_def = HEXAGON_CPU_GET_CLASS(hex_cpu)->hex_def;
     ctx->ieee_fp_extension = hex_cpu->cfg.ieee_fp_extension;
 #ifndef CONFIG_USER_ONLY
-    ctx->num_cycles = 0;
-    ctx->pcycle_enabled = FIELD_EX32(hex_flags, TB_FLAGS, PCYCLE_ENABLED);
     ctx->hvx_coproc_enabled =
         FIELD_EX32(hex_flags, TB_FLAGS, HVX_COPROC_ENABLED);
     ctx->hvx_check_emitted = false;
@@ -1465,8 +1446,6 @@ void hexagon_translate_init(void)
     hex_cause_code = tcg_global_mem_new_i32(tcg_env,
         offsetof(CPUHexagonState, cause_code), "cause_code");
 #ifndef CONFIG_USER_ONLY
-    hex_cycle_count = tcg_global_mem_new_i64(tcg_env,
-        offsetof(CPUHexagonState, t_cycle_count), "t_cycle_count");
     hex_imprecise_exception = tcg_global_mem_new(tcg_env,
         offsetof(CPUHexagonState, imprecise_exception), "imprecise_exception");
 #endif
diff --git a/hw/hexagon/trace-events b/hw/hexagon/trace-events
index 5d623ed2516..8c906a30ebd 100644
--- a/hw/hexagon/trace-events
+++ b/hw/hexagon/trace-events
@@ -1,3 +1,4 @@
 # Hexagon global register access
 hexagon_globalreg_read(uint32_t htid, const char *reg_name, uint32_t value) 
"htid=%u reg=%s value=0x%x"
 hexagon_globalreg_write(uint32_t htid, const char *reg_name, uint32_t value) 
"htid=%u reg=%s value=0x%x"
+hexagon_pcycle_run_state(bool running, uint64_t base) "running=%u base=%" 
PRIu64
-- 
2.34.1

Reply via email to