windows-nt/Source/XPSP1/NT/base/mvdm/wow16/win87em/emfadd.asm

252 lines
5.6 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
page ,132
subttl emfadd.asm - Addition and Subtraction
;***
;emfadd.asm - Addition and Subtraction
;
; Copyright (c) 1986-89, Microsoft Corporation
;
;Purpose:
; Addition and Subtraction
;
; This Module contains Proprietary Information of Microsoft
; Corporation and should be treated as Confidential.
;
;Revision History:
; See emulator.hst
;
;*******************************************************************************
;-----------------------------------------;
; ;
; Addition and Subtraction ;
; ;
;-----------------------------------------;
ProfBegin FADD
RABRQQ: ; Routine Add Both must see if we have two singles.
if fastSP
MOV BX,DX
XOR BX,Single + 256*Single
TEST BX,Single + 256*Single
JNZ RADRQQ
MOV BX,OFFSET TASRQQ
JMP [BX]
endif ;fastSP
pub RADRQQ ; RoutineAddDouble SI & DI point to valid non-0 reals
; AX CX are the exponents
; DL DH are the signs
if fastSP
CALL CoerceToDouble ; insure that both args are double
endif ;fastSP
SUB AX,CX ; See which number is larger
JL short DIBIG
XCHG esi,edi ; Swap pointers to operands
XCHG DH,DL ; Swap signs
ADD CX,AX ; CX = larger exponent (Tentative result)
NEG AX
pub DIBIG ; DI = larger, CX = expon, DH = sign
NEG AX
CMP AX,64+3 ; Is smaller argument significant?
JLE short SIGNIF
PUSH ebp ; Not signif so result is at DI except for
PUSH edx ; rounding. ROUND assumes old BP and Sign on
MOV SI,Expon[edi] ; stack. Exponent in SI
MOV BP,1 ; Other argument collapses into a sticky bit
XOR DL,DH ; if signs of operands differ bit is negative
JNS short GetOpMantissa
NEG BP
pub GetOpMantissa
MOV DX,MB0[edi]
MOV CX,MB2[edi]
MOV BX,MB4[edi]
MOV DI,MB6[edi]
OR BP,BP
JS short NegativeStickyBit
JMP ROUND
pub NegativeStickyBit
SUB DX,1 ; Must propagate negative sticky bit
SBB CX,0
SBB BX,0
SBB DI,0
JMP NODRQQ
pub SIGNIF
; Now things look like this:
; SI has pointer to smaller operand
; DI has pointer to larger operand
; AX has exponent difference ( 0 <= CL <= 53 )
; CX has exponent
; DH has sign
PUSH ebp ; Need all the registers
PUSH edx ; Save sign
PUSH ecx ; Save exponent
XOR DL,DH ; Must eventually know whether signs are same
PUSHF
MOV BP,AX ; Need all 8-bit registers now
; Load smaller operand
LODS word ptr ds:[esi]
MOV DX,AX
LODS word ptr ds:[esi]
MOV CX,AX
LODS word ptr ds:[esi]
MOV BX,AX
LODS word ptr ds:[esi]
XOR si,si ; BP Will be round,guard, & sticky bits (=0)
XCHG bp,si ; Done with Pointer to small. so SI = shift cnt
; hi lo 0
; Smaller operand now in AX:BX:CX:DX:BP with implied bit set, SI has shift count
OR si,si
JZ ALIGNED ; Alignment operations necessary?
pub CHKALN
CMP si,14 ; Do shifts of 16 bits by word rotate
JL short BYTSHFT ; If not enough for word, go try byte
OR BP,BP ; See if we're shifting something off the end
JZ short NOSTIK
OR DX,1 ; Ensure sticky bit will be set
pub NOSTIK
MOV BP,DX
MOV DX,CX
MOV CX,BX
MOV BX,AX
XOR AX,AX
SUB si,16 ; Counts for 16 bit shifts
JA short CHKALN ; If not enough, try again
JZ short ALIGNED ; Hit it exactly?
JB short SHFLEF ; Back up if too far
pub BYTSHFT
CMP si,6 ; Can we do a byte shift?
JL short BITSHFT
XCHG BP,AX
OR AL,AL
JZ short NSTIK
OR AH,1
pub NSTIK
MOV AL,AH
MOV AH,DL
XCHG BP,AX
MOV DL,DH
MOV DH,CL
MOV CL,CH
MOV CH,BL
MOV BL,BH
MOV BH,AL
MOV AL,AH
XOR AH,AH
SUB SI,8
JA short BITSHFT
JZ short ALIGNED
; To get here, we must have used a byte shift when we needed to shift less than
; 8 bits. Now we must correct by 1 or 2 left shifts.
pub SHFLEF
SHL BP,1
RCL DX,1
RCL CX,1
RCL BX,1
RCL AX,1
INC SI
JNZ SHFLEF ; Until DI is back to zero (from -1 or -2)
JMP SHORT ALIGNED
pub BITSHFT
ifdef i386
and esi,0FFFFh ; clear upper half of esi
endif
XCHG ecx,esi ; Swap count into CX, lo3:lo4 into DI
TEST BP,3FH ; See if we're shifting stuff off the end
JZ short SHFRIG
OR BP,20H ; Set sticky bit if so
pub SHFRIG
SHR AX,1
RCR BX,1
RCR SI,1
RCR DX,1
RCR BP,1
LOOP SHFRIG ; Do 1 to 5 64-bit right shifts
MOV CX,SI ; Get back CX = lo3:lo4
pub ALIGNED
MOV esi,edi ; Address of larger operand
MOV DI,AX ; Now DI = msb:mid
TEST BP,3FFFH ; Collapse LSBs into sticky bit
JZ short GETSIGN
OR BP,1 ; Set sticky bit
pub GETSIGN
POPF ; Recover XOR of signs
; 80286 errata for POPF shouldn't
; apply because interrupts should be
; turned on in this context
POP eax ; Recover Exponent
; Sign flag is XOR of signs
JS short SUBMAN ; Subtract mantissas if signs are different
ADD DX,[esi]
ADC CX,[esi+2]
ADC BX,[esi+4]
ADC DI,[esi+6]
JNC short JROUND ; Done if no overflow
; Have a carry, so result must be shifted right and exponent incremented
RCR DI,1
RCR BX,1
RCR CX,1
RCR DX,1
RCR BP,1
JNC short STIKYOK
OR BP,1 ; Shifted out the sticky bit so reset it.
pub STIKYOK
INC AX ; Bump exponent.
; JMP JROUND ; and go round. (need not normalize)
pub JROUND
MOV SI,AX ; We must have SI equal to exponent
JMP ROUND ; on our way to Round
pub SUBMAN
; Subtract mantissas since signs are different. We'll be subtracting larger
; from smaller, so sign will be inverted first after the subtraction.
SUB DX,[esi]
SBB CX,[esi+2]
SBB BX,[esi+4]
SBB DI,[esi+6]
JNC short JNORM ; Won't carry if we mixed up larger and smaller
; As expected, we got a carry which means we original sign was OK
XOR SI,SI ; We'll need a zero, so let's use SI
NOT DI
NOT BX
NOT CX
NOT DX
NEG BP ; Carry clear if zero
CMC ; Set CY
ADC DX,SI
ADC CX,SI ; Propagate carry
ADC BX,SI
ADC DI,SI
MOV SI,AX ; Get exponent to SI
JMP NODRQQ ; Go normalize
pub JNORM
MOV SI,AX ; Exponent in SI
POP eax
XOR AH,SIGN ; invert sign bit (on top of stack)
PUSH eax
JMP NODRQQ ; and go normalize
ProfEnd FADD