/* Copyright (C) 1994, 1995 Charles Sandmann (sandmann@clio.rice.edu) * FPU setup and emulation hooks for DJGPP V2.0 * This file maybe freely distributed, no warranty. */ /* Note: If this file is built with IMBED_EMU387 defined, the application should be linked with -lemu to imbed the code in the image. This makes it easier to distribute an application with a single file. The alternate behavior is to dynamically load the image. */ #include #include #include #include #include #include #include #include #include #include #include #include /* for _8087 */ #ifndef IMBED_EMU387 #include static int (*_emu_entry)(jmp_buf exc); #else int _emu_entry(jmp_buf exc); #endif int _8087; /* crt0.o references __emu387_load_hook just to pull in this object in libemu.a. Using -lemu -lc brings in the static objects instead of a dynamic link. */ int __emu387_load_hook; struct e387_state { int _8087; int __emu387_load_hook; }; static struct e387_state *sts; static void e387_pre(void) { #define _SV(x) sts->x = x _SV(_8087); _SV(__emu387_load_hook); } static void e387_post(void) { #define _RS(x) x = sts->x _RS(_8087); _RS(__emu387_load_hook); } DJ64_DEFINE_SWAPPABLE_CONTEXT2(e387_state, sts, ((struct e387_state){}), e387_pre(), e387_post()); /* The environment variable 387 can be used to disable a 387 which is present (for testing) by setting it to "n". The presence can be reported to stderr by setting 387 to "q" (query). If 387 is set to "y", we assume the coprocessor is present without checking. If a 387 is not present under DPMI, we call a V1.0 DPMI extension to ask that Exception 7 be sent to our process. If we don't have a 387, we attempt to load the EMU387.DXE and call it from the signal. */ #if 0 static void nofpsig(int sig) { if(_emu_entry(__djgpp_exception_state)) { raise(SIGFPE); return; } longjmp(__djgpp_exception_state, __djgpp_exception_state->__eax); } #endif #ifdef RESTORE_FPU static void restore_DPMI_fpu_state(void) { __dpmi_set_coprocessor_emulation(1); /* Enable Coprocessor, no exceptions */ } #endif extern int _detect_80387(void); void _npxsetup(char *argv0) { char *cp; char have_80387; #ifdef RESTORE_FPU static int veryfirst = 1; #endif cp = getenv("387"); if (cp && (tolower((unsigned char)cp[0]) == 'y')) { _8087 = 3; _control87(0x033f, 0xffff); /* mask all numeric exceptions */ return; } if (cp && (tolower((unsigned char)cp[0]) == 'n')) have_80387 = 0; else { /* This next function may fail, but that's OK. This may fix the nested FPU client fault - DJ */ __dpmi_set_coprocessor_emulation(1); have_80387 = _detect_80387(); } _8087 = (have_80387 ? 3 : 0); if (cp && (tolower((unsigned char)cp[0]) == 'q')) { if (!have_80387) _write(2, "No ", 3); _write(2, "80387 detected.\r\n", 17); } if(have_80387) { /* mask all exceptions */ _control87(0x033f, 0xffff); } else { /* Flags value 3 means coprocessor emulation, exceptions to us */ if (__dpmi_set_coprocessor_emulation(3)) { _write(2, "Warning: Coprocessor not present and DPMI setup failed!\r\n", 57); _write(2, " If application attempts floating operations system may hang!\r\n", 71); } else { #ifndef IMBED_EMU387 char emuname[512]; cp = getenv("EMU387"); if (!cp) { char *last, c; cp = last = emuname; while((c = *cp++ = *argv0++)) if(c == '/' || c == '\\') last = cp; *last = 0; strcat(emuname,"emu387.dxe"); cp = emuname; } _emu_entry = (int (*)(jmp_buf))_dxe_load(cp); if (_emu_entry == 0) return; #endif #ifdef RESTORE_FPU if (veryfirst) { veryfirst = 0; atexit(restore_DPMI_fpu_state); } #endif // signal(SIGNOFP, nofpsig); /* mask all exceptions for the emulation case, too */ _control87(0x033f, 0xffff); } } }