| 
					
				 | 
			
			
				@@ -254,3 +254,195 @@ static u32 vfp_double_fabs(int dd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static u32 vfp_double_fcpy(int dd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vfp_put_double(vfp_get_double(dm), dd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 vfp_double_fneg(int dd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vfp_put_double(vfp_double_packed_negate(vfp_get_double(dm)), dd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 vfp_double_fsqrt(int dd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct vfp_double vdm, vdd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int ret, tm; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vfp_double_unpack(&vdm, vfp_get_double(dm)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	tm = vfp_double_type(&vdm); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (tm & (VFP_NAN|VFP_INFINITY)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		struct vfp_double *vdp = &vdd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (tm & VFP_NAN) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else if (vdm.sign == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ sqrt_copy: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			vdp = &vdm; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ret = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ sqrt_invalid: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			vdp = &vfp_double_default_qnan; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ret = FPSCR_IOC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		vfp_put_double(vfp_double_pack(vdp), dd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return ret; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * sqrt(+/- 0) == +/- 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (tm & VFP_ZERO) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		goto sqrt_copy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * Normalise a denormalised number 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (tm & VFP_DENORMAL) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		vfp_double_normalise_denormal(&vdm); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * sqrt(<0) = invalid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (vdm.sign) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		goto sqrt_invalid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vfp_double_dump("sqrt", &vdm); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * Estimate the square root. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vdd.sign = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vfp_double_dump("sqrt estimate1", &vdd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vdm.significand >>= 1 + (vdm.exponent & 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vfp_double_dump("sqrt estimate2", &vdd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * And now adjust. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (vdd.significand < 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			vdd.significand = ~0ULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			u64 termh, terml, remh, reml; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			vdm.significand <<= 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			mul64to128(&termh, &terml, vdd.significand, vdd.significand); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			sub128(&remh, &reml, vdm.significand, 0, termh, terml); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			while ((s64)remh < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				vdd.significand -= 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				shift64left(&termh, &terml, vdd.significand); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				terml |= 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				add128(&remh, &reml, remh, reml, termh, terml); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			vdd.significand |= (remh | reml) != 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fsqrt"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Equal	:= ZC 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Less than	:= N 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Greater than	:= C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Unordered	:= CV 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 vfp_compare(int dd, int signal_on_qnan, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	s64 d, m; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u32 ret = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	m = vfp_get_double(dm); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		ret |= FPSCR_C | FPSCR_V; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 * Signalling NaN, or signalling on quiet NaN 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ret |= FPSCR_IOC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	d = vfp_get_double(dd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		ret |= FPSCR_C | FPSCR_V; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 * Signalling NaN, or signalling on quiet NaN 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ret |= FPSCR_IOC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (ret == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (d == m || vfp_double_packed_abs(d | m) == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 * equal 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ret |= FPSCR_Z | FPSCR_C; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} else if (vfp_double_packed_sign(d ^ m)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 * different signs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (vfp_double_packed_sign(d)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 * d is negative, so d < m 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				ret |= FPSCR_N; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 * d is positive, so d > m 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				ret |= FPSCR_C; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 * d < m 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ret |= FPSCR_N; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 * d > m 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ret |= FPSCR_C; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return ret; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 vfp_double_fcmp(int dd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return vfp_compare(dd, 0, dm, fpscr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 vfp_double_fcmpe(int dd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return vfp_compare(dd, 1, dm, fpscr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 vfp_double_fcmpz(int dd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return vfp_compare(dd, 0, VFP_REG_ZERO, fpscr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 vfp_double_fcmpez(int dd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return vfp_compare(dd, 1, VFP_REG_ZERO, fpscr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 vfp_double_fcvts(int sd, int unused, int dm, u32 fpscr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct vfp_double vdm; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct vfp_single vsd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int tm; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u32 exceptions = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vfp_double_unpack(&vdm, vfp_get_double(dm)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	tm = vfp_double_type(&vdm); 
			 |