TITLE mpmath_a.asm (C) 1989, Mark C. Peterson, CompuServe [70441,3353]
SUBTTL All rights reserved.
;
;  Code may be used in any program provided the author is credited
;    either during program execution or in the documentation.  Source
;    code may be distributed only in combination with public domain or
;    shareware source code.  Source code may be modified provided the
;    copyright notice and this message is left unchanged and all
;    modifications are clearly documented.
;
;    I would appreciate a copy of any work which incorporates this code,
;    however this is optional.
;
;    Mark C. Peterson
;    405-C Queen St., Suite #181
;    Southington, CT 06489
;    (203) 276-9721
;
;  Note: Remark statements following floating point commands generally indicate
;     the FPU stack contents after the command is completed.
;
;  References:
;     80386/80286 Assembly Language Programming
;        by William H. Murray, III and Chris H. Pappas
;        Published by Osborne McGraw-Hill, 1986
;        
;
;


IFDEF ??version
MASM51
QUIRKS
ENDIF

.model medium, c


.data

extrn cpu:WORD


MP STRUC
   Exp   DW    0
   Mant  DD    0
MP ENDS


PUBLIC MPOverflow
MPOverflow  DW        0

Ans         MP       <?>
Double      DQ        ? 


.code

.8086

fg2MP086    PROC     x:DWORD, fg:WORD
   mov   ax, WORD PTR [x]
   mov   dx, WORD PTR [x+2]
   mov   cx, ax
   or    cx, dx
   jz    ExitFg2MP

   mov   cx, 1 SHL 14 + 30
   sub   cx, fg

   or    dx, dx
   jns   BitScanRight

   or    ch, 80h
   not   ax
   not   dx
   add   ax, 1
   adc   dx, 0

BitScanRight:
   shl   ax, 1
   rcl   dx, 1
   dec   cx
   or    dx, dx
   jns   BitScanRight

ExitFg2MP:
   mov   Ans.Exp, cx
   mov   WORD PTR Ans.Mant+2, dx
   mov   WORD PTR Ans.Mant, ax
   lea   ax, Ans
   mov   dx, ds
   ret
fg2MP086    ENDP



MPcmp086    PROC     uses si di, xExp:WORD, xMant:DWORD, yExp:WORD, yMant:DWORD
LOCAL Rev:WORD, Flag:WORD
   mov   Rev, 0
   mov   Flag, 0
   mov   ax, xExp
   mov   dx, WORD PTR [xMant]
   mov   si, WORD PTR [xMant+2]
   mov   bx, yExp
   mov   cx, WORD PTR [yMant]
   mov   di, WORD PTR [yMant+2]
   or    ax, ax
   jns   AtLeastOnePos

   or    bx, bx
   jns   AtLeastOnePos

   mov   Rev, 1
   and   ah, 7fh
   and   bh, 7fh

AtLeastOnePos:
   cmp   ax, bx
   jle   Cmp1

   mov   Flag, 1
   jmp   ChkRev

Cmp1:
   je    Cmp2

   mov   Flag, -1
   jmp   ChkRev

Cmp2:
   cmp   si, di
   jbe   Cmp3

   mov   Flag, 1
   jmp   ChkRev

Cmp3:
   je    Cmp4

   mov   Flag, -1
   jmp   ChkRev

Cmp4:
   cmp   dx, cx
   jbe   Cmp5

   mov   Flag, 1
   jmp   ChkRev

Cmp5:
   je    ChkRev

   mov   Flag, -1

ChkRev:
	or    Rev, 0
   jz    ExitCmp

   neg   Flag

ExitCmp:
   mov   ax, Flag
   ret
MPcmp086    ENDP






MPmul086    PROC     uses si di, xExp:WORD, xMant:DWORD, yExp:WORD, yMant:DWORD
   mov   ax, xExp
   mov   bx, yExp
   xor   ch, ch
   shl   bh, 1
   rcr   ch, 1
   shr   bh, 1
   xor   ah, ch

   sub   bx, (1 SHL 14) - 2
   add   ax, bx
   jno   NoOverflow

