From: Toni Wilen Date: Sat, 16 Sep 2023 17:31:48 +0000 (+0300) Subject: fpu test max precision/double mode X-Git-Tag: 5.1.0~122 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=e58f45d5d4c93acd8dc9a44d65df6c79bf892c69;p=francis%2Fwinuae.git fpu test max precision/double mode --- diff --git a/cputest.cpp b/cputest.cpp index 77877c12..c636dc2a 100644 --- a/cputest.cpp +++ b/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,64 +1959,77 @@ static bool fpuregchange(int reg, fpdata *regs) } } - switch(reg) - { - case 0: // positive - add = floatx80_div(int32_to_floatx80(1), int32_to_floatx80(10), &fpustatus); - v = floatx80_add(v, add, &fpustatus); - break; - case 1: // negative - add = floatx80_div(int32_to_floatx80(1), int32_to_floatx80(10), &fpustatus); - v = floatx80_sub(v, add, &fpustatus); - break; - case 2: // positive/negative zero - v.high ^= 0x8000; - break; - case 3: - // very large value, larger than fits in double - 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)); - if (regcnt & 1) { + for(;;) { + + switch(reg) + { + case 0: // positive + 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(6 + regcnt), &fpustatus); + v = floatx80_sub(v, add, &fpustatus); + break; + case 2: // positive/negative zero 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; + 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 + { + 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 = 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) { + v = floatx80_default_nan(NULL); + v.high ^= 0x8000; + } else if ((regcnt & 3) == 2) { + v = packFloatx80(0, 0x7FFF, floatx80_default_infinity_low); + } else if ((regcnt & 3) == 3) { + v = packFloatx80(1, 0x7FFF, floatx80_default_infinity_low); + } } - v.low += n; break; } - break; - case 7: // +NaN, -Nan, +Inf, -Inf - if ((regcnt & 3) == 0) { - v = floatx80_default_nan(NULL); - } else if ((regcnt & 3) == 1) { - v = floatx80_default_nan(NULL); - v.high ^= 0x8000; - } else if ((regcnt & 3) == 2) { - v = packFloatx80(0, 0x7FFF, floatx80_default_infinity_low); - } else if ((regcnt & 3) == 3) { - v = packFloatx80(1, 0x7FFF, floatx80_default_infinity_low); + + if (fpu_precision_valid(v)) { + fpuregcnts[reg]++; + regs[reg].fpx = v; + return true; } - break; } - 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(); - } - // fill extra zeros - for (int i = 0; i < size; i++) { - if (frand8() < 0x70) - p[i] = 0x00; + 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(); + } + } 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) { - test_exception = -1; - break; - } + if (!fpu_precision_valid(regs.fp[i].fpx)) { + test_exception = -1; } } } @@ -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; - fpustatus.floatx80_rounding_precision = 80; + 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); - // NaN - fpuregisters[7] = floatx80_default_nan(NULL); + 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); diff --git a/cputest/asm.S b/cputest/asm.S index fa10af8a..4baf3b84 100644 --- a/cputest/asm.S +++ b/cputest/asm.S @@ -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 diff --git a/cputest/main.c b/cputest/main.c index 0e3c7372..b7c4f166 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -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 16-bit exponent range value. (16383 = 1.0)\n"); + printf("-fpuadj 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
. 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; - } - } + is_fpu_adjust = 1; + fpu_adjust_exp += 16384; } else if (!_stricmp(s, "-cycles")) { cycles = 1; if (i + 1 < argc && argv[i][0] != '-') {