From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1J8E5P-0007R2-9J for qemu-devel@nongnu.org; Fri, 28 Dec 2007 07:13:11 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1J8E5K-0007QP-P4 for qemu-devel@nongnu.org; Fri, 28 Dec 2007 07:13:10 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1J8E5K-0007QM-LW for qemu-devel@nongnu.org; Fri, 28 Dec 2007 07:13:06 -0500 Received: from mk-outboundfilter-4.mail.uk.tiscali.com ([212.74.114.32]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1J8E5K-0005B9-5O for qemu-devel@nongnu.org; Fri, 28 Dec 2007 07:13:06 -0500 Received: from firetop.home (85-211-25-172.dyn.gotadsl.co.uk [85.211.25.172]) by smtp.nildram.co.uk (Postfix) with ESMTP id 491F42B5008 for ; Fri, 28 Dec 2007 12:13:02 +0000 (GMT) Received: from richard by firetop.home with local (Exim 4.63) (envelope-from ) id 1J8E5I-00043K-3H for qemu-devel@nongnu.org; Fri, 28 Dec 2007 12:13:04 +0000 From: Richard Sandiford Date: Fri, 28 Dec 2007 12:13:04 +0000 Message-ID: <87hci36mr3.fsf@firetop.home> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Subject: [Qemu-devel] MIPS COP1X (and related) instructions Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --=-=-= All MIPS COP1X instructions currently require the FPU to be in 64-bit mode. My understanding is that this is too restrictive, and that the base conditions are different for different revisions of the ISA: MIPS IV: COP1X instructions are available when the XX (CU3) bit of the status register is set. This bit can be set independently of UX and FR, and controls the core MIPS IV instructions as well as the FPU ones. Revision 1 of MIPS64: COP1X instructions are available when 64-bit operations (as opposed to 64-bit floating-point operations) are enabled. Revision 2 of MIPS32 and MIPS64: COP1X instructions are available when a 64-bit FPU is present (i.e. if FCR0.F64 is set). The same conditions apply to some non-COP1X instructions too, such as RECIP.fmt and RSQRT.fmt. Of course, some of the affected instructions really do require 64-bit mode, such as the paired-single ones. The attached patch is one attempt to fix this. It's wrong if the description above is wrong. Because the conditions are different for different ISAs, I thought it was worth adding a MIPS_HFLAG_* to say whether COP1X (and related) instructions are available. This flag is directly associated with the nabla symbol in the MIPS32 and MIPS64 opcode tables. Any instructions that requires FR to be set (as enforced by check_cp1_64bitmode) is also affected by the nabla behaviour, so I've made check_cp1_64bitmode depend on both flags. I've added nabla checks for RECIP.S and RSQRT.S. My understanding is that the *.D forms are unpredictable when FR is clear, and that QEMU generally uses check_cp1_64bitmode for such instructions. I've therefore replaced the existing "even register" checks with check_cp1_64bitmode, rather than add a separate nabla test. I've replaced the single check_cp1_64bitmode calls in gen_flt3_ldst gen_flt3_arith with case-by-case checks. I've also made CABS.[SD] use nabla checks instead of check_cp1_64bitmode and added nabla checks to BC1ANY[24]. I noticed all this because a 3-ABI sysroot built with a --with-arch=mips64 GCC uses things like MADD in the o32 libm. There were lots of o32 GCC failures when testing against that libm before the patch, but the results after the patch are on a par with the MIPS32 ones. Please install if OK. Richard --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=cop1x-checks.diff Index: target-mips/cpu.h =================================================================== RCS file: /sources/qemu/qemu/target-mips/cpu.h,v retrieving revision 1.55 diff -u -p -r1.55 cpu.h --- target-mips/cpu.h 26 Dec 2007 19:34:03 -0000 1.55 +++ target-mips/cpu.h 28 Dec 2007 12:05:24 -0000 @@ -417,7 +417,7 @@ struct CPUMIPSState { int user_mode_only; /* user mode only simulation */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x00FF +#define MIPS_HFLAG_TMASK 0x01FF #define MIPS_HFLAG_MODE 0x0007 /* execution modes */ /* The KSU flags must be the lowest bits in hflags. The flag order must be the same as defined for CP0 Status. This allows to use @@ -431,16 +431,20 @@ struct CPUMIPSState { #define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */ #define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */ #define MIPS_HFLAG_F64 0x0040 /* 64-bit FPU enabled */ -#define MIPS_HFLAG_RE 0x0080 /* Reversed endianness */ + /* True if the MIPS IV COP1X instructions can be used. This also + controls the non-COP1X instructions RECIP.S, RECIP.D, RSQRT.S + and RSQRT.D. */ +#define MIPS_HFLAG_COP1X 0x0080 /* COP1X instructions enabled */ +#define MIPS_HFLAG_RE 0x0100 /* Reversed endianness */ /* If translation is interrupted between the branch instruction and * the delay slot, record what type of branch it is so that we can * resume translation properly. It might be possible to reduce * this from three bits to two. */ -#define MIPS_HFLAG_BMASK 0x0700 -#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */ -#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */ -#define MIPS_HFLAG_BL 0x0300 /* Likely branch */ -#define MIPS_HFLAG_BR 0x0400 /* branch to register (can't link TB) */ +#define MIPS_HFLAG_BMASK 0x0e00 +#define MIPS_HFLAG_B 0x0200 /* Unconditional branch */ +#define MIPS_HFLAG_BC 0x0400 /* Conditional branch */ +#define MIPS_HFLAG_BL 0x0600 /* Likely branch */ +#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */ target_ulong btarget; /* Jump / branch target */ int bcond; /* Branch condition (if needed) */ Index: target-mips/exec.h =================================================================== RCS file: /sources/qemu/qemu/target-mips/exec.h,v retrieving revision 1.44 diff -u -p -r1.44 exec.h --- target-mips/exec.h 25 Dec 2007 20:46:55 -0000 1.44 +++ target-mips/exec.h 28 Dec 2007 12:05:24 -0000 @@ -237,8 +237,8 @@ static always_inline int cpu_halted(CPUS static always_inline void compute_hflags(CPUState *env) { - env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | - MIPS_HFLAG_FPU | MIPS_HFLAG_KSU); + env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | + MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { @@ -257,6 +257,16 @@ static always_inline void compute_hflags env->hflags |= MIPS_HFLAG_FPU; if (env->CP0_Status & (1 << CP0St_FR)) env->hflags |= MIPS_HFLAG_F64; + if (env->insn_flags & ISA_MIPS32R2) { + if (env->fpu->fcr0 & FCR0_F64) + env->hflags |= MIPS_HFLAG_COP1X; + } else if (env->insn_flags & ISA_MIPS32) { + if (env->hflags & MIPS_HFLAG_64) + env->hflags |= MIPS_HFLAG_COP1X; + } else if (env->insn_flags & ISA_MIPS4) { + if (env->CP0_Status & (1 << CP0St_CU3)) + env->hflags |= MIPS_HFLAG_COP1X; + } } #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ Index: target-mips/translate.c =================================================================== RCS file: /sources/qemu/qemu/target-mips/translate.c,v retrieving revision 1.119 diff -u -p -r1.119 translate.c --- target-mips/translate.c 25 Dec 2007 20:46:56 -0000 1.119 +++ target-mips/translate.c 28 Dec 2007 12:05:24 -0000 @@ -794,9 +794,22 @@ static always_inline void check_cp1_enab generate_exception_err(ctx, EXCP_CpU, 1); } +/* Verify that the processor is running with COP1X instructions enabled. + This is associated with the nabla symbol in the MIPS32 and MIPS64 + opcode tables. */ + +static always_inline void check_cop1x(DisasContext *ctx) +{ + if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) + generate_exception(ctx, EXCP_RI); +} + +/* Verify that the processor is running with 64-bit floating-point + operations enabled. */ + static always_inline void check_cp1_64bitmode(DisasContext *ctx) { - if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64))) + if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) generate_exception(ctx, EXCP_RI); } @@ -5178,12 +5191,14 @@ static void gen_farith (DisasContext *ct opn = "movn.s"; break; case FOP(21, 16): + check_cop1x(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_recip_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "recip.s"; break; case FOP(22, 16): + check_cop1x(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_rsqrt_s(); GEN_STORE_FTN_FREG(fd, WT2); @@ -5266,7 +5281,7 @@ static void gen_farith (DisasContext *ct GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); if (ctx->opcode & (1 << 6)) { - check_cp1_64bitmode(ctx); + check_cop1x(ctx); gen_cmpabs_s(func-48, cc); opn = condnames_abs[func-48]; } else { @@ -5419,14 +5434,14 @@ static void gen_farith (DisasContext *ct opn = "movn.d"; break; case FOP(21, 17): - check_cp1_registers(ctx, fs | fd); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_recip_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "recip.d"; break; case FOP(22, 17): - check_cp1_registers(ctx, fs | fd); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_rsqrt_d(); GEN_STORE_FTN_FREG(fd, DT2); @@ -5481,7 +5496,8 @@ static void gen_farith (DisasContext *ct GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); if (ctx->opcode & (1 << 6)) { - check_cp1_64bitmode(ctx); + check_cop1x(ctx); + check_cp1_registers(ctx, fs | ft); gen_cmpabs_d(func-48, cc); opn = condnames_abs[func-48]; } else { @@ -5814,8 +5830,6 @@ static void gen_flt3_ldst (DisasContext const char *opn = "extended float load/store"; int store = 0; - /* All of those work only on 64bit FPUs. */ - check_cp1_64bitmode(ctx); if (base == 0) { if (index == 0) gen_op_reset_T0(); @@ -5832,33 +5846,41 @@ static void gen_flt3_ldst (DisasContext memory access. */ switch (opc) { case OPC_LWXC1: + check_cop1x(ctx); op_ldst(lwc1); GEN_STORE_FTN_FREG(fd, WT0); opn = "lwxc1"; break; case OPC_LDXC1: + check_cop1x(ctx); + check_cp1_registers(ctx, fd); op_ldst(ldc1); GEN_STORE_FTN_FREG(fd, DT0); opn = "ldxc1"; break; case OPC_LUXC1: + check_cp1_64bitmode(ctx); op_ldst(luxc1); GEN_STORE_FTN_FREG(fd, DT0); opn = "luxc1"; break; case OPC_SWXC1: + check_cop1x(ctx); GEN_LOAD_FREG_FTN(WT0, fs); op_ldst(swc1); opn = "swxc1"; store = 1; break; case OPC_SDXC1: + check_cop1x(ctx); + check_cp1_registers(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); op_ldst(sdc1); opn = "sdxc1"; store = 1; break; case OPC_SUXC1: + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); op_ldst(suxc1); opn = "suxc1"; @@ -5878,10 +5900,9 @@ static void gen_flt3_arith (DisasContext { const char *opn = "flt3_arith"; - /* All of those work only on 64bit FPUs. */ - check_cp1_64bitmode(ctx); switch (opc) { case OPC_ALNV_PS: + check_cp1_64bitmode(ctx); GEN_LOAD_REG_T0(fr); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); @@ -5890,6 +5911,7 @@ static void gen_flt3_arith (DisasContext opn = "alnv.ps"; break; case OPC_MADD_S: + check_cop1x(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); GEN_LOAD_FREG_FTN(WT2, fr); @@ -5898,6 +5920,8 @@ static void gen_flt3_arith (DisasContext opn = "madd.s"; break; case OPC_MADD_D: + check_cop1x(ctx); + check_cp1_registers(ctx, fd | fs | ft | fr); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); GEN_LOAD_FREG_FTN(DT2, fr); @@ -5906,6 +5930,7 @@ static void gen_flt3_arith (DisasContext opn = "madd.d"; break; case OPC_MADD_PS: + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5918,6 +5943,7 @@ static void gen_flt3_arith (DisasContext opn = "madd.ps"; break; case OPC_MSUB_S: + check_cop1x(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); GEN_LOAD_FREG_FTN(WT2, fr); @@ -5926,6 +5952,8 @@ static void gen_flt3_arith (DisasContext opn = "msub.s"; break; case OPC_MSUB_D: + check_cop1x(ctx); + check_cp1_registers(ctx, fd | fs | ft | fr); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); GEN_LOAD_FREG_FTN(DT2, fr); @@ -5934,6 +5962,7 @@ static void gen_flt3_arith (DisasContext opn = "msub.d"; break; case OPC_MSUB_PS: + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5946,6 +5975,7 @@ static void gen_flt3_arith (DisasContext opn = "msub.ps"; break; case OPC_NMADD_S: + check_cop1x(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); GEN_LOAD_FREG_FTN(WT2, fr); @@ -5954,6 +5984,8 @@ static void gen_flt3_arith (DisasContext opn = "nmadd.s"; break; case OPC_NMADD_D: + check_cop1x(ctx); + check_cp1_registers(ctx, fd | fs | ft | fr); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); GEN_LOAD_FREG_FTN(DT2, fr); @@ -5962,6 +5994,7 @@ static void gen_flt3_arith (DisasContext opn = "nmadd.d"; break; case OPC_NMADD_PS: + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5974,6 +6007,7 @@ static void gen_flt3_arith (DisasContext opn = "nmadd.ps"; break; case OPC_NMSUB_S: + check_cop1x(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); GEN_LOAD_FREG_FTN(WT2, fr); @@ -5982,6 +6016,8 @@ static void gen_flt3_arith (DisasContext opn = "nmsub.s"; break; case OPC_NMSUB_D: + check_cop1x(ctx); + check_cp1_registers(ctx, fd | fs | ft | fr); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); GEN_LOAD_FREG_FTN(DT2, fr); @@ -5990,6 +6026,7 @@ static void gen_flt3_arith (DisasContext opn = "nmsub.d"; break; case OPC_NMSUB_PS: + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -6465,6 +6502,7 @@ static void decode_opc (CPUState *env, D #endif case OPC_BC1ANY2: case OPC_BC1ANY4: + check_cop1x(ctx); check_insn(env, ctx, ASE_MIPS3D); /* fall through */ case OPC_BC1: --=-=-=--