Ejemplo n.º 1
0
static inline
void storeMultiple(const unsigned int Fn, target_ulong addr)
{
   FPA11 *fpa11 = GET_FPA11();
   register unsigned int nType, *p;

   p = (unsigned int*)&(fpa11->fpreg[Fn]);
   nType = fpa11->fType[Fn];

   switch (nType)
   {
      case typeSingle:
      case typeDouble:
      {
         put_user_u32(p[0], addr + 8); /* single */
	 put_user_u32(p[1], addr + 4); /* double msw */
	 put_user_u32(nType << 14, addr);
      }
      break;

      case typeExtended:
      {
         put_user_u32(p[2], addr + 4); /* msw */
	 put_user_u32(p[1], addr + 8);
	 put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr);
      }
      break;
   }
}
Ejemplo n.º 2
0
static inline
void storeExtended(const unsigned int Fn, target_ulong addr)
{
   FPA11 *fpa11 = GET_FPA11();
   floatx80 val;
   register unsigned int *p = (unsigned int*)&val;

   switch (fpa11->fType[Fn])
   {
      case typeSingle:
         val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
      break;

      case typeDouble:
         val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
      break;

      default: val = fpa11->fpreg[Fn].fExtended;
   }

   /* FIXME - handle put_user() failures */
   put_user_u32(p[0], addr); /* sign & exp */
   put_user_u32(p[1], addr + 8);
   put_user_u32(p[2], addr + 4); /* msw */
}
Ejemplo n.º 3
0
static inline
void loadSingle(const unsigned int Fn,const unsigned int *pMem)
{
   FPA11 *fpa11 = GET_FPA11();
   fpa11->fType[Fn] = typeSingle;
   get_user(fpa11->fpreg[Fn].fSingle, pMem);
}
Ejemplo n.º 4
0
static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem)
{
	FPA11 *fpa11 = GET_FPA11();
	register unsigned int nType, *p;

	p = (unsigned int *) &(fpa11->fpreg[Fn]);
	nType = fpa11->fType[Fn];

	switch (nType) {
	case typeSingle:
	case typeDouble:
		{
			put_user(p[0], &pMem[2]);	/* single */
			put_user(p[1], &pMem[1]);	/* double msw */
			put_user(nType << 14, &pMem[0]);
		}
		break;

#ifdef CONFIG_FPE_NWFPE_XP
	case typeExtended:
		{
			put_user(p[2], &pMem[1]);	/* msw */
			put_user(p[1], &pMem[2]);
			put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
		}
		break;
#endif
	}
}
Ejemplo n.º 5
0
static inline
void storeSingle(const unsigned int Fn,unsigned int *pMem)
{
   FPA11 *fpa11 = GET_FPA11();
   union
   {
     float32 f;
     unsigned int i[1];
   } val;

   switch (fpa11->fType[Fn])
   {
      case typeDouble:
         val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble);
      break;

      case typeExtended:
         val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
      break;

      default: val.f = fpa11->fpreg[Fn].fSingle;
   }

   put_user(val.i[0], pMem);
}
Ejemplo n.º 6
0
static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem)
{
	FPA11 *fpa11 = GET_FPA11();
	union {
		floatx80 f;
		unsigned int i[3];
	} val;

	switch (fpa11->fType[Fn]) {
	case typeSingle:
		val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
		break;

	case typeDouble:
		val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
		break;

	default:
		val.f = fpa11->fpreg[Fn].fExtended;
	}

	put_user(val.i[0], &pMem[0]);	/* sign & exp */
#ifdef __ARMEB__
	put_user(val.i[1], &pMem[1]);	/* msw */
	put_user(val.i[2], &pMem[2]);
#else
	put_user(val.i[1], &pMem[2]);
	put_user(val.i[2], &pMem[1]);	/* msw */
#endif
}
Ejemplo n.º 7
0
static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
{
	FPA11 *fpa11 = GET_FPA11();
	union {
		float64 f;
		unsigned int i[2];
	} val;

	switch (fpa11->fType[Fn]) {
	case typeSingle:
		val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
		break;

#ifdef CONFIG_FPE_NWFPE_XP
	case typeExtended:
		val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);
		break;
#endif

	default:
		val.f = fpa11->fpreg[Fn].fDouble;
	}

