home *** CD-ROM | disk | FTP | other *** search
- {
- WIN87EM.DLL Interface unit version 2.0
- by Juancarlo Anez [73000,1064]
- date 93.07.28
-
- Purpose:
- 1) Solve the bug in BP who dosen't mention WIN87EM in a
- $N+ DLL imports section. Just include this module in
- the DLL's LIBRARY unit's USES clause.
-
- 2) Ability to ignore coprocessor exceptions
-
- 3) Ability to set your own 80x87 exception handler.
-
- 34 All other purposes of an interface unit.
-
-
- This unit can be used form EXE's and DLL's since it does it's own initialization
- and cleanup. In teh case of EXE's that's redundant with BP for DLL's it is not.
-
- Freeware. (Though you could send in some bucks if you like<g>)
-
- No garantees expressed or implied.
-
- Enjoy & pay forward
-
- chao, j
- }
- UNIT WIN87EM;
- INTERFACE
- CONST
- SIZE_80x87_AREA = 94;
-
- em87_Ok = $00;
- em87_StackOveUnder = $80; {128}
- em87_InvalidOperand = $81; {129}
- em87_DenormalOperand = $82; {130}
- em87_DivideByZero = $83; {131}
- em87_Overflow = $84; {132}
- em87_Underflow = $85; {133}
- em87_Precision = $86; {134}
- em87_SqrtNegative = $88; {136}
-
- CONST
- iee_BitsInSingle = 8*sizeOf(Single);
- iee_BitsInDouble = 8*sizeOf(Double);
- iee_BitsInExtended = 8*sizeOf(Extended);
-
- iee_BitsInSExp = 8;
- iee_BitsInDExp = 11;
- iee_BitsInEExp = 15;
- TYPE
- TBitSetForIEESingle = set of 0..iee_BitsInSingle-1;
- tBitSetForIEEDouble = set of 0..iee_BitsInDouble-1;
- tBitSetForIEEExtended = set of 0..iee_BitsInExtended-1;
-
- CONST
- IEE_SINGLE_INF_BITS : TBitSetForIEESingle = [23..iee_BitsInSingle-2];
- IEE_DOUBLE_INF_BITS : TBitSetForIEEDouble = [53..iee_BitsInDouble-2];
- IEE_EXTENDED_INF_BITS : TBitSetForIEEExtended = [64..iee_BitsInExtended-2];
-
- IEE_SINGLE_NAN_BITS : TBitSetForIEESingle = [0..iee_BitsInExtended-2];
- IEE_DOUBLE_NAN_BITS : TBitSetForIEEDouble = [0..iee_BitsInDouble-2];
- IEE_EXTENDED_NAN_BITS : TBitSetForIEEExtended = [0..iee_BitsInExtended-2];
- VAR
- { representations of special numbers }
- INF :Single absolute IEE_SINGLE_INF_BITS;
- NAN :Single absolute IEE_SINGLE_NAN_BITS;
-
- TYPE
- tEM87Handler = function (code :Byte):Byte;
-
- pWin87EmInfoStruct = ^Win87EmInfoStruct;
- Win87EmInfoStruct = RECORD
- Version,
- SizeSaveArea,
- WinDataSeg,
- WinCodeSeg,
- Havem87,
- Unused :Word;
- END;
-
-
- pWin87EmSaveArea = ^Win87EmSaveArea;
- Win87EmSaveArea = RECORD
- savem87Area : array[0..SIZE_80x87_AREA-1] of Byte;
- saveEmArea : array[0..0] of Byte;
- END;
-
- procedure __fpMath;
-
- { this 6 routines are the __fpMath functions }
- {function 0}
- function __fpInit:Boolean;
- {function 1}
- function __fpReset:Boolean;
- {function 2}
- procedure __fpStop;
- {function 3}
- procedure __fpSetHandler(exceptionHandler :Pointer);
- {function 10}
- function __fpFPStackCount :Word;
- {function 11}
- function __fp80x87Present :Boolean;
-
- function __Win87EmInfo(pWIS :Pointer; cbWin87EmInfoStruct :Word):Integer;
- function __Win87EmSave(pWin87EmSaveArea:Pointer; cbWin87EmSaveArea:Word):Integer;
- function __Win87EmRestore(pWin87EmSaveArea:Pointer; cbWin87EmSaveArea:Word):Integer;
-
-
- VAR
- Win87EMInfo : Win87EmInfoStruct;
-
- CONST
- { this function is called whenever a 80x87 exception occurs,
- default processing is almost like BP's,
- place your own handling routine here }
- em87Handler :tEM87Handler = nil;
-
- { the folowing variable determines how the default handler handles exceptions,
- TRUE = runtime error
- FALSE = clear exceptions and carry on }
- EM87AbortOnExceptions :Boolean = FALSE;
-
- { retreives last exception, and clears so next call is always 0 }
- function em87Exception :Byte;
-
- { set the exception handling to a custom routine,
- the handler should return a non zero value that will be passed to RunError(),
- or zero to clear exceptions and continue.
- The default handler traduces exceptions to runtime errors like BP }
- procedure setEM87ExceptionHandler(const handler :tEM87Handler);
- function em87DefaultHandler(code :Byte):Byte; far;
-
- procedure initEM87;
-
- function getFPExceptionFilter:Byte;
- function setFPExceptionFilter(filter :Byte):Byte;
- function isNAN(f :Extended):Boolean;
-
- IMPLEMENTATION
-
- CONST
- LastException :Byte = 0;
-
- procedure __fpMath; external 'WIN87EM' index 1;
- function __Win87EmInfo(pWIS :Pointer; cbWin87EmInfoStruct :Word):Integer;
- external 'WIN87EM' index 3;
- function __Win87EmSave(pWin87EmSaveArea:Pointer; cbWin87EmSaveArea:Word):Integer;
- external 'WIN87EM' index 5;
- function __Win87EmRestore(pWin87EmSaveArea:Pointer; cbWin87EmSaveArea:Word):Integer;
- external 'WIN87EM' index 4;
-
-
- function __fpInit :Boolean; assembler;
- asm
- xor bx, bx
- call __fpMath
- jc @@1
- xor ax, ax
- jc @@2
- @@1:
- mov ax, 1
- @@2:
- end;
-
- function __fpReset :Boolean; assembler;
- asm
- mov bx, 1
- call __fpMath
- jc @@1
- xor ax, ax
- jc @@2
- @@1:
- mov ax, 1
- @@2:
- end;
-
- procedure __fpStop; assembler;
- asm
- mov bx, 2
- call __fpMath
- end;
-
- procedure __fpSetHandler(exceptionHandler :Pointer); assembler;
- asm
- MOV BX, 3
- LES DI, ExceptionHandler
- MOV AX,DI
- MOV DX,ES
- CALL __FPMath
- end;
-
- function __fpFPStackCount :Word; assembler;
- asm
- mov bx, 10
- call __fpMath
- end;
-
- function __fp80x87Present :Boolean; assembler;
- asm
- mov bx, 11
- call __fpMath
- end;
-
-
-
-
- { does the same exception-code -> runtime-error-code conversion than BP }
- function em87DefaultHandler(code :Byte):Byte;
- begin
- case code of
- em87_DivideByZero : em87DefaultHandler := 200;
- em87_Overflow : em87DefaultHandler := 205;
- em87_Underflow : em87DefaultHandler := 206;
- else em87DefaultHandler := 207
- end;
- if not EM87AbortOnExceptions then
- em87DefaultHandler := 0
- end;
-
- procedure setEM87ExceptionHandler(const handler :tEM87Handler);
- begin
- em87Handler := handler;
- end;
-
- function em87Exception :Byte;
- begin
- em87Exception := LastException;
- LastException := em87_Ok;
- __fpReset;
- asm {clear exeptions}
- FNCLEX
- FWAIT
- end;
- end;
-
- function getFPExceptionFilter:Byte;
- var
- temp :Word;
- begin
- asm
- fstcw Temp
- fwait
- end;
- getFPExceptionFilter := temp and $FF
- end;
-
- function setFPExceptionFilter(filter :Byte):Byte;
- var
- temp :Word;
- begin
- temp := getFPExceptionFilter;
- setFPExceptionFilter := Temp;
- temp := (temp and $FF00) or filter;
- asm
- fldcw Temp
- fwait
- end;
- end;
-
- function isNAN(f :Extended):Boolean;
- var
- b :tBitSetForIEEExtended absolute f;
- begin
- isNAN := (IEE_EXTENDED_INF_BITS <= b) and not (b <= IEE_EXTENDED_INF_BITS);
- end;
-
- { our own exception handler,
- calls em87Handler and stops the program on a non 0 result
- otherwise it resets clears the coprocesor exception }
- procedure Exception; FAR;
- var
- code :Byte;
- begin
- asm
- push ds { restore data segment }
- push SEG [lastException]
- pop ds
- mov [lastException], al
- end;
- code := em87Handler(lastException);
- if code <> 0 then
- runError(code)
- else begin
- __fpReset;
- asm
- pop ds {undo data segment change }
- FNCLEX
- FWAIT
- end; {clear exeptions}
- end
- end;
-
- const
- exitSave :Pointer = nil;
-
- procedure exitEM87; far;
- begin
- __fpStop;
- exitProc := exitSave
- end;
-
-
- procedure initEM87;
- begin
- __fpInit;
- __fpSetHandler(@Exception);
- setEM87ExceptionHandler(em87DefaultHandler);
- __Win87EmInfo(@win87EMInfo, sizeOf(Win87EmInfo));
- exitSave := exitProc;
- exitProc := @exitEM87;
- end;
-
-
- BEGIN
- initEM87;
- END.
-