home *** CD-ROM | disk | FTP | other *** search
- title BCDASM -- Copyright 1997, Morten Elling
- subttl Perform a digit left-shift (MUL 10^n) on a packed BCD
-
- include model.inc
- include modelt.inc
- include bcd.ash
-
- @CODESEG
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name bcdShl
- ;// Desc Perform a digit left-shift of a packed signed BCD.
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Packed signed BCD returned to destination.
- ;// Accumulator (and cf,zf flags) determined:
- ;// Acc = 0: Result is zero (zf=1)
- ;// Acc > 0: Result is non-zero (zf=0)
- ;//
- ;// If any significant digits were shifted out
- ;// of the high-order, cf=1, else cf=0
- ;// (sign and overflow flags should be ignored).
- ;//
- ;// Note A 10-byte BCD holds 18 BCD digits ( 2*(10-1) ).
- ;//
- ;// Note This procedure shifts one digit, i.e. one nibble,
- ;// per shift count effectively performing a
- ;// MUL 10-to-the-n'th-power operation.
- ;// Zeros are shifted into the low-order. The sign of
- ;// the destination is changed only if the result is
- ;// zero. If the shift count is larger than or equals
- ;// the number of digits in the BCD, the result will
- ;// be zero.
-
- bcdShl proc
- arg dstBCD :dataptr, \ ; Addr of BCD
- dstsz :@uint, \ ; Byte size of BCD
- count :@uint ; No. of BCD digits to shift
- @uses ds,es,rsi,rdi,rbx,rcx,rdx
- ;.
- ; ----- Load registers. Instead of a local variable, the AH
- ; register is used to flag if any significant digits
- ; are shifted out of the high-order. The 80x86 SHL
- ; instruction, however, flags only the last bit shifted.
-
- @cld ; String ops forward
- @LDS rsi, [dstBCD]
- @LES rdi, [dstBCD]
- mov rdx, [count]
- mov rbx, [dstsz]
- dec rbx ; # bytes, excl. sign byte
- mov ah, 00h
-
- ; ----- Handle special cases
- test rdx, rdx ; If under-sized shift,
- jz sh @@chkz ; check for zero result
- mov rcx, rdx ; Shift count
- shr rcx, 1 ; Make # bytes
- jz sh @@odd ; If zero, shift count = 1
- cmp rcx, rbx ; If over-sized shift,
- jae sh @@clear ; zero-fill
-
- ; ----- Shift the even digit pairs
- add rdi, rbx
- dec rdi ; Point to byte before sign
- mov rsi, rdi
- sub rsi, rcx ; Point to source
- push rcx ; Save count/2
- neg rcx ; - Count/2
- add rcx, rbx ; + Field width = # bytes to shift
- push rcx
- push rdi
- sub al, al ; Zero al
- std ; Auto-decrement index reg.s
- repz scasb ; Determine
- sbb ah, ah ; significance flag
- pop rdi
- pop rcx
- rep movsb ; Shift left (rsi < rdi)
- pop rcx ; Count/2 = # bytes to zero
- rep stosb ; Zero low-order of number
- inc rdi ; Point to LSB
- cld ; Auto-increment index reg.s
-
- ; ----- Prepare for odd digit
- shr rdx, 1 ; Is there an odd digit?
- jnc sh @@chkz ; No, see if result is zero
- add rdi, rdx ; Point index reg.s
- mov rsi, rdi ; to target
- mov rcx, rdx ; Get # bytes shifted
- neg rcx ; Negate
- @@odd: add rcx, rbx ; = # bytes to 'odd-shift'
-
- ; ----- Shift the odd digit
- sub dl, dl ; Zero dl
- mov dh, ah ; Temporary signif. flag
- @@lt: lodsb ; Get a byte
- or dh, al ; Update signif. flag
- @shl rax, 4 ; Shift acc left one nibble
- or al, dl ; Combine with prev. digit
- stosb ; Store al to destination
- mov dl, ah ; Save high-order
- and dl, 0fh ; for next loop
- loop @@lt ; Loop until done
- sub rdi, rbx ; Point to LSB
- mov ah, dh ; Copy signif. flag to ah
-
- ; ----- Check if result is zero
- @@chkz: ; rdi -> LSB
- mov rcx, rbx ; REP count
- sub al, al ; Zero al
- repz scasb ; See if all zeros (cf=0 if zero)
- rcr al, 1 ; Set to 80h if result non-zero
- add rdi, rcx ; Point to sign byte
- jmp sh @@sign
-
- ; ----- Shift count > # digits: zero-fill
- @@clear: ; rdi -> LSB
- mov rcx, rbx ; REP count
- sub al, al ; Zero al
- repz scasb ; See if all zeros
- sbb ah, ah ; ah = significance flag
- add rdi, rcx ; Point
- sub rdi, rbx ; back to LSB
- mov rcx, rbx ; REP count
- rep stosb ; Whip it
-
- ; ----- Determine sign and return value
- @@sign: ; rdi -> sign byte
- ; al = 0 if result zero, else 80h
- ; ah = significance flag (0 or > 0)
- neg ah ; If zero,
- sbb dl, dl ; set dl 0, else 0FFh
- and @ES [rdi], al ; Clear sign bit if appropriate
- rol al, 1 ; Set acc 0 or 1
- and rax, 1 ; Determine acc and zero flag
- ror dl, 1 ; Determine carry flag
- RET ; Return acc, zf and cf
- bcdShl endp
-
- END