]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/erc32/exec.c
Do not use old-style definitions in sim
[thirdparty/binutils-gdb.git] / sim / erc32 / exec.c
index 8690cea9d898ff1614b35a27e4047d2933aef637..8daf759514ecd04b1b58315e24583fe19f6354de 100644 (file)
@@ -1,31 +1,28 @@
-/*
- * This file is part of SIS.
- * 
- * SIS, SPARC instruction simulator V1.8 Copyright (C) 1995 Jiri Gaisler,
- * European Space Agency
- * 
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- * 
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- * 
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 675
- * Mass Ave, Cambridge, MA 02139, USA.
- * 
- */
+/* This file is part of SIS (SPARC instruction simulator)
 
+   Copyright (C) 1995-2021 Free Software Foundation, Inc.
+   Contributed by Jiri Gaisler, European Space Agency
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
 #include "sis.h"
-#include "end.h"
 #include <math.h>
 #include <stdio.h>
 
-extern int32    ext_irl, irqpend, iurev0, sis_verbose;
+extern int32    sis_verbose, sparclite;
+int ext_irl = 0;
 
 /* Load/store interlock delay */
 #define FLSTHOLD 1
@@ -55,6 +52,14 @@ extern int32    ext_irl, irqpend, iurev0, sis_verbose;
 #define        FBUG    5
 #define        FBG     6
 #define        FBU     7
+#define FBA    8
+#define FBE    9
+#define FBUE   10
+#define FBGE   11
+#define FBUGE  12
+#define FBLE   13
+#define FBULE  14
+#define FBO    15
 
 #define        FCC_E   0
 #define        FCC_L   1
@@ -73,10 +78,12 @@ extern int32    ext_irl, irqpend, iurev0, sis_verbose;
 #define PSR_CWP 0x7
 #define PSR_PIL 0x0f00
 
-#define ICC_N  sregs->psr
-#define ICC_Z  (sregs->psr << 1)
-#define ICC_V  (sregs->psr << 2)
-#define ICC_C  (sregs->psr << 3)
+#define ICC_N  (icc >> 3)
+#define ICC_Z  (icc >> 2)
+#define ICC_V  (icc >> 1)
+#define ICC_C  (icc)
+
+#define FP_PRES        (sregs->fpu_pres)
 
 #define TRAP_IEXC 1
 #define TRAP_UNIMP 2
@@ -88,6 +95,7 @@ extern int32    ext_irl, irqpend, iurev0, sis_verbose;
 #define TRAP_FPEXC 8
 #define TRAP_DEXC 9
 #define TRAP_TAG 10
+#define TRAP_DIV0 0x2a
 
 #define FSR_TT         0x1C000
 #define FP_IEEE                0x04000
@@ -103,6 +111,13 @@ extern int32    ext_irl, irqpend, iurev0, sis_verbose;
 #define        BICC_NEG        6
 #define        BICC_BVS        7
 #define        BICC_BA         8
+#define        BICC_BNE        9
+#define        BICC_BG         10
+#define        BICC_BGE        11
+#define        BICC_BGU        12
+#define        BICC_BCC        13
+#define        BICC_POS        14
+#define        BICC_BVC        15
 
 #define INST_SIMM13 0x1fff
 #define INST_RS2    0x1f
@@ -112,12 +127,23 @@ extern int32    ext_irl, irqpend, iurev0, sis_verbose;
 #define ADDX   0x08
 #define ADDXCC         0x18
 #define TADDCC         0x20
-#define TADDCCTV       0x22
+#define TSUBCC  0x21
+#define TADDCCTV 0x22
+#define TSUBCCTV 0x23
 #define IAND   0x01
 #define IANDCC         0x11
 #define IANDN  0x05
 #define IANDNCC        0x15
 #define MULScc         0x24
+#define DIVScc         0x1D
+#define SMUL   0x0B
+#define SMULCC 0x1B
+#define UMUL   0x0A
+#define UMULCC 0x1A
+#define SDIV   0x0F
+#define SDIVCC 0x1F
+#define UDIV   0x0E
+#define UDIVCC 0x1E
 #define IOR    0x02
 #define IORCC  0x12
 #define IORN   0x06
@@ -140,6 +166,7 @@ extern int32    ext_irl, irqpend, iurev0, sis_verbose;
 #define RDPSR  0x29
 #define RDWIM  0x2A
 #define RDTBR  0x2B
+#define SCAN   0x2C
 #define WRY    0x30
 #define WRPSR  0x31
 #define WRWIM  0x32
@@ -180,55 +207,64 @@ extern int32    ext_irl, irqpend, iurev0, sis_verbose;
 #define STHA   0x16
 #define SWAP   0x0F
 #define SWAPA  0x1F
+#define FLUSH  0x3B
+
+#define SIGN_BIT 0x80000000
 
 /* # of cycles overhead when a trap is taken */
 #define TRAP_C  3
 
-int32           fpexec();
+/* Forward declarations */
+
+static uint32  sub_cc (uint32 psr, int32 operand1, int32 operand2,
+                       int32 result);
+static uint32  add_cc (uint32 psr, int32 operand1, int32 operand2,
+                       int32 result);
+static void    log_cc (int32 result, struct pstate *sregs);
+static int     fpexec (uint32 op3, uint32 rd, uint32 rs1, uint32 rs2,
+                       struct pstate *sregs);
+static int     chk_asi (struct pstate *sregs, uint32 *asi, uint32 op3);
+
+
 extern struct estate ebase;
-extern int32    nfp;
+extern int32    nfp,ift;
+
+#ifdef ERRINJ
+extern uint32 errtt, errftt;
+#endif
 
