emu387.pp 5.9 KB

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