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