[PATCH 07/11] target/hexagon: read UTIMERLO/UTIMERHI from the global timer
Brian Cain <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
In system mode, route accesses to the qtimer-backed global TIMERLO/TIMERHI so guest reads see a live, monotonically increasing timer. In user mode we derive it from QEMU_CLOCK_VIRTUAL. Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/helper.h | 4 ++++ target/hexagon/genptr.c | 29 +++++++++++++++++++++++++++++ target/hexagon/op_helper.c | 21 +++++++++++++++++++++ tests/tcg/hexagon/reg_mut.c | 11 ++++++++--- 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 78dc28ca9e5..e39afd623b5 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -113,6 +113,10 @@ DEF_HELPER_FLAGS_4(gvec_sabsdiff_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_uabsdiff_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_uabsdiff_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +#if defined(CONFIG_USER_ONLY) +DEF_HELPER_FLAGS_0(utimer, TCG_CALL_NO_RWG, i64) +#endif + #if !defined(CONFIG_USER_ONLY) DEF_HELPER_3(raise_stack_overflow, void, env, i32, i32) DEF_HELPER_2(swi, void, env, i32) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 2a98b13b714..282a697d190 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -411,6 +411,23 @@ static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num, } else if (reg_num == HEX_REG_QEMU_HVX_CNT) { tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT], ctx->num_hvx_insns); +#ifndef CONFIG_USER_ONLY + } else if (reg_num == HEX_REG_UTIMERLO) { + gen_helper_sreg_read(dest, tcg_env, + tcg_constant_i32(HEX_SREG_TIMERLO)); + } else if (reg_num == HEX_REG_UTIMERHI) { + gen_helper_sreg_read(dest, tcg_env, + tcg_constant_i32(HEX_SREG_TIMERHI)); +#else + } else if (reg_num == HEX_REG_UTIMERLO) { + TCGv_i64 utimer = tcg_temp_new_i64(); + gen_helper_utimer(utimer); + tcg_gen_extrl_i64_i32(dest, utimer); + } else if (reg_num == HEX_REG_UTIMERHI) { + TCGv_i64 utimer = tcg_temp_new_i64(); + gen_helper_utimer(utimer); + tcg_gen_extrh_i64_i32(dest, utimer); +#endif } else { tcg_gen_mov_tl(dest, hex_gpr[reg_num]); } @@ -439,6 +456,18 @@ static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num, tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT], ctx->num_hvx_insns); tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]); +#ifndef CONFIG_USER_ONLY + } else if (reg_num == HEX_REG_UTIMERLO) { + TCGv lo = tcg_temp_new(); + TCGv hi = tcg_temp_new(); + 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 + } else if (reg_num == HEX_REG_UTIMERLO) { + /* One helper call, so the pair is a coherent 64-bit snapshot. */ + gen_helper_utimer(dest); +#endif } else { tcg_gen_concat_i32_i64(dest, hex_gpr[reg_num], diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 2cea1927263..df31ed2488a 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -37,6 +37,9 @@ #include "cpu_helper.h" #include "tcg/tcg-gvec-desc.h" #include "translate.h" +#ifdef CONFIG_USER_ONLY +#include "qemu/timer.h" +#endif #ifndef CONFIG_USER_ONLY #include "hw/hexagon/hexagon_globalreg.h" #include "hex_mmu.h" @@ -46,6 +49,24 @@ #include "hexswi.h" #endif +#ifdef CONFIG_USER_ONLY +/* + * User mode has no qtimer device backing TIMERLO/TIMERHI, so derive the + * user timer directly from the virtual clock -- the same clock the qtimer + * counts -- at the qtimer's default 19.2MHz tick rate, masked to the + * qtimer's counter width. + */ +#define HEX_UTIMER_FREQ_HZ 19200000ULL +#define HEX_UTIMER_CNT_MASK 0x00ffffffffffffffULL + +uint64_t HELPER(utimer)(void) +{ + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + HEX_UTIMER_FREQ_HZ, NANOSECONDS_PER_SECOND) & + HEX_UTIMER_CNT_MASK; +} +#endif + #define SF_BIAS 127 #define SF_MANTBITS 23 diff --git a/tests/tcg/hexagon/reg_mut.c b/tests/tcg/hexagon/reg_mut.c index c5a39e55100..9ce18f3ebe5 100644 --- a/tests/tcg/hexagon/reg_mut.c +++ b/tests/tcg/hexagon/reg_mut.c @@ -77,10 +77,10 @@ static inline void write_control_registers(void) check32(result, 0x00000000); WRITE_REG_NOCLOBBER(result, "utimerlo", 0xffffffff); - check32(result, 0x00000000); + check32_ne(result, 0xffffffff); WRITE_REG_NOCLOBBER(result, "utimerhi", 0xffffffff); - check32(result, 0x00000000); + check32_ne(result, 0xffffffff); /* * PC is special. Setting it to these values @@ -106,8 +106,13 @@ static inline void write_control_register_pairs(void) WRITE_REG_NOCLOBBER(result, "c15:14", 0xffffffffffffffff); check64(result, 0x0000000000000000); + /* + * c31:30 is UTIMERHI:UTIMERLO, a read-only free-running counter. The + * write must be discarded; the read-back is whatever the timer says, + * so only check that the written value did not stick. + */ WRITE_REG_NOCLOBBER(result, "c31:30", 0xffffffffffffffff); - check64(result, 0x0000000000000000); + check64_ne(result, 0xffffffffffffffff); WRITE_REG_PAIR_ENCODED(result, "c9:8", (uint64_t) 0x0000000000000000, C9_8_EQ_R1_0); -- 2.34.1