/*
    NetWinder Floating Point Emulator
    (c) Rebel.COM, 1998,1999
    (c) Philip Blundell, 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, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "fpa11.h"
#include "softfloat.h"
#include "fpopcode.h"
#include "fpa11.inl"
//#include "fpmodule.h"
//#include "fpmodule.inl"

void SetRoundingMode(const unsigned int opcode);

unsigned int PerformFLT(const unsigned int opcode);
unsigned int PerformFIX(const unsigned int opcode);

static unsigned int
PerformComparison(const unsigned int opcode);

unsigned int EmulateCPRT(const unsigned int opcode)
{
  unsigned int nRc = 1;

  //printk("EmulateCPRT(0x%08x)\n",opcode);

  if (opcode & 0x800000)
  {
     /* This is some variant of a comparison (PerformComparison will
	sort out which one).  Since most of the other CPRT
	instructions are oddball cases of some sort or other it makes
	sense to pull this out into a fast path.  */
     return PerformComparison(opcode);
  }

  /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
  switch ((opcode & 0x700000) >> 20)
  {
    case  FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
    case  FIX_CODE >> 20: nRc = PerformFIX(opcode); break;

    case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
    case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;

#if 0    /* We currently have no use for the FPCR, so there's no point
	    in emulating it. */
    case  WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode)));
    case  RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break;
#endif

    default: nRc = 0;
  }

  return nRc;
}

unsigned int PerformFLT(const unsigned int opcode)
{
   FPA11 *fpa11 = GET_FPA11();

   unsigned int nRc = 1;
   SetRoundingMode(opcode);

   switch (opcode & MASK_ROUNDING_PRECISION)
   {
      case ROUND_SINGLE:
      {
        fpa11->fType[getFn(opcode)] = typeSingle;
        fpa11->fpreg[getFn(opcode)].fSingle =
	   int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
      }
      break;

      case ROUND_DOUBLE:
      {
        fpa11->fType[getFn(opcode)] = typeDouble;
        fpa11->fpreg[getFn(opcode)].fDouble =
            int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
      }
      break;

      case ROUND_EXTENDED:
      {
        fpa11->fType[getFn(opcode)] = typeExtended;
        fpa11->fpreg[getFn(opcode)].fExtended =
	   int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
      }
      break;

      default: nRc = 0;
  }

  return nRc;
}

unsigned int PerformFIX(const unsigned int opcode)
{
   FPA11 *fpa11 = GET_FPA11();
   unsigned int nRc = 1;
   unsigned int Fn = getFm(opcode);

   SetRoundingMode(opcode);

   switch (fpa11->fType[Fn])
   {
      case typeSingle:
      {
         writeRegister(getRd(opcode),
	               float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
      }
      break;

      case typeDouble:
      {
         //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
         writeRegister(getRd(opcode),
	               float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
      }
      break;

      case typeExtended:
      {
         writeRegister(getRd(opcode),
	               floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
      }
      break;

      default: nRc = 0;
  }

  return nRc;
}


static unsigned int __inline__
PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
{
   FPA11 *fpa11 = GET_FPA11();
   unsigned int flags = 0;

   /* test for less than condition */
   if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
   {
      flags |= CC_NEGATIVE;
   }

   /* test for equal condition */
   if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
   {
      flags |= CC_ZERO;
   }

   /* test for greater than or equal condition */
   if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
   {
      flags |= CC_CARRY;
   }

   writeConditionCodes(flags);
   return 1;
}

/* This instruction sets the flags N, Z, C, V in the FPSR. */

static unsigned int PerformComparison(const unsigned int opcode)
{
   FPA11 *fpa11 = GET_FPA11();
   unsigned int Fn, Fm;
   floatx80 rFn, rFm;
   int e_flag = opcode & 0x400000;	/* 1 if CxFE */
   int n_flag = opcode & 0x200000;	/* 1 if CNxx */
   unsigned int flags = 0;

   //printk("PerformComparison(0x%08x)\n",opcode);

   Fn = getFn(opcode);
   Fm = getFm(opcode);

   /* Check for unordered condition and convert all operands to 80-bit
      format.
      ?? Might be some mileage in avoiding this conversion if possible.
      Eg, if both operands are 32-bit, detect this and do a 32-bit
      comparison (cheaper than an 80-bit one).  */
   switch (fpa11->fType[Fn])
   {
      case typeSingle:
        //printk("single.\n");
	if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
	   goto unordered;
        rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
      break;

      case typeDouble:
        //printk("double.\n");
	if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
	   goto unordered;
        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
      break;

      case typeExtended:
        //printk("extended.\n");
	if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
	   goto unordered;
        rFn = fpa11->fpreg[Fn].fExtended;
      break;

      default: return 0;
   }

   if (CONSTANT_FM(opcode))
   {
     //printk("Fm is a constant: #%d.\n",Fm);
     rFm = getExtendedConstant(Fm);
     if (floatx80_is_nan(rFm))
        goto unordered;
   }
   else
   {
     //printk("Fm = r%d which contains a ",Fm);
      switch (fpa11->fType[Fm])
      {
         case typeSingle:
           //printk("single.\n");
	   if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
	      goto unordered;
           rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
         break;

         case typeDouble:
           //printk("double.\n");
	   if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
	      goto unordered;
           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
         break;

         case typeExtended:
           //printk("extended.\n");
	   if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
	      goto unordered;
           rFm = fpa11->fpreg[Fm].fExtended;
         break;

         default: return 0;
      }
   }

   if (n_flag)
   {
      rFm.high ^= 0x8000;
   }

   return PerformComparisonOperation(rFn,rFm);

 unordered:
   /* ?? The FPA data sheet is pretty vague about this, in particular
      about whether the non-E comparisons can ever raise exceptions.
      This implementation is based on a combination of what it says in
      the data sheet, observation of how the Acorn emulator actually
      behaves (and how programs expect it to) and guesswork.  */
   flags |= CC_OVERFLOW;
   flags &= ~(CC_ZERO | CC_NEGATIVE);

   if (BIT_AC & readFPSR()) flags |= CC_CARRY;

   if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);

   writeConditionCodes(flags);
   return 1;
}
