diff --git a/target/mips/cpu.c b/target/mips/cpu.c index b223b767c9..d72044aef6 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -320,6 +320,7 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type) env->CP0_HWREna |= 0x0000000F; if (env->insn_flags & INSN_OCTEON) { env->CP0_HWREna |= 0x40000000u; + env->CP0_HWREna |= 0x80000000u; } if (env->CP0_Config1 & (1 << CP0C1_FP)) { env->CP0_Status |= (1 << CP0St_CU1); diff --git a/target/mips/helper.h b/target/mips/helper.h index 141350e80a..786117813a 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -255,6 +255,7 @@ DEF_HELPER_1(rdhwr_ccres, tl, env) DEF_HELPER_1(rdhwr_performance, tl, env) DEF_HELPER_1(rdhwr_xnp, tl, env) DEF_HELPER_1(rdhwr_chord, tl, env) +DEF_HELPER_1(rdhwr_cvmcount, tl, env) DEF_HELPER_2(pmon, void, env, int) DEF_HELPER_1(wait, void, env) diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c index 3e586e3049..df1b5c3734 100644 --- a/target/mips/tcg/op_helper.c +++ b/target/mips/tcg/op_helper.c @@ -25,6 +25,7 @@ #include "exec/memop.h" #include "fpu_helper.h" #include "qemu/crc32c.h" +#include "qemu/timer.h" #include static inline target_ulong bitswap(target_ulong v) @@ -209,7 +210,7 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc) { - if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) { + if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1u << reg))) { return; } do_raise_exception(env, EXCP_RI, pc); @@ -261,6 +262,16 @@ target_ulong helper_rdhwr_chord(CPUMIPSState *env) return env->octeon_crypto.chord; } +target_ulong helper_rdhwr_cvmcount(CPUMIPSState *env) +{ + check_hwrena(env, 31, GETPC()); +#ifdef CONFIG_USER_ONLY + return cpu_get_host_ticks(); +#else + return (uint32_t)cpu_mips_get_count(env); +#endif +} + void helper_pmon(CPUMIPSState *env, int function) { function /= 2; diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 1f44932882..e3467d1525 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -10933,6 +10933,17 @@ void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) gen_helper_rdhwr_chord(t0, tcg_env); gen_store_gpr(t0, rt); break; + case 31: + if (!(ctx->insn_flags & INSN_OCTEON)) { + gen_reserved_instruction(ctx); + break; + } + translator_io_start(&ctx->base); + gen_helper_rdhwr_cvmcount(t0, tcg_env); + gen_store_gpr(t0, rt); + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; + break; default: /* Invalid */ MIPS_INVAL("rdhwr"); gen_reserved_instruction(ctx); diff --git a/tests/tcg/mips/user/isa/octeon/octeon-insns.c b/tests/tcg/mips/user/isa/octeon/octeon-insns.c index f3c52d7829..6480c8532a 100644 --- a/tests/tcg/mips/user/isa/octeon/octeon-insns.c +++ b/tests/tcg/mips/user/isa/octeon/octeon-insns.c @@ -330,6 +330,22 @@ static uint64_t octeon_cop2_gfm_mul_reflect_readback(uint64_t value) return rd; } +static uint64_t octeon_rdhwr31_non_decreasing(void) +{ + uint64_t first, second; + + asm volatile( + ".word 0x7c08f83b\n\t" /* rdhwr $8, $31 */ + ".word 0x7c09f83b\n\t" /* rdhwr $9, $31 */ + "move %[first], $8\n\t" + "move %[second], $9\n\t" + : [first] "=r" (first), [second] "=r" (second) + : + : "$8", "$9"); + + return second >= first; +} + int main(void) { assert(octeon_baddu(0x123, 0x0f0) == 0x13); @@ -358,6 +374,7 @@ int main(void) 0x0123456789abcdefULL) == 0xf7b3d591e6a2c480ULL); assert(octeon_cop2_gfm_mul_reflect_readback( 0xfedcba9876543210ULL) == 0x084c2a6e195d3b7fULL); + assert(octeon_rdhwr31_non_decreasing()); return 0; }