Overflow:
   or    WORD PTR [xMant+2], 0
   jz    ZeroAns
   or    WORD PTR [yMant+2], 0
   jz    ZeroAns

   mov   MPOverflow, 1

ZeroAns:
   xor   ax, ax
   xor   dx, dx
   mov   Ans.Exp, ax
   jmp   StoreMant

NoOverflow:
   mov   Ans.Exp, ax

   mov   si, WORD PTR [xMant+2]
   mov   bx, WORD PTR [xMant]
   mov   di, WORD PTR [yMant+2]
   mov   cx, WORD PTR [yMant]

   mov   ax, si
   or    ax, bx
   jz    ZeroAns

   mov   ax, di
   or    ax, cx
   jz    ZeroAns

   mov   ax, cx
   mul   bx
   push  dx

   mov   ax, cx
   mul   si
   push  ax
   push  dx

   mov   ax, bx
   mul   di
   push  ax
   push  dx

   mov   ax, si
   mul   di
   pop   bx
   pop   cx
   pop   si
   pop   di

   add   ax, bx
   adc   dx, 0
   pop   bx
   add   di, bx
   adc   ax, 0
   adc   dx, 0
   add   di, cx
   adc   ax, si
   adc   dx, 0

   or    dx, dx
   js    StoreMant

   shl   di, 1
   rcl   ax, 1
   rcl   dx, 1
   sub   Ans.Exp, 1
   jo    Overflow

StoreMant:
   mov   WORD PTR Ans.Mant+2, dx
   mov   WORD PTR Ans.Mant, ax

   lea   ax, Ans
   mov   dx, ds
   ret
MPmul086    ENDP



d2MP086     PROC     uses si di, x:QWORD
   mov   dx, WORD PTR [x+6]
   mov   ax, WORD PTR [x+4]
   mov   bx, WORD PTR [x+2]
   mov   cx, WORD PTR [x]
   mov   si, dx
   shl   si, 1
   or    si, bx
   or    si, ax
   or    si, dx
   or    si, cx
   jnz   NonZero

   xor   ax, ax
   xor   dx, dx
   jmp   StoreAns

NonZero:
   mov   si, dx
   shl   si, 1
   pushf
   mov   cl, 4
   shr   si, cl
   popf
   rcr   si, 1
   add   si, (1 SHL 14) - (1 SHL 10)

   mov   di, ax                           ; shl dx:ax:bx 12 bits
   mov   cl, 12
   shl   dx, cl
   shl   ax, cl
   mov   cl, 4
   shr   di, cl
   shr   bx, cl
   or    dx, di
   or    ax, bx
   stc
   rcr   dx, 1
   rcr   ax, 1

StoreAns:
   mov   Ans.Exp, si
   mov   WORD PTR Ans.Mant+2, dx
   mov   WORD PTR Ans.Mant, ax

   lea   ax, Ans
   mov   dx, ds
   ret
d2MP086     ENDP



MP2d086     PROC     uses si di, xExp:WORD, xMant:DWORD
   sub   xExp, (1 SHL 14) - (1 SHL 10)
   jo    Overflow

   mov   bx, xExp
   and   bx, 0111100000000000b
   jz    InRangeOfDouble

Overflow:
   mov   MPOverflow, 1
   xor   ax, ax
   xor   dx, dx
   xor   bx, bx
   jmp   StoreAns

InRangeOfDouble:
   mov   si, xExp
   mov   ax, si
   mov   cl, 5
   shl   si, cl
   shl   ax, 1
   rcr   si, 1

   mov   dx, WORD PTR [xMant+2]
   mov   ax, WORD PTR [xMant]
   shl   ax, 1
   rcl   dx, 1

   mov   bx, ax
   mov   di, dx
   mov   cl, 12
   shr   dx, cl
   shr   ax, cl
   mov   cl, 4
   shl   bx, cl
   shl   di, cl
   or    ax, di
   or    dx, si