#ifdef __ARMEB__
	put_user(val.i[0], &pMem[0]);	/* msw */
	put_user(val.i[1], &pMem[1]);	/* lsw */
#else
	put_user(val.i[1], &pMem[0]);	/* msw */
	put_user(val.i[0], &pMem[1]);	/* lsw */
#endif
}
Ejemplo n.º 8
0
unsigned int PerformFIX(const unsigned int opcode)
{
    FPA11 *fpa11 = GET_FPA11();
    unsigned int Fn = getFm(opcode);

    SetRoundingMode(opcode);

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

    case typeDouble:
    {
        writeRegister(getRd(opcode), float64_to_int32(fpa11->fpreg[Fn].fDouble));
    }
    break;

#ifdef CONFIG_FPE_NWFPE_XP
    case typeExtended:
    {
        writeRegister(getRd(opcode), floatx80_to_int32(fpa11->fpreg[Fn].fExtended));
    }
    break;
#endif

    default:
        return 0;
    }

    return 1;
}
Ejemplo n.º 9
0
static inline
void loadMultiple(const unsigned int Fn, target_ulong addr)
{
   FPA11 *fpa11 = GET_FPA11();
   register unsigned int *p;
   unsigned long x;

   p = (unsigned int*)&(fpa11->fpreg[Fn]);
   /* FIXME - handle failure of get_user() */
   get_user_u32(&x, addr);
   fpa11->fType[Fn] = (x >> 14) & 0x00000003;

   switch (fpa11->fType[Fn])
   {
      case typeSingle:
      case typeDouble:
      {
         /* FIXME - handle failure of get_user() */
         get_user_u32(&p[0], addr + 8);  /* Single */
         get_user_u32(&p[1], addr + 4);  /* double msw */
         p[2] = 0;        /* empty */
      }
      break;

      case typeExtended:
      {
         /* FIXME - handle failure of get_user() */
         get_user_u32(&p[1], addr + 8);
         get_user_u32(&p[2], addr + 4);  /* msw */
         p[0] = (x & 0x80003fff);
      }
      break;
   }
}
Ejemplo n.º 10
0
static inline
void storeDouble(const unsigned int Fn, target_ulong addr)
{
   FPA11 *fpa11 = GET_FPA11();
   float64 val;
   register unsigned int *p = (unsigned int*)&val;

   switch (fpa11->fType[Fn])
   {
      case typeSingle:
         val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
      break;

      case typeExtended:
         val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
      break;

      default: val = fpa11->fpreg[Fn].fDouble;
   }
   /* FIXME - handle put_user() failures */
#ifdef HOST_WORDS_BIGENDIAN
   put_user_u32(p[0], addr);	/* msw */
   put_user_u32(p[1], addr + 4);	/* lsw */
#else
   put_user_u32(p[1], addr);	/* msw */
   put_user_u32(p[0], addr + 4);	/* lsw */
#endif
}
Ejemplo n.º 11
0
static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
{
	FPA11 *fpa11 = GET_FPA11();
	register unsigned int *p;
	unsigned long x;

	p = (unsigned int *) &(fpa11->fpreg[Fn]);
	get_user(x, &pMem[0]);
	fpa11->fType[Fn] = (x >> 14) & 0x00000003;

	switch (fpa11->fType[Fn]) {
	case typeSingle:
	case typeDouble:
		{
			get_user(p[0], &pMem[2]);	/* Single */
			get_user(p[1], &pMem[1]);	/* double msw */
			p[2] = 0;			/* empty */
		}
		break;

#ifdef CONFIG_FPE_NWFPE_XP
	case typeExtended:
		{
			get_user(p[1], &pMem[2]);
			get_user(p[2], &pMem[1]);	/* msw */
			p[0] = (x & 0x80003fff);
		}
		break;
#endif
	}
}
Ejemplo n.º 12
0
static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
{
	FPA11 *fpa11 = GET_FPA11();
	union {
		float32 f;
		unsigned int i[1];
	} val;

	switch (fpa11->fType[Fn]) {
	case typeDouble:
		val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);
		break;

#ifdef CONFIG_FPE_NWFPE_XP
	case typeExtended:
		val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);
		break;
