xref: /linux/arch/arm/nwfpe/extended_cpdo.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2     NetWinder Floating Point Emulator
3     (c) Rebel.COM, 1998,1999
4 
5     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 
22 #include "fpa11.h"
23 #include "softfloat.h"
24 #include "fpopcode.h"
25 
26 floatx80 floatx80_exp(floatx80 Fm);
27 floatx80 floatx80_ln(floatx80 Fm);
28 floatx80 floatx80_sin(floatx80 rFm);
29 floatx80 floatx80_cos(floatx80 rFm);
30 floatx80 floatx80_arcsin(floatx80 rFm);
31 floatx80 floatx80_arctan(floatx80 rFm);
32 floatx80 floatx80_log(floatx80 rFm);
33 floatx80 floatx80_tan(floatx80 rFm);
34 floatx80 floatx80_arccos(floatx80 rFm);
35 floatx80 floatx80_pow(floatx80 rFn, floatx80 rFm);
36 floatx80 floatx80_pol(floatx80 rFn, floatx80 rFm);
37 
38 static floatx80 floatx80_rsf(struct roundingData *roundData, floatx80 rFn, floatx80 rFm)
39 {
40 	return floatx80_sub(roundData, rFm, rFn);
41 }
42 
43 static floatx80 floatx80_rdv(struct roundingData *roundData, floatx80 rFn, floatx80 rFm)
44 {
45 	return floatx80_div(roundData, rFm, rFn);
46 }
47 
48 static floatx80 (*const dyadic_extended[16])(struct roundingData*, floatx80 rFn, floatx80 rFm) = {
49 	[ADF_CODE >> 20] = floatx80_add,
50 	[MUF_CODE >> 20] = floatx80_mul,
51 	[SUF_CODE >> 20] = floatx80_sub,
52 	[RSF_CODE >> 20] = floatx80_rsf,
53 	[DVF_CODE >> 20] = floatx80_div,
54 	[RDF_CODE >> 20] = floatx80_rdv,
55 	[RMF_CODE >> 20] = floatx80_rem,
56 
57 	/* strictly, these opcodes should not be implemented */
58 	[FML_CODE >> 20] = floatx80_mul,
59 	[FDV_CODE >> 20] = floatx80_div,
60 	[FRD_CODE >> 20] = floatx80_rdv,
61 };
62 
63 static floatx80 floatx80_mvf(struct roundingData *roundData, floatx80 rFm)
64 {
65 	return rFm;
66 }
67 
68 static floatx80 floatx80_mnf(struct roundingData *roundData, floatx80 rFm)
69 {
70 	rFm.high ^= 0x8000;
71 	return rFm;
72 }
73 
74 static floatx80 floatx80_abs(struct roundingData *roundData, floatx80 rFm)
75 {
76 	rFm.high &= 0x7fff;
77 	return rFm;
78 }
79 
80 static floatx80 (*const monadic_extended[16])(struct roundingData*, floatx80 rFm) = {
81 	[MVF_CODE >> 20] = floatx80_mvf,
82 	[MNF_CODE >> 20] = floatx80_mnf,
83 	[ABS_CODE >> 20] = floatx80_abs,
84 	[RND_CODE >> 20] = floatx80_round_to_int,
85 	[URD_CODE >> 20] = floatx80_round_to_int,
86 	[SQT_CODE >> 20] = floatx80_sqrt,
87 	[NRM_CODE >> 20] = floatx80_mvf,
88 };
89 
90 unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd)
91 {
92 	FPA11 *fpa11 = GET_FPA11();
93 	floatx80 rFm;
94 	unsigned int Fm, opc_mask_shift;
95 
96 	Fm = getFm(opcode);
97 	if (CONSTANT_FM(opcode)) {
98 		rFm = getExtendedConstant(Fm);
99 	} else {
100 		switch (fpa11->fType[Fm]) {
101 		case typeSingle:
102 			rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
103 			break;
104 
105 		case typeDouble:
106 			rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
107 			break;
108 
109 		case typeExtended:
110 			rFm = fpa11->fpreg[Fm].fExtended;
111 			break;
112 
113 		default:
114 			return 0;
115 		}
116 	}
117 
118 	opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
119 	if (!MONADIC_INSTRUCTION(opcode)) {
120 		unsigned int Fn = getFn(opcode);
121 		floatx80 rFn;
122 
123 		switch (fpa11->fType[Fn]) {
124 		case typeSingle:
125 			rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
126 			break;
127 
128 		case typeDouble:
129 			rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
130 			break;
131 
132 		case typeExtended:
133 			rFn = fpa11->fpreg[Fn].fExtended;
134 			break;
135 
136 		default:
137 			return 0;
138 		}
139 
140 		if (dyadic_extended[opc_mask_shift]) {
141 			rFd->fExtended = dyadic_extended[opc_mask_shift](roundData, rFn, rFm);
142 		} else {
143 			return 0;
144 		}
145 	} else {
146 		if (monadic_extended[opc_mask_shift]) {
147 			rFd->fExtended = monadic_extended[opc_mask_shift](roundData, rFm);
148 		} else {
149 			return 0;
150 		}
151 	}
152 
153 	return 1;
154 }
155