home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
pascal
/
library
/
windows
/
win87emu
/
win87em.pas
< prev
Wrap
Pascal/Delphi Source File
|
1993-03-29
|
7KB
|
253 lines
{-----------------------------------------------------}
{ WIN87EM.PAS - A Protected mode WIN87EM "simulator" }
{ Copyright (c) 1993, Pat Ritchey CIS:[70007,4660] }
{-----------------------------------------------------}
{$N+} { This is turned on so that the FP asm statements will compile }
{$IFNDEF DPMI}
!! Error: This is a Protected mode DLL.
{$ENDIF}
Library Win87EM;
{$C FIXED,PRELOAD,PERMANENT} { Match SYSTEM unit attrib. }
{$D WIN87EM DOS Protected mode code}
{$S 65535} { All code in one segment }
uses WinAPI;
const
emDataSize = 230+16; { from EI86.ASM }
npuDataSize = 108; { Some references say 94 others say 108 }
SaveDataSize = emDataSize+npuDataSize;
LibName = 'WIN87EM';
EmulatorError =
'Emulator code not present, compile calling program with $N+'+
#13#10' and include a floating point statement';
FloatInstErr =
'A DLL has performed a floating point operation in its outer block.'+
#13#10' This DLL is not useable in DOS protected mode.';
NotWindowsErr =
'This DLL is not a Windows DLL. It is a DOS Protected mode DLL';
function EmulatorWillInstall : boolean;
{ A hack to determine if the calling app will install the
emulator/FP support code. The logic is:
1. Find the limit of the stack segment.
2. The return address to the APP will be at Stack's seg limit - 3.
3. This return address will point to the FAR call that
calls SYSTEM.InitTurbo.
4. IF the instruction following the APP's call to SYSTEM.InitTurbo
is another FAR call to code in the same segment, it is call to
SYSTEM.InitEM8x and the FP code will be installed.
5. IF the instruction is NOT a FAR call or is a FAR call to a different
segment then the FP code will NOT be installed.
Caveats:
--------
This routine assumes that WIN87EM.DLL is being loaded due to an implicit
reference to the DLL. If this DLL is loaded via a LoadLibrary() call in
a calling app the stack will not be in the "as expected" state and the
result of this function is undefined
}
type
TFarCallInst = record
Opcode : byte;
Offset : word;
Segment : word;
end;
PAppEntry = ^TAppEntry;
TAppEntry = record
InitTurbo : TFarCallInst;
InitEM8x : TFarCallInst;
end;
var
SegLimit : word;
AppEntry : PAppEntry;
const
CallFar = $9A;
begin
EmulatorWillInstall := false;
asm
mov ax,ss
lsl ax,ax
mov SegLimit,ax
end;
AppEntry := PAppEntry(Ptr(SSeg,SegLimit-3)^);
With AppEntry^ do begin
If (InitTurbo.Opcode <> CallFar) or (InitEM8x.Opcode <> CallFar) then exit;
EmulatorWillInstall := InitTurbo.Segment = InitEM8x.Segment;
end;
end;
procedure InvalidOp; far;
begin
asm
sti
mov ax,Seg @DATA
mov ds,ax
end;
MessageBox(0,FloatInstErr,LibName,MB_OK);
RunError(207);
end;
procedure InstallIntVect; assembler;
{ Yet another hack. This procedure points all of the FP emulator interrupts
to the InvalidOp procedure. This allows WIN87EM to trap floating point
operations that occur prior to the installation of the Borland floating
point code (ie: A DLL that does a FP op in it's LibMain code). InvalidOp
displays a more user-friendly message than the "Unexpected interrupt" dump
produced by RTM. The only remaing problem is how to handle DLLs produced
by BP7 (either Pmode or Windows) that have FP code in its outer block.
BP7 does not generate a call to __FPMATH in a Windows target DLL.
}
asm
push ds
push cs
pop ds
mov dx,OFFSET InvalidOp
mov cx,11
mov ax,$2534
@1:
int $21
inc ax
loop @1
pop ds
end;
function __FPMATH : word; export; external;
{$L WIN87EM }
{ __FPMATH is passed its parameters in the CPU registers. Since one
of the parameters is passed in AX, BASM can't be used to implement
this function (the stack setup code would trash AX). The external
code simply pushes the registers on the stack, establishes DS
addressability and calls FPMATH (see below). }
function FPMATH(Fn : word; DXReg : word; AXReg: word) : word; far;
{ __FPMATH has 13 functions. Some (such as 0, 2 and 3) are already handled
by the Borland emulator. Some MS DLLs/EXEs call function 11 to determine
if an NPU is present, so this function is supported. The others MIGHT need
to be implemented. Function 4 was easy to reverse engineer, so it's
included here. }
begin
FPMATH := 0; { assume success }
case fn of
0: ; { Initialize }
1: ;
2: ; { Cleanup }
3: ; { set Exception Vector }
4: begin
asm
and AXReg,$FF3C
fldcw AXReg
end;
FPMATH := AXReg;
end;
5: ;
6: ;
7: ;
8: ;
9: ;
10: ;
11: FPMath := Test8087;
12: ;
else
FPMATH := $FFFF; { invalid function }
end;
end;
function __WIN87EMINFO(var InfoBuff; BuffLen : word) : wordbool; export;
var
IB : array[0..5] of word absolute InfoBuff;
begin
__WIN87EMINFO := true;
if BuffLen = 12 then
begin
IB[0] := $0600; { I'm not sure what this value signifies ?? }
IB[1] := SaveDataSize;
IB[2] := SSeg;
IB[3] := CSeg;
IB[4] := word(Test8087);
IB[5] := 0;
__Win87EMInfo := false;
end;
end;
function __WIN87EMRESTORE(var SaveBuff; BuffLen : word): wordbool; export;
begin
__Win87EMRestore := true; { assume failure }
if BuffLen <> SaveDataSize then exit;
asm
mov dl,Test8087
push ds
lds si,SaveBuff
or dl,dl
jz @1
db $9B { wait }
db $DD,$24 { frstor [si] }
@1:
add si,npuDataSize
push ss
pop es
mov di,0
mov cx,emDataSize
rep movsb
pop ds
end;
__Win87EMRestore := false;
end;
function __WIN87EMSAVE(var SaveBuff; BuffLen : word) : wordbool; export;
begin
__Win87EMSave := true; { assume failure }
if BuffLen <> SaveDataSize then exit;
asm
les di,SaveBuff;
cmp Test8087,0
jz @1
db $9B { wait }
db $26,$DD,$35 { fsave es:[di] }
@1:
add di,npuDataSize
push ds
mov ax,ss
mov ds,ax
xor ax,ax
mov cx,emDataSize
rep movsb
pop ds
end;
__Win87EMSave := false;
end;
exports
__FPMATH index 1
,__WIN87EMINFO index 3
,__WIN87EMRESTORE index 4
,__WIN87EMSAVE index 5
;
begin
if GetWinFlags and wf_DPMI = 0 then
begin
MessageBox(0,NotWindowsErr,LibName,MB_OK);
halt;
end;
if not EmulatorWillInstall then
begin
MessageBox(0,EmulatorError,LibName,MB_OK);
RunError(207);
end;
InstallIntVect;
{ A DLL doesn't link in the FP library, so Test8087 must be initialized
"manually" }
if GetWinFlags and wf_80x87 <> 0 then
Test8087 := 1;
end.