mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3118 lines
84 KiB
3118 lines
84 KiB
PAGE 60, 132
|
|
TITLE miscellaneous utilities sub-functions
|
|
|
|
COMMENT `
|
|
|
|
|
|
Copyright (c) 1990-1991 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
htutils.asm
|
|
|
|
|
|
Abstract:
|
|
|
|
This module provided a set of sub-functions for math speed up
|
|
subfunctions.
|
|
|
|
This function is the equivelant codes in the htmath.c
|
|
|
|
Author:
|
|
|
|
24-Sep-1991 Tue 18:33:44 updated -by- Daniel Chou (danielc)
|
|
|
|
[Environment:]
|
|
|
|
Printer Driver.
|
|
|
|
|
|
[Notes:]
|
|
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
.XLIST
|
|
INCLUDE i386\i80x86.inc
|
|
.LIST
|
|
|
|
|
|
IF HT_ASM_80x86
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
.XLIST
|
|
INCLUDE i386\htp.inc
|
|
.LIST
|
|
;------------------------------------------------------------------------------
|
|
|
|
.CODE
|
|
|
|
|
|
FD6NUM_1_DW equ 0f4240h
|
|
FD6NUM_1_HW equ 0fh
|
|
FD6NUM_1_LW equ 4240h
|
|
|
|
|
|
|
|
|
|
SUBTTL ComputeChecksum
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function compute 32-bit checksum of the passed data
|
|
|
|
Arguments:
|
|
|
|
pData - Pointer to a byte array to be computed for the checksum
|
|
|
|
DataSize - Size of the data in bytes
|
|
|
|
Return Value:
|
|
|
|
32-bit checksum in dx:ax or EAX
|
|
|
|
Author:
|
|
|
|
18-Mar-1991 Mon 13:48:51 created -by- Daniel Chou (danielc)
|
|
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
@BEG_PROC ComputeChecksum <pData:DWORD, \
|
|
InitialChecksum:DWORD, \
|
|
DataSize:DWORD>
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
;==================================
|
|
; ds:si = data
|
|
; bx:cx = size
|
|
; ax = Checksum Octet S
|
|
; dx = Checksun Octet R
|
|
;============================================================================
|
|
;We have two 16-bit checksum octet R,S , inital are zero
|
|
;
|
|
; S(n) = S(n-1) + Data
|
|
; R(n) = R(n-1) + S(n)
|
|
;============================================================================
|
|
|
|
@ENTER _DS _SI ; Save environment registers
|
|
|
|
LDS_SI pData
|
|
cld
|
|
|
|
mov cx, WPTR DataSize
|
|
mov bx, WPTR DataSize+2
|
|
|
|
mov ax, WPTR InitialChecksum ; assume no odd byte
|
|
mov dx, WPTR InitialChecksum+2
|
|
|
|
shr bx, 1
|
|
rcr cx, 1
|
|
jnc short CheckSum1
|
|
|
|
CheckSum0:
|
|
xor ax, ax
|
|
lodsb
|
|
add ax, WPTR InitialChecksum
|
|
|
|
CheckSum1:
|
|
inc cx
|
|
inc bx
|
|
jmp short CheckSumStart
|
|
|
|
CheckSumLoop:
|
|
add ax, WPTR [_SI] ; S(n) = one's complement arithmic
|
|
adc dx, ax,
|
|
add _SI, 2
|
|
|
|
CheckSumStart:
|
|
dec cx
|
|
jnz CheckSumLoop
|
|
dec bx
|
|
jnz short CheckSumLoop
|
|
|
|
@EXIT
|
|
|
|
ELSE
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
;==================================
|
|
; _BX = data
|
|
; _CX = size
|
|
; ax = Checksum Octet S
|
|
; dx = Checksun Octet R
|
|
;============================================================================
|
|
;We have two 16-bit checksum octet R,S , inital are zero
|
|
;
|
|
; S(n) = S(n-1) + Data
|
|
; R(n) = R(n-1) + S(n)
|
|
;============================================================================
|
|
|
|
|
|
@ENTER
|
|
|
|
mov _BX, DPTR pData
|
|
mov _CX, DPTR DataSize
|
|
|
|
movzx _AX, WPTR InitialChecksum ; assume no odd byte
|
|
movzx _DX, WPTR InitialChecksum+2 ; assume no odd byte
|
|
|
|
shr _CX, 1
|
|
jnc short CheckSum1
|
|
|
|
CheckSum0:
|
|
xor ax, ax
|
|
mov al, BPTR [_BX]
|
|
add ax, WPTR InitialChecksum
|
|
inc _BX
|
|
|
|
CheckSum1:
|
|
inc _CX
|
|
jmp short CheckSumStart
|
|
|
|
CheckSumLoop:
|
|
add ax, WPTR [_BX] ; S(n) = one's complement arithmic
|
|
add dx, ax ; R(n) = one's complement arithmic
|
|
add _BX, 2
|
|
|
|
CheckSumStart:
|
|
dec _CX
|
|
jnz CheckSumLoop
|
|
|
|
Done: shl _DX, 16 ; R:S = dx:ax = _AX = 32-bits
|
|
or _AX, _DX ; return at EAX
|
|
|
|
@EXIT
|
|
|
|
ENDIF
|
|
|
|
@END_PROC
|
|
|
|
|
|
|
|
|
|
SUBTTL MulFD6
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function multiply two FD6 numbers (FIX decimal point decimal long
|
|
number, the LONG DECIMAL POINT SIX (FD6) is a number with lowest 6 digits
|
|
as fraction to the right of the decimal point), so like 1234567 = 1.234567,
|
|
the range for this data type is -2147.483647 to 2147.483647.
|
|
|
|
Arguments:
|
|
|
|
Multiplicand - a 32-bit FD6 multiplicand dividend number.
|
|
|
|
Multiplier - a 32-bit FD6 multiplier number.
|
|
|
|
Return Value:
|
|
|
|
The return value is the 32-bit FD6 number which is round up from 7th
|
|
decimal points, there is no remainder returned.
|
|
|
|
NO ERROR returned, if divisor is zero the return value will be 0, if
|
|
overflow happened, then maximum FD6 number will be returned (ie.
|
|
2147.483647)
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
@BEG_PROC MulFD6 <Multiplicand:DWORD, \
|
|
Multiplier:DWORD>
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
@ENTER _SI _DI _BP ; save these registers
|
|
|
|
mov ax, WPTR Multiplier
|
|
mov dx, WPTR Multiplier + 2
|
|
mov cx, ax
|
|
or cx, dx
|
|
jz short MulFD6_Zero
|
|
|
|
mov bx, WPTR Multiplicand
|
|
mov bp, WPTR Multiplicand + 2
|
|
mov cx, bx
|
|
or cx, bp
|
|
jz short MulFD6_Zero ; if any one of them is zero then
|
|
; result must be zero
|
|
MulFD6_1:
|
|
|
|
xor cx, cx
|
|
or bp, bp
|
|
jns short MulFD6_2
|
|
|
|
NEG32_FROMR16HL bp, bx
|
|
not cx ; cx=0 if positive, cx=0xffff negative
|
|
|
|
MulFD6_2:
|
|
|
|
or dx, dx
|
|
jns short MulFD6_3
|
|
|
|
NEG32_FROMR16HL dx, ax
|
|
not cx ; flip the final sign indicator
|
|
|
|
MulFD6_3:
|
|
|
|
cmp bp, FD6NUM_1_HW ; check if bp:bx == 1000000 (1.0)
|
|
jnz short MulFD6_31
|
|
cmp bx, FD6NUM_1_LW
|
|
jz short MulFD6_4 ; bp:bx = 1.0 return dx:ax
|
|
|
|
MulFD6_31:
|
|
|
|
cmp dx, FD6NUM_1_HW
|
|
jnz short MulFD6_32 ;
|
|
cmp ax, FD6NUM_1_LW ; check if dx:ax == 1000000 (1.0)
|
|
jnz short MulFD6_32
|
|
mov ax, bx
|
|
mov dx, bp ; dx:ax = 1.0 return bp:bx
|
|
jmp short MulFD6_4
|
|
|
|
MulFD6_32:
|
|
|
|
push cx ; save it
|
|
call U32MulU32_U64 ; dx:ax * bp:bx = dx:ax:bp:bx
|
|
call U64Div1000000 ; dx:ax:bp:bx / 1000000 = dx:ax
|
|
pop cx ; restore sign indicator
|
|
|
|
MulFD6_4:
|
|
|
|
S32_FROMR16HL_SR16 dx, ax, cx ; flip sign if sign
|
|
|
|
@EXIT
|
|
|
|
MulFD6_Zero:
|
|
|
|
xor ax, ax ; return 0
|
|
xor dx, dx
|
|
jmp short MulFD6_4
|
|
|
|
ELSE
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
@ENTER ; entering function
|
|
|
|
mov _AX, DPTR Multiplier ; see if this guy is zero
|
|
cdq ; save dx sign
|
|
xor _AX, _DX ; take absolute Multiplier in _AX
|
|
sub _AX, _DX ; zero ?
|
|
jz short MulFD6_Done ; return zero
|
|
|
|
mov _BX, _DX ; _BX = sign
|
|
mov _CX, _AX ; save absolute Multiplier in _CX
|
|
mov _AX, DPTR Multiplicand ; edx:eax now
|
|
cdq ; sign extended, saved the sign at here
|
|
xor _AX, _DX
|
|
sub _AX, _DX ; eax=absolute dividend now
|
|
jz short MulFD6_Done ; dividend = 0, return 0
|
|
|
|
xor _BX, _DX ; _BX=final sign only if _BX != _DX
|
|
|
|
;
|
|
; _AX=Multiplicand, _CX=Multiplier, _BX = final sign indicator
|
|
;
|
|
|
|
mov _DX, _CX
|
|
mov _CX, FD6NUM_1_DW ; multiply dividend by 1.0 (decimal)
|
|
|
|
;
|
|
; _AX=Multiplicand, _DX=Multiplier, _BX=sign, _CX=1.0
|
|
;
|
|
|
|
cmp _DX, _CX ; if Multiplier=1.0 or -1.0 then exit
|
|
jz short MulFD6_Sign ; return Multiplicand
|
|
|
|
xchg _DX, _AX ; _AX=Multiplier, _DX=Multiplicand
|
|
|
|
;
|
|
; _AX=Multiplier, _DX=Multiplicand, _BX=sign, _CX=1.0
|
|
;
|
|
|
|
cmp _DX, _CX ; if Multiplicand=1.0 or -1.0 then exit
|
|
jz short MulFD6_Sign ; return Multiplier
|
|
|
|
mul _DX ; _DX x _AX = _DX:_AX
|
|
add _AX, (FD6NUM_1_DW / 2) ; try to round up
|
|
adc _DX, 0
|
|
|
|
cmp _DX, _CX ; will divison overflow?
|
|
jae short MulFD6_Overflow
|
|
|
|
div _CX ; _DX=remainder, _AX=quotient
|
|
|
|
MulFD6_Sign:
|
|
|
|
xor _AX, _BX ; do any sign if necessary
|
|
sub _AX, _BX
|
|
|
|
MulFD6_Done:
|
|
|
|
cdq ; make it 64-bits
|
|
@EXIT ; exiting function
|
|
|
|
MulFD6_Overflow:
|
|
|
|
mov _AX, 07fffffffh ; return maximum number
|
|
jmp short MulFD6_Sign
|
|
|
|
ENDIF ; i8086 or i286
|
|
|
|
|
|
@END_PROC
|
|
|
|
|
|
|
|
SUBTTL Cube
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function compute the cube of the Number (ie. Number ^ 3)
|
|
the range for this data type is -2147.483647 to 2147.483647.
|
|
|
|
Arguments:
|
|
|
|
Number - a 32-bit FD6 multiplicand dividend number.
|
|
|
|
Return Value:
|
|
|
|
The return value is the 32-bit FD6 number which is round up from 7th
|
|
decimal points, there is no remainder returned.
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
@BEG_PROC Cube <Number:DWORD>
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
@ENTER _SI _DI _BP ; save these registers
|
|
|
|
mov ax, WPTR Number
|
|
mov dx, WPTR Number + 2
|
|
mov cx, ax
|
|
or cx, dx
|
|
jz short Cube_Done ; return 0
|
|
; result must be zero
|
|
Cube_1:
|
|
|
|
xor cx, cx
|
|
or dx, dx
|
|
jns short Cube_2
|
|
|
|
NEG32_FROMR16HL dx, ax
|
|
not cx ; flip the final sign indicator
|
|
|
|
Cube_2:
|
|
|
|
cmp dx, FD6NUM_1_HW
|
|
jnz short Cube_3 ;
|
|
cmp ax, FD6NUM_1_LW ; check if dx:ax == 1000000 (1.0)
|
|
jz Cube_Sign ; done
|
|
|
|
Cube_3:
|
|
|
|
push cx ; save it (sign)
|
|
push dx
|
|
push ax
|
|
mov bp, dx
|
|
mov bx, ax
|
|
call U32MulU32_U64 ; dx:ax * bp:bx = dx:ax:bp:bx
|
|
call U64Div1000000 ; dx:ax:bp:bx / 1000000 = dx:ax
|
|
pop bx ; now multiply the original again
|
|
pop bp
|
|
call U32MulU32_U64 ; dx:ax * bp:bx = dx:ax:bp:bx
|
|
call U64Div1000000 ; dx:ax:bp:bx / 1000000 = dx:ax
|
|
pop cx ; restore sign indicator
|
|
|
|
Cube_Sign:
|
|
|
|
S32_FROMR16HL_SR16 dx, ax, cx ; flip sign if sign
|
|
|
|
Cube_Done:
|
|
|
|
@EXIT
|
|
|
|
ELSE
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
@ENTER ; entering function
|
|
|
|
mov _AX, DPTR Number ; see if this guy is zero
|
|
cdq ; save dx sign
|
|
xor _AX, _DX ; take absolute Multiplier in _AX
|
|
sub _AX, _DX ; zero ?
|
|
jz short Cube_Done ; return zero
|
|
push _DX ; save sign
|
|
mov _CX, _AX ; save absolute Multiplier in _CX
|
|
mov _BX, FD6NUM_1_DW
|
|
|
|
;
|
|
; _AX=_CX=ABS(Number), esp= final sign indicator, _BX=1.0
|
|
;
|
|
|
|
cmp _AX, _BX
|
|
jz Cube_Sign ; return 1.0 or -1.0
|
|
|
|
mul _CX ; _DX:_AX=result
|
|
add _AX, (FD6NUM_1_DW / 2) ; try to round up
|
|
adc _DX, 0
|
|
cmp _DX, FD6NUM_1_DW ; will divison overflow?
|
|
jae short Cube_Overflow
|
|
div _BX ; _DX=remainder, _AX=quotient
|
|
|
|
mul _CX
|
|
add _AX, (FD6NUM_1_DW / 2) ; try to round up
|
|
adc _DX, 0
|
|
cmp _DX, FD6NUM_1_DW ; will divison overflow?
|
|
jae short Cube_Overflow
|
|
div _BX ; _DX=remainder, _AX=quotient
|
|
|
|
Cube_Sign:
|
|
|
|
pop _BX
|
|
xor _AX, _BX ; do any sign if necessary
|
|
sub _AX, _BX
|
|
|
|
Cube_Done:
|
|
|
|
cdq ; make it 64-bits
|
|
@EXIT ; exiting function
|
|
|
|
Cube_Overflow:
|
|
|
|
mov _AX, 07fffffffh ; return maximum number
|
|
jmp short Cube_Sign
|
|
|
|
ENDIF ; i8086 or i286
|
|
|
|
|
|
@END_PROC
|
|
|
|
|
|
|
|
|
|
SUBTTL MulDivFD6Pairs
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function multiply each pair of FD6 numbers and add the each pair
|
|
of the result together. (FIX decimal point decimal long number, the LONG
|
|
DECIMAL POINT SIX (FD6) is a number with lowest 6 digits as fraction to
|
|
the right of the decimal point), so like 1234567 = 1.234567, the range
|
|
for this data type is -2147.483647 to 2147.483647.
|
|
|
|
Arguments:
|
|
|
|
pMulDivPair - Pointer to array of MULDIVPAIR data structure, the first
|
|
structure in the array tell the count of the FD6 pairs,
|
|
a Divisor present flag and a Divisor, the FD6 pairs start
|
|
from second element in the array.
|
|
|
|
Return Value:
|
|
|
|
The return value is the 32-bit FD6 number which is round up from 7th
|
|
decimal points, there is no remainder returned.
|
|
|
|
NO ERROR returned, if divisor is zero then it assume no divisor is present,
|
|
if Count of FD6 pairs is zero then it return FD6_0
|
|
|
|
Author:
|
|
|
|
27-Aug-1992 Thu 18:13:55 updated -by- Daniel Chou (danielc)
|
|
Re-write to remove variable argument conflict, and make it only passed
|
|
a pointer to the MULDIVPAIR structure array
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
|
|
@BEG_PROC MulDivFD6Pairs <pMulDivPair:DWORD>
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
@ENTER _DS _SI _DI _BP
|
|
|
|
lds si, pMulDivPair
|
|
lodsw ; get count
|
|
xor dx, dx ; clear dx for quick exit
|
|
or ax, ax
|
|
jnz short MulDivFD6PairCount
|
|
|
|
jmp MulDivFD6Pair9 ; exit with 0
|
|
|
|
MulDivFD6PairCount:
|
|
|
|
mov cx, ax ; cx=count
|
|
lodsw ; get divisor present flag
|
|
or ax, ax ; has divisor ?
|
|
jz short MulDivFD6PairsStart
|
|
|
|
mov ax, WPTR [si] ; get divisor = dx:ax
|
|
mov dx, WPTR [si + 2] ;
|
|
|
|
MulDivFD6PairStart:
|
|
|
|
push dx ; save divisor dx:ax on stack
|
|
push ax
|
|
add si, 4 ; jump to first pair
|
|
|
|
MulDivFD6PairsStart:
|
|
|
|
xor dx, dx ; sum = 0 to start with
|
|
xor ax, ax
|
|
xor bp, bp
|
|
xor bx, bx
|
|
|
|
MulDivFD6PairsLoop:
|
|
|
|
push cx ; save count
|
|
push dx ; save sum dx:ax:bp:bx
|
|
push ax
|
|
push bp
|
|
push bx
|
|
|
|
lodsw
|
|
mov cx, ax
|
|
lodsw
|
|
mov dx, ax
|
|
lodsw
|
|
mov bx, ax
|
|
lodsw
|
|
|
|
;
|
|
; now dx:cx is multipler, ax:bx=multiplicand
|
|
;
|
|
|
|
mov bp, ax ; bp:bx=multiplicand
|
|
mov ax, cx ; dx:ax=multiplier
|
|
|
|
MulDivFD6Pairs0:
|
|
|
|
or cx, dx
|
|
jz short MulDivFD6PairsZero ; zero content
|
|
|
|
mov cx, bx
|
|
or cx, bp
|
|
jz short MulDivFD6PairsZero ; zero content
|
|
|
|
MulDivFD6Pairs1:
|
|
|
|
xor cx, cx ; initialize sign to zero
|
|
or bp, bp
|
|
jns short MulDivFD6Pairs2
|
|
|
|
NEG32_FROMR16HL bp, bx
|
|
not cx ; flip the sign
|
|
|
|
MulDivFD6Pairs2:
|
|
|
|
or dx, dx
|
|
jns short MulDivFD6Pairs3
|
|
|
|
NEG32_FROMR16HL dx, ax
|
|
not cx
|
|
|
|
MulDivFD6Pairs3:
|
|
|
|
push si ; save pFD6Pairs
|
|
push cx ; save it
|
|
call U32MulU32_U64 ; dx:ax * bp:bx = dx:ax:bp:bx
|
|
pop cx ; restore sign indicator
|
|
pop si
|
|
jcxz short MulDivFD6PairsPos
|
|
|
|
MulDivFD6PairsNeg:
|
|
|
|
pop cx
|
|
sub cx, bx
|
|
mov bx, cx
|
|
pop cx
|
|
sbb cx, bp
|
|
mov bp, cx
|
|
pop cx
|
|
sbb cx, ax
|
|
mov ax, cx
|
|
pop cx
|
|
sbb cx, dx
|
|
mov dx, cx
|
|
jmp short MulDivFD6PairsLoop2
|
|
|
|
MulDivFD6PairsZero:
|
|
|
|
pop bx
|
|
pop bp
|
|
pop ax
|
|
pop dx
|
|
jmp short MulDivFD6PairsLoop2
|
|
|
|
MulDivFD6PairsPos:
|
|
|
|
pop cx
|
|
add bx, cx
|
|
pop cx
|
|
adc bp, cx
|
|
pop cx
|
|
adc ax, cx
|
|
pop cx
|
|
adc dx, cx
|
|
|
|
MulDivFD6PairsLoop2:
|
|
|
|
pop cx
|
|
dec cx
|
|
jz short MulDivFD6Pairs4
|
|
jmp MulDivFD6PairsLoop
|
|
|
|
MulDivFD6Pairs4: ; dx:ax:bp:bx=number
|
|
|
|
xor cx, cx
|
|
or dx, dx
|
|
jns short MulDivFD6Pairs5
|
|
|
|
not bx
|
|
not bp
|
|
not ax
|
|
not dx
|
|
add bx, 1
|
|
adc bp, cx
|
|
adc ax, cx
|
|
adc dx, cx
|
|
not cx ; flip sign
|
|
|
|
MulDivFD6Pairs5:
|
|
|
|
pop di ; get divisor si:di
|
|
pop si
|
|
|
|
or si, si ; a negative number ?
|
|
jns short MulDivFD6Pair6
|
|
not cx
|
|
|
|
MulDivFD6Pair6:
|
|
|
|
push cx ; save sign indicator
|
|
mov cx, si
|
|
or cx, si ; if divisor = 0, then divide by 1.0
|
|
jz short MulDivFD6Pair7
|
|
|
|
call U64DivU32_U32 ; dx:ax:bp:bx / si:di = dx:ax/bx:cx
|
|
|
|
;
|
|
; need to round up (if remainder (bx:cx * 2) >= si:di
|
|
;
|
|
|
|
add cx, cx
|
|
adc bx, bx
|
|
sub cx, di
|
|
sbb bx, si
|
|
cmc
|
|
adc ax, 0
|
|
adc dx, 0
|
|
jmp short MulDivFD6Pairs8
|
|
|
|
MulDivFD6Pairs7:
|
|
|
|
call U64Div1000000 ; dx:ax:bp:bx / 1000000 = dx:ax
|
|
|
|
MulDivFD6Pairs8:
|
|
|
|
pop cx ; restore sign indicator
|
|
|
|
S32_FROMR16HL_SR16 dx, ax, cx
|
|
|
|
MulDivFD6Pairs9:
|
|
|
|
@EXIT
|
|
|
|
ELSE
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
@ENTER _SI _DI
|
|
|
|
mov _SI, DPTR pMulDivPair
|
|
xor _AX, _AX ; clear return
|
|
lodsw ; get count
|
|
or ax, ax ; if count=0, then return 0.0
|
|
jz short MulDivFD6PairsNone
|
|
|
|
mov _CX, _AX ; _CX=count
|
|
|
|
lodsw ; get divisor present flag
|
|
or ax, ax ; if none then divisor=0
|
|
jz short MulDivFD6PairStart
|
|
|
|
mov _AX, DPTR [_SI]
|
|
|
|
MulDivFD6PairStart:
|
|
|
|
push _AX ; save divisor
|
|
add _SI, 4 ; jump to first pair
|
|
|
|
xor _BX, _BX
|
|
xor _DI, _DI ; _BX:_DI is the sum = initialize to 0
|
|
|
|
MulDivFD6PairsLoop:
|
|
|
|
lodsd ; get multiplicand
|
|
mov _DX, _AX
|
|
lodsd
|
|
or _AX, _AX ; see if zero, if zero do nothing
|
|
jz short MulDivFD6PairsLoop2
|
|
or _DX, _DX
|
|
jz short MulDivFD6PairsLoop2
|
|
imul _DX ; _DX:_AX = result
|
|
|
|
MulDivFD6Pairs1:
|
|
|
|
add _DI, _AX
|
|
adc _BX, _DX
|
|
|
|
MulDivFD6PairsLoop2:
|
|
|
|
loop MulDivFD6PairsLoop
|
|
|
|
MulDivFD6Pairs2:
|
|
|
|
mov _AX, _DI
|
|
mov _DX, _BX
|
|
|
|
shl _BX, 1
|
|
sbb _BX, _BX ; _BX=sign indicator
|
|
|
|
S64_FROMR32HL_SR32 _DX, _AX, _BX ; flip the _DX, _AX according the sign
|
|
|
|
mov _DI, FD6NUM_1_DW ; now _DX:_AX / _DI 1.0 (decimal)
|
|
|
|
pop _CX ; get divisor
|
|
jecxz short MulDivFD6Pairs3 ; divide by 1.0 if divisor=0.0
|
|
cmp _CX, _DI ; divisor=1.0?
|
|
jz short MulDivFD6Pairs3
|
|
|
|
mov _DI, _CX ; using new divisor
|
|
shl _CX, 1
|
|
sbb _CX, _CX ; _CX=sign indicator
|
|
xor _DI, _CX
|
|
sub _DI, _CX ; _DI=absolute divisor
|
|
xor _BX, _CX ; flip the final sign if any
|
|
|
|
MulDivFD6Pairs3:
|
|
|
|
cmp _DX, _DI ; will divison overflow?
|
|
jae short MulDivFD6PairsOverflow
|
|
|
|
div _DI ; edx=remainder, eax=quotient
|
|
|
|
shr _DI, 1 ; if remainder >= (divisor / 2) then
|
|
sub _DX, _DI ; round it up
|
|
cmc
|
|
adc _AX, 0 ; round it up
|
|
|
|
MulDivFD6PairsSign:
|
|
|
|
xor _AX, _BX ; do any sign if necessary
|
|
sub _AX, _BX
|
|
|
|
MulDivFD6Pairs4:
|
|
|
|
cdq ; convert to 64-bit
|
|
|
|
@EXIT
|
|
|
|
MulDivFD6PairsNone:
|
|
|
|
xor _AX, _AX
|
|
jmp short MulDivFD6Pairs4
|
|
|
|
MulDivFD6PairsOverflow:
|
|
|
|
mov _AX, 07fffffffh ; return maximum number
|
|
jmp short MulDivFD6PairsSign
|
|
|
|
ENDIF ; i8086 or i286
|
|
|
|
|
|
@END_PROC
|
|
|
|
|
|
|
|
|
|
SUBTTL DivFD6
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function divide two FD6 numbers (FIX decimal point decimal long
|
|
number, the LONG DECIMAL POINT SIX (FD6) is a number with lowest 6 digits
|
|
as fraction to the right of the decimal point), so like 1234567 = 1.234567,
|
|
the range for this data type is -2147.483647 to 2147.483647.
|
|
|
|
Arguments:
|
|
|
|
Dividend - a 32-bit FD6 dividend number.
|
|
|
|
Divisor - a 32-bit FD6 divisor number.
|
|
|
|
Return Value:
|
|
|
|
The return value is the 32-bit FD6 number which is round up from 7th
|
|
decimal points, there is no remainder returned.
|
|
|
|
NO ERROR returned, if divisor is zero the return value will be dividend, if
|
|
overflow happened, then maximum FD6 number will be returned (ie.
|
|
2147.483647)
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
@BEG_PROC DivFD6 <Dividend:DWORD, Divisor:DWORD>
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
@ENTER _SI _DI _BP ; save used registers
|
|
|
|
mov di, WPTR Divisor
|
|
mov si, WPTR Divisor + 2
|
|
mov ax, WPTR Dividend
|
|
mov dx, WPTR Dividend + 2
|
|
|
|
mov cx, si
|
|
or cx, di
|
|
jz short DivFD6_Divisor0
|
|
|
|
DivFD6_Chk1:
|
|
|
|
mov cx, dx
|
|
or cx, ax
|
|
jz short DivFD6_Done
|
|
|
|
DivFD6_Chk1: ; dx:ax=dividend, si:di=divisor
|
|
|
|
xor cx, cx
|
|
or si, si
|
|
jns short DivFD6_1
|
|
|
|
NEG32_FROMR16HL si, di
|
|
not cx
|
|
|
|
DivFD6_1: ; check if divided by 1.0 or -1.0
|
|
|
|
cmp si, FD6NUM_1_HW
|
|
jnz short DivFD6_1a
|
|
cmp di, FD6NUM_1_LW
|
|
jz short DivFD6_Sign ; exit with dx:ax and sign in cx
|
|
|
|
DivFD6_1a:
|
|
|
|
or dx, dx
|
|
jns short DivFD6_2
|
|
|
|
NEG32_FROMR16HL dx, ax
|
|
not cx
|
|
|
|
DivFD6_2:
|
|
|
|
cmp dx, si
|
|
jnz short DivFD6_3
|
|
cmp ax, di
|
|
jnz short DivFD6_3
|
|
|
|
mov dx, FD6NUM_1_HW
|
|
mov ax, FD6NUM_1_LW
|
|
jmp short DivFD6_Sign ; dx:ax=si:di, return 1.0 or -1.0
|
|
|
|
DivFD6_3:
|
|
|
|
push cx ; save sign
|
|
call u32Mul1000000 ; dx:ax * 0xf4240 = dx:ax:bp:bx
|
|
call U64DivU32_U32 ; dx:ax:bp:bx / si:di = dx:ax/bx:cx
|
|
|
|
;
|
|
; Check if we have 0.0000005 to round up, Divisor - (reminder * 2) >= 0
|
|
; that is.
|
|
;
|
|
|
|
sub di, cx ; Divisor - Remainder = X (si:di)
|
|
sbb si, bx
|
|
sub cx, di
|
|
sbb bx, si ; Remainder - X = U (bx:cx)
|
|
cmc
|
|
adc ax, 0 ; if (U >= 0) then round up
|
|
adc dx, 0
|
|
|
|
pop cx ; cx=sign
|
|
|
|
DivFD6_Sign:
|
|
|
|
S32_FROMR16HL_SR16 dx, ax cx
|
|
|
|
DivFD6_Done:
|
|
|
|
@EXIT
|
|
|
|
DivFD6_Divisor0:
|
|
|
|
inc ax
|
|
jmp short DivFD6_Chk0
|
|
|
|
|
|
ELSE ; assume i386 or up at here
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
@ENTER ; entering function
|
|
|
|
mov _AX, DPTR Divisor ; see if this guy is zero
|
|
cdq ; save dx sign
|
|
mov _BX, _DX ; _BX = sign
|
|
xor _AX, _DX ; take divisor as absolute number _AX
|
|
sub _AX, _DX ; zero ? DO NOT DESTROY ZERO FLAG
|
|
jz short DivFD6_Divisor0
|
|
|
|
DivFD6_1:
|
|
|
|
mov _CX, _AX ; save absolute divisor in _CX
|
|
mov _AX, DPTR Dividend ; _AX=Dividend, _CX=Divisor, _BX=Sign
|
|
cdq ; sign extended, saved the sign at here
|
|
xor _AX, _DX
|
|
sub _AX, _DX ; eax=absolute dividend now
|
|
jz short DivFD6_Done ; dividend = 0, return 0
|
|
xor _BX, _DX ; _BX=final sign only if _BX != _DX
|
|
|
|
;
|
|
; _AX=Dividend, _CX=Divisor, _BX = final sign indicator
|
|
;
|
|
|
|
mov _DX, FD6NUM_1_DW ; multiply dividend by 1.0 (decimal)
|
|
cmp _CX, _DX ; if divisor == 1.0 or -1.0 then exit
|
|
jz short DivFD6_Sign
|
|
|
|
xchg _AX, _DX ; _AX = 1.0, _DX=Dividend
|
|
cmp _DX, _CX
|
|
jz short DivFD6_Sign ; Divisor=Dividend, return 1.0 or -1.0
|
|
|
|
mul _DX ; edx:eax = 64-bit product
|
|
|
|
cmp _DX, _CX ; will division overflow ?
|
|
jae short DivFD6_Overflow
|
|
|
|
div _CX ; edx=remainder, eax=quotient
|
|
|
|
;
|
|
; Check if we have 0.0000005 to round up, Divisor - (reminder * 2) >= 0
|
|
; that is.
|
|
;
|
|
|
|
sub _CX, _DX ; divisor - remainder = X
|
|
sub _DX, _CX ; Remainder - X = U
|
|
cmc ; if U >= 0 then round up
|
|
adc _AX, 0
|
|
|
|
DivFD6_Sign:
|
|
|
|
xor _AX, _BX ; do any sign if necessary
|
|
sub _AX, _BX
|
|
cdq ; make it 64-bits
|
|
|
|
DivFD6_Done:
|
|
|
|
@EXIT ; exiting function
|
|
|
|
DivFD6_Overflow:
|
|
|
|
mov _AX, 07fffffffh ; return maximum number
|
|
jmp short DivFD6_Sign
|
|
|
|
DivFD6_Divisor0:
|
|
|
|
inc _AX
|
|
jmp short DivFD6_1
|
|
|
|
|
|
ENDIF ; i8086 or i286
|
|
|
|
|
|
@END_PROC
|
|
|
|
|
|
|
|
SUBTTL FD6DivL
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function divide a FD6 number by a LONG integer.
|
|
|
|
Arguments:
|
|
|
|
Dividend - a 32-bit FD6 dividend number.
|
|
|
|
Divisor - a 32-bit signed number.
|
|
|
|
Return Value:
|
|
|
|
The return value is the 32-bit FD6 number which is round up from 7th
|
|
decimal points, there is no remainder returned.
|
|
|
|
NO ERROR returned, if divisor is zero the return value will be dividend, if
|
|
overflow happened, then maximum FD6 number will be returned (ie.
|
|
2147.483647)
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
@BEG_PROC FD6DivL <Dividend:DWORD, Divisor:DWORD>
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
@ENTER _SI _DI _BP ; save used registers
|
|
|
|
mov di, WPTR Divisor
|
|
mov si, WPTR Divisor + 2
|
|
mov ax, WPTR Dividend
|
|
mov dx, WPTR Dividend + 2
|
|
|
|
mov cx, si
|
|
or cx, di
|
|
jz short FD6DivL_Done
|
|
mov cx, dx
|
|
or cx, ax
|
|
jz short FD6DivL_Done
|
|
|
|
FD6DivL_Chk1: ; dx:ax=dividend, si:di=divisor
|
|
|
|
xor cx, cx
|
|
or si, si
|
|
jns short FD6DivL_1
|
|
|
|
NEG32_FROMR16HL si, di
|
|
not cx
|
|
|
|
FD6DivL_1: ; check if divided by 1.0 or -1.0
|
|
|
|
or dx, dx
|
|
jns short FD6DivL_2
|
|
|
|
NEG32_FROMR16HL dx, ax
|
|
not cx
|
|
|
|
FD6DivL_2:
|
|
|
|
push cx ; save sign
|
|
call U32DivU32_U32 ; dx:ax / si:di = dx:ax / bx:cx
|
|
jz short FD6DivL_3 ; zero flag set if no remainder
|
|
|
|
;
|
|
; Check if we have 0.0000005 to round up, Divisor - (reminder * 2) >= 0
|
|
; that is.
|
|
;
|
|
|
|
sub di, cx ; Divisor - Remainder = X (si:di)
|
|
sbb si, bx
|
|
sub cx, di
|
|
sbb bx, si ; Remainder - X = U (bx:cx)
|
|
cmc
|
|
adc ax, 0 ; if (U >= 0) then round up
|
|
adc dx, 0
|
|
|
|
FD6DivL_3:
|
|
|
|
pop cx ; cx=sign
|
|
|
|
FD6DivL_Sign:
|
|
|
|
S32_FROMR16HL_SR16 dx, ax cx
|
|
|
|
FD6DivL_Done:
|
|
|
|
@EXIT
|
|
|
|
ELSE ; assume i386 or up at here
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
@ENTER ; entering function
|
|
|
|
mov _AX, DPTR Divisor ; see if this guy is zero
|
|
cdq ; save dx sign
|
|
mov _BX, _DX ; _BX = sign
|
|
xor _AX, _DX ; take divisor as absolute number _AX
|
|
sub _AX, _DX ; zero ? DO NOT DESTROY ZERO FLAG
|
|
mov _CX, _AX ; save absolute divisor in _CX
|
|
mov _AX, DPTR Dividend ; _AX=Dividend, _CX=Divisor, _BX=Sign
|
|
jz short FD6DivL_Done ; If Divisor=0, return Dividend
|
|
|
|
cdq ; sign extended, saved the sign at here
|
|
xor _AX, _DX
|
|
sub _AX, _DX ; eax=absolute dividend now
|
|
jz short FD6DivL_Done ; dividend = 0, return 0
|
|
xor _BX, _DX ; _BX=final sign only if _BX != _DX
|
|
|
|
;
|
|
; _AX=Dividend, _CX=Divisor, _BX = final sign indicator
|
|
;
|
|
|
|
xor _DX, _DX ; 0:_AX / _CX
|
|
div _CX ; _DX=remainder, _AX=quotient
|
|
|
|
;
|
|
; Check if we have 0.0000005 to round up, Divisor - (reminder * 2) >= 0
|
|
; that is.
|
|
;
|
|
|
|
sub _CX, _DX ; divisor - remainder = X
|
|
sub _DX, _CX ; Remainder - X = U
|
|
cmc ; if U >= 0 then round up
|
|
adc _AX, 0
|
|
|
|
FD6DivL_Sign:
|
|
|
|
xor _AX, _BX ; do any sign if necessary
|
|
sub _AX, _BX
|
|
cdq ; make it 64-bits
|
|
|
|
FD6DivL_Done:
|
|
|
|
@EXIT ; exiting function
|
|
|
|
ENDIF ; i8086 or i286
|
|
|
|
|
|
@END_PROC
|
|
|
|
|
|
|
|
;=============================================================================
|
|
|
|
IF 0
|
|
|
|
SUBTTL FD6IntFrac
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function is used to extract integer/fraction portion of the FIX
|
|
decimal point decimal long number, the LONG DECIMAL POINT SIX (FD6)
|
|
is a number with lowest 6 digits as fraction to the right of the decimal
|
|
point), so like 1234567 = 1.234567, the range for this data type is
|
|
-2147.483647 - 2147.483647.
|
|
|
|
Arguments:
|
|
|
|
Number - the FD6 number which will be break down as integer portion
|
|
and fraction portion. if -1.123456 is passed then return
|
|
will be INTEGER = -1 (16-bit extended to 32-bit), and
|
|
FRACTION = -123456 (ie. -0.123456)
|
|
|
|
pFrac - pointer to the DWORD (32-bit) to store the fraction portion
|
|
of the FD6 (Num) number.
|
|
|
|
Return Value:
|
|
|
|
The return value is the sign 16-bit integer of the number passed in, it
|
|
will be extented to 32-bit for caller's convinent.
|
|
|
|
Since the integer portion for the FD6 only -2147 to 2147 it only need
|
|
16-bit number to retreat.
|
|
|
|
The fraction portion is stored at pointer points by the pFrac parameter.
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
|
|
@BEG_PROC FD6IntFrac <Number:DWORD, pFrac:DWORD>
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
|
|
@ENTER ; enter function
|
|
|
|
mov ax, WPTR Number
|
|
mov dx, WPTR Number + 2
|
|
|
|
mov bx, dx
|
|
shl bx, 1
|
|
sbb bx, bx ; bx=0xffff if dx:ax is negative
|
|
|
|
S32_FROMR16HL_SR16 dx, ax, bx
|
|
|
|
mov bl, al ;
|
|
and bl, 0fh ; save lowest 4 bits of dividend in BL
|
|
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
|
|
mov cx, 0f424h
|
|
div cx ; dx:bl=remainder, ax=quotient
|
|
|
|
rol dx, 1 ; rotate the dx left 4 times to put
|
|
rol dx, 1 ; saved lowest 4 remainder bits back
|
|
rol dx, 1
|
|
rol dx, 1
|
|
mov cx, 0fh
|
|
and cx, dx ; cx=high portion of remainder
|
|
xor dx, cx ; clear dx low 4 bits
|
|
or dl, bl ; move low 4 bits in, cx:dx=remainder
|
|
;
|
|
mov bl, bh
|
|
xor ax, bx
|
|
sub ax, bx
|
|
|
|
S32_FROMR16HL_SR16 dx, cx, bx
|
|
|
|
les bx, pFrac
|
|
mov WPTR es:[bx], dx ; save fraction
|
|
mov WPTR es:[bx+2], cx
|
|
cwd ; dx:ax=quotient
|
|
|
|
@EXIT
|
|
|
|
ELSE ; assume i386 or up at here
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
@ENTER ; entering function
|
|
|
|
mov _AX, DPTR Number ; load the 32-bit number
|
|
cdq ; extended to 64-bits
|
|
mov _CX, 1000000 ; divisor = 1000000 decimal
|
|
idiv _CX ; edx=r, eax=q
|
|
mov _BX, DPTR pFrac
|
|
mov DPTR [_BX], _DX ; save remainder
|
|
cdq ; _AX=quotient, now sign extended
|
|
|
|
@EXIT ; exiting function
|
|
|
|
ENDIF ; i8086 or i286
|
|
|
|
|
|
@END_PROC
|
|
|
|
|
|
ENDIF
|
|
|
|
;=============================================================================
|
|
|
|
|
|
|
|
SUBTTL FractionToMantissa
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function convert a fraction FD6 number to the logarithm mantissa
|
|
with correction data.
|
|
|
|
Arguments:
|
|
|
|
Fraction - the fraction number after decimal place, because
|
|
we have mantissa table up to two decimal places, the
|
|
correction is necessary because logarithm numbers are
|
|
no linear. The number is range from 0.000000-0.999999
|
|
|
|
CorrectData - The correction data which from MantissaCorrectData[]
|
|
|
|
|
|
Return Value:
|
|
|
|
No error returned, the return value is the Mantissa value for the fraction
|
|
passed in.
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
@BEG_PROC FractionToMantissa <Fraction:DWORD, CorrectData:DWORD>
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
|
|
@ENTER _SI _DI _BP ; save used registers
|
|
|
|
mov ax, WPTR Fraction
|
|
mov dx, WPTR Fraction + 2 ; 0-999999 decimal
|
|
mov si, ax
|
|
and si, 1 ; 1 bit remainder
|
|
shr dx, 1 ; divide by (100000/2) so dividend
|
|
rcr ax, 1 ; must shift right by 1
|
|
mov cx, 0c350h ; 100000 / 2
|
|
div cx ; dx=remainder, ax=quotient
|
|
mov cx, ax ; cx=0-9, quotient
|
|
inc cx ; make it 1-10
|
|
mov di, dx ; remainder = (remainder*2) + save
|
|
shr si, 1 ; check the lowest remainder bit
|
|
adc di, di ; put it into final remainder
|
|
adc si, si ; si = 0/1
|
|
|
|
;
|
|
; starting correction
|
|
;
|
|
; <---High Word---> <----Low Word--->
|
|
; Bit# 3 2 1 0
|
|
; 10987654 32109876 54321098 76543210
|
|
; | | | | | | | || | |
|
|
; | | | | | | | || | +-- x.000 Minimum Difference
|
|
; | | | | | | | || +----- x.001-x.002 (0-7) Correct 1
|
|
; | | | | | | | |+-------- x.000-x.001 (0-7) Correct 2
|
|
; | | | | | | | +--------- x.009-y.000 (0-1) Correct 10
|
|
; | | | | | | +------------- x.009-y.000 (0-7) Correct 3
|
|
; | | | | | +---------------- x.008-x.009 (0-7) Correct 4
|
|
; | | | | +------------------ x.007-x.008 (0-3) Correct 5
|
|
; | | | +--------------------- x.006-x.007 (0-3) Correct 6
|
|
; | | +----------------------- x.005-x.006 (0-3) Correct 7
|
|
; | +------------------------- x.004-x.005 (0-3) Correct 8
|
|
; +--------------------------- x.003-x.004 (0-3) Correct 9
|
|
;
|
|
|
|
mov ax, WPTR CorrectData
|
|
mov dx, WPTR CorrectData + 2 ; dx:ax=correct data
|
|
|
|
mov bp, ax ; first get the DifMin = 9 bits
|
|
and bp, 01ffh ; bp=base
|
|
xor bx, bx ; different accumulator=base
|
|
|
|
Frac2Mant1:
|
|
|
|
mov ch, ah
|
|
mov ax, 7
|
|
shr ch, 1
|
|
and al, ch
|
|
dec cl
|
|
jz short Frac2MantGetFrac ; bx=total, next dif=ax
|
|
add bx, ax
|
|
add bx, bp
|
|
|
|
Frac2Mant2:
|
|
|
|
shr ch, 1 ; shift away correction 1
|
|
shr ch, 1
|
|
shr ch, 1 ; ch bit 3 is the correction 10
|
|
mov al, 7
|
|
and al, ch
|
|
dec cl
|
|
jz short Frac2MantGetFrac ;
|
|
add bx, ax ; correct 2
|
|
add bx, bp
|
|
|
|
Frac2Mant3:
|
|
|
|
mov ax, 7
|
|
and ax, dx
|
|
dec cl ; correct 3
|
|
jz short Frac2MantGetFrac
|
|
add bx, ax
|
|
add bx, bp
|
|
|
|
Frac2Mant4:
|
|
|
|
mov ax, 7
|
|
cmp al, ch ; if bit 3 of ch is on then carry
|
|
rcr dx, 1 ; we actually move that bit into
|
|
shr dx, 1 ; bit 15 of dx
|
|
shr dx, 1 ; shift away correction 3
|
|
and ax, dx
|
|
dec cl
|
|
jz short Frac2MantGetFrac
|
|
|
|
shr dx, 1 ; shift away correction 4
|
|
mov ch, 3 ; this is the mask, all 2 bits now
|
|
|
|
Frac2Mant5_10:
|
|
|
|
add bx, ax
|
|
add bx, bp
|
|
shr dx, 1
|
|
shr dx, 1
|
|
mov al, ch
|
|
and ax, dx
|
|
dec cl
|
|
jnz short Frac2Mant5_10
|
|
|
|
Frac2MantGetFrac:
|
|
|
|
add bp, ax ; add minimum diff. to next table
|
|
|
|
;
|
|
; Now, bx=Minimum x.00x,
|
|
; bp=different to the next mantissa x.000x + 0.0001
|
|
; si:di=fraction ratio (0.000000 - 0.099999)
|
|
;
|
|
; Total Dif = bx + ((bp * si:di) / 100000)
|
|
;
|
|
; si:di * ax will never greater than 32-bit because (si:di < 100000) and
|
|
; BP < (2^9 = 512)
|
|
;
|
|
|
|
mov ax, si
|
|
or ax, di
|
|
jz short Frac2MantDoneFrac
|
|
mov ax, si ; if si=0, then no 'mul si'
|
|
or ax, ax
|
|
jz short Frac2MantDoneHF
|
|
mov ax, bp ; si:di
|
|
mul si ; * ax
|
|
|
|
Frac2MantDoneHF:
|
|
|
|
xchg bp, ax ; ---------------
|
|
mul di ; dx:ax
|
|
add dx, bp ; bp
|
|
mov cx, 0c350h ; ----------------
|
|
add ax, cx ; dx:ax
|
|
adc dx, 0 ; now round up
|
|
shr dx, 1 ; divide by (100000/2) so dividend
|
|
rcr ax, 1 ; must also right shift by 1
|
|
div cx ; ax=qotient, ignored the remainder
|
|
|
|
Frac2MantDoneFrac:
|
|
|
|
xor dx, dx ; using dx:ax=final number
|
|
add ax, bx
|
|
adc dx, dx ; dx:ax=fraction mantissa number
|
|
|
|
@EXIT
|
|
|
|
ELSE
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
@ENTER _SI _DI _BP ; entering function
|
|
|
|
mov _AX, DPTR Fraction
|
|
cdq
|
|
mov _CX, 100000
|
|
div _CX ; _DX=r, _AX=q
|
|
mov _CX, _AX ; _CX=q+1
|
|
inc _CX ; _CX= 1-10
|
|
|
|
;
|
|
; starting correction
|
|
;
|
|
; <---High Word---> <----Low Word--->
|
|
; Bit# 3 2 1 0
|
|
; 10987654 32109876 54321098 76543210
|
|
; | | | | | | | || | |
|
|
; | | | | | | | || | +-- x.000 Minimum Difference
|
|
; | | | | | | | || +----- x.001-x.002 (0-7) Correct 1
|
|
; | | | | | | | |+-------- x.000-x.001 (0-7) Correct 2
|
|
; | | | | | | | +--------- x.009-y.000 (0-1) Correct 10
|
|
; | | | | | | +------------- x.009-y.000 (0-7) Correct 3
|
|
; | | | | | +---------------- x.008-x.009 (0-7) Correct 4
|
|
; | | | | +------------------ x.007-x.008 (0-3) Correct 5
|
|
; | | | +--------------------- x.006-x.007 (0-3) Correct 6
|
|
; | | +----------------------- x.005-x.006 (0-3) Correct 7
|
|
; | +------------------------- x.004-x.005 (0-3) Correct 8
|
|
; +--------------------------- x.003-x.004 (0-3) Correct 9
|
|
;
|
|
|
|
mov _DI, DPTR CorrectData ; _AX=correct data
|
|
mov _BP, _DI
|
|
and _BP, 01ffh ; _SI = 9 bit of the DifMin
|
|
mov _SI, 7
|
|
mov bx, di
|
|
shl bx, 1 ; get the correction 10
|
|
rcr _DI, 1 ; put into bit 31
|
|
shr _DI, 8
|
|
xor _BX, _BX
|
|
|
|
Frac2Mant1:
|
|
|
|
mov _AX, _SI
|
|
and _AX, _DI
|
|
dec cl
|
|
jz short Frac2MantGetFrac
|
|
add _BX, _AX
|
|
add _BX, _BP
|
|
|
|
Frac2Mant2:
|
|
|
|
shr _DI, 3
|
|
mov _AX, _SI
|
|
and _AX, _DI
|
|
dec cl
|
|
jz short Frac2MantGetFrac ;
|
|
add _BX, _AX ; correct 2
|
|
add _BX, _BP
|
|
|
|
Frac2Mant3:
|
|
|
|
shr _DI, 4 ; shift away correction 2/10
|
|
mov _AX, _SI
|
|
and _AX, _DI
|
|
dec cl ; correct 3
|
|
jz short Frac2MantGetFrac ;
|
|
add _BX, _AX ;
|
|
add _BX, _BP
|
|
|
|
Frac2Mant4:
|
|
|
|
shr _DI, 3
|
|
mov _AX, _SI
|
|
and _AX, _DI
|
|
dec cl ; correct 4
|
|
jz short Frac2MantGetFrac ;
|
|
shr _DI, 1 ; pre-shift, remainding all 2 bits
|
|
mov _SI, 3
|
|
|
|
Frac2Mant5_10:
|
|
|
|
add _BX, _AX
|
|
add _BX, _BP
|
|
shr _DI, 2
|
|
mov _AX, _SI
|
|
and _AX, _DI
|
|
dec cl
|
|
jnz short Frac2Mant5_10
|
|
|
|
Frac2MantGetFrac:
|
|
|
|
add _BP, _AX
|
|
|
|
;
|
|
; Now, _BX=Minimum x.00x,
|
|
; _BP=different to the next mantissa x.000x + 0.0001
|
|
; _DX=fraction ratio (0.000000 - 0.099999)
|
|
;
|
|
; Total Dif = _BX + ((_BP * _DX) / 100000)
|
|
;
|
|
; _BP * _DX will never greater than 32-bit because (_DX < 100000) and
|
|
; _BP < (2^9 = 512)
|
|
;
|
|
|
|
mov _AX, _BX
|
|
or _DX, _DX ; zero fraction?
|
|
jz short Frac2MantDoneFrac
|
|
mov _AX, _BP
|
|
mul _DX ; _DX:_AX=products
|
|
add _AX, 50000 ; round up
|
|
adc _DX, 0
|
|
mov _CX, 100000
|
|
div _CX ; _AX=quotient
|
|
add _AX, _BX
|
|
|
|
Frac2MantDoneFrac:
|
|
|
|
cdq ; _DX:_AX=final number
|
|
|
|
@EXIT ; exiting function
|
|
|
|
ENDIF ; i8086 or i286
|
|
|
|
|
|
@END_PROC
|
|
|
|
|
|
|
|
FD6P1ToP9 dd 100000
|
|
dd 200000
|
|
dd 300000
|
|
dd 400000
|
|
dd 500000
|
|
dd 600000
|
|
dd 700000
|
|
dd 800000
|
|
dd 900000
|
|
dd 1000000
|
|
|
|
|
|
|
|
SUBTTL MantissaToFraction
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function take mantissa number and convert it to the decimal fraction
|
|
in FD6 format.
|
|
|
|
Arguments:
|
|
|
|
Mantissa - the mantissa values which will converted to the the
|
|
fraction number.
|
|
|
|
CorrectData - The correction data which from MantissaCorrectData[]
|
|
|
|
Return Value:
|
|
|
|
No error returned, the return value is the fraction value for the mantissa
|
|
passed in, it range from 0.000000 - 1.000000
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
@BEG_PROC MantissaToFraction <Mantissa:DWORD, CorrectData:DWORD>
|
|
|
|
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
|
|
@ENTER _SI _DI _BP ; saved used registers
|
|
|
|
;
|
|
; starting correction
|
|
;
|
|
; <---High Word---> <----Low Word--->
|
|
; Bit# 3 2 1 0
|
|
; 10987654 32109876 54321098 76543210
|
|
; | | | | | | | || | |
|
|
; | | | | | | | || | +-- x.000 Minimum Difference
|
|
; | | | | | | | || +----- x.001-x.002 (0-7) Correct 1
|
|
; | | | | | | | |+-------- x.000-x.001 (0-7) Correct 2
|
|
; | | | | | | | +--------- x.009-y.000 (0-1) Correct 10
|
|
; | | | | | | +------------- x.009-y.000 (0-7) Correct 3
|
|
; | | | | | +---------------- x.008-x.009 (0-7) Correct 4
|
|
; | | | | +------------------ x.007-x.008 (0-3) Correct 5
|
|
; | | | +--------------------- x.006-x.007 (0-3) Correct 6
|
|
; | | +----------------------- x.005-x.006 (0-3) Correct 7
|
|
; | +------------------------- x.004-x.005 (0-3) Correct 8
|
|
; +--------------------------- x.003-x.004 (0-3) Correct 9
|
|
;
|
|
|
|
mov ax, WPTR Mantissa ; only 16-bit needed
|
|
mov cx, WPTR CorrectData
|
|
mov dx, WPTR CorrectData + 2 ; dx:cx=correct data
|
|
|
|
mov bp, cx ; first get the DifMin = 9 bits
|
|
and bp, 01ffh ; bp=base
|
|
xor si, si ; si=fraction index
|
|
mov di, 7
|
|
|
|
Mant2Frac1:
|
|
|
|
mov bh, ch
|
|
shr bh, 1
|
|
mov cx, di
|
|
and cl, bh
|
|
inc si ; increase the fraction index
|
|
add cx, bp ; cx=range
|
|
sub ax, cx ; ax=mantissa
|
|
jle short Mant2FracGetFrac
|
|
|
|
Mant2Frac2:
|
|
|
|
shr bh, 1 ; shift away correction 1
|
|
shr bh, 1
|
|
shr bh, 1 ; bh bit 3 is the correction 10
|
|
mov cx, di
|
|
and cl, bh
|
|
inc si ; increase the fraction index
|
|
add cx, bp ; cx=range
|
|
sub ax, cx ; ax=mantissa
|
|
jle short Mant2FracGetFrac
|
|
|
|
Mant2Frac3:
|
|
|
|
mov cx, di
|
|
and cx, dx
|
|
inc si ; increase the fraction index
|
|
add cx, bp ; cx=range
|
|
sub ax, cx ; ax=mantissa
|
|
jle short Mant2FracGetFrac
|
|
|
|
Mant2Frac4:
|
|
|
|
mov cx, di
|
|
cmp cl, bh ; if bit 3 of bh is on then carry
|
|
rcr dx, 1 ; we actually move that bit into
|
|
shr dx, 1 ; bit 15 of dx
|
|
shr dx, 1 ; shift away correction 3
|
|
and cx, dx
|
|
inc si ; increase the fraction index
|
|
add cx, bp ; cx=range
|
|
sub ax, cx ; ax=mantissa
|
|
jle short Mant2FracGetFrac
|
|
|
|
shr dx, 1 ; shift away correction 4
|
|
mov di, 3 ; this is the mask, all 2 bits now
|
|
|
|
Mant2Frac5_10:
|
|
|
|
shr dx, 1
|
|
shr dx, 1
|
|
mov cx, di
|
|
and cx, dx
|
|
inc si
|
|
add cx, bp ; cx=range
|
|
sub ax, cx ; ax=mantissa
|
|
jg short Mant2Frac5_10
|
|
|
|
Mant2FracGetFrac:
|
|
|
|
;
|
|
; si = fraction index of 000000 - 900000 (0-9)
|
|
; cx = range,
|
|
; ax = mantissa, if (ax=0) then si=frac else if (ax<0) then add range back
|
|
;
|
|
; Final Frac = (si * 1000000) + (((ax * 100000) + cx / 2) / cx)
|
|
;
|
|
|
|
mov dx, 0
|
|
jz short Mant2FracGetFracH ; si=fraction index
|
|
|
|
add ax, cx ; move it back since negative
|
|
dec si ; move the index back by one
|
|
mov dx, 0c350h ; 100000 = (50000 * 2)
|
|
mul dx ; dx:ax= ax * 50000 of the mantissa
|
|
add ax, ax
|
|
adc dx, dx ; dx:ax = ax * 100000
|
|
|
|
xor di, di
|
|
cmp dx, cx
|
|
jb short Mant2FracDiv2
|
|
|
|
mov di, ax ; save dividend L
|
|
mov ax, dx
|
|
xor dx, dx
|
|
div cx ; 0:ax / bx, dx=r, ax=q
|
|
xchg di, ax ; dx:ax=remainder, di=q
|
|
|
|
Mant2FracDiv2:
|
|
|
|
div cx ; dx=remainder, di:ax=q
|
|
|
|
add dx, dx ; to round up, check if
|
|
sub dx, cx ; (remainder * 2) > divisor, if yes
|
|
mov dx, 0
|
|
cmc ; then increase the qoutient by 1
|
|
adc ax, dx
|
|
adc dx, di ; dx:ax=((ax*100000) + cx/2) / cx)
|
|
|
|
Mant2FracGetFracH:
|
|
|
|
dec si
|
|
js short Mant2FracDone
|
|
add si, si ; 4 bytes alignment
|
|
add si, si
|
|
add ax, WORD PTR cs:FD6P1ToP9[si]
|
|
adc dx, WORD PTR cs:FD6P1ToP9[si+2]
|
|
|
|
Mant2FracDone:
|
|
|
|
@EXIT
|
|
|
|
ELSE
|
|
|
|
;*************************************************************************
|
|
; for i386 or upward compatble
|
|
;*************************************************************************
|
|
|
|
@ENTER _SI _DI ; entering function
|
|
|
|
;
|
|
; starting correction
|
|
;
|
|
; <---High Word---> <----Low Word--->
|
|
; Bit# 3 2 1 0
|
|
; 10987654 32109876 54321098 76543210
|
|
; | | | | | | | || | |
|
|
; | | | | | | | || | +-- x.000 Minimum Difference
|
|
; | | | | | | | || +----- x.001-x.002 (0-7) Correct 1
|
|
; | | | | | | | |+-------- x.000-x.001 (0-7) Correct 2
|
|
; | | | | | | | +--------- x.009-y.000 (0-1) Correct 10
|
|
; | | | | | | +------------- x.009-y.000 (0-7) Correct 3
|
|
; | | | | | +---------------- x.008-x.009 (0-7) Correct 4
|
|
; | | | | +------------------ x.007-x.008 (0-3) Correct 5
|
|
; | | | +--------------------- x.006-x.007 (0-3) Correct 6
|
|
; | | +----------------------- x.005-x.006 (0-3) Correct 7
|
|
; | +------------------------- x.004-x.005 (0-3) Correct 8
|
|
; +--------------------------- x.003-x.004 (0-3) Correct 9
|
|
;
|
|
|
|
movzx _AX, WPTR Mantissa ; only 16-bit needed
|
|
mov _DX, DPTR CorrectData ; _DX=correct data
|
|
mov _CX, _DX ; first get the DifMin = 9 bits
|
|
and _CX, 01ffh ; _CX=base
|
|
mov bx, dx ; move correction 10 (1 bit) to
|
|
shl bx, 1 ; _DX bit 31
|
|
rcr _DX, 1
|
|
shr _DX, 8 ; shift out rest of the bits
|
|
xor _BX, _BX ; _BX=fraction count
|
|
mov _SI, 7 ; si=mask
|
|
|
|
Mant2Frac1:
|
|
|
|
mov _DI, _SI ; get mask
|
|
and _DI, _DX ; _DI=current correction 1
|
|
inc _BX ; increase the fraction index
|
|
add _DI, _CX ; _DI=range to next
|
|
sub _AX, _DI ; substract the mantissa from it
|
|
jle short Mant2FracGetFrac
|
|
|
|
Mant2Frac2:
|
|
|
|
shr _DX, 3 ; shift away correction 1
|
|
mov _DI, _SI
|
|
and _DI, _DX
|
|
inc _BX ; increase the fraction index
|
|
add _DI, _CX ; _DI=range to next
|
|
sub _AX, _DI ; substract the mantissa from it
|
|
jle short Mant2FracGetFrac
|
|
|
|
Mant2Frac3:
|
|
|
|
shr _DX, 4 ; shift away correction 2/10
|
|
mov _DI, _SI
|
|
and _DI, _DX
|
|
inc _BX ; increase the fraction index
|
|
add _DI, _CX ; _DI=range to next
|
|
sub _AX, _DI ; substract the mantissa from it
|
|
jle short Mant2FracGetFrac
|
|
|
|
Mant2Frac4:
|
|
|
|
shr _DX, 3 ; shift away correction 3
|
|
mov _DI, _SI
|
|
and _DI, _DX
|
|
inc _BX ; increase the fraction index
|
|
add _DI, _CX ; _DI=range to next
|
|
sub _AX, _DI ; substract the mantissa from it
|
|
jle short Mant2FracGetFrac
|
|
|
|
mov _SI, 3 ; all the rest are 2 bits
|
|
shr _DX, 1 ; pre-shift 1 bit for correction 4
|
|
|
|
Mant2Frac5_10:
|
|
|
|
shr _DX, 2
|
|
mov _DI, _SI
|
|
and _DI, _DX
|
|
inc _BX
|
|
add _DI, _CX
|
|
sub _AX, _DI
|
|
jg short Mant2Frac5_10
|
|
|
|
Mant2FracGetFrac:
|
|
|
|
;
|
|
; _BX = fraction index of 000000 - 900000 (0-9)
|
|
; _DI = range,
|
|
; _AX = mantissa, if (_AX=0) then _BX=frac
|
|
; else if (_AX<0) then add range back
|
|
;
|
|
; Final Frac = (_BX * 1000000) + (((_AX * 100000) + _DI / 2) / _DI)
|
|
;
|
|
|
|
or _AX, _AX
|
|
jz short Mant2FracGetFracH ; BX=fraction index
|
|
add _AX, _DI ; _AX is negative, move it back
|
|
dec _BX ; by 1 step
|
|
mov _CX, 100000
|
|
mul _CX ; _DX:_AX=products
|
|
mov _CX, _DI
|
|
shr _CX, 1 ; round up
|
|
add _AX, _CX
|
|
adc _DX, 0
|
|
div _DI ; _DX=r, _AX=q
|
|
|
|
Mant2FracGetFracH:
|
|
|
|
dec _BX ; see if alrady 0
|
|
js short Mant2FracDone
|
|
add _AX, DPTR cs:FD6P1ToP9[_BX * 4] ; 4 bytes alignment
|
|
|
|
Mant2FracDone:
|
|
|
|
cdq ; _AX --> _DX:_AX
|
|
|
|
@EXIT ; exiting function
|
|
|
|
ENDIF ; i8086 or i286
|
|
|
|
|
|
@END_PROC
|
|
|
|
|
|
|
|
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
;@ Following codes only for 8086/80286, and all functions are used for @
|
|
;@ internally @
|
|
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
|
|
|
|
IF i8086 OR i286 ; lots of works for this kind of CPU
|
|
|
|
|
|
SUBTTL U64Div1000000
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function divide a 64-bit number by 1000000 (decimal), this function
|
|
only assembly under 8086/80286 cpu, for 80386 and up it will use in line
|
|
code to do divison
|
|
|
|
Arguments:
|
|
|
|
dx:ax:bp:bx - dividend
|
|
|
|
Return Value:
|
|
|
|
dx:ax = round up quotient (dx:ax:bp:bx / 1000000 decimal)
|
|
if dx:ax = 0x7fff:ffff then an overflow has been occurred.
|
|
|
|
bp:bx registers are destroyed.
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
PUBLIC U64Div1000000
|
|
|
|
U64Div1000000 label near
|
|
|
|
;
|
|
; dx:ax:bp:bx / FD6NUM_1_DW (0f4240h) --> dx:ax=round up quotient
|
|
; registers bp/bx are destroyed
|
|
;
|
|
; dx:ax:bp:bx / FD6NUM_1_DW (0f4240h) = (dx:ax:bp:bx >> 4)/f424h)
|
|
; = remainder << 4
|
|
;
|
|
|
|
add bx, 0a120h ; 0f4240h / 2 = 7a120h
|
|
adc bp, 7
|
|
adc ax, 0
|
|
adc dx, 0 ; round up
|
|
|
|
; shift the dividend right by 4 (64 bits shifts)
|
|
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
rcr bp, 1
|
|
rcr bx, 1
|
|
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
rcr bp, 1
|
|
rcr bx, 1
|
|
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
rcr bp, 1
|
|
rcr bx, 1
|
|
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
rcr bp, 1
|
|
rcr bx, 1
|
|
|
|
u64Div1000000_0:
|
|
|
|
or dx, dx ; dx must be zero (lower 48 bits only)
|
|
jnz short u64Div1000000_OF ; 0:ax:bp:bx / divisor
|
|
mov dx, ax ; aligned the dividend in dx:ax:bx
|
|
mov ax, bp ; dx:ax:bx / bp
|
|
mov bp, 0f424h ; divisor = f424h
|
|
cmp dx, bp
|
|
jae short u64Div1000000_OF ; dx:ax:bx / bp
|
|
div bp ; dx=r, ax=q
|
|
xchg ax, bx ; bx=q, dx:ax=remainder
|
|
div bp ; bx:ax=q
|
|
mov dx, bx ; dx:ax=q
|
|
ret
|
|
|
|
u64Div1000000_OF:
|
|
|
|
mov ax, 0ffffh
|
|
mov dx, 07fffh
|
|
ret
|
|
|
|
|
|
|
|
SUBTTL U32Mul1000000
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function multiply a 32-bit number by 1000000 (decimal), this function
|
|
only assembly under 8086/80286 cpu, for 80386 and up it will use in line
|
|
code to do divison
|
|
|
|
Arguments:
|
|
|
|
dx:ax - multiplicand
|
|
|
|
Return Value:
|
|
|
|
dx:ax:bp:bx - final 64-bit number which is dx:ax * 1000000 decimal
|
|
|
|
CX register destroyed
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
PUBLIC u32Mul1000000
|
|
|
|
u32Mul1000000 label near
|
|
|
|
;
|
|
; at return dx:ax:bp:bx is the (dx:ax * 1000000 (decimal))
|
|
; cx is destroyed
|
|
;
|
|
; dx:ax * FD6NUM_1_DW0 (0f4240h) = (dx:ax * f424h) << 4
|
|
;
|
|
; dx:ax
|
|
; x bp
|
|
; -----------------
|
|
; ax:bp x0 = bp:bx
|
|
; dx:bp x1 = dx:ax
|
|
;---------------------
|
|
;
|
|
|
|
mov cx, 0f424h
|
|
xor bp, bp ; assuem x0=0
|
|
xor bx, bx
|
|
or ax, ax
|
|
jz short u32Mul1000000_1 ; jmp if ax=0
|
|
mov bx, dx ; save it
|
|
mul cx ; dx:ax=result = x0
|
|
xchg dx, bp
|
|
xchg ax, bx ; bp:bx=x0, ax=high 16-bit, dx=0
|
|
xchg dx, ax ; dx=high 16-bit, ax=0 to fall through
|
|
|
|
u32Mul1000000_1:
|
|
|
|
xchg dx, ax ; dx=0, ax=next 16-bit
|
|
or ax, ax
|
|
jz short u32Mul1000000_2 ; nothing to do
|
|
mul cx ; dx:ax=x1
|
|
add bp, ax ; bp:bx = x0
|
|
mov ax, dx ; + dx:ax = x1
|
|
mov dx, 0 ;-----------------------
|
|
adc ax, dx ; dx:ax:bp:bx = products
|
|
adc dx, dx
|
|
|
|
u32Mul1000000_2:
|
|
|
|
add bx, bx
|
|
adc bp, bp
|
|
adc ax, ax
|
|
adc dx, dx
|
|
|
|
add bx, bx
|
|
adc bp, bp
|
|
adc ax, ax
|
|
adc dx, dx
|
|
|
|
add bx, bx
|
|
adc bp, bp
|
|
adc ax, ax
|
|
adc dx, dx
|
|
|
|
add bx, bx
|
|
adc bp, bp
|
|
adc ax, ax
|
|
adc dx, dx
|
|
ret
|
|
|
|
|
|
|
|
|
|
SUBTTL U64DivU32_U32
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function divide a 64-bit number by 32-bit number.
|
|
only assembly under 8086/80286 cpu, for 80386 and up it will use in line
|
|
code to do divison
|
|
|
|
Arguments:
|
|
|
|
dx:ax:bp:bx - dividend
|
|
si:di - divisor
|
|
|
|
Return Value:
|
|
|
|
bx:cx - 32-bit unsigned quotient, if dx:ax = 7fff:ffff then overflow.
|
|
dx:ax - 32-bit unsigned remainder
|
|
si:di = divisor (unchanged)
|
|
|
|
all other registers are destroyed
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Total re-construct, re-write, it make it calculate the 6 decimal
|
|
points precision easier for not using slow floating emulation, the
|
|
speed is faster then the reqular (long/long) routine in the
|
|
standard library while it provide me all the necessary color calcuation
|
|
with good precisions.
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
;==========================================================================
|
|
; Defined several useful data at here
|
|
;==========================================================================
|
|
|
|
|
|
RShiftTable equ this word
|
|
dw RShift_0
|
|
dw RShift_1
|
|
dw RShift_2
|
|
dw RShift_3
|
|
dw RShift_4
|
|
dw RShift_5
|
|
dw RShift_6
|
|
dw RShift_7
|
|
|
|
ShiftTable1 equ this word
|
|
dw 1000h ; 00010000 00000000
|
|
dw 0010h ; 00000000 00010000
|
|
|
|
ShiftTable2 equ this word
|
|
dw 4000h ; 01000000 00000000
|
|
dw 0400h ; 00000100 00000000
|
|
dw 0040h ; 00000000 01000000
|
|
dw 0004h ; 00000000 00000100
|
|
|
|
ShiftTable3 equ this word
|
|
dw 8000h ; 10000000 00000000
|
|
dw 2000h ; 00100000 00000000
|
|
dw 0800h ; 00001000 00000000
|
|
dw 0200h ; 00000010 00000000
|
|
dw 0080h ; 00000000 10000000
|
|
dw 0020h ; 00000000 00100000
|
|
dw 0008h ; 00000000 00001000
|
|
dw 0002h ; 00000000 00000010
|
|
|
|
;***************************************************************************
|
|
; END OF LOCAL DATA
|
|
;***************************************************************************
|
|
|
|
|
|
uDiv6432_L16:
|
|
|
|
;
|
|
; dx:ax:bp:bx / si:di (si=0) = dx:ax/bx:cx
|
|
;
|
|
|
|
or di, di
|
|
jz short uDiv6432_Overflow
|
|
or dx, dx
|
|
jnz short uDiv6432_Overflow ; dx=0 otherwise overflow
|
|
cmp ax, di
|
|
jae short uDiv6432_Overflow
|
|
mov dx, ax
|
|
mov ax, bp ; move up
|
|
div di ; dx:bx=remainder, ax=quotient
|
|
xchg bx, ax ; dx:ax=remainder, bx=quotient
|
|
div di ; dx=remainder, bx:ax=quotient
|
|
|
|
mov cx, dx ; cx=remainder, bx:ax=quotient
|
|
mov dx, bx ; cx=remainder, dx:ax=quotient
|
|
xor bx, bx ; bx:cx=remainder, dx:ax=quotient
|
|
ret
|
|
|
|
uDiv6432_H16:
|
|
|
|
;
|
|
; dx:ax:bp:bx / si:di (di=0) = dx:ax/bx:cx
|
|
;
|
|
|
|
cmp dx, si
|
|
jae short uDiv6432_Overflow ; the dividend too big
|
|
div si ; dx:bp:bx=remainder, ax=quotient
|
|
xchg bp, ax ; dx:ax:bx=remainder, bp=quotient
|
|
div si ; dx:bx=remainder, bp:ax=quotient
|
|
mov cx, bx ; dx:cx=remainder, bp:ax=quotient
|
|
mov bx, dx ; bx:cx=remainder, bp:ax=quotient
|
|
mov dx, bp ; bx:cx=remainder, dx:ax=quotient
|
|
ret
|
|
|
|
uDiv6432_Overflow:
|
|
|
|
mov dx, 07fffh ; return quotient (dx:ax) = max. number
|
|
mov ax, 0ffffh
|
|
xor bx, bx
|
|
xor cx, cx
|
|
ret
|
|
|
|
|
|
PUBLIC U64DivU32_U32
|
|
|
|
U64DivU32_U32 label near
|
|
|
|
;
|
|
; dx:ax:bp:bx / si:di = dx:ax/bx:cx
|
|
;
|
|
|
|
or si, si
|
|
jz short uDiv6432_L16
|
|
or di, di
|
|
jz short uDiv6432_H16
|
|
cmp dx, si ; have to make sure dx/si != 0
|
|
jae short uDiv6432_Overflow ; the dividend too big
|
|
|
|
uDiv6432_M1a:
|
|
|
|
;
|
|
; dx:ax:bp:bx / si:di
|
|
; dx:ax=remainder, bx:cx=quotient
|
|
;
|
|
|
|
push bx ; save lowest 16-bit of dividend
|
|
div si ; dx=r, ax=q
|
|
mov cx, dx ; cx:bp:sp=r, bx=q
|
|
mov bx, ax
|
|
mul di ; dx:ax=overrun, cx:bp=remainder
|
|
; bx=quotient
|
|
xchg ax, bp ; cx:bp=overrun, dx:ax=last remainder
|
|
xchg dx, cx
|
|
sub ax, bp ; remainder - overrun
|
|
sbb dx, cx
|
|
|
|
mov bp, 0 ; no shift count
|
|
jnc short uDiv6432_M1c ; remainder >= overrun
|
|
|
|
;
|
|
; now we have -(dx:ax) of overrun, we need to add the divisor back until
|
|
; dx:ax is not negative, for every divisor (si:di) we add the quotient (bx)
|
|
; must decrement by one.
|
|
;
|
|
uDiv6432_M1b:
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1c ; carry on...
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1c ; carry on...
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1c ; carry on...
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1c ; carry on...
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1c ; carry on...
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1c ; carry on...
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1c ; carry on...
|
|
|
|
call uDiv6432_QR ; at return BP=shift count
|
|
; bx=adjusted quot, dx:ax=remainder
|
|
uDiv6432_M1c:
|
|
|
|
mov cx, bp ; save shift count in CX
|
|
pop bp ; bp=lowest 16-bit of dividend
|
|
push bx ; save high 16-bit of quotient
|
|
|
|
cmp dx, si
|
|
jae short uDiv6432_NegDiv ; using negative division algorithm
|
|
|
|
push cx ; save shift count
|
|
|
|
uDiv6432_M1d:
|
|
|
|
div si ; dx=r, ax=q
|
|
mov cx, dx ; cx=r, sp:bx=q
|
|
mov bx, ax ; cx:bp=r, sp:bx=q
|
|
mul di ; dx:ax=remainder 2
|
|
|
|
xchg ax, bp ; cx:bp=overrun, dx:ax=last remainder
|
|
xchg dx, cx
|
|
sub ax, bp ; remainder - overrun
|
|
sbb dx, cx
|
|
|
|
pop bp ; get shift count
|
|
|
|
jnc short uDiv6432_M1e ; remainder >= overrun
|
|
|
|
;
|
|
; now we have -(dx:ax) of overrun, we need to add the divisor back until
|
|
; dx:ax is not negative, for every divisor (si:di) we add the quotient (bx)
|
|
; must decrement by one.
|
|
;
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1e ; do until positive number
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1e ; do until positive number
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1e ; do until positive number
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1e ; do until positive number
|
|
|
|
dec bx
|
|
add ax, di
|
|
adc dx, si
|
|
jc short uDiv6432_M1e ; do until positive number
|
|
|
|
call uDiv6432_QR ; too many call-up the division
|
|
; bx=adjusted quot, dx:ax=remainder
|
|
uDiv6432_M1e: ; sp:bx=quotient, dx:ax=remainder
|
|
|
|
mov cx, ax ; sp:bx=quotient, dx:cx=remainder
|
|
mov ax, bx ; sp:ax=quotient, dx:cx=remainder
|
|
mov bx, dx ; sp:ax=quotient, bx:cx=remainder
|
|
pop dx ; dx:ax=quotient, bx:cx=remainder
|
|
ret
|
|
|
|
;
|
|
;
|
|
;============================================================================
|
|
; interal subfunctions to the uDiv6432
|
|
;============================================================================
|
|
;
|
|
;
|
|
; uDiv6432_NegDiv --- Negate and divide algorithm
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
;
|
|
; dx:ax:bp / si:di, *sp=high qoutient
|
|
;
|
|
; (dx == si) and (ax < di) at here
|
|
;
|
|
; now we use maximum difference (di:0 - ax:bp) as estimate 32-bit
|
|
; dividend number then divide it by divisor, the (0xffff - resulting
|
|
; quotient) is the original quotient, and remainder is equal to
|
|
; (divisor - resulting remainder), the only exception is that if remainder
|
|
; is zero then the quotient need to increment by 1.
|
|
;
|
|
|
|
uDiv6432_NegDiv:
|
|
|
|
mov dx, di
|
|
neg bp
|
|
sbb dx, ax
|
|
mov ax, bp ; dx:ax=inverted 32-bit dividend
|
|
call uDiv3232_32Divisor ; dx:ax=quot (0:ax) bx:cx=remainder
|
|
jz short uDiv6432_NegDiv1 ; remainder = 0, just negate quot
|
|
inc ax ; compensate for non-zero remainder
|
|
neg bx ; remainder = divosr - remainder
|
|
neg cx ; bx=0 at here
|
|
sbb bx, dx
|
|
add cx, di
|
|
adc bx, si ; bx:cx=final remainder
|
|
|
|
uDiv6432_NegDiv1:
|
|
|
|
neg ax ; negate the quotient
|
|
pop dx ; dx:ax=quot, bx:cx=remainder
|
|
ret
|
|
|
|
;
|
|
; uDiv6432_QR - 32-bit/32-bit with previos quotient adjustment
|
|
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
;
|
|
; Entry:
|
|
; bp = shift count
|
|
; bx = Previous quotient to be adjusted
|
|
; dx:ax = Negative overrun factor
|
|
; si:di = Divisor
|
|
;
|
|
; Exit:
|
|
; bx = Adjusted quotient
|
|
; dx:ax = positive/0 remainder after overun adjustment
|
|
; si:di = divisor (unchanged)
|
|
;
|
|
; cx, bp destroyed
|
|
;
|
|
|
|
uDiv6432_QR:
|
|
|
|
|
|
NEG32_FROMR16HL dx, ax
|
|
|
|
;
|
|
; dx:ax / si:di (bx:di)
|
|
; remainder = dx:ax
|
|
;
|
|
|
|
uDiv6432_QR_0:
|
|
|
|
xchg bx, bp ; bp=quotient, bx=shift count
|
|
|
|
; dx:ax / cx:di
|
|
|
|
|
|
uDiv6432_QR_1:
|
|
|
|
|
|
or bx, bx
|
|
jnz short HasShiftCount
|
|
|
|
;
|
|
; shift dx:ax/cx:di right by bp shift count
|
|
;
|
|
|
|
cmp si, 0100h ; right side set the carry
|
|
adc bl, bl ; 0 <= bx <= 1
|
|
|
|
add bx, bx ; bx = 0, 2, pre-shift for word table
|
|
cmp si, cs:ShiftTable1[bx] ; split again
|
|
adc bl, bh ; 0 <= bx <= 3
|
|
|
|
add bx, bx ; bx = 0,2,4,6, shift for word table
|
|
cmp si, cs:ShiftTable2[bx]
|
|
adc bl, bh ; 0 <= bx <= 7
|
|
|
|
add bx, bx ; bx = 0,2,4,6,8,10,12,14
|
|
cmp si, cs:ShiftTable3[bx]
|
|
adc bl, bh ; 0 <= bx <= 15
|
|
neg bx
|
|
add bx, 16
|
|
|
|
HasShiftCount:
|
|
|
|
push bx ; save shift count back
|
|
|
|
push dx ; save dividend high
|
|
push di ; save divisor low
|
|
push bp ; save quotient
|
|
mov bp, ax ; save dividend low
|
|
mov cx, si
|
|
|
|
;
|
|
; dx:ax / cx:di, sp=shift count, sp+2=dx, sp+4=di, sp+6=quotient
|
|
|
|
cmp bx, 8
|
|
jb short Shift1
|
|
|
|
mov al, ah
|
|
mov ah, dl
|
|
mov dl, dh
|
|
xor dh, dh
|
|
|
|
xchg ax, di
|
|
mov al, ah
|
|
mov ah, cl
|
|
mov cl, ch
|
|
xor ch, ch
|
|
xchg ax, di
|
|
|
|
and bx, 7
|
|
|
|
Shift1:
|
|
|
|
add bx, bx
|
|
jmp cs:RShiftTable[bx]
|
|
|
|
RShift_7:
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr cx, 1
|
|
rcr di, 1
|
|
RShift_6:
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr cx, 1
|
|
rcr di, 1
|
|
RShift_5:
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr cx, 1
|
|
rcr di, 1
|
|
RShift_4:
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr cx, 1
|
|
rcr di, 1
|
|
RShift_3:
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr cx, 1
|
|
rcr di, 1
|
|
RShift_2:
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr cx, 1
|
|
rcr di, 1
|
|
RShift_1:
|
|
shr dx, 1
|
|
rcr ax, 1
|
|
shr cx, 1
|
|
rcr di, 1
|
|
|
|
RShift_0:
|
|
|
|
pop bx ; restore quotient
|
|
|
|
div di ; get estimate quotient = ax
|
|
sub bx, ax ; decrement the quotient
|
|
mov cx, ax ; ax=bx=estimate quotient
|
|
pop di ; si:di=original divisor
|
|
|
|
;
|
|
; estimation of Quotient = eQ
|
|
;
|
|
; vH:vL
|
|
; eQ
|
|
; -------------------
|
|
; vL:eQ -- x0 dx:ax
|
|
; vH:eQ -- x1 ..:cx
|
|
; -----------------------------------------------
|
|
; ..:dx:ax
|
|
;
|
|
;
|
|
; dx += cx;
|
|
;
|
|
; if (carry) return (eQ - 1);
|
|
; if (dx:ax > original dividend) return(eQ - 1) else return(eQ)
|
|
;
|
|
; now multiply the eQ (bx) with original divisor (si:di)
|
|
; now cx:bp=original dividend
|
|
;
|
|
|
|
mul si ; dx:ax, using only ax
|
|
xchg ax, cx ; ax=eQ, cx=H(eQ * Divisor)
|
|
mul di ; dx:ax=L(eQ * Divisor)
|
|
add dx, cx
|
|
pop cx ; restore cx (original High dividend)
|
|
|
|
jc short uDiv6432_QR_s1
|
|
|
|
cmp dx, cx
|
|
ja short uDiv6432_QR_s1
|
|
jb short uDiv6432_QR_s2
|
|
cmp ax, bp
|
|
jbe short uDiv6432_QR_s2
|
|
|
|
uDiv6432_QR_s1:
|
|
|
|
inc bx ; add 1 back to the quotient
|
|
sub ax, di ; substract divisor
|
|
sbb dx, si
|
|
|
|
uDiv6432_QR_s2:
|
|
; substract original dividend
|
|
sub ax, bp ; at here, we either carry or zero
|
|
sbb dx, cx
|
|
jnc short uDiv6432_QR_Done
|
|
|
|
;
|
|
; still has overrun, that is we have remainder,
|
|
;
|
|
|
|
dec bx ; substract one from the qoutient
|
|
add ax, di
|
|
adc dx, si
|
|
|
|
uDiv6432_QR_Done:
|
|
|
|
pop bp ; return BP=shift count
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
SUBTTL U32MulU32_U64
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function multiply a 32-bit multipicand with a 32-bit multiplier
|
|
and return a 64-bit product.
|
|
|
|
only assembly under 8086/80286 cpu, for 80386 and up it will use in line
|
|
code to do divison
|
|
|
|
Arguments:
|
|
|
|
bp:bx = multiplicand
|
|
dx:ax = multiplier
|
|
|
|
Return Value:
|
|
|
|
dx:ax:bp:bx - 64-bit products (dx:ax * bp:bx)
|
|
|
|
all other registers are destroyed.
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Total re-construct, re-write, it make it calculate the 6 decimal
|
|
points precision easier for not using slow floating emulation, the
|
|
speed is faster then the reqular (long/long) routine in the
|
|
standard library while it provide me all the necessary color calcuation
|
|
with good precisions.
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
|
|
PUBLIC U32MulU32_U64
|
|
|
|
U32MulU32_U64 label near
|
|
|
|
|
|
; bp:bx bp:bx
|
|
; x dx:ax x si:di
|
|
; ---------------- ----------------
|
|
; bx*ax x0 bx*di x0
|
|
; bp*ax x1 bp*di x1
|
|
; bx*dx x2 bx*si x2
|
|
; + bp*dx x3 + bp*si x3
|
|
; ===================== =====================
|
|
; dx:ax:bp:bx products dx:ax:bp:bx products
|
|
|
|
uMul3232_Low:
|
|
|
|
mov di, ax ; save multiplier in si:di
|
|
mov si, dx
|
|
|
|
xor cx, cx
|
|
xor dx, dx
|
|
xor ax, ax
|
|
|
|
or di, di ; see if zero (no business here)
|
|
jz short uMul3232_High
|
|
|
|
uMul3232_x0:
|
|
|
|
or bx, bx ; zero ?
|
|
jz short uMul3232_x1
|
|
mov ax, di
|
|
mul bx ; dx:ax = x0
|
|
|
|
uMul3232_x1:
|
|
|
|
or bp, bp
|
|
jz short uMul3232_x1a ; zeroing the DI
|
|
|
|
xchg di, ax ; cx:di = x0, ax=di
|
|
mov cx, dx
|
|
mul bp ; dx:ax = x1
|
|
|
|
xchg di, ax ; dx:ax = x0
|
|
xchg cx, dx ; cx:di = x1
|
|
; --------------------
|
|
add dx, di ; di:cx:dx:ax
|
|
|
|
uMul3232_x1a:
|
|
|
|
mov di, 0
|
|
adc cx, di
|
|
adc di, di
|
|
|
|
uMul3232_High:
|
|
|
|
or si, si ; now di:cx:dx:ax = x0+x1
|
|
jz short uMul3232_Done
|
|
|
|
uMul3232_x2:
|
|
|
|
or bx, bx
|
|
jz short uMul3232_x3 ; di:cx:dx:ax
|
|
|
|
push ax
|
|
xchg bx, dx ; di:cx:dx:ax ===> di:cx:bx:push
|
|
mov ax, si ; dx:ax = x3
|
|
mul dx ;
|
|
|
|
add bx, ax
|
|
mov ax, 0
|
|
adc cx, dx
|
|
adc di, ax ; di:cx:bx:ax
|
|
pop ax
|
|
mov dx, bx ; di:cx:bx:ax -> di:cx:dx:ax
|
|
|
|
uMul3232_x3:
|
|
|
|
or bp, bp
|
|
jz short uMul3232_Done ;
|
|
|
|
mov bx, dx
|
|
xchg si, ax ; di:cx:dx:ax --> di:cx:bx:si
|
|
mul bp ; dx:ax = x3
|
|
|
|
add cx, ax
|
|
adc di, dx ; di:cx:bx:si => dx:ax:bp:bx
|
|
|
|
mov dx, di
|
|
mov ax, cx
|
|
mov bp, bx
|
|
mov bx, si
|
|
ret
|
|
|
|
uMul3232_Done: ; di:cx:dx:ax -> dx:ax:bp:bx
|
|
|
|
mov bp, dx
|
|
mov bx, ax
|
|
mov dx, di
|
|
mov ax, cx
|
|
ret
|
|
|
|
|
|
|
|
|
|
SUBTTL U32DivU32_U32
|
|
PAGE
|
|
|
|
COMMENT `
|
|
|
|
Routine Description:
|
|
|
|
This function divide a 32-bit number by 32-bit number and return both
|
|
32-bit quotient and 32-bit remainder.
|
|
|
|
only assembly under 8086/80286 cpu, for 80386 and up it will use in line
|
|
code to do divison
|
|
|
|
Arguments:
|
|
|
|
dx:ax - 32-bit unsigned Dividend
|
|
si:di - 32-bit unsigned Divisor
|
|
|
|
Return Value:
|
|
|
|
dx:ax - 32-bit unsigned quotient,
|
|
bx:cx - 32-bit unsigned remainder
|
|
si:di - Divisor, unchanged.
|
|
zero flag - set if remainder is zero, clear otherwise
|
|
cx/bp - destroyed.
|
|
|
|
Author:
|
|
|
|
26-Sep-1991 Thu 17:05:21 created -by- Daniel Chou (danielc)
|
|
|
|
Total re-construct, re-write, it make it calculate the 6 decimal
|
|
points precision easier for not using slow floating emulation, the
|
|
speed is faster then the reqular (long/long) routine in the
|
|
standard library while it provide me all the necessary color calcuation
|
|
with good precisions.
|
|
|
|
Revision History:
|
|
|
|
`
|
|
|
|
PUBLIC U32DivU32_U32
|
|
|
|
U32DivU32_U32 label near
|
|
|
|
;
|
|
; dx:ax / si:di ====> dx:ax=quotient, bx:cx=remainder
|
|
;
|
|
|
|
or si, si
|
|
jnz short uDiv3232_32Divisor
|
|
|
|
or di, di ; if di=0, then error
|
|
jz short uDiv3232_Err
|
|
|
|
xor bx, bx ; assume quotient H = 0
|
|
cmp dx, di ; see if will overflow ?
|
|
jb short uDiv3232_1
|
|
|
|
mov bx, ax ; save dividend L in bx
|
|
mov ax, dx
|
|
xor dx, dx
|
|
div di ; 0:ax/di, dx=r, ax=q
|
|
xchg bx, ax ; dx:ax=remainder, bx=quotient H
|
|
|
|
uDiv3232_1:
|
|
|
|
div di ; bx:ax=quotient, dx=remainder
|
|
mov cx, dx ; bx:ax=quotient, cx=remainder
|
|
mov dx, bx ; dx:ax=quotient, cx=remainder
|
|
xor bx, bx ; dx:ax=quotient, bx:cx(0:cx)=remainder
|
|
or cx, cx ; return zero flag for remainder
|
|
ret
|
|
|
|
uDiv3232_Err:
|
|
|
|
sub bx, bx
|
|
sub cx, cx ; remainder = 0
|
|
ret
|
|
|
|
|
|
uDiv3232_Zero:
|
|
|
|
mov cx, ax
|
|
mov bx, dx ; return remainder = dividend
|
|
or ax, dx ; return (BOOL)(remainder == 0)
|
|
mov ax, 0
|
|
mov dx, 0 ; dx:ax=quotient, bx:cx=remainder
|
|
ret
|
|
|
|
uDiv3232_One:
|
|
|
|
mov ax, 1 ; return quotient = 1 and no remainder
|
|
sub dx, dx ; return dx:ax=1 (quotient) bx:cx=0
|
|
sub bx, bx ; (remainder) and zero flag set to
|
|
sub cx, cx ; indicate that remainder is zero
|
|
ret ; indicate that remainder is zero
|
|
|
|
|
|
PUBLIC uDiv3232_32Divisor
|
|
|
|
uDiv3232_32Divisor label near ; full 32-bit divisor
|
|
|
|
;
|
|
; dx:ax / si:di = dx:ax/bx:cx
|
|
;
|
|
|
|
mov bx, dx
|
|
mov cx, ax
|
|
sub cx, di
|
|
sbb bx, si
|
|
jc short uDiv3232_Zero ; if carry then dx:ax < si:di
|
|
or cx, bx ; if bx:cx=0 then dx:ax=si:di
|
|
jz short uDiv3232_One
|
|
|
|
;
|
|
; dx:ax / si:di (bx:cx / bp:ss:sp)
|
|
;
|
|
|
|
mov bx, dx
|
|
mov cx, ax
|
|
mov bp, si
|
|
push di
|
|
|
|
; dx:ax / bp:di
|
|
|
|
shl di, 1 ; prepare to fall through
|
|
|
|
uDiv3232_3:
|
|
|
|
rcr di, 1 ; first pass, so that we do not
|
|
;=============== ; need to do a seperate check to
|
|
shr dx, 1 ; see if 'bp' alreay zero
|
|
rcr ax, 1
|
|
shr bp, 1
|
|
jnz short uDiv3232_3
|
|
rcr di, 1 ; do the last one
|
|
|
|
;
|
|
; ready to divide a 32-bit number by 16-bit number
|
|
|
|
div di ; get estimate quotient = ax
|
|
mov bp, ax ; ax=bp=estimate quotient
|
|
pop di ; si:di=original divisor
|
|
|
|
;
|
|
; estimation of Quotient = eQ
|
|
;
|
|
; vH:vL
|
|
; eQ
|
|
; -------------------
|
|
; vL:eQ -- x0 dx:ax
|
|
; vH:eQ -- x1 ..:cx
|
|
; -----------------------------------------------
|
|
; ..:dx:ax
|
|
;
|
|
;
|
|
; dx += cx;
|
|
;
|
|
; if (carry) return (eQ - 1);
|
|
; if (dx:ax > original dividend) return(eQ - 1) else return(eQ)
|
|
;
|
|
; now multiply the eQ (bp) with original divisor (si:di)
|
|
; now bx:cx=original dividend
|
|
;
|
|
|
|
mul si ; dx:ax, using only ax
|
|
push bp ; save eQ
|
|
xchg ax, bp ; ax=eQ, bp=H(eQ * Divisor)
|
|
mul di ; dx:ax=L(eQ * Divisor)
|
|
add dx, bp
|
|
pop bp ; get the eQ back
|
|
jc short uDiv3232_EQm1 ; the eQ*Divisor is one divisor higher
|
|
cmp dx, bx ; if the eQ*Divisor > original dividend
|
|
jc short uDiv3232_EQ ; then the quotient need decrement by 1
|
|
ja short uDiv3232_EQm1 ; if less or equal then is ok
|
|
cmp ax, cx
|
|
jbe short uDiv3232_EQ
|
|
|
|
uDiv3232_EQm1: ; eQ-1: bp=eQ, dx:ax=eQ*Divisor, bx:cx=dvnd
|
|
|
|
dec bp ; decrement the eQ by 1
|
|
sub ax, di ; and also substract the divisor one more
|
|
sbb dx, si ; time to compensate for the eQ-1
|
|
|
|
uDiv3232_EQ: ; eQ: bp=q, dx:ax=eQ * Divisor, bx:cx=dvnd
|
|
|
|
sub cx, ax ; remainder of the number is
|
|
sbb bx, dx ; original dividend - (eQ * Divisor)
|
|
mov ax, bp ; 0:ax (dx:ax)=quotient, bx:cx=remainder
|
|
mov dx, cx
|
|
or dx, bx ; return zero flag for (remainder == 0)
|
|
mov dx, 0 ; quotient high always zero at here
|
|
ret
|
|
|
|
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
;@ End of only for 8086/80286 only, and all functions are used internally @
|
|
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
|
|
ENDIF ; i8086/i286
|
|
ENDIF ; HT_ASM_80x86
|
|
|
|
|
|
|
|
|
|
END
|