StoreAns:
   mov   WORD PTR Double+6, dx
   mov   WORD PTR Double+4, ax
   mov   WORD PTR Double+2, bx
   xor   bx, bx
   mov   WORD PTR Double, bx

   lea   ax, Double
   mov   dx, ds
   ret
MP2d086     ENDP




MPadd086    PROC     uses si di, xExp:WORD, xMant:DWORD, yExp:WORD, yMant:DWORD
   mov   si, xExp
   mov   dx, WORD PTR [xMant+2]
   mov   ax, WORD PTR [xMant]

   mov   di, yExp

   mov   cx, si
   xor   cx, di
   js    Subtract
   jz    SameMag

   cmp   si, di
   jg    XisGreater

   xchg  si, di
   xchg  dx, WORD PTR [yMant+2]
   xchg  ax, WORD PTR [yMant]

XisGreater:
   mov   cx, si
   sub   cx, di
   cmp   cx, 32
   jl    ChkSixteen
   jmp   StoreAns

ChkSixteen:
   cmp   cx, 16
   jl    SixteenBitShift

   sub   cx, 16
   mov   bx, WORD PTR [yMant+2]
   shr   bx, cl
   mov   WORD PTR [yMant], bx
   mov   WORD PTR [yMant+2], 0
   jmp   SameMag

SixteenBitShift:
   mov   bx, WORD PTR [yMant+2]
   shr   WORD PTR [yMant+2], cl
   shr   WORD PTR [yMant], cl
   neg   cl
   add   cl, 16
   shl   bx, cl
   or    WORD PTR [yMant], bx

SameMag:
   add   ax, WORD PTR [yMant]
   adc   dx, WORD PTR [yMant+2]
   jc    ShiftCarry
   jmp   StoreAns

ShiftCarry:
   rcr   dx, 1
   rcr   ax, 1
   add   si, 1
   jo    Overflow
   jmp   StoreAns

Overflow:
   mov   MPOverflow, 1

ZeroAns:
   xor   si, si
   xor   ax, ax
   xor   dx, dx
   jmp   StoreAns

Subtract:
   xor   di, 8000h
   mov   cx, si
   sub   cx, di
   jnz   DifferentMag

   cmp   dx, WORD PTR [yMant+2]
   jg    SubtractNumbers
   jne   SwapNumbers

   cmp   ax, WORD PTR [yMant]
   jg    SubtractNumbers
   je    ZeroAns

SwapNumbers:   
   xor   si, 8000h
   xchg  ax, WORD PTR [yMant]
   xchg  dx, WORD PTR [yMant+2]
   jmp   SubtractNumbers

DifferentMag:
   or    cx, cx
   jns   NoSwap

   xchg  si, di
   xchg  ax, WORD PTR [yMant]
   xchg  dx, WORD PTR [yMant+2]
   xor   si, 8000h
   neg   cx

NoSwap:
   cmp   cx, 32
   jge   StoreAns

   cmp   cx, 16
   jl    SixteenBitShift2

   sub   cx, 16
   mov   bx, WORD PTR [yMant+2]
   shr   bx, cl
   mov   WORD PTR [yMant], bx
   mov   WORD PTR [yMant+2], 0
   jmp   SubtractNumbers

SixteenBitShift2:
   mov   bx, WORD PTR [yMant+2]
   shr   WORD PTR [yMant+2], cl
   shr   WORD PTR [yMant], cl
   neg   cl
   add   cl, 16
   shl   bx, cl
   or    WORD PTR [yMant], bx

SubtractNumbers:
   sub   ax, WORD PTR [yMant]
   sbb   dx, WORD PTR [yMant+2]

