]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add a proper support for several MIPS instructions that generate SigFPE.
authorPetar Jovanovic <mips32r2@gmail.com>
Fri, 19 Oct 2012 14:55:58 +0000 (14:55 +0000)
committerPetar Jovanovic <mips32r2@gmail.com>
Fri, 19 Oct 2012 14:55:58 +0000 (14:55 +0000)
This VEX change needs to be paired with r13059 on Valgrind.

Add support to properly handle TEQ, ADD and SUB instructions that generate
exceptions on MIPS platforms.

git-svn-id: svn://svn.valgrind.org/vex/trunk@2554

VEX/priv/guest_mips_toIR.c
VEX/priv/host_mips_defs.c
VEX/priv/host_mips_isel.c
VEX/priv/ir_defs.c
VEX/pub/libvex_ir.h
VEX/pub/libvex_trc_values.h

index 65700fc1b1efa0153bdb2dc7a916c081211b8b92..6813a63847aaf400547b2ac7820bad93b32d7d76 100644 (file)
@@ -2944,14 +2944,40 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
          putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
          break;
 
-      case 0x20:  /* ADD */
+      case 0x20: /* ADD */
          DIP("add r%d, r%d, r%d", rd, rs, rt);
-         {
-            t2 = newTemp(Ity_I32);
+         t0 = newTemp(Ity_I32);
+         t1 = newTemp(Ity_I32);
+         t2 = newTemp(Ity_I32);
+         t3 = newTemp(Ity_I32);
+         t4 = newTemp(Ity_I32);
+         /* dst = src0 + src1
+         * if(sign(src0 ) != sign(src1 ))
+         * goto no overflow;
+         * if(sign(dst) == sign(src0 ))
+         * goto no overflow;
+         * # we have overflow! */
 
-            assign(t2, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
-            putIReg(rd, mkexpr(t2));
-         }
+         assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
+         assign(t1, binop(Iop_Xor32, getIReg(rs), getIReg(rt)));
+         assign(t2, unop(Iop_1Uto32,
+                         binop(Iop_CmpEQ32,
+                               binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)),
+                               mkU32(0x80000000))));
+
+         assign(t3, binop(Iop_Xor32, mkexpr(t0), getIReg(rs)));
+         assign(t4, unop(Iop_1Uto32,
+                         binop(Iop_CmpNE32,
+                               binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)),
+                               mkU32(0x80000000))));
+         
+         stmt(IRStmt_Exit(binop(Iop_CmpEQ32,
+                                binop(Iop_Or32, mkexpr(t2), mkexpr(t4)),
+                                mkU32(0)),
+                          Ijk_SigFPE_IntOvf,
+                          IRConst_U32(guest_PC_curr_instr + 4), OFFB_PC));
+
+         putIReg(rd, mkexpr(t0));
          break;
 
       case 0x1A:  /* DIV */
@@ -3007,7 +3033,40 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
 
       case 0x22:  /* SUB */
          DIP("sub r%d, r%d, r%d", rd, rs, rt);
-         ALU_PATTERN(Iop_Sub32);
+         t0 = newTemp(Ity_I32);
+         t1 = newTemp(Ity_I32);
+         t2 = newTemp(Ity_I32);
+         t3 = newTemp(Ity_I32);
+         t4 = newTemp(Ity_I32);
+         t5 = newTemp(Ity_I32);
+         /* dst = src0 + (-1 * src1)
+         * if(sign(src0 ) != sign((-1 * src1) ))
+         * goto no overflow;
+         * if(sign(dst) == sign(src0 ))
+         * goto no overflow;
+         * # we have overflow! */
+
+         assign(t5, binop(Iop_Mul32, getIReg(rt), mkU32(-1)));
+         assign(t0, binop(Iop_Add32, getIReg(rs), mkexpr(t5)));
+         assign(t1, binop(Iop_Xor32, getIReg(rs), mkexpr(t5)));
+         assign(t2, unop(Iop_1Sto32,
+                         binop(Iop_CmpEQ32,
+                               binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)),
+                               mkU32(0x80000000))));
+
+         assign(t3, binop(Iop_Xor32, mkexpr(t0), getIReg(rs)));
+         assign(t4, unop(Iop_1Sto32,
+                         binop(Iop_CmpNE32,
+                               binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)),
+                               mkU32(0x80000000))));
+
+         stmt(IRStmt_Exit(binop(Iop_CmpEQ32,
+                                binop(Iop_Or32, mkexpr(t2), mkexpr(t4)),
+                                mkU32(0)),
+                          Ijk_SigFPE_IntOvf,
+                          IRConst_U32(guest_PC_curr_instr + 4), OFFB_PC));
+
+         putIReg(rd, mkexpr(t0));
          break;
 
       case 0x23:  /* SUBU */
