Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3    NetWinder Floating Point Emulator
  4    (c) Rebel.COM, 1998,1999
  5    (c) Philip Blundell, 1999, 2001
  6
  7    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
  8
  9*/
 10
 11#include "fpa11.h"
 12#include "fpopcode.h"
 13#include "fpa11.inl"
 14#include "fpmodule.h"
 15#include "fpmodule.inl"
 16#include "softfloat.h"
 17
 18unsigned int PerformFLT(const unsigned int opcode);
 19unsigned int PerformFIX(const unsigned int opcode);
 20
 21static unsigned int PerformComparison(const unsigned int opcode);
 22
 23unsigned int EmulateCPRT(const unsigned int opcode)
 24{
 25
 26	if (opcode & 0x800000) {
 27		/* This is some variant of a comparison (PerformComparison
 28		   will sort out which one).  Since most of the other CPRT
 29		   instructions are oddball cases of some sort or other it
 30		   makes sense to pull this out into a fast path.  */
 31		return PerformComparison(opcode);
 32	}
 33
 34	/* Hint to GCC that we'd like a jump table rather than a load of CMPs */
 35	switch ((opcode & 0x700000) >> 20) {
 36	case FLT_CODE >> 20:
 37		return PerformFLT(opcode);
 38		break;
 39	case FIX_CODE >> 20:
 40		return PerformFIX(opcode);
 41		break;
 42
 43	case WFS_CODE >> 20:
 44		writeFPSR(readRegister(getRd(opcode)));
 45		break;
 46	case RFS_CODE >> 20:
 47		writeRegister(getRd(opcode), readFPSR());
 48		break;
 49
 50	default:
 51		return 0;
 52	}
 53
 54	return 1;
 55}
 56
 57unsigned int PerformFLT(const unsigned int opcode)
 58{
 59	FPA11 *fpa11 = GET_FPA11();
 60	struct roundingData roundData;
 61
 62	roundData.mode = SetRoundingMode(opcode);
 63	roundData.precision = SetRoundingPrecision(opcode);
 64	roundData.exception = 0;
 65
 66	switch (opcode & MASK_ROUNDING_PRECISION) {
 67	case ROUND_SINGLE:
 68		{
 69			fpa11->fType[getFn(opcode)] = typeSingle;
 70			fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
 71		}
 72		break;
 73
 74	case ROUND_DOUBLE:
 75		{
 76			fpa11->fType[getFn(opcode)] = typeDouble;
 77			fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
 78		}
 79		break;
 80
 81#ifdef CONFIG_FPE_NWFPE_XP
 82	case ROUND_EXTENDED:
 83		{
 84			fpa11->fType[getFn(opcode)] = typeExtended;
 85			fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
 86		}
 87		break;
 88#endif
 89
 90	default:
 91		return 0;
 92	}
 93
 94	if (roundData.exception)
 95		float_raise(roundData.exception);
 96
 97	return 1;
 98}
 99