BitScanRight:
   or    dx, dx
   js    StoreAns

   shl   ax, 1
   rcl   dx, 1
   sub   si, 1
   jno   BitScanRight
   jmp   Overflow

StoreAns:
   mov   Ans.Exp, si
   mov   WORD PTR Ans.Mant+2, dx
   mov   WORD PTR Ans.Mant, ax

   lea   ax, Ans
   mov   dx, ds
   ret
MPadd086    ENDP



MPdiv086    PROC     uses si di, xExp:WORD, xMant:DWORD, yExp:WORD, \
                     yMant:DWORD
   mov   ax, xExp
   mov   bx, yExp
   xor   ch, ch
   shl   bh, 1
   rcr   ch, 1
   shr   bh, 1
   xor   ah, ch

   sub   bx, (1 SHL 14) - 2
   sub   ax, bx
   jno   NoOverflow

Overflow:
   mov   MPOverflow, 1

ZeroAns:
   xor   ax, ax
   xor   dx, dx
   mov   Ans.Exp, dx
   jmp   StoreMant

NoOverflow:
   mov   Ans.Exp, ax

   mov   dx, WORD PTR [xMant+2]
   mov   ax, WORD PTR [xMant]
   or    dx, dx
   jz    ZeroAns

   mov   cx, WORD PTR [yMant+2]
   mov   bx, WORD PTR [yMant]
   or    cx, cx
   jz    Overflow

   cmp   dx, cx
   jl    Divide

   shr   dx, 1
   rcr   ax, 1
   add   Ans.Exp, 1
   jo    Overflow

Divide:
   div   cx
   mov   si, dx
   mov   dx, bx
   mov   bx, ax
   mul   dx
   xor   di, di
   cmp   dx, si
   jnc   RemReallyNeg

   xchg  ax, di
   xchg  dx, si
   sub   ax, di
   sbb   dx, si

   shr   dx, 1
   rcr   ax, 1
   div   cx
   mov   dx, bx
   shl   ax, 1
   adc   dx, 0
   jmp   StoreMant

RemReallyNeg:
   sub   ax, di
   sbb   dx, si

   shr   dx, 1
   rcr   ax, 1
   div   cx
   mov   dx, bx
   mov   bx, ax
   xor   ax, ax
   xor   cx, cx
   shl   bx, 1
   rcl   cx, 1
   sub   ax, bx
   sbb   dx, cx
   jno   StoreMant

   shl   ax, 1
   rcl   dx, 1
   dec   Ans.Exp

StoreMant:
   mov   WORD PTR Ans.Mant, ax
   mov   WORD PTR Ans.Mant+2, dx
   lea   ax, Ans
   mov   dx, ds
   ret
MPdiv086    ENDP


MPcmp386    PROC     uses si di, xExp:WORD, xMant:DWORD, yExp:WORD, yMant:DWORD
   mov   si, 0
   mov   di, si
.386
   mov   ax, xExp
   mov   edx, xMant
   mov   bx, yExp
   mov   ecx, yMant
   or    ax, ax
   jns   AtLeastOnePos

   or    bx, bx
   jns   AtLeastOnePos

   mov   si, 1
   and   ah, 7fh
   and   bh, 7fh

AtLeastOnePos:
   cmp   ax, bx
   jle   Cmp1

   mov   di, 1
   jmp   ChkRev

Cmp1:
   je    Cmp2

   mov   di, -1
   jmp   ChkRev

Cmp2:
   cmp   edx, ecx
   jbe   Cmp3

   mov   di, 1
   jmp   ChkRev

Cmp3:
   je    ChkRev

   mov   di, -1

ChkRev:
	or    si, si
   jz    ExitCmp

   neg   di

ExitCmp:
   mov   ax, di
.8086
   ret
MPcmp386    ENDP



d2MP386     PROC     uses si di, x:QWORD
   mov   si, WORD PTR [x+6]
