home *** CD-ROM | disk | FTP | other *** search
- title BCDASM -- Copyright 1997, Morten Elling
- subttl Convert packed signed BCDs to/from signed binary
-
- include model.inc
- include modelt.inc
- include bcd.ash
-
- @CODESEG
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name bcdP2b
- ;// Desc Convert packed signed BCD to signed binary.
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Signed binary value returned to destination.
- ;// Acc undefined.
- ;//
- ;// Note The parameter [dstsz] which indicates the byte size
- ;// of the binary destination, must be even-sized and
- ;// large enough to ensure no overflow during the
- ;// conversion. A qword (8 bytes) is required to convert
- ;// a tbyte (10 bytes) source BCD.
- ;//
- ;// ToDo Return error if overflow/loss of significance/bad size.
-
- bcdP2b proc
- arg dstBIN :dataptr, \ ; Addr of binary destination
- dstsz :@uint, \ ; Byte size of dest. (see note)
- srcBCD :dataptr, \ ; Addr of source BCD
- srcsz :@uint ; Byte size of src
- @uses ds,es,rsi,rdi,rbx,rcx,rdx,rax
- ;.
- @cld ; String ops forward
- @LDS rsi, [srcBCD]
- @LES rdi, [dstBIN]
-
- ; ----- Zero destination
- mov rcx, [dstsz]
- sub al, al ; Zero al
- rep stosb
-
- ; ----- Skip non-significant zeros in src
- mov rcx, [srcsz]
- dec rcx
- add rsi, rcx ; -> Sign byte
- @@skpz: dec rsi ; Work towards LSB in source
- cmp al, [rsi] ; BCD digit pair zero?
- loopz @@skpz ; Yes, keep going
- jnz sh @@add_digits ; No, jump into loop
- jmp sh @@end ; Exit if src is zero
-
-
- ; ----- Multiply destination by 100
- @@loop_top:
- mov rcx, [dstsz]
- shr rcx, 1 ; No. of words to process
- sub rbx, rbx ; Clear hi-order
- @@x100: mov AX, @ES [rdi] ; Get a binary word
- mov rdx, 100d ; Set up to multiply
- mul DX ; by 100, product in dx:ax
- add AX, BX ; Add hi-order from prev. loop
- adc DX, 00h ; Increment dx if carry
- stosW ; Store AX to destination
- mov BX, DX ; Save hi-order for next loop
- loop @@x100 ; Loop until done
- ; test DX, DX ; Possible modification:
- ; jnz sh @@err ; error if loss of significance
-
- ; ----- Add in next BCD digit pair
- @@add_digits:
- mov rdi,@uiptr [dstBIN] ; Point to destination[0]
- mov al, [rsi] ; Get two digits of source
- mov ah, al ; Make unpacked BCD
- and al, 0fh
- @shr ah, 4
- aad ; Convert to binary in ax
- add @ES [rdi], AX ; Add to destination (no carry
- ; since dest. is a multiple of 100, and ax is max. 99)
- dec rsi ; Work towards LSB of src
- cmp rsi, @uiptr [srcBCD]
- jae @@loop_top
-
-
- ; ----- The number has been converted, now test source's sign.
- ; If positive, we're done, otherwise negate the destination
- ; to make two's complement.
-
- add rsi, [srcsz]
- test @bptr [rsi], 80h
- jz sh @@end ; Exit if source positive
- mov rcx, [dstsz]
- shr rcx, 1 ; No. of words to process
- clc ; Clear carry in
- @@ngt: mov rax, 0 ; Subtract from zero
- sbb rax, @ES [rdi] ; and propagate the carry
- stosW ; Store AX to destination
- loop @@ngt ; Loop until done
-
- @@end: RET
- bcdP2b endp
-
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name bcdB2p
- ;// Desc Convert signed binary to packed signed BCD.
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Acc > 0: Packed signed BCD returned to destination
- ;// Acc = 0: Error (bad srcsz)
- ;//
- ;// Note The parameter [srcsz] which indicates the byte size of
- ;// the binary source must be even (min. 2), and contain
- ;// no more significant bits than can be converted to
- ;// packed BCD format without overflow (for example, max.
- ;// 59 significant bits of a qword, plus sign bit).
- ;//
- ;// ToDo Return error if overflow/loss of significance.
-
- MAX_SIZEOF_BIN = 20h
-
- bcdB2p proc
- arg dstBCD :dataptr, \ ; Addr of destination BCD
- dstsz :@uint, \ ; Byte size of dst
- srcBIN :dataptr, \ ; Addr of source binary
- srcsz :@uint ; Byte size of src (even, min. 2)
- local @@src :byte :MAX_SIZEOF_BIN ; Work buffer
- @uses ds,es,rsi,rdi,rbx,rcx,rdx
- ;.
- ; ----- Check size parameter
- mov rax, [srcsz]
- shr rax, 1
- jbe sh @@err
- add rax, rax
- cmp rax, MAX_SIZEOF_BIN
- jbe sh @@cpy
- @@err: sub rax, rax
- jmp @@ret
-
- ; ----- Copy src to local storage
- @@cpy: xchg rbx, rax ; rbx = size of src
- @cld ; String ops forward
- @LDS rsi, [srcBIN]
- @LDSEGM es, ss, rdi
- lea rdi, [@@src]
- mov rcx, rbx
- rep movsb
-
- ; ----- Zero destination
- @LES rdi, [dstBCD]
- mov rcx, [dstsz]
- sub al, al
- rep stosb
-
- ; ----- Load src pointer
- test @bptr [rsi-1], 80h ; Test src's sign
- if @isStackFar
- @LDSEGM ds, ss, rsi
- endif
- lea rsi, [@@src]
- jns sh @@cvt1 ; sf = 0 if positive
-
- ; ----- Negate source to get abs. value
- mov rcx, rbx
- ; cf=0 after 'test'
- @@neg: mov al, 00h
- sbb al, [rsi]
- mov [rsi], al
- inc rsi
- loop @@neg
- ; Set destination negative
- or @bptr @ES [rdi-1], 80h
- ;
- @@cvt1: mov rdi, @uiptr [dstBCD]
-
-
- ; ----- Perform the conversion by repeatedly dividing
- ; the binary source by 100 to extract 2 BCD digits
- ; on each loop (uses shift-and-subtract algorithm)
- @@looptop:
- ; Entry here: rdi -> destination
- mov rdx, rbx ; No. of bytes in source
- @shl rdx, 3 ; * 8 = no. of bits in source
- sub rax, rax ; Clear remainder
- lea rsi, [@@src] ; Addr of source
- @@shl: dec rdx ; Decrement bit counter
- js sh @@stor ; Loop done when < 0
- mov rcx, rbx ; Loop count =
- shr rcx, 1 ; no. of source words, cf=0
- @alignn
- @@shm: rcl @wptr [rsi], 1 ; Rotate word thru carry left
- inc rsi ; Step
- inc rsi ; source pointer
- loop @@shm ; Shift whole source left
- rcl rax, 1 ; Accumulate remainder in acc
- ;
- sub rsi, rbx ; Point to @@src[0]
- cmp rax, 100d ; Compare acc against divisor
- jb @@shl ; Not yet
- sub rax, 100d ; One hit
- inc @bptr [rsi] ; Update quotient (in low source)
- jmp @@shl ; And keep going
-
- ; ----- Store 2 BCD digits (acc = source MOD 100)
- @@stor: aam ; Convert ax to unpacked BCD
- @shl ah, 4 ; Convert un- to packed
- or al, ah ; Pack two BCD digits in al
- stosb ; Store al to destination
-
- ; ----- Check if quotient is zero
- ; rsi -> @@src[0]
- mov rcx, rbx
- sub al, al
- dec rsi
- @@qzr: inc rsi
- or al, [rsi]
- loopz @@qzr
- jnz @@looptop ; Keep going until quotient = 0
- mov rax, 1
- @@ret: RET
- bcdB2p endp
-
- END