#endif

	default:
		val.f = fpa11->fpreg[Fn].fSingle;
	}

	put_user(val.i[0], pMem);
}
Ejemplo n.º 13
0
static inline
void loadSingle(const unsigned int Fn, target_ulong addr)
{
   FPA11 *fpa11 = GET_FPA11();
   fpa11->fType[Fn] = typeSingle;
   /* FIXME - handle failure of get_user() */
   get_user_u32(&float32_val(fpa11->fpreg[Fn].fSingle), addr);
}
Ejemplo n.º 14
0
unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd)
{
	FPA11 *fpa11 = GET_FPA11();
	float64 rFm;
	unsigned int Fm, opc_mask_shift;

	Fm = getFm(opcode);
	if (CONSTANT_FM(opcode)) {
		rFm = getDoubleConstant(Fm);
	} else {
		switch (fpa11->fType[Fm]) {
		case typeSingle:
			rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
			break;

		case typeDouble:
			rFm = fpa11->fpreg[Fm].fDouble;
			break;

		default:
			return 0;
		}
	}

	opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
	if (!MONADIC_INSTRUCTION(opcode)) {
		unsigned int Fn = getFn(opcode);
		float64 rFn;

		switch (fpa11->fType[Fn]) {
		case typeSingle:
			rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
			break;

		case typeDouble:
			rFn = fpa11->fpreg[Fn].fDouble;
			break;

		default:
			return 0;
		}

		if (dyadic_double[opc_mask_shift]) {
			rFd->fDouble = dyadic_double[opc_mask_shift](rFn, rFm);
		} else {
			return 0;
		}
	} else {
		if (monadic_double[opc_mask_shift]) {
			rFd->fDouble = monadic_double[opc_mask_shift](rFm);
		} else {
			return 0;
		}
	}

	return 1;
}
Ejemplo n.º 15
0
static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem)
{
	FPA11 *fpa11 = GET_FPA11();
	unsigned int *p;
	p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
	fpa11->fType[Fn] = typeDouble;
	get_user(p[0], &pMem[1]);
	get_user(p[1], &pMem[0]);	/* sign & exponent */
}
Ejemplo n.º 16
0
static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem)
{
	FPA11 *fpa11 = GET_FPA11();
	unsigned int *p;
	p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
	fpa11->fType[Fn] = typeExtended;
	get_user(p[0], &pMem[0]);	/* sign & exponent */
	get_user(p[1], &pMem[2]);	/* ls bits */
	get_user(p[2], &pMem[1]);	/* ms bits */
}
Ejemplo n.º 17
0
static inline
void loadExtended(const unsigned int Fn, target_ulong addr)
{
   FPA11 *fpa11 = GET_FPA11();
   unsigned int *p;
   p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
   fpa11->fType[Fn] = typeExtended;
   /* FIXME - handle failure of get_user() */
   get_user_u32(&p[0], addr);  /* sign & exponent */
   get_user_u32(&p[1], addr + 8);  /* ls bits */
   get_user_u32(&p[2], addr + 4);  /* ms bits */
}
Ejemplo n.º 18
0
static void resetFPA11(void)
{
	int i;
	FPA11 *fpa11 = GET_FPA11();

	/*                                    */
	for (i = 0; i <= 7; i++) {
		fpa11->fType[i] = typeNone;
	}

	/*                                                                  */
	fpa11->fpsr = FP_EMULATOR | BIT_AC;
}
Ejemplo n.º 19
0
/* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
static 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;
}
Ejemplo n.º 20
0
static inline
void loadDouble(const unsigned int Fn, target_ulong addr)
{
   FPA11 *fpa11 = GET_FPA11();
   unsigned int *p;
   p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
   fpa11->fType[Fn] = typeDouble;
#ifdef HOST_WORDS_BIGENDIAN
   /* FIXME - handle failure of get_user() */
   get_user_u32(&p[0], addr); /* sign & exponent */
   get_user_u32(&p[1], addr + 4);
