123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- _fadd:
- PUSH BP
- MOV BP,SP
- MOV EAX,DWORD PTR [BP+4]
- MOV EDX,DWORD PTR [BP+8]
- MOV EBX,DWORD PTR [BP+12]
- MOV ECX,DWORD PTR [BP+16]
- CALL faddfxfy
- MOV DWORD PTR _facc,EAX
- MOV DWORD PTR _facc+4,EDX
- POP BP
- RET
- fsubfxfy:
- XOR ECX,#$80000000 ; complement sign bit, fall into add routine
- faddfxfy:
- PUSH EBP
- PUSH EDI
- PUSH ESI
- MOV EDI,ECX ; free CL for shifts
- MOV ESI,EDX ; this mainly for consistent naming
- AND ESI,#$7FFFFFFF ; discard sign so comparison is simple
- AND EDI,#$7FFFFFFF
- CMP ESI,EDI
- JA XBIG
- JB SWAP
- CMP EAX,EBX
- JAE XBIG
- SWAP:
- XCHG EDX,ECX
- XCHG ESI,EDI
- XCHG EAX,EBX
- XBIG:
- AND ESI,#$000FFFFF ; discard exponent
- AND EDI,#$000FFFFF
- OR ESI,#$00100000 ; normalize
- OR EDI,#$00100000
- SHR ECX,32-(1+11)
- SHR EDX,32-(1+11)
- MOV EBP,ECX ; prepare to compare signs (want high bits 0)
- SUB CX,DX ; get difference of signs in CX
- NEG CX ; D holds sign and exponent of both throughout
- CMP CX,#(64-11)+2
- JAE TO_DONE1 ; x dominates y
- XOR BP,DX
- AND BP,#$0800 ; see if signs are same
- JNZ TO_SUBTRACT ; else roundoff reg EBP is 0
- CMP CL,#32
- JAE TO_ADD_BIGSHIFT
- SHRD EBP,EBX,CL
- SHRD EBX,EDI,CL
- SHR EDI,CL
- ADD EAX,EBX
- ADC ESI,EDI
- SUB EBX,EBX
- ; result DX(1+11):SI:AX:BP:BX but needs normalization
- NORMALIZE:
- MOV CX,DX
- AND CX,#$07FF
- TEST ESI,#$00200000
- JZ NORMALIZE2
- BR LOVERFLOW
- TO_DONE1:
- JMP DONE1
- TO_SUBTRACT:
- BR SUBTRACT
- TO_ADD_BIGSHIFT:
- BR ADD_BIGSHIFT
- TO_NORMLITTLE:
- BR NORMLITTLE
- ; result DX(1):CX(11):SI:AX:BP:BX
- NORMALIZE2:
- SHRD EDI,ESI,32-11
- ; top 11 bits of ESI known 0 and BSR is slooow
- BSR EDI,EDI ; index of leading 1 bit in EDI is 11..31 in DI
- JZ TO_NORMLITTLE ; ESI is zero (flag wrong in Intel Manual)
- SUB DI,#31
- NEG DI
- PUSH CX ; gr
- MOV CX,DI ; rr
- SHLD ESI,EAX,CL
- SHLD EAX,EBP,CL
- SHLD EBP,EBX,CL
- SHL EBX,CL
- POP CX ; rr
- SUB CX,DI
- JC UNDERFLOW
- ROUND:
- CMP EBP,#$80000000 ; test roundoff register
- JA ROUNDUP
- JB DONE ; no rounding
- TEST EBX,EBX
- JNZ ROUNDUP
- TEST AL,#1 ; ambiguous case, round to even
- JZ DONE ; even, no rounding
- ROUNDUP:
- ADD EAX,#1
- ADC ESI,#0
- SUB EBP,EBP
- SUB EBX,EBX
- TEST ESI,#$00200000
- JNZ LOVERFLOW ; rounding may cause overflow!
- DONE:
- AND DX,#$0800 ; extract sign of largest and result
- OR DX,CX ; include exponent with sign
- DONE1:
- SHL EDX,32-(1+11)
- AND ESI,#$000FFFFF ; discard normalization bit
- OR EDX,ESI
- POP ESI
- POP EDI
- POP EBP
- RET
- UNDERFLOW: ; should have error message here
- ANSWER0:
- SUB EDX,EDX
- MOV EAX,EDX
- POP ESI
- POP EDI
- POP EBP
- RET
- LOVERFLOW: ; carry bit must be right-shifted back in
- SHR ESI,1
- RCR EAX,1
- RCR EBP,1
- RCR EBX,1
- INC CX
- CMP CX,#$0800
- JNZ ROUND
- OVERFLOW: ; should have error message here
- MOV EDX,#$FFE00000 ; + infinity
- SUB EAX,EAX
- POP ESI
- POP EDI
- POP EBP
- RET
- ADD_BIGSHIFT:
- SUB CL,#32
- SHRD EBP,EBX,CL
- SHRD EBX,EDI,CL
- SHR EDI,CL
- ADD EAX,EDI
- ADC ESI,#0
- XCHG EBP,EBX
- BR NORMALIZE
- NORMLITTLE:
- SHLD ESI,EAX,32-(1+11)
- SHLD EAX,EBP,32-(1+11)
- SHLD EBP,EBX,32-(1+11)
- SHL EBX,20
- SUB CL,#32-(1+11)
- JC UNDERFLOW
- BR NORMALIZE2
- SUBTRACT:
- SUB EBP,EBP ; set up roundoff register
- CMP CL,#32
- JAE SUBTRACT_BIGSHIFT
- SHRD EBP,EBX,CL
- SHRD EBX,EDI,CL
- SHR EDI,CL
- NEG EBP
- SBB EAX,EBX
- SBB ESI,EDI
- SUB EBX,EBX
- MOV CX,DX
- AND CX,#$07FF
- BR NORMALIZE2
- SUBTRACT_BIGSHIFT:
- SUB CL,#32
- SHRD EBP,EBX,CL
- SHRD EBX,EDI,CL
- SHR EDI,CL
- NEG EBX
- NEG EBP
- SBB EBX,#0
- SBB EAX,EDI
- SBB ESI,#0
- XCHG EBP,EBX
- MOV CX,DX
- AND CX,#$07FF
- BR NORMALIZE2
- TO_ANSWER0:
- BR ANSWER0
- TO_OVERFLOW:
- JMP TO_OVERFLOW
- TO_UNDERFLOW:
- BR UNDERFLOW
- fmulfxfy:
- PUSH EBP
- PUSH EDI
- PUSH ESI
- MOV ESI,EDX ; free DX for multiplications
- MOV EDI,ECX ; this mainly for consistent naming
- SHR EDX,32-(1+11)
- SHR ECX,32-(1+11)
- MOV BP,DX
- XOR BP,CX
- AND BP,#$0800 ; extract sign
- AND DX,#$07FF ; exp(x)
- JZ TO_ANSWER0
- AND CX,#$07FF ; exp(y)
- JZ TO_ANSWER0
- ADD CX,DX
- SUB CX,#$0400
- JB TO_UNDERFLOW
- CMP CX,#$07FF
- JA TO_OVERFLOW ; probably not quite right
- AND ESI,#$000FFFFF ; discard sign and exponent
- AND EDI,#$000FFFFF
- OR ESI,#$00100000 ; normalize
- OR EDI,#$00100000
- ; exponent is in CX, sign in BP, operands in ESI:EAX and EDI:EBX, DX is free
- ; product to go in ESI:EAX:EBP:EBX
- ; terminology: x * y = (x32:x0) * (y32:y0) = x32y32 + x32y0 + x0y32 +x0y0
- PUSH CX
- PUSH BP
- MOV ECX,EAX
- MUL EBX ; x0y0
- MOV EBP,EDX ; x0y0.high in EBP
- XCHG EBX,EAX ; x0y0.low in EBX (final), y0 in EAX
- MUL ESI ; x32y0
- PUSH EAX ; x32y0.low on stack
- PUSH EDX ; x32y0.high on stack
- MOV EAX,ESI
- MUL EDI ; x32y32
- MOV ESI,EDX ; x32y32.high in ESI (final except carries)
- XCHG ECX,EAX ; x32y32.low in ECX, x0 in EAX
- MUL EDI ; x0y32
- ADD EBP,EAX ; x0y0.high + x0y32.low
- POP EAX ; x32y0.high
- ADC EAX,EDX ; x32y0.high + x0y32.high
- ADC ESI,#0
- POP EDX ; x32y0.low
- ADD EBP,EDX ; (x0y0.high + x0y32.low) + x32y0.low
- ADC EAX,ECX ; (x32y0.high + x0y32.high) + x32y32.low
- ADC ESI,#0
- POP DX ; sign
- POP CX ; exponent
- ADD CX,#13 ; temp fixup
- BR NORMALIZE2
- _facc:
- .word 0,0
|