emu387.pp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1996-98 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. uses
  17. dxeload,dpmiexcp,strings;
  18. type
  19. emu_entry_type = function(exc : pexception_state) : longint;
  20. var
  21. _emu_entry : emu_entry_type;
  22. procedure _control87(mask1,mask2 : word);
  23. begin
  24. { Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details }
  25. { from file cntrl87.s in src/libc/pc_hw/fpu }
  26. asm
  27. { make room on stack }
  28. pushl %eax
  29. fstcw (%esp)
  30. fwait
  31. popl %eax
  32. andl $0xffff, %eax
  33. { OK; we have the old value ready }
  34. movl mask2, %ecx
  35. notl %ecx
  36. andl %eax, %ecx /* the bits we want to keep */
  37. movl mask2, %edx
  38. andl mask1, %edx /* the bits we want to change */
  39. orl %ecx, %edx /* the new value */
  40. pushl %edx
  41. fldcw (%esp)
  42. popl %edx
  43. end;
  44. end;
  45. { the problem with the stack that is not cleared }
  46. function emu_entry(exc : pexception_state) : longint;
  47. begin
  48. emu_entry:=_emu_entry(exc);
  49. end;
  50. function nofpsig( sig : longint) : longint;
  51. const
  52. last_eip : longint = 0;
  53. var
  54. res : longint;
  55. begin
  56. {if last_eip=djgpp_exception_state^.__eip then
  57. begin
  58. writeln('emu call two times at same address');
  59. dpmi_set_coprocessor_emulation(1);
  60. _raise(SIGFPE);
  61. exit(0);
  62. end; }
  63. last_eip:=djgpp_exception_state^.__eip;
  64. res:=emu_entry(djgpp_exception_state);
  65. if res<>0 then
  66. begin
  67. writeln('emu call failed. res = ',res);
  68. dpmi_set_coprocessor_emulation(1);
  69. _raise(SIGFPE);
  70. exit(0);
  71. end;
  72. dpmi_longjmp(pdpmi_jmp_buf(djgpp_exception_state)^, djgpp_exception_state^.__eax);
  73. nofpsig:=0;
  74. end;
  75. var
  76. prev_exit : pointer;
  77. procedure restore_DPMI_fpu_state;
  78. begin
  79. exitproc:=prev_exit;
  80. { Enable Coprocessor, no exceptions }
  81. dpmi_set_coprocessor_emulation(1);
  82. {$ifdef SYSTEMDEBUG}
  83. writeln('Coprocessor restored ');
  84. {$endif}
  85. end;
  86. { function _detect_80387 : boolean;
  87. not used because of the underscore problem }
  88. {$L fpu.o }
  89. function getenv(const envvar:string):string;
  90. { Copied here, preserves uses Dos (PFV) }
  91. var
  92. hp : ppchar;
  93. hs,
  94. _envvar : string;
  95. eqpos : longint;
  96. begin
  97. _envvar:=upcase(envvar);
  98. hp:=envp;
  99. getenv:='';
  100. while assigned(hp^) do
  101. begin
  102. hs:=strpas(hp^);
  103. eqpos:=pos('=',hs);
  104. if copy(hs,1,eqpos-1)=_envvar then
  105. begin
  106. getenv:=copy(hs,eqpos+1,255);
  107. exit;
  108. end;
  109. hp:=hp+4;
  110. end;
  111. end;
  112. procedure npxsetup(prog_name : string);
  113. var
  114. cp : string;
  115. i : byte;
  116. have_80387 : boolean;
  117. emu_p : pointer;
  118. const
  119. veryfirst : boolean = True;
  120. begin
  121. cp:=getenv('387');
  122. if (length(cp)>0) and (upcase(cp[1])='N') then
  123. have_80387:=False
  124. else
  125. begin
  126. dpmi_set_coprocessor_emulation(1);
  127. asm
  128. call __detect_80387
  129. movb %al,have_80387
  130. end;
  131. end;
  132. if (length(cp)>0) and (upcase(cp[1])='Q') then
  133. begin
  134. if not have_80387 then
  135. write(stderr,'No ');
  136. writeln(stderr,'80387 detected.');
  137. end;
  138. if have_80387 then
  139. begin
  140. { mask all exceptions, except invalid operation }
  141. _control87($033e, $ffff)
  142. end
  143. else
  144. begin
  145. { Flags value 3 means coprocessor emulation, exceptions to us }
  146. if (dpmi_set_coprocessor_emulation(3)<>0) then
  147. begin
  148. writeln(stderr,'Warning: Coprocessor not present and DPMI setup failed!');
  149. writeln(stderr,' If application attempts floating operations system may hang!');
  150. end
  151. else
  152. begin
  153. cp:=getenv('EMU387');
  154. if length(cp)=0 then
  155. begin
  156. for i:=length(prog_name) downto 1 do
  157. if (prog_name[i]='\') or (prog_name[i]='/') then
  158. break;
  159. if i>1 then
  160. cp:=copy(prog_name,1,i);
  161. cp:=cp+'wmemu387.dxe';
  162. end;
  163. emu_p:=dxe_load(cp);
  164. _emu_entry:=emu_entry_type(emu_p);
  165. if (emu_p=nil) then
  166. begin
  167. writeln(cp+' load failed !');
  168. halt;
  169. end;
  170. if veryfirst then
  171. begin
  172. veryfirst:=false;
  173. prev_exit:=exitproc;
  174. exitproc:=@restore_DPMI_fpu_state;
  175. end;
  176. signal(SIGNOFP,@nofpsig);
  177. end;
  178. end;
  179. end;
  180. begin
  181. npxsetup(paramstr(0));
  182. end.
  183. {
  184. $Log$
  185. Revision 1.8 1998-08-15 17:01:14 peter
  186. * smartlinking the units works now
  187. * setjmp/longjmp -> dmpi_setjmp/dpmi_longjmp to solve systemunit
  188. conflict
  189. Revision 1.7 1998/07/22 21:37:51 michael
  190. + ENViron unknow, replaced by envp
  191. Revision 1.6 1998/07/21 12:06:56 carl
  192. * restored working version
  193. }