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