summaryrefslogtreecommitdiff
path: root/as/asm/fadd.asm
diff options
context:
space:
mode:
Diffstat (limited to 'as/asm/fadd.asm')
-rw-r--r--as/asm/fadd.asm271
1 files changed, 271 insertions, 0 deletions
diff --git a/as/asm/fadd.asm b/as/asm/fadd.asm
new file mode 100644
index 0000000..d18f002
--- /dev/null
+++ b/as/asm/fadd.asm
@@ -0,0 +1,271 @@
+_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