diff options
author | Yongbok Kim <yongbok.kim@imgtec.com> | 2016-02-03 12:31:07 +0000 |
---|---|---|
committer | Leon Alrae <leon.alrae@imgtec.com> | 2016-02-26 08:59:17 +0000 |
commit | 01bc435b44b8802cc4697faa07d908684afbce4e (patch) | |
tree | eb377fa81c980fba2f2c08941e43ba526d395041 /target-mips/op_helper.c | |
parent | bee62662a312b99b4418b558a99b3963a4cbff07 (diff) |
target-mips: implement R6 multi-threading
MIPS Release 6 provides multi-threading features which replace
pre-R6 MT Module. CP0.Config3.MT is always 0 in R6, instead there is new
CP0.Config5.VP (Virtual Processor) bit which indicates presence of
multi-threading support which includes CP0.GlobalNumber register and
DVP/EVP instructions.
Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Diffstat (limited to 'target-mips/op_helper.c')
-rw-r--r-- | target-mips/op_helper.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 684ec92c12..7c5669cc96 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -571,6 +571,14 @@ static bool mips_vpe_is_wfi(MIPSCPU *c) return cpu->halted && mips_vpe_active(env); } +static bool mips_vp_is_wfi(MIPSCPU *c) +{ + CPUState *cpu = CPU(c); + CPUMIPSState *env = &c->env; + + return cpu->halted && mips_vp_active(env); +} + static inline void mips_vpe_wake(MIPSCPU *c) { /* Dont set ->halted = 0 directly, let it be done via cpu_has_work @@ -1840,6 +1848,46 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) return env->CP0_YQMask; } +/* R6 Multi-threading */ +#ifndef CONFIG_USER_ONLY +target_ulong helper_dvp(CPUMIPSState *env) +{ + CPUState *other_cs = first_cpu; + target_ulong prev = env->CP0_VPControl; + + if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) { + CPU_FOREACH(other_cs) { + MIPSCPU *other_cpu = MIPS_CPU(other_cs); + /* Turn off all VPs except the one executing the dvp. */ + if (&other_cpu->env != env) { + mips_vpe_sleep(other_cpu); + } + } + env->CP0_VPControl |= (1 << CP0VPCtl_DIS); + } + return prev; +} + +target_ulong helper_evp(CPUMIPSState *env) +{ + CPUState *other_cs = first_cpu; + target_ulong prev = env->CP0_VPControl; + + if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) { + CPU_FOREACH(other_cs) { + MIPSCPU *other_cpu = MIPS_CPU(other_cs); + if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) { + /* If the VP is WFI, don't disturb its sleep. + * Otherwise, wake it up. */ + mips_vpe_wake(other_cpu); + } + } + env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS); + } + return prev; +} +#endif /* !CONFIG_USER_ONLY */ + #ifndef CONFIG_USER_ONLY /* TLB management */ static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first) |