@@ -3126,43 +3185,97 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
 
       case 0x30: { /* TGE */
          /*tge */ DIP("tge r%d, r%d %d", rs, rt, trap_code);
-         stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)),
-                            Ijk_SigTRAP,
-                            IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         if (trap_code == 7)
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)),
+                               Ijk_SigFPE_IntDiv,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else if (trap_code == 6)
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)),
+                               Ijk_SigFPE_IntOvf,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)),
+                               Ijk_SigTRAP,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
          break;
       }
       case 0x31: { /* TGEU */
          /*tgeu */ DIP("tgeu r%d, r%d %d", rs, rt, trap_code);
-         stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)),
-                            Ijk_SigTRAP,
-                            IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         if (trap_code == 7)
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)),
+                               Ijk_SigFPE_IntDiv,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else if (trap_code == 6)
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)),
+                               Ijk_SigFPE_IntOvf,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)),
+                               Ijk_SigTRAP,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
          break;
       }
       case 0x32: { /* TLT */
          /*tlt */ DIP("tlt r%d, r%d %d", rs, rt, trap_code);
-         stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)),
-                            Ijk_SigTRAP,
-                            IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         if (trap_code == 7)
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)),
+                               Ijk_SigFPE_IntDiv,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else if (trap_code == 6)
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)),
+                               Ijk_SigFPE_IntOvf,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)),
+                               Ijk_SigTRAP,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
          break;
       }
       case 0x33: { /* TLTU */
          /*tltu */ DIP("tltu r%d, r%d %d", rs, rt, trap_code);
-         stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)),
-                            Ijk_SigTRAP,
-                            IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         if (trap_code == 7)
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)),
+                               Ijk_SigFPE_IntDiv,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else if (trap_code == 6)
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)),
+                               Ijk_SigFPE_IntOvf,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else
+            stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)),
+                               Ijk_SigTRAP,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
          break;
       }
       case 0x34: { /* TEQ */
          /*teq */ DIP("teq r%d, r%d %d", rs, rt, trap_code);
-         stmt (IRStmt_Exit(binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)),
-               Ijk_SigTRAP, IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         if (trap_code == 7)
+            stmt (IRStmt_Exit (binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)),
+                               Ijk_SigFPE_IntDiv,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else if (trap_code == 6)
+            stmt (IRStmt_Exit(binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)),
+                              Ijk_SigFPE_IntOvf,
+                              IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else
+            stmt (IRStmt_Exit(binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)),
+                  Ijk_SigTRAP, IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
          break;
       }
       case 0x36: { /* TNE */
          /*tne */ DIP("tne r%d, r%d %d", rs, rt, trap_code);
-         stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)),
-                            Ijk_SigTRAP,
-                            IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         if (trap_code == 7)
+            stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)),
+                               Ijk_SigFPE_IntDiv,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else if (trap_code == 6)
+            stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)),
+                               Ijk_SigFPE_IntOvf,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+         else
+            stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)),
+                               Ijk_SigTRAP,
+                               IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
          break;
       }
       case 0x0F: {
@@ -3345,9 +3458,40 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
                                      getIReg(rs), mkU32(0x0)))), imm);
       break;
 
