diff mbox

[02/21] target-mips: signal RI Exception on instructions removed in R6

Message ID 1401461279-59617-3-git-send-email-leon.alrae@imgtec.com
State New
Headers show

Commit Message

Leon Alrae May 30, 2014, 2:47 p.m. UTC
Signal Reserved Instruction Exception on instructions that do not exist in R6.
In this commit the following groups of preR6 instructions are marked as deleted:
- Floating Point Paired Single
- Floating Point Compare
- conditional moves / branches on FPU conditions
- branch likelies
- unaligned loads / stores
- traps
- legacy accumulator instructions
- COP1X
- MIPS-3D

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/translate.c |   64 +++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 56 insertions(+), 8 deletions(-)

Comments

Aurelien Jarno May 30, 2014, 4:43 p.m. UTC | #1
On Fri, May 30, 2014 at 03:47:40PM +0100, Leon Alrae wrote:
> Signal Reserved Instruction Exception on instructions that do not exist in R6.
> In this commit the following groups of preR6 instructions are marked as deleted:
> - Floating Point Paired Single
> - Floating Point Compare
> - conditional moves / branches on FPU conditions
> - branch likelies
> - unaligned loads / stores
> - traps
> - legacy accumulator instructions
> - COP1X
> - MIPS-3D
> 
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
>  target-mips/translate.c |   64 +++++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 56 insertions(+), 8 deletions(-)
> 
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index 05f82d2..2ac8023 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -1430,6 +1430,16 @@ static inline void check_insn(DisasContext *ctx, int flags)
>      }
>  }
>  
> +/* This code generates a "reserved instruction" exception if the
> +   CPU has corresponding flag set which indicates that the instruction
> +   has been removed. */
> +static inline void check_insn_opc_removed(DisasContext *ctx, int flags)
> +{
> +    if (unlikely(ctx->insn_flags & flags)) {
> +        generate_exception(ctx, EXCP_RI);
> +    }
> +}
> +
>  /* This code generates a "reserved instruction" exception if 64-bit
>     instructions are not enabled. */
>  static inline void check_mips_64(DisasContext *ctx)
> @@ -7667,10 +7677,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "floor.w.s";
>          break;
>      case OPC_MOVCF_S:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
>          opn = "movcf.s";
>          break;
>      case OPC_MOVZ_S:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          {
>              int l1 = gen_new_label();
>              TCGv_i32 fp0;
> @@ -7687,6 +7699,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "movz.s";
>          break;
>      case OPC_MOVN_S:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          {
>              int l1 = gen_new_label();
>              TCGv_i32 fp0;
> @@ -7820,6 +7833,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);
>          {
>              TCGv_i64 fp64 = tcg_temp_new_i64();
> @@ -7852,6 +7866,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>      case OPC_CMP_NGE_S:
>      case OPC_CMP_LE_S:
>      case OPC_CMP_NGT_S:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          if (ctx->opcode & (1 << 6)) {
>              gen_cmpabs_s(ctx, func-48, ft, fs, cc);
>              opn = condnames_abs[func-48];
> @@ -8076,10 +8091,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "floor.w.d";
>          break;
>      case OPC_MOVCF_D:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
>          opn = "movcf.d";
>          break;
>      case OPC_MOVZ_D:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          {
>              int l1 = gen_new_label();
>              TCGv_i64 fp0;
> @@ -8096,6 +8113,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>          opn = "movz.d";
>          break;
>      case OPC_MOVN_D:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          {
>              int l1 = gen_new_label();
>              TCGv_i64 fp0;
> @@ -8205,6 +8223,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
>      case OPC_CMP_NGE_D:
>      case OPC_CMP_LE_D:
>      case OPC_CMP_NGT_D:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          if (ctx->opcode & (1 << 6)) {
>              gen_cmpabs_d(ctx, func-48, ft, fs, cc);
>              opn = condnames_abs[func-48];
> @@ -8305,6 +8324,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);
>          {
>              TCGv_i64 fp0 = tcg_temp_new_i64();
> @@ -14455,6 +14475,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>              break;
>          case OPC_MOVN:         /* Conditional move */
>          case OPC_MOVZ:
> +            check_insn_opc_removed(ctx, ISA_MIPS32R6);
>              check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
>                                   INSN_LOONGSON2E | INSN_LOONGSON2F);
>              gen_cond_move(ctx, op1, rd, rs, rt);
> @@ -14515,10 +14536,12 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>              break;
>          case OPC_MFHI:          /* Move from HI/LO */
>          case OPC_MFLO:
> +            check_insn_opc_removed(ctx, ISA_MIPS32R6);
>              gen_HILO(ctx, op1, rs & 3, rd);
>              break;
>          case OPC_MTHI:
>          case OPC_MTLO:          /* Move to HI/LO */
> +            check_insn_opc_removed(ctx, ISA_MIPS32R6);
>              gen_HILO(ctx, op1, rd & 3, rs);
>              break;
>          case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
> @@ -14551,6 +14574,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>              break;
>  
>          case OPC_MOVCI:
> +            check_insn_opc_removed(ctx, ISA_MIPS32R6);
>              check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
>              if (env->CP0_Config1 & (1 << CP0C1_FP)) {
>                  check_cp1_enabled(ctx);
> @@ -14653,10 +14677,12 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>          switch (op1) {
>          case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
>          case OPC_MSUB ... OPC_MSUBU:
> +            check_insn_opc_removed(ctx, ISA_MIPS32R6);
>              check_insn(ctx, ISA_MIPS32);
>              gen_muldiv(ctx, op1, rd & 3, rs, rt);
>              break;
>          case OPC_MUL:
> +            check_insn_opc_removed(ctx, ISA_MIPS32R6);
>              gen_arith(ctx, op1, rd, rs, rt);
>              break;
>          case OPC_CLO:
> @@ -15271,12 +15297,20 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>      case OPC_REGIMM:
>          op1 = MASK_REGIMM(ctx->opcode);
>          switch (op1) {
> -        case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
> -        case OPC_BLTZAL ... OPC_BGEZALL:
> +        case OPC_BLTZL: /* REGIMM branches */
> +        case OPC_BGEZL:
> +        case OPC_BLTZALL:
> +        case OPC_BGEZALL:
> +            check_insn_opc_removed(ctx, ISA_MIPS32R6);
> +        case OPC_BLTZ:
> +        case OPC_BGEZ:
> +        case OPC_BLTZAL:
> +        case OPC_BGEZAL:
>              gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
>              break;
>          case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
>          case OPC_TNEI:
> +            check_insn_opc_removed(ctx, ISA_MIPS32R6);
>              gen_trap(ctx, op1, rs, -1, imm);
>              break;
>          case OPC_SYNCI:
> @@ -15401,16 +15435,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>           offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
>           gen_compute_branch(ctx, op, 4, rs, rt, offset);
>           break;
> -    case OPC_BEQ ... OPC_BGTZ: /* Branch */
> -    case OPC_BEQL ... OPC_BGTZL:
> +    case OPC_BEQL ... OPC_BGTZL:  /* Branch */
> +         check_insn_opc_removed(ctx, ISA_MIPS32R6);
> +    case OPC_BEQ ... OPC_BGTZ:
>           gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
>           break;
> -    case OPC_LB ... OPC_LWR: /* Load and stores */
> +    case OPC_LWL: /* Load and stores */
> +    case OPC_LWR:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
> +    case OPC_LB ... OPC_LH:
> +    case OPC_LW ... OPC_LHU:
>      case OPC_LL:
>           gen_ld(ctx, op, rt, rs, imm);
>           break;
> -    case OPC_SB ... OPC_SW:
> +    case OPC_SWL:
>      case OPC_SWR:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
> +    case OPC_SB ... OPC_SH:
> +    case OPC_SW:
>           gen_st(ctx, op, rt, rs, imm);
>           break;
>      case OPC_SC:
> @@ -15457,18 +15499,21 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>  #endif
>              case OPC_BC1ANY2:
>              case OPC_BC1ANY4:
> +                check_insn_opc_removed(ctx, ISA_MIPS32R6);
>                  check_cop1x(ctx);
>                  check_insn(ctx, ASE_MIPS3D);
>                  /* fall through */
>              case OPC_BC1:
> +                check_insn_opc_removed(ctx, ISA_MIPS32R6);
>                  gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
>                                      (rt >> 2) & 0x7, imm << 2);
>                  break;
> +            case OPC_PS_FMT:
> +                check_insn_opc_removed(ctx, ISA_MIPS32R6);
>              case OPC_S_FMT:
>              case OPC_D_FMT:
>              case OPC_W_FMT:
>              case OPC_L_FMT:
> -            case OPC_PS_FMT:
>                  gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
>                             (imm >> 8) & 0x7);
>                  break;
> @@ -15497,6 +15542,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>          break;
>  
>      case OPC_CP3:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>          if (env->CP0_Config1 & (1 << CP0C1_FP)) {
>              check_cp1_enabled(ctx);
>              op1 = MASK_CP3(ctx->opcode);
> @@ -15539,8 +15585,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>  
>  #if defined(TARGET_MIPS64)
>      /* MIPS64 opcodes */
> -    case OPC_LWU:
>      case OPC_LDL ... OPC_LDR:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
> +    case OPC_LWU:
>      case OPC_LLD:
>      case OPC_LD:
>          check_insn(ctx, ISA_MIPS3);
> @@ -15548,6 +15595,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
>          gen_ld(ctx, op, rt, rs, imm);
>          break;
>      case OPC_SDL ... OPC_SDR:
> +        check_insn_opc_removed(ctx, ISA_MIPS32R6);
>      case OPC_SD:
>          check_insn(ctx, ISA_MIPS3);
>          check_mips_64(ctx);

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

Just a comment, not related to QEMU: while it looks at a first glance to
build a binary that runs on both pre-R6 and R6 by not using the removed
instructions, I do wonder how the transition would be done for unaligned
load/stores. On pre-R6, unaligned load/stores are not supported so 
LDR/LDL must be used, while on R6 LDR/LDL are not supported, so
unaligned load/stores should be used instead...
Maciej W. Rozycki June 2, 2014, 10:03 a.m. UTC | #2
On Fri, 30 May 2014, Aurelien Jarno wrote:

> Just a comment, not related to QEMU: while it looks at a first glance to
> build a binary that runs on both pre-R6 and R6 by not using the removed
> instructions, I do wonder how the transition would be done for unaligned
> load/stores. On pre-R6, unaligned load/stores are not supported so 
> LDR/LDL must be used, while on R6 LDR/LDL are not supported, so
> unaligned load/stores should be used instead...

 IIUC you just don't.  R6 is an incompatible ISA change (one could say 
just a new ISA that happens to resemble existing ones a bit), so you just 
have to recompile high-level sources from scratch and rewrite assembly 
code (here the resemblance helps, you might be able to use the C 
preprocessor or similar tools to switch between fragments meant for the 
specific ISAs).

  Maciej
diff mbox

Patch

diff --git a/target-mips/translate.c b/target-mips/translate.c
index 05f82d2..2ac8023 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1430,6 +1430,16 @@  static inline void check_insn(DisasContext *ctx, int flags)
     }
 }
 
+/* This code generates a "reserved instruction" exception if the
+   CPU has corresponding flag set which indicates that the instruction
+   has been removed. */
+static inline void check_insn_opc_removed(DisasContext *ctx, int flags)
+{
+    if (unlikely(ctx->insn_flags & flags)) {
+        generate_exception(ctx, EXCP_RI);
+    }
+}
+
 /* This code generates a "reserved instruction" exception if 64-bit
    instructions are not enabled. */
 static inline void check_mips_64(DisasContext *ctx)
@@ -7667,10 +7677,12 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "floor.w.s";
         break;
     case OPC_MOVCF_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
         opn = "movcf.s";
         break;
     case OPC_MOVZ_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         {
             int l1 = gen_new_label();
             TCGv_i32 fp0;
@@ -7687,6 +7699,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "movz.s";
         break;
     case OPC_MOVN_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         {
             int l1 = gen_new_label();
             TCGv_i32 fp0;
@@ -7820,6 +7833,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);
         {
             TCGv_i64 fp64 = tcg_temp_new_i64();
@@ -7852,6 +7866,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
     case OPC_CMP_NGE_S:
     case OPC_CMP_LE_S:
     case OPC_CMP_NGT_S:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         if (ctx->opcode & (1 << 6)) {
             gen_cmpabs_s(ctx, func-48, ft, fs, cc);
             opn = condnames_abs[func-48];
@@ -8076,10 +8091,12 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "floor.w.d";
         break;
     case OPC_MOVCF_D:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
         opn = "movcf.d";
         break;
     case OPC_MOVZ_D:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         {
             int l1 = gen_new_label();
             TCGv_i64 fp0;
@@ -8096,6 +8113,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
         opn = "movz.d";
         break;
     case OPC_MOVN_D:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         {
             int l1 = gen_new_label();
             TCGv_i64 fp0;
@@ -8205,6 +8223,7 @@  static void gen_farith (DisasContext *ctx, enum fopcode op1,
     case OPC_CMP_NGE_D:
     case OPC_CMP_LE_D:
     case OPC_CMP_NGT_D:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         if (ctx->opcode & (1 << 6)) {
             gen_cmpabs_d(ctx, func-48, ft, fs, cc);
             opn = condnames_abs[func-48];
@@ -8305,6 +8324,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);
         {
             TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -14455,6 +14475,7 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
         case OPC_MOVN:         /* Conditional move */
         case OPC_MOVZ:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
                                  INSN_LOONGSON2E | INSN_LOONGSON2F);
             gen_cond_move(ctx, op1, rd, rs, rt);
@@ -14515,10 +14536,12 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
         case OPC_MFHI:          /* Move from HI/LO */
         case OPC_MFLO:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             gen_HILO(ctx, op1, rs & 3, rd);
             break;
         case OPC_MTHI:
         case OPC_MTLO:          /* Move to HI/LO */
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             gen_HILO(ctx, op1, rd & 3, rs);
             break;
         case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
@@ -14551,6 +14574,7 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
             break;
 
         case OPC_MOVCI:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
             if (env->CP0_Config1 & (1 << CP0C1_FP)) {
                 check_cp1_enabled(ctx);
@@ -14653,10 +14677,12 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         switch (op1) {
         case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
         case OPC_MSUB ... OPC_MSUBU:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             check_insn(ctx, ISA_MIPS32);
             gen_muldiv(ctx, op1, rd & 3, rs, rt);
             break;
         case OPC_MUL:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             gen_arith(ctx, op1, rd, rs, rt);
             break;
         case OPC_CLO:
@@ -15271,12 +15297,20 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
     case OPC_REGIMM:
         op1 = MASK_REGIMM(ctx->opcode);
         switch (op1) {
-        case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
-        case OPC_BLTZAL ... OPC_BGEZALL:
+        case OPC_BLTZL: /* REGIMM branches */
+        case OPC_BGEZL:
+        case OPC_BLTZALL:
+        case OPC_BGEZALL:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
+        case OPC_BLTZ:
+        case OPC_BGEZ:
+        case OPC_BLTZAL:
+        case OPC_BGEZAL:
             gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
             break;
         case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
         case OPC_TNEI:
+            check_insn_opc_removed(ctx, ISA_MIPS32R6);
             gen_trap(ctx, op1, rs, -1, imm);
             break;
         case OPC_SYNCI:
@@ -15401,16 +15435,24 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
          offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
          gen_compute_branch(ctx, op, 4, rs, rt, offset);
          break;
-    case OPC_BEQ ... OPC_BGTZ: /* Branch */
-    case OPC_BEQL ... OPC_BGTZL:
+    case OPC_BEQL ... OPC_BGTZL:  /* Branch */
+         check_insn_opc_removed(ctx, ISA_MIPS32R6);
+    case OPC_BEQ ... OPC_BGTZ:
          gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
          break;
-    case OPC_LB ... OPC_LWR: /* Load and stores */
+    case OPC_LWL: /* Load and stores */
+    case OPC_LWR:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+    case OPC_LB ... OPC_LH:
+    case OPC_LW ... OPC_LHU:
     case OPC_LL:
          gen_ld(ctx, op, rt, rs, imm);
          break;
-    case OPC_SB ... OPC_SW:
+    case OPC_SWL:
     case OPC_SWR:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+    case OPC_SB ... OPC_SH:
+    case OPC_SW:
          gen_st(ctx, op, rt, rs, imm);
          break;
     case OPC_SC:
@@ -15457,18 +15499,21 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
 #endif
             case OPC_BC1ANY2:
             case OPC_BC1ANY4:
+                check_insn_opc_removed(ctx, ISA_MIPS32R6);
                 check_cop1x(ctx);
                 check_insn(ctx, ASE_MIPS3D);
                 /* fall through */
             case OPC_BC1:
+                check_insn_opc_removed(ctx, ISA_MIPS32R6);
                 gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
                                     (rt >> 2) & 0x7, imm << 2);
                 break;
+            case OPC_PS_FMT:
+                check_insn_opc_removed(ctx, ISA_MIPS32R6);
             case OPC_S_FMT:
             case OPC_D_FMT:
             case OPC_W_FMT:
             case OPC_L_FMT:
-            case OPC_PS_FMT:
                 gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
                            (imm >> 8) & 0x7);
                 break;
@@ -15497,6 +15542,7 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         break;
 
     case OPC_CP3:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
         if (env->CP0_Config1 & (1 << CP0C1_FP)) {
             check_cp1_enabled(ctx);
             op1 = MASK_CP3(ctx->opcode);
@@ -15539,8 +15585,9 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
 
 #if defined(TARGET_MIPS64)
     /* MIPS64 opcodes */
-    case OPC_LWU:
     case OPC_LDL ... OPC_LDR:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
+    case OPC_LWU:
     case OPC_LLD:
     case OPC_LD:
         check_insn(ctx, ISA_MIPS3);
@@ -15548,6 +15595,7 @@  static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
         gen_ld(ctx, op, rt, rs, imm);
         break;
     case OPC_SDL ... OPC_SDR:
+        check_insn_opc_removed(ctx, ISA_MIPS32R6);
     case OPC_SD:
         check_insn(ctx, ISA_MIPS3);
         check_mips_64(ctx);