252 lines
5.6 KiB
NASM
252 lines
5.6 KiB
NASM
|
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
|