home *** CD-ROM | disk | FTP | other *** search
- title BCDASM -- Copyright 1997, Morten Elling
- subttl Signed multiplication of packed signed BCDs
-
- include model.inc
- include modelt.inc
- include bcd.ash
-
- ;
- ; Convert packed BCD byte to binary in AL
- ; Changes AH
- ;
- @PackedBCDToBin MACRO reg8
- ifdifi <reg8>, <al>
- mov al, reg8
- endif
- ifdifi <reg8>, <ah>
- mov ah, al
- endif
- and al, 0fh ;; Convert packed to unpacked BCD
- @shr ah, 4
- aad ;; Then to binary: ax = ah*10 + al
- endm
-
- ;
- ; Convert binary byte to packed BCD in AL
- ; Changes AH
- ;
- @BinToPackedBCD MACRO reg8
- ifdifi <reg8>, <al>
- mov al, reg8
- endif
- aam ;; ah = al DIV 10, al = al MOD 10
- @shl ah, 4 ;; Convert unpacked to packed BCD
- or al, ah
- endm
-
-
- @CODESEG
-
- ;//////////////////////////////////////////////////////////////////////
- ;// Name bcdImul
- ;// Desc Signed multiplication of two packed signed BCDs.
- ;//
- ;//
- ;// Entry Passed args
- ;// Exit Double-size packed signed BCD product returned to
- ;// destination _replacing_ the multiplicand.
- ;// Acc undefined.
- ;//
- ;// Note Both BCD operands must be defined as double-size, e.g.
- ;// mplic dt 456512,?
- ;// mplier dt 888644,?
- ;// where the high-order is undefined (because the result
- ;// is returned as double-precision and the multiplier
- ;// provides temporary work space for this procedure).
- ;//
- ;// Destination and source may be the same.
- ;//
- ;// Note This procedure was inspired by:
- ;// MPMUL1.ASM by Ray Duncan * PC Magazine Vol. 8 no. 20
- ;// Copyright (C) 1989 Ziff Davis Communications
- ;//
- ;//
- ;// ToDo Rewrite loop to skip non-significant zeros.
-
- bcdImul proc
- arg dstBCD :dataptr, \ ; Addr of multiplicand
- srcBCD :dataptr, \ ; Addr of 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
- mov rbx, [srcsz]
- @LDS rsi, [dstBCD]
- @LES rdi, [srcBCD]
- mov rcx, rbx
- shr rcx, 1
- add rdi, rcx
- rep movsb
-
- ; ----- Zero destination
- @LES rdi, [dstBCD]
- mov rcx, rbx
- sub rax, rax
- rep stosb
-
- ; ----- Fix pointers
- @LDS rsi, [srcBCD] ; u[0]
- sub rdi, rbx ; w[0]
- shr rbx, 1
- lea rbp, [rsi+rbx] ; v[0]
- ; *** No stack frame ***
- lea rdx, [rbx-1] ; Byte size, excl. sign byte
-
- ; ----- Perform the multiplication
- ;
- ; for (i=0; i<m; i++) {
- ; k=0;
- ; for (j=0; j<m; j++) {
- ; t = u[j] * v[i] + w[i+j] + k;
- ; w[i+j] = t % 100;
- ; k = t / 100;
- ; }
- ; w[i+m] = k;
- ; }
- ;
- ; Usage:
- ; ds:rsi = u[0] base address of multiplier
- ; ds:rbp = v[0] base address of multiplicand
- ; es:rdi = w[0] base address of product
- ; rbx = i index for outer loop
- ; rcx = j index for inner loop
- ; rdx = m operand length in bytes
- ; ah/dh = k remainder of partial products
- ;
- 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
- ;
- ; Since we are going to multiply and divide later on,
- ; we'll convert the packed BCDs to binary before doing
- ; the math in binary, then convert back to BCD.
- ; Note that the remainder (ah/dh register) is a binary
- ; number, not a BCD.
- ;
- ife @isUse32
- xchg rbx, rcx
- mov al, [rsi+rbx] ; Get u[j]
- xchg rbx, rcx
- xchg rsi, rbp
- mov dl, [rsi+rbx] ; Get v[i]
- xchg rsi, rbp
- else
- mov al, [rsi+rcx]
- mov dl, [rbx+rbp]
- endif
- @PackedBCDToBin al
- xchg al, dl
- @PackedBCDToBin al
- mov ah, dl
- push rax
- ;
- add rbx, rcx
- mov al, @ES [rdi+rbx] ; Get w[i+j]
- @PackedBCDToBin al
- mov dl, al
- pop rax
- mul ah ; t = u[j] * v[i]
- add al, dl ; + w[i+j]
- adc ah, 0
- add al, dh ; + k
- adc ah, 0
- ;
- mov dl, 100d
- div dl
- mov dh, al
- @BinToPackedBCD ah
- mov @ES [rdi+rbx], al ; w[i+j] = t mod 100
- mov ah, dh ; k = t div 100
- sub rbx, rcx ; Restore i
- ;
- pop rdx ; Restore m
- inc rcx ; j++
- cmp rcx, rdx ; j == m?
- jb @@innr ; No, repeat inner loop
- ;
- @BinToPackedBCD ah
- add rbx, rdx
- mov @ES [rdi+rbx], al ; w[i+m] = k
- sub rbx, rdx ; Restore i
- inc rbx ; i++
- cmp rbx, rdx ; i == m?
- je sh @@zr
- jmp @@outr ; No, repeat outer loop
-
- ; ----- Check for zero result
- @@zr: pop rbp
- ; *** Stack frame restored ***
- mov rcx, rdx
- add rcx, rcx
- inc rcx
- sub rax, rax ; Zero acc
- repz scasb
- rcr ah, 1 ; 0 if product is zero, else 80h
-
- ; ----- Determine product's sign
- add rdi, rcx ; Point to sign byte
- add rsi, rdx
- inc rdx
- mov al, [rsi] ; Get sign of multiplier
- add rsi, rdx
- xor al, [rsi] ; XOR with sign of multiplicand
- and al, ah ; Zero if product is zero, else 80h
- stosb ; Store sign
- RET
- bcdImul endp
-
- END