qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] MIPS COP1X (and related) instructions


From: Richard Sandiford
Subject: Re: [Qemu-devel] MIPS COP1X (and related) instructions
Date: Sun, 30 Dec 2007 07:54:53 +0000
User-agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux)

Thiemo Seufer <address@hidden> writes:
> Richard Sandiford wrote:
>> What should the patch do instead for MIPS IV?  Enable them unconditionally?
>
> Given that it is currently theoretical, as the only MIPS IV CPU
> supported is the VR5432: Add a comment to the MIPS IV test that it is
> too restrictive for some CPUs.

Thanks, sounds good.  Here's the patch with a comment added.

Richard


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   30 Dec 2007 07:50:21 -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  30 Dec 2007 07:50:21 -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,20 @@ 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) {
+        /* All supported MIPS IV CPUs use the XX (CU3) to enable
+           and disable the MIPS IV extensions to the MIPS III ISA.
+           Some other MIPS IV CPUs ignore the bit, so the check here
+           would be too restrictive for them.  */
+        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     30 Dec 2007 07:50:22 -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:

reply via email to

[Prev in Thread] Current Thread [Next in Thread]