Add qemu 2.4.0
[kvmfornfv.git] / qemu / linux-user / arm / nwfpe / fpa11.c
diff --git a/qemu/linux-user/arm/nwfpe/fpa11.c b/qemu/linux-user/arm/nwfpe/fpa11.c
new file mode 100644 (file)
index 0000000..eebd93f
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Rebel.COM, 1998,1999
+
+    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
+
+    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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fpa11.h"
+
+#include "fpopcode.h"
+
+//#include "fpmodule.h"
+//#include "fpmodule.inl"
+
+//#include <asm/system.h>
+
+#include <stdio.h>
+
+FPA11* qemufpa = NULL;
+CPUARMState* user_registers;
+
+/* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
+void resetFPA11(void)
+{
+  int i;
+  FPA11 *fpa11 = GET_FPA11();
+
+  /* initialize the register type array */
+  for (i=0;i<=7;i++)
+  {
+    fpa11->fType[i] = typeNone;
+  }
+
+  /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
+  fpa11->fpsr = FP_EMULATOR | BIT_AC;
+
+  /* FPCR: set SB, AB and DA bits, clear all others */
+#ifdef MAINTAIN_FPCR
+  fpa11->fpcr = MASK_RESET;
+#endif
+}
+
+void SetRoundingMode(const unsigned int opcode)
+{
+    int rounding_mode;
+   FPA11 *fpa11 = GET_FPA11();
+
+#ifdef MAINTAIN_FPCR
+   fpa11->fpcr &= ~MASK_ROUNDING_MODE;
+#endif
+   switch (opcode & MASK_ROUNDING_MODE)
+   {
+      default:
+      case ROUND_TO_NEAREST:
+         rounding_mode = float_round_nearest_even;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_TO_NEAREST;
+#endif
+      break;
+
+      case ROUND_TO_PLUS_INFINITY:
+         rounding_mode = float_round_up;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
+#endif
+      break;
+
+      case ROUND_TO_MINUS_INFINITY:
+         rounding_mode = float_round_down;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
+#endif
+      break;
+
+      case ROUND_TO_ZERO:
+         rounding_mode = float_round_to_zero;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_TO_ZERO;
+#endif
+      break;
+  }
+   set_float_rounding_mode(rounding_mode, &fpa11->fp_status);
+}
+
+void SetRoundingPrecision(const unsigned int opcode)
+{
+    int rounding_precision;
+   FPA11 *fpa11 = GET_FPA11();
+#ifdef MAINTAIN_FPCR
+   fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
+#endif
+   switch (opcode & MASK_ROUNDING_PRECISION)
+   {
+      case ROUND_SINGLE:
+         rounding_precision = 32;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_SINGLE;
+#endif
+      break;
+
+      case ROUND_DOUBLE:
+         rounding_precision = 64;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_DOUBLE;
+#endif
+      break;
+
+      case ROUND_EXTENDED:
+         rounding_precision = 80;
+#ifdef MAINTAIN_FPCR
+         fpa11->fpcr |= ROUND_EXTENDED;
+#endif
+      break;
+
+      default: rounding_precision = 80;
+  }
+   set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status);
+}
+
+/* Emulate the instruction in the opcode. */
+/* ??? This is not thread safe.  */
+unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs)
+{
+  unsigned int nRc = 0;
+//  unsigned long flags;
+  FPA11 *fpa11;
+//  save_flags(flags); sti();
+
+  qemufpa=qfpa;
+  user_registers=qregs;
+
+#if 0
+  fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n",
+          opcode, qregs[ARM_REG_PC]);
+#endif
+  fpa11 = GET_FPA11();
+
+  if (fpa11->initflag == 0)            /* good place for __builtin_expect */
+  {
+    resetFPA11();
+    SetRoundingMode(ROUND_TO_NEAREST);
+    SetRoundingPrecision(ROUND_EXTENDED);
+    fpa11->initflag = 1;
+  }
+
+  set_float_exception_flags(0, &fpa11->fp_status);
+
+  if (TEST_OPCODE(opcode,MASK_CPRT))
+  {
+    //fprintf(stderr,"emulating CPRT\n");
+    /* Emulate conversion opcodes. */
+    /* Emulate register transfer opcodes. */
+    /* Emulate comparison opcodes. */
+    nRc = EmulateCPRT(opcode);
+  }
+  else if (TEST_OPCODE(opcode,MASK_CPDO))
+  {
+    //fprintf(stderr,"emulating CPDO\n");
+    /* Emulate monadic arithmetic opcodes. */
+    /* Emulate dyadic arithmetic opcodes. */
+    nRc = EmulateCPDO(opcode);
+  }
+  else if (TEST_OPCODE(opcode,MASK_CPDT))
+  {
+    //fprintf(stderr,"emulating CPDT\n");
+    /* Emulate load/store opcodes. */
+    /* Emulate load/store multiple opcodes. */
+    nRc = EmulateCPDT(opcode);
+  }
+  else
+  {
+    /* Invalid instruction detected.  Return FALSE. */
+    nRc = 0;
+  }
+
+//  restore_flags(flags);
+  if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status))
+  {
+    //printf("fef 0x%x\n",float_exception_flags);
+    nRc = -get_float_exception_flags(&fpa11->fp_status);
+  }
+
+  //printf("returning %d\n",nRc);
+  return(nRc);
+}
+
+#if 0
+unsigned int EmulateAll1(unsigned int opcode)
+{
+  switch ((opcode >> 24) & 0xf)
+  {
+     case 0xc:
+     case 0xd:
+       if ((opcode >> 20) & 0x1)
+       {
+          switch ((opcode >> 8) & 0xf)
+          {
+             case 0x1: return PerformLDF(opcode); break;
+             case 0x2: return PerformLFM(opcode); break;
+             default: return 0;
+          }
+       }
+       else
+       {
+          switch ((opcode >> 8) & 0xf)
+          {
+             case 0x1: return PerformSTF(opcode); break;
+             case 0x2: return PerformSFM(opcode); break;
+             default: return 0;
+          }
+      }
+     break;
+
+     case 0xe:
+       if (opcode & 0x10)
+         return EmulateCPDO(opcode);
+       else
+         return EmulateCPRT(opcode);
+     break;
+
+     default: return 0;
+  }
+}
+#endif