100unsigned int PerformFIX(const unsigned int opcode)
101{
102	FPA11 *fpa11 = GET_FPA11();
103	unsigned int Fn = getFm(opcode);
104	struct roundingData roundData;
105
106	roundData.mode = SetRoundingMode(opcode);
107	roundData.precision = SetRoundingPrecision(opcode);
108	roundData.exception = 0;
109
110	switch (fpa11->fType[Fn]) {
111	case typeSingle:
112		{
113			writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
114		}
115		break;
116
117	case typeDouble:
118		{
119			writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
120		}
121		break;
122
123#ifdef CONFIG_FPE_NWFPE_XP
124	case typeExtended:
125		{
126			writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
127		}
128		break;
129#endif
130
131	default:
132		return 0;
133	}
134
135	if (roundData.exception)
136		float_raise(roundData.exception);
137
138	return 1;
139}
140
141/* This instruction sets the flags N, Z, C, V in the FPSR. */
142static unsigned int PerformComparison(const unsigned int opcode)
143{
144	FPA11 *fpa11 = GET_FPA11();
145	unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
146	int e_flag = opcode & 0x400000;	/* 1 if CxFE */
147	int n_flag = opcode & 0x200000;	/* 1 if CNxx */
148	unsigned int flags = 0;
149
150#ifdef CONFIG_FPE_NWFPE_XP
151	floatx80 rFn, rFm;
152
153	/* Check for unordered condition and convert all operands to 80-bit
154	   format.
155	   ?? Might be some mileage in avoiding this conversion if possible.
156	   Eg, if both operands are 32-bit, detect this and do a 32-bit
157	   comparison (cheaper than an 80-bit one).  */
158	switch (fpa11->fType[Fn]) {
159	case typeSingle:
160		//printk("single.\n");
161		if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
162			goto unordered;
163		rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
164		break;
165
166	case typeDouble:
167		//printk("double.\n");
168		if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
169			goto unordered;
170		rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
171		break;
172
173	case typeExtended:
174		//printk("extended.\n");
175		if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
176			goto unordered;
177		rFn = fpa11->fpreg[Fn].fExtended;
178		break;
179
180	default:
181		return 0;
182	}
183
184	if (CONSTANT_FM(opcode)) {
185		//printk("Fm is a constant: #%d.\n",Fm);
186		rFm = getExtendedConstant(Fm);
187		if (floatx80_is_nan(rFm))
188			goto unordered;
189	} else {
190		//printk("Fm = r%d which contains a ",Fm);
191		switch (fpa11->fType[Fm]) {
192		case typeSingle:
193			//printk("single.\n");
194			if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
195				goto unordered;
196			rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
197			break;
198
199		case typeDouble:
200			//printk("double.\n");
201			if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
202				goto unordered;
203			rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
204			break;
205
206		case typeExtended:
207			//printk("extended.\n");
208			if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
209				goto unordered;
210			rFm = fpa11->fpreg[Fm].fExtended;
211			break;
212
213		default:
214			return 0;
215		}
216	}
217
218	if (n_flag)
219		rFm.high ^= 0x8000;
220
221	/* test for less than condition */
222	if (floatx80_lt(rFn, rFm))
223		flags |= CC_NEGATIVE;
224
225	/* test for equal condition */
226	if (floatx80_eq(rFn, rFm))
227		flags |= CC_ZERO;
228
229	/* test for greater than or equal condition */
230	if (floatx80_lt(rFm, rFn))
231		flags |= CC_CARRY;
232
233#else
234	if (CONSTANT_FM(opcode)) {
235		/* Fm is a constant.  Do the comparison in whatever precision
236		   Fn happens to be stored in.  */
237		if (fpa11->fType[Fn] == typeSingle) {
238			float32 rFm = getSingleConstant(Fm);
239			float32 rFn = fpa11->fpreg[Fn].fSingle;
240
241			if (float32_is_nan(rFn))
242				goto unordered;
243
244			if (n_flag)
245				rFm ^= 0x80000000;
246
247			/* test for less than condition */
248			if (float32_lt_nocheck(rFn, rFm))
249				flags |= CC_NEGATIVE;
250
251			/* test for equal condition */
252			if (float32_eq_nocheck(rFn, rFm))
253				flags |= CC_ZERO;
254
255			/* test for greater than or equal condition */
256			if (float32_lt_nocheck(rFm, rFn))
257				flags |= CC_CARRY;
258		} else {
259			float64 rFm = getDoubleConstant(Fm);
260			float64 rFn = fpa11->fpreg[Fn].fDouble;
261
262			if (float64_is_nan(rFn))
263				goto unordered;
264
265			if (n_flag)
266				rFm ^= 0x8000000000000000ULL;
267
268			/* test for less than condition */
269			if (float64_lt_nocheck(rFn, rFm))
270				flags |= CC_NEGATIVE;
271
272			/* test for equal condition */
273			if (float64_eq_nocheck(rFn, rFm))
274				flags |= CC_ZERO;
275
276			/* test for greater than or equal condition */
277			if (float64_lt_nocheck(rFm, rFn))
278				flags |= CC_CARRY;
279		}
280	} else {
281		/* Both operands are in registers.  */
282		if (fpa11->fType[Fn] == typeSingle
283		    && fpa11->fType[Fm] == typeSingle) {
284			float32 rFm = fpa11->fpreg[Fm].fSingle;
285			float32 rFn = fpa11->fpreg[Fn].fSingle;
286
287			if (float32_is_nan(rFn)
288			    || float32_is_nan(rFm))
289				goto unordered;
290
291			if (n_flag)
292				rFm ^= 0x80000000;
293
294			/* test for less than condition */
295			if (float32_lt_nocheck(rFn, rFm))
296				flags |= CC_NEGATIVE;
297
298			/* test for equal condition */
299			if (float32_eq_nocheck(rFn, rFm))
300				flags |= CC_ZERO;
301
302			/* test for greater than or equal condition */
303			if (float32_lt_nocheck(rFm, rFn))
304				flags |= CC_CARRY;
305		} else {
306			/* Promote 32-bit operand to 64 bits.  */
307			float64 rFm, rFn;
308
309			rFm = (fpa11->fType[Fm] == typeSingle) ?
310			    float32_to_float64(fpa11->fpreg[Fm].fSingle)
311			    : fpa11->fpreg[Fm].fDouble;
312
313			rFn = (fpa11->fType[Fn] == typeSingle) ?
314			    float32_to_float64(fpa11->fpreg[Fn].fSingle)
315			    : fpa11->fpreg[Fn].fDouble;
316
317			if (float64_is_nan(rFn)
318			    || float64_is_nan(rFm))
319				goto unordered;
320
321			if (n_flag)
322				rFm ^= 0x8000000000000000ULL;
323
324			/* test for less than condition */
325			if (float64_lt_nocheck(rFn, rFm))
326				flags |= CC_NEGATIVE;
327
328			/* test for equal condition */
329			if (float64_eq_nocheck(rFn, rFm))
330				flags |= CC_ZERO;
331
332			/* test for greater than or equal condition */
333			if (float64_lt_nocheck(rFm, rFn))
334				flags |= CC_CARRY;
335		}
336	}
337
338#endif
339
340	writeConditionCodes(flags);
341
342	return 1;
343
344      unordered:
345	/* ?? The FPA data sheet is pretty vague about this, in particular
346	   about whether the non-E comparisons can ever raise exceptions.
347	   This implementation is based on a combination of what it says in
348	   the data sheet, observation of how the Acorn emulator actually
349	   behaves (and how programs expect it to) and guesswork.  */
350	flags |= CC_OVERFLOW;
351	flags &= ~(CC_ZERO | CC_NEGATIVE);
352
353	if (BIT_AC & readFPSR())
354		flags |= CC_CARRY;
355
356	if (e_flag)
357		float_raise(float_flag_invalid);
358
359	writeConditionCodes(flags);
360	return 1;
361}
v6.8
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3    NetWinder Floating Point Emulator
  4    (c) Rebel.COM, 1998,1999
  5    (c) Philip Blundell, 1999, 2001
  6
  7    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
  8
  9*/
 10
 11#include "fpa11.h"
 12#include "fpopcode.h"
 13#include "fpa11.inl"
 14#include "fpmodule.h"
 15#include "fpmodule.inl"
 16#include "softfloat.h"
 17
 18unsigned int PerformFLT(const unsigned int opcode);
 19unsigned int PerformFIX(const unsigned int opcode);
 20
 21static unsigned int PerformComparison(const unsigned int opcode);
 22
 23unsigned int EmulateCPRT(const unsigned int opcode)
 24{
 25
 26	if (opcode & 0x800000) {
 27		/* This is some variant of a comparison (PerformComparison
 28		   will sort out which one).  Since most of the other CPRT
 29		   instructions are oddball cases of some sort or other it
 30		   makes sense to pull this out into a fast path.  */
 31		return PerformComparison(opcode);
 32	}
 33
 34	/* Hint to GCC that we'd like a jump table rather than a load of CMPs */
 35	switch ((opcode & 0x700000) >> 20) {
 36	case FLT_CODE >> 20:
 37		return PerformFLT(opcode);
 38		break;
 39	case FIX_CODE >> 20:
 40		return PerformFIX(opcode);
 41		break;
 42
 43	case WFS_CODE >> 20:
 44		writeFPSR(readRegister(getRd(opcode)));
 45		break;
 46	case RFS_CODE >> 20:
 47		writeRegister(getRd(opcode), readFPSR());
 48		break;
 49
 50	default:
 51		return 0;
 52	}
 53
 54	return 1;
 55}
 56
 57unsigned int PerformFLT(const unsigned int opcode)
 58{
 59	FPA11 *fpa11 = GET_FPA11();
 60	struct roundingData roundData;
 61
 62	roundData.mode = SetRoundingMode(opcode);
 63	roundData.precision = SetRoundingPrecision(opcode);
 64	roundData.exception = 0;
 65
 66	switch (opcode & MASK_ROUNDING_PRECISION) {
 67	case ROUND_SINGLE:
 68		{
 69			fpa11->fType[getFn(opcode)] = typeSingle;
 70			fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
 71		}
 72		break;
 73
 74	case ROUND_DOUBLE:
 75		{
 76			fpa11->fType[getFn(opcode)] = typeDouble;
 77			fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
 78		}
 79		break;
 80
 81#ifdef CONFIG_FPE_NWFPE_XP
 82	case ROUND_EXTENDED:
 83		{
 84			fpa11->fType[getFn(opcode)] = typeExtended;
 85			fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
 86		}
 87		break;
 88#endif
 89
 90	default:
 91		return 0;
 92	}
 93
 94	if (roundData.exception)
 95		float_raise(roundData.exception);
 96
 97	return 1;
 98}
 99
