home *** CD-ROM | disk | FTP | other *** search
- COMMENT ~
- MULTIDGT.ASM -- Multidigit Arithmetic Procedures
-
- From `BLUEBOOK of ASSEMBLY ROUTINES for the IBM PC & XT'
- by Christopher L. Morgan
- Copyright (C) 1984 by The Waite Group, Inc.
-
- Purpose: These routines perform addition, subtraction, multiplication,
- and division upon multidigit integers (16-bit).
-
- Contents:
- ---------
- MBINADD -- Multidigit binary addition
- MBINDIV -- Multidigit binary division
- MBINMUL -- Multidigit binary multiplication
- MBINSUB -- Multidigit binary subtraction
-
- >>>> See MULTIDGT.DOC for complete descriptions of these routines. <<<<<
- _____________________________________________________________________________
- ~
- EXTRN STDIN:FAR,STDOUT:FAR
- ;______________________________________________________________________________
- ;
- ; Needs a constant named ISIZE
- DATAS SEGMENT PUBLIC
- TBUFF DB 5 DUP(?)
- DATAS ENDS
- ;______________________________________________________________________________
- ;
- CODES SEGMENT
-
- PUBLIC MBINADD,MBINSUB,MBINMUL,MBINDIV
-
- ASSUME CS:CODES,DS:DATAS
- ;____________________________I/O ROUTINES______________________________________
- ;
- MBINADD
- ;Routine to add multidigit binary numbers
- ;
- MBINADD PROC FAR
- PUSH SI ;Save registers
- PUSH DI
- PUSH BX
- PUSH CX
- PUSH AX
- MOV CX,ISIZE ;Get the # of 16-bit "digits"
- CLC ;Clear the carry in
- MBINADD1:
- MOV AX,[SI] ;Get "digit" from first number
- INC SI ;Point to next "digit"
- INC SI
- ADC AX,[DI] ;Add "digit" from second num
- INC DI ;Point to next "digit"
- INC DI ;Move resulting
- MOV [BX],AX ; "digit" into place
- INC BX ;Point to next "digit"
- INC BX
- LOOP MBINADD1 ;Loop through all "digits"
- POP AX ;Restore registers
- POP CX
- POP BX
- POP DI
- POP SI
- RET
-
- MBINADD ENDP
- ;______________________________________________________________________________
- ;Routine to subtract multidigit binary numbers
- ;
- MBINSUB PROC FAR
- PUSH SI ;Save registers
- PUSH DI
- PUSH BX
- PUSH CX
- PUSH AX
- MOV CX,ISIZE ;Get the # of 16-bit "digits"
- CLC ;Clear the carry in
- MBINSUB1:
- MOV AX,[DI] ;Get "digit" from second num
- INC DI ;Point to next "digit"
- INC DI
- SBB AX,[SI] ;Subtract "digit" of first num
- INC SI ;Point to next "digit"
- INC SI ;Move resulting
- MOV [BX],AX ; "digit" into place
- INC BX ;Point to next "digit"
- INC BX
- LOOP MBINADD1 ;Loop through all "digits"
- POP AX ;Restore registers
- POP CX
- POP BX
- POP DI
- POP SI
- RET
- MBINSUB ENDP
- ;______________________________________________________________________________
- ;Routine to multiply multidigit binary numbers
- ;
- MBINMUL PROC FAR
- PUSH SI ;Save registers
- PUSH DI
- PUSH BX
- PUSH CX
- PUSH AX
- ;
- ;Clear result buffer
- PUSH BX ;Save result pointer BX
- MOV AX,0 ;Get a zero
- MOV CX,2*ISIZE ;Double precision for this num
- CLD ;Forward direction
- MBINMUL1:
- MOV [BX],AX ;Clear the "digit"
- INC BX ;Point to next "digit"
- INC BX
- LOOP MBINMUL1 ;Loop through all "digits"
- POP BX ;Restore result pointer BX
- MOV CX,ISIZE ;Get the num of 16-bit "digits"
- MBINMUL2:
- PUSH CX ;Save outer loop count
- MOV DX,[SI] ;Get "digit" from first number
- INC SI ;Point to next "digit"
- INC SI
- PUSH BX ;Save regs during inner loop
- PUSH DI
- MOV CX,ISIZE ;Get the num of 16-bit "digits"
- MBINMUL3:
- PUSH CX ;Save inner loop count
- PUSH DX ;Save multiplier "digit"
- MOV AX,[DI] ;Get "digit" from second num
- INC DI ;Point to next "digit"
- INC DI
- MUL DX ;Multiply
- ADD [BX],AX ;Add lower "digit" to result
- INC BX ;Point to next "digit"
- INC BX
- ADC [BX],DX ;Add upper part to result
- POP DX ;Restore multiplier
- POP CX ;Restore inner loop count
- LOOP MBINMUL3 ;Loop through all "digits" of
- ; second
- POP DI ;Restore registers
- POP BX
- INC BX ;Shift by one "digit"
- INC BX
- POP CX ;Restore outer loop count
- LOOP MBINMUL3 ;Loop through all "digits" of
- ; first
- POP AX ;Restore registers
- POP CX
- POP BX
- POP DI
- POP SI
- RET
- MBINMUL ENDP
- ;______________________________________________________________________________
- ;Routine to divide multidigit binary numbers
- ; This routine uses 4 local subroutines: DIVCMP,DIVSAL,DIVSLR,DIVSUB,QUOTSHL
- ;
- ;---------------------------LOCAL SUBROUTINES----------------------------------
- ;Local subroutine to compare divisor against dividend
- ;
- DIVCMP PROC NEAR
- PUSH SI ;Save registers
- PUSH DI
- PUSH CX
- STD ;Backward direction
- ADD SI,4*ISIZE-2 ;Point to end of temp divisor
- ADD DI,4*ISIZE-2 ;Point to end of quotient
- MOV CX,2*ISIZE ;Count for double precision
- REPZ CMPSW ;Compare "digit" by "digit"
- POP CX ;Restore registers
- POP DI
- POP SI
- RET
- DIVCMP ENDP
- ;------------------------------------------------------------------------------
- ;Local subroutine to arithmetically shift divisor left
- ;
- DIVSAL PROC NEAR
- PUSH SI ;Save registers
- PUSH CX
- MOV CX,2*ISIZE ;Set counter
- CLC ;Clear carry in
- DIVSAL1:
- RCL WORD PTR [SI],1 ;Shift one word by one bit
- INC SI ;Point to next word
- INC SI
- LOOP DIVSAL1 ;Loop through entire divisor
- POP CX ;Restore registers
- POP SI
- RET
- DIVSAL ENDP
- ;------------------------------------------------------------------------------
- ;Local subroutine to logically shift divisor right
- ;
- DIVSLR PROC NEAR
- PUSH SI ;Save registers
- PUSH CX
- ADD SI,4*ISIZE-2 ;Point to end of temp divisor
- MOV CX,2*ISIZE ;Count for double precision
- CLC ;Clear carry in
- DIVSLR1:
- RCR WORD PTR [SI],1 ;Rotate one word by one bit
- DEC SI ;Point to next word
- DEC SI
- LOOP DIVSLR1 ;Loop through entire divisor
- POP CX ;Restore registers
- POP SI
- RET
- DIVSLR ENDP
- ;------------------------------------------------------------------------------
- ;Local subroutine to subtract shifted divisor from divident
- ;
- DIVSUB PROC NEAR
- PUSH SI ;Save registers
- PUSH DI
- PUSH CX
- CLC ;Cleary carry in
- MOV CX,2*ISIZE ;Set count for double precision
- DIVSUB1:
- MOV AX,[SI] ;Get word from shifted divisor
- INC SI ;Point to next word
- INC SI
- SBB [DI],AX ;Subtract from word of dividend
- INC DI ;Point to next word
- INC DI
- LOOP DIVSUB1 ;Loop through all words
- POP CX ;Restore registers
- POP DI
- POP SI
- RET
- DIVSUB ENDP
- ;------------------------------------------------------------------------------
- ;Local subroutine to shift quotient left
- ;
- QUOTSHL PROC NEAR
- PUSH BX ;Save registers
- PUSH CX
- MOV CX,ISIZE ;Count for single precision
- QUOTSHL1:
- RCL WORD PTR [BX],1 ;Shift wrd of quotnt left once
- INC BX ;Point to next word
- INC BX
- LOOP QUOTSHL1 ;Loop through entire quotient
- POP CX ;Restore registers
- POP BX
- RET
-
- DIVSHL ENDP
- ;------------------------------------------------------------------------------
- ; >>>>> End of Local Subroutines
- ;
- ;Routine to divide multidigit binary numbers
- ;
- MBINDIV PROC FAR
- PUSH SI ;Save registers
- PUSH DI
- PUSH BX
- PUSH CX
- PUSH AX
- ;
- ;Put single precision divisor into double precision location
- PUSH DI ;Save dividend pointer
- LEA DI,TEMPDIV ;Point SI to temporary divisor
- MOV CX,1 ;Initialize shift count to 1
- ;
- ;Normalize divisor
- MBINDIV1:
- TEST MSBDIV,8000H ;Test MSB of divisor
- JNZ MBINDIV2 ;Exit if normalized
- CALL DIVSAL ;Arith shift left, if not
- INC CX ;Count the shift
- JMP MBINDIV1 ;Keep looping till normalized
- ;
- ;Compare, subtract, shift loop
- MBINDIV2:
- CALL DIVCMP ;Compare divisor with dividend
- JA MBINDIV3 ;Skip if too large
- CALL DIVSUB ;Else subtract
- STC ;New bit of quotient is in 1
- JMP MBINDIV4 ;Jump to end of loop
- MBINDIV3:
- CLC ;New bit of quotient is in 0
- MBINDIV4:
- CALL QUOTSHL ;Shift bit into the quotient
- CALL DIVSLR ;Logic shift divisor right once
- LOOP MBINDIV2 ;Loop for next digit
- POP AX ;Restore registers
- POP CX
- POP BX
- POP DI
- POP SI
- RET
- MBINDIV ENDP
- ;______________________________________________________________________________
- CODES ENDS
- ;
- END
- ;______________________________________________________________________________
- ;>>>>> Physical EOF MULTIDGT.ASM <<<<<