cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

reg_divide.c (5030B)


      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}