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_cifloatx80 floatx80_exp(floatx80 Fm);
1562306a36Sopenharmony_cifloatx80 floatx80_ln(floatx80 Fm);
1662306a36Sopenharmony_cifloatx80 floatx80_sin(floatx80 rFm);
1762306a36Sopenharmony_cifloatx80 floatx80_cos(floatx80 rFm);
1862306a36Sopenharmony_cifloatx80 floatx80_arcsin(floatx80 rFm);
1962306a36Sopenharmony_cifloatx80 floatx80_arctan(floatx80 rFm);
2062306a36Sopenharmony_cifloatx80 floatx80_log(floatx80 rFm);
2162306a36Sopenharmony_cifloatx80 floatx80_tan(floatx80 rFm);
2262306a36Sopenharmony_cifloatx80 floatx80_arccos(floatx80 rFm);
2362306a36Sopenharmony_cifloatx80 floatx80_pow(floatx80 rFn, floatx80 rFm);
2462306a36Sopenharmony_cifloatx80 floatx80_pol(floatx80 rFn, floatx80 rFm);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic floatx80 floatx80_rsf(struct roundingData *roundData, floatx80 rFn, floatx80 rFm)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	return floatx80_sub(roundData, rFm, rFn);
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic floatx80 floatx80_rdv(struct roundingData *roundData, floatx80 rFn, floatx80 rFm)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	return floatx80_div(roundData, rFm, rFn);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic floatx80 (*const dyadic_extended[16])(struct roundingData*, floatx80 rFn, floatx80 rFm) = {
3762306a36Sopenharmony_ci	[ADF_CODE >> 20] = floatx80_add,
3862306a36Sopenharmony_ci	[MUF_CODE >> 20] = floatx80_mul,
3962306a36Sopenharmony_ci	[SUF_CODE >> 20] = floatx80_sub,
4062306a36Sopenharmony_ci	[RSF_CODE >> 20] = floatx80_rsf,
4162306a36Sopenharmony_ci	[DVF_CODE >> 20] = floatx80_div,
4262306a36Sopenharmony_ci	[RDF_CODE >> 20] = floatx80_rdv,
4362306a36Sopenharmony_ci	[RMF_CODE >> 20] = floatx80_rem,
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* strictly, these opcodes should not be implemented */
4662306a36Sopenharmony_ci	[FML_CODE >> 20] = floatx80_mul,
4762306a36Sopenharmony_ci	[FDV_CODE >> 20] = floatx80_div,
4862306a36Sopenharmony_ci	[FRD_CODE >> 20] = floatx80_rdv,
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic floatx80 floatx80_mvf(struct roundingData *roundData, floatx80 rFm)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	return rFm;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic floatx80 floatx80_mnf(struct roundingData *roundData, floatx80 rFm)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	rFm.high ^= 0x8000;
5962306a36Sopenharmony_ci	return rFm;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic floatx80 floatx80_abs(struct roundingData *roundData, floatx80 rFm)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	rFm.high &= 0x7fff;
6562306a36Sopenharmony_ci	return rFm;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic floatx80 (*const monadic_extended[16])(struct roundingData*, floatx80 rFm) = {
6962306a36Sopenharmony_ci	[MVF_CODE >> 20] = floatx80_mvf,
7062306a36Sopenharmony_ci	[MNF_CODE >> 20] = floatx80_mnf,
7162306a36Sopenharmony_ci	[ABS_CODE >> 20] = floatx80_abs,
7262306a36Sopenharmony_ci	[RND_CODE >> 20] = floatx80_round_to_int,
7362306a36Sopenharmony_ci	[URD_CODE >> 20] = floatx80_round_to_int,
7462306a36Sopenharmony_ci	[SQT_CODE >> 20] = floatx80_sqrt,
7562306a36Sopenharmony_ci	[NRM_CODE >> 20] = floatx80_mvf,
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciunsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	FPA11 *fpa11 = GET_FPA11();
8162306a36Sopenharmony_ci	floatx80 rFm;
8262306a36Sopenharmony_ci	unsigned int Fm, opc_mask_shift;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	Fm = getFm(opcode);
8562306a36Sopenharmony_ci	if (CONSTANT_FM(opcode)) {
8662306a36Sopenharmony_ci		rFm = getExtendedConstant(Fm);
8762306a36Sopenharmony_ci	} else {
8862306a36Sopenharmony_ci		switch (fpa11->fType[Fm]) {
8962306a36Sopenharmony_ci		case typeSingle:
9062306a36Sopenharmony_ci			rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
9162306a36Sopenharmony_ci			break;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		case typeDouble:
9462306a36Sopenharmony_ci			rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
9562306a36Sopenharmony_ci			break;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci		case typeExtended:
9862306a36Sopenharmony_ci			rFm = fpa11->fpreg[Fm].fExtended;
9962306a36Sopenharmony_ci			break;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		default:
10262306a36Sopenharmony_ci			return 0;
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
10762306a36Sopenharmony_ci	if (!MONADIC_INSTRUCTION(opcode)) {
10862306a36Sopenharmony_ci		unsigned int Fn = getFn(opcode);
10962306a36Sopenharmony_ci		floatx80 rFn;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		switch (fpa11->fType[Fn]) {
11262306a36Sopenharmony_ci		case typeSingle:
11362306a36Sopenharmony_ci			rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
11462306a36Sopenharmony_ci			break;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		case typeDouble:
11762306a36Sopenharmony_ci			rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
11862306a36Sopenharmony_ci			break;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		case typeExtended:
12162306a36Sopenharmony_ci			rFn = fpa11->fpreg[Fn].fExtended;
12262306a36Sopenharmony_ci			break;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		default:
12562306a36Sopenharmony_ci			return 0;
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		if (dyadic_extended[opc_mask_shift]) {
12962306a36Sopenharmony_ci			rFd->fExtended = dyadic_extended[opc_mask_shift](roundData, rFn, rFm);
13062306a36Sopenharmony_ci		} else {
13162306a36Sopenharmony_ci			return 0;
13262306a36Sopenharmony_ci		}
13362306a36Sopenharmony_ci	} else {
13462306a36Sopenharmony_ci		if (monadic_extended[opc_mask_shift]) {
13562306a36Sopenharmony_ci			rFd->fExtended = monadic_extended[opc_mask_shift](roundData, rFm);
13662306a36Sopenharmony_ci		} else {
13762306a36Sopenharmony_ci			return 0;
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return 1;
14262306a36Sopenharmony_ci}
143