Linux Audio

Check our new training course

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