DataMuseum.dk

Presents historical artifacts from the history of:

CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦2f4340b3e⟧ TextFile

    Length: 5504 (0x1580)
    Types: TextFile
    Names: »MPDDIV.MAC«

Derivation

└─⟦01b5c9619⟧ Bits:30005906 Microsoft Multiplan v1.05 og HELP
    └─ ⟦this⟧ »MPDDIV.MAC« 

TextFile

;
;
;	Title		Multiple-Precision Decimal Division
;	Name:		MPDDIV
;
;
;	Purpose:	Divide 2 arrays of BCD bytes
;			Quotient := dividend / divisor
;
;	Entry:		Register pair HL = Base address of dividend
;			Register pair DE = Base address of divisor
;			Register B = Lenght of operand in bytes
;
;			  The arrays are unsigned BCD numbers with a
;			  maximum lenght of 255 bytes, ARRAYÆ0Å is the
;			  least significant byte, and ARRAYÆLENGHT-1Å
;			  the most significant byte.
;
;	Exit:		Dividend := dividend / divisor
;			Remainder := Base address in HDEPTR
;			If no errors then
;			  carry := 0
;			ELSE
;			  divide-by-0 error
;			  carry := 1
;			  dividend unchanged
;			  remainder := 0
;
;	Registers used:	AF,BC,DE,HL
;
;	Time:		Assuming the average digit value in the
;			quotient is 5 then the time is approximately
;			(1050 * lenght ^2) + (2297 * lenght) + 390 cycles
;
;	Size:		Program 168 bytes
;			Data    523 bytes
;
;
;
MPDDIV:
	;Save parameters and check for zero lenght
	ld	(dvadr),hl	;Save dividend address
	ld	(dsadr),de	;Save divisor address
	ld	a,b
	ld	(lenght),a	;Save lenght
	or	a		;Test lenght
	jp	z,okexit

	;Zero both dividend buffers
	;  and set up the dividend pointers
	ld	hl,hide1	;HL = address of high dividend 1
	ld	(hdeptr),hl	;High dividend ptr = hide1
	ld	de,hide2	;DE = address of high dividend 2
	ld	(odeptr),de	;Otehr dividend ptr = hide2
	sub	a		;Get 0 to use in filling buffers

	;Fill both buffers with zeros
initlp:
	ld	(hl),a		;Zero byte of hide1
	ld	(de),a		;Zero byte of hide2
	inc	hl
	inc	de
	djnz	initlp

	;Set count to number of digits plus 1
	;  count := (lenght * 2) + 1;
	ld	a,(lenght)	;Extent lenght to 16 bits
	ld	l,a
	ld	h,0
	add	hl,hl		;Lenght * 2
	inc	hl		;Lenght + 1
	ld	(count),hl	;Count := (lenght * 2) + 1

	;Check for divide by zero
	;  logically or entire divisor to see if all bytes are 0
	ld	hl,(dsadr)	;HL = address of divisor
	ld	a,(lenght)
	ld	b,a		;B = lenght in bytes
	sub	a		;Start logical or with 0
dv01:
	or	(hl)		;Or next byte of divisor
	inc	hl
	djnz	dv01
	or	a		;Test for zero divisor
	jr	z,erexit	;Error exit if divisor is 0

	sub	a
	ld	(ndigit),a	;Start next digit at 0

	;Divide by determing how many times divisor can
	;  be subtractes from dividend for each digit
	;  position

dvloop:
	;Rotate left lower dividend and quotient:
	;  high digit of ndigit becoms least significant digit
	;  of quotient (divideend array) and most significant digit
	;  of dividend array goes to high digit of ndigit
	ld	hl,(dvadr)
	call	rlary		;Rotate low dividend

	;If digit count = 0 then we are done
	ld	hl,(count)	;Decrement count by 1
	dec	hl
	ld	(count),hl
	ld	a,h		;Test 16-bit count for 0
	or	l
	jr	z,okexit	;Exit when count = 0

	;
	;Rotate left high dividend, least significant digit
	;  of high dividend becomes high digit of ndigit
	ld	hl,(hdeptr)

	call	rlary		;Rotate high dividend

	;
	;See how many times divisor goes into high dividend
	;  on exit from this loop, high digit of ndigit is next
	;  quotient digit and high dividend is remainder
	sub	a		;Clear number of times initialy
	ld	(ndigit),a

sublp:
	ld	hl,(dsadr)	;HL points to divisor
	ld	de,(hdeptr)	;DE points to current higi dividend
	ld	bc,(odeptr)	;BC points to other high dividend
	ld	a,(lenght)
	ld	(cnt),a		;Loop counter = lenght
	or	a		;Clear carry initialy

inner:
	ld	a,(de)		;Get next byte of dividend
	sbc	a,(hl)		;Subtract divisor
	daa			;Change to decimal
	ld	(bc),a		;Store difference in other dividend
	inc	hl		;Increment to next byte
	inc	de
	inc	bc
	ld	a,(cnt)		;Decrement counter
	dec	a
	ld	(cnt),a
	jr	nz,inner	;Continue through all bytes
	jr	c,dvloop	;Jump when borrow occurs
				;NDIGIT is number of times divisor
				;  goes into original high dividend
				;  high dividend contains remainder
	;Differnce is not negative, so add 1 to
	;  number of successful subtractions
	;  (low digit of ndigit)
	ld	hl,ndigit	;Ndigit = ndigit + 1
	inc	(hl)

	;Exchange pointers, thus making difference new dividend
	ld	hl,(hdeptr)
	ld	de,(odeptr)
	ld	(hdeptr),de
	ld	(odeptr),hl
	jr	sublp		;Continue until difference negative

	;No errors, clear carry
okexit:
	or	a		;Clear carry, valid result
	ret

	;Divide-by-zero error, set carry
erexit:
	scf			;Set carry, invalid result
	ret

	;**************************************************
	;Subroutine: rlary
	;Purpose:    rotate left an array one digit (4 bits)
	;Entry:  HL = base address of array
	;	 low digit of ndigit is digit to rotate through
	;Exit:   Array rotated left through low digit of ndigit
	;Registers used:  AF,BC,DE,HL
	;**************************************************

rlary:
	;Shift ndigit into low of array and
	;  shift array left
	ld	a,(lenght)
	ld	b,a		;B = lenght of array in bytes
	ld	a,(ndigit)	;A = Ndigit

shift:
	rld			;Shift byte left 1 digit (4 bits)
	inc	hl
	djnz	shift		;Continue until all bytes shifted
	ld	(ndigit),a	;Save new next digit
	ret

	;DATA
lenght:	ds	1		;Lenght of arrays in bytes
ndigit:	ds	1		;Next digit in array
cnt:	ds	1		;Counter for subtract loop
dvadr:	ds	2		;Dividend address
dsadr:	ds	2		;Divisor address
hdeptr:	ds	2		;High dividend pointer
odeptr:	ds	2		;Other dividend pointer
count:	ds	2		;Divide loop counter
hide1:	ds	255		;High dividend buffer 1
hide2:	ds	255		;High dividend buffer 2
«eof»