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

fpa11_cprt.c (8590B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3    NetWinder Floating Point Emulator
      4    (c) Rebel.COM, 1998,1999
      5    (c) Philip Blundell, 1999, 2001
      6
      7    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
      8
      9*/
     10
     11#include "fpa11.h"
     12#include "fpopcode.h"
     13#include "fpa11.inl"
     14#include "fpmodule.h"
     15#include "fpmodule.inl"
     16#include "softfloat.h"
     17
     18unsigned int PerformFLT(const unsigned int opcode);
     19unsigned int PerformFIX(const unsigned int opcode);
     20
     21static unsigned int PerformComparison(const unsigned int opcode);
     22
     23unsigned int EmulateCPRT(const unsigned int opcode)
     24{
     25
     26	if (opcode & 0x800000) {
     27		/* This is some variant of a comparison (PerformComparison
     28		   will sort out which one).  Since most of the other CPRT
     29		   instructions are oddball cases of some sort or other it
     30		   makes sense to pull this out into a fast path.  */
     31		return PerformComparison(opcode);
     32	}
     33
     34	/* Hint to GCC that we'd like a jump table rather than a load of CMPs */
     35	switch ((opcode & 0x700000) >> 20) {
     36	case FLT_CODE >> 20:
     37		return PerformFLT(opcode);
     38		break;
     39	case FIX_CODE >> 20:
     40		return PerformFIX(opcode);
     41		break;
     42
     43	case WFS_CODE >> 20:
     44		writeFPSR(readRegister(getRd(opcode)));
     45		break;
     46	case RFS_CODE >> 20:
     47		writeRegister(getRd(opcode), readFPSR());
     48		break;
     49
     50	default:
     51		return 0;
     52	}
     53
     54	return 1;
     55}
     56
     57unsigned int PerformFLT(const unsigned int opcode)
     58{
     59	FPA11 *fpa11 = GET_FPA11();
     60	struct roundingData roundData;
     61
     62	roundData.mode = SetRoundingMode(opcode);
     63	roundData.precision = SetRoundingPrecision(opcode);
     64	roundData.exception = 0;
     65
     66	switch (opcode & MASK_ROUNDING_PRECISION) {
     67	case ROUND_SINGLE:
     68		{
     69			fpa11->fType[getFn(opcode)] = typeSingle;
     70			fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
     71		}
     72		break;
     73
     74	case ROUND_DOUBLE:
     75		{
     76			fpa11->fType[getFn(opcode)] = typeDouble;
     77			fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
     78		}
     79		break;
     80
     81#ifdef CONFIG_FPE_NWFPE_XP
     82	case ROUND_EXTENDED:
     83		{
     84			fpa11->fType[getFn(opcode)] = typeExtended;
     85			fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
     86		}
     87		break;
     88#endif
     89
     90	default:
     91		return 0;
     92	}
     93
     94	if (roundData.exception)
     95		float_raise(roundData.exception);
     96
     97	return 1;
     98}
     99
    100unsigned int PerformFIX(const unsigned int opcode)
    101{
    102	FPA11 *fpa11 = GET_FPA11();
    103	unsigned int Fn = getFm(opcode);
    104	struct roundingData roundData;
    105
    106	roundData.mode = SetRoundingMode(opcode);
    107	roundData.precision = SetRoundingPrecision(opcode);
    108	roundData.exception = 0;
    109
    110	switch (fpa11->fType[Fn]) {
    111	case typeSingle:
    112		{
    113			writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
    114		}
    115		break;
    116
    117	case typeDouble:
    118		{
    119			writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
    120		}
    121		break;
    122
    123#ifdef CONFIG_FPE_NWFPE_XP
    124	case typeExtended:
    125		{
    126			writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
    127		}
    128		break;
    129#endif
    130
    131	default:
    132		return 0;
    133	}
    134
    135	if (roundData.exception)
    136		float_raise(roundData.exception);
    137
    138	return 1;
    139}
    140
    141/* This instruction sets the flags N, Z, C, V in the FPSR. */
    142static unsigned int PerformComparison(const unsigned int opcode)
    143{
    144	FPA11 *fpa11 = GET_FPA11();
    145	unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
    146	int e_flag = opcode & 0x400000;	/* 1 if CxFE */
    147	int n_flag = opcode & 0x200000;	/* 1 if CNxx */
    148	unsigned int flags = 0;
    149
    150#ifdef CONFIG_FPE_NWFPE_XP
    151	floatx80 rFn, rFm;
    152
    153	/* Check for unordered condition and convert all operands to 80-bit
    154	   format.
    155	   ?? Might be some mileage in avoiding this conversion if possible.
    156	   Eg, if both operands are 32-bit, detect this and do a 32-bit
    157	   comparison (cheaper than an 80-bit one).  */
    158	switch (fpa11->fType[Fn]) {
    159	case typeSingle:
    160		//printk("single.\n");
    161		if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
    162			goto unordered;
    163		rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
    164		break;
    165
    166	case typeDouble:
    167		//printk("double.\n");
    168		if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
    169			goto unordered;
    170		rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
    171		break;
    172
    173	case typeExtended:
    174		//printk("extended.\n");
    175		if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
    176			goto unordered;
    177		rFn = fpa11->fpreg[Fn].fExtended;
    178		break;
    179
    180	default:
    181		return 0;
    182	}
    183
    184	if (CONSTANT_FM(opcode)) {
    185		//printk("Fm is a constant: #%d.\n",Fm);
    186		rFm = getExtendedConstant(Fm);
    187		if (floatx80_is_nan(rFm))
    188			goto unordered;
    189	} else {
    190		//printk("Fm = r%d which contains a ",Fm);
    191		switch (fpa11->fType[Fm]) {
    192		case typeSingle:
    193			//printk("single.\n");
    194			if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
    195				goto unordered;
    196			rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
    197			break;
    198
    199		case typeDouble:
    200			//printk("double.\n");
    201			if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
    202				goto unordered;
    203			rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
    204			break;
    205
    206		case typeExtended:
    207			//printk("extended.\n");
    208			if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
    209				goto unordered;
    210			rFm = fpa11->fpreg[Fm].fExtended;
    211			break;
    212
    213		default:
    214			return 0;
    215		}
    216	}
    217
    218	if (n_flag)
    219		rFm.high ^= 0x8000;
    220
    221	/* test for less than condition */
    222	if (floatx80_lt(rFn, rFm))
    223		flags |= CC_NEGATIVE;
    224
    225	/* test for equal condition */
    226	if (floatx80_eq(rFn, rFm))
    227		flags |= CC_ZERO;
    228
    229	/* test for greater than or equal condition */
    230	if (floatx80_lt(rFm, rFn))
    231		flags |= CC_CARRY;
    232
    233#else
    234	if (CONSTANT_FM(opcode)) {
    235		/* Fm is a constant.  Do the comparison in whatever precision
    236		   Fn happens to be stored in.  */
    237		if (fpa11->fType[Fn] == typeSingle) {
    238			float32 rFm = getSingleConstant(Fm);
    239			float32 rFn = fpa11->fpreg[Fn].fSingle;
    240
    241			if (float32_is_nan(rFn))
    242				goto unordered;
    243
    244			if (n_flag)
    245				rFm ^= 0x80000000;
    246
    247			/* test for less than condition */
    248			if (float32_lt_nocheck(rFn, rFm))
    249				flags |= CC_NEGATIVE;
    250
    251			/* test for equal condition */
    252			if (float32_eq_nocheck(rFn, rFm))
    253				flags |= CC_ZERO;
    254
    255			/* test for greater than or equal condition */
    256			if (float32_lt_nocheck(rFm, rFn))
    257				flags |= CC_CARRY;
    258		} else {
    259			float64 rFm = getDoubleConstant(Fm);
    260			float64 rFn = fpa11->fpreg[Fn].fDouble;
    261
    262			if (float64_is_nan(rFn))
    263				goto unordered;
    264
    265			if (n_flag)
    266				rFm ^= 0x8000000000000000ULL;
    267
    268			/* test for less than condition */
    269			if (float64_lt_nocheck(rFn, rFm))
    270				flags |= CC_NEGATIVE;
    271
    272			/* test for equal condition */
    273			if (float64_eq_nocheck(rFn, rFm))
    274				flags |= CC_ZERO;
    275
    276			/* test for greater than or equal condition */
    277			if (float64_lt_nocheck(rFm, rFn))
    278				flags |= CC_CARRY;
    279		}
    280	} else {
    281		/* Both operands are in registers.  */
    282		if (fpa11->fType[Fn] == typeSingle
    283		    && fpa11->fType[Fm] == typeSingle) {
    284			float32 rFm = fpa11->fpreg[Fm].fSingle;
    285			float32 rFn = fpa11->fpreg[Fn].fSingle;
    286
    287			if (float32_is_nan(rFn)
    288			    || float32_is_nan(rFm))
    289				goto unordered;
    290
    291			if (n_flag)
    292				rFm ^= 0x80000000;
    293
    294			/* test for less than condition */
    295			if (float32_lt_nocheck(rFn, rFm))
    296				flags |= CC_NEGATIVE;
    297
    298			/* test for equal condition */
    299			if (float32_eq_nocheck(rFn, rFm))
    300				flags |= CC_ZERO;
    301
    302			/* test for greater than or equal condition */
    303			if (float32_lt_nocheck(rFm, rFn))
    304				flags |= CC_CARRY;
    305		} else {
    306			/* Promote 32-bit operand to 64 bits.  */
    307			float64 rFm, rFn;
    308
    309			rFm = (fpa11->fType[Fm] == typeSingle) ?
    310			    float32_to_float64(fpa11->fpreg[Fm].fSingle)
    311			    : fpa11->fpreg[Fm].fDouble;
    312
    313			rFn = (fpa11->fType[Fn] == typeSingle) ?
    314			    float32_to_float64(fpa11->fpreg[Fn].fSingle)
    315			    : fpa11->fpreg[Fn].fDouble;
    316
    317			if (float64_is_nan(rFn)
    318			    || float64_is_nan(rFm))
    319				goto unordered;
    320
    321			if (n_flag)
    322				rFm ^= 0x8000000000000000ULL;
    323
    324			/* test for less than condition */
    325			if (float64_lt_nocheck(rFn, rFm))
    326				flags |= CC_NEGATIVE;
    327
    328			/* test for equal condition */
    329			if (float64_eq_nocheck(rFn, rFm))
    330				flags |= CC_ZERO;
    331
    332			/* test for greater than or equal condition */
    333			if (float64_lt_nocheck(rFm, rFn))
    334				flags |= CC_CARRY;
    335		}
    336	}
    337
    338#endif
    339
    340	writeConditionCodes(flags);
    341
    342	return 1;
    343
    344      unordered:
    345	/* ?? The FPA data sheet is pretty vague about this, in particular
    346	   about whether the non-E comparisons can ever raise exceptions.
    347	   This implementation is based on a combination of what it says in
    348	   the data sheet, observation of how the Acorn emulator actually
    349	   behaves (and how programs expect it to) and guesswork.  */
    350	flags |= CC_OVERFLOW;
    351	flags &= ~(CC_ZERO | CC_NEGATIVE);
    352
    353	if (BIT_AC & readFPSR())
    354		flags |= CC_CARRY;
    355
    356	if (e_flag)
    357		float_raise(float_flag_invalid);
    358
    359	writeConditionCodes(flags);
    360	return 1;
    361}