Пример #1
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
}
Пример #2
0
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_DOUBLE_REAL(bxInstruction_c *i)
{
  BX_CPU_THIS_PTR prepareFPU(i);

  RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
  float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i));

  FPU_update_last_instruction(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1)) {
    FPU_stack_overflow();
    BX_NEXT_INSTR(i);
  }

  float_status_t status =
    FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());

  // convert to floatx80 format
  floatx80 result = float64_to_floatx80(load_reg, status);

  unsigned unmasked = FPU_exception(status.float_exception_flags);
  if (! (unmasked & FPU_CW_Invalid)) {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(result, 0);
  }

  BX_NEXT_INSTR(i);
}
Пример #3
0
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_DOUBLE_REAL(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i));

  clear_C1();

  if (! IS_TAG_EMPTY(-1)) {
    BX_CPU_THIS_PTR FPU_stack_overflow();
    return;
  }

  float_status_t status =
     FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());

  // convert to floatx80 format
  floatx80 result = float64_to_floatx80(load_reg, status);

  if (BX_CPU_THIS_PTR FPU_exception(status.float_exception_flags))
    return;

  BX_CPU_THIS_PTR the_i387.FPU_push();
  BX_WRITE_FPU_REG(result, 0);
#else
  BX_INFO(("FLD_DOUBLE_REAL: required FPU, configure --enable-fpu"));
