subttl emlsenv.asm - Emulator Save/Restore page ;*** ;emlsenv.asm - Emulator Save/Restore ; ; ; Copyright (c) Microsoft Corporation 1991 ; ; All Rights Reserved ; ;Purpose: ; FLDCW, FSTCW, FSTSW, FSTENV, FLDENV, FSAVE, FRSTOR instructions ; ;Revision History: ; ; [] 09/05/91 TP Initial 32-bit version. ; ; ;******************************************************************************* ;When setting the control word, the [RoundMode] vector must be set ;according to the rounding and precision modes. tRoundMode label dword irp RC, irp PC,<24,24,53,64> dd Round&&PC&&RC endm endm EM_ENTRY eFLDCW eFLDCW: ;Uses only eax and ebx mov ax, dseg:[esi] ; Fetch control word from user memory SetControlWord: and ax,0F3FH ; Limit to valid values mov EMSEG:[ControlWord], ax ; Store in the emulated control word not al ;Flip mask bits for fast compare and al,3FH ;Limit to valid mask bits mov EMSEG:[ErrMask],al and eax,(RoundControl + PrecisionControl) shl 8 .erre RoundControl eq 1100B .erre PrecisionControl eq 0011B shr eax,6 ;Put PC and RC in bits 2-5 mov ebx,tRoundMode[eax] ;Get correct RoundMode vector mov EMSEG:[RoundMode],ebx mov EMSEG:[SavedRoundMode],ebx and eax,RoundControl shl (8-6) ;Mask off precision control mov ebx,tRoundMode[eax+PC64 shl (8-6)];Get correct RoundMode vector mov EMSEG:[TransRound],ebx ;Round mode w/o precision ret EM_ENTRY eFSTCW eFSTCW: ;Uses only eax mov ax, EMSEG:[ControlWord] ; Fetch user control word mov dseg:[esi], ax ; Store into user memory ret EM_ENTRY eFSTSW eFSTSW: ;Uses only eax and ebx call GetStatusWord ; Fetch emulated Status word mov dseg:[esi], ax ; Store into user memory ret eFSTSWax: ;Uses only eax and ebx call GetStatusWord ; Fetch emulated Status word mov [esp+4].regAX,ax ret EM_ENTRY eFDECSTP eFDECSTP: ;edi = [CURstk] cmp edi,BEGstk jbe DecWrap sub EMSEG:[CURstk],Reg87Len ret DecWrap: mov EMSEG:[CURstk],INITstk ret EM_ENTRY eFINCSTP eFINCSTP: ;edi = [CURstk] cmp edi,INITstk jae IncWrap add EMSEG:[CURstk],Reg87Len ret IncWrap: mov EMSEG:[CURstk],BEGstk ret eFCLEX: mov EMSEG:[SWerr],0 and [esp+4].OldLongStatus,0FFFF00FFH ; clear saved SWerr ret ;*** eFSTENV - emulate FSTENV [address] ; ; ARGUMENTS ; dseg:esi = where to store environment ; ; ; DESCRIPTION ; This routine emulates an 80387 FSTENV (store environment) ; EM_ENTRY eFSTENV eFSTENV: mov ax,[esp+4].OldStatus mov EMSEG:[StatusWord],ax SaveEnv: xor ax,ax mov dseg:[esi.reserved1],ax mov dseg:[esi.reserved2],ax mov dseg:[esi.reserved3],ax mov dseg:[esi.reserved4],ax mov dseg:[esi.reserved5],ax mov ax,EMSEG:[ControlWord] mov dseg:[esi.E32_ControlWord],ax call GetEMSEGStatusWord mov dseg:[esi.E32_StatusWord],ax call GetTagWord mov dseg:[esi.E32_TagWord],ax mov ax,cs mov dseg:[esi.E32_CodeSeg],ax mov ax,ss mov dseg:[esi.E32_DataSeg],ax mov eax,EMSEG:[PrevCodeOff] mov dseg:[esi.E32_CodeOff],eax mov eax,EMSEG:[PrevDataOff] mov dseg:[esi.E32_DataOff],eax mov EMSEG:[CWmask],03FH ;Set all mask bits mov EMSEG:[ErrMask],0 ret ;*** eFSAVE - emulate FSAVE [address] ; ; ARGUMENTS ; dseg:esi = where to store environment ; ; ; DESCRIPTION ; This routine emulates an 80387 FSAVE (store environment) ; Once the data is stored an finit is executed. ; ; REGISTERS ; destroys ALL. EM_ENTRY eFSAVE eFSAVE: mov ax,[esp+4].OldStatus mov EMSEG:[StatusWord],ax mov eax,[esp+4].OldCodeOff mov EMSEG:[PrevCodeOff],eax push offset eFINIT ; After fsave we must do a finit SaveState: ; Enter here for debugger save state call SaveEnv add esi,size Env80x87_32 ;Skip over environment mov ebp,NumLev ;Save entire stack mov edi,EMSEG:[CURstk] FsaveStoreLoop: mov eax,EMSEG:[edi].ExpSgn call StoreTempReal ;in emstore.asm add esi,10 mov edi,EMSEG:[CURstk] NextStackElem edi,FSave mov EMSEG:[CURstk],edi dec ebp jnz FsaveStoreLoop ret WrapFSave: ; tied to NextStackElem above mov edi, BEGstk mov EMSEG:[CURstk],edi dec ebp jnz FsaveStoreLoop ret ;*** eFRSTOR - emulate FRSTOR [address] ; ; ARGUMENTS ; dseg:esi = where to get the environment ; ; DESCRIPTION ; This routine emulates an 80387 FRSTOR (restore state) NextStackWrap edi,Frstor EM_ENTRY eFRSTOR eFRSTOR: ;First we set up the status word so that [CURstk] is initialized. ;The floating-point registers are stored in logical ST(0) - ST(7) order, ;not physical register order. We don't do a full load of the environment ;because we're not ready to use the tag word yet. and [esp+4].[OldLongStatus], NOT(LongSavedFlags) ;clear saved codes, errs mov ax, dseg:[esi.E32_StatusWord] call SetEmStatusWord ;Initialize [CURstk] add esi,size Env80x87_32 ;Skip over environment ;Load of temp real has one difference from real math chip: it is an invalid ;operation to load an unsupported format. By ensuring the exception is ;masked, we will convert unsupported format to Indefinite. Note that the ;mask and [CURerr] will be completely restored by the FLDENV at the end. mov EMSEG:[CWmask],3FH ;Mask off invalid operation exception mov edi,EMSEG:[CURstk] mov ebp,NumLev FrstorLoadLoop: push esi call LoadTempReal ;In emload.asm pop esi add esi,10 ;Point to next temp real NextStackElem edi,Frstor dec ebp jnz FrstorLoadLoop sub esi,NumLev*10+size Env80x87_32 ;Point to start of env. jmp eFLDENV ;Fall into eFLDENV ;*** eFLDENV - emulate FLDENV [address] ; ; ARGUMENTS ; dseg:si = where to store environment ; ; This routine emulates an 80387 FLDENV (load environment) EM_ENTRY eFLDENV eFLDENV: and [esp+4].[OldLongStatus], NOT(LongSavedFlags) ;clear saved codes, errs mov ax, dseg:[esi.E32_StatusWord] call SetEmStatusWord ; set up status word mov ax, dseg:[esi.E32_ControlWord] call SetControlWord mov ax, dseg:[esi.E32_TagWord] call UseTagWord mov eax, dseg:[esi.E32_CodeOff] mov EMSEG:[PrevCodeOff], eax mov eax, dseg:[esi.E32_DataOff] mov EMSEG:[PrevDataOff], eax ret ;*** GetTagWord - figures out what the tag word is from the numeric stack ; and returns the value of the tag word in ax. ; GetTagWord: push esi xor eax, eax mov ecx, NumLev ; get tags for regs. 0, 7 - 1 mov esi,INITstk GetTagLoop: mov bh, EMSEG:[esi.bTag] ; The top 2 bits of Tag are the X87 tag bits. shld ax, bx, 2 sub esi, Reg87Len loop GetTagLoop rol ax, 2 ; This moves Tag(0) into the low 2 bits pop esi ret ;*** UseTagWord - Set up tags using tag word from environment ; ; ARGUMENTS ; ax - should contain the tag word ; ; Destroys ax,bx,cx,dx,di UseTagWord: ror ax, 2 ; mov Tag(0) into top bits of ax mov edi,INITstk mov ecx, NumLev UseTagLoop: mov dl,bTAG_EMPTY cmp ah, 0c0h ;Is register to be tagged Empty? jae SetTag ;Yes, go mark it mov dl,EMSEG:[edi].bTag ;Get current tag cmp dl,bTAG_EMPTY ;Is register currently Empty? je SetTagNotEmpty ;If so, go figure out tag for it SetTag: mov EMSEG:[edi].bTag,dl UseTagLoopCheck: sub edi, Reg87Len shl eax, 2 loop UseTagLoop ret SetTagEmpty: mov EMSEG:[edi.bTag], bTAG_EMPTY jmp UseTagLoopCheck SetTagNotEmpty: ;Register is currently tagged empty, but new tag word says it is not empty. ;Figure out a new tag for it. The rules are: ; ;1. Everything is either normalized or zero--unnormalized formats cannot ;get in. So if the high half mantissa is zero, the number is zero. ; ;2. Although the exponent bias is different, NANs and Infinities are in ;standard IEEE format - exponent is TexpMax, mantissa indicates NAN vs. ;infinity (mantissa for infinity is 800..000H). ; ;3. Denormals have an exponent less than TexpMin. ; ;4. If the low half of the mantissa is zero, it is tagged bTAG_SNGL ; ;5. Everything else is bTAG_VALID mov ebx,EMSEG:[edi].lManHi mov dl,bTAG_ZERO ;Try zero first or ebx,ebx ;Is mantissa zero? jz SetTag mov edx,EMSEG:[edi].ExpSgn mov dl,bTAG_DEN cmp edx,TexpMin shl 16 ;Is it denormal? jl SetTag cmp EMSEG:[edi].lManLo,0 ;Is low half zero? .erre bTAG_VALID eq 1 .erre bTAG_SNGL eq 0 setnz dl ;if low half==0 then dl=0 else dl=1 cmp edx,TexpMax shl 16 ;Is it NAN or Infinity? jl SetTag ;If not, it's valid .erre (bTAG_VALID - bTAG_SNGL) shl TAG_SHIFT eq (bTAG_NAN - bTAG_INF) shl dl,TAG_SHIFT add dl,bTAG_INF - bTAG_SNGL ;If the low bits were zero we have just changed bTAG_SNGL to bTAG_INF ;If the low bits weren't zero, we changed bTAG_VALID to bTAG_NAN ;See if infinity is really possible: is high half 80..00H? cmp ebx,1 shl 31 ;Is it infinity? jz SetTag ;Store tag for infinity or NAN mov dl,bTAG_NAN jmp SetTag ;*** GetStatusWord - ; ; User status word returned in ax. ; Destroys ebx only. GetStatusWord: mov eax, EMSEG:[CURstk] sub eax, BEGstk mov bl,Reg87Len div bl inc eax ; adjust for emulator's stack layout and eax, 7 ; eax is now the stack number shl ax, 11 or ax,[esp+8].OldStatus ; or in the rest of the status word. ret ;*** GetEMSEGStatusWord - ; ; User status word returned in ax. ; Destroys ebx only. ; Uses status word in per-thread data area, otherwise ; identical to GetStatusWord EM_ENTRY eGetStatusWord GetEMSEGStatusWord: mov eax, EMSEG:[CURstk] sub eax, BEGstk mov bl,Reg87Len div bl inc eax ; adjust for emulator's stack layout and eax, 7 ; eax is now the stack number shl ax, 11 or ax, EMSEG:[StatusWord] ; or in the rest of the status word. ret ;*** SetEmStatusWord - ; ; Given user status word in ax, set into emulator. ; Destroys ebx only. SetEmStatusWord: and ax,7F7FH mov bx,ax and bx,3FH ; set up CURerr in case user mov EMSEG:[CURerr],bl ; wants to force an exception mov ebx, eax and ebx, not (7 shl 11) ; remove stack field. mov EMSEG:[StatusWord], bx sub ah, 8 ; adjust for emulator's stack layout and ah, 7 shl 3 mov al, ah shr ah, 1 add al, ah ; stack field * 3 * 4 .erre Reg87Len eq 12 and eax, 255 ; eax is now 12*stack number add eax, BEGstk mov EMSEG:[CURstk], eax ret public _SaveEm87Context _SaveEm87Context PROC push ebp mov ebp, esp push ebx push edi push esi mov esi, [ebp+8] call SaveState test EMSEG:[CURErr], Summary jne RetSaveEmIdle mov eax, Em87Busy jmp RetSaveEm RetSaveEmIdle: mov eax, Em87Idle RetSaveEm: pop esi pop edi pop ebx pop ebp ret _SaveEm87Context ENDP public _RestoreEm87Context _RestoreEm87Context PROC push ebp mov ebp, esp push ebx push edi push esi mov esi, [ebp+8] call eFRSTOR pop esi pop edi pop ebx pop ebp ret _RestoreEm87Context ENDP