emu387.pp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Pierre Muller
  4. FPU Emulator support
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit emu387;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. interface
  15. procedure npxsetup(prog_name : string);
  16. implementation
  17. {$asmmode ATT}
  18. {$IFDEF FPC_DOTTEDUNITS}
  19. uses
  20. DOSApi.dxeload,DOSApi.dpmiexcp,System.Strings;
  21. {$ELSE FPC_DOTTEDUNITS}
  22. uses
  23. dxeload,dpmiexcp,strings;
  24. {$ENDIF FPC_DOTTEDUNITS}
  25. type
  26. emu_entry_type = function(exc : pexception_state) : longint;
  27. var
  28. _emu_entry : emu_entry_type;
  29. procedure _control87(mask1,mask2 : longint);
  30. begin
  31. { Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details }
  32. { from file cntrl87.s in src/libc/pc_hw/fpu }
  33. asm
  34. { make room on stack }
  35. pushl %eax
  36. fstcw (%esp)
  37. fwait
  38. popl %eax
  39. andl $0xffff, %eax
  40. { OK; we have the old value ready }
  41. movl mask2, %ecx
  42. notl %ecx
  43. andl %eax, %ecx { the bits we want to keep }
  44. movl mask2, %edx
  45. andl mask1, %edx { the bits we want to change }
  46. orl %ecx, %edx { the new value }
  47. pushl %edx
  48. fldcw (%esp)
  49. popl %edx
  50. end;
  51. end;
  52. { the problem with the stack that is not cleared }
  53. function emu_entry(exc : pexception_state) : longint;
  54. begin
  55. emu_entry:=_emu_entry(exc);
  56. end;
  57. function nofpsig( sig : longint) : longint;cdecl;
  58. const
  59. last_eip : longint = 0;
  60. var
  61. res : longint;
  62. begin
  63. {if last_eip=djgpp_exception_state^.__eip then
  64. begin
  65. writeln('emu call two times at same address');
  66. dpmi_set_coprocessor_emulation(1);
  67. _raise(SIGFPE);
  68. exit(0);
  69. end; }
  70. last_eip:=djgpp_exception_state^.__eip;
  71. res:=emu_entry(djgpp_exception_state);
  72. if res<>0 then
  73. begin
  74. writeln('emu call failed. res = ',res);
  75. dpmi_set_coprocessor_emulation(1);
  76. _raise(SIGFPE);
  77. exit(0);
  78. end;
  79. dpmi_longjmp(pdpmi_jmp_buf(djgpp_exception_state)^, djgpp_exception_state^.__eax);
  80. nofpsig:=0;
  81. end;
  82. var
  83. prev_exit : pointer;
  84. procedure restore_DPMI_fpu_state;
  85. begin
  86. exitproc:=prev_exit;
  87. { Enable Coprocessor, no exceptions }
  88. dpmi_set_coprocessor_emulation(1);
  89. {$ifdef SYSTEMDEBUG}
  90. writeln(stderr,'Coprocessor restored ');
  91. {$endif}
  92. end;
  93. { function _detect_80387 : boolean;
  94. not used because of the underscore problem }
  95. {$L fpu.o }
  96. function getenv(const envvar:string):string;
  97. { Copied here, preserves uses Dos (PFV) }
  98. var
  99. hp : PPAnsiChar;
  100. hs,
  101. _envvar : string;
  102. eqpos : longint;
  103. begin
  104. _envvar:=upcase(envvar);
  105. hp:=envp;
  106. getenv:='';
  107. while assigned(hp^) do
  108. begin
  109. hs:=strpas(hp^);
  110. eqpos:=pos('=',hs);
  111. if copy(hs,1,eqpos-1)=_envvar then
  112. begin
  113. getenv:=copy(hs,eqpos+1,255);
  114. exit;
  115. end;
  116. inc(hp);
  117. end;
  118. end;
  119. function __detect_80387:byte;external name '__detect_80387';
  120. procedure npxsetup(prog_name : string);
  121. var
  122. cp : string;
  123. i : byte;
  124. have_80387 : boolean;
  125. emu_p : pointer;
  126. const
  127. veryfirst : boolean = True;
  128. begin
  129. cp:=getenv('387');
  130. if (length(cp)>0) and (upcase(cp[1])='N') then
  131. have_80387:=False
  132. else
  133. begin
  134. dpmi_set_coprocessor_emulation(1);
  135. asm
  136. call __detect_80387
  137. movb %al,have_80387
  138. end;
  139. end;
  140. if (length(cp)>0) and (upcase(cp[1])='Q') then
  141. begin
  142. if not have_80387 then
  143. write(stderr,'No ');
  144. writeln(stderr,'80387 detected.');
  145. end;
  146. if have_80387 then
  147. begin
  148. { mask all exceptions, except invalid operation }
  149. { change to same value as in v2prt0.as (PM) }
  150. _control87($0332, $ffff)
  151. end
  152. else
  153. begin
  154. { Flags value 3 means coprocessor emulation, exceptions to us }
  155. if (dpmi_set_coprocessor_emulation(3)<>0) then
  156. begin
  157. writeln(stderr,'Warning: Coprocessor not present and DPMI setup failed!');
  158. writeln(stderr,' If application attempts floating operations system may hang!');
  159. end
  160. else
  161. begin
  162. cp:=getenv('EMU387');
  163. if length(cp)=0 then
  164. begin
  165. for i:=length(prog_name) downto 1 do
  166. if prog_name[i] in AllowDirectorySeparators then
  167. break;
  168. if i>1 then
  169. cp:=copy(prog_name,1,i);
  170. cp:=cp+'wmemu387.dxe';
  171. end;
  172. emu_p:=dxe_load(cp);
  173. _emu_entry:=emu_entry_type(emu_p);
  174. if (emu_p=nil) then
  175. begin
  176. writeln(cp+' load failed !');
  177. halt;
  178. end;
  179. if veryfirst then
  180. begin
  181. veryfirst:=false;
  182. prev_exit:=exitproc;
  183. exitproc:=@restore_DPMI_fpu_state;
  184. end;
  185. signal(SIGNOFP,@nofpsig);
  186. end;
  187. end;
  188. end;
  189. begin
  190. npxsetup(paramstr(0));
  191. end.