home *** CD-ROM | disk | FTP | other *** search
- title BCDUU -- Copyright 1997, Morten Elling
- subttl Routines to handle unsigned un-packed BCDs
-
- include model.inc
- include modelt.inc
- include bcduu.ash
-
- @CODESEG
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name BCDUUmov
- ;// Desc Move (copy) an un-packed BCD value.
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Destination = source. Acc undefined.
-
- BCDUUmov proc
- arg dstBCD :dataptr, \ ; Addr of dest. BCD (size = srcsz)
- srcBCD :dataptr, \ ; Addr of source BCD
- srcsz :@uint ; Byte size of source
- @uses ds,es,rsi,rdi,rcx
- ;.
- @cld ; String ops forward
- @LDS rsi, [srcBCD]
- @LES rdi, [dstBCD]
- mov rcx, [srcsz]
- rep movsb
- RET
- BCDUUmov endp
-
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name BCDUUadd
- ;// Desc Add two unpacked unsigned BCD numbers (dst += src).
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Sum of dest. and source returned to destination.
- ;// Accumulator (and cf flag) determined:
- ;// Acc = 0: No carry
- ;// Acc = 1: Carry (overflow)
- ;//
- ;// Note Destination and source may be the same.
-
- BCDUUadd proc
- arg dstBCD :dataptr, \ ; Addr of dest. BCD (size = srcsz)
- srcBCD :dataptr, \ ; Addr of source BCD
- srcsz :@uint ; Byte size of source
- @uses ds,es,rsi,rdi,rcx
- ;.
- @cld ; String ops forward
- @LDS rsi, [srcBCD]
- @LES rdi, [dstBCD]
- mov rcx, [srcsz] ; Byte size = loop count
- clc ; Clear carry in
- @@nxta: lodsb ; Get one digit of source
- adc al, @ES [rdi] ; Add digit of dest + carry
- aaa ; Adjust to unpacked BCD format
- stosb ; Store al to destination
- loop @@nxta ; Loop until done
- ; Carry set by AAA
- ; if overflow (ah > 0)
- sbb rax, rax ; Acc=0,cf=0 or acc=-1,cf=1
- neg rax ; Acc=0,cf=0 or acc=1,cf=1
- RET
- BCDUUadd endp
-
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name BCDUUsub
- ;// Desc Subtract two unpacked unsigned BCD numbers (dst -= src)
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Difference (dest - source) returned to destination.
- ;// Accumulator (and cf flag) determined:
- ;// Acc = 0: No borrow
- ;// Acc = 1: Borrow (underflow)
- ;//
- ;// Note Destination and source may be the same.
-
- BCDUUsub proc
- arg dstBCD :dataptr, \ ; Addr of dest. BCD (size = srcsz)
- srcBCD :dataptr, \ ; Addr of source BCD
- srcsz :@uint ; Byte size of source
- @uses ds,es,rsi,rdi,rcx
- ;.
- @cld ; String ops forward
- @LDS rsi, [srcBCD]
- @LES rdi, [dstBCD]
- mov rcx, [srcsz] ; Byte size = loop count
- clc ; Clear carry in
- @@nxts: mov al, @ES [rdi] ; Get one digit of dest
- sbb al, [rsi] ; Subtract source and carry
- aas ; Adjust to unpacked BCD format
- stosb ; Store al to destination
- inc rsi ; Step src pointer
- loop @@nxts ; Loop until done
- ; Carry set by AAS
- ; if underflow (ah < 0)
- sbb rax, rax ; Acc=0,cf=0 or acc=-1,cf=1
- neg rax ; Acc=0,cf=0 or acc=1,cf=1
- RET
- BCDUUsub endp
-
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name BCDUUu2p
- ;// Desc Convert un-packed unsigned BCD to packed unsigned BCD.
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Packed BCD returned to destination.
- ;// Acc > 0: No error.
- ;// Acc = 0: High word of source contains information
- ;// that cannot be converted.
- ;//
- ;// Note Assumes source size is twice that of destination.
-
- BCDUUu2p proc
- arg dstBCD :dataptr, \ ; Addr of dest. BCD (size = srcsz/2)
- srcBCD :dataptr, \ ; Addr of unpacked source BCD
- srcsz :@uint ; Byte size of source
- @uses ds,es,rsi,rdi,rcx
- ;.
- @cld ; String ops forward
- @LDS rsi, [srcBCD]
- @LES rdi, [dstBCD]
- mov rcx, [srcsz] ; Byte size = loop count
- @@up1: lodsW ; Get two digits of source
- @shl ah, 4 ; Shift nibble into position
- or al, ah ; Pack two digits into al
- stosb ; Store al to destination
- loop @@up1 ; Loop until done
-
- ; ----- Return 0 or 1
- neg al ; Set carry if al <> 0
- sbb rax, rax
- inc rax
- RET
- BCDUUu2p endp
-
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name BCDUUu2a
- ;// Desc Convert unpacked unsigned BCD to decimal Ascii.
- ;// Outputs at least one character.
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Zero-terminated Ascii string returned to destination.
- ;// Acc = length of destination string (less trailing 0).
- ;//
- ;// Note Maximum output to the destination string equals the
- ;// BCD's byte size plus 1.
-
- BCDUUu2a proc
- arg pStr :dataptr, \ ; Addr of AsciiZ dest.
- srcBCD :dataptr, \ ; Addr of source BCD
- srcsz :@uint ; Byte size of source BCD
- @uses ds,es,rsi,rdi,rcx
- ;.
- @cld ; String ops forward
- @LDS rsi, [srcBCD]
- @LES rdi, [pStr]
- mov rcx, [srcsz]
-
- ; ----- Skip insignificant zeros
- add rsi, rcx
- @@ua1: dec rsi
- mov al, [rsi]
- test al, al
- loopz @@ua1
- inc rcx ; Output at least one digit
-
- ; ----- Convert BCD
- @@ua2: mov al, [rsi] ; Get unpacked BCD digit
- dec rsi ; Decrement src. index
- or al, '0' ; Convert to Ascii
- stosb ; Store al to destination
- loop @@ua2 ; Loop until done
-
- ; ----- Zero-terminate string
- ; and return its length
- sub al, al
- stosb
- lea rax, [rdi-1]
- sub rax, @uiptr [pStr]
- RET
- BCDUUu2a endp
-
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name BCDUUmul
- ;// Desc Multiply two unpacked unsigned BCDs (dst *= src).
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Double-size unpacked unsigned BCD product returned to
- ;// destination _replacing_ the multiplicand.
- ;// Acc undefined.
- ;//
- ;// Note Both BCD operands must be defined as double-size,
- ;// where the high-order is undefined (because the result
- ;// is returned as double-precision, and the multiplier
- ;// provides temporary work space for this procedure).
- ;//
- ;// See bcdImul for details on algorithm.
-
- BCDUUmul proc
- arg dstBCD :dataptr, \ ; Addr of BCD multiplicand
- srcBCD :dataptr, \ ; Addr of BCD multiplier
- srcsz :@uint ; Byte size of each BCD (double-size)
- @uses ds,es,rsi,rdi,rbx,rcx,rdx,rax
- ;.
- ; ----- Copy multiplicand to hi(src)
- push rbp
- @cld ; String ops forward
- @LDS rsi, [dstBCD]
- @LES rdi, [srcBCD]
- mov rbx, [srcsz]
- mov rcx, rbx
- shr rcx, 1
- add rdi, rcx
- rep movsb
-
- ; ----- Zero-fill destination
- @LES rdi, [dstBCD]
- mov rcx, rbx
- sub al, al
- rep stosb
-
- ; ----- Fix pointers
- @LDS rsi, [srcBCD] ; u[0]
- sub rdi, rbx ; w[0]
- mov rdx, rbx
- shr rbx, 1
- lea rbp, [rsi+rbx] ; v[0]
- ; *** No stack frame ***
-
-
- ; ----- Perform the multiplication using the
- ; MUL, AAM, ADD, and AAA instructions
- ;
- sub rbx, rbx ; i = 0
- @alignn
- @@outr: sub rcx, rcx ; j = 0
- sub ah, ah ; k = 0
- @@innr: push rdx ; Save m
- mov dh, ah ; Save k (un-packed BCD)
- ife @isUse32
- xchg rbx, rcx
- mov ah, [rsi+rbx] ; Get u[j]
- xchg rbx, rcx
- xchg rsi, rbp
- mov al, [rsi+rbx] ; Get v[i]
- xchg rsi, rbp
- else
- mov ah, [rsi+rcx]
- mov al, [rbx+rbp]
- endif
- mul ah ; t = u[j] * v[i]
- aam
- add al, dh ; + k
- aaa
- add rbx, rcx
- add al, @ES [rdi+rbx] ; + w[i+j]
- aaa
- mov @ES [rdi+rbx], al ; w[i+j] = t mod 10
- ;mov ah, ah ; k = t div 10
- sub rbx, rcx ; Restore i
- pop rdx ; Restore m
- inc rcx ; j++
- cmp rcx, rdx ; j == m?
- jb @@innr ; No, repeat inner loop
- ;
- add rbx, rdx
- mov @ES [rdi+rbx], ah ; w[i+m] = k
- sub rbx, rdx ; Restore i
- inc rbx ; i++
- cmp rbx, rdx ; i == m?
- jb @@outr ; No, repeat outer loop
- ;
- pop rbp
- ; *** Stack frame restored ***
- RET ; Return
- BCDUUmul endp
-
- END