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

fp_arith.c (14665B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3
      4   fp_arith.c: floating-point math routines for the Linux-m68k
      5   floating point emulator.
      6
      7   Copyright (c) 1998-1999 David Huggins-Daines.
      8
      9   Somewhat based on the AlphaLinux floating point emulator, by David
     10   Mosberger-Tang.
     11
     12 */
     13
     14#include "fp_emu.h"
     15#include "multi_arith.h"
     16#include "fp_arith.h"
     17
     18const struct fp_ext fp_QNaN =
     19{
     20	.exp = 0x7fff,
     21	.mant = { .m64 = ~0 }
     22};
     23
     24const struct fp_ext fp_Inf =
     25{
     26	.exp = 0x7fff,
     27};
     28
     29/* let's start with the easy ones */
     30
     31struct fp_ext *
     32fp_fabs(struct fp_ext *dest, struct fp_ext *src)
     33{
     34	dprint(PINSTR, "fabs\n");
     35
     36	fp_monadic_check(dest, src);
     37
     38	dest->sign = 0;
     39
     40	return dest;
     41}
     42
     43struct fp_ext *
     44fp_fneg(struct fp_ext *dest, struct fp_ext *src)
     45{
     46	dprint(PINSTR, "fneg\n");
     47
     48	fp_monadic_check(dest, src);
     49
     50	dest->sign = !dest->sign;
     51
     52	return dest;
     53}
     54
     55/* Now, the slightly harder ones */
     56
     57/* fp_fadd: Implements the kernel of the FADD, FSADD, FDADD, FSUB,
     58   FDSUB, and FCMP instructions. */
     59
     60struct fp_ext *
     61fp_fadd(struct fp_ext *dest, struct fp_ext *src)
     62{
     63	int diff;
     64
     65	dprint(PINSTR, "fadd\n");
     66
     67	fp_dyadic_check(dest, src);
     68
     69	if (IS_INF(dest)) {
     70		/* infinity - infinity == NaN */
     71		if (IS_INF(src) && (src->sign != dest->sign))
     72			fp_set_nan(dest);
     73		return dest;
     74	}
     75	if (IS_INF(src)) {
     76		fp_copy_ext(dest, src);
     77		return dest;
     78	}
     79
     80	if (IS_ZERO(dest)) {
     81		if (IS_ZERO(src)) {
     82			if (src->sign != dest->sign) {
     83				if (FPDATA->rnd == FPCR_ROUND_RM)
     84					dest->sign = 1;
     85				else
     86					dest->sign = 0;
     87			}
     88		} else
     89			fp_copy_ext(dest, src);
     90		return dest;
     91	}
     92
     93	dest->lowmant = src->lowmant = 0;
     94
     95	if ((diff = dest->exp - src->exp) > 0)
     96		fp_denormalize(src, diff);
     97	else if ((diff = -diff) > 0)
     98		fp_denormalize(dest, diff);
     99
    100	if (dest->sign == src->sign) {
    101		if (fp_addmant(dest, src))
    102			if (!fp_addcarry(dest))
    103				return dest;
    104	} else {
    105		if (dest->mant.m64 < src->mant.m64) {
    106			fp_submant(dest, src, dest);
    107			dest->sign = !dest->sign;
    108		} else
    109			fp_submant(dest, dest, src);
    110	}
    111
    112	return dest;
    113}
    114
    115/* fp_fsub: Implements the kernel of the FSUB, FSSUB, and FDSUB
    116   instructions.
    117
    118   Remember that the arguments are in assembler-syntax order! */
    119
    120struct fp_ext *
    121fp_fsub(struct fp_ext *dest, struct fp_ext *src)
    122{
    123	dprint(PINSTR, "fsub ");
    124
    125	src->sign = !src->sign;
    126	return fp_fadd(dest, src);
    127}
    128
    129
    130struct fp_ext *
    131fp_fcmp(struct fp_ext *dest, struct fp_ext *src)
    132{
    133	dprint(PINSTR, "fcmp ");
    134
    135	FPDATA->temp[1] = *dest;
    136	src->sign = !src->sign;
    137	return fp_fadd(&FPDATA->temp[1], src);
    138}
    139
    140struct fp_ext *
    141fp_ftst(struct fp_ext *dest, struct fp_ext *src)
    142{
    143	dprint(PINSTR, "ftst\n");
    144
    145	(void)dest;
    146
    147	return src;
    148}
    149
    150struct fp_ext *
    151fp_fmul(struct fp_ext *dest, struct fp_ext *src)
    152{
    153	union fp_mant128 temp;
    154	int exp;
    155
    156	dprint(PINSTR, "fmul\n");
    157
    158	fp_dyadic_check(dest, src);
    159
    160	/* calculate the correct sign now, as it's necessary for infinities */
    161	dest->sign = src->sign ^ dest->sign;
    162
    163	/* Handle infinities */
    164	if (IS_INF(dest)) {
    165		if (IS_ZERO(src))
    166			fp_set_nan(dest);
    167		return dest;
    168	}
    169	if (IS_INF(src)) {
    170		if (IS_ZERO(dest))
    171			fp_set_nan(dest);
    172		else
    173			fp_copy_ext(dest, src);
    174		return dest;
    175	}
    176
    177	/* Of course, as we all know, zero * anything = zero.  You may
    178	   not have known that it might be a positive or negative
    179	   zero... */
    180	if (IS_ZERO(dest) || IS_ZERO(src)) {
    181		dest->exp = 0;
    182		dest->mant.m64 = 0;
    183		dest->lowmant = 0;
    184
    185		return dest;
    186	}
    187
    188	exp = dest->exp + src->exp - 0x3ffe;
    189
    190	/* shift up the mantissa for denormalized numbers,
    191	   so that the highest bit is set, this makes the
    192	   shift of the result below easier */
    193	if ((long)dest->mant.m32[0] >= 0)
    194		exp -= fp_overnormalize(dest);
    195	if ((long)src->mant.m32[0] >= 0)
    196		exp -= fp_overnormalize(src);
    197
    198	/* now, do a 64-bit multiply with expansion */
    199	fp_multiplymant(&temp, dest, src);
    200
    201	/* normalize it back to 64 bits and stuff it back into the
    202	   destination struct */
    203	if ((long)temp.m32[0] > 0) {
    204		exp--;
    205		fp_putmant128(dest, &temp, 1);
    206	} else
    207		fp_putmant128(dest, &temp, 0);
    208
    209	if (exp >= 0x7fff) {
    210		fp_set_ovrflw(dest);
    211		return dest;
    212	}
    213	dest->exp = exp;
    214	if (exp < 0) {
    215		fp_set_sr(FPSR_EXC_UNFL);
    216		fp_denormalize(dest, -exp);
    217	}
    218
    219	return dest;
    220}
    221
    222/* fp_fdiv: Implements the "kernel" of the FDIV, FSDIV, FDDIV and
    223   FSGLDIV instructions.
    224
    225   Note that the order of the operands is counter-intuitive: instead
    226   of src / dest, the result is actually dest / src. */
    227
    228struct fp_ext *
    229fp_fdiv(struct fp_ext *dest, struct fp_ext *src)
    230{
    231	union fp_mant128 temp;
    232	int exp;
    233
    234	dprint(PINSTR, "fdiv\n");
    235
    236	fp_dyadic_check(dest, src);
    237
    238	/* calculate the correct sign now, as it's necessary for infinities */
    239	dest->sign = src->sign ^ dest->sign;
    240
    241	/* Handle infinities */
    242	if (IS_INF(dest)) {
    243		/* infinity / infinity = NaN (quiet, as always) */
    244		if (IS_INF(src))
    245			fp_set_nan(dest);
    246		/* infinity / anything else = infinity (with appropriate sign) */
    247		return dest;
    248	}
    249	if (IS_INF(src)) {
    250		/* anything / infinity = zero (with appropriate sign) */
    251		dest->exp = 0;
    252		dest->mant.m64 = 0;
    253		dest->lowmant = 0;
    254
    255		return dest;
    256	}
    257
    258	/* zeroes */
    259	if (IS_ZERO(dest)) {
    260		/* zero / zero = NaN */
    261		if (IS_ZERO(src))
    262			fp_set_nan(dest);
    263		/* zero / anything else = zero */
    264		return dest;
    265	}
    266	if (IS_ZERO(src)) {
    267		/* anything / zero = infinity (with appropriate sign) */
    268		fp_set_sr(FPSR_EXC_DZ);
    269		dest->exp = 0x7fff;
    270		dest->mant.m64 = 0;
    271
    272		return dest;
    273	}
    274
    275	exp = dest->exp - src->exp + 0x3fff;
    276
    277	/* shift up the mantissa for denormalized numbers,
    278	   so that the highest bit is set, this makes lots
    279	   of things below easier */
    280	if ((long)dest->mant.m32[0] >= 0)
    281		exp -= fp_overnormalize(dest);
    282	if ((long)src->mant.m32[0] >= 0)
    283		exp -= fp_overnormalize(src);
    284
    285	/* now, do the 64-bit divide */
    286	fp_dividemant(&temp, dest, src);
    287
    288	/* normalize it back to 64 bits and stuff it back into the
    289	   destination struct */
    290	if (!temp.m32[0]) {
    291		exp--;
    292		fp_putmant128(dest, &temp, 32);
    293	} else
    294		fp_putmant128(dest, &temp, 31);
    295
    296	if (exp >= 0x7fff) {
    297		fp_set_ovrflw(dest);
    298		return dest;
    299	}
    300	dest->exp = exp;
    301	if (exp < 0) {
    302		fp_set_sr(FPSR_EXC_UNFL);
    303		fp_denormalize(dest, -exp);
    304	}
    305
    306	return dest;
    307}
    308
    309struct fp_ext *
    310fp_fsglmul(struct fp_ext *dest, struct fp_ext *src)
    311{
    312	int exp;
    313
    314	dprint(PINSTR, "fsglmul\n");
    315
    316	fp_dyadic_check(dest, src);
    317
    318	/* calculate the correct sign now, as it's necessary for infinities */
    319	dest->sign = src->sign ^ dest->sign;
    320
    321	/* Handle infinities */
    322	if (IS_INF(dest)) {
    323		if (IS_ZERO(src))
    324			fp_set_nan(dest);
    325		return dest;
    326	}
    327	if (IS_INF(src)) {
    328		if (IS_ZERO(dest))
    329			fp_set_nan(dest);
    330		else
    331			fp_copy_ext(dest, src);
    332		return dest;
    333	}
    334
    335	/* Of course, as we all know, zero * anything = zero.  You may
    336	   not have known that it might be a positive or negative
    337	   zero... */
    338	if (IS_ZERO(dest) || IS_ZERO(src)) {
    339		dest->exp = 0;
    340		dest->mant.m64 = 0;
    341		dest->lowmant = 0;
    342
    343		return dest;
    344	}
    345
    346	exp = dest->exp + src->exp - 0x3ffe;
    347
    348	/* do a 32-bit multiply */
    349	fp_mul64(dest->mant.m32[0], dest->mant.m32[1],
    350		 dest->mant.m32[0] & 0xffffff00,
    351		 src->mant.m32[0] & 0xffffff00);
    352
    353	if (exp >= 0x7fff) {
    354		fp_set_ovrflw(dest);
    355		return dest;
    356	}
    357	dest->exp = exp;
    358	if (exp < 0) {
    359		fp_set_sr(FPSR_EXC_UNFL);
    360		fp_denormalize(dest, -exp);
    361	}
    362
    363	return dest;
    364}
    365
    366struct fp_ext *
    367fp_fsgldiv(struct fp_ext *dest, struct fp_ext *src)
    368{
    369	int exp;
    370	unsigned long quot, rem;
    371
    372	dprint(PINSTR, "fsgldiv\n");
    373
    374	fp_dyadic_check(dest, src);
    375
    376	/* calculate the correct sign now, as it's necessary for infinities */
    377	dest->sign = src->sign ^ dest->sign;
    378
    379	/* Handle infinities */
    380	if (IS_INF(dest)) {
    381		/* infinity / infinity = NaN (quiet, as always) */
    382		if (IS_INF(src))
    383			fp_set_nan(dest);
    384		/* infinity / anything else = infinity (with approprate sign) */
    385		return dest;
    386	}
    387	if (IS_INF(src)) {
    388		/* anything / infinity = zero (with appropriate sign) */
    389		dest->exp = 0;
    390		dest->mant.m64 = 0;
    391		dest->lowmant = 0;
    392
    393		return dest;
    394	}
    395
    396	/* zeroes */
    397	if (IS_ZERO(dest)) {
    398		/* zero / zero = NaN */
    399		if (IS_ZERO(src))
    400			fp_set_nan(dest);
    401		/* zero / anything else = zero */
    402		return dest;
    403	}
    404	if (IS_ZERO(src)) {
    405		/* anything / zero = infinity (with appropriate sign) */
    406		fp_set_sr(FPSR_EXC_DZ);
    407		dest->exp = 0x7fff;
    408		dest->mant.m64 = 0;
    409
    410		return dest;
    411	}
    412
    413	exp = dest->exp - src->exp + 0x3fff;
    414
    415	dest->mant.m32[0] &= 0xffffff00;
    416	src->mant.m32[0] &= 0xffffff00;
    417
    418	/* do the 32-bit divide */
    419	if (dest->mant.m32[0] >= src->mant.m32[0]) {
    420		fp_sub64(dest->mant, src->mant);
    421		fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]);
    422		dest->mant.m32[0] = 0x80000000 | (quot >> 1);
    423		dest->mant.m32[1] = (quot & 1) | rem;	/* only for rounding */
    424	} else {
    425		fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]);
    426		dest->mant.m32[0] = quot;
    427		dest->mant.m32[1] = rem;		/* only for rounding */
    428		exp--;
    429	}
    430
    431	if (exp >= 0x7fff) {
    432		fp_set_ovrflw(dest);
    433		return dest;
    434	}
    435	dest->exp = exp;
    436	if (exp < 0) {
    437		fp_set_sr(FPSR_EXC_UNFL);
    438		fp_denormalize(dest, -exp);
    439	}
    440
    441	return dest;
    442}
    443
    444/* fp_roundint: Internal rounding function for use by several of these
    445   emulated instructions.
    446
    447   This one rounds off the fractional part using the rounding mode
    448   specified. */
    449
    450static void fp_roundint(struct fp_ext *dest, int mode)
    451{
    452	union fp_mant64 oldmant;
    453	unsigned long mask;
    454
    455	if (!fp_normalize_ext(dest))
    456		return;
    457
    458	/* infinities and zeroes */
    459	if (IS_INF(dest) || IS_ZERO(dest))
    460		return;
    461
    462	/* first truncate the lower bits */
    463	oldmant = dest->mant;
    464	switch (dest->exp) {
    465	case 0 ... 0x3ffe:
    466		dest->mant.m64 = 0;
    467		break;
    468	case 0x3fff ... 0x401e:
    469		dest->mant.m32[0] &= 0xffffffffU << (0x401e - dest->exp);
    470		dest->mant.m32[1] = 0;
    471		if (oldmant.m64 == dest->mant.m64)
    472			return;
    473		break;
    474	case 0x401f ... 0x403e:
    475		dest->mant.m32[1] &= 0xffffffffU << (0x403e - dest->exp);
    476		if (oldmant.m32[1] == dest->mant.m32[1])
    477			return;
    478		break;
    479	default:
    480		return;
    481	}
    482	fp_set_sr(FPSR_EXC_INEX2);
    483
    484	/* We might want to normalize upwards here... however, since
    485	   we know that this is only called on the output of fp_fdiv,
    486	   or with the input to fp_fint or fp_fintrz, and the inputs
    487	   to all these functions are either normal or denormalized
    488	   (no subnormals allowed!), there's really no need.
    489
    490	   In the case of fp_fdiv, observe that 0x80000000 / 0xffff =
    491	   0xffff8000, and the same holds for 128-bit / 64-bit. (i.e. the
    492	   smallest possible normal dividend and the largest possible normal
    493	   divisor will still produce a normal quotient, therefore, (normal
    494	   << 64) / normal is normal in all cases) */
    495
    496	switch (mode) {
    497	case FPCR_ROUND_RN:
    498		switch (dest->exp) {
    499		case 0 ... 0x3ffd:
    500			return;
    501		case 0x3ffe:
    502			/* As noted above, the input is always normal, so the
    503			   guard bit (bit 63) is always set.  therefore, the
    504			   only case in which we will NOT round to 1.0 is when
    505			   the input is exactly 0.5. */
    506			if (oldmant.m64 == (1ULL << 63))
    507				return;
    508			break;
    509		case 0x3fff ... 0x401d:
    510			mask = 1 << (0x401d - dest->exp);
    511			if (!(oldmant.m32[0] & mask))
    512				return;
    513			if (oldmant.m32[0] & (mask << 1))
    514				break;
    515			if (!(oldmant.m32[0] << (dest->exp - 0x3ffd)) &&
    516					!oldmant.m32[1])
    517				return;
    518			break;
    519		case 0x401e:
    520			if (oldmant.m32[1] & 0x80000000)
    521				return;
    522			if (oldmant.m32[0] & 1)
    523				break;
    524			if (!(oldmant.m32[1] << 1))
    525				return;
    526			break;
    527		case 0x401f ... 0x403d:
    528			mask = 1 << (0x403d - dest->exp);
    529			if (!(oldmant.m32[1] & mask))
    530				return;
    531			if (oldmant.m32[1] & (mask << 1))
    532				break;
    533			if (!(oldmant.m32[1] << (dest->exp - 0x401d)))
    534				return;
    535			break;
    536		default:
    537			return;
    538		}
    539		break;
    540	case FPCR_ROUND_RZ:
    541		return;
    542	default:
    543		if (dest->sign ^ (mode - FPCR_ROUND_RM))
    544			break;
    545		return;
    546	}
    547
    548	switch (dest->exp) {
    549	case 0 ... 0x3ffe:
    550		dest->exp = 0x3fff;
    551		dest->mant.m64 = 1ULL << 63;
    552		break;
    553	case 0x3fff ... 0x401e:
    554		mask = 1 << (0x401e - dest->exp);
    555		if (dest->mant.m32[0] += mask)
    556			break;
    557		dest->mant.m32[0] = 0x80000000;
    558		dest->exp++;
    559		break;
    560	case 0x401f ... 0x403e:
    561		mask = 1 << (0x403e - dest->exp);
    562		if (dest->mant.m32[1] += mask)
    563			break;
    564		if (dest->mant.m32[0] += 1)
    565                        break;
    566		dest->mant.m32[0] = 0x80000000;
    567                dest->exp++;
    568		break;
    569	}
    570}
    571
    572/* modrem_kernel: Implementation of the FREM and FMOD instructions
    573   (which are exactly the same, except for the rounding used on the
    574   intermediate value) */
    575
    576static struct fp_ext *
    577modrem_kernel(struct fp_ext *dest, struct fp_ext *src, int mode)
    578{
    579	struct fp_ext tmp;
    580
    581	fp_dyadic_check(dest, src);
    582
    583	/* Infinities and zeros */
    584	if (IS_INF(dest) || IS_ZERO(src)) {
    585		fp_set_nan(dest);
    586		return dest;
    587	}
    588	if (IS_ZERO(dest) || IS_INF(src))
    589		return dest;
    590
    591	/* FIXME: there is almost certainly a smarter way to do this */
    592	fp_copy_ext(&tmp, dest);
    593	fp_fdiv(&tmp, src);		/* NOTE: src might be modified */
    594	fp_roundint(&tmp, mode);
    595	fp_fmul(&tmp, src);
    596	fp_fsub(dest, &tmp);
    597
    598	/* set the quotient byte */
    599	fp_set_quotient((dest->mant.m64 & 0x7f) | (dest->sign << 7));
    600	return dest;
    601}
    602
    603/* fp_fmod: Implements the kernel of the FMOD instruction.
    604
    605   Again, the argument order is backwards.  The result, as defined in
    606   the Motorola manuals, is:
    607
    608   fmod(src,dest) = (dest - (src * floor(dest / src))) */
    609
    610struct fp_ext *
    611fp_fmod(struct fp_ext *dest, struct fp_ext *src)
    612{
    613	dprint(PINSTR, "fmod\n");
    614	return modrem_kernel(dest, src, FPCR_ROUND_RZ);
    615}
    616
    617/* fp_frem: Implements the kernel of the FREM instruction.
    618
    619   frem(src,dest) = (dest - (src * round(dest / src)))
    620 */
    621
    622struct fp_ext *
    623fp_frem(struct fp_ext *dest, struct fp_ext *src)
    624{
    625	dprint(PINSTR, "frem\n");
    626	return modrem_kernel(dest, src, FPCR_ROUND_RN);
    627}
    628
    629struct fp_ext *
    630fp_fint(struct fp_ext *dest, struct fp_ext *src)
    631{
    632	dprint(PINSTR, "fint\n");
    633
    634	fp_copy_ext(dest, src);
    635
    636	fp_roundint(dest, FPDATA->rnd);
    637
    638	return dest;
    639}
    640
    641struct fp_ext *
    642fp_fintrz(struct fp_ext *dest, struct fp_ext *src)
    643{
    644	dprint(PINSTR, "fintrz\n");
    645
    646	fp_copy_ext(dest, src);
    647
    648	fp_roundint(dest, FPCR_ROUND_RZ);
    649
    650	return dest;
    651}
    652
    653struct fp_ext *
    654fp_fscale(struct fp_ext *dest, struct fp_ext *src)
    655{
    656	int scale, oldround;
    657
    658	dprint(PINSTR, "fscale\n");
    659
    660	fp_dyadic_check(dest, src);
    661
    662	/* Infinities */
    663	if (IS_INF(src)) {
    664		fp_set_nan(dest);
    665		return dest;
    666	}
    667	if (IS_INF(dest))
    668		return dest;
    669
    670	/* zeroes */
    671	if (IS_ZERO(src) || IS_ZERO(dest))
    672		return dest;
    673
    674	/* Source exponent out of range */
    675	if (src->exp >= 0x400c) {
    676		fp_set_ovrflw(dest);
    677		return dest;
    678	}
    679
    680	/* src must be rounded with round to zero. */
    681	oldround = FPDATA->rnd;
    682	FPDATA->rnd = FPCR_ROUND_RZ;
    683	scale = fp_conv_ext2long(src);
    684	FPDATA->rnd = oldround;
    685
    686	/* new exponent */
    687	scale += dest->exp;
    688
    689	if (scale >= 0x7fff) {
    690		fp_set_ovrflw(dest);
    691	} else if (scale <= 0) {
    692		fp_set_sr(FPSR_EXC_UNFL);
    693		fp_denormalize(dest, -scale);
    694	} else
    695		dest->exp = scale;
    696
    697	return dest;
    698}
    699