.386
   mov   edx, DWORD PTR [x+4]
   mov   eax, DWORD PTR [x]

   mov   ebx, edx
   shl   ebx, 1
   or    ebx, eax
   jnz   NonZero
   
   xor   si, si
   xor   edx, edx
   jmp   StoreAns

NonZero:
   shl   si, 1
   pushf
   shr   si, 4
   popf
   rcr   si, 1
   add   si, (1 SHL 14) - (1 SHL 10)

   shld  edx, eax, 12
   stc
   rcr   edx, 1

StoreAns:
   mov   Ans.Exp, si
   mov   Ans.Mant, edx

   lea   ax, Ans
   mov   dx, ds
.8086
   ret
d2MP386     ENDP




MP2d386     PROC     uses si di, xExp:WORD, xMant:DWORD
   sub   xExp, (1 SHL 14) - (1 SHL 10)
.386
   jo    Overflow

   mov   bx, xExp
   and   bx, 0111100000000000b
   jz    InRangeOfDouble

Overflow:
   mov   MPOverflow, 1
   xor   eax, eax
   xor   edx, edx
   jmp   StoreAns

InRangeOfDouble:
   mov   bx, xExp
   mov   ax, bx 
   shl   bx, 5
   shl   ax, 1
   rcr   bx, 1
   shr   bx, 4

   mov   edx, xMant
   shl   edx, 1
   xor   eax, eax
   shrd  eax, edx, 12
   shrd  edx, ebx, 12

StoreAns:
   mov   DWORD PTR Double+4, edx
   mov   DWORD PTR Double, eax

   lea   ax, Double
   mov   dx, ds
.8086
   ret
MP2d386     ENDP



MPmul386    PROC     uses si di, xExp:WORD, xMant:DWORD, yExp:WORD, \
                     yMant:DWORD
   mov   ax, xExp
   mov   bx, yExp
.386
   xor   ch, ch
   shl   bh, 1
   rcr   ch, 1
   shr   bh, 1
   xor   ah, ch

   sub   bx, (1 SHL 14) - 2
   add   ax, bx
   jno   NoOverflow

Overflow:
   or    WORD PTR [xMant+2], 0
   jz    ZeroAns
   or    WORD PTR [yMant+2], 0
   jz    ZeroAns

   mov   MPOverflow, 1

ZeroAns:
   xor   edx, edx
   mov   Ans.Exp, dx
   jmp   StoreMant

NoOverflow:
   mov   Ans.Exp, ax

   mov   eax, xMant
   mov   edx, yMant
   or    eax, eax
   jz    ZeroAns

   or    edx, edx
   jz    ZeroAns

   mul   edx

   or    edx, edx
   js    StoreMant

   shld  edx, eax, 1
   sub   Ans.Exp, 1
   jo    Overflow

StoreMant:
   mov   Ans.Mant, edx
   lea   ax, Ans
   mov   dx, ds
.8086
   ret
MPmul386    ENDP



MPadd386    PROC     uses si di, xExp:WORD, xMant:DWORD, yExp:WORD, \
                     yMant:DWORD
   mov   si, xExp
.386
   mov   eax, xMant

   mov   di, yExp
   mov   edx, yMant

   mov   cx, si
   xor   cx, di
   js    Subtract
   jz    SameMag

   cmp   si, di
   jg    XisGreater

   xchg  si, di
   xchg  eax, edx

XisGreater:
   mov   cx, si
   sub   cx, di
   cmp   cx, 32
   jge   StoreAns

   shr   edx, cl

SameMag:
   add   eax, edx
   jnc   StoreAns

   rcr   eax, 1
   add   si, 1
   jno   StoreAns

Overflow:
   mov   MPOverflow, 1

ZeroAns:
   xor   si, si
   xor   edx, edx
   jmp   StoreAns

