mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
fpu test max precision/double mode
This commit is contained in:
parent
d2838c08e1
commit
e58f45d5d4
194
cputest.cpp
194
cputest.cpp
@ -75,7 +75,7 @@ static int feature_exception_vectors = 0;
|
||||
static int feature_interrupts = 0;
|
||||
static int feature_waitstates = 0;
|
||||
static int feature_instruction_size = 0;
|
||||
static int fpu_min_exponent, fpu_max_exponent;
|
||||
static int fpu_min_exponent, fpu_max_exponent, fpu_max_precision, fpu_unnormals;
|
||||
static int feature_ipl_delay;
|
||||
static int max_file_size;
|
||||
static int rnd_seed, rnd_seed_prev;
|
||||
@ -1853,6 +1853,57 @@ static uae_u8 frand8(void)
|
||||
return (uae_u8)xorshift32();
|
||||
}
|
||||
|
||||
static bool fpu_precision_valid(floatx80 f)
|
||||
{
|
||||
int exp = f.high & 0x7fff;
|
||||
if (exp != 0x0000) {
|
||||
exp -= 16384;
|
||||
if (exp < fpu_min_exponent || exp > fpu_max_exponent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
float_status status = { 0 };
|
||||
status.floatx80_rounding_precision = 80;
|
||||
status.float_rounding_mode = float_round_nearest_even;
|
||||
status.float_exception_flags = 0;
|
||||
if (fpu_max_precision == 2) {
|
||||
float64 fo = floatx80_to_float64(f, &status);
|
||||
int exp = (float64_val(fo) >> 52) & 0x7FF;
|
||||
if (exp >= 0x700) {
|
||||
return false;
|
||||
}
|
||||
if (float64_is_nan(fo)) {
|
||||
return false;
|
||||
}
|
||||
} else if (fpu_max_precision == 1) {
|
||||
float32 fo = floatx80_to_float32(f, &status);
|
||||
int exp = (float32_val(fo) >> 23) & 0xFF;
|
||||
if (exp >= 0xe0) {
|
||||
return false;
|
||||
}
|
||||
if (float32_is_nan(fo)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fpu_max_precision) {
|
||||
if (status.float_exception_flags & (float_flag_underflow | float_flag_overflow | float_flag_denormal | float_flag_invalid)) {
|
||||
return false;
|
||||
}
|
||||
if (floatx80_is_any_nan(f)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!fpu_unnormals) {
|
||||
if (!(f.low & 0x8000000000000000) && (f.high & 0x7fff) && (f.high & 0x7fff) != 0x7fff) {
|
||||
return false;
|
||||
}
|
||||
if (status.float_exception_flags & float_flag_denormal) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uae_u32 registers[] =
|
||||
{
|
||||
0x00000010, // 0
|
||||
@ -1877,6 +1928,21 @@ static int regcnts[16];
|
||||
static int fpuregcnts[8];
|
||||
static float_status fpustatus;
|
||||
|
||||
static floatx80 fpu_random(void)
|
||||
{
|
||||
floatx80 v = int32_to_floatx80(rand32());
|
||||
for (int i = 0; i < 10; i++) {
|
||||
uae_u64 n = rand32() | (((uae_u64)rand16()) << 32);
|
||||
// don't create denormals yet
|
||||
if (!((v.low + n) & 0x8000000000000000)) {
|
||||
v.low |= 0x8000000000000000;
|
||||
continue;
|
||||
}
|
||||
v.low += n;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static bool fpuregchange(int reg, fpdata *regs)
|
||||
{
|
||||
int regcnt = fpuregcnts[reg];
|
||||
@ -1893,14 +1959,16 @@ static bool fpuregchange(int reg, fpdata *regs)
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case 0: // positive
|
||||
add = floatx80_div(int32_to_floatx80(1), int32_to_floatx80(10), &fpustatus);
|
||||
add = floatx80_div(int32_to_floatx80(1), int32_to_floatx80(5 + regcnt), &fpustatus);
|
||||
v = floatx80_add(v, add, &fpustatus);
|
||||
break;
|
||||
case 1: // negative
|
||||
add = floatx80_div(int32_to_floatx80(1), int32_to_floatx80(10), &fpustatus);
|
||||
add = floatx80_div(int32_to_floatx80(1), int32_to_floatx80(6 + regcnt), &fpustatus);
|
||||
v = floatx80_sub(v, add, &fpustatus);
|
||||
break;
|
||||
case 2: // positive/negative zero
|
||||
@ -1908,34 +1976,40 @@ static bool fpuregchange(int reg, fpdata *regs)
|
||||
break;
|
||||
case 3:
|
||||
// very large value, larger than fits in double
|
||||
if (fpu_max_precision) {
|
||||
v = fpu_random();
|
||||
} else {
|
||||
v = packFloatx80(1, 0x7000 + (rand16() & 0xfff), 0x8000000000000000 | (((uae_u64)rand32()) << 32));
|
||||
if (regcnt & 1) {
|
||||
v.high ^= 0x8000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// value that fits in double but does not fit in single
|
||||
v = packFloatx80(1, 0x700 + rand8(), 0x8000000000000000 | (((uae_u64)rand32()) << 32));
|
||||
{
|
||||
int exp;
|
||||
if (fpu_max_precision < 128) {
|
||||
exp = fpu_max_precision + rand8();
|
||||
} else {
|
||||
exp = 128 + rand8();
|
||||
}
|
||||
exp += 16384;
|
||||
v = packFloatx80(1, exp, 0x8000000000000000 | (((uae_u64)rand32()) << 32));
|
||||
if (regcnt & 1) {
|
||||
v.high ^= 0x8000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
// random
|
||||
v = int32_to_floatx80(rand32());
|
||||
for (int i = 0; i < 10; i++) {
|
||||
uae_u64 n = rand32() | (((uae_u64)rand16()) << 32);
|
||||
// don't create denormals yet
|
||||
if (!((v.low + n) & 0x8000000000000000)) {
|
||||
v.low |= 0x8000000000000000;
|
||||
continue;
|
||||
}
|
||||
v.low += n;
|
||||
break;
|
||||
}
|
||||
v = fpu_random();
|
||||
break;
|
||||
case 7: // +NaN, -Nan, +Inf, -Inf
|
||||
if (fpu_max_precision) {
|
||||
v = fpu_random();
|
||||
} else {
|
||||
if ((regcnt & 3) == 0) {
|
||||
v = floatx80_default_nan(NULL);
|
||||
} else if ((regcnt & 3) == 1) {
|
||||
@ -1946,12 +2020,17 @@ static bool fpuregchange(int reg, fpdata *regs)
|
||||
} else if ((regcnt & 3) == 3) {
|
||||
v = packFloatx80(1, 0x7FFF, floatx80_default_infinity_low);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (fpu_precision_valid(v)) {
|
||||
fpuregcnts[reg]++;
|
||||
regs[reg].fpx = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool regchange(int reg, uae_u32 *regs)
|
||||
{
|
||||
@ -2060,13 +2139,51 @@ static bool regchange(int reg, uae_u32 *regs)
|
||||
|
||||
static void fill_memory_buffer(uae_u8 *p, int size)
|
||||
{
|
||||
for (int i = 0; i < size; i++) {
|
||||
p[i] = frand8();
|
||||
uae_u8 *pend = p - 64;
|
||||
int i = 0;
|
||||
while (p < pend) {
|
||||
int x = (i & 3);
|
||||
if (x == 1) {
|
||||
floatx80 v = int32_to_floatx80(xorshift32());
|
||||
*p++ = v.high >> 8;
|
||||
*p++ = v.high >> 0;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = (uae_u8)(v.low >> 56);
|
||||
*p++ = (uae_u8)(v.low >> 48);
|
||||
*p++ = (uae_u8)(v.low >> 40);
|
||||
*p++ = (uae_u8)(v.low >> 32);
|
||||
if ((i & 15) < 8) {
|
||||
*p++ = (uae_u8)(v.low >> 24);
|
||||
*p++ = (uae_u8)(v.low >> 16);
|
||||
*p++ = (uae_u8)(v.low >> 8);
|
||||
*p++ = (uae_u8)(v.low >> 0);
|
||||
} else {
|
||||
*p++ = frand8();
|
||||
*p++ = frand8();
|
||||
*p++ = frand8();
|
||||
*p++ = frand8();
|
||||
}
|
||||
// fill extra zeros
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (frand8() < 0x70)
|
||||
p[i] = 0x00;
|
||||
} else if (x == 2) {
|
||||
floatx80 v = int32_to_floatx80(xorshift32());
|
||||
float64 v2 = floatx80_to_float64(v, &fpustatus);
|
||||
*p++ = (uae_u8)(v2 >> 56);
|
||||
*p++ = (uae_u8)(v2 >> 48);
|
||||
*p++ = (uae_u8)(v2 >> 40);
|
||||
*p++ = (uae_u8)(v2 >> 32);
|
||||
*p++ = (uae_u8)(v2 >> 24);
|
||||
*p++ = (uae_u8)(v2 >> 16);
|
||||
*p++ = (uae_u8)(v2 >> 8);
|
||||
*p++ = (uae_u8)(v2 >> 0);
|
||||
} else if (x == 3) {
|
||||
floatx80 v = int32_to_floatx80(xorshift32());
|
||||
float32 v2 = floatx80_to_float32(v, &fpustatus);
|
||||
*p++ = (uae_u8)(v2 >> 24);
|
||||
*p++ = (uae_u8)(v2 >> 16);
|
||||
*p++ = (uae_u8)(v2 >> 8);
|
||||
*p++ = (uae_u8)(v2 >> 0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2619,7 +2736,7 @@ static void save_data(uae_u8 *dst, const TCHAR *dir, int size)
|
||||
(feature_min_interrupt_mask << 20) | (safe_memory_mode << 23) | (feature_interrupts << 26) |
|
||||
((feature_loop_mode_jit ? 1 : 0) << 28) | ((feature_loop_mode_68010 ? 1 : 0) << 29));
|
||||
fwrite(data, 1, 4, f);
|
||||
pl(data, (feature_initial_interrupt_mask & 7) | ((feature_initial_interrupt & 7) << 3));
|
||||
pl(data, (feature_initial_interrupt_mask & 7) | ((feature_initial_interrupt & 7) << 3) | (fpu_max_precision << 6));
|
||||
fwrite(data, 1, 4, f);
|
||||
pl(data, 0);
|
||||
fwrite(data, 1, 4, f);
|
||||
@ -4329,12 +4446,8 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool
|
||||
// skip result if it has too large or small exponent
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (regs.fp[i].fpx.high != cur_regs.fp[i].fpx.high || regs.fp[i].fpx.low != cur_regs.fp[i].fpx.low) {
|
||||
int exp = regs.fp[i].fpx.high & 0x7fff;
|
||||
if (exp != 0x0000) {
|
||||
if (exp < fpu_min_exponent || exp > fpu_max_exponent) {
|
||||
if (!fpu_precision_valid(regs.fp[i].fpx)) {
|
||||
test_exception = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4900,7 +5013,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
|
||||
target_ea_opcode_cnt = 0;
|
||||
generate_address_mode = 0;
|
||||
|
||||
if (fpu_max_precision == 2) {
|
||||
fpustatus.floatx80_rounding_precision = 64;
|
||||
} else if (fpu_max_precision == 1) {
|
||||
fpustatus.floatx80_rounding_precision = 32;
|
||||
} else {
|
||||
fpustatus.floatx80_rounding_precision = 80;
|
||||
}
|
||||
fpustatus.float_rounding_mode = float_round_nearest_even;
|
||||
|
||||
// 1.0
|
||||
@ -4909,12 +5028,16 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi
|
||||
fpuregisters[1] = int32_to_floatx80(-1);
|
||||
// 0.0
|
||||
fpuregisters[2] = int32_to_floatx80(0);
|
||||
if (fpu_max_precision) {
|
||||
fpuregisters[7] = int32_to_floatx80(2);
|
||||
} else {
|
||||
// NaN
|
||||
fpuregisters[7] = floatx80_default_nan(NULL);
|
||||
}
|
||||
|
||||
for (int i = 3; i < 7; i++) {
|
||||
uae_u32 v = rand32();
|
||||
if (v < 10 || v > -10)
|
||||
if (v < 15 || v > -15)
|
||||
continue;
|
||||
fpuregisters[i] = int32_to_floatx80(v);
|
||||
}
|
||||
@ -6954,8 +7077,9 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna
|
||||
}
|
||||
}
|
||||
|
||||
fpu_min_exponent = 0;
|
||||
fpu_max_exponent = 32768;
|
||||
fpu_min_exponent = -65535;
|
||||
fpu_max_exponent = 65535;
|
||||
fpu_max_precision = 0;
|
||||
if (ini_getvalx(ini, sections, _T("fpu_min_exponent"), &v)) {
|
||||
if (v >= 0) {
|
||||
fpu_min_exponent = v;
|
||||
@ -6966,6 +7090,16 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna
|
||||
fpu_max_exponent = v;
|
||||
}
|
||||
}
|
||||
if (ini_getvalx(ini, sections, _T("fpu_max_precision"), &v)) {
|
||||
if (v == 1 || v == 2) {
|
||||
fpu_max_precision = v;
|
||||
}
|
||||
}
|
||||
if (ini_getvalx(ini, sections, _T("fpu_unnormals"), &v)) {
|
||||
if (v) {
|
||||
fpu_unnormals = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rnd_seed = 0;
|
||||
ini_getvalx(ini, sections, _T("seed"), &rnd_seed);
|
||||
|
||||
@ -56,7 +56,7 @@ S_NEXT = S_FSAVE+216
|
||||
asm_start:
|
||||
|
||||
_initfpu:
|
||||
moveq #0,d0
|
||||
move.l 4(sp),d0
|
||||
fmove.l d0,fpcr
|
||||
rts
|
||||
|
||||
|
||||
@ -90,6 +90,7 @@ static uae_u8 *vbr_zero = 0;
|
||||
static int hmem_rom, lmem_rom;
|
||||
static uae_u8 *absallocated;
|
||||
static int cpu_lvl, fpu_model;
|
||||
static uae_u8 fpu_max_precision;
|
||||
static uae_u16 sr_undefined_mask;
|
||||
static int check_undefined_sr;
|
||||
static short is_fpu_adjust;
|
||||
@ -137,6 +138,7 @@ static short dooutput = 1;
|
||||
static short quit;
|
||||
static uae_u8 ccr_mask;
|
||||
static uae_u32 fpsr_ignore_mask;
|
||||
static short fpiar_ignore;
|
||||
static uae_u32 addressing_mask = 0x00ffffff;
|
||||
static uae_u32 interrupt_mask;
|
||||
static short initial_interrupt_mask;
|
||||
@ -257,7 +259,7 @@ static uae_u32 fpucompzero(void *v)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static void initfpu(void)
|
||||
static void initfpu(uae_u32 v)
|
||||
{
|
||||
}
|
||||
static void *error_vector;
|
||||
@ -288,7 +290,7 @@ extern void *error_vector;
|
||||
extern void berrcopy(void*, void*, uae_u32, uae_u32);
|
||||
extern uae_u32 fpucomp(void *);
|
||||
extern uae_u32 fpucompzero(void *);
|
||||
extern void initfpu(void);
|
||||
extern void initfpu(uae_u32);
|
||||
|
||||
#endif
|
||||
static uae_u32 exceptiontableinuse;
|
||||
@ -2832,7 +2834,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st
|
||||
int size;
|
||||
p = restore_value(p, &val, &size);
|
||||
if (val != tregs->fpiar) {
|
||||
if (!ignore_errors) {
|
||||
if (!ignore_errors && !fpiar_ignore) {
|
||||
if (dooutput) {
|
||||
if (sregs->fpiar == tregs->fpiar) {
|
||||
sprintf(outbp, "FPIAR: expected %08x but register was not modified\n", val);
|
||||
@ -2968,7 +2970,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st
|
||||
}
|
||||
errflag |= 1 << 4;
|
||||
}
|
||||
if (fpiar_changed && tregs->fpiar != lregs->fpiar) {
|
||||
if (fpiar_changed && tregs->fpiar != lregs->fpiar && !fpiar_ignore) {
|
||||
if (dooutput) {
|
||||
uae_u32 val = lregs->fpiar;
|
||||
sprintf(outbp, "FPIAR: expected %08x but got %08x\n", val, tregs->fpiar);
|
||||
@ -3241,7 +3243,13 @@ static void process_test(uae_u8 *p)
|
||||
|
||||
int fpumode = fpu_model && (opcode_memory[0] & 0xf0) == 0xf0;
|
||||
if (fpumode) {
|
||||
initfpu();
|
||||
uae_u32 v = 0;
|
||||
if (fpu_max_precision == 2) {
|
||||
v = 2 << 6;
|
||||
} else if (fpu_max_precision == 1) {
|
||||
v = 1 << 6;
|
||||
}
|
||||
initfpu(v);
|
||||
}
|
||||
copyregs(&last_regs, &cur_regs, fpumode);
|
||||
|
||||
@ -3667,6 +3675,7 @@ static int test_mnemo(const char *opcode)
|
||||
v = read_u32(headerfile, &headoffset);
|
||||
initial_interrupt_mask = v & 7;
|
||||
initial_interrupt = (v >> 3) & 7;
|
||||
fpu_max_precision = (v >> 6) & 3;
|
||||
v = read_u32(headerfile, &headoffset);
|
||||
v = read_u32(headerfile, &headoffset);
|
||||
fpu_model = read_u32(headerfile, &headoffset);
|
||||
@ -3959,8 +3968,9 @@ int main(int argc, char *argv[])
|
||||
printf("-askifmissing = ask for new path if dat file is missing.\n");
|
||||
printf("-exit n = exit after n tests.\n");
|
||||
printf("-exitok n = exit after n tests, continue normally.\n");
|
||||
printf("-fpuadj <exp> 16-bit exponent range value. (16383 = 1.0)\n");
|
||||
printf("-fpuadj <exp> 16-bit exponent range value. (0 = 1.0)\n");
|
||||
printf("-fpsrmask = ignore FPSR bits that are not set.\n");
|
||||
printf("-nofpiar = ignore FPIAR.\n");
|
||||
printf("-cycles [range adjust] = check cycle counts.\n");
|
||||
printf("-cyclecnt <address>. Use custom hardware cycle counter.\n");
|
||||
#ifdef AMIGA
|
||||
@ -3975,6 +3985,7 @@ int main(int argc, char *argv[])
|
||||
check_undefined_sr = 1;
|
||||
ccr_mask = 0xff;
|
||||
fpsr_ignore_mask = 0xffffffff;
|
||||
fpiar_ignore = 0;
|
||||
disasm = 1;
|
||||
exitcnt2 = -1;
|
||||
exitmode = 0;
|
||||
@ -4002,11 +4013,13 @@ int main(int argc, char *argv[])
|
||||
i++;
|
||||
}
|
||||
} else if (!_stricmp(s, "-fpsrmask")) {
|
||||
fpsr_ignore_mask = 0;
|
||||
fpsr_ignore_mask = (1 << 27) | (1 << 26);
|
||||
if (next) {
|
||||
fpsr_ignore_mask = ~getparamval(next);
|
||||
i++;
|
||||
}
|
||||
} else if (!_stricmp(s, "-nofpiar")) {
|
||||
fpiar_ignore = 1;
|
||||
} else if (!_stricmp(s, "-silent")) {
|
||||
dooutput = 0;
|
||||
} else if (!_stricmp(s, "-68000")) {
|
||||
@ -4057,13 +4070,12 @@ int main(int argc, char *argv[])
|
||||
} else if (!_stricmp(s, "-prealloc")) {
|
||||
prealloc = 1;
|
||||
} else if (!_stricmp(s, "-fpuadj")) {
|
||||
fpu_adjust_exp = 0;
|
||||
if (next) {
|
||||
fpu_adjust_exp = atol(next);
|
||||
if (fpu_adjust_exp >= 0) {
|
||||
}
|
||||
is_fpu_adjust = 1;
|
||||
}
|
||||
|
||||
}
|
||||
fpu_adjust_exp += 16384;
|
||||
} else if (!_stricmp(s, "-cycles")) {
|
||||
cycles = 1;
|
||||
if (i + 1 < argc && argv[i][0] != '-') {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user