#else
   /* FIXME - handle failure of get_user() */
   get_user_u32(&p[0], addr + 4);
   get_user_u32(&p[1], addr); /* sign & exponent */
#endif
}
Ejemplo n.º 21
0
unsigned int PerformFLT(const unsigned int opcode)
{
    FPA11 *fpa11 = GET_FPA11();
    struct roundingData roundData;

    roundData.mode = SetRoundingMode(opcode);
    roundData.precision = SetRoundingPrecision(opcode);
    roundData.exception = 0;

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

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

#ifdef CONFIG_FPE_NWFPE_XP
    case ROUND_EXTENDED:
        {
            fpa11->fType[getFn(opcode)] = typeExtended;
            fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
        }
        break;
#endif

    default:
        return 0;
    }

    if (roundData.exception)
        float_raise(roundData.exception);

    return 1;
}
Ejemplo n.º 22
0
unsigned int PerformFIX(const unsigned int opcode)
{
    FPA11 *fpa11 = GET_FPA11();
    unsigned int Fn = getFm(opcode);
    struct roundingData roundData;

    roundData.mode = SetRoundingMode(opcode);
    roundData.precision = SetRoundingPrecision(opcode);
    roundData.exception = 0;

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

    case typeDouble:
        {
            writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
        }
        break;

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

    default:
        return 0;
    }

    if (roundData.exception)
        float_raise(roundData.exception);

    return 1;
}
Ejemplo n.º 23
0
static inline
void storeSingle(const unsigned int Fn,unsigned int *pMem)
{
   FPA11 *fpa11 = GET_FPA11();
   float32 val;
   register unsigned int *p = (unsigned int*)&val;
   
   switch (fpa11->fType[Fn])
   {
      case typeDouble: 
         val = float64_to_float32(fpa11->fpreg[Fn].fDouble);
      break;

      case typeExtended: 
         val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
      break;

      default: val = fpa11->fpreg[Fn].fSingle;
   }
  
   put_user(p[0], pMem);
}   
Ejemplo n.º 24
0
unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd)
{
    FPA11 *fpa11 = GET_FPA11();
    float32 rFm;
    unsigned int Fm, opc_mask_shift;

    Fm = getFm(opcode);
    if (CONSTANT_FM(opcode)) {
        rFm = getSingleConstant(Fm);
    } else if (fpa11->fType[Fm] == typeSingle) {
        rFm = fpa11->fpreg[Fm].fSingle;
    } else {
        return 0;
    }

    opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
    if (!MONADIC_INSTRUCTION(opcode)) {
        unsigned int Fn = getFn(opcode);
        float32 rFn;

        if (fpa11->fType[Fn] == typeSingle &&
            dyadic_single[opc_mask_shift]) {
            rFn = fpa11->fpreg[Fn].fSingle;
            rFd->fSingle = dyadic_single[opc_mask_shift](roundData, rFn, rFm);
        } else {
            return 0;
        }
    } else {
        if (monadic_single[opc_mask_shift]) {
            rFd->fSingle = monadic_single[opc_mask_shift](roundData, rFm);
        } else {
            return 0;
        }
    }

    return 1;
}
Ejemplo n.º 25
0
static inline
void storeExtended(const unsigned int Fn,unsigned int *pMem)
{
   FPA11 *fpa11 = GET_FPA11();
   floatx80 val;
   register unsigned int *p = (unsigned int*)&val;
   
   switch (fpa11->fType[Fn])
   {
      case typeSingle: 
         val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
      break;

      case typeDouble: 
         val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
      break;

      default: val = fpa11->fpreg[Fn].fExtended;
   }
   
   put_user(p[0], &pMem[0]); /* sign & exp */
   put_user(p[1], &pMem[2]);
   put_user(p[2], &pMem[1]); /* msw */
}   
Ejemplo n.º 26
0
unsigned int EmulateCPDO(const unsigned int opcode)
{
   FPA11 *fpa11 = GET_FPA11();
   unsigned int Fd, nType, nDest, nRc = 1;

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

   /* Get the destination size.  If not valid let Linux perform
      an invalid instruction trap. */
   nDest = getDestinationSize(opcode);
   if (typeNone == nDest) return 0;

   SetRoundingMode(opcode);

   /* Compare the size of the operands in Fn and Fm.
      Choose the largest size and perform operations in that size,
      in order to make use of all the precision of the operands.
      If Fm is a constant, we just grab a constant of a size
      matching the size of the operand in Fn. */
   if (MONADIC_INSTRUCTION(opcode))
     nType = nDest;
   else
     nType = fpa11->fType[getFn(opcode)];

   if (!CONSTANT_FM(opcode))
   {
     register unsigned int Fm = getFm(opcode);
     if (nType < fpa11->fType[Fm])
     {
        nType = fpa11->fType[Fm];
     }
   }

   switch (nType)
   {
      case typeSingle   : nRc = SingleCPDO(opcode);   break;
      case typeDouble   : nRc = DoubleCPDO(opcode);   break;
      case typeExtended : nRc = ExtendedCPDO(opcode); break;
      default           : nRc = 0;
   }

   /* If the operation succeeded, check to see if the result in the
      destination register is the correct size.  If not force it
      to be. */
   Fd = getFd(opcode);
   nType = fpa11->fType[Fd];
   if ((0 != nRc) && (nDest != nType))
   {
     switch (nDest)
     {
       case typeSingle:
       {
         if (typeDouble == nType)
           fpa11->fpreg[Fd].fSingle =
              float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
         else
           fpa11->fpreg[Fd].fSingle =
              floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
       }
       break;

       case typeDouble:
       {
         if (typeSingle == nType)
           fpa11->fpreg[Fd].fDouble =
              float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
         else
           fpa11->fpreg[Fd].fDouble =
              floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
       }
       break;

       case typeExtended:
       {
         if (typeSingle == nType)
           fpa11->fpreg[Fd].fExtended =
              float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
         else
           fpa11->fpreg[Fd].fExtended =
              float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
       }
       break;
     }

     fpa11->fType[Fd] = nDest;
   }

   return nRc;
}
Ejemplo n.º 27
0
unsigned int ExtendedCPDO(const unsigned int opcode)
{
   FPA11 *fpa11 = GET_FPA11();
   floatx80 rFm, rFn;
   unsigned int Fd, Fm, Fn, nRc = 1;

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

   Fm = getFm(opcode);
   if (CONSTANT_FM(opcode))
   {
     rFm = getExtendedConstant(Fm);
   }
   else
   {
     switch (fpa11->fType[Fm])
     {
        case typeSingle:
          rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
        break;

        case typeDouble:
          rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
        break;

        case typeExtended:
          rFm = fpa11->fpreg[Fm].fExtended;
        break;

        default: return 0;
     }
   }

   if (!MONADIC_INSTRUCTION(opcode))
   {
      Fn = getFn(opcode);
      switch (fpa11->fType[Fn])
      {
        case typeSingle:
          rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
        break;

        case typeDouble:
          rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
        break;

        case typeExtended:
          rFn = fpa11->fpreg[Fn].fExtended;
        break;

        default: return 0;
      }
   }

   Fd = getFd(opcode);
   switch (opcode & MASK_ARITHMETIC_OPCODE)
   {
      /* dyadic opcodes */
      case ADF_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm, &fpa11->fp_status);
      break;

      case MUF_CODE:
      case FML_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm, &fpa11->fp_status);
      break;

      case SUF_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm, &fpa11->fp_status);
      break;

      case RSF_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn, &fpa11->fp_status);
      break;

      case DVF_CODE:
      case FDV_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm, &fpa11->fp_status);
      break;

      case RDF_CODE:
      case FRD_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn, &fpa11->fp_status);
      break;

