emu387.pp 4.9 KB

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