Subtract:
   xor   di, 8000h
   mov   cx, si
   sub   cx, di
   jnz   DifferentMag

   cmp   eax, edx
   jg    SubtractNumbers
   je    ZeroAns

   xor   si, 8000h
   xchg  eax, edx
   jmp   SubtractNumbers

DifferentMag:
   or    cx, cx
   jns   NoSwap

   xchg  si, di
   xchg  eax, edx
   xor   si, 8000h
   neg   cx

NoSwap:
   cmp   cx, 32
   jge   StoreAns

   shr   edx, cl

SubtractNumbers:
   sub   eax, edx
   bsr   ecx, eax
   neg   cx
   add   cx, 31
   shl   eax, cl
   sub   si, cx
   jo    Overflow

StoreAns:
   mov   Ans.Exp, si
   mov   Ans.Mant, eax

   lea   ax, Ans
   mov   dx, ds
.8086
   ret
MPadd386    ENDP
   

   


MPdiv386    PROC     uses si di, xExp:WORD, xMant:DWORD, yExp:WORD, \
                     yMant:DWORD
   mov   ax, xExp
   mov   bx, yExp
.386
   xor   ch, ch
   shl   bh, 1
   rcr   ch, 1
   shr   bh, 1
   xor   ah, ch

   sub   bx, (1 SHL 14) - 2
   sub   ax, bx
   jno   NoOverflow

Overflow:
   mov   MPOverflow, 1

ZeroAns:
   xor   eax, eax
   mov   Ans.Exp, ax
   jmp   StoreMant

NoOverflow:
   mov   Ans.Exp, ax

   xor   eax, eax
   mov   edx, xMant
   mov   ecx, yMant
   or    edx, edx
   jz    ZeroAns

   or    ecx, ecx
   jz    Overflow

   cmp   edx, ecx
   jl    Divide

   shr   edx, 1
   rcr   eax, 1
   add   Ans.Exp, 1
   jo    Overflow

Divide:
   div   ecx

StoreMant:
   mov   Ans.Mant, eax
   lea   ax, Ans
   mov   dx, ds
.8086
   ret
MPdiv386    ENDP


fg2MP386    PROC     x:DWORD, fg:WORD
   mov   bx, 1 SHL 14 + 30
   sub   bx, fg
.386
   mov   edx, x

   or    edx, edx
   jnz   ChkNegMP

   mov   bx, dx
   jmp   StoreAns

ChkNegMP:
   jns   BitScanRight

   or    bh, 80h
   neg   edx

BitScanRight:
   bsr   ecx, edx
   neg   cx
   add   cx, 31
   sub   bx, cx
   shl   edx, cl

StoreAns:
   mov   Ans.Exp, bx
   mov   Ans.Mant, edx
.8086
   lea   ax, Ans
   mov   dx, ds
   ret
fg2MP386    ENDP



PUBLIC MPcmp, MPmul, MPadd, MPdiv, MP2d, d2MP, fg2MP

fg2MP:
   cmp   cpu, 386
   je    Use386fg2MP
   jmp   fg2MP086

Use386fg2MP:
   jmp   fg2MP386

MPcmp:
   cmp   cpu, 386
   je    Use386cmp
   jmp   MPcmp086

Use386cmp:
   jmp   MPcmp386

MPmul:
   cmp   cpu, 386
   je    Use386mul
   jmp   MPmul086

Use386mul:
   jmp   MPmul386

d2MP:
   cmp   cpu, 386
   je    Use386d2MP
   jmp   d2MP086

Use386d2MP:
   jmp   d2MP386

MPadd:
   cmp   cpu, 386
   je    Use386add
   jmp   MPadd086

Use386add:
   jmp   MPadd386

MPdiv:
   cmp   cpu, 386
   je    Use386div
   jmp   MPdiv086

Use386div:
   jmp   MPdiv386

MP2d:
   cmp   cpu, 386
   je    Use386MP2d
   jmp   MP2d086

Use386MP2d:
   jmp   MP2d386


END