#if 0
      case POW_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm);
      break;

      case RPW_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn);
      break;
#endif

      case RMF_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm, &fpa11->fp_status);
      break;

#if 0
      case POL_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm);
      break;
#endif

      /* monadic opcodes */
      case MVF_CODE:
         fpa11->fpreg[Fd].fExtended = rFm;
      break;

      case MNF_CODE:
         rFm.high ^= 0x8000;
         fpa11->fpreg[Fd].fExtended = rFm;
      break;

      case ABS_CODE:
         rFm.high &= 0x7fff;
         fpa11->fpreg[Fd].fExtended = rFm;
      break;

      case RND_CODE:
      case URD_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm, &fpa11->fp_status);
      break;

      case SQT_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm, &fpa11->fp_status);
      break;

#if 0
      case LOG_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_log(rFm);
      break;

      case LGN_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm);
      break;

      case EXP_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm);
      break;

      case SIN_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm);
      break;

      case COS_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm);
      break;

      case TAN_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm);
      break;

      case ASN_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm);
      break;

      case ACS_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm);
      break;

      case ATN_CODE:
         fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm);
      break;
#endif

      case NRM_CODE:
      break;

      default:
      {
        nRc = 0;
      }
   }

   if (0 != nRc) fpa11->fType[Fd] = typeExtended;
   return nRc;
}
Ejemplo n.º 28
0
/* 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 = getFn(opcode), Fm = getFm(opcode);
    int e_flag = opcode & 0x400000;    /* 1 if CxFE */
    int n_flag = opcode & 0x200000;    /* 1 if CNxx */
    unsigned int flags = 0;

