From patchwork Wed Jun 3 09:32:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leon Alrae X-Patchwork-Id: 479848 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 39737140280 for ; Wed, 3 Jun 2015 19:37:05 +1000 (AEST) Received: from localhost ([::1]:34265 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z056d-0005Kr-2Y for incoming@patchwork.ozlabs.org; Wed, 03 Jun 2015 05:37:03 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54785) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z052h-0006md-Dk for qemu-devel@nongnu.org; Wed, 03 Jun 2015 05:33:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Z052d-0007qd-6F for qemu-devel@nongnu.org; Wed, 03 Jun 2015 05:32:59 -0400 Received: from mailapp01.imgtec.com ([195.59.15.196]:28087) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z052c-0007qH-Ub for qemu-devel@nongnu.org; Wed, 03 Jun 2015 05:32:55 -0400 Received: from KLMAIL01.kl.imgtec.org (unknown [192.168.5.35]) by Websense Email Security Gateway with ESMTPS id 60734EC8898AA; Wed, 3 Jun 2015 10:32:51 +0100 (IST) Received: from lalrae-linux.kl.imgtec.org (192.168.14.163) by KLMAIL01.kl.imgtec.org (192.168.5.35) with Microsoft SMTP Server (TLS) id 14.3.195.1; Wed, 3 Jun 2015 10:32:52 +0100 From: Leon Alrae To: Date: Wed, 3 Jun 2015 10:32:33 +0100 Message-ID: <1433323956-7867-5-git-send-email-leon.alrae@imgtec.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1433323956-7867-1-git-send-email-leon.alrae@imgtec.com> References: <1433323956-7867-1-git-send-email-leon.alrae@imgtec.com> MIME-Version: 1.0 X-Originating-IP: [192.168.14.163] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 195.59.15.196 Cc: james.hogan@imgtec.com, aurelien@aurel32.net Subject: [Qemu-devel] [PATCH v2 4/7] target-mips: add MTHC0 and MFHC0 instructions 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Implement MTHC0 and MFHC0 instructions. In MIPS32 they are used to access upper word of extended to 64-bits CP0 registers. In MIPS64, when CP0 destination register specified is the EntryLo0 or EntryLo1, bits 1:0 of the GPR appear at bits 31:30 of EntryLo0 or EntryLo1. This is to compensate for RI and XI, which were shifted to bits 63:62 by MTC0 to EntryLo0 or EntryLo1. Therefore creating separate functions for EntryLo0 and EntryLo1. Signed-off-by: Leon Alrae --- disas/mips.c | 2 + target-mips/cpu.h | 1 + target-mips/translate.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) diff --git a/disas/mips.c b/disas/mips.c index 1afe0c5..8aaa87c 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -2238,6 +2238,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, {"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, {"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"mfhc0", "t,G,H", 0x40400000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I33}, +{"mthc0", "t,G,H", 0x40c00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I33}, {"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, {"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, {"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, diff --git a/target-mips/cpu.h b/target-mips/cpu.h index e106bb8..7b5ef36 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -473,6 +473,7 @@ struct CPUMIPSState { #define CP0C5_UFE 9 #define CP0C5_FRE 8 #define CP0C5_SBRI 6 +#define CP0C5_MVH 5 #define CP0C5_UFR 2 #define CP0C5_NFExists 0 int32_t CP0_Config6; diff --git a/target-mips/translate.c b/target-mips/translate.c index 9b77816..c931eda 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -868,8 +868,10 @@ enum { enum { OPC_MFC0 = (0x00 << 21) | OPC_CP0, OPC_DMFC0 = (0x01 << 21) | OPC_CP0, + OPC_MFHC0 = (0x02 << 21) | OPC_CP0, OPC_MTC0 = (0x04 << 21) | OPC_CP0, OPC_DMTC0 = (0x05 << 21) | OPC_CP0, + OPC_MTHC0 = (0x06 << 21) | OPC_CP0, OPC_MFTR = (0x08 << 21) | OPC_CP0, OPC_RDPGPR = (0x0A << 21) | OPC_CP0, OPC_MFMC0 = (0x0B << 21) | OPC_CP0, @@ -1424,6 +1426,9 @@ typedef struct DisasContext { int ie; bool bi; bool bp; + uint64_t PAMask; + bool mvh; + int CP0_LLAddr_shift; } DisasContext; enum { @@ -1770,6 +1775,13 @@ static inline void check_cp1_registers(DisasContext *ctx, int regs) This is enabled by CP0 Status register MX(24) bit. */ +static inline void check_mvh(DisasContext *ctx) +{ + if (unlikely(!ctx->mvh)) { + generate_exception(ctx, EXCP_RI); + } +} + static inline void check_dsp(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_DSP))) { @@ -4833,6 +4845,65 @@ static void gen_bshfl (DisasContext *ctx, uint32_t op2, int rt, int rd) #ifndef CONFIG_USER_ONLY /* CP0 (MMU and control) */ +static inline void gen_mthc0_entrylo(TCGv arg, target_ulong off) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t0, arg); + tcg_gen_ld_i64(t1, cpu_env, off); +#if defined(TARGET_MIPS64) + tcg_gen_deposit_i64(t1, t1, t0, 30, 32); +#else + tcg_gen_concat32_i64(t1, t1, t0); +#endif + tcg_gen_st_i64(t1, cpu_env, off); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static inline void gen_mthc0_store64(TCGv arg, target_ulong off) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t0, arg); + tcg_gen_ld_i64(t1, cpu_env, off); + tcg_gen_concat32_i64(t1, t1, t0); + tcg_gen_st_i64(t1, cpu_env, off); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static inline void gen_mfhc0_entrylo(TCGv arg, target_ulong off) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + + tcg_gen_ld_i64(t0, cpu_env, off); +#if defined(TARGET_MIPS64) + tcg_gen_shri_i64(t0, t0, 30); + tcg_gen_ext32s_tl(arg, t0); +#else + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_tl(arg, t0); +#endif + tcg_temp_free_i64(t0); +} + +static inline void gen_mfhc0_load64(TCGv arg, target_ulong off, int shift) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + + tcg_gen_ld_i64(t0, cpu_env, off); + tcg_gen_shri_i64(t0, t0, 32 + shift); +#if defined(TARGET_MIPS64) + tcg_gen_ext32s_tl(arg, t0); +#else + tcg_gen_trunc_i64_tl(arg, t0); +#endif + tcg_temp_free_i64(t0); +} + static inline void gen_mfc0_load32 (TCGv arg, target_ulong off) { TCGv_i32 t0 = tcg_temp_new_i32(); @@ -4863,6 +4934,140 @@ static inline void gen_mtc0_store64 (TCGv arg, target_ulong off) tcg_gen_st_tl(arg, cpu_env, off); } +static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel) +{ + const char *rn = "invalid"; + + if (!(ctx->hflags & MIPS_HFLAG_ELPA)) { + goto mfhc0_read_zero; + } + + switch (reg) { + case 2: + switch (sel) { + case 0: + gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo0)); + rn = "EntryLo0"; + break; + default: + goto mfhc0_read_zero; + } + break; + case 3: + switch (sel) { + case 0: + gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1)); + rn = "EntryLo1"; + break; + default: + goto mfhc0_read_zero; + } + break; + case 17: + switch (sel) { + case 0: + gen_mfhc0_load64(arg, offsetof(CPUMIPSState, lladdr), + ctx->CP0_LLAddr_shift); + rn = "LLAddr"; + break; + default: + goto mfhc0_read_zero; + } + break; + case 28: + switch (sel) { + case 0: + case 2: + case 4: + case 6: + gen_mfhc0_load64(arg, offsetof(CPUMIPSState, CP0_TagLo), 0); + rn = "TagLo"; + break; + default: + goto mfhc0_read_zero; + } + break; + default: + goto mfhc0_read_zero; + } + + (void)rn; /* avoid a compiler warning */ + LOG_DISAS("mfhc0 %s (reg %d sel %d)\n", rn, reg, sel); + return; + +mfhc0_read_zero: + LOG_DISAS("mfhc0 %s (reg %d sel %d)\n", rn, reg, sel); + tcg_gen_movi_tl(arg, 0); +} + +static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) +{ + const char *rn = "invalid"; + uint64_t mask = ctx->PAMask >> 36; + + if (!(ctx->hflags & MIPS_HFLAG_ELPA)) { + goto mthc0_nop; + } + + switch (reg) { + case 2: + switch (sel) { + case 0: + tcg_gen_andi_tl(arg, arg, mask); + gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo0)); + rn = "EntryLo0"; + break; + default: + goto mthc0_nop; + } + break; + case 3: + switch (sel) { + case 0: + tcg_gen_andi_tl(arg, arg, mask); + gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1)); + rn = "EntryLo1"; + break; + default: + goto mthc0_nop; + } + break; + case 17: + switch (sel) { + case 0: + /* LLAddr is read-only (the only exception is bit 0 if LLB is + supported); the CP0_LLAddr_rw_bitmask does not seem to be + relevant for modern MIPS cores supporting MTHC0, therefore + treating MTHC0 to LLAddr as NOP. */ + rn = "LLAddr"; + break; + default: + goto mthc0_nop; + } + break; + case 28: + switch (sel) { + case 0: + case 2: + case 4: + case 6: + tcg_gen_andi_tl(arg, arg, mask); + gen_mthc0_store64(arg, offsetof(CPUMIPSState, CP0_TagLo)); + rn = "TagLo"; + break; + default: + goto mthc0_nop; + } + break; + default: + goto mthc0_nop; + } + + (void)rn; /* avoid a compiler warning */ +mthc0_nop: + LOG_DISAS("mthc0 %s (reg %d sel %d)\n", rn, reg, sel); +} + static inline void gen_mfc0_unimplemented(DisasContext *ctx, TCGv arg) { if (ctx->insn_flags & ISA_MIPS32R6) { @@ -7860,6 +8065,25 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, opn = "dmtc0"; break; #endif + case OPC_MFHC0: + check_mvh(ctx); + if (rt == 0) { + /* Treat as NOP. */ + return; + } + gen_mfhc0(ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); + opn = "mfhc0"; + break; + case OPC_MTHC0: + check_mvh(ctx); + { + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, rt); + gen_mthc0(ctx, t0, rd, ctx->opcode & 0x7); + tcg_temp_free(t0); + } + opn = "mthc0"; + break; case OPC_MFTR: check_insn(ctx, ASE_MT); if (rd == 0) { @@ -18591,6 +18815,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) case OPC_MTC0: case OPC_MFTR: case OPC_MTTR: + case OPC_MFHC0: + case OPC_MTHC0: #if defined(TARGET_MIPS64) case OPC_DMFC0: case OPC_DMTC0: @@ -19161,6 +19387,9 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.ie = (env->CP0_Config4 >> CP0C4_IE) & 3; ctx.bi = (env->CP0_Config3 >> CP0C3_BI) & 1; ctx.bp = (env->CP0_Config3 >> CP0C3_BP) & 1; + ctx.PAMask = env->PAMask; + ctx.mvh = (env->CP0_Config5 >> CP0C5_MVH) & 1; + ctx.CP0_LLAddr_shift = env->CP0_LLAddr_shift; /* Restore delay slot state from the tb context. */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1;