11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*---------------------------------------------------------------------------+
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |  reg_mul.c                                                                |
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |                                                                           |
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | Multiply one FPU_REG by another, put the result in a destination FPU_REG. |
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |                                                                           |
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | Copyright (C) 1992,1993,1997                                              |
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |                  E-mail   billm@suburbia.net                              |
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |                                                                           |
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | Returns the tag of the result if no exceptions or errors occurred.        |
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds |                                                                           |
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds +---------------------------------------------------------------------------*/
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*---------------------------------------------------------------------------+
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | The destination may be any FPU_REG, including one of the source FPU_REGs. |
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds +---------------------------------------------------------------------------*/
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "fpu_emu.h"
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "exception.h"
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "reg_constant.h"
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "fpu_system.h"
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  Multiply two registers to give a register result.
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  The sources are st(deststnr) and (b,tagb,signb).
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  The destination is st(deststnr).
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine must be called with non-empty source registers */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
313d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	FPU_REG *a = &st(deststnr);
323d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	FPU_REG *dest = a;
333d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	u_char taga = FPU_gettagi(deststnr);
343d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	u_char saved_sign = getsign(dest);
353d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	u_char sign = (getsign(a) ^ getsign(b));
363d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	int tag;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
383d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	if (!(taga | tagb)) {
393d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		/* Both regs Valid, this should be the most common case. */
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
413d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		tag =
423d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		    FPU_u_mul(a, b, dest, control_w, sign,
433d0d14f983b55a570b976976284df4c434af3223Ingo Molnar			      exponent(a) + exponent(b));
443d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		if (tag < 0) {
453d0d14f983b55a570b976976284df4c434af3223Ingo Molnar			setsign(dest, saved_sign);
463d0d14f983b55a570b976976284df4c434af3223Ingo Molnar			return tag;
473d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		}
483d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		FPU_settagi(deststnr, tag);
493d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return tag;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
523d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	if (taga == TAG_Special)
533d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		taga = FPU_Special(a);
543d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	if (tagb == TAG_Special)
553d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		tagb = FPU_Special(b);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
573d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
593d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
603d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		FPU_REG x, y;
613d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		if (denormal_operand() < 0)
623d0d14f983b55a570b976976284df4c434af3223Ingo Molnar			return FPU_Exception;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
643d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		FPU_to_exp16(a, &x);
653d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		FPU_to_exp16(b, &y);
663d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		tag = FPU_u_mul(&x, &y, dest, control_w, sign,
673d0d14f983b55a570b976976284df4c434af3223Ingo Molnar				exponent16(&x) + exponent16(&y));
683d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		if (tag < 0) {
693d0d14f983b55a570b976976284df4c434af3223Ingo Molnar			setsign(dest, saved_sign);
703d0d14f983b55a570b976976284df4c434af3223Ingo Molnar			return tag;
713d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		}
723d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		FPU_settagi(deststnr, tag);
733d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return tag;
743d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
753d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		if (((tagb == TW_Denormal) || (taga == TW_Denormal))
763d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		    && (denormal_operand() < 0))
773d0d14f983b55a570b976976284df4c434af3223Ingo Molnar			return FPU_Exception;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
793d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		/* Must have either both arguments == zero, or
803d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		   one valid and the other zero.
813d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		   The result is therefore zero. */
823d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
833d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		/* The 80486 book says that the answer is +0, but a real
843d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		   80486 behaves this way.
853d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		   IEEE-754 apparently says it should be this way. */
863d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		setsign(dest, sign);
873d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return TAG_Zero;
883d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	}
893d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	/* Must have infinities, NaNs, etc */
903d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
913d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return real_2op_NaN(b, tagb, deststnr, &st(0));
923d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	} else if (((taga == TW_Infinity) && (tagb == TAG_Zero))
933d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		   || ((tagb == TW_Infinity) && (taga == TAG_Zero))) {
943d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return arith_invalid(deststnr);	/* Zero*Infinity is invalid */
953d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	} else if (((taga == TW_Denormal) || (tagb == TW_Denormal))
963d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		   && (denormal_operand() < 0)) {
973d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return FPU_Exception;
983d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	} else if (taga == TW_Infinity) {
993d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		FPU_copy_to_regi(a, TAG_Special, deststnr);
1003d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		setsign(dest, sign);
1013d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return TAG_Special;
1023d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	} else if (tagb == TW_Infinity) {
1033d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		FPU_copy_to_regi(b, TAG_Special, deststnr);
1043d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		setsign(dest, sign);
1053d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return TAG_Special;
1063d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef PARANOID
1083d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	else {
1093d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		EXCEPTION(EX_INTERNAL | 0x102);
1103d0d14f983b55a570b976976284df4c434af3223Ingo Molnar		return FPU_Exception;
1113d0d14f983b55a570b976976284df4c434af3223Ingo Molnar	}
1123d0d14f983b55a570b976976284df4c434af3223Ingo Molnar#endif /* PARANOID */
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
116