#ifdef CONFIG_FPE_NWFPE_XP
    floatx80 rFn, rFm;

    /* 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);
        break;

    case typeDouble:
        //printk("double.\n");
        if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
            goto unordered;
        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
        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);
            break;

        case typeDouble:
            //printk("double.\n");
            if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
                goto unordered;
            rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
            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;

    /* test for less than condition */
    if (floatx80_lt(rFn, rFm))
        flags |= CC_NEGATIVE;

    /* test for equal condition */
    if (floatx80_eq(rFn, rFm))
        flags |= CC_ZERO;

    /* test for greater than or equal condition */
    if (floatx80_lt(rFm, rFn))
        flags |= CC_CARRY;

#else
    if (CONSTANT_FM(opcode)) {
        /* Fm is a constant.  Do the comparison in whatever precision
           Fn happens to be stored in.  */
        if (fpa11->fType[Fn] == typeSingle) {
            float32 rFm = getSingleConstant(Fm);
            float32 rFn = fpa11->fpreg[Fn].fSingle;

            if (float32_is_nan(rFn))
                goto unordered;

            if (n_flag)
                rFm ^= 0x80000000;

            /* test for less than condition */
            if (float32_lt_nocheck(rFn, rFm))
                flags |= CC_NEGATIVE;

            /* test for equal condition */
            if (float32_eq_nocheck(rFn, rFm))
                flags |= CC_ZERO;

            /* test for greater than or equal condition */
            if (float32_lt_nocheck(rFm, rFn))
                flags |= CC_CARRY;
        } else {
            float64 rFm = getDoubleConstant(Fm);
            float64 rFn = fpa11->fpreg[Fn].fDouble;

            if (float64_is_nan(rFn))
                goto unordered;

            if (n_flag)
                rFm ^= 0x8000000000000000ULL;

            /* test for less than condition */
            if (float64_lt_nocheck(rFn, rFm))
                flags |= CC_NEGATIVE;

            /* test for equal condition */
            if (float64_eq_nocheck(rFn, rFm))
                flags |= CC_ZERO;

            /* test for greater than or equal condition */
            if (float64_lt_nocheck(rFm, rFn))
                flags |= CC_CARRY;
        }
    } else {
        /* Both operands are in registers.  */
        if (fpa11->fType[Fn] == typeSingle
            && fpa11->fType[Fm] == typeSingle) {
            float32 rFm = fpa11->fpreg[Fm].fSingle;
            float32 rFn = fpa11->fpreg[Fn].fSingle;

            if (float32_is_nan(rFn)
                || float32_is_nan(rFm))
                goto unordered;

            if (n_flag)
                rFm ^= 0x80000000;

            /* test for less than condition */
            if (float32_lt_nocheck(rFn, rFm))
                flags |= CC_NEGATIVE;

            /* test for equal condition */
            if (float32_eq_nocheck(rFn, rFm))
                flags |= CC_ZERO;

            /* test for greater than or equal condition */
            if (float32_lt_nocheck(rFm, rFn))
                flags |= CC_CARRY;
        } else {
            /* Promote 32-bit operand to 64 bits.  */
            float64 rFm, rFn;

            rFm = (fpa11->fType[Fm] == typeSingle) ?
                float32_to_float64(fpa11->fpreg[Fm].fSingle)
                : fpa11->fpreg[Fm].fDouble;

            rFn = (fpa11->fType[Fn] == typeSingle) ?
                float32_to_float64(fpa11->fpreg[Fn].fSingle)
                : fpa11->fpreg[Fn].fDouble;

            if (float64_is_nan(rFn)
                || float64_is_nan(rFm))
                goto unordered;

            if (n_flag)
                rFm ^= 0x8000000000000000ULL;

            /* test for less than condition */
            if (float64_lt_nocheck(rFn, rFm))
                flags |= CC_NEGATIVE;

            /* test for equal condition */
            if (float64_eq_nocheck(rFn, rFm))
                flags |= CC_ZERO;

            /* test for greater than or equal condition */
            if (float64_lt_nocheck(rFm, rFn))
                flags |= CC_CARRY;
        }
    }

