diff options
Diffstat (limited to 'as/asm/fadd.asm')
-rw-r--r-- | as/asm/fadd.asm | 271 |
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 |