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