#endif

    writeConditionCodes(flags);

    return 1;

      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);

    writeConditionCodes(flags);
    return 1;
}
Ejemplo n.º 29
0
unsigned int EmulateCPDO(const unsigned int opcode)
{
    FPA11 *fpa11 = GET_FPA11();
    FPREG *rFd;
    unsigned int nType, nDest, nRc;
    struct roundingData roundData;

    /* Get the destination size.  If not valid let Linux perform
       an invalid instruction trap. */
    nDest = getDestinationSize(opcode);
    if (typeNone == nDest)
        return 0;

    roundData.mode = SetRoundingMode(opcode);
    roundData.precision = SetRoundingPrecision(opcode);
    roundData.exception = 0;

    /* Compare the size of the operands in Fn and Fm.
       Choose the largest size and perform operations in that size,
       in order to make use of all the precision of the operands.
       If Fm is a constant, we just grab a constant of a size
       matching the size of the operand in Fn. */
    if (MONADIC_INSTRUCTION(opcode))
        nType = nDest;
    else
        nType = fpa11->fType[getFn(opcode)];

    if (!CONSTANT_FM(opcode)) {
        register unsigned int Fm = getFm(opcode);
        if (nType < fpa11->fType[Fm]) {
            nType = fpa11->fType[Fm];
        }
    }

    rFd = &fpa11->fpreg[getFd(opcode)];

    switch (nType) {
    case typeSingle:
        nRc = SingleCPDO(&roundData, opcode, rFd);
        break;
    case typeDouble:
        nRc = DoubleCPDO(&roundData, opcode, rFd);
        break;
#ifdef CONFIG_FPE_NWFPE_XP
    case typeExtended:
        nRc = ExtendedCPDO(&roundData, opcode, rFd);
        break;
#endif
    default:
        nRc = 0;
    }

    /* The CPDO functions used to always set the destination type
       to be the same as their working size. */

    if (nRc != 0) {
        /* If the operation succeeded, check to see if the result in the
           destination register is the correct size.  If not force it
           to be. */

        fpa11->fType[getFd(opcode)] = nDest;

#ifdef CONFIG_FPE_NWFPE_XP
        if (nDest != nType) {
            switch (nDest) {
            case typeSingle:
                {
                    if (typeDouble == nType)
                        rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
                    else
                        rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
                }
                break;

            case typeDouble:
                {
                    if (typeSingle == nType)
                        rFd->fDouble = float32_to_float64(rFd->fSingle);
                    else
                        rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
                }
                break;

            case typeExtended:
                {
                    if (typeSingle == nType)
                        rFd->fExtended = float32_to_floatx80(rFd->fSingle);
                    else
                        rFd->fExtended = float64_to_floatx80(rFd->fDouble);
                }
                break;
            }
        }
#else
        if (nDest != nType) {
            if (nDest == typeSingle)
                rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
            else
                rFd->fDouble = float32_to_float64(rFd->fSingle);
        }
#endif
    }

    if (roundData.exception)
        float_raise(roundData.exception);

    return nRc;
}
Ejemplo n.º 30
0
unsigned int SingleCPDO(const unsigned int opcode)
{
   FPA11 *fpa11 = GET_FPA11();
   float32 rFm, rFn = float32_zero;
   unsigned int Fd, Fm, Fn, nRc = 1;

   Fm = getFm(opcode);
   if (CONSTANT_FM(opcode))
   {
     rFm = getSingleConstant(Fm);
   }
   else
   {
     switch (fpa11->fType[Fm])
     {
        case typeSingle:
          rFm = fpa11->fpreg[Fm].fSingle;
        break;

        default: return 0;
     }
   }

   if (!MONADIC_INSTRUCTION(opcode))
   {
      Fn = getFn(opcode);
      switch (fpa11->fType[Fn])
      {
        case typeSingle:
          rFn = fpa11->fpreg[Fn].fSingle;
        break;

        default: return 0;
      }
   }

   Fd = getFd(opcode);
   switch (opcode & MASK_ARITHMETIC_OPCODE)
   {
      /* dyadic opcodes */
      case ADF_CODE:
         fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm, &fpa11->fp_status);
      break;

      case MUF_CODE:
      case FML_CODE:
        fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm, &fpa11->fp_status);
      break;

      case SUF_CODE:
         fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm, &fpa11->fp_status);
      break;

      case RSF_CODE:
         fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn, &fpa11->fp_status);
      break;

      case DVF_CODE:
      case FDV_CODE:
         fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm, &fpa11->fp_status);
      break;

      case RDF_CODE:
      case FRD_CODE:
         fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn, &fpa11->fp_status);
      break;