-sub_cc(operand1, operand2, result, sregs)
-    int32           operand1;
-    int32           operand2;
-    int32           result;
-    struct pstate  *sregs;
+static uint32
+sub_cc(uint32 psr, int32 operand1, int32 operand2, int32 result)
 {
-    sregs->psr = ((sregs->psr & ~PSR_N) | ((result >> 8) & PSR_N));
+    psr = ((psr & ~PSR_N) | ((result >> 8) & PSR_N));
     if (result)
-       sregs->psr &= ~PSR_Z;
+       psr &= ~PSR_Z;
     else
-       sregs->psr |= PSR_Z;
-    sregs->psr = (sregs->psr & ~PSR_V) | ((
-                                        ((operand1 & ~operand2 & ~result) |
+       psr |= PSR_Z;
+    psr = (psr & ~PSR_V) | ((((operand1 & ~operand2 & ~result) |
                           (~operand1 & operand2 & result)) >> 10) & PSR_V);
-    sregs->psr = (sregs->psr & ~PSR_C) | ((
-                                          ((~operand1 & operand2) |
+    psr = (psr & ~PSR_C) | ((((~operand1 & operand2) |
                         ((~operand1 | operand2) & result)) >> 11) & PSR_C);
+    return psr;
 }
 
-add_cc(operand1, operand2, result, psr)
-    int32           operand1;
-    int32           operand2;
-    int32           result;
-    uint32         *psr;
+uint32
+add_cc(uint32 psr, int32 operand1, int32 operand2, int32 result)
 {
-    *psr = ((*psr & ~PSR_N) | ((result >> 8) & PSR_N));
+    psr = ((psr & ~PSR_N) | ((result >> 8) & PSR_N));
     if (result)
-       *psr &= ~PSR_Z;
+       psr &= ~PSR_Z;
     else
-       *psr |= PSR_Z;
-    *psr = (*psr & ~PSR_V) | ((
-                              ((operand1 & operand2 & ~result) |
+       psr |= PSR_Z;
+    psr = (psr & ~PSR_V) | ((((operand1 & operand2 & ~result) |
                          (~operand1 & ~operand2 & result)) >> 10) & PSR_V);
-    *psr = (*psr & ~PSR_C) | ((
-                              ((operand1 & operand2) |
+    psr = (psr & ~PSR_C) | ((((operand1 & operand2) |
                         ((operand1 | operand2) & ~result)) >> 11) & PSR_C);
+    return psr;
 }
 
-log_cc(result, sregs)
-    int32           result;
-    struct pstate  *sregs;
+static void
+log_cc(int32 result, struct pstate *sregs)
 {
     sregs->psr &= ~(PSR_CC);   /* Zero CC bits */
     sregs->psr = (sregs->psr | ((result >> 8) & PSR_N));
@@ -236,25 +272,141 @@ log_cc(result, sregs)
        sregs->psr |= PSR_Z;
 }
 
+/* Add two unsigned 32-bit integers, and calculate the carry out. */
+
+static uint32
+add32 (uint32 n1, uint32 n2, int *carry)
+{
+  uint32 result = n1 + n2;
+
+  *carry = result < n1 || result < n2;
+  return result;
+}
+
+/* Multiply two 32-bit integers.  */
+
+static void
+mul64 (uint32 n1, uint32 n2, uint32 *result_hi, uint32 *result_lo, int msigned)
+{
+  uint32 lo, mid1, mid2, hi, reg_lo, reg_hi;
+  int carry;
+  int sign = 0;
+
+  /* If this is a signed multiply, calculate the sign of the result
+     and make the operands positive.  */
+  if (msigned)
+    {
+      sign = (n1 ^ n2) & SIGN_BIT;
+      if (n1 & SIGN_BIT)
+       n1 = -n1;
+      if (n2 & SIGN_BIT)
+       n2 = -n2;
+      
+    }
+  
+  /* We can split the 32x32 into four 16x16 operations. This ensures
+     that we do not lose precision on 32bit only hosts: */
+  lo =   ((n1 & 0xFFFF) * (n2 & 0xFFFF));
+  mid1 = ((n1 & 0xFFFF) * ((n2 >> 16) & 0xFFFF));
+  mid2 = (((n1 >> 16) & 0xFFFF) * (n2 & 0xFFFF));
+  hi =   (((n1 >> 16) & 0xFFFF) * ((n2 >> 16) & 0xFFFF));
+  
+  /* We now need to add all of these results together, taking care
+     to propogate the carries from the additions: */
+  reg_lo = add32 (lo, (mid1 << 16), &carry);
+  reg_hi = carry;
+  reg_lo = add32 (reg_lo, (mid2 << 16), &carry);
+  reg_hi += (carry + ((mid1 >> 16) & 0xFFFF) + ((mid2 >> 16) & 0xFFFF) + hi);
+
+  /* Negate result if necessary. */
+  if (sign)
+    {
+      reg_hi = ~ reg_hi;
+      reg_lo = - reg_lo;
+      if (reg_lo == 0)
+       reg_hi++;
+    }
+  
+  *result_lo = reg_lo;
+  *result_hi = reg_hi;
+}
+
+
+/* Divide a 64-bit integer by a 32-bit integer.  We cheat and assume
+   that the host compiler supports long long operations.  */
+
+static void
+div64 (uint32 n1_hi, uint32 n1_low, uint32 n2, uint32 *result, int msigned)
+{
+  uint64 n1;
+
+  n1 = ((uint64) n1_hi) << 32;
+  n1 |= ((uint64) n1_low) & 0xffffffff;
+
+  if (msigned)
+    {
+      int64 n1_s = (int64) n1;
+      int32 n2_s = (int32) n2;
+      n1_s = n1_s / n2_s;
+      n1 = (uint64) n1_s;
+    }
+  else
+    n1 = n1 / n2;
+
+  *result = (uint32) (n1 & 0xffffffff);
+}
+
+
+static int
+extract_short (uint32 data, uint32 address)
+{
+    return ((data >> ((2 - (address & 2)) * 8)) & 0xffff);
+}
+
+static int
+extract_short_signed (uint32 data, uint32 address)
+{
+    uint32 tmp = ((data >> ((2 - (address & 2)) * 8)) & 0xffff);
+    if (tmp & 0x8000)
+        tmp |= 0xffff0000;
+    return tmp;
+}
+
+static int
+extract_byte (uint32 data, uint32 address)
+{
+    return ((data >> ((3 - (address & 3)) * 8)) & 0xff);
+}
+
+static int
+extract_byte_signed (uint32 data, uint32 address)
+{
+    uint32 tmp = ((data >> ((3 - (address & 3)) * 8)) & 0xff);
+    if (tmp & 0x80)
+        tmp |= 0xffffff00;
+    return tmp;
+}
+
 int
-dispatch_instruction(sregs)
-    struct pstate  *sregs;
+dispatch_instruction(struct pstate *sregs)
 {
 
-    uint32          cwp, op, op2, op3, opf, opc, asi, a, rd, cond, rs1,
+    uint32          cwp, op, op2, op3, asi, rd, cond, rs1,
                     rs2;
-    uint32          ldep;
-    int32           operand1, operand2, *rdd, result, i, disp22, eicc,
+    uint32          ldep, icc;
+    int32           operand1, operand2, *rdd, result, eicc,
                     new_cwp;
     int32           pc, npc, data, address, ws, mexc, fcc;
+    int32          ddata[2];
 
     sregs->ninst++;
-    sregs->icnt = 1;
     cwp = ((sregs->psr & PSR_CWP) << 4);
     op = sregs->inst >> 30;
     pc = sregs->npc;
     npc = sregs->npc + 4;
-    if (op > 1) {
+    op3 = rd = rs1 = operand2 = eicc = 0;
+    rdd = 0;
+    if (op & 2) {
 
        op3 = (sregs->inst >> 19) & 0x3f;
        rs1 = (sregs->inst >> 14) & 0x1f;
@@ -263,14 +415,15 @@ dispatch_instruction(sregs)
 #ifdef LOAD_DEL
 
        /* Check if load dependecy is possible */
-       ldep = ((ebase.simtime <= sregs->ildtime) && ((op3 & 0x38) != 0x28) &&
-               ((op3 & 0x3e) != 0x34) && (sregs->ildreg != 0));
+       if (ebase.simtime <= sregs->ildtime)
+           ldep = (((op3 & 0x38) != 0x28) && ((op3 & 0x3e) != 0x34) && (sregs->ildreg != 0));
+        else
+           ldep = 0;
        if (sregs->inst & INST_I) {
            if (ldep && (sregs->ildreg == rs1))
                sregs->hold++;
-           operand2 = sregs->inst & INST_SIMM13;
-           if (operand2 > 0x0fff)
-               operand2 |= 0xfffff000;
+           operand2 = sregs->inst;
+           operand2 = ((operand2 << 19) >> 19);        /* sign extend */
        } else {
            rs2 = sregs->inst & INST_RS2;
            if (rs2 > 7)
@@ -282,9 +435,8 @@ dispatch_instruction(sregs)
        }
 #else
        if (sregs->inst & INST_I) {
-           operand2 = sregs->inst & INST_SIMM13;
-           if (operand2 > 0x0fff)
-               operand2 |= 0xfffff000;
+           operand2 = sregs->inst;
+           operand2 = ((operand2 << 19) >> 19);        /* sign extend */
        } else {
            rs2 = sregs->inst & INST_RS2;
            if (rs2 > 7)
@@ -319,8 +471,9 @@ dispatch_instruction(sregs)
 #ifdef STAT
            sregs->nbranch++;
 #endif
+           icc = sregs->psr >> 20;
            cond = ((sregs->inst >> 25) & 0x0f);
-           switch (cond & 0x7) {
+           switch (cond) {
            case BICC_BN:
                eicc = 0;
                break;
@@ -345,20 +498,39 @@ dispatch_instruction(sregs)
            case BICC_BVS:
                eicc = ICC_V;
                break;
-           }
-           eicc &= PSR_N;
-           if (sregs->inst & 0x10000000)
-               eicc = !eicc;
-           a = sregs->inst & 0x20000000;
-           if (eicc) {
-               operand1 = sregs->inst & 0x3fffff;
-               if (sregs->inst & 0x200000)
-                   operand1 |= 0xffc00000;
-               npc = sregs->pc + (operand1 << 2);
-               if ((cond == BICC_BA) && (a))
+           case BICC_BA:
+               eicc = 1;
+               if (sregs->inst & 0x20000000)
                    sregs->annul = 1;
+               break;
+           case BICC_BNE:
+               eicc = ~(ICC_Z);
+               break;
+           case BICC_BG:
+               eicc = ~(ICC_Z | (ICC_N ^ ICC_V));
+               break;
+           case BICC_BGE:
+               eicc = ~(ICC_N ^ ICC_V);
+               break;
+           case BICC_BGU:
+               eicc = ~(ICC_C | ICC_Z);
+               break;
+           case BICC_BCC:
+               eicc = ~(ICC_C);
+               break;
+           case BICC_POS:
+               eicc = ~(ICC_N);
+               break;
+           case BICC_BVC:
+               eicc = ~(ICC_V);
+               break;
+           }
+           if (eicc & 1) {
+               operand1 = sregs->inst;
+               operand1 = ((operand1 << 10) >> 8);     /* sign extend */
+               npc = sregs->pc + operand1;
            } else {
-               if (a)
+               if (sregs->inst & 0x20000000)
                    sregs->annul = 1;
            }
            break;
@@ -366,7 +538,7 @@ dispatch_instruction(sregs)
 #ifdef STAT
            sregs->nbranch++;
 #endif
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
                break;
            }
@@ -375,7 +547,7 @@ dispatch_instruction(sregs)
            }
            cond = ((sregs->inst >> 25) & 0x0f);
            fcc = (sregs->fsr >> 10) & 0x3;
-           switch (cond & 0x7) {
+           switch (cond) {
            case FBN:
                eicc = 0;
                break;
@@ -400,19 +572,39 @@ dispatch_instruction(sregs)
            case FBU:
                eicc = (fcc == FCC_U);
                break;
+           case FBA:
+               eicc = 1;
+               if (sregs->inst & 0x20000000)
+                   sregs->annul = 1;
+               break;
+           case FBE:
+               eicc = !(fcc != FCC_E);
+               break;
+           case FBUE:
+               eicc = !((fcc == FCC_L) || (fcc == FCC_G));
+               break;
+           case FBGE:
+               eicc = !((fcc == FCC_L) || (fcc == FCC_U));
+               break;
+           case FBUGE:
+               eicc = !(fcc == FCC_L);
+               break;
+           case FBLE:
+               eicc = !((fcc == FCC_G) || (fcc == FCC_U));
+               break;
+           case FBULE:
+               eicc = !(fcc == FCC_G);
+               break;
+           case FBO:
+               eicc = !(fcc == FCC_U);
+               break;
            }
-           if (sregs->inst & 0x10000000)
-               eicc = !eicc;
-           a = sregs->inst & 0x20000000;
            if (eicc) {
-               operand1 = sregs->inst & 0x3fffff;
-               if (sregs->inst & 0x200000)
-                   operand1 |= 0xffc00000;
-               npc = sregs->pc + (operand1 << 2);
-               if ((cond == FBA) && (a))
-                   sregs->annul = 1;
+               operand1 = sregs->inst;
+               operand1 = ((operand1 << 10) >> 8);     /* sign extend */
+               npc = sregs->pc + operand1;
            } else {
-               if (a)
+               if (sregs->inst & 0x20000000)
                    sregs->annul = 1;
            }
            break;
@@ -432,7 +624,7 @@ dispatch_instruction(sregs)
 
     case 2:
        if ((op3 >> 1) == 0x1a) {
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
            } else {
                rs1 = (sregs->inst >> 14) & 0x1f;
@@ -443,8 +635,9 @@ dispatch_instruction(sregs)
 
            switch (op3) {
            case TICC:
-               cond = ((sregs->inst >> 25) & 0x0f);
-               switch (cond & 0x7) {
+               icc = sregs->psr >> 20;
+               cond = ((sregs->inst >> 25) & 0x0f);
+               switch (cond) {
                case BICC_BN:
                    eicc = 0;
                    break;
@@ -469,11 +662,32 @@ dispatch_instruction(sregs)
                case BICC_BVS:
                    eicc = ICC_V;
                    break;
+               case BICC_BA:
+                   eicc = 1;
+                   break;
+               case BICC_BNE:
+                   eicc = ~(ICC_Z);
+                   break;
+               case BICC_BG:
+                   eicc = ~(ICC_Z | (ICC_N ^ ICC_V));
+                   break;
+               case BICC_BGE:
+                   eicc = ~(ICC_N ^ ICC_V);
+                   break;
+               case BICC_BGU:
+                   eicc = ~(ICC_C | ICC_Z);
+                   break;
+               case BICC_BCC:
+                   eicc = ~(ICC_C);
+                   break;
+               case BICC_POS:
+                   eicc = ~(ICC_N);
+                   break;
+               case BICC_BVC:
+                   eicc = ~(ICC_V);
+                   break;
                }
-               eicc &= PSR_N;
-               if (sregs->inst & 0x10000000)
-                   eicc = !eicc;
-               if (eicc) {
+               if (eicc & 1) {
                    sregs->trap = (0x80 | ((rs1 + operand2) & 0x7f));
                }
                break;
@@ -486,7 +700,211 @@ dispatch_instruction(sregs)
                    operand2 = 0;
                *rdd = operand1 + operand2;
                sregs->y = (rs1 << 31) | (sregs->y >> 1);
-               add_cc(operand1, operand2, *rdd, &sregs->psr);
+               sregs->psr = add_cc(sregs->psr, operand1, operand2, *rdd);
+               break;
+           case DIVScc:
+               {
+                 int sign;
+                 uint32 result, remainder;
+                 int c0, y31;
+
+                 if (!sparclite) {
+                    sregs->trap = TRAP_UNIMP;
+                     break;
+                 }
+
+                 sign = ((sregs->psr & PSR_V) != 0) ^ ((sregs->psr & PSR_N) != 0);
+
+                 remainder = (sregs->y << 1) | (rs1 >> 31);
+
+                 /* If true sign is positive, calculate remainder - divisor.
+                    Otherwise, calculate remainder + divisor.  */
+                 if (sign == 0)
+                   operand2 = ~operand2 + 1;
+                 result = remainder + operand2;
+
+                 /* The SPARClite User's Manual is not clear on how
+                    the "carry out" of the above ALU operation is to
+                    be calculated.  From trial and error tests
+                    on the the chip itself, it appears that it is
+                    a normal addition carry, and not a subtraction borrow,
+                    even in cases where the divisor is subtracted
+                    from the remainder.  FIXME: get the true story
+                    from Fujitsu. */
+                 c0 = result < (uint32) remainder
+                      || result < (uint32) operand2;
+
+                 if (result & 0x80000000)
+                   sregs->psr |= PSR_N;
+                 else
+                   sregs->psr &= ~PSR_N;
+
+                 y31 = (sregs->y & 0x80000000) == 0x80000000;
+
+                 if (result == 0 && sign == y31)
+                   sregs->psr |= PSR_Z;
+                 else
+                   sregs->psr &= ~PSR_Z;
+
+                 sign = (sign && !y31) || (!c0 && (sign || !y31));
+
+                 if (sign ^ (result >> 31))
+                   sregs->psr |= PSR_V;
+                 else
+                   sregs->psr &= ~PSR_V;
+
+                 if (!sign)
+                   sregs->psr |= PSR_C;
+                 else
+                   sregs->psr &= ~PSR_C;
+
+                 sregs->y = result;
+
+                 if (rd != 0)
+                   *rdd = (rs1 << 1) | !sign;
+               }
+               break;
+           case SMUL:
+               {
+                 mul64 (rs1, operand2, &sregs->y, rdd, 1);
+               }
+               break;
+           case SMULCC:
+               {
+                 uint32 result;
+
+                 mul64 (rs1, operand2, &sregs->y, &result, 1);
+
+                 if (result & 0x80000000)
+                   sregs->psr |= PSR_N;
+                 else
+                   sregs->psr &= ~PSR_N;
+
+                 if (result == 0)
+                   sregs->psr |= PSR_Z;
+                 else
+                   sregs->psr &= ~PSR_Z;
+
+                 *rdd = result;
+               }
+               break;
+           case UMUL:
+               {
+                 mul64 (rs1, operand2, &sregs->y, rdd, 0);
+               }
+               break;
+           case UMULCC:
+               {
+                 uint32 result;
+
+                 mul64 (rs1, operand2, &sregs->y, &result, 0);
+
+                 if (result & 0x80000000)
+                   sregs->psr |= PSR_N;
+                 else
+                   sregs->psr &= ~PSR_N;
+
+                 if (result == 0)
+                   sregs->psr |= PSR_Z;
+                 else
+                   sregs->psr &= ~PSR_Z;
+
+                 *rdd = result;
+               }
+               break;
+           case SDIV:
+               {
+                 if (sparclite) {
+                    sregs->trap = TRAP_UNIMP;
+                     break;
+                 }
+
+                 if (operand2 == 0) {
+                   sregs->trap = TRAP_DIV0;
+                   break;
+                 }
+
+                 div64 (sregs->y, rs1, operand2, rdd, 1);
+               }
+               break;
+           case SDIVCC:
+               {
+                 uint32 result;
+
+                 if (sparclite) {
+                    sregs->trap = TRAP_UNIMP;
+                     break;
+                 }
+
+                 if (operand2 == 0) {
+                   sregs->trap = TRAP_DIV0;
+                   break;
+                 }
+
+                 div64 (sregs->y, rs1, operand2, &result, 1);
+
+                 if (result & 0x80000000)
+                   sregs->psr |= PSR_N;
+                 else
+                   sregs->psr &= ~PSR_N;
+
+                 if (result == 0)
+                   sregs->psr |= PSR_Z;
+                 else
+                   sregs->psr &= ~PSR_Z;
+
+                 /* FIXME: should set overflow flag correctly.  */
+                 sregs->psr &= ~(PSR_C | PSR_V);
+
+                 *rdd = result;
+               }
+               break;
+           case UDIV:
+               {
+                 if (sparclite) {
+                    sregs->trap = TRAP_UNIMP;
+                     break;
+                 }
+
+                 if (operand2 == 0) {
+                   sregs->trap = TRAP_DIV0;
+                   break;
+                 }
+
+                 div64 (sregs->y, rs1, operand2, rdd, 0);
+               }
+               break;
+           case UDIVCC:
+               {
+                 uint32 result;
+
+                 if (sparclite) {
+                    sregs->trap = TRAP_UNIMP;
+                     break;
+                 }
+
+                 if (operand2 == 0) {
+                   sregs->trap = TRAP_DIV0;
+                   break;
+                 }
+
+                 div64 (sregs->y, rs1, operand2, &result, 0);
+
+                 if (result & 0x80000000)
+                   sregs->psr |= PSR_N;
+                 else
+                   sregs->psr &= ~PSR_N;
+
+                 if (result == 0)
+                   sregs->psr |= PSR_Z;
+                 else
+                   sregs->psr &= ~PSR_Z;
+
+                 /* FIXME: should set overflow flag correctly.  */
+                 sregs->psr &= ~(PSR_C | PSR_V);
+
+                 *rdd = result;
+               }
                break;
            case IXNOR:
                *rdd = rs1 ^ ~operand2;
@@ -535,47 +953,66 @@ dispatch_instruction(sregs)
                break;
            case SUBCC:
                *rdd = rs1 - operand2;
-               sub_cc(rs1, operand2, *rdd, sregs);
+               sregs->psr = sub_cc(sregs->psr, rs1, operand2, *rdd);
                break;
            case SUBX:
                *rdd = rs1 - operand2 - ((sregs->psr >> 20) & 1);
                break;
            case SUBXCC:
                *rdd = rs1 - operand2 - ((sregs->psr >> 20) & 1);
-               sub_cc(rs1, operand2, *rdd, sregs);
+               sregs->psr = sub_cc(sregs->psr, rs1, operand2, *rdd);
                break;
            case ADD:
                *rdd = rs1 + operand2;
                break;
            case ADDCC:
                *rdd = rs1 + operand2;
-               add_cc(rs1, operand2, *rdd, &sregs->psr);
+               sregs->psr = add_cc(sregs->psr, rs1, operand2, *rdd);
                break;
            case ADDX:
                *rdd = rs1 + operand2 + ((sregs->psr >> 20) & 1);
                break;
            case ADDXCC:
                *rdd = rs1 + operand2 + ((sregs->psr >> 20) & 1);
-               add_cc(rs1, operand2, *rdd, &sregs->psr);
+               sregs->psr = add_cc(sregs->psr, rs1, operand2, *rdd);
                break;
            case TADDCC:
                *rdd = rs1 + operand2;
-               add_cc(rs1, operand2, *rdd, &sregs->psr);
+               sregs->psr = add_cc(sregs->psr, rs1, operand2, *rdd);
+               if ((rs1 | operand2) & 0x3)
+                   sregs->psr |= PSR_V;
+               break;
+           case TSUBCC:
+               *rdd = rs1 - operand2;
+               sregs->psr = sub_cc (sregs->psr, rs1, operand2, *rdd);
                if ((rs1 | operand2) & 0x3)
                    sregs->psr |= PSR_V;
                break;
            case TADDCCTV:
                *rdd = rs1 + operand2;
-               result = 0;
-               add_cc(rs1, operand2, *rdd, &result);
+               result = add_cc(0, rs1, operand2, *rdd);
                if ((rs1 | operand2) & 0x3)
                    result |= PSR_V;
                if (result & PSR_V) {
                    sregs->trap = TRAP_TAG;
                } else {
-                   sregs->psr = (sregs->psr & PSR_CC) | result;
+                   sregs->psr = (sregs->psr & ~PSR_CC) | result;
                }
                break;
+           case TSUBCCTV:
+               *rdd = rs1 - operand2;
+               result = add_cc (0, rs1, operand2, *rdd);
+               if ((rs1 | operand2) & 0x3)
+                   result |= PSR_V;
+               if (result & PSR_V)
+                 {
+                     sregs->trap = TRAP_TAG;
+                 }
+               else
+                 {
+                     sregs->psr = (sregs->psr & ~PSR_CC) | result;
+                 }
+               break;
            case SLL:
                *rdd = rs1 << (operand2 & 0x1f);
                break;
@@ -585,6 +1022,9 @@ dispatch_instruction(sregs)
            case SRA:
                *rdd = ((int) rs1) >> (operand2 & 0x1f);
                break;
+           case FLUSH:
+               if (ift) sregs->trap = TRAP_UNIMP;
+               break;
            case SAVE:
                new_cwp = ((sregs->psr & PSR_CWP) - 1) & PSR_CWP;
                if (sregs->wim & (1 << new_cwp)) {
@@ -598,16 +1038,6 @@ dispatch_instruction(sregs)
                break;
            case RESTORE:
 
-#ifdef IUREV0
-               if ((iurev0) && ((sregs->jmpltime + 1) == sregs->ninst)) {
-                   if (!(sregs->rett_err)) {
-                       sregs->rett_err = 1;
-                       if (sis_verbose)
-                           printf("IU rev.0 bug mode entered\n");
-                   }
-               }
-#endif
-
                new_cwp = ((sregs->psr & PSR_CWP) + 1) & PSR_CWP;
                if (sregs->wim & (1 << new_cwp)) {
                    sregs->trap = TRAP_WUFL;
@@ -624,26 +1054,21 @@ dispatch_instruction(sregs)
                    break;
                }
                *rdd = sregs->psr;
-#ifdef IUREV0
-
-               if (iurev0 & sregs->rett_err) {
-                   operand2 = sregs->psr;
-                   *rdd |= PSR_ET;
-                   *rdd &= ~(PSR_S);
-                   *rdd |= ((*rdd & PSR_PS) << 1);
-                   if (sis_verbose) {
-                       if (operand2 != *rdd)
-                           printf("rdpsr failed: %08X -> %08X\n", operand2, *rdd);
-                   }
-               }
-#endif
                break;
            case RDY:
-               if (!(sregs->psr & PSR_S)) {
-                   sregs->trap = TRAP_PRIVI;
-                   break;
-               }
-               *rdd = sregs->y;
+                if (!sparclite)
+                    *rdd = sregs->y;
+                else {
+                    int rs1_is_asr = (sregs->inst >> 14) & 0x1f;
+                    if ( 0 == rs1_is_asr )
+                        *rdd = sregs->y;
+                    else if ( 17 == rs1_is_asr )
+                        *rdd = sregs->asr17;
+                    else {
+                        sregs->trap = TRAP_UNIMP;
+                        break;
+                    }
+                }
                break;
            case RDWIM:
                if (!(sregs->psr & PSR_S)) {
@@ -668,7 +1093,8 @@ dispatch_instruction(sregs)
                    sregs->trap = TRAP_PRIVI;
                    break;
                }
-               sregs->psr = (rs1 ^ operand2) & 0x00f03fff;
+               sregs->psr = (sregs->psr & 0xff000000) |
+                       (rs1 ^ operand2) & 0x00f03fff;
                break;
            case WRWIM:
                if (!(sregs->psr & PSR_S)) {
@@ -686,14 +1112,21 @@ dispatch_instruction(sregs)
                    ((rs1 ^ operand2) & 0xfffff000);
                break;
            case WRY:
-               sregs->y = (rs1 ^ operand2);
+                if (!sparclite)
+                    sregs->y = (rs1 ^ operand2);
+                else {
+                    if ( 0 == rd )
+                        sregs->y = (rs1 ^ operand2);
+                    else if ( 17 == rd )
+                        sregs->asr17 = (rs1 ^ operand2);
+                    else {
+                        sregs->trap = TRAP_UNIMP;
+                        break;
+                    }
+                }
                break;
            case JMPL:
 
-#ifdef IUREV0
-               if (iurev0)
-                   sregs->jmpltime = sregs->ninst;
-#endif
 #ifdef STAT
                sregs->nbranch++;
 #endif
@@ -706,14 +1139,6 @@ dispatch_instruction(sregs)
                npc = rs1 + operand2;
                break;
            case RETT:
-#ifdef IUREV0
-               if (iurev0 && sregs->rett_err) {
-                   sregs->rett_err = 0;
-                   if (sis_verbose)
-                       printf("IU rev.0 bug mode reset\n");
-               }
-#endif
-
                address = rs1 + operand2;
                new_cwp = ((sregs->psr & PSR_CWP) + 1) & PSR_CWP;
                sregs->icnt = T_RETT;   /* RETT takes two cycles */
@@ -739,6 +1164,28 @@ dispatch_instruction(sregs)
                npc = address;
                break;
 
+           case SCAN:
+               {
+                 uint32 result, mask;
+                 int i;
+
+                 if (!sparclite) {
+                    sregs->trap = TRAP_UNIMP;
+                     break;
+                 }
+                 mask = (operand2 & 0x80000000) | (operand2 >> 1);
+                 result = rs1 ^ mask;
+
+                 for (i = 0; i < 32; i++) {
+                   if (result & 0x80000000)
+                     break;
+                   result <<= 1;
+                 }
+
+                 *rdd = i == 32 ? 63 : i;
+               }
+               break;
+
            default:
                sregs->trap = TRAP_UNIMP;
                break;
@@ -749,29 +1196,10 @@ dispatch_instruction(sregs)
 
        address = rs1 + operand2;
 
-       /* Check for load/store to alternate address space */
-
-       if ((op3 >> 4) == 1) {
-           if (!(sregs->psr & PSR_S)) {
-               sregs->trap = TRAP_PRIVI;
-               break;
-           } else if (sregs->inst & INST_I) {
-               sregs->trap = TRAP_UNIMP;
-               break;
-           } else
-               asi = (sregs->inst >> 5) & 0x0ff;
-       } else {
-           if (sregs->psr & PSR_S)
-               asi = 11;
-           else
-               asi = 10;
-#ifdef IUREV0
-           if (iurev0 && sregs->rett_err) {
-               asi &= ~0x1;
-               asi |= ((sregs->psr & PSR_PS) >> 6);
-           }
-#endif
-       }
+       if (sregs->psr & PSR_S)
+           asi = 11;
+        else
+           asi = 10;
 
        if (op3 & 4) {
            sregs->icnt = T_ST; /* Set store instruction count */
@@ -789,6 +1217,7 @@ dispatch_instruction(sregs)
 
        switch (op3) {
        case LDDA:
+           if (!chk_asi(sregs, &asi, op3)) break;
        case LDD:
            if (address & 0x7) {
                sregs->trap = TRAP_UNALI;
@@ -801,34 +1230,30 @@ dispatch_instruction(sregs)
                else
                    rdd = &(sregs->g[rd]);
            }
-           mexc = memory_read(asi, address, &data, &ws);
+           mexc = memory_read (asi, address, ddata, 2, &ws);
+           sregs->hold += ws;
+           mexc |= memory_read (asi, address+4, &ddata[1], 2, &ws);
            sregs->hold += ws;
            sregs->icnt = T_LDD;
            if (mexc) {
                sregs->trap = TRAP_DEXC;
            } else {
-               rdd[0] = data;
-               address += 4;
-               mexc = memory_read(asi, address, &data, &ws);
-               sregs->hold += ws;
+               rdd[0] = ddata[0];
+               rdd[1] = ddata[1];
 #ifdef STAT
                sregs->nload++; /* Double load counts twice */
 #endif
-               if (mexc) {
-                   sregs->trap = TRAP_DEXC;
-               } else {
-                   rdd[1] = data;
-               }
            }
            break;
 
        case LDA:
+           if (!chk_asi(sregs, &asi, op3)) break;
        case LD:
            if (address & 0x3) {
                sregs->trap = TRAP_UNALI;
                break;
            }
-           mexc = memory_read(asi, address, &data, &ws);
+           mexc = memory_read(asi, address, &data, 2, &ws);
            sregs->hold += ws;
            if (mexc) {
                sregs->trap = TRAP_DEXC;
@@ -836,16 +1261,17 @@ dispatch_instruction(sregs)
                *rdd = data;
            }
            break;
-       case LDSTUB:
        case LDSTUBA:
-           mexc = memory_read(asi, address, &data, &ws);
+           if (!chk_asi(sregs, &asi, op3)) break;
+       case LDSTUB:
+           mexc = memory_read(asi, address, &data, 0, &ws);
            sregs->hold += ws;
            sregs->icnt = T_LDST;
            if (mexc) {
                sregs->trap = TRAP_DEXC;
                break;
            }
-           data = (data >> ((3 - (address & 0x3)) << 3)) & 0x0ff;
+           data = extract_byte (data, address);
            *rdd = data;
            data = 0x0ff;
            mexc = memory_write(asi, address, &data, 0, &ws);
@@ -859,42 +1285,44 @@ dispatch_instruction(sregs)
            break;
        case LDSBA:
        case LDUBA:
+           if (!chk_asi(sregs, &asi, op3)) break;
        case LDSB:
        case LDUB:
-           mexc = memory_read(asi, address, &data, &ws);
+           mexc = memory_read(asi, address, &data, 0, &ws);
            sregs->hold += ws;
            if (mexc) {
                sregs->trap = TRAP_DEXC;
                break;
            }
-           data = (data >> ((3 - (address & 0x3)) << 3)) & 0x0ff;
-           if ((op3 == LDSB) && (data >> 7))
-               data |= 0xffffff00;
+           if (op3 == LDSB)
+               data = extract_byte_signed (data, address);
+           else
+               data = extract_byte (data, address);
            *rdd = data;
            break;
        case LDSHA:
        case LDUHA:
+           if (!chk_asi(sregs, &asi, op3)) break;
        case LDSH:
        case LDUH:
            if (address & 0x1) {
                sregs->trap = TRAP_UNALI;
                break;
            }
-           mexc = memory_read(asi, address, &data, &ws);
+           mexc = memory_read(asi, address, &data, 1, &ws);
            sregs->hold += ws;
            if (mexc) {
                sregs->trap = TRAP_DEXC;
                break;
            }
-           if (!(address & 0x2))
-               data >>= 16;
-           data &= 0x0ffff;
-           if ((op3 == LDSH) && (data >> 15))
-               data |= 0xffff0000;
+           if (op3 == LDSH)
+               data = extract_short_signed (data, address);
+           else
+               data = extract_short (data, address);
            *rdd = data;
            break;
        case LDF:
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
                break;
            }
@@ -907,7 +1335,7 @@ dispatch_instruction(sregs)
                    (sregs->frs2 == rd))
                    sregs->fhold += (sregs->ftime - ebase.simtime);
            }
-           mexc = memory_read(asi, address, &data, &ws);
+           mexc = memory_read(asi, address, &data, 2, &ws);
            sregs->hold += ws;
            sregs->flrd = rd;
            sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD +
@@ -919,7 +1347,7 @@ dispatch_instruction(sregs)
            }
            break;
        case LDDF:
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
                break;
            }
@@ -933,7 +1361,9 @@ dispatch_instruction(sregs)
                    ((sregs->frs2 >> 1) == (rd >> 1)))
                    sregs->fhold += (sregs->ftime - ebase.simtime);
            }
-           mexc = memory_read(asi, address, &data, &ws);
+           mexc = memory_read (asi, address, ddata, 2, &ws);
+           sregs->hold += ws;
+           mexc |= memory_read (asi, address+4, &ddata[1], 2, &ws);
            sregs->hold += ws;
            sregs->icnt = T_LDD;
            if (mexc) {
@@ -941,26 +1371,20 @@ dispatch_instruction(sregs)
            } else {
                rd &= 0x1E;
                sregs->flrd = rd;
-               sregs->fs[rd] = *((float32 *) & data);
-               mexc = memory_read(asi, address + 4, &data, &ws);
-               sregs->hold += ws;
+               sregs->fs[rd] = *((float32 *) & ddata[0]);
 #ifdef STAT
                sregs->nload++; /* Double load counts twice */
 #endif
-               if (mexc) {
-                   sregs->trap = TRAP_DEXC;
-               } else {
-                   sregs->fs[rd + 1] = *((float32 *) & data);
-                   sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD +
-                       sregs->hold + sregs->fhold;
-               }
+               sregs->fs[rd + 1] = *((float32 *) & ddata[1]);
+               sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD +
+                              sregs->hold + sregs->fhold;
            }
            break;
        case LDFSR:
            if (ebase.simtime < sregs->ftime) {
                sregs->fhold += (sregs->ftime - ebase.simtime);
            }
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
                break;
            }
@@ -968,7 +1392,7 @@ dispatch_instruction(sregs)
                sregs->trap = TRAP_UNALI;
                break;
            }
-           mexc = memory_read(asi, address, &data, &ws);
+           mexc = memory_read(asi, address, &data, 2, &ws);
            sregs->hold += ws;
            if (mexc) {
                sregs->trap = TRAP_DEXC;
@@ -979,7 +1403,7 @@ dispatch_instruction(sregs)
            }
            break;
        case STFSR:
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
                break;
            }
@@ -997,8 +1421,9 @@ dispatch_instruction(sregs)
            }
            break;
 
-       case ST:
        case STA:
+           if (!chk_asi(sregs, &asi, op3)) break;
+       case ST:
            if (address & 0x3) {
                sregs->trap = TRAP_UNALI;
                break;
@@ -1009,16 +1434,18 @@ dispatch_instruction(sregs)
                sregs->trap = TRAP_DEXC;
            }
            break;
-       case STB:
        case STBA:
+           if (!chk_asi(sregs, &asi, op3)) break;
+       case STB:
            mexc = memory_write(asi, address, rdd, 0, &ws);
            sregs->hold += ws;
            if (mexc) {
                sregs->trap = TRAP_DEXC;
            }
            break;
-       case STD:
        case STDA:
+           if (!chk_asi(sregs, &asi, op3)) break;
+       case STD:
            if (address & 0x7) {
                sregs->trap = TRAP_UNALI;
                break;
@@ -1046,7 +1473,7 @@ dispatch_instruction(sregs)
                sregs->trap = TRAP_UNIMP;
                break;
            }
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
                break;
            }
@@ -1074,6 +1501,7 @@ dispatch_instruction(sregs)
            }
            break;
        case STHA:
+           if (!chk_asi(sregs, &asi, op3)) break;
        case STH:
            if (address & 0x1) {
                sregs->trap = TRAP_UNALI;
@@ -1086,7 +1514,7 @@ dispatch_instruction(sregs)
            }
            break;
        case STF:
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
                break;
            }
@@ -1105,7 +1533,7 @@ dispatch_instruction(sregs)
            }
            break;
        case STDF:
-           if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) {
+           if (!((sregs->psr & PSR_EF) && FP_PRES)) {
                sregs->trap = TRAP_FPDIS;
                break;
            }
@@ -1128,13 +1556,14 @@ dispatch_instruction(sregs)
                sregs->trap = TRAP_DEXC;
            }
            break;
-       case SWAP:
        case SWAPA:
+           if (!chk_asi(sregs, &asi, op3)) break;
+       case SWAP:
            if (address & 0x3) {
                sregs->trap = TRAP_UNALI;
                break;
            }
-           mexc = memory_read(asi, address, &data, &ws);
+           mexc = memory_read(asi, address, &data, 2, &ws);
            sregs->hold += ws;
            if (mexc) {
                sregs->trap = TRAP_DEXC;
@@ -1180,7 +1609,7 @@ dispatch_instruction(sregs)
        sregs->pc = pc;
        sregs->npc = npc;
     }
-    return (0);
+    return 0;
 }
 
 #define T_FABSs                2
@@ -1230,26 +1659,21 @@ dispatch_instruction(sregs)
 #define FsTOd  0xC9
 
 
-int
-fpexec(op3, rd, rs1, rs2, sregs)
-    uint32          op3, rd, rs1, rs2;
-    struct pstate  *sregs;
+static int
+fpexec(uint32 op3, uint32 rd, uint32 rs1, uint32 rs2, struct pstate *sregs)
 {
     uint32          opf, tem, accex;
-    float32         ftmps;
-    float64         ftmpd;
     int32           fcc;
-    char           *res;
     uint32          ldadj;
 
     if (sregs->fpstate == FP_EXC_MODE) {
        sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_SEQ_ERR;
-       sregs->fpstate == FP_EXC_PE;
-       return (0);
+       sregs->fpstate = FP_EXC_PE;
+       return 0;
     }
     if (sregs->fpstate == FP_EXC_PE) {
        sregs->fpstate = FP_EXC_MODE;
-       return (TRAP_FPEXC);
+       return TRAP_FPEXC;
     }
     opf = (sregs->inst >> 5) & 0x1ff;
 
@@ -1290,7 +1714,12 @@ fpexec(op3, rd, rs1, rs2, sregs)
 
     /* SPARC is big-endian - swap double floats if host is little-endian */
     /* This is ugly - I know ... */
-#ifdef HOST_LITTLE_ENDIAN_FLOAT
+
+    /* FIXME: should use (HOST_BYTE_ORDER == CURRENT_TARGET_BYTE_ORDER)
+       but what about machines where float values are different endianness
+       from integer values? */
+
+#ifdef HOST_LITTLE_ENDIAN
     rs1 &= 0x1f;
     switch (opf) {
        case FADDd:
@@ -1307,6 +1736,7 @@ fpexec(op3, rd, rs1, rs2, sregs)
            sregs->fdp[rs2 | 1] = sregs->fs[rs2 & ~1];
            sregs->fdp[rs2 & ~1] = sregs->fs[rs2 | 1];
     default:
+      break;
     }
 #endif
 
@@ -1341,7 +1771,7 @@ fpexec(op3, rd, rs1, rs2, sregs)
        sregs->ftime += T_FCMPs;
        sregs->frd = 32;        /* rd ignored */
        if ((fcc == 0) && (opf == FCMPEs)) {
-           sregs->fpstate == FP_EXC_PE;
+           sregs->fpstate = FP_EXC_PE;
            sregs->fsr = (sregs->fsr & ~0x1C000) | (1 << 14);
        }
        break;
@@ -1360,7 +1790,7 @@ fpexec(op3, rd, rs1, rs2, sregs)
        sregs->ftime += T_FCMPd;
        sregs->frd = 32;        /* rd ignored */
        if ((fcc == 0) && (opf == FCMPEd)) {
-           sregs->fpstate == FP_EXC_PE;
+           sregs->fpstate = FP_EXC_PE;
            sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE;
        }
        break;
@@ -1392,7 +1822,7 @@ fpexec(op3, rd, rs1, rs2, sregs)
        break;
     case FSQRTs:
        if (sregs->fs[rs2] < 0.0) {
-           sregs->fpstate == FP_EXC_PE;
+           sregs->fpstate = FP_EXC_PE;
            sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE;
            sregs->fsr = (sregs->fsr & 0x1f) | 0x10;
            break;
@@ -1403,7 +1833,7 @@ fpexec(op3, rd, rs1, rs2, sregs)
        break;
     case FSQRTd:
        if (sregs->fd[rs2 >> 1] < 0.0) {
-           sregs->fpstate == FP_EXC_PE;
+           sregs->fpstate = FP_EXC_PE;
            sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE;
            sregs->fsr = (sregs->fsr & 0x1f) | 0x10;
            break;
@@ -1453,12 +1883,21 @@ fpexec(op3, rd, rs1, rs2, sregs)
 
     default:
        sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_UNIMP;
-       sregs->fpstate == FP_EXC_PE;
+       sregs->fpstate = FP_EXC_PE;
     }
 
+#ifdef ERRINJ
+    if (errftt) {
+       sregs->fsr = (sregs->fsr & ~FSR_TT) | (errftt << 14);
+       sregs->fpstate = FP_EXC_PE;
+       if (sis_verbose) printf("Inserted fpu error %X\n",errftt);
+       errftt = 0;
+    }
+#endif
+
     accex = get_accex();
 
-#ifdef HOST_LITTLE_ENDIAN_FLOAT
+#ifdef HOST_LITTLE_ENDIAN
     switch (opf) {
     case FADDd:
     case FDIVd:
@@ -1470,6 +1909,7 @@ fpexec(op3, rd, rs1, rs2, sregs)
        sregs->fs[rd & ~1] = sregs->fdp[rd | 1];
        sregs->fs[rd | 1] = sregs->fdp[rd & ~1];
     default:
+      break;
     }
 #endif
     if (sregs->fpstate == FP_EXC_PE) {
@@ -1493,14 +1933,27 @@ fpexec(op3, rd, rs1, rs2, sregs)
     }
     clear_accex();
 
-    return (0);
+    return 0;
 
 
 }
 
+static int
+chk_asi(struct pstate *sregs, uint32 *asi, uint32 op3)
+{
+    if (!(sregs->psr & PSR_S)) {
+       sregs->trap = TRAP_PRIVI;
+       return 0;
+    } else if (sregs->inst & INST_I) {
+       sregs->trap = TRAP_UNIMP;
+       return 0;
+    } else
+       *asi = (sregs->inst >> 5) & 0x0ff;
+    return 1;
+}
+
 int
-execute_trap(sregs)
-    struct pstate  *sregs;
+execute_trap(struct pstate *sregs)
 {
     int32           cwp;
 
@@ -1508,10 +1961,12 @@ execute_trap(sregs)
        sregs->pc = 0;
        sregs->npc = 4;
        sregs->trap = 0;
+    } else if (sregs->trap == 257) {
+           return ERROR;
     } else {
 
        if ((sregs->psr & PSR_ET) == 0)
-           return (ERROR);
+           return ERROR;
 
        sregs->tbr = (sregs->tbr & 0xfffff000) | (sregs->trap << 4);
        sregs->trap = 0;
@@ -1526,42 +1981,54 @@ execute_trap(sregs)
        sregs->pc = sregs->tbr;
        sregs->npc = sregs->tbr + 4;
 
+        if ( 0 != (1 & sregs->asr17) ) {
+            /* single vector trapping! */
+            sregs->pc = sregs->tbr & 0xfffff000;
+            sregs->npc = sregs->pc + 4;
+        }
+
        /* Increase simulator time */
        sregs->icnt = TRAP_C;
 
     }
 
 
-    return (0);
+    return 0;
 
 }
 
 extern struct irqcell irqarr[16];
 
-void
-check_interrupts(sregs)
-    struct pstate  *sregs;
+int
+check_interrupts(struct pstate *sregs)
 {
+#ifdef ERRINJ
+    if (errtt) {
+       sregs->trap = errtt;
+       if (sis_verbose) printf("Inserted error trap 0x%02X\n",errtt);
+       errtt = 0;
+    }
+#endif
+
     if ((ext_irl) && (sregs->psr & PSR_ET) &&
-       ((ext_irl == 15) || (ext_irl > ((sregs->psr & PSR_PIL) >> 8)))) {
+       ((ext_irl == 15) || (ext_irl > (int) ((sregs->psr & PSR_PIL) >> 8)))) {
        if (sregs->trap == 0) {
            sregs->trap = 16 + ext_irl;
            irqarr[ext_irl & 0x0f].callback(irqarr[ext_irl & 0x0f].arg);
-           clear_int(ext_irl);
+           return 1;
        }
     }
+    return 0;
 }
 
-init_regs(sregs)
-    struct pstate  *sregs;
+void
+init_regs(struct pstate *sregs)
 {
-    int32           i;
-
     sregs->pc = 0;
     sregs->npc = 4;
     sregs->trap = 0;
     sregs->psr &= 0x00f03fdf;
-    sregs->psr |= 0x080;       /* Set supervisor bit */
+    sregs->psr |= 0x11000080;  /* Set supervisor bit */
     sregs->breakpoint = 0;
     sregs->annul = 0;
     sregs->fpstate = FP_EXE_MODE;
@@ -1570,9 +2037,8 @@ init_regs(sregs)
     sregs->ltime = 0;
     sregs->err_mode = 0;
     ext_irl = 0;
-    irqpend = 0;
     sregs->g[0] = 0;
-#ifdef HOST_LITTLE_ENDIAN_FLOAT
+#ifdef HOST_LITTLE_ENDIAN
     sregs->fdp = (float32 *) sregs->fd;
     sregs->fsi = (int32 *) sregs->fs;
 #else
@@ -1586,12 +2052,9 @@ init_regs(sregs)
     sregs->ildreg = 0;
     sregs->ildtime = 0;
 
+    sregs->y = 0;
+    sregs->asr17 = 0;
+
     sregs->rett_err = 0;
     sregs->jmpltime = 0;
 }
-
-chk_fp(sregs)
-    struct pstate  *sregs;
-{
-    return (sregs->fpu_pres);
-}