100unsigned int PerformFIX(const unsigned int opcode)
101{
102	FPA11 *fpa11 = GET_FPA11();
103	unsigned int Fn = getFm(opcode);
104	struct roundingData roundData;
105
106	roundData.mode = SetRoundingMode(opcode);
107	roundData.precision = SetRoundingPrecision(opcode);
108	roundData.exception = 0;
109
110	switch (fpa11->fType[Fn]) {
111	case typeSingle:
112		{
113			writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
114		}
115		break;
116
117	case typeDouble:
118		{
119			writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
120		}
121		break;
122
123#ifdef CONFIG_FPE_NWFPE_XP
124	case typeExtended:
125		{
126			writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
127		}
128		break;
129#endif
130
131	default:
132		return 0;
133	}
134
135	if (roundData.exception)
136		float_raise(roundData.exception);
137
138	return 1;
139}
140
141/* This instruction sets the flags N, Z, C, V in the FPSR. */
142static unsigned int PerformComparison(const unsigned int opcode)
143{
144	FPA11 *fpa11 = GET_FPA11();
145	unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
146	int e_flag = opcode & 0x400000;	/* 1 if CxFE */
147	int n_flag = opcode & 0x200000;	/* 1 if CNxx */
148	unsigned int flags = 0;
149
150#ifdef CONFIG_FPE_NWFPE_XP
151	floatx80 rFn, rFm;
152
153	/* Check for unordered condition and convert all operands to 80-bit
154	   format.
155	   ?? Might be some mileage in avoiding this conversion if possible.
156	   Eg, if both operands are 32-bit, detect this and do a 32-bit
157	   comparison (cheaper than an 80-bit one).  */
158	switch (fpa11->fType[Fn]) {
159	case typeSingle:
160		//printk("single.\n");
161		if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
162			goto unordered;
163		rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
164		break;
165
166	case typeDouble:
167		//printk("double.\n");
168		if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
169			goto unordered;
170		rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
171		break;
172
173	case typeExtended:
174		//printk("extended.\n");
175		if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
176			goto unordered;
177		rFn = fpa11->fpreg[Fn].fExtended;
178		break;
179
180	default:
181		return 0;
182	}
183
184	if (CONSTANT_FM(opcode)) {
185		//printk("Fm is a constant: #%d.\n",Fm);
186		rFm = getExtendedConstant(Fm);
187		if (floatx80_is_nan(rFm))
188			goto unordered;
189	} else {
190		//printk("Fm = r%d which contains a ",Fm);
191		switch (fpa11->fType[Fm]) {
192		case typeSingle:
193			//printk("single.\n");
194			if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
195				goto unordered;
196			rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
197			break;
198
199		case typeDouble:
200			//printk("double.\n");
201			if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
202				goto unordered;
203			rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
204			break;
205
206		case typeExtended:
207			//printk("extended.\n");
208			if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
209				goto unordered;
210			rFm = fpa11->fpreg[Fm].fExtended;
211			break;
212
213		default:
214			return 0;
215		}
216	}
217
218	if (n_flag)
219		rFm.high ^= 0x8000;
220
221	/* test for less than condition */
222	if (floatx80_lt(rFn, rFm))
223		flags |= CC_NEGATIVE;
224
225	/* test for equal condition */
226	if (floatx80_eq(rFn, rFm))
227		flags |= CC_ZERO;
228
229	/* test for greater than or equal condition */
230	if (floatx80_lt(rFm, rFn))
231		flags |= CC_CARRY;
232
233#else
234	if (CONSTANT_FM(opcode)) {
235		/* Fm is a constant.  Do the comparison in whatever precision
236		   Fn happens to be stored in.  */
237		if (fpa11->fType[Fn] == typeSingle) {
238			float32 rFm = getSingleConstant(Fm);
239			float32 rFn = fpa11->fpreg[Fn].fSingle;
240
241			if (float32_is_nan(rFn))
242				goto unordered;
243
244			if (n_flag)
245				rFm ^= 0x80000000;
246
247			/* test for less than condition */
248			if (float32_lt_nocheck(rFn, rFm))
249				flags |= CC_NEGATIVE;
250
251			/* test for equal condition */
252			if (float32_eq_nocheck(rFn, rFm))
253				flags |= CC_ZERO;
254
255			/* test for greater than or equal condition */
256			if (float32_lt_nocheck(rFm, rFn))
257				flags |= CC_CARRY;
258		} else {
259			float64 rFm = getDoubleConstant(Fm);
260			float64 rFn = fpa11->fpreg[Fn].fDouble;
261
262			if (float64_is_nan(rFn))
263				goto unordered;
264
265			if (n_flag)
266				rFm ^= 0x8000000000000000ULL;
267
268			/* test for less than condition */
269			if (float64_lt_nocheck(rFn, rFm))
270				flags |= CC_NEGATIVE;
271
272			/* test for equal condition */
273			if (float64_eq_nocheck(rFn, rFm))
274				flags |= CC_ZERO;
275
276			/* test for greater than or equal condition */
277			if (float64_lt_nocheck(rFm, rFn))
278				flags |= CC_CARRY;
279		}
280	} else {
281		/* Both operands are in registers.  */
282		if (fpa11->fType[Fn] == typeSingle
283		    && fpa11->fType[Fm] == typeSingle) {
284			float32 rFm = fpa11->fpreg[Fm].fSingle;
285			float32 rFn = fpa11->fpreg[Fn].fSingle;
286
287			if (float32_is_nan(rFn)
288			    || float32_is_nan(rFm))
289				goto unordered;
290
291			if (n_flag)
292				rFm ^= 0x80000000;
293
294			/* test for less than condition */
295			if (float32_lt_nocheck(rFn, rFm))
296				flags |= CC_NEGATIVE;
297
298			/* test for equal condition */
299			if (float32_eq_nocheck(rFn, rFm))
300				flags |= CC_ZERO;
301
302			/* test for greater than or equal condition */
303			if (float32_lt_nocheck(rFm, rFn))
304				flags |= CC_CARRY;
305		} else {
306			/* Promote 32-bit operand to 64 bits.  */
307			float64 rFm, rFn;
308
309			rFm = (fpa11->fType[Fm] == typeSingle) ?
310			    float32_to_float64(fpa11->fpreg[Fm].fSingle)
311			    : fpa11->fpreg[Fm].fDouble;
312
313			rFn = (fpa11->fType[Fn] == typeSingle) ?
314			    float32_to_float64(fpa11->fpreg[Fn].fSingle)
315			    : fpa11->fpreg[Fn].fDouble;
316
317			if (float64_is_nan(rFn)
318			    || float64_is_nan(rFm))
319				goto unordered;
320
321			if (n_flag)
322				rFm ^= 0x8000000000000000ULL;
323
324			/* test for less than condition */
325			if (float64_lt_nocheck(rFn, rFm))
326				flags |= CC_NEGATIVE;
327
328			/* test for equal condition */
329			if (float64_eq_nocheck(rFn, rFm))
330				flags |= CC_ZERO;
331
332			/* test for greater than or equal condition */
333			if (float64_lt_nocheck(rFm, rFn))
334				flags |= CC_CARRY;
335		}
336	}
337
338#endif
339
340	writeConditionCodes(flags);
341
342	return 1;
343
344      unordered:
345	/* ?? The FPA data sheet is pretty vague about this, in particular
346	   about whether the non-E comparisons can ever raise exceptions.
347	   This implementation is based on a combination of what it says in
348	   the data sheet, observation of how the Acorn emulator actually
349	   behaves (and how programs expect it to) and guesswork.  */
350	flags |= CC_OVERFLOW;
351	flags &= ~(CC_ZERO | CC_NEGATIVE);
352
353	if (BIT_AC & readFPSR())
354		flags |= CC_CARRY;
355
356	if (e_flag)
357		float_raise(float_flag_invalid);
358
359	writeConditionCodes(flags);
360	return 1;
361}