home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
pascal
/
library
/
windows
/
vbcore
/
win87em.pas
< prev
Wrap
Pascal/Delphi Source File
|
1994-05-12
|
8KB
|
319 lines
{
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.