Loading target-mips/cpu.h +51 −0 Original line number Diff line number Diff line Loading @@ -618,6 +618,14 @@ enum { /* Dummy exception for conditional stores. */ #define EXCP_SC 0x100 /* * This is an interrnally generated WAKE request line. * It is driven by the CPU itself. Raised when the MT * block wants to wake a VPE from an inactive state and * cleared when VPE goes from active to inactive. */ #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 int cpu_mips_exec(CPUMIPSState *s); CPUMIPSState *cpu_mips_init(const char *cpu_model); //~ uint32_t cpu_mips_get_clock (void); Loading Loading @@ -658,6 +666,37 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls) env->tls_value = newtls; } static inline int mips_vpe_active(CPUState *env) { int active = 1; /* Check that the VPE is enabled. */ if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) { active = 0; } /* Check that the VPE is actived. */ if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) { active = 0; } /* Now verify that there are active thread contexts in the VPE. This assumes the CPU model will internally reschedule threads if the active one goes to sleep. If there are no threads available the active one will be in a sleeping state, and we can turn off the entire VPE. */ if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) { /* TC is not activated. */ active = 0; } if (env->active_tc.CP0_TCHalt & 1) { /* TC is in halt state. */ active = 0; } return active; } static inline int cpu_has_work(CPUState *env) { int has_work = 0; Loading @@ -670,6 +709,18 @@ static inline int cpu_has_work(CPUState *env) has_work = 1; } /* MIPS-MT has the ability to halt the CPU. */ if (env->CP0_Config3 & (1 << CP0C3_MT)) { /* The QEMU model will issue an _WAKE request whenever the CPUs should be woken up. */ if (env->interrupt_request & CPU_INTERRUPT_WAKE) { has_work = 1; } if (!mips_vpe_active(env)) { has_work = 0; } } return has_work; } Loading target-mips/op_helper.c +78 −4 Original line number Diff line number Diff line Loading @@ -749,6 +749,46 @@ void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) #endif #ifndef CONFIG_USER_ONLY /* SMP helpers. */ static int mips_vpe_is_wfi(CPUState *c) { /* If the VPE is halted but otherwise active, it means it's waiting for an interrupt. */ return c->halted && mips_vpe_active(c); } static inline void mips_vpe_wake(CPUState *c) { /* Dont set ->halted = 0 directly, let it be done via cpu_has_work because there might be other conditions that state that c should be sleeping. */ cpu_interrupt(c, CPU_INTERRUPT_WAKE); } static inline void mips_vpe_sleep(CPUState *c) { /* The VPE was shut off, really go to bed. Reset any old _WAKE requests. */ c->halted = 1; cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE); } static inline void mips_tc_wake(CPUState *c, int tc) { /* FIXME: TC reschedule. */ if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) { mips_vpe_wake(c); } } static inline void mips_tc_sleep(CPUState *c, int tc) { /* FIXME: TC reschedule. */ if (!mips_vpe_active(c)) { mips_vpe_sleep(c); } } /* tc should point to an int with the value of the global TC index. This function will transform it into a local index within the returned CPUState. Loading Loading @@ -1340,6 +1380,11 @@ void helper_mtc0_tchalt (target_ulong arg1) env->active_tc.CP0_TCHalt = arg1 & 0x1; // TODO: Halt TC / Restart (if allocated+active) TC. if (env->active_tc.CP0_TCHalt & 1) { mips_tc_sleep(env, env->current_tc); } else { mips_tc_wake(env, env->current_tc); } } void helper_mttc0_tchalt (target_ulong arg1) Loading @@ -1353,6 +1398,12 @@ void helper_mttc0_tchalt (target_ulong arg1) other->active_tc.CP0_TCHalt = arg1; else other->tcs[other_tc].CP0_TCHalt = arg1; if (arg1 & 1) { mips_tc_sleep(other, other_tc); } else { mips_tc_wake(other, other_tc); } } void helper_mtc0_tccontext (target_ulong arg1) Loading Loading @@ -1858,14 +1909,36 @@ target_ulong helper_emt(void) target_ulong helper_dvpe(void) { // TODO return 0; CPUState *other_cpu = first_cpu; target_ulong prev = env->mvp->CP0_MVPControl; do { /* Turn off all VPEs except the one executing the dvpe. */ if (other_cpu != env) { other_cpu->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP); mips_vpe_sleep(other_cpu); } other_cpu = other_cpu->next_cpu; } while (other_cpu); return prev; } target_ulong helper_evpe(void) { // TODO return 0; CPUState *other_cpu = first_cpu; target_ulong prev = env->mvp->CP0_MVPControl; do { if (other_cpu != env /* If the VPE is WFI, dont distrub it's sleep. */ && !mips_vpe_is_wfi(other_cpu)) { /* Enable the VPE. */ other_cpu->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); mips_vpe_wake(other_cpu); /* And wake it up. */ } other_cpu = other_cpu->next_cpu; } while (other_cpu); return prev; } #endif /* !CONFIG_USER_ONLY */ Loading Loading @@ -2213,6 +2286,7 @@ void helper_pmon (int function) void helper_wait (void) { env->halted = 1; cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE); helper_raise_exception(EXCP_HLT); } Loading Loading
target-mips/cpu.h +51 −0 Original line number Diff line number Diff line Loading @@ -618,6 +618,14 @@ enum { /* Dummy exception for conditional stores. */ #define EXCP_SC 0x100 /* * This is an interrnally generated WAKE request line. * It is driven by the CPU itself. Raised when the MT * block wants to wake a VPE from an inactive state and * cleared when VPE goes from active to inactive. */ #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 int cpu_mips_exec(CPUMIPSState *s); CPUMIPSState *cpu_mips_init(const char *cpu_model); //~ uint32_t cpu_mips_get_clock (void); Loading Loading @@ -658,6 +666,37 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls) env->tls_value = newtls; } static inline int mips_vpe_active(CPUState *env) { int active = 1; /* Check that the VPE is enabled. */ if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) { active = 0; } /* Check that the VPE is actived. */ if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) { active = 0; } /* Now verify that there are active thread contexts in the VPE. This assumes the CPU model will internally reschedule threads if the active one goes to sleep. If there are no threads available the active one will be in a sleeping state, and we can turn off the entire VPE. */ if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) { /* TC is not activated. */ active = 0; } if (env->active_tc.CP0_TCHalt & 1) { /* TC is in halt state. */ active = 0; } return active; } static inline int cpu_has_work(CPUState *env) { int has_work = 0; Loading @@ -670,6 +709,18 @@ static inline int cpu_has_work(CPUState *env) has_work = 1; } /* MIPS-MT has the ability to halt the CPU. */ if (env->CP0_Config3 & (1 << CP0C3_MT)) { /* The QEMU model will issue an _WAKE request whenever the CPUs should be woken up. */ if (env->interrupt_request & CPU_INTERRUPT_WAKE) { has_work = 1; } if (!mips_vpe_active(env)) { has_work = 0; } } return has_work; } Loading
target-mips/op_helper.c +78 −4 Original line number Diff line number Diff line Loading @@ -749,6 +749,46 @@ void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) #endif #ifndef CONFIG_USER_ONLY /* SMP helpers. */ static int mips_vpe_is_wfi(CPUState *c) { /* If the VPE is halted but otherwise active, it means it's waiting for an interrupt. */ return c->halted && mips_vpe_active(c); } static inline void mips_vpe_wake(CPUState *c) { /* Dont set ->halted = 0 directly, let it be done via cpu_has_work because there might be other conditions that state that c should be sleeping. */ cpu_interrupt(c, CPU_INTERRUPT_WAKE); } static inline void mips_vpe_sleep(CPUState *c) { /* The VPE was shut off, really go to bed. Reset any old _WAKE requests. */ c->halted = 1; cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE); } static inline void mips_tc_wake(CPUState *c, int tc) { /* FIXME: TC reschedule. */ if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) { mips_vpe_wake(c); } } static inline void mips_tc_sleep(CPUState *c, int tc) { /* FIXME: TC reschedule. */ if (!mips_vpe_active(c)) { mips_vpe_sleep(c); } } /* tc should point to an int with the value of the global TC index. This function will transform it into a local index within the returned CPUState. Loading Loading @@ -1340,6 +1380,11 @@ void helper_mtc0_tchalt (target_ulong arg1) env->active_tc.CP0_TCHalt = arg1 & 0x1; // TODO: Halt TC / Restart (if allocated+active) TC. if (env->active_tc.CP0_TCHalt & 1) { mips_tc_sleep(env, env->current_tc); } else { mips_tc_wake(env, env->current_tc); } } void helper_mttc0_tchalt (target_ulong arg1) Loading @@ -1353,6 +1398,12 @@ void helper_mttc0_tchalt (target_ulong arg1) other->active_tc.CP0_TCHalt = arg1; else other->tcs[other_tc].CP0_TCHalt = arg1; if (arg1 & 1) { mips_tc_sleep(other, other_tc); } else { mips_tc_wake(other, other_tc); } } void helper_mtc0_tccontext (target_ulong arg1) Loading Loading @@ -1858,14 +1909,36 @@ target_ulong helper_emt(void) target_ulong helper_dvpe(void) { // TODO return 0; CPUState *other_cpu = first_cpu; target_ulong prev = env->mvp->CP0_MVPControl; do { /* Turn off all VPEs except the one executing the dvpe. */ if (other_cpu != env) { other_cpu->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP); mips_vpe_sleep(other_cpu); } other_cpu = other_cpu->next_cpu; } while (other_cpu); return prev; } target_ulong helper_evpe(void) { // TODO return 0; CPUState *other_cpu = first_cpu; target_ulong prev = env->mvp->CP0_MVPControl; do { if (other_cpu != env /* If the VPE is WFI, dont distrub it's sleep. */ && !mips_vpe_is_wfi(other_cpu)) { /* Enable the VPE. */ other_cpu->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); mips_vpe_wake(other_cpu); /* And wake it up. */ } other_cpu = other_cpu->next_cpu; } while (other_cpu); return prev; } #endif /* !CONFIG_USER_ONLY */ Loading Loading @@ -2213,6 +2286,7 @@ void helper_pmon (int function) void helper_wait (void) { env->halted = 1; cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE); helper_raise_exception(EXCP_HLT); } Loading