#if 0
      case POW_CODE:
         fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm);
      break;

      case RPW_CODE:
         fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn);
      break;
#endif

      case RMF_CODE:
         fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm, &fpa11->fp_status);
      break;

#if 0
      case POL_CODE:
         fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm);
      break;
#endif

      /* monadic opcodes */
      case MVF_CODE:
         fpa11->fpreg[Fd].fSingle = rFm;
      break;

      case MNF_CODE:
         fpa11->fpreg[Fd].fSingle = float32_chs(rFm);
      break;

      case ABS_CODE:
         fpa11->fpreg[Fd].fSingle = float32_abs(rFm);
      break;

      case RND_CODE:
      case URD_CODE:
         fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm, &fpa11->fp_status);
      break;

      case SQT_CODE:
         fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm, &fpa11->fp_status);
      break;

#if 0
      case LOG_CODE:
         fpa11->fpreg[Fd].fSingle = float32_log(rFm);
      break;

      case LGN_CODE:
         fpa11->fpreg[Fd].fSingle = float32_ln(rFm);
      break;

      case EXP_CODE:
         fpa11->fpreg[Fd].fSingle = float32_exp(rFm);
      break;

      case SIN_CODE:
         fpa11->fpreg[Fd].fSingle = float32_sin(rFm);
      break;

      case COS_CODE:
         fpa11->fpreg[Fd].fSingle = float32_cos(rFm);
      break;

      case TAN_CODE:
         fpa11->fpreg[Fd].fSingle = float32_tan(rFm);
      break;

      case ASN_CODE:
         fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm);
      break;

      case ACS_CODE:
         fpa11->fpreg[Fd].fSingle = float32_arccos(rFm);
      break;

      case ATN_CODE:
         fpa11->fpreg[Fd].fSingle = float32_arctan(rFm);
      break;
#endif

      case NRM_CODE:
      break;

      default:
      {
        nRc = 0;
      }
   }

   if (0 != nRc) fpa11->fType[Fd] = typeSingle;
   return nRc;
}