Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/*---------------------------------------------------------------------------+
  3 |  reg_divide.c                                                             |
  4 |                                                                           |
  5 | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
  6 |                                                                           |
  7 | Copyright (C) 1996                                                        |
  8 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  9 |                  E-mail   billm@jacobi.maths.monash.edu.au                |
 10 |                                                                           |
 11 |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
 12 |    one was raised, or -1 on internal error.                               |
 13 |                                                                           |
 14 +---------------------------------------------------------------------------*/
 15
 16/*---------------------------------------------------------------------------+
 17 | The destination may be any FPU_REG, including one of the source FPU_REGs. |
 18 +---------------------------------------------------------------------------*/
 19
 20#include "exception.h"
 21#include "reg_constant.h"
 22#include "fpu_emu.h"
 23#include "fpu_system.h"
 24
 25/*
 26  Divide one register by another and put the result into a third register.
 27  */
 28int FPU_div(int flags, int rm, int control_w)
 29{
 30	FPU_REG x, y;
 31	FPU_REG const *a, *b, *st0_ptr, *st_ptr;
 32	FPU_REG *dest;
 33	u_char taga, tagb, signa, signb, sign, saved_sign;
 34	int tag, deststnr;
 35
 36	if (flags & DEST_RM)
 37		deststnr = rm;
 38	else
 39		deststnr = 0;
 40
 41	if (flags & REV) {
 42		b = &st(0);
 43		st0_ptr = b;
 44		tagb = FPU_gettag0();
 45		if (flags & LOADED) {
 46			a = (FPU_REG *) rm;
 47			taga = flags & 0x0f;
 48		} else {
 49			a = &st(rm);
 50			st_ptr = a;
 51			taga = FPU_gettagi(rm);
 52		}
 53	} else {
 54		a = &st(0);
 55		st0_ptr = a;
 56		taga = FPU_gettag0();
 57		if (flags & LOADED) {
 58			b = (FPU_REG *) rm;
 59			tagb = flags & 0x0f;
 60		} else {
 61			b = &st(rm);
 62			st_ptr = b;
 63			tagb = FPU_gettagi(rm);
 64		}
 65	}
 66
 67	signa = getsign(a);
 68	signb = getsign(b);
 69
 70	sign = signa ^ signb;
 71
 72	dest = &st(deststnr);
 73	saved_sign = getsign(dest);
 74
 75	if (!(taga | tagb)) {
 76		/* Both regs Valid, this should be the most common case. */
 77		reg_copy(a, &x);
 78		reg_copy(b, &y);
 79		setpositive(&x);
 80		setpositive(&y);
 81		tag = FPU_u_div(&x, &y, dest, control_w, sign);
 82
 83		if (tag < 0)
 84			return tag;
 85
 86		FPU_settagi(deststnr, tag);
 87		return tag;
 88	}
 89
 90	if (taga == TAG_Special)
 91		taga = FPU_Special(a);
 92	if (tagb == TAG_Special)
 93		tagb = FPU_Special(b);
 94
 95	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
 96	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
 97	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
 98		if (denormal_operand() < 0)
 99			return FPU_Exception;
100
101		FPU_to_exp16(a, &x);
102		FPU_to_exp16(b, &y);
103		tag = FPU_u_div(&x, &y, dest, control_w, sign);
104		if (tag < 0)
105			return tag;
106
107		FPU_settagi(deststnr, tag);
108		return tag;
109	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
110		if (tagb != TAG_Zero) {
111			/* Want to find Zero/Valid */
112			if (tagb == TW_Denormal) {
113				if (denormal_operand() < 0)
114					return FPU_Exception;
115			}
116
117			/* The result is zero. */
118			FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
119			setsign(dest, sign);
120			return TAG_Zero;
121		}
122		/* We have an exception condition, either 0/0 or Valid/Zero. */
123		if (taga == TAG_Zero) {
124			/* 0/0 */
125			return arith_invalid(deststnr);
126		}
127		/* Valid/Zero */
128		return FPU_divide_by_zero(deststnr, sign);
129	}
130	/* Must have infinities, NaNs, etc */
131	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
132		if (flags & LOADED)
133			return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
134					    st0_ptr);
135
136		if (flags & DEST_RM) {
137			int tag;
138			tag = FPU_gettag0();
139			if (tag == TAG_Special)
140				tag = FPU_Special(st0_ptr);
141			return real_2op_NaN(st0_ptr, tag, rm,
142					    (flags & REV) ? st0_ptr : &st(rm));
143		} else {
144			int tag;
145			tag = FPU_gettagi(rm);
146			if (tag == TAG_Special)
147				tag = FPU_Special(&st(rm));
148			return real_2op_NaN(&st(rm), tag, 0,
149					    (flags & REV) ? st0_ptr : &st(rm));
150		}
151	} else if (taga == TW_Infinity) {
152		if (tagb == TW_Infinity) {
153			/* infinity/infinity */
154			return arith_invalid(deststnr);
155		} else {
156			/* tagb must be Valid or Zero */
157			if ((tagb == TW_Denormal) && (denormal_operand() < 0))
158				return FPU_Exception;
159
160			/* Infinity divided by Zero or Valid does
161			   not raise and exception, but returns Infinity */
162			FPU_copy_to_regi(a, TAG_Special, deststnr);
163			setsign(dest, sign);
164			return taga;
165		}
166	} else if (tagb == TW_Infinity) {
167		if ((taga == TW_Denormal) && (denormal_operand() < 0))
168			return FPU_Exception;
169
170		/* The result is zero. */
171		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
172		setsign(dest, sign);
173		return TAG_Zero;
174	}
175#ifdef PARANOID
176	else {
177		EXCEPTION(EX_INTERNAL | 0x102);
178		return FPU_Exception;
179	}
180#endif /* PARANOID */
181
182	return 0;
183}
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2/*---------------------------------------------------------------------------+
  3 |  reg_divide.c                                                             |
  4 |                                                                           |
  5 | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
  6 |                                                                           |
  7 | Copyright (C) 1996                                                        |
  8 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  9 |                  E-mail   billm@jacobi.maths.monash.edu.au                |
 10 |                                                                           |
 11 |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
 12 |    one was raised, or -1 on internal error.                               |
 13 |                                                                           |
 14 +---------------------------------------------------------------------------*/
 15
 16/*---------------------------------------------------------------------------+
 17 | The destination may be any FPU_REG, including one of the source FPU_REGs. |
 18 +---------------------------------------------------------------------------*/
 19
 20#include "exception.h"
 21#include "reg_constant.h"
 22#include "fpu_emu.h"
 23#include "fpu_system.h"
 24
 25/*
 26  Divide one register by another and put the result into a third register.
 27  */
 28int FPU_div(int flags, int rm, int control_w)
 29{
 30	FPU_REG x, y;
 31	FPU_REG const *a, *b, *st0_ptr, *st_ptr;
 32	FPU_REG *dest;
 33	u_char taga, tagb, signa, signb, sign, saved_sign;
 34	int tag, deststnr;
 35
 36	if (flags & DEST_RM)
 37		deststnr = rm;
 38	else
 39		deststnr = 0;
 40
 41	if (flags & REV) {
 42		b = &st(0);
 43		st0_ptr = b;
 44		tagb = FPU_gettag0();
 45		if (flags & LOADED) {
 46			a = (FPU_REG *) rm;
 47			taga = flags & 0x0f;
 48		} else {
 49			a = &st(rm);
 50			st_ptr = a;
 51			taga = FPU_gettagi(rm);
 52		}
 53	} else {
 54		a = &st(0);
 55		st0_ptr = a;
 56		taga = FPU_gettag0();
 57		if (flags & LOADED) {
 58			b = (FPU_REG *) rm;
 59			tagb = flags & 0x0f;
 60		} else {
 61			b = &st(rm);
 62			st_ptr = b;
 63			tagb = FPU_gettagi(rm);
 64		}
 65	}
 66
 67	signa = getsign(a);
 68	signb = getsign(b);
 69
 70	sign = signa ^ signb;
 71
 72	dest = &st(deststnr);
 73	saved_sign = getsign(dest);
 74
 75	if (!(taga | tagb)) {
 76		/* Both regs Valid, this should be the most common case. */
 77		reg_copy(a, &x);
 78		reg_copy(b, &y);
 79		setpositive(&x);
 80		setpositive(&y);
 81		tag = FPU_u_div(&x, &y, dest, control_w, sign);
 82
 83		if (tag < 0)
 84			return tag;
 85
 86		FPU_settagi(deststnr, tag);
 87		return tag;
 88	}
 89
 90	if (taga == TAG_Special)
 91		taga = FPU_Special(a);
 92	if (tagb == TAG_Special)
 93		tagb = FPU_Special(b);
 94
 95	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
 96	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
 97	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
 98		if (denormal_operand() < 0)
 99			return FPU_Exception;
100
101		FPU_to_exp16(a, &x);
102		FPU_to_exp16(b, &y);
103		tag = FPU_u_div(&x, &y, dest, control_w, sign);
104		if (tag < 0)
105			return tag;
106
107		FPU_settagi(deststnr, tag);
108		return tag;
109	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
110		if (tagb != TAG_Zero) {
111			/* Want to find Zero/Valid */
112			if (tagb == TW_Denormal) {
113				if (denormal_operand() < 0)
114					return FPU_Exception;
115			}
116
117			/* The result is zero. */
118			FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
119			setsign(dest, sign);
120			return TAG_Zero;
121		}
122		/* We have an exception condition, either 0/0 or Valid/Zero. */
123		if (taga == TAG_Zero) {
124			/* 0/0 */
125			return arith_invalid(deststnr);
126		}
127		/* Valid/Zero */
128		return FPU_divide_by_zero(deststnr, sign);
129	}
130	/* Must have infinities, NaNs, etc */
131	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
132		if (flags & LOADED)
133			return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
134					    st0_ptr);
135
136		if (flags & DEST_RM) {
137			int tag;
138			tag = FPU_gettag0();
139			if (tag == TAG_Special)
140				tag = FPU_Special(st0_ptr);
141			return real_2op_NaN(st0_ptr, tag, rm,
142					    (flags & REV) ? st0_ptr : &st(rm));
143		} else {
144			int tag;
145			tag = FPU_gettagi(rm);
146			if (tag == TAG_Special)
147				tag = FPU_Special(&st(rm));
148			return real_2op_NaN(&st(rm), tag, 0,
149					    (flags & REV) ? st0_ptr : &st(rm));
150		}
151	} else if (taga == TW_Infinity) {
152		if (tagb == TW_Infinity) {
153			/* infinity/infinity */
154			return arith_invalid(deststnr);
155		} else {
156			/* tagb must be Valid or Zero */
157			if ((tagb == TW_Denormal) && (denormal_operand() < 0))
158				return FPU_Exception;
159
160			/* Infinity divided by Zero or Valid does
161			   not raise and exception, but returns Infinity */
162			FPU_copy_to_regi(a, TAG_Special, deststnr);
163			setsign(dest, sign);
164			return taga;
165		}
166	} else if (tagb == TW_Infinity) {
167		if ((taga == TW_Denormal) && (denormal_operand() < 0))
168			return FPU_Exception;
169
170		/* The result is zero. */
171		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
172		setsign(dest, sign);
173		return TAG_Zero;
174	}
175#ifdef PARANOID
176	else {
177		EXCEPTION(EX_INTERNAL | 0x102);
178		return FPU_Exception;
179	}
180#endif /* PARANOID */
181
182	return 0;
183}