xref: /openbmc/linux/arch/arm/nwfpe/double_cpdo.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*74ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds     NetWinder Floating Point Emulator
41da177e4SLinus Torvalds     (c) Rebel.COM, 1998,1999
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include "fpa11.h"
111da177e4SLinus Torvalds #include "softfloat.h"
121da177e4SLinus Torvalds #include "fpopcode.h"
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds union float64_components {
151da177e4SLinus Torvalds 	float64 f64;
161da177e4SLinus Torvalds 	unsigned int i[2];
171da177e4SLinus Torvalds };
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds float64 float64_exp(float64 Fm);
201da177e4SLinus Torvalds float64 float64_ln(float64 Fm);
211da177e4SLinus Torvalds float64 float64_sin(float64 rFm);
221da177e4SLinus Torvalds float64 float64_cos(float64 rFm);
231da177e4SLinus Torvalds float64 float64_arcsin(float64 rFm);
241da177e4SLinus Torvalds float64 float64_arctan(float64 rFm);
251da177e4SLinus Torvalds float64 float64_log(float64 rFm);
261da177e4SLinus Torvalds float64 float64_tan(float64 rFm);
271da177e4SLinus Torvalds float64 float64_arccos(float64 rFm);
281da177e4SLinus Torvalds float64 float64_pow(float64 rFn, float64 rFm);
291da177e4SLinus Torvalds float64 float64_pol(float64 rFn, float64 rFm);
301da177e4SLinus Torvalds 
float64_rsf(struct roundingData * roundData,float64 rFn,float64 rFm)31f148af25SRichard Purdie static float64 float64_rsf(struct roundingData *roundData, float64 rFn, float64 rFm)
321da177e4SLinus Torvalds {
33f148af25SRichard Purdie 	return float64_sub(roundData, rFm, rFn);
341da177e4SLinus Torvalds }
351da177e4SLinus Torvalds 
float64_rdv(struct roundingData * roundData,float64 rFn,float64 rFm)36f148af25SRichard Purdie static float64 float64_rdv(struct roundingData *roundData, float64 rFn, float64 rFm)
371da177e4SLinus Torvalds {
38f148af25SRichard Purdie 	return float64_div(roundData, rFm, rFn);
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds 
41f148af25SRichard Purdie static float64 (*const dyadic_double[16])(struct roundingData*, float64 rFn, float64 rFm) = {
421da177e4SLinus Torvalds 	[ADF_CODE >> 20] = float64_add,
431da177e4SLinus Torvalds 	[MUF_CODE >> 20] = float64_mul,
441da177e4SLinus Torvalds 	[SUF_CODE >> 20] = float64_sub,
451da177e4SLinus Torvalds 	[RSF_CODE >> 20] = float64_rsf,
461da177e4SLinus Torvalds 	[DVF_CODE >> 20] = float64_div,
471da177e4SLinus Torvalds 	[RDF_CODE >> 20] = float64_rdv,
481da177e4SLinus Torvalds 	[RMF_CODE >> 20] = float64_rem,
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	/* strictly, these opcodes should not be implemented */
511da177e4SLinus Torvalds 	[FML_CODE >> 20] = float64_mul,
521da177e4SLinus Torvalds 	[FDV_CODE >> 20] = float64_div,
531da177e4SLinus Torvalds 	[FRD_CODE >> 20] = float64_rdv,
541da177e4SLinus Torvalds };
551da177e4SLinus Torvalds 
float64_mvf(struct roundingData * roundData,float64 rFm)56f148af25SRichard Purdie static float64 float64_mvf(struct roundingData *roundData,float64 rFm)
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds 	return rFm;
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
float64_mnf(struct roundingData * roundData,float64 rFm)61f148af25SRichard Purdie static float64 float64_mnf(struct roundingData *roundData,float64 rFm)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	union float64_components u;
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	u.f64 = rFm;
661da177e4SLinus Torvalds #ifdef __ARMEB__
671da177e4SLinus Torvalds 	u.i[0] ^= 0x80000000;
681da177e4SLinus Torvalds #else
691da177e4SLinus Torvalds 	u.i[1] ^= 0x80000000;
701da177e4SLinus Torvalds #endif
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	return u.f64;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
float64_abs(struct roundingData * roundData,float64 rFm)75f148af25SRichard Purdie static float64 float64_abs(struct roundingData *roundData,float64 rFm)
761da177e4SLinus Torvalds {
771da177e4SLinus Torvalds 	union float64_components u;
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	u.f64 = rFm;
801da177e4SLinus Torvalds #ifdef __ARMEB__
811da177e4SLinus Torvalds 	u.i[0] &= 0x7fffffff;
821da177e4SLinus Torvalds #else
831da177e4SLinus Torvalds 	u.i[1] &= 0x7fffffff;
841da177e4SLinus Torvalds #endif
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	return u.f64;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
89f148af25SRichard Purdie static float64 (*const monadic_double[16])(struct roundingData *, float64 rFm) = {
901da177e4SLinus Torvalds 	[MVF_CODE >> 20] = float64_mvf,
911da177e4SLinus Torvalds 	[MNF_CODE >> 20] = float64_mnf,
921da177e4SLinus Torvalds 	[ABS_CODE >> 20] = float64_abs,
931da177e4SLinus Torvalds 	[RND_CODE >> 20] = float64_round_to_int,
941da177e4SLinus Torvalds 	[URD_CODE >> 20] = float64_round_to_int,
951da177e4SLinus Torvalds 	[SQT_CODE >> 20] = float64_sqrt,
961da177e4SLinus Torvalds 	[NRM_CODE >> 20] = float64_mvf,
971da177e4SLinus Torvalds };
981da177e4SLinus Torvalds 
DoubleCPDO(struct roundingData * roundData,const unsigned int opcode,FPREG * rFd)99f148af25SRichard Purdie unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd)
1001da177e4SLinus Torvalds {
1011da177e4SLinus Torvalds 	FPA11 *fpa11 = GET_FPA11();
1021da177e4SLinus Torvalds 	float64 rFm;
1031da177e4SLinus Torvalds 	unsigned int Fm, opc_mask_shift;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	Fm = getFm(opcode);
1061da177e4SLinus Torvalds 	if (CONSTANT_FM(opcode)) {
1071da177e4SLinus Torvalds 		rFm = getDoubleConstant(Fm);
1081da177e4SLinus Torvalds 	} else {
1091da177e4SLinus Torvalds 		switch (fpa11->fType[Fm]) {
1101da177e4SLinus Torvalds 		case typeSingle:
1111da177e4SLinus Torvalds 			rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
1121da177e4SLinus Torvalds 			break;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 		case typeDouble:
1151da177e4SLinus Torvalds 			rFm = fpa11->fpreg[Fm].fDouble;
1161da177e4SLinus Torvalds 			break;
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds 		default:
1191da177e4SLinus Torvalds 			return 0;
1201da177e4SLinus Torvalds 		}
1211da177e4SLinus Torvalds 	}
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 	opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
1241da177e4SLinus Torvalds 	if (!MONADIC_INSTRUCTION(opcode)) {
1251da177e4SLinus Torvalds 		unsigned int Fn = getFn(opcode);
1261da177e4SLinus Torvalds 		float64 rFn;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 		switch (fpa11->fType[Fn]) {
1291da177e4SLinus Torvalds 		case typeSingle:
1301da177e4SLinus Torvalds 			rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
1311da177e4SLinus Torvalds 			break;
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds 		case typeDouble:
1341da177e4SLinus Torvalds 			rFn = fpa11->fpreg[Fn].fDouble;
1351da177e4SLinus Torvalds 			break;
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 		default:
1381da177e4SLinus Torvalds 			return 0;
1391da177e4SLinus Torvalds 		}
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 		if (dyadic_double[opc_mask_shift]) {
142f148af25SRichard Purdie 			rFd->fDouble = dyadic_double[opc_mask_shift](roundData, rFn, rFm);
1431da177e4SLinus Torvalds 		} else {
1441da177e4SLinus Torvalds 			return 0;
1451da177e4SLinus Torvalds 		}
1461da177e4SLinus Torvalds 	} else {
1471da177e4SLinus Torvalds 		if (monadic_double[opc_mask_shift]) {
148f148af25SRichard Purdie 			rFd->fDouble = monadic_double[opc_mask_shift](roundData, rFm);
1491da177e4SLinus Torvalds 		} else {
1501da177e4SLinus Torvalds 			return 0;
1511da177e4SLinus Torvalds 		}
1521da177e4SLinus Torvalds 	}
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	return 1;
1551da177e4SLinus Torvalds }
156