|
|
1.1 root 1: /*
2: NetWinder Floating Point Emulator
3: (c) Rebel.COM, 1998,1999
4: (c) Philip Blundell, 1999
5:
6: Direct questions, comments to Scott Bambrough <[email protected]>
7:
8: This program is free software; you can redistribute it and/or modify
9: it under the terms of the GNU General Public License as published by
10: the Free Software Foundation; either version 2 of the License, or
11: (at your option) any later version.
12:
13: This program is distributed in the hope that it will be useful,
14: but WITHOUT ANY WARRANTY; without even the implied warranty of
15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: GNU General Public License for more details.
17:
18: You should have received a copy of the GNU General Public License
1.1.1.3 ! root 19: along with this program; if not, see <http://www.gnu.org/licenses/>.
1.1 root 20: */
21:
22: #include "fpa11.h"
23: #include "softfloat.h"
24: #include "fpopcode.h"
25: #include "fpa11.inl"
26: //#include "fpmodule.h"
27: //#include "fpmodule.inl"
28:
29: unsigned int PerformFLT(const unsigned int opcode);
30: unsigned int PerformFIX(const unsigned int opcode);
31:
32: static unsigned int
33: PerformComparison(const unsigned int opcode);
34:
35: unsigned int EmulateCPRT(const unsigned int opcode)
36: {
37: unsigned int nRc = 1;
38:
39: //printk("EmulateCPRT(0x%08x)\n",opcode);
40:
41: if (opcode & 0x800000)
42: {
43: /* This is some variant of a comparison (PerformComparison will
44: sort out which one). Since most of the other CPRT
45: instructions are oddball cases of some sort or other it makes
46: sense to pull this out into a fast path. */
47: return PerformComparison(opcode);
48: }
49:
50: /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
51: switch ((opcode & 0x700000) >> 20)
52: {
53: case FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
54: case FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
55:
56: case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
57: case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
58:
59: #if 0 /* We currently have no use for the FPCR, so there's no point
60: in emulating it. */
61: case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode)));
62: case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break;
63: #endif
64:
65: default: nRc = 0;
66: }
67:
68: return nRc;
69: }
70:
71: unsigned int PerformFLT(const unsigned int opcode)
72: {
73: FPA11 *fpa11 = GET_FPA11();
74:
75: unsigned int nRc = 1;
76: SetRoundingMode(opcode);
77:
78: switch (opcode & MASK_ROUNDING_PRECISION)
79: {
80: case ROUND_SINGLE:
81: {
82: fpa11->fType[getFn(opcode)] = typeSingle;
83: fpa11->fpreg[getFn(opcode)].fSingle =
84: int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
85: }
86: break;
87:
88: case ROUND_DOUBLE:
89: {
90: fpa11->fType[getFn(opcode)] = typeDouble;
91: fpa11->fpreg[getFn(opcode)].fDouble =
92: int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
93: }
94: break;
95:
96: case ROUND_EXTENDED:
97: {
98: fpa11->fType[getFn(opcode)] = typeExtended;
99: fpa11->fpreg[getFn(opcode)].fExtended =
100: int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
101: }
102: break;
103:
104: default: nRc = 0;
105: }
106:
107: return nRc;
108: }
109:
110: unsigned int PerformFIX(const unsigned int opcode)
111: {
112: FPA11 *fpa11 = GET_FPA11();
113: unsigned int nRc = 1;
114: unsigned int Fn = getFm(opcode);
115:
116: SetRoundingMode(opcode);
117:
118: switch (fpa11->fType[Fn])
119: {
120: case typeSingle:
121: {
122: writeRegister(getRd(opcode),
123: float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
124: }
125: break;
126:
127: case typeDouble:
128: {
129: //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
130: writeRegister(getRd(opcode),
131: float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
132: }
133: break;
134:
135: case typeExtended:
136: {
137: writeRegister(getRd(opcode),
138: floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
139: }
140: break;
141:
142: default: nRc = 0;
143: }
144:
145: return nRc;
146: }
147:
148:
1.1.1.2 root 149: static __inline unsigned int
1.1 root 150: PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
151: {
152: FPA11 *fpa11 = GET_FPA11();
153: unsigned int flags = 0;
154:
155: /* test for less than condition */
156: if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
157: {
158: flags |= CC_NEGATIVE;
159: }
160:
161: /* test for equal condition */
162: if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
163: {
164: flags |= CC_ZERO;
165: }
166:
167: /* test for greater than or equal condition */
168: if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
169: {
170: flags |= CC_CARRY;
171: }
172:
173: writeConditionCodes(flags);
174: return 1;
175: }
176:
177: /* This instruction sets the flags N, Z, C, V in the FPSR. */
178:
179: static unsigned int PerformComparison(const unsigned int opcode)
180: {
181: FPA11 *fpa11 = GET_FPA11();
182: unsigned int Fn, Fm;
183: floatx80 rFn, rFm;
184: int e_flag = opcode & 0x400000; /* 1 if CxFE */
185: int n_flag = opcode & 0x200000; /* 1 if CNxx */
186: unsigned int flags = 0;
187:
188: //printk("PerformComparison(0x%08x)\n",opcode);
189:
190: Fn = getFn(opcode);
191: Fm = getFm(opcode);
192:
193: /* Check for unordered condition and convert all operands to 80-bit
194: format.
195: ?? Might be some mileage in avoiding this conversion if possible.
196: Eg, if both operands are 32-bit, detect this and do a 32-bit
197: comparison (cheaper than an 80-bit one). */
198: switch (fpa11->fType[Fn])
199: {
200: case typeSingle:
201: //printk("single.\n");
202: if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
203: goto unordered;
204: rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
205: break;
206:
207: case typeDouble:
208: //printk("double.\n");
209: if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
210: goto unordered;
211: rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
212: break;
213:
214: case typeExtended:
215: //printk("extended.\n");
216: if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
217: goto unordered;
218: rFn = fpa11->fpreg[Fn].fExtended;
219: break;
220:
221: default: return 0;
222: }
223:
224: if (CONSTANT_FM(opcode))
225: {
226: //printk("Fm is a constant: #%d.\n",Fm);
227: rFm = getExtendedConstant(Fm);
228: if (floatx80_is_nan(rFm))
229: goto unordered;
230: }
231: else
232: {
233: //printk("Fm = r%d which contains a ",Fm);
234: switch (fpa11->fType[Fm])
235: {
236: case typeSingle:
237: //printk("single.\n");
238: if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
239: goto unordered;
240: rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
241: break;
242:
243: case typeDouble:
244: //printk("double.\n");
245: if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
246: goto unordered;
247: rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
248: break;
249:
250: case typeExtended:
251: //printk("extended.\n");
252: if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
253: goto unordered;
254: rFm = fpa11->fpreg[Fm].fExtended;
255: break;
256:
257: default: return 0;
258: }
259: }
260:
261: if (n_flag)
262: {
263: rFm.high ^= 0x8000;
264: }
265:
266: return PerformComparisonOperation(rFn,rFm);
267:
268: unordered:
269: /* ?? The FPA data sheet is pretty vague about this, in particular
270: about whether the non-E comparisons can ever raise exceptions.
271: This implementation is based on a combination of what it says in
272: the data sheet, observation of how the Acorn emulator actually
273: behaves (and how programs expect it to) and guesswork. */
274: flags |= CC_OVERFLOW;
275: flags &= ~(CC_ZERO | CC_NEGATIVE);
276:
277: if (BIT_AC & readFPSR()) flags |= CC_CARRY;
278:
279: if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
280:
281: writeConditionCodes(flags);
282: return 1;
283: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.