-   case 0x08:     /* ADDI TODO: Check this */
+   case 0x08:     /* ADDI */
       DIP("addi r%d, r%d, %d", rt, rs, imm);
-      putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+      t0 = newTemp(Ity_I32);
+      t1 = newTemp(Ity_I32);
+      t2 = newTemp(Ity_I32);
+      t3 = newTemp(Ity_I32);
+      t4 = newTemp(Ity_I32);
+      /* dst = src0 + sign(imm)
+      * if(sign(src0 ) != sign(imm ))
+      * goto no overflow;
+      * if(sign(dst) == sign(src0 ))
+      * goto no overflow;
+      * # we have overflow! */
+
+      assign(t0, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+      assign(t1, binop(Iop_Xor32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+      assign(t2, unop(Iop_1Sto32,
+                      binop(Iop_CmpEQ32,
+                            binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)),
+                            mkU32(0x80000000))));
+
+      assign(t3, binop(Iop_Xor32, mkexpr(t0), getIReg(rs)));
+      assign(t4, unop(Iop_1Sto32,
+                      binop(Iop_CmpNE32,
+                            binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)),
+                            mkU32(0x80000000))));
+
+      stmt(IRStmt_Exit(binop(Iop_CmpEQ32,
+                             binop(Iop_Or32, mkexpr(t2), mkexpr(t4)),
+                             mkU32(0)),
+                       Ijk_SigFPE_IntOvf,
+                       IRConst_U32(guest_PC_curr_instr + 4), OFFB_PC));
+
+      putIReg(rt, mkexpr(t0));
       break;
 
    case 0x09:     /* ADDIU */
index 02f396799e875066655f4133ac02b1260b2e17ca..8eb93cb456c41136abb6d826200313a78162967f 100644 (file)
@@ -3284,20 +3284,22 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc,
          /* imm32/64 r31, $magic_number */
          UInt trcval = 0;
          switch (i->Min.XAssisted.jk) {
-            case Ijk_ClientReq:   trcval = VEX_TRC_JMP_CLIENTREQ;   break;
-            case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
-            //case Ijk_Sys_int128:  trcval = VEX_TRC_JMP_SYS_INT128;  break;
-            //case Ijk_Yield:       trcval = VEX_TRC_JMP_YIELD;       break;
-            case Ijk_EmWarn:      trcval = VEX_TRC_JMP_EMWARN;      break;
-            case Ijk_EmFail:      trcval = VEX_TRC_JMP_EMFAIL;      break;
-            //case Ijk_MapFail:     trcval = VEX_TRC_JMP_MAPFAIL;     break;
-            case Ijk_NoDecode:    trcval = VEX_TRC_JMP_NODECODE;    break;
-            case Ijk_TInval:      trcval = VEX_TRC_JMP_TINVAL;      break;
-            case Ijk_NoRedir:     trcval = VEX_TRC_JMP_NOREDIR;     break;
-            case Ijk_SigTRAP:     trcval = VEX_TRC_JMP_SIGTRAP;     break;
-            //case Ijk_SigSEGV:     trcval = VEX_TRC_JMP_SIGSEGV;     break;
-            case Ijk_SigBUS:        trcval = VEX_TRC_JMP_SIGBUS;    break;
-            case Ijk_Boring:      trcval = VEX_TRC_JMP_BORING;      break;
+            case Ijk_ClientReq:     trcval = VEX_TRC_JMP_CLIENTREQ;     break;
+            case Ijk_Sys_syscall:   trcval = VEX_TRC_JMP_SYS_SYSCALL;   break;
+            //case Ijk_Sys_int128:    trcval = VEX_TRC_JMP_SYS_INT128;    break;
+            //case Ijk_Yield:         trcval = VEX_TRC_JMP_YIELD;         break;
+            case Ijk_EmWarn:        trcval = VEX_TRC_JMP_EMWARN;        break;
+            case Ijk_EmFail:        trcval = VEX_TRC_JMP_EMFAIL;        break;
+            //case Ijk_MapFail:       trcval = VEX_TRC_JMP_MAPFAIL;       break;
+            case Ijk_NoDecode:      trcval = VEX_TRC_JMP_NODECODE;      break;
+            case Ijk_TInval:        trcval = VEX_TRC_JMP_TINVAL;        break;
+            case Ijk_NoRedir:       trcval = VEX_TRC_JMP_NOREDIR;       break;
+            case Ijk_SigTRAP:       trcval = VEX_TRC_JMP_SIGTRAP;       break;
+            //case Ijk_SigSEGV:       trcval = VEX_TRC_JMP_SIGSEGV;       break;
+            case Ijk_SigBUS:        trcval = VEX_TRC_JMP_SIGBUS;        break;
+            case Ijk_SigFPE_IntDiv: trcval = VEX_TRC_JMP_SIGFPE_INTDIV; break;
+            case Ijk_SigFPE_IntOvf: trcval = VEX_TRC_JMP_SIGFPE_INTOVF; break;
+            case Ijk_Boring:        trcval = VEX_TRC_JMP_BORING;        break;
             /* We don't expect to see the following being assisted. */
             //case Ijk_Ret:
             //case Ijk_Call:
index 7df8543dc1e503bdc03f12bbab24e954a6a94e8a..82e4b5a03c7b8a541744a0883d415a283a3da0da 100644 (file)
@@ -3049,6 +3049,8 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt)
          case Ijk_NoRedir:
          case Ijk_SigBUS:
          case Ijk_SigTRAP:
