xref: /openbmc/linux/arch/arm/nwfpe/double_cpdo.c (revision a36954f5)
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 union float64_components {
27 	float64 f64;
28 	unsigned int i[2];
29 };
30 
31 float64 float64_exp(float64 Fm);
32 float64 float64_ln(float64 Fm);
33 float64 float64_sin(float64 rFm);
34 float64 float64_cos(float64 rFm);
35 float64 float64_arcsin(float64 rFm);
36 float64 float64_arctan(float64 rFm);
37 float64 float64_log(float64 rFm);
38 float64 float64_tan(float64 rFm);
39 float64 float64_arccos(float64 rFm);
40 float64 float64_pow(float64 rFn, float64 rFm);
41 float64 float64_pol(float64 rFn, float64 rFm);
42 
43 static float64 float64_rsf(struct roundingData *roundData, float64 rFn, float64 rFm)
44 {
45 	return float64_sub(roundData, rFm, rFn);
46 }
47 
48 static float64 float64_rdv(struct roundingData *roundData, float64 rFn, float64 rFm)
49 {
50 	return float64_div(roundData, rFm, rFn);
51 }
52 
53 static float64 (*const dyadic_double[16])(struct roundingData*, float64 rFn, float64 rFm) = {
54 	[ADF_CODE >> 20] = float64_add,
55 	[MUF_CODE >> 20] = float64_mul,
56 	[SUF_CODE >> 20] = float64_sub,
57 	[RSF_CODE >> 20] = float64_rsf,
58 	[DVF_CODE >> 20] = float64_div,
59 	[RDF_CODE >> 20] = float64_rdv,
60 	[RMF_CODE >> 20] = float64_rem,
61 
62 	/* strictly, these opcodes should not be implemented */
63 	[FML_CODE >> 20] = float64_mul,
64 	[FDV_CODE >> 20] = float64_div,
65 	[FRD_CODE >> 20] = float64_rdv,
66 };
67 
68 static float64 float64_mvf(struct roundingData *roundData,float64 rFm)
69 {
70 	return rFm;
71 }
72 
73 static float64 float64_mnf(struct roundingData *roundData,float64 rFm)
74 {
75 	union float64_components u;
76 
77 	u.f64 = rFm;
78 #ifdef __ARMEB__
79 	u.i[0] ^= 0x80000000;
80 #else
81 	u.i[1] ^= 0x80000000;
82 #endif
83 
84 	return u.f64;
85 }
86 
87 static float64 float64_abs(struct roundingData *roundData,float64 rFm)
88 {
89 	union float64_components u;
90 
91 	u.f64 = rFm;
92 #ifdef __ARMEB__
93 	u.i[0] &= 0x7fffffff;
94 #else
95 	u.i[1] &= 0x7fffffff;
96 #endif
97 
98 	return u.f64;
99 }
100 
101 static float64 (*const monadic_double[16])(struct roundingData *, float64 rFm) = {
102 	[MVF_CODE >> 20] = float64_mvf,
103 	[MNF_CODE >> 20] = float64_mnf,
104 	[ABS_CODE >> 20] = float64_abs,
105 	[RND_CODE >> 20] = float64_round_to_int,
106 	[URD_CODE >> 20] = float64_round_to_int,
107 	[SQT_CODE >> 20] = float64_sqrt,
108 	[NRM_CODE >> 20] = float64_mvf,
109 };
110 
111 unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd)
112 {
113 	FPA11 *fpa11 = GET_FPA11();
114 	float64 rFm;
115 	unsigned int Fm, opc_mask_shift;
116 
117 	Fm = getFm(opcode);
118 	if (CONSTANT_FM(opcode)) {
119 		rFm = getDoubleConstant(Fm);
120 	} else {
121 		switch (fpa11->fType[Fm]) {
122 		case typeSingle:
123 			rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
124 			break;
125 
126 		case typeDouble:
127 			rFm = fpa11->fpreg[Fm].fDouble;
128 			break;
129 
130 		default:
131 			return 0;
132 		}
133 	}
134 
135 	opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
136 	if (!MONADIC_INSTRUCTION(opcode)) {
137 		unsigned int Fn = getFn(opcode);
138 		float64 rFn;
139 
140 		switch (fpa11->fType[Fn]) {
141 		case typeSingle:
142 			rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
143 			break;
144 
145 		case typeDouble:
146 			rFn = fpa11->fpreg[Fn].fDouble;
147 			break;
148 
149 		default:
150 			return 0;
151 		}
152 
153 		if (dyadic_double[opc_mask_shift]) {
154 			rFd->fDouble = dyadic_double[opc_mask_shift](roundData, rFn, rFm);
155 		} else {
156 			return 0;
157 		}
158 	} else {
159 		if (monadic_double[opc_mask_shift]) {
160 			rFd->fDouble = monadic_double[opc_mask_shift](roundData, rFm);
161 		} else {
162 			return 0;
163 		}
164 	}
165 
166 	return 1;
167 }
168