From patchwork Wed Feb 3 12:31:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leon Alrae X-Patchwork-Id: 8201781 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 1DF469F1C0 for ; Wed, 3 Feb 2016 12:31:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 087752025B for ; Wed, 3 Feb 2016 12:31:54 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B363320221 for ; Wed, 3 Feb 2016 12:31:52 +0000 (UTC) Received: from localhost ([::1]:34443 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQwbA-0007QM-3c for patchwork-qemu-devel@patchwork.kernel.org; Wed, 03 Feb 2016 07:31:52 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57775) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQwap-0007GM-QB for qemu-devel@nongnu.org; Wed, 03 Feb 2016 07:31:36 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aQwaj-0002N0-25 for qemu-devel@nongnu.org; Wed, 03 Feb 2016 07:31:30 -0500 Received: from mailapp01.imgtec.com ([195.59.15.196]:1824) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQwai-0002Lt-Og for qemu-devel@nongnu.org; Wed, 03 Feb 2016 07:31:24 -0500 Received: from hhmail02.hh.imgtec.org (unknown [10.100.10.20]) by Websense Email Security Gateway with ESMTPS id 4B4C7597512B9; Wed, 3 Feb 2016 12:31:18 +0000 (GMT) Received: from lalrae-linux.kl.imgtec.org (192.168.169.37) by hhmail02.hh.imgtec.org (10.100.10.20) with Microsoft SMTP Server (TLS) id 14.3.266.1; Wed, 3 Feb 2016 12:31:20 +0000 From: Leon Alrae To: Date: Wed, 3 Feb 2016 12:31:07 +0000 Message-ID: <1454502667-9014-1-git-send-email-leon.alrae@imgtec.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 X-Originating-IP: [192.168.169.37] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 195.59.15.196 Cc: Yongbok Kim , aurelien@aurel32.net Subject: [Qemu-devel] [PATCH v2] target-mips: implement R6 multi-threading X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Yongbok Kim 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 Signed-off-by: Leon Alrae --- This is an updated version of the patch originally sent by Yongbok some time ago. v2: * rebased * fix typo: GlobalNumer -> GlobalNumber * fix minor style issues * update the patch description --- disas/mips.c | 4 +++ target-mips/cpu.c | 9 +++++++ target-mips/cpu.h | 25 +++++++++++++++++++ target-mips/helper.h | 4 +++ target-mips/op_helper.c | 48 +++++++++++++++++++++++++++++++++++ target-mips/translate.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ target-mips/translate_init.c | 3 ++- 7 files changed, 151 insertions(+), 1 deletion(-) diff --git a/disas/mips.c b/disas/mips.c index 0e488d8..249931b 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1405,6 +1405,10 @@ const struct mips_opcode mips_builtin_opcodes[] = {"cmp.sor.d", "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, {"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, {"cmp.sne.d", "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"dvp", "", 0x41600024, 0xffffffff, TRAP, 0, I32R6}, +{"dvp", "t", 0x41600024, 0xffe0ffff, TRAP|WR_t, 0, I32R6}, +{"evp", "", 0x41600004, 0xffffffff, TRAP, 0, I32R6}, +{"evp", "t", 0x41600004, 0xffe0ffff, TRAP|WR_t, 0, I32R6}, /* MSA */ {"sll.b", "+d,+e,+f", 0x7800000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 0b3f130..7dc3a44 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -77,6 +77,15 @@ static bool mips_cpu_has_work(CPUState *cs) has_work = false; } } + /* MIPS Release 6 has the ability to halt the CPU. */ + if (env->CP0_Config5 & (1 << CP0C5_VP)) { + if (cs->interrupt_request & CPU_INTERRUPT_WAKE) { + has_work = true; + } + if (!mips_vp_active(env)) { + has_work = false; + } + } return has_work; } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 86b6333..ae8c575 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -238,6 +238,8 @@ struct CPUMIPSState { int32_t CP0_Index; /* CP0_MVP* are per MVP registers. */ + int32_t CP0_VPControl; +#define CP0VPCtl_DIS 0 int32_t CP0_Random; int32_t CP0_VPEControl; #define CP0VPECo_YSI 21 @@ -287,6 +289,8 @@ struct CPUMIPSState { # define CP0EnLo_RI 31 # define CP0EnLo_XI 30 #endif + int32_t CP0_GlobalNumber; +#define CP0GN_VPId 0 target_ulong CP0_Context; target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM]; int32_t CP0_PageMask; @@ -472,6 +476,7 @@ struct CPUMIPSState { #define CP0C5_XNP 13 #define CP0C5_UFE 9 #define CP0C5_FRE 8 +#define CP0C5_VP 7 #define CP0C5_SBRI 6 #define CP0C5_MVH 5 #define CP0C5_LLB 4 @@ -859,6 +864,26 @@ static inline int mips_vpe_active(CPUMIPSState *env) return active; } +static inline int mips_vp_active(CPUMIPSState *env) +{ + CPUState *other_cs = first_cpu; + + /* Check if the VP disabled other VPs (which means the VP is enabled) */ + if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) { + return 1; + } + + /* Check if the virtual processor is disabled due to a DVP */ + CPU_FOREACH(other_cs) { + MIPSCPU *other_cpu = MIPS_CPU(other_cs); + if ((&other_cpu->env != env) && + ((other_cpu->env.CP0_VPControl >> CP0VPCtl_DIS) & 1)) { + return 0; + } + } + return 1; +} + #include "exec/exec-all.h" static inline void compute_hflags(CPUMIPSState *env) diff --git a/target-mips/helper.h b/target-mips/helper.h index 95b9149..1bc8bb2 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -176,6 +176,10 @@ DEF_HELPER_0(dmt, tl) DEF_HELPER_0(emt, tl) DEF_HELPER_1(dvpe, tl, env) DEF_HELPER_1(evpe, tl, env) + +/* R6 Multi-threading */ +DEF_HELPER_1(dvp, tl, env) +DEF_HELPER_1(evp, tl, env) #endif /* !CONFIG_USER_ONLY */ /* microMIPS functions */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 684ec92..7c5669c 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) diff --git a/target-mips/translate.c b/target-mips/translate.c index 383d4b5..c6e2951 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -893,6 +893,8 @@ enum { OPC_EVPE = 0x01 | (1 << 5) | OPC_MFMC0, OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0, OPC_EI = (1 << 5) | (0x0C << 11) | OPC_MFMC0, + OPC_DVP = 0x04 | (0 << 3) | (1 << 5) | (0 << 11) | OPC_MFMC0, + OPC_EVP = 0x04 | (0 << 3) | (0 << 5) | (0 << 11) | OPC_MFMC0, }; /* Coprocessor 0 (with rs == C0) */ @@ -1428,6 +1430,7 @@ typedef struct DisasContext { bool mvh; int CP0_LLAddr_shift; bool ps; + bool vp; } DisasContext; enum { @@ -4949,6 +4952,11 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mfc0_mvpconf1(arg, cpu_env); rn = "MVPConf1"; break; + case 4: + CP0_CHECK(ctx->vp); + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPControl)); + rn = "VPControl"; + break; default: goto cp0_unimplemented; } @@ -5076,6 +5084,11 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) } rn = "EntryLo1"; break; + case 1: + CP0_CHECK(ctx->vp); + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_GlobalNumber)); + rn = "GlobalNumber"; + break; default: goto cp0_unimplemented; } @@ -5596,6 +5609,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* ignored */ rn = "MVPConf1"; break; + case 4: + CP0_CHECK(ctx->vp); + /* ignored */ + rn = "VPControl"; + break; default: goto cp0_unimplemented; } @@ -5698,6 +5716,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mtc0_entrylo1(cpu_env, arg); rn = "EntryLo1"; break; + case 1: + CP0_CHECK(ctx->vp); + /* ignored */ + rn = "GlobalNumber"; + break; default: goto cp0_unimplemented; } @@ -6233,6 +6256,11 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mfc0_mvpconf1(arg, cpu_env); rn = "MVPConf1"; break; + case 4: + CP0_CHECK(ctx->vp); + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPControl)); + rn = "VPControl"; + break; default: goto cp0_unimplemented; } @@ -6334,6 +6362,11 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1)); rn = "EntryLo1"; break; + case 1: + CP0_CHECK(ctx->vp); + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_GlobalNumber)); + rn = "GlobalNumber"; + break; default: goto cp0_unimplemented; } @@ -6840,6 +6873,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* ignored */ rn = "MVPConf1"; break; + case 4: + CP0_CHECK(ctx->vp); + /* ignored */ + rn = "VPControl"; + break; default: goto cp0_unimplemented; } @@ -6940,6 +6978,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_dmtc0_entrylo1(cpu_env, arg); rn = "EntryLo1"; break; + case 1: + CP0_CHECK(ctx->vp); + /* ignored */ + rn = "GlobalNumber"; + break; default: goto cp0_unimplemented; } @@ -19079,6 +19122,20 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) gen_helper_evpe(t0, cpu_env); gen_store_gpr(t0, rt); break; + case OPC_DVP: + check_insn(ctx, ISA_MIPS32R6); + if (ctx->vp) { + gen_helper_dvp(t0, cpu_env); + gen_store_gpr(t0, rt); + } + break; + case OPC_EVP: + check_insn(ctx, ISA_MIPS32R6); + if (ctx->vp) { + gen_helper_evp(t0, cpu_env); + gen_store_gpr(t0, rt); + } + break; case OPC_DI: check_insn(ctx, ISA_MIPS32R2); save_cpu_state(ctx, 1); @@ -19610,6 +19667,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb) ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1; ctx.ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) || (env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)); + ctx.vp = (env->CP0_Config5 >> CP0C5_VP) & 1; restore_cpu_state(env, &ctx); #ifdef CONFIG_USER_ONLY ctx.mem_idx = MIPS_HFLAG_UM; @@ -19994,6 +20052,7 @@ void cpu_state_reset(CPUMIPSState *env) env->CP0_Random = env->tlb->nb_tlb - 1; env->tlb->tlb_in_use = env->tlb->nb_tlb; env->CP0_Wired = 0; + env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId; env->CP0_EBase = (cs->cpu_index & 0x3FF); if (kvm_enabled()) { env->CP0_EBase |= 0x40000000; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index bb33c7c..cdef59d 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -665,7 +665,8 @@ static const mips_def_t mips_defs[] = (1 << CP0C3_RXI) | (1 << CP0C3_LPA), .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) | (0xfc << CP0C4_KScrExist), - .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_LLB), + .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_VP) | + (1 << CP0C5_LLB), .CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) | (1 << CP0C5_UFE), .CP0_LLAddr_rw_bitmask = 0,