#endif
}
extern __inline__
void storeExtended(const unsigned int Fn,unsigned int *pMem)
{
   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 */
#ifdef __ARMEB__
   put_user(p[1], &pMem[1]);
   put_user(p[2], &pMem[2]); /* msw */
#else
   put_user(p[1], &pMem[2]);
   put_user(p[2], &pMem[1]); /* msw */
#endif
}   
Пример #5
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 */
}
Пример #6
0
INLINE floatx80 double_to_fx80(double in)
{
	UINT64 *d;

	d = (UINT64 *)∈

	return float64_to_floatx80(*d);
}
Пример #7
0
long_double __extenddfxf2(float64 A)
{
#if __SIZEOF_LONG_DOUBLE__ == 12
	return float64_to_floatx80(A);
#else
	return float64_to_float128(A);
#endif
}
Пример #8
0
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_DOUBLE_REAL(bxInstruction_c *i)
{
  BX_CPU_THIS_PTR prepareFPU(i);

  int pop_stack = i->nnn() & 1, rc;

  RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
  float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i));

  BX_CPU_THIS_PTR FPU_update_last_instruction(i);

  clear_C1();

  if (IS_TAG_EMPTY(0))
  {
      FPU_exception(FPU_EX_Stack_Underflow);
      setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);

      if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
      {
          if (pop_stack)
              BX_CPU_THIS_PTR the_i387.FPU_pop();
      }
      BX_NEXT_INSTR(i);
  }

  float_status_t status =
      FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());

  floatx80 a = BX_READ_FPU_REG(0);

  if (floatx80_is_nan(a) || floatx80_is_unsupported(a) || float64_is_nan(load_reg)) {
    rc = float_relation_unordered;
    float_raise(status, float_flag_invalid);
  }
  else {
    rc = floatx80_compare(a, float64_to_floatx80(load_reg, status), status);
  }
  setcc(status_word_flags_fpu_compare(rc));

  if (! FPU_exception(status.float_exception_flags)) {
     if (pop_stack)
         BX_CPU_THIS_PTR the_i387.FPU_pop();
  }

  BX_NEXT_INSTR(i);
}
Пример #9
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 */
}   
Пример #10
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;
}
Пример #11
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;
}
Пример #12
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;
}
Пример #13
0
static void fpgen_rm_reg(m68000_base_device *m68k, UINT16 w2)
{
	int ea = m68k->ir & 0x3f;
	int rm = (w2 >> 14) & 0x1;
	int src = (w2 >> 10) & 0x7;
	int dst = (w2 >>  7) & 0x7;
	int opmode = w2 & 0x7f;
	floatx80 source;

	// fmovecr #$f, fp0 f200 5c0f

	if (rm)
	{
		switch (src)
		{
			case 0:     // Long-Word Integer
			{
				INT32 d = READ_EA_32(m68k, ea);
				source = int32_to_floatx80(d);
				break;
			}
			case 1:     // Single-precision Real
			{
				UINT32 d = READ_EA_32(m68k, ea);
				source = float32_to_floatx80(d);
				break;
			}
			case 2:     // Extended-precision Real
			{
				source = READ_EA_FPE(m68k, ea);
				break;
			}
			case 3:     // Packed-decimal Real
			{
				source = READ_EA_PACK(m68k, ea);
				break;
			}
			case 4:     // Word Integer
			{
				INT16 d = READ_EA_16(m68k, ea);
				source = int32_to_floatx80((INT32)d);
				break;
			}
			case 5:     // Double-precision Real
			{
				UINT64 d = READ_EA_64(m68k, ea);

				source = float64_to_floatx80(d);
				break;
			}
			case 6:     // Byte Integer
			{
				INT8 d = READ_EA_8(m68k, ea);
				source = int32_to_floatx80((INT32)d);
				break;
			}
			case 7:     // FMOVECR load from constant ROM
			{
				switch (w2 & 0x7f)
				{
					case 0x0:   // Pi
						source.high = 0x4000;
						source.low = U64(0xc90fdaa22168c235);
						break;

					case 0xb:   // log10(2)
						source.high = 0x3ffd;
						source.low = U64(0x9a209a84fbcff798);
						break;

					case 0xc:   // e
						source.high = 0x4000;
						source.low = U64(0xadf85458a2bb4a9b);
						break;

					case 0xd:   // log2(e)
						source.high = 0x3fff;
						source.low = U64(0xb8aa3b295c17f0bc);
						break;

					case 0xe:   // log10(e)
						source.high = 0x3ffd;
						source.low = U64(0xde5bd8a937287195);
						break;

					case 0xf:   // 0.0
						source = int32_to_floatx80((INT32)0);
						break;

					case 0x30:  // ln(2)
						source.high = 0x3ffe;
						source.low = U64(0xb17217f7d1cf79ac);
						break;

					case 0x31:  // ln(10)
						source.high = 0x4000;
						source.low = U64(0x935d8dddaaa8ac17);
						break;

					case 0x32:  // 1 (or 100?  manuals are unclear, but 1 would make more sense)
						source = int32_to_floatx80((INT32)1);
						break;

					case 0x33:  // 10^1
						source = int32_to_floatx80((INT32)10);
						break;

					case 0x34:  // 10^2
						source = int32_to_floatx80((INT32)10*10);
						break;

					case 0x35:  // 10^4
						source = int32_to_floatx80((INT32)1000*10);
						break;

					case 0x36:  // 1.0e8
						source = int32_to_floatx80((INT32)10000000*10);
						break;

					case 0x37:  // 1.0e16 - can't get the right precision from INT32 so go "direct" with constants from h/w
						source.high = 0x4034;
						source.low = U64(0x8e1bc9bf04000000);
						break;

					case 0x38:  // 1.0e32
						source.high = 0x4069;
						source.low = U64(0x9dc5ada82b70b59e);
						break;

					case 0x39:  // 1.0e64
						source.high = 0x40d3;
						source.low = U64(0xc2781f49ffcfa6d5);
						break;

					case 0x3a:  // 1.0e128
						source.high = 0x41a8;
						source.low = U64(0x93ba47c980e98ce0);
						break;

					case 0x3b:  // 1.0e256
						source.high = 0x4351;
						source.low = U64(0xaa7eebfb9df9de8e);
						break;

					case 0x3c:  // 1.0e512
						source.high = 0x46a3;
						source.low = U64(0xe319a0aea60e91c7);
						break;

					case 0x3d:  // 1.0e1024
						source.high = 0x4d48;
						source.low = U64(0xc976758681750c17);
						break;

					case 0x3e:  // 1.0e2048
						source.high = 0x5a92;
						source.low = U64(0x9e8b3b5dc53d5de5);
						break;

					case 0x3f:  // 1.0e4096
						source.high = 0x7525;
						source.low = U64(0xc46052028a20979b);
						break;

					default:
						fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC(m68k)-4);
						break;
				}

				// handle it right here, the usual opmode bits aren't valid in the FMOVECR case
				REG_FP(m68k)[dst] = source;
				m68k->remaining_cycles -= 4;
				return;
			}
			default:    fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, REG_PC(m68k)-4);
		}
	}
	else
	{
		source = REG_FP(m68k)[src];
	}



	switch (opmode)
	{
		case 0x00:      // FMOVE
		{
			REG_FP(m68k)[dst] = source;
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 4;
			break;
		}
		case 0x01:      // FINT
		{
			INT32 temp;
			temp = floatx80_to_int32(source);
			REG_FP(m68k)[dst] = int32_to_floatx80(temp);
			break;
		}
		case 0x03:      // FINTRZ
		{
			INT32 temp;
			temp = floatx80_to_int32_round_to_zero(source);
			REG_FP(m68k)[dst] = int32_to_floatx80(temp);
			break;
		}
		case 0x04:      // FSQRT
		{
			REG_FP(m68k)[dst] = floatx80_sqrt(source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 109;
			break;
		}
		case 0x06:      // FLOGNP1
		{
			REG_FP(m68k)[dst] = floatx80_flognp1 (source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 594; // for MC68881
			break;
		}
		case 0x0e:      // FSIN
		{
			REG_FP(m68k)[dst] = source;
			floatx80_fsin(REG_FP(m68k)[dst]);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 75;
			break;
		}
		case 0x0f:      // FTAN
		{
			REG_FP(m68k)[dst] = source;
			floatx80_ftan(REG_FP(m68k)[dst]);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 75;
			break;
		}
		case 0x14:      // FLOGN
		{
			REG_FP(m68k)[dst] = floatx80_flogn (source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 548; // for MC68881
			break;
		}
		case 0x15:      // FLOG10
		{
			REG_FP(m68k)[dst] = floatx80_flog10 (source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 604; // for MC68881
			break;
		}
		case 0x16:      // FLOG2
		{
			REG_FP(m68k)[dst] = floatx80_flog2 (source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 604; // for MC68881
			break;
		}
		case 0x18:      // FABS
		{
			REG_FP(m68k)[dst] = source;
			REG_FP(m68k)[dst].high &= 0x7fff;
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 3;
			break;
		}
		case 0x1a:      // FNEG
		{
			REG_FP(m68k)[dst] = source;
			REG_FP(m68k)[dst].high ^= 0x8000;
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 3;
			break;
		}
		case 0x1d:      // FCOS
		{
			REG_FP(m68k)[dst] = source;
			floatx80_fcos(REG_FP(m68k)[dst]);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 75;
			break;
		}
		case 0x1e:      // FGETEXP
		{
			INT16 temp2;

			temp2 = source.high;    // get the exponent
			temp2 -= 0x3fff;    // take off the bias
			REG_FP(m68k)[dst] = double_to_fx80((double)temp2);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 6;
			break;
		}
		case 0x20:      // FDIV
		{
			REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source);
			m68k->remaining_cycles -= 43;
			break;
		}
		case 0x22:      // FADD
		{
			REG_FP(m68k)[dst] = floatx80_add(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 9;
			break;
		}
		case 0x23:      // FMUL
		{
			REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 11;
			break;
		}
		case 0x24:      // FSGLDIV
		{
			float32 a = floatx80_to_float32( REG_FP(m68k)[dst] );
			float32 b = floatx80_to_float32( source );
			REG_FP(m68k)[dst] = float32_to_floatx80( float32_div(a, b) );
			m68k->remaining_cycles -= 43; //  // ? (value is from FDIV)
			break;
		}
		case 0x25:      // FREM
		{
			REG_FP(m68k)[dst] = floatx80_rem(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 43;   // guess
			break;
		}
		case 0x27:      // FSGLMUL
		{
			float32 a = floatx80_to_float32( REG_FP(m68k)[dst] );
			float32 b = floatx80_to_float32( source );
			REG_FP(m68k)[dst] = float32_to_floatx80( float32_mul(a, b) );
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 11; // ? (value is from FMUL)
			break;
		}
		case 0x28:      // FSUB
		{
			REG_FP(m68k)[dst] = floatx80_sub(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 9;
			break;
		}
		case 0x38:      // FCMP
		{
			floatx80 res;
			res = floatx80_sub(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, res);
			m68k->remaining_cycles -= 7;
			break;
		}
		case 0x3a:      // FTST
		{
			floatx80 res;
			res = source;
			SET_CONDITION_CODES(m68k, res);
			m68k->remaining_cycles -= 7;
			break;
		}

		default:    fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC(m68k));
	}
}
Пример #14
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;
}
Пример #15
0
static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2)
{
	int ea = m68k->ir & 0x3f;
	int rm = (w2 >> 14) & 0x1;
	int src = (w2 >> 10) & 0x7;
	int dst = (w2 >>  7) & 0x7;
	int opmode = w2 & 0x7f;
	floatx80 source;

	// fmovecr #$f, fp0 f200 5c0f

	if (rm)
	{
		switch (src)
		{
			case 0:		// Long-Word Integer
			{
				INT32 d = READ_EA_32(m68k, ea);
				source = int32_to_floatx80(d);
				break;
			}
			case 1:		// Single-precision Real
			{
				UINT32 d = READ_EA_32(m68k, ea);
				source = float32_to_floatx80(d);
				break;
			}
			case 2:		// Extended-precision Real
			{
				source = READ_EA_FPE(m68k, ea);
				break;
			}
			case 3:		// Packed-decimal Real
			{
				source = READ_EA_PACK(m68k, ea);
				break;
			}
			case 4:		// Word Integer
			{
				INT16 d = READ_EA_16(m68k, ea);
				source = int32_to_floatx80((INT32)d);
				break;
			}
			case 5:		// Double-precision Real
			{
				UINT64 d = READ_EA_64(m68k, ea);

				source = float64_to_floatx80(d);
				break;
			}
			case 6:		// Byte Integer
			{
				INT8 d = READ_EA_8(m68k, ea);
				source = int32_to_floatx80((INT32)d);
				break;
			}
			case 7:		// FMOVECR load from constant ROM
			{
				switch (w2 & 0x7f)
				{
					case 0x0:	// Pi
						source.high = 0x4000;
						source.low = U64(0xc90fdaa22168c235);
						break;

					case 0xb:	// log10(2)
						source.high = 0x3ffd;
						source.low = U64(0x9a209a84fbcff798);
						break;

					case 0xc:	// e
						source.high = 0x4000;
						source.low = U64(0xadf85458a2bb4a9b);
						break;

					case 0xd:	// log2(e)
						source.high = 0x3fff;
						source.low = U64(0xb8aa3b295c17f0bc);
						break;

					case 0xe:	// log10(e)
						source.high = 0x3ffd;
						source.low = U64(0xde5bd8a937287195);
						break;

					case 0xf:	// 0.0
						source = int32_to_floatx80((INT32)0);
						break;

					case 0x30:	// ln(2)
						source.high = 0x3ffe;
						source.low = U64(0xb17217f7d1cf79ac);
						break;

					case 0x31:	// ln(10)
						source.high = 0x4000;
						source.low = U64(0x935d8dddaaa8ac17);
						break;

					case 0x32:	// 1 (or 100?  manuals are unclear, but 1 would make more sense)
						source = int32_to_floatx80((INT32)1);
						break;

					case 0x33:	// 10^1
						source = int32_to_floatx80((INT32)10);
						break;

					case 0x34:	// 10^2
						source = int32_to_floatx80((INT32)10*10);
						break;

					default:
						fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC(m68k)-4);
						break;
				}

				// handle it right here, the usual opmode bits aren't valid in the FMOVECR case
				REG_FP(m68k)[dst] = source;
				m68k->remaining_cycles -= 4;
				return;
			}
			default:	fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, REG_PC(m68k)-4);
		}
	}
	else
	{
		source = REG_FP(m68k)[src];
	}



	switch (opmode)
	{
		case 0x00:		// FMOVE
		{
			REG_FP(m68k)[dst] = source;
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 4;
			break;
		}
		case 0x01:		// FINT
		{
			INT32 temp;
			temp = floatx80_to_int32(source);
			REG_FP(m68k)[dst] = int32_to_floatx80(temp);
			break;
		}
		case 0x03:		// FINTRZ
		{
			INT32 temp;
			temp = floatx80_to_int32_round_to_zero(source);
			REG_FP(m68k)[dst] = int32_to_floatx80(temp);
			break;
		}
		case 0x04:		// FSQRT
		{
			REG_FP(m68k)[dst] = floatx80_sqrt(source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 109;
			break;
		}
		case 0x0e:      // FSIN
		{
			REG_FP(m68k)[dst] = source;
			floatx80_fsin(REG_FP(m68k)[dst]);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 75;
			break;
		}
		case 0x0f:		// FTAN
		{
			REG_FP(m68k)[dst] = source;
			floatx80_ftan(REG_FP(m68k)[dst]);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 75;
			break;
		}
		case 0x18:		// FABS
		{
			REG_FP(m68k)[dst] = source;
			REG_FP(m68k)[dst].high &= 0x7fff;
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 3;
			break;
		}
		case 0x1a:		// FNEG
		{
			REG_FP(m68k)[dst] = source;
			REG_FP(m68k)[dst].high ^= 0x8000;
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 3;
			break;
		}
		case 0x1d:      // FCOS
		{
			REG_FP(m68k)[dst] = source;
			floatx80_fcos(REG_FP(m68k)[dst]);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 75;
			break;
		}
		case 0x1e:		// FGETEXP
		{
			INT16 temp2;

			temp2 = source.high;	// get the exponent
			temp2 -= 0x3fff;	// take off the bias
			REG_FP(m68k)[dst] = double_to_fx80((double)temp2);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 6;
		}
		case 0x20:		// FDIV
		{
			REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source);
			m68k->remaining_cycles -= 43;
			break;
		}
		case 0x22:		// FADD
		{
			REG_FP(m68k)[dst] = floatx80_add(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 9;
			break;
		}
		case 0x23:		// FMUL
		{
			REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 11;
			break;
		}
		case 0x24:		// FSGLDIV
		{
			REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source);
			m68k->remaining_cycles -= 43; //  // ? (value is from FDIV)
			break;
		}
		case 0x25:		// FREM
		{
			REG_FP(m68k)[dst] = floatx80_rem(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 43;	// guess
			break;
		}
		case 0x27:		// FSGLMUL
		{
			REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 11; // ? (value is from FMUL)
			break;
		}
		case 0x28:		// FSUB
		{
			REG_FP(m68k)[dst] = floatx80_sub(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]);
			m68k->remaining_cycles -= 9;
			break;
		}
		case 0x38:		// FCMP
		{
			floatx80 res;
			res = floatx80_sub(REG_FP(m68k)[dst], source);
			SET_CONDITION_CODES(m68k, res);
			m68k->remaining_cycles -= 7;
			break;
		}
		case 0x3a:		// FTST
		{
			floatx80 res;
			res = source;
			SET_CONDITION_CODES(m68k, res);
			m68k->remaining_cycles -= 7;
			break;
		}

		default:	fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC(m68k));
	}
}