From: Toni Wilen Date: Sat, 28 Apr 2018 12:54:21 +0000 (+0300) Subject: MSVC 80-bit host FPU mode. X-Git-Tag: 4000~90 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=6bca38d06fac709a24f8c7e18f1290b37d7807a2;p=francis%2Fwinuae.git MSVC 80-bit host FPU mode. --- diff --git a/cfgfile.cpp b/cfgfile.cpp index b5b8ed01..3df845f2 100644 --- a/cfgfile.cpp +++ b/cfgfile.cpp @@ -2367,7 +2367,10 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type) cfgfile_dwrite_bool (f, _T("fpu_no_unimplemented"), p->fpu_no_unimplemented); cfgfile_dwrite_bool (f, _T("cpu_no_unimplemented"), p->int_no_unimplemented); cfgfile_write_bool (f, _T("fpu_strict"), p->fpu_strict); - cfgfile_dwrite_bool (f, _T("fpu_softfloat"), p->fpu_softfloat); + cfgfile_dwrite_bool (f, _T("fpu_softfloat"), p->fpu_mode > 0); +#ifdef MSVC_LONG_DOUBLE + cfgfile_dwrite_bool(f, _T("fpu_msvc_long_double"), p->fpu_mode < 0); +#endif cfgfile_write_bool (f, _T("rtg_nocustom"), p->picasso96_nocustom); cfgfile_write (f, _T("rtg_modes"), _T("0x%x"), p->picasso96_modeflags); @@ -5140,7 +5143,6 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH || cfgfile_yesno (option, value, _T("serial_hardware_ctsrts"), &p->serial_hwctsrts) || cfgfile_yesno (option, value, _T("serial_direct"), &p->serial_direct) || cfgfile_yesno (option, value, _T("fpu_strict"), &p->fpu_strict) - || cfgfile_yesno (option, value, _T("fpu_softfloat"), &p->fpu_softfloat) || cfgfile_yesno (option, value, _T("comp_nf"), &p->compnf) || cfgfile_yesno (option, value, _T("comp_constjump"), &p->comp_constjump) #ifdef USE_JIT_FPU @@ -5241,6 +5243,19 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH || cfgfile_string (option, value, _T("ghostscript_parameters"), p->ghostscript_parameters, sizeof p->ghostscript_parameters / sizeof (TCHAR))) return 1; + if (cfgfile_yesno(option, value, _T("fpu_softfloat"), &dummybool)) { + if (dummybool) + p->fpu_mode = 1; + return 1; + } +#ifdef MSVC_LONG_DOUBLE + if (cfgfile_yesno(option, value, _T("fpu_msvc_long_double"), &dummybool)) { + if (dummybool) + p->fpu_mode = -1; + return 1; + } +#endif + if (cfgfile_string(option, value, _T("uaeboard_options"), tmpbuf, sizeof tmpbuf / sizeof(TCHAR))) { TCHAR *s = cfgfile_option_get(value, _T("order")); if (s) @@ -7528,7 +7543,7 @@ void default_prefs (struct uae_prefs *p, bool reset, int type) p->fpu_no_unimplemented = false; p->int_no_unimplemented = false; p->fpu_strict = 0; - p->fpu_softfloat = 0; + p->fpu_mode = 0; p->m68k_speed = 0; p->cpu_compatible = 1; p->address_space_24 = 1; diff --git a/fpp.cpp b/fpp.cpp index 7ceb305f..578da31c 100644 --- a/fpp.cpp +++ b/fpp.cpp @@ -35,6 +35,13 @@ #include "softfloat/softfloat.h" +// global variable for JIT FPU +#ifdef USE_LONG_DOUBLE +bool use_long_double = true; +#else +bool use_long_double = false; +#endif + FPP_PRINT fpp_print; FPP_IS fpp_is_snan; @@ -346,7 +353,7 @@ STATIC_INLINE bool fp_is_dyadic(uae_u16 extra) static bool fp_exception_pending(bool pre) { // first check for pending arithmetic exceptions - if (currprefs.fpu_softfloat) { + if (currprefs.fpu_mode > 0) { if (regs.fp_exp_pend) { if (warned > 0) { write_log (_T("FPU ARITHMETIC EXCEPTION (%d)\n"), regs.fp_exp_pend); @@ -405,7 +412,7 @@ static uae_u32 fpsr_get_vector(uae_u32 exception) static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea) { - if (!currprefs.fpu_softfloat) + if (currprefs.fpu_mode <= 0) return; bool nonmaskable; @@ -427,7 +434,7 @@ static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 o #endif } - if (!currprefs.fpu_softfloat) { + if (currprefs.fpu_mode <= 0) { // log message and exit regs.fp_exp_pend = 0; return; @@ -588,7 +595,7 @@ static uae_u32 fpsr_make_status(void) if (regs.fpsr & (FPSR_OVFL | FPSR_INEX2 | FPSR_INEX1)) regs.fpsr |= FPSR_AE_INEX; // INEX = INEX1 || INEX2 || OVFL - if (!currprefs.fpu_softfloat) + if (currprefs.fpu_mode <= 0) return 0; // return exceptions that interrupt calculation @@ -607,7 +614,7 @@ static int fpsr_set_bsun(void) if (regs.fpcr & FPSR_BSUN) { // logging only so far write_log (_T("FPU exception: BSUN! (FPSR: %08x, FPCR: %04x)\n"), regs.fpsr, regs.fpcr); - if (currprefs.fpu_softfloat) { + if (currprefs.fpu_mode > 0) { regs.fp_exp_pend = fpsr_get_vector(FPSR_BSUN); fp_exception_pending(true); return 1; @@ -1218,7 +1225,7 @@ static void fpu_null (void) // 68040/060 does not support denormals static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src) { - if (!currprefs.fpu_softfloat) + if (currprefs.fpu_mode <= 0) return false; if (fpp_is_unnormal(src) || fpp_is_denormal(src)) { if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) { @@ -1236,7 +1243,7 @@ static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 ex } static bool normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *dst, fpdata *src) { - if (!currprefs.fpu_softfloat) + if (currprefs.fpu_mode <= 0) return false; if (fpp_is_unnormal(dst) || fpp_is_denormal(dst)) { if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) { @@ -1266,7 +1273,7 @@ static bool fault_if_no_packed_support(uae_u16 opcode, uae_u16 extra, uaecptr ea // 68040 does not support move to integer format static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src) { - if (currprefs.cpu_model == 68040 && currprefs.fpu_model && currprefs.fpu_softfloat) { + if (currprefs.cpu_model == 68040 && currprefs.fpu_model && currprefs.fpu_mode > 0) { fpsr_make_status(); if (regs.fpsr & (FPSR_SNAN | FPSR_OPERR)) { fpsr_check_arithmetic_exception(FPSR_SNAN | FPSR_OPERR, src, opcode, extra, ea); @@ -3055,8 +3062,13 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) fpu_noinst (opcode, pc); } +static bool plop; + void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra) { + if (plop) + write_log(_T("%04x %04x %08x\n"), opcode, extra, M68K_GETPC); + regs.fpu_state = 1; regs.fp_exception = false; fpu_mmu_fixup = false; @@ -3070,16 +3082,25 @@ void fpu_modechange(void) { uae_u32 temp_ext[8][3]; - if (currprefs.fpu_softfloat == changed_prefs.fpu_softfloat) + if (currprefs.fpu_mode == changed_prefs.fpu_mode) return; - currprefs.fpu_softfloat = changed_prefs.fpu_softfloat; + currprefs.fpu_mode = changed_prefs.fpu_mode; + set_cpu_caches(true); for (int i = 0; i < 8; i++) { fpp_from_exten_fmovem(®s.fp[i], &temp_ext[i][0], &temp_ext[i][1], &temp_ext[i][2]); } - if (currprefs.fpu_softfloat) { + if (currprefs.fpu_mode > 0) { fp_init_softfloat(); +#ifdef MSVC_LONG_DOUBLE + } else if (currprefs.fpu_mode < 0) { + use_long_double = true; + fp_init_native_80(); +#endif } else { +#ifdef MSVC_LONG_DOUBLE + use_long_double = false; +#endif fp_init_native(); } for (int i = 0; i < 8; i++) { @@ -3105,14 +3126,25 @@ static void fpu_test(void) void fpu_reset (void) { - if (currprefs.fpu_softfloat) { + if (currprefs.fpu_mode > 0) { fp_init_softfloat(); +#ifdef MSVC_LONG_DOUBLE + } else if (currprefs.fpu_mode < 0) { + use_long_double = true; + fp_init_native_80(); +#endif } else { +#ifdef MSVC_LONG_DOUBLE + use_long_double = false; +#endif fp_init_native(); } #if defined(CPU_i386) || defined(CPU_x86_64) init_fpucw_x87(); +#ifdef MSVC_LONG_DOUBLE + init_fpucw_x87_80(); +#endif #endif regs.fpiar = 0; diff --git a/fpp_native.cpp b/fpp_native.cpp index f7bccd56..3bc1ee54 100644 --- a/fpp_native.cpp +++ b/fpp_native.cpp @@ -1065,9 +1065,9 @@ static void fp_from_pack (fpdata *src, uae_u32 *wrd, int kfactor) wrd[0] = wrd[1] = wrd[2] = 0; - fpp_to_native(&fp, src); + fp_to_native(&fp, src); -#if USE_LONG_DOUBLE +#ifdef USE_LONG_DOUBLE sprintf (str, "%#.17Le", fp); #else sprintf (str, "%#.17e", fp); @@ -1241,12 +1241,12 @@ static void fp_to_pack (fpdata *fpd, uae_u32 *wrd, int dummy) *cp++ = ((wrd[0] >> 20) & 0xf) + '0'; *cp++ = ((wrd[0] >> 16) & 0xf) + '0'; *cp = 0; -#if USE_LONG_DOUBLE +#ifdef USE_LONG_DOUBLE sscanf (str, "%Le", &d); #else sscanf (str, "%le", &d); #endif - fpp_from_native(d, fpd); + fp_from_native(d, fpd); } @@ -1269,9 +1269,6 @@ void fp_init_native(void) fpp_clear_status = fp_clear_status; fpp_set_mode = fp_set_mode; - fpp_from_native = fp_from_native; - fpp_to_native = fp_to_native; - fpp_to_int = fp_to_int; fpp_from_int = fp_from_int; diff --git a/fpp_softfloat.cpp b/fpp_softfloat.cpp index cf2b6d8b..97e1d195 100644 --- a/fpp_softfloat.cpp +++ b/fpp_softfloat.cpp @@ -514,7 +514,7 @@ static void to_native(fptype *fp, fpdata *fpd) return; } if (fp_is_nan(fpd)) { -#if USE_LONG_DOUBLE +#ifdef USE_LONG_DOUBLE *fp = sqrtl(-1); #else *fp = sqrt(-1); @@ -523,7 +523,7 @@ static void to_native(fptype *fp, fpdata *fpd) } if (fp_is_infinity(fpd)) { double zero = 0.0; -#if USE_LONG_DOUBLE +#ifdef USE_LONG_DOUBLE *fp = fp_is_neg(fpd) ? logl(0.0) : (1.0 / zero); #else *fp = fp_is_neg(fpd) ? log(0.0) : (1.0 / zero); @@ -534,7 +534,7 @@ static void to_native(fptype *fp, fpdata *fpd) frac = (fptype)fpd->fpx.low / (fptype)(twoto32 * 2147483648.0); if (fp_is_neg(fpd)) frac = -frac; -#if USE_LONG_DOUBLE +#ifdef USE_LONG_DOUBLE *fp = ldexpl (frac, expon - 16383); #else *fp = ldexp (frac, expon - 16383); @@ -568,7 +568,7 @@ static void from_native(fptype fp, fpdata *fpd) if (fp < 0.0) fp = -fp; -#if USE_LONG_DOUBLE +#ifdef USE_LONG_DOUBLE frac = frexpl (fp, &expon); #else frac = frexp (fp, &expon); @@ -739,9 +739,6 @@ void fp_init_softfloat(void) fpp_clear_status = fp_clear_status; fpp_set_mode = fp_set_mode; - fpp_from_native = from_native; - fpp_to_native = to_native; - fpp_to_int = to_int; fpp_from_int = from_int; diff --git a/include/fpp.h b/include/fpp.h index b30c7455..7374d486 100644 --- a/include/fpp.h +++ b/include/fpp.h @@ -17,12 +17,18 @@ #define FPSR_INEX1 0x00000100 extern void fp_init_native(void); +#ifdef MSVC_LONG_DOUBLE +extern void fp_init_native_80(void); +#endif extern void fp_init_softfloat(void); extern void fpsr_set_exception(uae_u32 exception); extern void fpu_modechange(void); #if defined(CPU_i386) || defined(CPU_x86_64) extern void init_fpucw_x87(void); +#ifdef MSVC_LONG_DOUBLE +extern void init_fpucw_x87_80(void); +#endif #endif typedef void (*FPP_ABQS)(fpdata*, fpdata*, uae_u64*, uae_u8*); @@ -72,9 +78,6 @@ extern FPP_GET_STATUS fpp_get_status; extern FPP_CLEAR_STATUS fpp_clear_status; extern FPP_SET_MODE fpp_set_mode; -extern FPP_FROM_NATIVE fpp_from_native; -extern FPP_TO_NATIVE fpp_to_native; - extern FPP_TO_INT fpp_to_int; extern FPP_FROM_INT fpp_from_int; diff --git a/include/newcpu.h b/include/newcpu.h index 208b7183..8ceb3938 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -92,10 +92,8 @@ typedef uae_u8 flagtype; #ifdef USE_LONG_DOUBLE typedef long double fptype; -#define LDPTR tbyte ptr #else typedef double fptype; -#define LDPTR qword ptr #endif #endif @@ -143,10 +141,25 @@ struct mmufixup }; extern struct mmufixup mmufixup[2]; +#ifdef MSVC_LONG_DOUBLE +typedef struct { + uae_u64 m; + uae_u16 e; + uae_u16 dummy; +} fprawtype; +#endif + typedef struct { floatx80 fpx; +#ifdef MSVC_LONG_DOUBLE + union { + fptype fp; + fprawtype rfp; + }; +#else fptype fp; +#endif } fpdata; struct regstruct diff --git a/include/options.h b/include/options.h index b27fc805..9cc6d022 100644 --- a/include/options.h +++ b/include/options.h @@ -493,7 +493,7 @@ struct uae_prefs { bool comp_constjump; int cachesize; bool fpu_strict; - bool fpu_softfloat; + int fpu_mode; struct monconfig gfx_monitor[MAX_AMIGADISPLAYS]; int gfx_framerate, gfx_autoframerate; diff --git a/include/sysdeps.h b/include/sysdeps.h index a4507e2a..3c276c4a 100644 --- a/include/sysdeps.h +++ b/include/sysdeps.h @@ -470,6 +470,7 @@ extern void logging_init (void); extern FILE *log_open (const TCHAR *name, int append, int bootlog, TCHAR*); extern void log_close (FILE *f); +extern bool use_long_double; #ifndef O_BINARY #define O_BINARY 0 diff --git a/jit/compemu_support.cpp b/jit/compemu_support.cpp index eaac9c28..54150c0e 100644 --- a/jit/compemu_support.cpp +++ b/jit/compemu_support.cpp @@ -2195,11 +2195,11 @@ static void bt_l_ri_noclobber(RR4 r, IMM i) static void f_tomem(int r) { if (live.fate[r].status==DIRTY) { -#if defined(USE_LONG_DOUBLE) - raw_fmov_ext_mr((uintptr)live.fate[r].mem,live.fate[r].realreg); -#else - raw_fmov_mr((uintptr)live.fate[r].mem,live.fate[r].realreg); -#endif + if (use_long_double) { + raw_fmov_ext_mr((uintptr)live.fate[r].mem, live.fate[r].realreg); + } else { + raw_fmov_mr((uintptr)live.fate[r].mem, live.fate[r].realreg); + } live.fate[r].status=CLEAN; } } @@ -2207,11 +2207,11 @@ static void f_tomem(int r) static void f_tomem_drop(int r) { if (live.fate[r].status==DIRTY) { -#if defined(USE_LONG_DOUBLE) - raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg); -#else - raw_fmov_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg); -#endif + if (use_long_double) { + raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem, live.fate[r].realreg); + } else { + raw_fmov_mr_drop((uintptr)live.fate[r].mem, live.fate[r].realreg); + } live.fate[r].status=INMEM; } } @@ -2315,11 +2315,11 @@ static int f_alloc_reg(int r, int willclobber) if (!willclobber) { if (live.fate[r].status!=UNDEF) { -#if defined(USE_LONG_DOUBLE) - raw_fmov_ext_rm(bestreg,(uintptr)live.fate[r].mem); -#else - raw_fmov_rm(bestreg,(uintptr)live.fate[r].mem); -#endif + if (use_long_double) { + raw_fmov_ext_rm(bestreg, (uintptr)live.fate[r].mem); + } else { + raw_fmov_rm(bestreg, (uintptr)live.fate[r].mem); + } } live.fate[r].status=CLEAN; } diff --git a/jit/compemu_support_codegen.cpp b/jit/compemu_support_codegen.cpp index 86b4086a..ee291618 100644 --- a/jit/compemu_support_codegen.cpp +++ b/jit/compemu_support_codegen.cpp @@ -1967,24 +1967,24 @@ static void bt_l_ri_noclobber(R4 r, IMM i) static void f_tomem(int r) { if (live.fate[r].status==DIRTY) { -#if USE_LONG_DOUBLE - raw_fmov_ext_mr((uintptr)live.fate[r].mem,live.fate[r].realreg); -#else - raw_fmov_mr((uintptr)live.fate[r].mem,live.fate[r].realreg); -#endif - live.fate[r].status=CLEAN; + if (use_long_double) { + raw_fmov_ext_mr((uintptr)live.fate[r].mem, live.fate[r].realreg); + } else { + raw_fmov_mr((uintptr)live.fate[r].mem, live.fate[r].realreg); + } + live.fate[r].status=CLEAN; } } static void f_tomem_drop(int r) { - if (live.fate[r].status==DIRTY) { -#if USE_LONG_DOUBLE - raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg); -#else - raw_fmov_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg); -#endif - live.fate[r].status=INMEM; + if (live.fate[r].status == DIRTY) { + if (use_long_double) { + raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem, live.fate[r].realreg); + } else { + raw_fmov_mr_drop((uintptr)live.fate[r].mem, live.fate[r].realreg); + } + live.fate[r].status=INMEM; } } @@ -2089,11 +2089,11 @@ static int f_alloc_reg(int r, int willclobber) if (!willclobber) { if (live.fate[r].status!=UNDEF) { -#if USE_LONG_DOUBLE - raw_fmov_ext_rm(bestreg,(uintptr)live.fate[r].mem); -#else - raw_fmov_rm(bestreg,(uintptr)live.fate[r].mem); -#endif + if (use_long_double) { + raw_fmov_ext_rm(bestreg, (uintptr)live.fate[r].mem); + } else { + raw_fmov_rm(bestreg, (uintptr)live.fate[r].mem); + } } live.fate[r].status=CLEAN; } @@ -6586,7 +6586,7 @@ void compiler_dumpstate(void) write_log("\n"); write_log("### M68k processor state\n"); - m68k_dumpstate(0); + m68k_dumpstate(NULL, 0xffffffff); write_log("\n"); write_log("### Block in Mac address space\n"); diff --git a/main.cpp b/main.cpp index 8aefd56f..67cbfb9a 100644 --- a/main.cpp +++ b/main.cpp @@ -300,9 +300,9 @@ void fixup_cpu (struct uae_prefs *p) error_log (_T("JIT is not compatible with unimplemented CPU/FPU instruction emulation.")); p->fpu_no_unimplemented = p->int_no_unimplemented = false; } - if (p->cachesize && p->compfpu && p->fpu_softfloat) { + if (p->cachesize && p->compfpu && p->fpu_mode > 0) { error_log (_T("JIT FPU emulation is not compatible with softfloat FPU emulation.")); - p->fpu_softfloat = false; + p->fpu_mode = 0; } #if 0 diff --git a/newcpu.cpp b/newcpu.cpp index 6d84fee4..771bba61 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -1878,7 +1878,7 @@ static void build_cpufunctbl (void) write_log(_T("CPU=%d, FPU=%d%s, MMU=%d, JIT%s=%d."), currprefs.cpu_model, - currprefs.fpu_model, currprefs.fpu_model ? (currprefs.fpu_softfloat ? _T(" (softfloat)") : _T(" (host)")) : _T(""), + currprefs.fpu_model, currprefs.fpu_model ? (currprefs.fpu_mode > 0 ? _T(" (softfloat)") : (currprefs.fpu_mode < 0 ? _T(" (host 80b)") : _T(" (host 64b)"))) : _T(""), currprefs.mmu_model, currprefs.cachesize ? (currprefs.compfpu ? _T("=CPU/FPU") : _T("=CPU")) : _T(""), currprefs.cachesize); @@ -2054,7 +2054,7 @@ static int check_prefs_changed_cpu2(void) || currprefs.cpu_compatible != changed_prefs.cpu_compatible || currprefs.cpu_cycle_exact != changed_prefs.cpu_cycle_exact || currprefs.cpu_memory_cycle_exact != changed_prefs.cpu_memory_cycle_exact - || currprefs.fpu_softfloat != changed_prefs.fpu_softfloat) { + || currprefs.fpu_mode != changed_prefs.fpu_mode) { cpu_prefs_changed_flag |= 1; } if (changed diff --git a/od-win32/asm.cmd b/od-win32/asm.cmd index 4a672104..8697e0c0 100644 --- a/od-win32/asm.cmd +++ b/od-win32/asm.cmd @@ -1,6 +1,9 @@ -nasm -O1 -f win32 hq2x32.asm -nasm -O1 -f win32 hq3x32.asm -nasm -O1 -f win32 hq4x32.asm -nasm -O1 -f win32 hq2x16.asm -nasm -O1 -f win32 hq3x16.asm -nasm -O1 -f win32 hq4x16.asm +nasm -f win32 fpux86_80.asm +nasm -f win64 fpux64_80.asm + +nasm -w-orphan-labels -f win32 hq2x32.asm +nasm -w-orphan-labels -f win32 hq3x32.asm +nasm -w-orphan-labels -f win32 hq4x32.asm +nasm -w-orphan-labels -f win32 hq2x16.asm +nasm -w-orphan-labels -f win32 hq3x16.asm +nasm -w-orphan-labels -f win32 hq4x16.asm diff --git a/od-win32/fpp_native_msvc_80bit.cpp b/od-win32/fpp_native_msvc_80bit.cpp new file mode 100644 index 00000000..e9d6832e --- /dev/null +++ b/od-win32/fpp_native_msvc_80bit.cpp @@ -0,0 +1,1231 @@ +/* +* UAE - The Un*x Amiga Emulator +* +* MC68881/68882/68040/68060 FPU emulation +* +* Native FPU, MSVC 80-bit hack +*/ + +#include +#include +#include + +#include "sysconfig.h" +#include "sysdeps.h" + +#define USE_HOST_ROUNDING 1 + +#include "options.h" +#include "memory.h" +#include "newcpu.h" +#include "fpp.h" +#include "uae/attributes.h" +#include "uae/vm.h" +#include "newcpu.h" +#include "softfloat/softfloat-specialize.h" + +extern "C" +{ + extern void _cdecl xfp_fldcw(uae_u16*); + extern void _cdecl xfp_int(void*, void*); + extern void _cdecl xfp_mov(void*, void*); + extern void _cdecl xfp_div(void*, void*); + extern void _cdecl xfp_mul(void*, void*); + extern void _cdecl xfp_abs(void*, void*); + extern void _cdecl xfp_neg(void*, void*); + extern void _cdecl xfp_add(void*, void*); + extern void _cdecl xfp_sub(void*, void*); + extern void _cdecl xfp_sqrt(void*, void*); + extern void _cdecl xfp_sin(void*, void*); + extern void _cdecl xfp_cos(void*, void*); + extern void _cdecl xfp_to_single(void*, uae_u32*); + extern void _cdecl xfp_from_single(void*, uae_u32*); + extern void _cdecl xfp_to_double(void*, uae_u32*); + extern void _cdecl xfp_from_double(void*, uae_u32*); + extern void _cdecl xfp_from_int(void*, uae_s32*); + extern void _cdecl xfp_to_int(void*, uae_s64*); + extern void _cdecl xfp_round_single(void*, void*); + extern void _cdecl xfp_round_double(void*, void*); + extern void _cdecl xfp_x_to_double(void*, fptype*); + extern void _cdecl xfp_x_from_double(void*, fptype*); + extern uae_u16 _cdecl xfp_get_status(void); + extern void _cdecl xfp_clear_status(void); +} +static uae_u16 fpx_mode = 0x107f; + +static uae_u32 xhex_nan[] ={0xffffffff, 0xffffffff, 0x7fff}; +static long double *fp_nan = (long double *)xhex_nan; + +#define FPCR_ROUNDING_MODE 0x00000030 +#define FPCR_ROUND_NEAR 0x00000000 +#define FPCR_ROUND_ZERO 0x00000010 +#define FPCR_ROUND_MINF 0x00000020 +#define FPCR_ROUND_PINF 0x00000030 + +#define FPCR_ROUNDING_PRECISION 0x000000c0 +#define FPCR_PRECISION_SINGLE 0x00000040 +#define FPCR_PRECISION_DOUBLE 0x00000080 +#define FPCR_PRECISION_EXTENDED 0x00000000 + +static struct float_status fs; +static uae_u32 fpu_mode_control = 0; +static int fpu_prec; +static int temp_prec; + +static void fp_set_mode(uae_u32 m68k_cw) +{ + // RN, RZ, RM, RP + static const uae_u16 fp87_round[4] = { 0 << 10, 3 << 10, 1 << 10, 2 << 10 }; + // Extend X, Single S, Double D, Undefined (Double) + static const uae_u16 fp87_prec[4] = { 3 << 8, 0 << 8, 2 << 8, 2 << 8 }; + + int round = (m68k_cw >> 4) & 3; + int prec = (m68k_cw >> 6) & 3; + + fpx_mode = fp87_round[round] | fp87_prec[prec] | 0x107f; + xfp_fldcw(&fpx_mode); +} + +/* The main motivation for dynamically creating an x86(-64) function in +* memory is because MSVC (x64) does not allow you to use inline assembly, +* and the x86-64 versions of _control87/_controlfp functions only modifies +* SSE2 registers. */ + +static uae_u16 x87_cw = 0; +static uae_u8 *x87_fldcw_code = NULL; +typedef void (uae_cdecl *x87_fldcw_function)(void); + +void init_fpucw_x87_80(void) +{ + if (x87_fldcw_code) { + return; + } + x87_fldcw_code = (uae_u8 *)uae_vm_alloc(uae_vm_page_size(), UAE_VM_32BIT, UAE_VM_READ_WRITE_EXECUTE); + uae_u8 *c = x87_fldcw_code; + /* mov eax,0x0 */ + *(c++) = 0xb8; + *(c++) = 0x00; + *(c++) = 0x00; + *(c++) = 0x00; + *(c++) = 0x00; +#ifdef CPU_x86_64 + /* Address override prefix */ + *(c++) = 0x67; +#endif + /* fldcw WORD PTR [eax+addr] */ + *(c++) = 0xd9; + *(c++) = 0xa8; + *(c++) = (((uintptr_t)&x87_cw)) & 0xff; + *(c++) = (((uintptr_t)&x87_cw) >> 8) & 0xff; + *(c++) = (((uintptr_t)&x87_cw) >> 16) & 0xff; + *(c++) = (((uintptr_t)&x87_cw) >> 24) & 0xff; + /* ret */ + *(c++) = 0xc3; + /* Write-protect the function */ + uae_vm_protect(x87_fldcw_code, uae_vm_page_size(), UAE_VM_READ_EXECUTE); +} + +static void native_set_fpucw(uae_u32 m68k_cw) +{ + static int ex = 0; + // RN, RZ, RM, RP + static const unsigned int fp87_round[4] = { _RC_NEAR, _RC_CHOP, _RC_DOWN, _RC_UP }; + // Extend X, Single S, Double D, Undefined + static const unsigned int fp87_prec[4] = { _PC_53, _PC_24, _PC_53, _PC_53 }; + int round = (m68k_cw >> 4) & 3; +#ifdef WIN64 + // x64 only sets SSE2, must also call x87_fldcw_code() to set FPU rounding mode. + _controlfp(ex | fp87_round[round], _MCW_RC); +#else + int prec = (m68k_cw >> 6) & 3; + // x86 sets both FPU and SSE2 rounding mode, don't need x87_fldcw_code() + _control87(ex | fp87_round[round] | fp87_prec[prec], _MCW_RC | _MCW_PC); + return; +#endif + static const uae_u16 x87_cw_tab[] = { + 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* Double */ + 0x107f, 0x1c7f, 0x147f, 0x187f, /* Single */ + 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* Double */ + 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* undefined (Double) */ + }; + x87_cw = x87_cw_tab[(m68k_cw >> 4) & 0xf]; + ((x87_fldcw_function)x87_fldcw_code)(); +} + +/* Functions for setting host/library modes and getting status */ +static void fp_set_mode_native(uae_u32 mode_control) +{ + if (mode_control == fpu_mode_control) + return; + switch (mode_control & FPCR_ROUNDING_PRECISION) { + case FPCR_PRECISION_EXTENDED: // X + fpu_prec = 80; + break; + case FPCR_PRECISION_SINGLE: // S + fpu_prec = 32; + break; + case FPCR_PRECISION_DOUBLE: // D + default: // undefined + fpu_prec = 64; + break; + } +#if USE_HOST_ROUNDING + if ((mode_control & FPCR_ROUNDING_MODE) != (fpu_mode_control & FPCR_ROUNDING_MODE)) { + switch (mode_control & FPCR_ROUNDING_MODE) { + case FPCR_ROUND_NEAR: // to neareset + fesetround(FE_TONEAREST); + break; + case FPCR_ROUND_ZERO: // to zero + fesetround(FE_TOWARDZERO); + break; + case FPCR_ROUND_MINF: // to minus + fesetround(FE_DOWNWARD); + break; + case FPCR_ROUND_PINF: // to plus + fesetround(FE_UPWARD); + break; + } + } + native_set_fpucw(mode_control); +#endif + fpu_mode_control = mode_control; +} + + +static bool xfp_changed; +static bool native_changed; + +static void xfp_resetprec(void) +{ + if (xfp_changed) + xfp_fldcw(&fpx_mode); +} +static void xfp_setprec(int prec) +{ + uae_u16 v = fpx_mode; + // clear precision fields + v &= ~(3 << 8); + switch (prec) + { + case 0: + break; + case 32: + v |= 2 << 8; + break; + default: + case 64: + v |= 3 << 8; + break; + } + if (v != fpx_mode) { + xfp_fldcw(&v); + xfp_changed = true; + } else { + xfp_changed = false; + } +} + +// Must use default precision/rounding mode when calling C-library math functions. +static void fp_normal_prec(void) +{ + if ((fpu_mode_control & FPCR_ROUNDING_PRECISION) != FPCR_PRECISION_DOUBLE || (fpu_mode_control & FPCR_ROUNDING_MODE) != FPCR_ROUND_NEAR) { + fp_set_mode_native(FPCR_PRECISION_DOUBLE | FPCR_ROUND_NEAR); + native_changed = true; + } else { + native_changed = false; + } +} + +static void fp_reset_normal_prec(void) +{ + if (native_changed) { + fp_set_mode_native(temp_prec); + xfp_fldcw(&fpx_mode); + } +} + +static void fp_get_status(uae_u32 *status) +{ + uae_u16 st = xfp_get_status(); + + if (st & (1 << 5)) + *status |= FPSR_INEX2; + if (st & (1 << 4)) + *status |= FPSR_UNFL; + if (st & (1 << 3)) + *status |= FPSR_OVFL; + if (st & (1 << 2)) + *status |= FPSR_DZ; +} + +static void fp_clear_status(void) +{ + xfp_clear_status(); +} + +static void toxnative(fpdata *fpd, fptype *fp) +{ + xfp_x_to_double(&fpd->rfp, fp); +} +static void fromxnative(fptype *fp, fpdata *fpd) +{ + xfp_x_from_double(&fpd->rfp, fp); + fp_clear_status(); +} + +static void xfp_to_softfloat(fpdata *fpd) +{ + fpd->fpx.high = fpd->rfp.e; + fpd->fpx.low = fpd->rfp.m; +} +static void xfp_from_softfloat(fpdata *fpd) +{ + fpd->rfp.e = fpd->fpx.high; + fpd->rfp.m = fpd->fpx.low; +} + +/* Functions for detecting float type */ +static bool fp_is_snan(fpdata *fpd) +{ + return 0; /* FIXME: how to detect SNAN */ +} +static bool fp_unset_snan(fpdata *fpd) +{ + /* FIXME: how to unset SNAN */ + return 0; +} +static bool fp_is_nan (fpdata *fpd) +{ + xfp_to_softfloat(fpd); + return floatx80_is_nan(fpd->fpx); +} +static bool fp_is_infinity (fpdata *fpd) +{ + xfp_to_softfloat(fpd); + return floatx80_is_infinity(fpd->fpx); +} +static bool fp_is_zero(fpdata *fpd) +{ + xfp_to_softfloat(fpd); + return floatx80_is_zero(fpd->fpx); +} +static bool fp_is_neg(fpdata *fpd) +{ + xfp_to_softfloat(fpd); + return floatx80_is_negative(fpd->fpx); +} +static bool fp_is_denormal(fpdata *fpd) +{ + return false; + //return (isnormal(fpd->fp) == 0); /* FIXME: how to differ denormal/unnormal? */ +} +static bool fp_is_unnormal(fpdata *fpd) +{ + return false; + //return (isnormal(fpd->fp) == 0); /* FIXME: how to differ denormal/unnormal? */ +} + +/* Functions for converting between float formats */ +/* FIXME: how to preserve/fix denormals and unnormals? */ + +static void fp_to_native(fptype *fp, fpdata *fpd) +{ + toxnative(fpd, fp); +} +static void fp_from_native(fptype fp, fpdata *fpd) +{ + fromxnative(&fp, fpd); +} + +static void fp_to_single(fpdata *fpd, uae_u32 wrd1) +{ + xfp_to_single(&fpd->rfp, &wrd1); +} +static uae_u32 fp_from_single(fpdata *fpd) +{ + uae_u32 v; + xfp_from_single(&fpd->rfp, &v); + return v; +} + +static void fp_to_double(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2) +{ + uae_u32 v[2] = { wrd2, wrd1 }; + xfp_to_double(&fpd->rfp, v); +} +static void fp_from_double(fpdata *fpd, uae_u32 *wrd1, uae_u32 *wrd2) +{ + uae_u32 v[2]; + xfp_from_double(&fpd->rfp, v); + *wrd1 = v[1]; + *wrd2 = v[0]; +} +static void fp_to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +{ + fpd->rfp.m = ((uae_u64)wrd2 << 32) | wrd3; + fpd->rfp.e = wrd1 >> 16; +} +static void fp_from_exten(fpdata *fpd, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3) +{ + *wrd3 = (uae_u32)fpd->rfp.m; + *wrd2 = fpd->rfp.m >> 32; + *wrd1 = (uae_u32)fpd->rfp.e << 16; +} + +static uae_s64 fp_to_int(fpdata *src, int size) +{ + static const fptype fxsizes1[6] = + { + -128.0, 127.0, + -32768.0, 32767.0, + -2147483648.0, 2147483647.0 + }; + static const uae_s64 fxsizes2[6] = + { + -128, 127, + -32768, 32767, + -2147483648LL, 2147483647 + }; + // x86 FPU returns infinity if conversion to integer is out + // of range so convert to double first, then do range check + fptype d; + xfp_x_to_double(&src->rfp, &d); + if (d < fxsizes1[size * 2 + 0]) { + return fxsizes2[size * 2 + 0]; + } if (d > fxsizes1[size * 2 + 1]) { + return fxsizes2[size * 2 + 1]; + } + uae_s64 v; + xfp_to_int(&src->rfp, &v); + return v; +} +static void fp_from_int(fpdata *fpd, uae_s32 src) +{ + xfp_from_int(&fpd->rfp, &src); +} + +/* Functions for rounding */ + +// round to float with extended precision exponent +static void fp_round32(fpdata *fpd) +{ + int expon; + float mant; + fptype fp; + toxnative(fpd, &fp); + fp_normal_prec(); + mant = (float)(frexpl(fp, &expon) * 2.0); + fp = ldexpl((fptype)mant, expon - 1); + fp_reset_normal_prec(); + fromxnative(&fp, fpd); +} + +// round to double with extended precision exponent +static void fp_round64(fpdata *fpd) +{ + int expon; + double mant; + fptype fp; + toxnative(fpd, &fp); + fp_normal_prec(); + mant = (double)(frexpl(fp, &expon) * 2.0); + fp = ldexpl((fptype)mant, expon - 1); + fp_reset_normal_prec(); + fromxnative(&fp, fpd); +} + +// round to float +static void fp_round_single(fpdata *fpd) +{ + xfp_round_single(&fpd->rfp, &fpd->rfp); +} + +// round to double +static void fp_round_double(fpdata *fpd) +{ + xfp_round_double(&fpd->rfp, &fpd->rfp); +} + +static const TCHAR *fp_print(fpdata *fpd, int mode) +{ + static TCHAR fsout[32]; + bool n; + fptype fp; + + if (mode < 0) { + uae_u32 w1, w2, w3; + fp_from_exten(fpd, &w1, &w2, &w3); + _stprintf(fsout, _T("%04X-%08X-%08X"), w1 >> 16, w2, w3); + return fsout; + } + toxnative(fpd, &fp); + fp_normal_prec(); + + n = signbit(fp) ? 1 : 0; + + if(isinf(fp)) { + _stprintf(fsout, _T("%c%s"), n ? '-' : '+', _T("inf")); + } else if(isnan(fp)) { + _stprintf(fsout, _T("%c%s"), n ? '-' : '+', _T("nan")); + } else { + if(n) + fpd->fp *= -1.0; + _stprintf(fsout, _T("#%e"), fp); + } + fp_reset_normal_prec(); + if (mode == 0 || mode > _tcslen(fsout)) + return fsout; + fsout[mode] = 0; + return fsout; +} + +static void fp_round_prec(fpdata *fpd, int prec) +{ + if (prec == 64) { + fp_round_double(fpd); + } else if (prec == 32) { + fp_round_single(fpd); + } +} + +static void fp_round(fpdata *fpd) +{ + if (!currprefs.fpu_strict) + return; + fp_round_prec(fpd, fpu_prec); +} + +/* Arithmetic functions */ + +static void fp_move(fpdata *a, fpdata *b, int prec) +{ + xfp_setprec(prec); + xfp_mov(&a->rfp, &b->rfp); + xfp_resetprec(); +} + +static void fp_int(fpdata *a, fpdata *b) +{ + xfp_int(&a->rfp, &b->rfp); +} + +static void fp_getexp(fpdata *a, fpdata *b) +{ + int expon; + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + frexpl(bb, &expon); + aa = (fptype) (expon - 1); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_getman(fpdata *a, fpdata *b) +{ + int expon; + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = frexpl(bb, &expon) * 2.0; + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_div(fpdata *a, fpdata *b, int prec) +{ + xfp_setprec(prec); + xfp_div(&a->rfp, &b->rfp); + xfp_resetprec(); +} +static void fp_mod(fpdata *a, fpdata *b, uae_u64 *q, uae_u8 *s) +{ + fptype quot; + fptype aa, bb; + toxnative(a, &aa); + toxnative(b, &bb); +#if USE_HOST_ROUNDING + quot = truncl(aa / bb); +#else + quot = fp_round_to_zero(aa / bb); +#endif + if (quot < 0.0) { + *s = 1; + quot = -quot; + } else { + *s = 0; + } + *q = (uae_u64)quot; + aa = fmodl(aa, bb); + fromxnative(&aa, a); +} + +static void fp_rem(fpdata *a, fpdata *b, uae_u64 *q, uae_u8 *s) +{ + fptype quot; + fptype aa, bb; + toxnative(a, &aa); + toxnative(b, &bb); +#if USE_HOST_ROUNDING + quot = roundl(aa / bb); +#else + quot = fp_round_to_nearest(aa / bb); +#endif + if (quot < 0.0) { + *s = 1; + quot = -quot; + } else { + *s = 0; + } + *q = (uae_u64)quot; + aa = remainderl(aa, bb); + fromxnative(&aa, a); +} + +static void fp_scale(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(a, &aa); + toxnative(b, &bb); + fp_normal_prec(); + aa = ldexpl(aa, (int)bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} + +static void fp_sinh(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = sinhl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_intrz(fpdata *a, fpdata *b) +{ + if ((fpx_mode & (3 << 10)) == (3 << 10)) { + xfp_int(&a->rfp, &b->rfp); + } else { + uae_u16 old = fpx_mode; + uae_u16 s = fpx_mode | (3 << 10); + xfp_fldcw(&s); + xfp_int(&a->rfp, &b->rfp); + xfp_fldcw(&old); + } +} +static void fp_sqrt(fpdata *a, fpdata *b, int prec) +{ + xfp_setprec(prec); + xfp_sqrt(&a->rfp, &b->rfp); + xfp_resetprec(); +} +static void fp_lognp1(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = log1pl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_etoxm1(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = expm1l(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_tanh(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + a->fp = tanhl(b->fp); + fp_reset_normal_prec(); + fp_round(a); + fromxnative(&aa, a); +} +static void fp_atan(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = atanl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_atanh(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = atanhl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_sin(fpdata *a, fpdata *b) +{ + xfp_sin(&a->rfp, &b->rfp); +} +static void fp_asin(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = asinl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_tan(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = tanl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_etox(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = expl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_twotox(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = powl(2.0, bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_tentox(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = powl(10.0, bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_logn(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = logl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_log10(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = log10l(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_log2(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = log2l(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_abs(fpdata *a, fpdata *b, int prec) +{ + xfp_setprec(prec); + xfp_abs(&a->rfp, &b->rfp); + xfp_resetprec(); +} +static void fp_cosh(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = coshl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_neg(fpdata *a, fpdata *b, int prec) +{ + xfp_setprec(prec); + xfp_neg(&a->rfp, &b->rfp); + xfp_resetprec(); +} +static void fp_acos(fpdata *a, fpdata *b) +{ + fptype aa, bb; + toxnative(b, &bb); + fp_normal_prec(); + aa = acosl(bb); + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_cos(fpdata *a, fpdata *b) +{ + xfp_cos(&a->rfp, &b->rfp); +} +static void fp_sub(fpdata *a, fpdata *b, int prec) +{ + xfp_setprec(prec); + xfp_sub(&a->rfp, &b->rfp); + xfp_resetprec(); +} +static void fp_add(fpdata *a, fpdata *b, int prec) +{ + xfp_setprec(prec); + xfp_add(&a->rfp, &b->rfp); + xfp_resetprec(); +} +static void fp_mul(fpdata *a, fpdata *b, int prec) +{ + xfp_setprec(prec); + xfp_mul(&a->rfp, &b->rfp); + xfp_resetprec(); +} +static void fp_sglmul(fpdata *a, fpdata *b) +{ + float mant; + int expon; + + xfp_mul(&a->rfp, &b->rfp); + + fptype aa; + toxnative(a, &aa); + fp_normal_prec(); + + mant = (float)(frexpl(aa, &expon) * 2.0); + aa = ldexpl((fptype)mant, expon - 1); + + fp_reset_normal_prec(); + fromxnative(&aa, a); +} +static void fp_sgldiv(fpdata *a, fpdata *b) +{ + float mant; + int expon; + + xfp_div(&a->rfp, &b->rfp); + + fptype aa; + toxnative(a, &aa); + fp_normal_prec(); + + mant = (float)(frexpl(aa, &expon) * 2.0); + aa = ldexpl((fptype)mant, expon - 1); + + fp_reset_normal_prec(); + fromxnative(&aa, a); +} + +static void fp_normalize(fpdata *a) +{ +} + +static void fp_cmp(fpdata *a, fpdata *b) +{ + xfp_setprec(64); + fptype v = 1.0; + if (currprefs.fpu_strict) { + bool xvset = false; + bool a_neg = fpp_is_neg(a); + bool b_neg = fpp_is_neg(b); + bool a_inf = fpp_is_infinity(a); + bool b_inf = fpp_is_infinity(b); + bool a_zero = fpp_is_zero(a); + bool b_zero = fpp_is_zero(b); + bool a_nan = fpp_is_nan(a); + bool b_nan = fpp_is_nan(b); + + if (a_nan || b_nan) { + // FCMP never returns N + NaN + a->rfp.m = ((uae_u64)xhex_nan[0] << 32) | xhex_nan[1]; + a->rfp.e = xhex_nan[2]; + xvset = true; + } else if (a_zero && b_zero) { + if ((a_neg && b_neg) || (a_neg && !b_neg)) + v = -0.0; + else + v = 0.0; + } else if (a_zero && b_inf) { + if (!b_neg) + v = -1.0; + else + v = 1.0; + } else if (a_inf && b_zero) { + if (!a_neg) + v = -1.0; + else + v = 1.0; + } else if (a_inf && b_inf) { + if (a_neg == b_neg) + v = 0.0; + if ((a_neg && b_neg) || (a_neg && !b_neg)) + v = -v; + } else if (a_inf) { + if (a_neg) + v = -1.0; + } else if (b_inf) { + if (!b_neg) + v = -1.0; + } else { + xfp_sub(&a->rfp, &b->rfp); + xvset = true; + } + if (!xvset) + xfp_x_from_double(&a->rfp, &v); + } else { + xfp_sub(&a->rfp, &b->rfp); + } + fp_clear_status(); + xfp_resetprec(); +} + +static void fp_tst(fpdata *a, fpdata *b) +{ + a->rfp.m = b->rfp.m; + a->rfp.e = b->rfp.e; +} + +/* Functions for returning exception state data */ + +static void fp_get_internal_overflow(fpdata *fpd) +{ + fpd->rfp.m = 0; + fpd->rfp.e = 0; +} +static void fp_get_internal_underflow(fpdata *fpd) +{ + fpd->rfp.m = 0; + fpd->rfp.e = 0; +} +static void fp_get_internal_round_all(fpdata *fpd) +{ + fpd->rfp.m = 0; + fpd->rfp.e = 0; +} +static void fp_get_internal_round(fpdata *fpd) +{ + fpd->rfp.m = 0; + fpd->rfp.e = 0; +} +static void fp_get_internal_round_exten(fpdata *fpd) +{ + fpd->rfp.m = 0; + fpd->rfp.e = 0; +} +static void fp_get_internal(fpdata *fpd) +{ + fpd->rfp.m = 0; + fpd->rfp.e = 0; +} +static uae_u32 fp_get_internal_grs(void) +{ + return 0; +} + +/* Function for denormalizing */ +static void fp_denormalize(fpdata *fpd, int esign) +{ +} + +static void fp_from_pack (fpdata *src, uae_u32 *wrd, int kfactor) +{ + int i, j, t; + int exp; + int ndigits; + char *cp, *strp; + char str[100]; + fptype fp; + + if (fpp_is_nan (src)) { + // copy bit by bit, handle signaling nan + fpp_from_exten(src, &wrd[0], &wrd[1], &wrd[2]); + return; + } + if (fpp_is_infinity (src)) { + // extended exponent and all 0 packed fraction + fpp_from_exten(src, &wrd[0], &wrd[1], &wrd[2]); + wrd[1] = wrd[2] = 0; + return; + } + + wrd[0] = wrd[1] = wrd[2] = 0; + + fp_to_native(&fp, src); + fp_normal_prec(); + + sprintf (str, "%#.17e", fp); + + // get exponent + cp = str; + while (*cp != 'e') { + if (*cp == 0) + return; + cp++; + } + cp++; + if (*cp == '+') + cp++; + exp = atoi (cp); + + // remove trailing zeros + cp = str; + while (*cp != 'e') { + cp++; + } + cp[0] = 0; + cp--; + while (cp > str && *cp == '0') { + *cp = 0; + cp--; + } + + cp = str; + // get sign + if (*cp == '-') { + cp++; + wrd[0] = 0x80000000; + } else if (*cp == '+') { + cp++; + } + strp = cp; + + if (kfactor <= 0) { + ndigits = abs (exp) + (-kfactor) + 1; + } else { + if (kfactor > 17) { + kfactor = 17; + fpsr_set_exception(FPSR_OPERR); + } + ndigits = kfactor; + } + + if (ndigits < 0) + ndigits = 0; + if (ndigits > 16) + ndigits = 16; + + // remove decimal point + strp[1] = strp[0]; + strp++; + // add trailing zeros + i = strlen (strp); + cp = strp + i; + while (i < ndigits) { + *cp++ = '0'; + i++; + } + i = ndigits + 1; + while (i < 17) { + strp[i] = 0; + i++; + } + *cp = 0; + i = ndigits - 1; + // need to round? + if (i >= 0 && strp[i + 1] >= '5') { + while (i >= 0) { + strp[i]++; + if (strp[i] <= '9') + break; + if (i == 0) { + strp[i] = '1'; + exp++; + } else { + strp[i] = '0'; + } + i--; + } + } + strp[ndigits] = 0; + + // store first digit of mantissa + cp = strp; + wrd[0] |= *cp++ - '0'; + + // store rest of mantissa + for (j = 1; j < 3; j++) { + for (i = 0; i < 8; i++) { + wrd[j] <<= 4; + if (*cp >= '0' && *cp <= '9') + wrd[j] |= *cp++ - '0'; + } + } + + // exponent + if (exp < 0) { + wrd[0] |= 0x40000000; + exp = -exp; + } + if (exp > 9999) // ?? + exp = 9999; + if (exp > 999) { + int d = exp / 1000; + wrd[0] |= d << 12; + exp -= d * 1000; + fpsr_set_exception(FPSR_OPERR); + } + i = 100; + t = 0; + while (i >= 1) { + int d = exp / i; + t <<= 4; + t |= d; + exp -= d * i; + i /= 10; + } + wrd[0] |= t << 16; + fp_reset_normal_prec(); +} + +static void fp_to_pack (fpdata *fpd, uae_u32 *wrd, int dummy) +{ + fptype d; + char *cp; + char str[100]; + + if (((wrd[0] >> 16) & 0x7fff) == 0x7fff) { + // infinity has extended exponent and all 0 packed fraction + // nans are copies bit by bit + fpp_to_exten(fpd, wrd[0], wrd[1], wrd[2]); + return; + } + if (!(wrd[0] & 0xf) && !wrd[1] && !wrd[2]) { + // exponent is not cared about, if mantissa is zero + wrd[0] &= 0x80000000; + fpp_to_exten(fpd, wrd[0], wrd[1], wrd[2]); + return; + } + + fp_normal_prec(); + cp = str; + if (wrd[0] & 0x80000000) + *cp++ = '-'; + *cp++ = (wrd[0] & 0xf) + '0'; + *cp++ = '.'; + *cp++ = ((wrd[1] >> 28) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 24) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 20) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 16) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 12) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 8) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 4) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 0) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 28) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 24) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 20) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 16) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 12) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 8) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 4) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 0) & 0xf) + '0'; + *cp++ = 'E'; + if (wrd[0] & 0x40000000) + *cp++ = '-'; + *cp++ = ((wrd[0] >> 24) & 0xf) + '0'; + *cp++ = ((wrd[0] >> 20) & 0xf) + '0'; + *cp++ = ((wrd[0] >> 16) & 0xf) + '0'; + *cp = 0; + sscanf (str, "%le", &d); + fp_reset_normal_prec(); + fp_from_native(d, fpd); +} + + +void fp_init_native_80(void) +{ + set_floatx80_rounding_precision(80, &fs); + set_float_rounding_mode(float_round_to_zero, &fs); + + fpp_print = fp_print; + fpp_is_snan = fp_is_snan; + fpp_unset_snan = fp_unset_snan; + fpp_is_nan = fp_is_nan; + fpp_is_infinity = fp_is_infinity; + fpp_is_zero = fp_is_zero; + fpp_is_neg = fp_is_neg; + fpp_is_denormal = fp_is_denormal; + fpp_is_unnormal = fp_is_unnormal; + + fpp_get_status = fp_get_status; + fpp_clear_status = fp_clear_status; + fpp_set_mode = fp_set_mode; + + fpp_to_int = fp_to_int; + fpp_from_int = fp_from_int; + + fpp_to_pack = fp_to_pack; + fpp_from_pack = fp_from_pack; + + fpp_to_single = fp_to_single; + fpp_from_single = fp_from_single; + fpp_to_double = fp_to_double; + fpp_from_double = fp_from_double; + fpp_to_exten = fp_to_exten; + fpp_from_exten = fp_from_exten; + fpp_to_exten_fmovem = fp_to_exten; + fpp_from_exten_fmovem = fp_from_exten; + + fpp_round_single = fp_round_single; + fpp_round_double = fp_round_double; + fpp_round32 = fp_round32; + fpp_round64 = fp_round64; + + fpp_normalize = fp_normalize; + fpp_denormalize = fp_denormalize; + fpp_get_internal_overflow = fp_get_internal_overflow; + fpp_get_internal_underflow = fp_get_internal_underflow; + fpp_get_internal_round_all = fp_get_internal_round_all; + fpp_get_internal_round = fp_get_internal_round; + fpp_get_internal_round_exten = fp_get_internal_round_exten; + fpp_get_internal = fp_get_internal; + fpp_get_internal_grs = fp_get_internal_grs; + + fpp_int = fp_int; + fpp_sinh = fp_sinh; + fpp_intrz = fp_intrz; + fpp_sqrt = fp_sqrt; + fpp_lognp1 = fp_lognp1; + fpp_etoxm1 = fp_etoxm1; + fpp_tanh = fp_tanh; + fpp_atan = fp_atan; + fpp_atanh = fp_atanh; + fpp_sin = fp_sin; + fpp_asin = fp_asin; + fpp_tan = fp_tan; + fpp_etox = fp_etox; + fpp_twotox = fp_twotox; + fpp_tentox = fp_tentox; + fpp_logn = fp_logn; + fpp_log10 = fp_log10; + fpp_log2 = fp_log2; + fpp_abs = fp_abs; + fpp_cosh = fp_cosh; + fpp_neg = fp_neg; + fpp_acos = fp_acos; + fpp_cos = fp_cos; + fpp_getexp = fp_getexp; + fpp_getman = fp_getman; + fpp_div = fp_div; + fpp_mod = fp_mod; + fpp_add = fp_add; + fpp_mul = fp_mul; + fpp_rem = fp_rem; + fpp_scale = fp_scale; + fpp_sub = fp_sub; + fpp_sgldiv = fp_sgldiv; + fpp_sglmul = fp_sglmul; + fpp_cmp = fp_cmp; + fpp_tst = fp_tst; + fpp_move = fp_move; +} diff --git a/od-win32/fpux64_80.asm b/od-win32/fpux64_80.asm new file mode 100644 index 00000000..65d671f1 --- /dev/null +++ b/od-win32/fpux64_80.asm @@ -0,0 +1,175 @@ + +global xfp_int +global xfp_mov +global xfp_fldcw +global xfp_to_single +global xfp_from_single +global xfp_to_double +global xfp_from_double +global xfp_from_int +global xfp_to_int +global xfp_x_to_double +global xfp_x_from_double +global xfp_round_single +global xfp_round_double + +global xfp_div +global xfp_mul +global xfp_abs +global xfp_neg +global xfp_add +global xfp_sub +global xfp_sqrt +global xfp_sin +global xfp_cos +global xfp_get_status +global xfp_clear_status + +section .text + +bits 64 + +%macro loadfp1 0 + fld tword[rdx] +%endmacro + +%macro loadfp2 0 + fld tword[rcx] + fld tword[rdx] +%endmacro + +%macro storefp 0 + fstp tword[rcx] +%endmacro + + +xfp_fldcw: + fldcw word[rcx] + ret + +xfp_get_status: + fnstsw ax + ret + +xfp_clear_status: + fnclex + ret + +xfp_int: + loadfp1 + frndint + storefp + ret + +xfp_x_to_double: + fld tword[rcx] + fstp qword[rdx] + ret + +xfp_x_from_double: + fld qword[rdx] + fstp tword[rcx] + ret + +xfp_round_single: + fld tword[rdx] + fstp dword[rcx] + fld dword[rcx] + fstp tword[rcx] + ret + +xfp_round_double: + fld tword[rdx] + fstp qword[rcx] + fld qword[rcx] + fstp tword[rcx] + ret + +xfp_to_single: + fld dword[rdx] + fstp tword[rcx] + ret + +xfp_from_single: + fld tword[rcx] + fstp dword[rdx] + ret + +xfp_to_double: + fld qword[rdx] + fstp tword[rcx] + ret + +xfp_from_double: + fld tword[rcx] + fstp qword[rdx] + ret + +xfp_to_int: + fld tword[rcx] + fistp qword[rdx] + ret + +xfp_from_int: + fild dword[rdx] + fstp tword[rcx] + ret + +xfp_mov: + loadfp1 + storefp + ret + +xfp_add: + loadfp2 + faddp + storefp + ret + +xfp_sub: + loadfp2 + fsubp + storefp + ret + +xfp_div: + loadfp2 + fdivp + storefp + ret + +xfp_mul: + loadfp2 + fmulp + storefp + ret + +xfp_sqrt: + loadfp1 + fsqrt + storefp + ret + +xfp_neg: + loadfp1 + fchs + storefp + ret + +xfp_abs: + loadfp1 + fabs + storefp + ret + +xfp_cos: + loadfp1 + fcos + storefp + ret + +xfp_sin: + loadfp1 + fsin + storefp + ret diff --git a/od-win32/fpux86_80.asm b/od-win32/fpux86_80.asm new file mode 100644 index 00000000..459e2ab0 --- /dev/null +++ b/od-win32/fpux86_80.asm @@ -0,0 +1,197 @@ + +global _xfp_int +global _xfp_mov +global _xfp_fldcw +global _xfp_to_single +global _xfp_from_single +global _xfp_to_double +global _xfp_from_double +global _xfp_from_int +global _xfp_to_int +global _xfp_x_to_double +global _xfp_x_from_double +global _xfp_round_single +global _xfp_round_double + +global _xfp_div +global _xfp_mul +global _xfp_abs +global _xfp_neg +global _xfp_add +global _xfp_sub +global _xfp_sqrt +global _xfp_sin +global _xfp_cos +global _xfp_get_status +global _xfp_clear_status + +section .text + +%macro loadfp1 0 + mov eax,[esp+4] + mov ecx,[esp+8] + fld tword[ecx] +%endmacro + +%macro loadfp2 0 + mov eax,[esp+4] + mov ecx,[esp+8] + fld tword[eax] + fld tword[ecx] +%endmacro + +%macro storefp 0 + fstp tword[eax] +%endmacro + +_xfp_fldcw: + mov eax,[esp+4] + fldcw word[eax] + ret + +_xfp_get_status: + fnstsw ax + ret + +_xfp_clear_status: + fnclex + ret + +_xfp_int: + loadfp1 + frndint + storefp + ret + +_xfp_x_to_double: + mov ecx,[esp+4] + fld tword[ecx] + mov eax,[esp+8] + fstp qword[eax] + ret + +_xfp_x_from_double: + mov eax,[esp+8] + fld qword[eax] + mov ecx,[esp+4] + fstp tword[ecx] + ret + +_xfp_round_single: + mov ecx,[esp+8] + fld tword[ecx] + mov eax,[esp+4] + fstp dword[eax] + fld dword[eax] + fstp tword[eax] + ret + +_xfp_round_double: + mov ecx,[esp+8] + fld tword[ecx] + mov eax,[esp+4] + fstp qword[eax] + fld qword[eax] + fstp tword[eax] + ret + +_xfp_to_single: + mov ecx,[esp+8] + mov eax,[esp+4] + fld dword[ecx] + fstp tword[eax] + ret + +_xfp_from_single: + mov eax,[esp+4] + mov ecx,[esp+8] + fld tword[eax] + fstp dword[ecx] + ret + +_xfp_to_double: + mov ecx,[esp+8] + mov eax,[esp+4] + fld qword[ecx] + fstp tword[eax] + ret + +_xfp_from_double: + mov eax,[esp+4] + mov ecx,[esp+8] + fld tword[eax] + fstp qword[ecx] + ret + +_xfp_to_int: + mov eax,[esp+4] + mov ecx,[esp+8] + fld tword[eax] + fistp qword[ecx] + ret + +_xfp_from_int: + mov eax,[esp+4] + mov ecx,[esp+8] + fild dword[ecx] + fstp tword[eax] + ret + +_xfp_mov: + loadfp1 + storefp + ret + +_xfp_add: + loadfp2 + faddp + storefp + ret + +_xfp_sub: + loadfp2 + fsubp + storefp + ret + +_xfp_div: + loadfp2 + fdivp + storefp + ret + +_xfp_mul: + loadfp2 + fmulp + storefp + ret + +_xfp_sqrt: + loadfp1 + fsqrt + storefp + ret + +_xfp_neg: + loadfp1 + fchs + storefp + ret + +_xfp_abs: + loadfp1 + fabs + storefp + ret + +_xfp_cos: + loadfp1 + fcos + storefp + ret + +_xfp_sin: + loadfp1 + fsin + storefp + ret diff --git a/od-win32/resources/resource.h b/od-win32/resources/resource.h index a0fad723..03597b78 100644 --- a/od-win32/resources/resource.h +++ b/od-win32/resources/resource.h @@ -556,7 +556,7 @@ #define IDC_16BIT 1231 #define IDC_PPC_CPUIDLE 1231 #define IDC_11KHZ 1232 -#define IDC_FPU_SOFTFLOAT 1232 +#define IDC_FPU_MODE 1232 #define IDC_22KHZ 1233 #define IDC_SPEED_x86 1233 #define IDC_44KHZ 1234 diff --git a/od-win32/resources/winuae.rc b/od-win32/resources/winuae.rc index dc7185a3..2d914104 100644 --- a/od-win32/resources/winuae.rc +++ b/od-win32/resources/winuae.rc @@ -279,9 +279,9 @@ BEGIN CONTROL "68882",IDC_FPU2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,8,249,87,10 CONTROL "CPU internal",IDC_FPU3,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,8,262,93,10 CONTROL "More compatible [] More compatible but slower FPU emulation.",IDC_COMPATIBLE_FPU, - "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,8,276,117,10 + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,8,275,117,10 CONTROL "Unimplemented FPU emu [] Emulate FPU unimplemented instructions",IDC_FPU_UNIMPLEMENTED, - "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,8,289,116,10 + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,8,287,116,10 GROUPBOX "CPU Emulation Speed",IDC_STATIC,136,1,258,97 CONTROL "Fastest possible",IDC_CS_HOST,"Button",BS_AUTORADIOBUTTON | BS_LEFT | WS_GROUP | WS_TABSTOP,143,19,195,10 CONTROL "Approximate A500/A1200 or cycle-exact",IDC_CS_68000, @@ -314,10 +314,10 @@ BEGIN CONTROL "Direct",IDC_TRUST0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,143,299,72,10 CONTROL "Indirect",IDC_TRUST1,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,221,299,72,10 CONTROL "No flags",IDC_NOFLAGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,299,299,68,11 - CONTROL "Softfloat FPU emulation",IDC_FPU_SOFTFLOAT,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,8,302,115,10 GROUPBOX "MMU",IDC_STATIC,2,168,129,42,BS_LEFT CONTROL "Data cache emulation [] 68030, 040 and 060 optional data cache emulation. Requires More compatible option.",IDC_CPUDATACACHE, "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,8,123,119,12 + COMBOBOX IDC_FPU_MODE,7,299,112,75,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_FLOPPY DIALOGEX 0, 0, 396, 261 diff --git a/od-win32/sysconfig.h b/od-win32/sysconfig.h index 584f1daa..74d42a1a 100644 --- a/od-win32/sysconfig.h +++ b/od-win32/sysconfig.h @@ -14,6 +14,7 @@ #define GFXFILTER #define X86_MSVC_ASSEMBLY #define OPTIMIZED_FLAGS +#define MSVC_LONG_DOUBLE #ifndef __i386__ #define __i386__ #endif diff --git a/od-win32/win32gui.cpp b/od-win32/win32gui.cpp index 373d5cee..648203f2 100644 --- a/od-win32/win32gui.cpp +++ b/od-win32/win32gui.cpp @@ -11604,33 +11604,33 @@ static void enable_for_cpudlg (HWND hDlg) #endif enable = jitenable && workprefs.cachesize; - ew (hDlg, IDC_TRUST0, enable); - ew (hDlg, IDC_TRUST1, enable); - ew (hDlg, IDC_HARDFLUSH, enable); - ew (hDlg, IDC_CONSTJUMP, enable); - ew (hDlg, IDC_JITFPU, enable); - ew (hDlg, IDC_NOFLAGS, enable); - ew (hDlg, IDC_CS_CACHE_TEXT, enable); - ew (hDlg, IDC_CACHE, enable); - ew (hDlg, IDC_JITENABLE, jitenable); - ew (hDlg, IDC_COMPATIBLE, !workprefs.cpu_memory_cycle_exact && !(workprefs.cachesize && workprefs.cpu_model >= 68040)); - ew (hDlg, IDC_COMPATIBLE_FPU, workprefs.fpu_model > 0); - ew (hDlg, IDC_FPU_UNIMPLEMENTED, workprefs.fpu_model && !workprefs.cachesize); - ew (hDlg, IDC_FPU_SOFTFLOAT, workprefs.fpu_model && (!workprefs.compfpu || !workprefs.cachesize)); - ew (hDlg, IDC_CPU_UNIMPLEMENTED, workprefs.cpu_model == 68060 && !workprefs.cachesize); + ew(hDlg, IDC_FPU_MODE, workprefs.fpu_model != 0); + ew(hDlg, IDC_TRUST0, enable); + ew(hDlg, IDC_TRUST1, enable); + ew(hDlg, IDC_HARDFLUSH, enable); + ew(hDlg, IDC_CONSTJUMP, enable); + ew(hDlg, IDC_JITFPU, enable); + ew(hDlg, IDC_NOFLAGS, enable); + ew(hDlg, IDC_CS_CACHE_TEXT, enable); + ew(hDlg, IDC_CACHE, enable); + ew(hDlg, IDC_JITENABLE, jitenable); + ew(hDlg, IDC_COMPATIBLE, !workprefs.cpu_memory_cycle_exact && !(workprefs.cachesize && workprefs.cpu_model >= 68040)); + ew(hDlg, IDC_COMPATIBLE_FPU, workprefs.fpu_model > 0); + ew(hDlg, IDC_FPU_UNIMPLEMENTED, workprefs.fpu_model && !workprefs.cachesize); + ew(hDlg, IDC_CPU_UNIMPLEMENTED, workprefs.cpu_model == 68060 && !workprefs.cachesize); #if 0 - ew (hDlg, IDC_CPU_MULTIPLIER, workprefs.cpu_cycle_exact); + ew(hDlg, IDC_CPU_MULTIPLIER, workprefs.cpu_cycle_exact); #endif - ew (hDlg, IDC_CPU_FREQUENCY, workprefs.cpu_cycle_exact && workprefs.m68k_speed >= 0); - ew (hDlg, IDC_CPU_FREQUENCY2, workprefs.cpu_cycle_exact && !workprefs.cpu_clock_multiplier && workprefs.m68k_speed >= 0); + ew(hDlg, IDC_CPU_FREQUENCY, workprefs.cpu_cycle_exact && workprefs.m68k_speed >= 0); + ew(hDlg, IDC_CPU_FREQUENCY2, workprefs.cpu_cycle_exact && !workprefs.cpu_clock_multiplier && workprefs.m68k_speed >= 0); - ew (hDlg, IDC_FPU1, workprefs.cpu_model < 68040 && (workprefs.cpu_model >= 68020 || !workprefs.cpu_compatible)); - ew (hDlg, IDC_FPU2, workprefs.cpu_model < 68040 && (workprefs.cpu_model >= 68020 || !workprefs.cpu_compatible)); - ew (hDlg, IDC_FPU3, workprefs.cpu_model >= 68040); - ew (hDlg, IDC_MMUENABLEEC, workprefs.cpu_model >= 68030 && workprefs.cachesize == 0); - ew (hDlg, IDC_MMUENABLE, workprefs.cpu_model >= 68030 && workprefs.cachesize == 0); - ew (hDlg, IDC_CPUDATACACHE, workprefs.cpu_model >= 68030 && workprefs.cachesize == 0 && workprefs.cpu_compatible); - ew (hDlg, IDC_CPU_PPC, workprefs.cpu_model >= 68040 && (workprefs.ppc_mode == 1 || (workprefs.ppc_mode == 0 && !is_ppc_cpu(&workprefs)))); + ew(hDlg, IDC_FPU1, workprefs.cpu_model < 68040 && (workprefs.cpu_model >= 68020 || !workprefs.cpu_compatible)); + ew(hDlg, IDC_FPU2, workprefs.cpu_model < 68040 && (workprefs.cpu_model >= 68020 || !workprefs.cpu_compatible)); + ew(hDlg, IDC_FPU3, workprefs.cpu_model >= 68040); + ew(hDlg, IDC_MMUENABLEEC, workprefs.cpu_model >= 68030 && workprefs.cachesize == 0); + ew(hDlg, IDC_MMUENABLE, workprefs.cpu_model >= 68030 && workprefs.cachesize == 0); + ew(hDlg, IDC_CPUDATACACHE, workprefs.cpu_model >= 68030 && workprefs.cachesize == 0 && workprefs.cpu_compatible); + ew(hDlg, IDC_CPU_PPC, workprefs.cpu_model >= 68040 && (workprefs.ppc_mode == 1 || (workprefs.ppc_mode == 0 && !is_ppc_cpu(&workprefs)))); SendDlgItemMessage(hDlg, IDC_SPEED, TBM_SETRANGE, TRUE, workprefs.m68k_speed < 0 || (workprefs.cpu_memory_cycle_exact && !workprefs.cpu_cycle_exact) ? MAKELONG(-9, 0) : MAKELONG(-9, 50)); SendDlgItemMessage(hDlg, IDC_SPEED, TBM_SETPAGESIZE, 0, 1); @@ -11666,7 +11666,7 @@ static void values_to_cpudlg (HWND hDlg) CheckDlgButton (hDlg, IDC_CPUDATACACHE, workprefs.cpu_data_cache); CheckDlgButton (hDlg, IDC_COMPATIBLE_FPU, workprefs.fpu_strict); CheckDlgButton (hDlg, IDC_FPU_UNIMPLEMENTED, !workprefs.fpu_no_unimplemented || workprefs.cachesize); - CheckDlgButton (hDlg, IDC_FPU_SOFTFLOAT, workprefs.fpu_softfloat); + SendDlgItemMessage(hDlg, IDC_FPU_MODE, CB_SETCURSEL, workprefs.fpu_mode < 0 ? 1 : (workprefs.fpu_mode > 0 ? 2 : 0), 0); CheckDlgButton (hDlg, IDC_CPU_UNIMPLEMENTED, !workprefs.int_no_unimplemented || workprefs.cachesize); SendDlgItemMessage (hDlg, IDC_CPUIDLE, TBM_SETPOS, TRUE, workprefs.cpu_idle == 0 ? 0 : 12 - workprefs.cpu_idle / 15); SendDlgItemMessage (hDlg, IDC_PPC_CPUIDLE, TBM_SETPOS, TRUE, workprefs.ppc_cpu_idle); @@ -11726,7 +11726,6 @@ static void values_from_cpudlg (HWND hDlg) workprefs.cpu_compatible = workprefs.cpu_memory_cycle_exact | (ischecked (hDlg, IDC_COMPATIBLE) ? 1 : 0); workprefs.fpu_strict = ischecked (hDlg, IDC_COMPATIBLE_FPU) ? 1 : 0; workprefs.fpu_no_unimplemented = ischecked (hDlg, IDC_FPU_UNIMPLEMENTED) ? 0 : 1; - workprefs.fpu_softfloat = ischecked (hDlg, IDC_FPU_SOFTFLOAT) ? 1 : 0; workprefs.int_no_unimplemented = ischecked (hDlg, IDC_CPU_UNIMPLEMENTED) ? 0 : 1; workprefs.address_space_24 = ischecked (hDlg, IDC_COMPATIBLE24) ? 1 : 0; workprefs.m68k_speed = ischecked (hDlg, IDC_CS_HOST) ? -1 : 0; @@ -11734,6 +11733,13 @@ static void values_from_cpudlg (HWND hDlg) if (workprefs.m68k_speed_throttle > 0 && workprefs.m68k_speed < 0) workprefs.m68k_speed_throttle = 0; workprefs.x86_speed_throttle = SendMessage(GetDlgItem(hDlg, IDC_SPEED_x86), TBM_GETPOS, 0, 0) * 100; + idx = SendDlgItemMessage(hDlg, IDC_FPU_MODE, CB_GETCURSEL, 0, 0); + if (idx == 0) + workprefs.fpu_mode = 0; + if (idx == 1) + workprefs.fpu_mode = -1; + if (idx == 2) + workprefs.fpu_mode = 1; newcpu = ischecked (hDlg, IDC_CPU0) ? 68000 : ischecked (hDlg, IDC_CPU1) ? 68010 @@ -11832,7 +11838,7 @@ static void values_from_cpudlg (HWND hDlg) workprefs.comptrustword = trust_prev; workprefs.comptrustlong = trust_prev; workprefs.comptrustnaddr = trust_prev; - if (workprefs.fpu_softfloat) { + if (workprefs.fpu_mode > 0) { workprefs.compfpu = false; setchecked(hDlg, IDC_JITFPU, false); } @@ -11840,9 +11846,9 @@ static void values_from_cpudlg (HWND hDlg) if (!workprefs.cachesize) { setchecked (hDlg, IDC_JITENABLE, false); } - if (workprefs.cachesize && workprefs.compfpu && workprefs.fpu_softfloat) { - workprefs.fpu_softfloat = false; - setchecked(hDlg, IDC_FPU_SOFTFLOAT, false); + if (workprefs.cachesize && workprefs.compfpu && workprefs.fpu_mode > 0) { + workprefs.fpu_mode = 0; + SendDlgItemMessage(hDlg, IDC_FPU_MODE, CB_SETCURSEL, 0, 0); } if (oldcache == 0 && workprefs.cachesize > 0) { canbang = 1; @@ -11918,6 +11924,11 @@ static INT_PTR CALLBACK CPUDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM l SendDlgItemMessage (hDlg, IDC_CPU_FREQUENCY, CB_ADDSTRING, 0, (LPARAM)_T("8x")); SendDlgItemMessage (hDlg, IDC_CPU_FREQUENCY, CB_ADDSTRING, 0, (LPARAM)_T("Custom")); + SendDlgItemMessage(hDlg, IDC_FPU_MODE, CB_RESETCONTENT, 0, 0); + SendDlgItemMessage(hDlg, IDC_FPU_MODE, CB_ADDSTRING, 0, (LPARAM)_T("Host (64-bit)")); + SendDlgItemMessage(hDlg, IDC_FPU_MODE, CB_ADDSTRING, 0, (LPARAM)_T("Host (80-bit)")); + SendDlgItemMessage(hDlg, IDC_FPU_MODE, CB_ADDSTRING, 0, (LPARAM)_T("Softfloat (80-bit)")); + idx = 4; if (workprefs.cpu_clock_multiplier >= 1 << 8) { idx = 0; diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj b/od-win32/winuae_msvc15/winuae_msvc.vcxproj index 99989db4..8dd17f68 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj @@ -966,6 +966,7 @@ + @@ -1421,6 +1422,28 @@ 4.0_level_9_1 + + + true + true + true + true + false + false + false + false + + + true + true + true + true + false + false + false + false + + diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters index b7bff364..a0b1beb0 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters @@ -889,6 +889,9 @@ common + + win32 + @@ -1023,4 +1026,8 @@ win32\Shaders + + + + \ No newline at end of file