/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:ldiv.s 12.0$ */
/* $ACIS:ldiv.s 12.0$ */
/* $Source: /ibm/acis/usr/src/lib/libc/ca/gen/RCS/ldiv.s,v $ */

	.data
rcsid:	.asciz	"$Header:ldiv.s 12.0$"
	.text

#include "LINKG.h"

 #	Signed divide of two 32 bit integers:
 #	quotient = ldiv(dividend, divisor);
 #
 #	NONSTANDARD LINKAGE:
 #
 #		On entry,	r0 MAY NOT be set: nonstandard linkage.
 #				r2 = dividend
 #				r3 = divisor
 #				r15= link
 #			
 #		On return,	r0 = quotient, for pcc
 #				r2 = quotient, for other compilers
 #				r3 = remainder, for other compilers
 #
 #	Signed remainder:
 #	remainder = lrem$$(dividend, divisor);
 #
 #		Same entry conditions, same exit except:
 #				r0 = remainder, for pcc
 #	
 #	Pascal division:
 #	quotient = ldivmod$$(dividend, divisor);
 #
 #		Same entry conditions, same exit as ldiv except:
 #				r3 = nonnegative remainder for Pascal "mod"
 #
 #	On preserving registers
 #		None of the three routines buys a stack frame, and
 #		lrem and ldivmod have to save registers over their calls
 #		to ldiv.  They use the proper register-save-area locations
 #		for a new stack frame, i.e. below r1.  ldiv uses this also,
 #		to save its r4, but this doesn't conflict.
 #		When made for profiling, each of the three routines also
 #		needs temp storage for r14 and r15 while it calls mcount;
 #		the argument locations below r1 are used for this, and the
 #		lifetime is so short (just over the mcount call) that all
 #		three routines can use the same locations.
 #		
 
.set mq      ,       r10                # multiplier quotient system control reg
 
	.globl	ldiv$$
ldiv$$:					# I have several names
ENTRY(ldiv$$)
	cli	r3,1			# special-case 0 and 1 divisors
	jnh	easy
	st	r4,REG_OFFSET+16(r1)
	mr	r4,r2			# determine no. of divide steps needed 
	shra	r4,16
	bmx	0f			# all 32
	clz	r4,r4			# upper half bitcount
	jnz	1f
	clz	r4,r2			# lower half bitcount,
	ai	r4,16			# augmented
1:	dec	r4,1			# dividing one extra position avoids
					# special-casing 0 and negative nos
	sl	r2,r4			# left-justify dividend
0:	mts	%mq,r2
	get	r0,$here
	a	r0,r4
	a	r0,r4
	brx	r0
        shra	r2,31			# extend dividend sign through hi reg
here: 				# 32 divide steps:
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3		# 8

        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3		# 16

        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3		# 24

        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3
        d       r2,r3		# 32
 
	bc0x	1f		# if carry-0, no correction needed
	mfs	%mq,r0		# (retrieve the quotient)
	a	r2,r3		# correction: complete the final restore

1:	sl	r0,r4		# sign-extend the (32-r4)-bit quotient
	sra	r0,r4
	cis     r2,0		# adjust quotient up, remainder down ...
	je      9f		# if remainder's nonzero and ...
        c       r2,r3
        je      7f              # remainder == divisor,
        cis	r0,0
        jnl	9f		# or quotient is negative.
7:	ai      r0,r0,1
        s       r2,r3
 
        #return to the calling routine
9:	mr	r3,r2
	mr	r2,r0 
	brx	r15
	l	r4,REG_OFFSET+16(r1)

			# divisor is zero (cc low) or one (cc equal).

easy:	lis	r0,0		# quotient = dividend = r2
	berx	r15		
	lis	r3,0		# remainder = 0
	
        		# zero.  this should trap.
 # NOTE:
 #	This trap instruction is very specific!  When the kernel
 #	receives a trap, it checks for this exact instruction to
 #	distinguish a division by zero from a break-point.  See
 #	code in trap.c, and be sure to fix if this ever changes!
 #
	ti	2,r3,0		# trap on equal
	lis	r2,1		# one quotient
	mr	r0,r2		# pcc quotient
	brx	r15
	lis	r3,0		# remainder = 0

	.globl	lrem$$
lrem$$: 
ENTRY(lrem$$)
	st	r15,REG_OFFSET+60(r1)	# remainder's just like divide
	bali	r15,ldiv$$
	l	r15,REG_OFFSET+60(r1)
	mr	r2,r3			# except for losing quotient info
	brx	r15
	mr	r0,r3

	.globl	ldivmod$$
ldivmod$$:
ENTRY(ldivmod$$)
	st	r15,REG_OFFSET+60(r1)
	balix	r15,ldiv$$
	st	r3,REG_OFFSET+12(r1)
	l	r15,REG_OFFSET+60(r1)
	cis	r3,0			# mod is same as remainder if >=0;
	bnmr	r15
	l	r0,REG_OFFSET+12(r1)
	brx	r15			# else it's made positive (if divisor's
	a	r3,r0			# positive; else undefined anyway)
	TTNOFRM 
