diff mbox

[v3,06/15] target-mips: raise RI exceptions when FIR.PS = 0

Message ID 1435073928-21830-7-git-send-email-yongbok.kim@imgtec.com
State New
Headers show

Commit Message

Yongbok Kim June 23, 2015, 3:38 p.m. UTC
64-bit paired-single (PS) floating point data type is optional in the
pre-Release 6.
It has to raise RI exception when PS type is not implemented. (FIR.PS = 0)
(The PS data type is removed in the Release 6.)

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/translate.c |   77 +++++++++++++++++++++++++++--------------------
 1 files changed, 44 insertions(+), 33 deletions(-)

Comments

Aurelien Jarno June 24, 2015, 12:28 p.m. UTC | #1
On 2015-06-23 16:38, Yongbok Kim wrote:
> 64-bit paired-single (PS) floating point data type is optional in the
> pre-Release 6.
> It has to raise RI exception when PS type is not implemented. (FIR.PS = 0)
> (The PS data type is removed in the Release 6.)
> 
> Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
> Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
>  target-mips/translate.c |   77 +++++++++++++++++++++++++++--------------------
>  1 files changed, 44 insertions(+), 33 deletions(-)
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index dc9aae6..1688bd5 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -1429,6 +1429,7 @@ typedef struct DisasContext {
>      uint64_t PAMask;
>      bool mvh;
>      int CP0_LLAddr_shift;
> +    bool ps;
>  } DisasContext;
>  
>  enum {
> @@ -1825,6 +1826,16 @@ static inline void check_insn_opc_removed(DisasContext *ctx, int flags)
>      }
>  }
>  
> +/* This code generates a "reserved instruction" exception if the
> +   CPU does not support 64-bit paired-single (PS) floating point data type */
> +static inline void check_ps(DisasContext *ctx)
> +{
> +    if (unlikely(!ctx->ps)) {
> +        generate_exception(ctx, EXCP_RI);
> +    }
> +    check_cp1_64bitmode(ctx);
> +}
> +
>  #ifdef TARGET_MIPS64
>  /* This code generates a "reserved instruction" exception if 64-bit
>     instructions are not enabled. */
> @@ -1858,7 +1869,7 @@ static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n,      \
>      TCGv_i##bits fp1 = tcg_temp_new_i##bits ();                               \
>      switch (ifmt) {                                                           \
>      case FMT_PS:                                                              \
> -        check_cp1_64bitmode(ctx);                                             \
> +        check_ps(ctx);                                                        \
>          break;                                                                \
>      case FMT_D:                                                               \
>          if (abs) {                                                            \
> @@ -8998,7 +9009,6 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>      };
>      enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
>      uint32_t func = ctx->opcode & 0x3f;
> -
>      switch (op1) {
>      case OPC_ADD_S:
>          {
> @@ -9491,8 +9501,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "cvt.l.s";
>          break;
>      case OPC_CVT_PS_S:
> -        check_insn_opc_removed(ctx, ISA_MIPS32R6);
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp64 = tcg_temp_new_i64();
>              TCGv_i32 fp32_0 = tcg_temp_new_i32();
> @@ -10109,8 +10118,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "cvt.d.l";
>          break;
>      case OPC_CVT_PS_PW:
> -        check_insn_opc_removed(ctx, ISA_MIPS32R6);
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>  
> @@ -10122,7 +10130,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "cvt.ps.pw";
>          break;
>      case OPC_ADD_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10137,7 +10145,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "add.ps";
>          break;
>      case OPC_SUB_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10152,7 +10160,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "sub.ps";
>          break;
>      case OPC_MUL_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10167,7 +10175,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "mul.ps";
>          break;
>      case OPC_ABS_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>  
> @@ -10179,7 +10187,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "abs.ps";
>          break;
>      case OPC_MOV_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>  
> @@ -10190,7 +10198,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "mov.ps";
>          break;
>      case OPC_NEG_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>  
> @@ -10202,12 +10210,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "neg.ps";
>          break;
>      case OPC_MOVCF_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          gen_movcf_ps(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
>          opn = "movcf.ps";
>          break;
>      case OPC_MOVZ_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGLabel *l1 = gen_new_label();
>              TCGv_i64 fp0;
> @@ -10223,7 +10231,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "movz.ps";
>          break;
>      case OPC_MOVN_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGLabel *l1 = gen_new_label();
>              TCGv_i64 fp0;
> @@ -10240,7 +10248,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "movn.ps";
>          break;
>      case OPC_ADDR_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10255,7 +10263,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "addr.ps";
>          break;
>      case OPC_MULR_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10270,7 +10278,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "mulr.ps";
>          break;
>      case OPC_RECIP2_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10285,7 +10293,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "recip2.ps";
>          break;
>      case OPC_RECIP1_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>  
> @@ -10297,7 +10305,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "recip1.ps";
>          break;
>      case OPC_RSQRT1_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>  
> @@ -10309,7 +10317,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "rsqrt1.ps";
>          break;
>      case OPC_RSQRT2_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10336,7 +10344,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "cvt.s.pu";
>          break;
>      case OPC_CVT_PW_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>  
> @@ -10360,7 +10368,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "cvt.s.pl";
>          break;
>      case OPC_PLL_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i32 fp0 = tcg_temp_new_i32();
>              TCGv_i32 fp1 = tcg_temp_new_i32();
> @@ -10375,7 +10383,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "pll.ps";
>          break;
>      case OPC_PLU_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i32 fp0 = tcg_temp_new_i32();
>              TCGv_i32 fp1 = tcg_temp_new_i32();
> @@ -10390,7 +10398,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "plu.ps";
>          break;
>      case OPC_PUL_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i32 fp0 = tcg_temp_new_i32();
>              TCGv_i32 fp1 = tcg_temp_new_i32();
> @@ -10405,7 +10413,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "pul.ps";
>          break;
>      case OPC_PUU_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i32 fp0 = tcg_temp_new_i32();
>              TCGv_i32 fp1 = tcg_temp_new_i32();
> @@ -10564,7 +10572,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
>  
>      switch (opc) {
>      case OPC_ALNV_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv t0 = tcg_temp_local_new();
>              TCGv_i32 fp = tcg_temp_new_i32();
> @@ -10639,7 +10647,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
>          opn = "madd.d";
>          break;
>      case OPC_MADD_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10694,7 +10702,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
>          opn = "msub.d";
>          break;
>      case OPC_MSUB_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10749,7 +10757,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
>          opn = "nmadd.d";
>          break;
>      case OPC_NMADD_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -10804,7 +10812,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
>          opn = "nmsub.d";
>          break;
>      case OPC_NMSUB_PS:
> -        check_cp1_64bitmode(ctx);
> +        check_ps(ctx);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
>              TCGv_i64 fp1 = tcg_temp_new_i64();
> @@ -14108,6 +14116,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
>                          gen_movcf_d(ctx, rs, rt, cc, 0);
>                          break;
>                      case FMT_SDPS_PS:
> +                        check_ps(ctx);
>                          gen_movcf_ps(ctx, rs, rt, cc, 0);
>                          break;
>                      default:
> @@ -14123,6 +14132,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
>                          gen_movcf_d(ctx, rs, rt, cc, 1);
>                          break;
>                      case FMT_SDPS_PS:
> +                        check_ps(ctx);
>                          gen_movcf_ps(ctx, rs, rt, cc, 1);
>                          break;
>                      default:
> @@ -14144,6 +14154,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
>                      mips32_op = OPC_##prfx##_D;         \
>                      goto do_fpop;                       \
>                  case FMT_SDPS_PS:                       \
> +                    check_ps(ctx);                      \
>                      mips32_op = OPC_##prfx##_PS;        \
>                      goto do_fpop;                       \
>                  default:                                \
> @@ -19149,8 +19160,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
>                                  (rt >> 2) & 0x7, imm << 2);
>              break;
>          case OPC_PS_FMT:
> -            check_cp1_enabled(ctx);
> -            check_insn_opc_removed(ctx, ISA_MIPS32R6);
> +            check_ps(ctx);
>              /* fall through */
>          case OPC_S_FMT:
>          case OPC_D_FMT:
> @@ -19459,6 +19469,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
>      /* 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;
> +    ctx.ps = (env->active_fpu.fcr0 >> FCR0_PS) & 1;
>      restore_cpu_state(env, &ctx);
>  #ifdef CONFIG_USER_ONLY
>          ctx.mem_idx = MIPS_HFLAG_UM;

This change means that the PS instructions are now enabled only when
FCR0_PS is set, instead of being enabled when the FPU in 64-bit mode.
Have you checked if we need to update a few CPU definitions for it to
work? I am thinking for example about all the CPU with FCR0_F64, but
without FCR0_PS.

Otherwise the patch looks fine to me.
Yongbok Kim June 24, 2015, 2:24 p.m. UTC | #2
On 24/06/2015 13:28, Aurelien Jarno wrote:
> On 2015-06-23 16:38, Yongbok Kim wrote:
>> 64-bit paired-single (PS) floating point data type is optional in the
>> pre-Release 6.
>> It has to raise RI exception when PS type is not implemented. (FIR.PS = 0)
>> (The PS data type is removed in the Release 6.)
>>
>> Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
>> Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
>> ---

> 
> This change means that the PS instructions are now enabled only when
> FCR0_PS is set, instead of being enabled when the FPU in 64-bit mode.
> Have you checked if we need to update a few CPU definitions for it to
> work? I am thinking for example about all the CPU with FCR0_F64, but
> without FCR0_PS.
> 
> Otherwise the patch looks fine to me.
> 

I just checked all the core definitions. All other cores are OK and even
the patch brought some corrections of behaviour like 24Kf shouldn't support
PS data type but it was wrongly enabled.
However Loongson-2E and Loongson-2F might be broken because of the patch.
The question is that how to allow ps data type for these Loongson cores as
in the MIPS III architecture all the those FCR0 field is reserved apart
from implementation and revision numbers.
(1) I could add few more line in check_ps() to allow Loongson according to
the Implementation and Revision numbers. (2) Otherwise updating the
reserved fields against later architectures - F64/PS/D/S. Perhaps that
would cause another problem if an application is expecting all zeroes on
the field.
What do you think?

Regards,
Yongbok
Aurelien Jarno June 24, 2015, 2:59 p.m. UTC | #3
On 2015-06-24 15:24, Yongbok Kim wrote:
> On 24/06/2015 13:28, Aurelien Jarno wrote:
> > On 2015-06-23 16:38, Yongbok Kim wrote:
> >> 64-bit paired-single (PS) floating point data type is optional in the
> >> pre-Release 6.
> >> It has to raise RI exception when PS type is not implemented. (FIR.PS = 0)
> >> (The PS data type is removed in the Release 6.)
> >>
> >> Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
> >> Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
> >> ---
> 
> > 
> > This change means that the PS instructions are now enabled only when
> > FCR0_PS is set, instead of being enabled when the FPU in 64-bit mode.
> > Have you checked if we need to update a few CPU definitions for it to
> > work? I am thinking for example about all the CPU with FCR0_F64, but
> > without FCR0_PS.
> > 
> > Otherwise the patch looks fine to me.
> > 
> 
> I just checked all the core definitions. All other cores are OK and even
> the patch brought some corrections of behaviour like 24Kf shouldn't support
> PS data type but it was wrongly enabled.

Great.

> However Loongson-2E and Loongson-2F might be broken because of the patch.
> The question is that how to allow ps data type for these Loongson cores as
> in the MIPS III architecture all the those FCR0 field is reserved apart
> from implementation and revision numbers.
> (1) I could add few more line in check_ps() to allow Loongson according to
> the Implementation and Revision numbers. (2) Otherwise updating the
> reserved fields against later architectures - F64/PS/D/S. Perhaps that
> would cause another problem if an application is expecting all zeroes on
> the field.

I think the best would be to add a line in check_ps(). I guess the
easiest is to check if the CPU supports the LOONGSON ISA, that is
testing (ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)).

Aurelien
Aurelien Jarno June 24, 2015, 3:24 p.m. UTC | #4
On 2015-06-24 16:59, Aurelien Jarno wrote:
> On 2015-06-24 15:24, Yongbok Kim wrote:
> > On 24/06/2015 13:28, Aurelien Jarno wrote:
> > > On 2015-06-23 16:38, Yongbok Kim wrote:
> > >> 64-bit paired-single (PS) floating point data type is optional in the
> > >> pre-Release 6.
> > >> It has to raise RI exception when PS type is not implemented. (FIR.PS = 0)
> > >> (The PS data type is removed in the Release 6.)
> > >>
> > >> Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
> > >> Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
> > >> ---
> > 
> > > 
> > > This change means that the PS instructions are now enabled only when
> > > FCR0_PS is set, instead of being enabled when the FPU in 64-bit mode.
> > > Have you checked if we need to update a few CPU definitions for it to
> > > work? I am thinking for example about all the CPU with FCR0_F64, but
> > > without FCR0_PS.
> > > 
> > > Otherwise the patch looks fine to me.
> > > 
> > 
> > I just checked all the core definitions. All other cores are OK and even
> > the patch brought some corrections of behaviour like 24Kf shouldn't support
> > PS data type but it was wrongly enabled.
> 
> Great.
> 
> > However Loongson-2E and Loongson-2F might be broken because of the patch.
> > The question is that how to allow ps data type for these Loongson cores as
> > in the MIPS III architecture all the those FCR0 field is reserved apart
> > from implementation and revision numbers.
> > (1) I could add few more line in check_ps() to allow Loongson according to
> > the Implementation and Revision numbers. (2) Otherwise updating the
> > reserved fields against later architectures - F64/PS/D/S. Perhaps that
> > would cause another problem if an application is expecting all zeroes on
> > the field.
> 
> I think the best would be to add a line in check_ps(). I guess the
> easiest is to check if the CPU supports the LOONGSON ISA, that is
> testing (ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)).

Or probably even better:

ctx.ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) ||
         (ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))
Yongbok Kim June 24, 2015, 3:53 p.m. UTC | #5
> Or probably even better:
> 
> ctx.ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) ||
>          (ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))
> 

Yes that is good.
I will send updated version soon.

Regards,
Yongbok
diff mbox

Patch

diff --git a/target-mips/translate.c b/target-mips/translate.c
index dc9aae6..1688bd5 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1429,6 +1429,7 @@  typedef struct DisasContext {
     uint64_t PAMask;
     bool mvh;
     int CP0_LLAddr_shift;
+    bool ps;
 } DisasContext;
 
 enum {
@@ -1825,6 +1826,16 @@  static inline void check_insn_opc_removed(DisasContext *ctx, int flags)
     }
 }
 
+/* This code generates a "reserved instruction" exception if the
+   CPU does not support 64-bit paired-single (PS) floating point data type */
+static inline void check_ps(DisasContext *ctx)
+{
+    if (unlikely(!ctx->ps)) {
+        generate_exception(ctx, EXCP_RI);
+    }
+    check_cp1_64bitmode(ctx);
+}
+
 #ifdef TARGET_MIPS64
 /* This code generates a "reserved instruction" exception if 64-bit
    instructions are not enabled. */
@@ -1858,7 +1869,7 @@  static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n,      \
     TCGv_i##bits fp1 = tcg_temp_new_i##bits ();                               \
     switch (ifmt) {                                                           \
     case FMT_PS:                                                              \
-        check_cp1_64bitmode(ctx);                                             \
+        check_ps(ctx);                                                        \
         break;                                                                \
     case FMT_D:                                                               \
         if (abs) {                                                            \
@@ -8998,7 +9009,6 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
     };
     enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
     uint32_t func = ctx->opcode & 0x3f;
-
     switch (op1) {
     case OPC_ADD_S:
         {
@@ -9491,8 +9501,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "cvt.l.s";
         break;
     case OPC_CVT_PS_S:
-        check_insn_opc_removed(ctx, ISA_MIPS32R6);
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp64 = tcg_temp_new_i64();
             TCGv_i32 fp32_0 = tcg_temp_new_i32();
@@ -10109,8 +10118,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "cvt.d.l";
         break;
     case OPC_CVT_PS_PW:
-        check_insn_opc_removed(ctx, ISA_MIPS32R6);
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
@@ -10122,7 +10130,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "cvt.ps.pw";
         break;
     case OPC_ADD_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10137,7 +10145,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "add.ps";
         break;
     case OPC_SUB_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10152,7 +10160,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "sub.ps";
         break;
     case OPC_MUL_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10167,7 +10175,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "mul.ps";
         break;
     case OPC_ABS_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
@@ -10179,7 +10187,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "abs.ps";
         break;
     case OPC_MOV_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
@@ -10190,7 +10198,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "mov.ps";
         break;
     case OPC_NEG_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
@@ -10202,12 +10210,12 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "neg.ps";
         break;
     case OPC_MOVCF_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         gen_movcf_ps(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
         opn = "movcf.ps";
         break;
     case OPC_MOVZ_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGLabel *l1 = gen_new_label();
             TCGv_i64 fp0;
@@ -10223,7 +10231,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "movz.ps";
         break;
     case OPC_MOVN_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGLabel *l1 = gen_new_label();
             TCGv_i64 fp0;
@@ -10240,7 +10248,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "movn.ps";
         break;
     case OPC_ADDR_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10255,7 +10263,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "addr.ps";
         break;
     case OPC_MULR_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10270,7 +10278,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "mulr.ps";
         break;
     case OPC_RECIP2_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10285,7 +10293,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "recip2.ps";
         break;
     case OPC_RECIP1_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
@@ -10297,7 +10305,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "recip1.ps";
         break;
     case OPC_RSQRT1_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
@@ -10309,7 +10317,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "rsqrt1.ps";
         break;
     case OPC_RSQRT2_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10336,7 +10344,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "cvt.s.pu";
         break;
     case OPC_CVT_PW_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
@@ -10360,7 +10368,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "cvt.s.pl";
         break;
     case OPC_PLL_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -10375,7 +10383,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "pll.ps";
         break;
     case OPC_PLU_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -10390,7 +10398,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "plu.ps";
         break;
     case OPC_PUL_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -10405,7 +10413,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "pul.ps";
         break;
     case OPC_PUU_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i32 fp0 = tcg_temp_new_i32();
             TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -10564,7 +10572,7 @@  static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
 
     switch (opc) {
     case OPC_ALNV_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv t0 = tcg_temp_local_new();
             TCGv_i32 fp = tcg_temp_new_i32();
@@ -10639,7 +10647,7 @@  static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
         opn = "madd.d";
         break;
     case OPC_MADD_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10694,7 +10702,7 @@  static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
         opn = "msub.d";
         break;
     case OPC_MSUB_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10749,7 +10757,7 @@  static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
         opn = "nmadd.d";
         break;
     case OPC_NMADD_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -10804,7 +10812,7 @@  static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
         opn = "nmsub.d";
         break;
     case OPC_NMSUB_PS:
-        check_cp1_64bitmode(ctx);
+        check_ps(ctx);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
             TCGv_i64 fp1 = tcg_temp_new_i64();
@@ -14108,6 +14116,7 @@  static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
                         gen_movcf_d(ctx, rs, rt, cc, 0);
                         break;
                     case FMT_SDPS_PS:
+                        check_ps(ctx);
                         gen_movcf_ps(ctx, rs, rt, cc, 0);
                         break;
                     default:
@@ -14123,6 +14132,7 @@  static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
                         gen_movcf_d(ctx, rs, rt, cc, 1);
                         break;
                     case FMT_SDPS_PS:
+                        check_ps(ctx);
                         gen_movcf_ps(ctx, rs, rt, cc, 1);
                         break;
                     default:
@@ -14144,6 +14154,7 @@  static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
                     mips32_op = OPC_##prfx##_D;         \
                     goto do_fpop;                       \
                 case FMT_SDPS_PS:                       \
+                    check_ps(ctx);                      \
                     mips32_op = OPC_##prfx##_PS;        \
                     goto do_fpop;                       \
                 default:                                \
@@ -19149,8 +19160,7 @@  static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
                                 (rt >> 2) & 0x7, imm << 2);
             break;
         case OPC_PS_FMT:
-            check_cp1_enabled(ctx);
-            check_insn_opc_removed(ctx, ISA_MIPS32R6);
+            check_ps(ctx);
             /* fall through */
         case OPC_S_FMT:
         case OPC_D_FMT:
@@ -19459,6 +19469,7 @@  gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
     /* 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;
+    ctx.ps = (env->active_fpu.fcr0 >> FCR0_PS) & 1;
     restore_cpu_state(env, &ctx);
 #ifdef CONFIG_USER_ONLY
         ctx.mem_idx = MIPS_HFLAG_UM;