162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci    NetWinder Floating Point Emulator
462306a36Sopenharmony_ci    (c) Rebel.COM, 1998,1999
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci*/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "fpa11.h"
1162306a36Sopenharmony_ci#include "softfloat.h"
1262306a36Sopenharmony_ci#include "fpopcode.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciunion float64_components {
1562306a36Sopenharmony_ci	float64 f64;
1662306a36Sopenharmony_ci	unsigned int i[2];
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cifloat64 float64_exp(float64 Fm);
2062306a36Sopenharmony_cifloat64 float64_ln(float64 Fm);
2162306a36Sopenharmony_cifloat64 float64_sin(float64 rFm);
2262306a36Sopenharmony_cifloat64 float64_cos(float64 rFm);
2362306a36Sopenharmony_cifloat64 float64_arcsin(float64 rFm);
2462306a36Sopenharmony_cifloat64 float64_arctan(float64 rFm);
2562306a36Sopenharmony_cifloat64 float64_log(float64 rFm);
2662306a36Sopenharmony_cifloat64 float64_tan(float64 rFm);
2762306a36Sopenharmony_cifloat64 float64_arccos(float64 rFm);
2862306a36Sopenharmony_cifloat64 float64_pow(float64 rFn, float64 rFm);
2962306a36Sopenharmony_cifloat64 float64_pol(float64 rFn, float64 rFm);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic float64 float64_rsf(struct roundingData *roundData, float64 rFn, float64 rFm)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	return float64_sub(roundData, rFm, rFn);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic float64 float64_rdv(struct roundingData *roundData, float64 rFn, float64 rFm)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	return float64_div(roundData, rFm, rFn);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic float64 (*const dyadic_double[16])(struct roundingData*, float64 rFn, float64 rFm) = {
4262306a36Sopenharmony_ci	[ADF_CODE >> 20] = float64_add,
4362306a36Sopenharmony_ci	[MUF_CODE >> 20] = float64_mul,
4462306a36Sopenharmony_ci	[SUF_CODE >> 20] = float64_sub,
4562306a36Sopenharmony_ci	[RSF_CODE >> 20] = float64_rsf,
4662306a36Sopenharmony_ci	[DVF_CODE >> 20] = float64_div,
4762306a36Sopenharmony_ci	[RDF_CODE >> 20] = float64_rdv,
4862306a36Sopenharmony_ci	[RMF_CODE >> 20] = float64_rem,
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/* strictly, these opcodes should not be implemented */
5162306a36Sopenharmony_ci	[FML_CODE >> 20] = float64_mul,
5262306a36Sopenharmony_ci	[FDV_CODE >> 20] = float64_div,
5362306a36Sopenharmony_ci	[FRD_CODE >> 20] = float64_rdv,
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic float64 float64_mvf(struct roundingData *roundData,float64 rFm)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	return rFm;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic float64 float64_mnf(struct roundingData *roundData,float64 rFm)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	union float64_components u;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	u.f64 = rFm;
6662306a36Sopenharmony_ci#ifdef __ARMEB__
6762306a36Sopenharmony_ci	u.i[0] ^= 0x80000000;
6862306a36Sopenharmony_ci#else
6962306a36Sopenharmony_ci	u.i[1] ^= 0x80000000;
7062306a36Sopenharmony_ci#endif
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return u.f64;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic float64 float64_abs(struct roundingData *roundData,float64 rFm)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	union float64_components u;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	u.f64 = rFm;
8062306a36Sopenharmony_ci#ifdef __ARMEB__
8162306a36Sopenharmony_ci	u.i[0] &= 0x7fffffff;
8262306a36Sopenharmony_ci#else
8362306a36Sopenharmony_ci	u.i[1] &= 0x7fffffff;
8462306a36Sopenharmony_ci#endif
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return u.f64;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic float64 (*const monadic_double[16])(struct roundingData *, float64 rFm) = {
9062306a36Sopenharmony_ci	[MVF_CODE >> 20] = float64_mvf,
9162306a36Sopenharmony_ci	[MNF_CODE >> 20] = float64_mnf,
9262306a36Sopenharmony_ci	[ABS_CODE >> 20] = float64_abs,
9362306a36Sopenharmony_ci	[RND_CODE >> 20] = float64_round_to_int,
9462306a36Sopenharmony_ci	[URD_CODE >> 20] = float64_round_to_int,
9562306a36Sopenharmony_ci	[SQT_CODE >> 20] = float64_sqrt,
9662306a36Sopenharmony_ci	[NRM_CODE >> 20] = float64_mvf,
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciunsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	FPA11 *fpa11 = GET_FPA11();
10262306a36Sopenharmony_ci	float64 rFm;
10362306a36Sopenharmony_ci	unsigned int Fm, opc_mask_shift;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	Fm = getFm(opcode);
10662306a36Sopenharmony_ci	if (CONSTANT_FM(opcode)) {
10762306a36Sopenharmony_ci		rFm = getDoubleConstant(Fm);
10862306a36Sopenharmony_ci	} else {
10962306a36Sopenharmony_ci		switch (fpa11->fType[Fm]) {
11062306a36Sopenharmony_ci		case typeSingle:
11162306a36Sopenharmony_ci			rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
11262306a36Sopenharmony_ci			break;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		case typeDouble:
11562306a36Sopenharmony_ci			rFm = fpa11->fpreg[Fm].fDouble;
11662306a36Sopenharmony_ci			break;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		default:
11962306a36Sopenharmony_ci			return 0;
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
12462306a36Sopenharmony_ci	if (!MONADIC_INSTRUCTION(opcode)) {
12562306a36Sopenharmony_ci		unsigned int Fn = getFn(opcode);
12662306a36Sopenharmony_ci		float64 rFn;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		switch (fpa11->fType[Fn]) {
12962306a36Sopenharmony_ci		case typeSingle:
13062306a36Sopenharmony_ci			rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
13162306a36Sopenharmony_ci			break;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		case typeDouble:
13462306a36Sopenharmony_ci			rFn = fpa11->fpreg[Fn].fDouble;
13562306a36Sopenharmony_ci			break;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		default:
13862306a36Sopenharmony_ci			return 0;
13962306a36Sopenharmony_ci		}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		if (dyadic_double[opc_mask_shift]) {
14262306a36Sopenharmony_ci			rFd->fDouble = dyadic_double[opc_mask_shift](roundData, rFn, rFm);
14362306a36Sopenharmony_ci		} else {
14462306a36Sopenharmony_ci			return 0;
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci	} else {
14762306a36Sopenharmony_ci		if (monadic_double[opc_mask_shift]) {
14862306a36Sopenharmony_ci			rFd->fDouble = monadic_double[opc_mask_shift](roundData, rFm);
14962306a36Sopenharmony_ci		} else {
15062306a36Sopenharmony_ci			return 0;
15162306a36Sopenharmony_ci		}
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return 1;
15562306a36Sopenharmony_ci}
156