mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:10 +00:00
target/mips: add Octeon CvmCount RDHWR support
Octeon exposes CvmCount through RDHWR register 31. Add the Octeon-only decode path, enable the corresponding HWREna bit for linux-user, and use an unsigned mask when checking HWREna so bit 31 is handled safely. For user-mode emulation, return host ticks as a monotonic counter source suitable for existing Octeon userspace code. In system mode, fall back to the existing CP0 Count value. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: James Hilliard <james.hilliard1@gmail.com> Message-ID: <20260608-mips-octeon-missing-insns-v2-v16-20-daef7a0d8b04@gmail.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
This commit is contained in:
committed by
Philippe Mathieu-Daudé
parent
8d399e3e03
commit
c2fd17ec64
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "exec/memop.h"
|
||||
#include "fpu_helper.h"
|
||||
#include "qemu/crc32c.h"
|
||||
#include "qemu/timer.h"
|
||||
#include <zlib.h>
|
||||
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user