+         case Ijk_SigFPE_IntDiv:
+         case Ijk_SigFPE_IntOvf:
          case Ijk_Sys_syscall:
          case Ijk_TInval:
          {
@@ -3150,6 +3152,8 @@ static void iselNext ( ISelEnv* env,
       case Ijk_NoRedir:
       case Ijk_SigBUS:
       case Ijk_SigTRAP:
+      case Ijk_SigFPE_IntDiv:
+      case Ijk_SigFPE_IntOvf:
       case Ijk_Sys_syscall:
       case Ijk_TInval: {
          HReg      r     = iselWordExpr_R(env, next);
index 8138d597309dad11935584efffd47e627373388e..0d0d151d5f47dbf5bd539cbd8be251efa7a0a000 100644 (file)
@@ -1217,27 +1217,29 @@ void ppIRPutI ( IRPutI* puti )
 void ppIRJumpKind ( IRJumpKind kind )
 {
    switch (kind) {
-      case Ijk_Boring:       vex_printf("Boring"); break;
-      case Ijk_Call:         vex_printf("Call"); break;
-      case Ijk_Ret:          vex_printf("Return"); break;
-      case Ijk_ClientReq:    vex_printf("ClientReq"); break;
-      case Ijk_Yield:        vex_printf("Yield"); break;
-      case Ijk_EmWarn:       vex_printf("EmWarn"); break;
-      case Ijk_EmFail:       vex_printf("EmFail"); break;
-      case Ijk_NoDecode:     vex_printf("NoDecode"); break;
-      case Ijk_MapFail:      vex_printf("MapFail"); break;
-      case Ijk_TInval:       vex_printf("Invalidate"); break;
-      case Ijk_NoRedir:      vex_printf("NoRedir"); break;
-      case Ijk_SigTRAP:      vex_printf("SigTRAP"); break;
-      case Ijk_SigSEGV:      vex_printf("SigSEGV"); break;
-      case Ijk_SigBUS:       vex_printf("SigBUS"); break;
-      case Ijk_Sys_syscall:  vex_printf("Sys_syscall"); break;
-      case Ijk_Sys_int32:    vex_printf("Sys_int32"); break;
-      case Ijk_Sys_int128:   vex_printf("Sys_int128"); break;
-      case Ijk_Sys_int129:   vex_printf("Sys_int129"); break;
-      case Ijk_Sys_int130:   vex_printf("Sys_int130"); break;
-      case Ijk_Sys_sysenter: vex_printf("Sys_sysenter"); break;
-      default:               vpanic("ppIRJumpKind");
+      case Ijk_Boring:        vex_printf("Boring"); break;
+      case Ijk_Call:          vex_printf("Call"); break;
+      case Ijk_Ret:           vex_printf("Return"); break;
+      case Ijk_ClientReq:     vex_printf("ClientReq"); break;
+      case Ijk_Yield:         vex_printf("Yield"); break;
+      case Ijk_EmWarn:        vex_printf("EmWarn"); break;
+      case Ijk_EmFail:        vex_printf("EmFail"); break;
+      case Ijk_NoDecode:      vex_printf("NoDecode"); break;
+      case Ijk_MapFail:       vex_printf("MapFail"); break;
+      case Ijk_TInval:        vex_printf("Invalidate"); break;
+      case Ijk_NoRedir:       vex_printf("NoRedir"); break;
+      case Ijk_SigTRAP:       vex_printf("SigTRAP"); break;
+      case Ijk_SigSEGV:       vex_printf("SigSEGV"); break;
+      case Ijk_SigBUS:        vex_printf("SigBUS"); break;
+      case Ijk_SigFPE_IntDiv: vex_printf("SigFPE_IntDiv"); break;
+      case Ijk_SigFPE_IntOvf: vex_printf("SigFPE_IntOvf"); break;
+      case Ijk_Sys_syscall:   vex_printf("Sys_syscall"); break;
+      case Ijk_Sys_int32:     vex_printf("Sys_int32"); break;
+      case Ijk_Sys_int128:    vex_printf("Sys_int128"); break;
+      case Ijk_Sys_int129:    vex_printf("Sys_int129"); break;
+      case Ijk_Sys_int130:    vex_printf("Sys_int130"); break;
+      case Ijk_Sys_sysenter:  vex_printf("Sys_sysenter"); break;
+      default:                vpanic("ppIRJumpKind");
    }
 }
 
index e210f8671ad54e8784298d43463245a87f0c0668..3ab417a12a4b0cbcab170c108e8de75842b9af8c 100644 (file)
@@ -1872,6 +1872,8 @@ typedef
       Ijk_SigTRAP,        /* current instruction synths SIGTRAP */
       Ijk_SigSEGV,        /* current instruction synths SIGSEGV */
       Ijk_SigBUS,         /* current instruction synths SIGBUS */
+      Ijk_SigFPE_IntDiv,  /* current instruction synths SIGFPE - IntDiv */
+      Ijk_SigFPE_IntOvf,  /* current instruction synths SIGFPE - IntOvf */
       /* Unfortunately, various guest-dependent syscall kinds.  They
         all mean: do a syscall before continuing. */
       Ijk_Sys_syscall,    /* amd64 'syscall', ppc 'sc', arm 'svc #0' */
index 688f28ed3baf7dcac2423ab64598ef518665ced7..db2909b9d5ffe1f9de62582621aff5b0f392e36f 100644 (file)
                                       continuing */
 #define VEX_TRC_JMP_SIGBUS     93  /* deliver SIGBUS before continuing */
 
+#define VEX_TRC_JMP_SIGFPE_INTDIV     97  /* deliver SIGFPE (integer divide
+                                             by zero) before continuing */
+
+#define VEX_TRC_JMP_SIGFPE_INTOVF     99  /* deliver SIGFPE (integer overflow)
+                                             before continuing */
+
 #define VEX_TRC_JMP_EMWARN     63  /* deliver emulation warning before
                                       continuing */
 #define VEX_TRC_JMP_EMFAIL     83  /* emulation fatal error; abort system */