home *** CD-ROM | disk | FTP | other *** search
-
- ; *******************************************************
- ; * *
- ; * Turbo Pascal Runtime Library Version 7.0 *
- ; * Longint Division *
- ; * *
- ; * Copyright (C) 1989-1993 Norbert Juffa *
- ; * *
- ; *******************************************************
-
- TITLE LDIV
-
-
- CODE SEGMENT BYTE PUBLIC
-
- ASSUME CS:CODE
-
- ; Externals
-
- EXTRN HaltError:NEAR
-
- ; Publics
-
- PUBLIC LongDiv
-
- ;-------------------------------------------------------------------------------
- ; LongDiv divides two LONGINT numbers, the dividend and the divisor, resulting
- ; in a quotient and a remainder. The routine checks for an attempted division
- ; by zero. In that case, it returns to the error handler with error code C8h.
- ;
- ; INPUT: DX:AX dividend
- ; BX:CX divisor
- ;
- ; OUTPUT: DX:AX quotient of division of dividend by divisor
- ; BX:CX remainder of division of dividend by divisor
- ;
- ; DESTROYS: AX,BX,CX,DX,SI,DI,Flags
- ;-------------------------------------------------------------------------------
-
- LongDiv PROC FAR
- XOR DX, BX ; SF set if quotient negative
- PUSHF ; save flag
- XOR DX, BX ; dividend negative ?
- PUSHF ; SF set if dividend (&remaindr) negative
- JNS $dividnd_pos ; no, ->
- NOT DX ; negate
- NEG AX ; dividend
- SBB DX, -1 ; in DX:AX
- $dividnd_pos:OR BX, BX ; divisor negative ?
- JNS $divisor_pos ; no, ->
- NOT BX ; negate
- NEG CX ; divisor
- SBB BX, -1 ; in BX:CX
- $divisor_pos:JNZ $big_divisor ; divisor > 65535
- CMP DX, CX ; only one division needed ?
- JB $one_div ; yes, one division sufficient
- JCXZ $zero_divide ; divisor is zero, error
- DB 087h, 0C3h ; XCHG AX, BX ; save lo-word of dividend in BX
- XCHG AX, DX ; get hi-word of dividend, load DX with 0
- DIV CX ; hi-word of quotient in AX
- XCHG AX, BX ; BX = quot. hi-word, AX = divid. lo-word
- $one_div: DIV CX ; AX = quotient lo-word
- MOV CX, DX ; CX = remainder lo-word,
- MOV DX, BX ; DX = quotient hi-word
- XOR BX, BX ; clear remainder hi-word (rem. in BX:CX)
- JMP $set_sign ; make signed
- $big_divisor:PUSH DX ; save
- PUSH AX ; dividend
- MOV SI, CX ; save
- MOV DI, BX ; divisor
- OR BH, BH ; shift more than 8 bits ?
- JZ $scale_down ; no, do bit shifts
- MOV CL, CH ; shift
- MOV CH, BL ; divisor
- MOV BL, BH ; and
- XOR BH, BH ; dividend
- MOV AL, AH ; 8 bits
- MOV AH, DL ; right
- MOV DL, DH ; each
- MOV DH, BH ;
- $scale_down: SHR DX, 1 ; scale
- RCR AX, 1 ; divisor
- SHR BX, 1 ; and
- RCR CX, 1 ; dividend until
- JNZ $scale_down ; divisor < 65536
- DIV CX ; compute quotient
- MOV CX, AX ; save quotient
- MOV BX, AX ; save quotient
- MUL DI ; quotient * divisor hi-word
- XCHG AX, CX ; save result in CX, get quotient from AX
- MUL SI ; quotient * divisor lo-word
- ADD DX, CX ; DX:AX = quotient * divisor
- POP CX ; get dividend lo-word
- SUB CX, AX ; divid. lo-word - (quot.*divisor)lo-word
- MOV AX, BX ; get quotient
- POP BX ; restore dividend hi-word
- SBB BX, DX ; subtract divisor * quot. from dividend
- JNB $remaindr_ok ; ok if remainder > 0
- ADD CX, SI ; compute
- ADC BX, DI ; correct remaindr (0.095% of all cases)
- DEC AX ; adjust quotient
- $remaindr_ok:XOR DX, DX ; clear hi-word of quotient (AX ≤ 7FFFh)
- $set_sign: POPF ; remainder negative ?
- JNS $pos_remaind ; no, ->
- NOT BX ; negate
- NEG CX ; remainder
- SBB BX, -1 ; in BX:CX
- $pos_remaind:POPF ; result negative ?
- JNS $pos_result ; no, ->
- NOT DX ; negate
- NEG AX ; quotient
- SBB DX, -1 ; in DX:AX
- $pos_result: RET ; done, return & pop arguments
- $zero_divide:ADD SP, 4 ; remove saved flags from stack
- MOV AX, 0C8H ; load error code 200, "division by zero"
- JMP HaltError ; execute error handler
- LongDiv ENDP
-
- ALIGN 4
-
- CODE ENDS
-
- END