1: /*
   2:  * Copyright (c) 1987 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifdef LIBC_SCCS
   8:         <@(#)ldiv.s	2.4 (GTE) 12/26/92\0>
   9:         .even
  10: #endif LIBC_SCCS
  11: 
  12: /*
  13:  * ldiv(lhs, rhs)
  14:  *	long	lhs, rhs;
  15:  *
  16:  * 32-bit "/" routine.  Calls to ldiv are generated automatically by the C
  17:  * compiler.
  18:  */
  19: #include "DEFS.h"
  20: 
  21: #if !defined(KERNEL)
  22: /*
  23:  * Ldiv for floating point hardware.  Check for divide by zero.  Don't want
  24:  * floating divide trap in integer math.
  25:  */
  26: ASENTRY(ldiv)
  27:         tst     6(sp)           / divide by zero check
  28:         bne     1f
  29:         tst     8.(sp)
  30:         bne     1f
  31:         mov     2(sp),r0
  32:         mov     4(sp),r1        / return lhs
  33:         rts     pc
  34: 1:
  35:         setl
  36:         movif   2(sp),fr0       / fr0 = lhs
  37:         movif   6(sp),fr1       / fr1 = rhs
  38:         divf    fr1,fr0         / fr0 /= rhs
  39:         movfi   fr0,-(sp)
  40:         mov     (sp)+,r0        / return result
  41:         mov     (sp)+,r1
  42:         seti
  43:         rts     pc
  44: #else
  45: /*
  46:  * Ldiv for fixed point hardware.
  47:  */
  48: #define negl(high, low) neg     high; \
  49:                         neg     low; \
  50:                         sbc     high    / high -= (low != 0)
  51: 
  52: ASENTRY(ldiv)
  53:         mov     r2,-(sp)        / faster than csv/cret ...
  54:         mov     r3,-(sp)
  55:         mov     r4,-(sp)
  56:         mov     14.(sp),r3      / r3 = loint(rhs)
  57:         sxt     r4              / r4 = sign(rhs)
  58:         bpl     1f              / if (int)loint(rhs) < 0
  59:         neg     r3              /   r3 = asb(loint(rhs))
  60: 1:
  61:         cmp     r4,12.(sp)      / hiint(rhs) all sign bits?
  62:         bne     hardldiv        /   no, rhs >= 2^15
  63: 
  64:         mov     10.(sp),r2      / r2 = loint(lhs)
  65:         mov     8.(sp),r1       / r1 = hiint(lhs)
  66:         bge     2f              / if lhs < 0
  67:         negl(r1, r2)            /   r1:r2 = abs(lhs)
  68:         com     r4              /   invert sign of result
  69: 2:
  70:         /*
  71: 	 * At this point we know what the sign of the result is going to be
  72: 	 * (r4), abs(rhs) < 2^15, we have the absolute value of rhs in
  73: 	 * r3 as a single word integer and the absolute value of lhs in
  74: 	 * r1 (hiint) and r2 (loint).  References to hiint(rhs), loint(lhs)
  75: 	 * and hiint(lhs) in the following comments actually refer to the
  76: 	 * absolute value of rhs and lhs.
  77: 	 *
  78: 	 * We perform a long division the same way you learned in school:
  79: 	 *	hiint(quo) = hiint(lhs) / loint(rhs)
  80: 	 *	tmp        = (hiint(lhs) % loint(rhs))<<16 | loint(lhs)
  81: 	 *	loint(quo) = tmp / loint(rhs)
  82: 	 */
  83:         mov     r4,-(sp)        / save sign of result
  84:         clr     r0              / r0 = hiint(lhs) / loint(rhs)
  85:         div     r3,r0           / r1 = hiint(lhs) % loint(rhs)
  86:         mov     r0,r4           / save high quotient
  87:         mov     r1,-(sp)        / stash hiint(tmp)
  88:         mov     r1,r0           / tmp=(hiint(lhs)%loint(rhs))<<16 | loint(lhs)
  89:         mov     r2,r1           / (r0:r1 = tmp)
  90:         div     r3,r0           / r0 = tmp / loint(rhs)
  91:         bvc     3f              / done if tmp/loint(rhs) < 2^15
  92:         /*
  93: 	 * Our second division overflowed leaving undefined values in
  94: 	 * registers.  This can only happen when:
  95: 	 *	tmp/loint(rhs) >= 2^15
  96: 	 *	tmp >= 2^15 * loint(rhs)
  97: 	 *	tmp >= 2^16 * (loint(rhs)/2)
  98: 	 *
  99: 	 * If we subtract 2^16 * loint(rhs) from both sides however, we get:
 100: 	 *	tmp - (2^16 * loint(rhs)) >= -(2^16 * (loint(rhs)/2))
 101: 	 *
 102: 	 * and then divide both sides by loint(rhs):
 103: 	 *	tmp/loint(rhs) - 2^16 >= -(2^15)
 104: 	 *
 105: 	 * which is a division that won't generate an overflow.  Finally:
 106: 	 *	tmp = quo*loint(rhs) + rem
 107: 	 *	tmp - (2^16 * loint(rhs)) = (quo - 2^16) * loint(rhs) + rem
 108: 	 *
 109: 	 * which is fine since all we're going for is a 16 bit quotient so the
 110: 	 * subtraction of 2^16 won't have any effect.  However, since we're
 111: 	 * now dividing a negative number and since the div instruction
 112: 	 * always generates a remainder the same sign as the dividend, if we
 113: 	 * get a non-zero remainder, we'll actually get:
 114: 	 *	(quo+1 - 2^16) * loint(rhs) + rem-loint(rhs)
 115: 	 *
 116: 	 * which means we'll have to adjust the quotient returned by
 117: 	 * subtracting one ...
 118: 	 */
 119:         mov     (sp),r0         / reload r0:r1 with tmp (regs may be
 120:         mov     r2,r1           /   clobbered by failed div)
 121:         sub     r3,r0           / r0:r1 -= 2^16 * loint(rhs)
 122:         div     r3,r0
 123:         tst     r1              / if (negative) remainder, subtract one from
 124:         sxt     r1              /   quotient
 125:         add     r1,r0           / cannot overflow!
 126: 3:
 127:         tst     (sp)+           / pop hiint(tmp) off stack
 128:         mov     r0,r1           / r1 (loint(quo)) = tmp / loint(rhs)
 129:         mov     r4,r0           / r0 (hiint(quo)) = hiint(lhs) / loint(rhs)
 130:         tst     (sp)+
 131:         bpl     ret
 132: negret:                         / if result should be negative
 133:         negl(r0, r1)            /   quo = -quo
 134: ret:
 135:         mov     (sp)+,r4        / restore registers
 136:         mov     (sp)+,r3
 137:         mov     (sp)+,r2
 138:         rts     pc
 139: 
 140: /*
 141:  * The divisor (rhs) is known to be >= 2^15 so we perform a bit shift
 142:  * algorithm as only 16 cycles are needed:
 143:  *	long
 144:  *	hardldiv(lhs, rhs)
 145:  *		long	lhs, rhs;
 146:  *	{
 147:  *		int		flag;
 148:  *		long		hi_sreg, lo_sreg;
 149:  * 		unsigned int	quo, cnt;
 150:  *
 151:  *		flag = 0;
 152:  *		if (lhs < 0) {
 153:  *			lhs = -lhs;
 154:  *			flag = !flag;
 155:  *		}
 156:  *		if (rhs < 0) {
 157:  *			rhs = -rhs;
 158:  *			flag = !flag;
 159:  *		}
 160:  *		hi_sreg = hiint(lhs);
 161:  *		lo_sreg = loint(lhs)<<16;
 162:  *		quo = 0;
 163:  *		for (cnt = 16; cnt; cnt--) {
 164:  *			quo <<= 1;
 165:  *			qshiftl(&hi_sreg, &lo_sreg);
 166:  *			if (hi_sreg >= rhs) {
 167:  *				hi_sreg -= rhs;
 168:  *				quo |= 1;
 169:  *			}
 170:  *		}
 171:  *		return((long)(flag ? -quo : quo));
 172:  *	}
 173:  * The assembly version of the above algorithm uses r2, r0 and r1 to implement
 174:  * hi_sreg, lo_sreg and quo by putting lhs into r0:r1 and zeroing r2 thereby
 175:  * creating a three word register r2:r0:r1 with hi_sreg = r2:r0, lo_sreg =
 176:  * r0:r1, and quo = r1 (using the unused bits in r1 as they become available
 177:  * after the shift in the loop) ...
 178:  */
 179: hardldiv:
 180:         mov     10.(sp),r1      / r1 = loint(lhs)
 181:         mov     8.(sp),r0       / r0 = hiint(lhs)
 182:         sxt     -(sp)           / flag = sign(lhs)
 183:         bpl     1f              / if lhs < 0
 184:         negl(r0, r1)            /   r0:r1 = abs(lhs)
 185: 1:
 186:         mov     14.(sp),r3      / r3 = hiint(rhs)
 187:         bge     2f              / if rhs < 0
 188:         negl(r3, 16.(sp))       /   rhs = -rhs (r3:loint(rhs))
 189:         com     (sp)            /   flag = !flag
 190: 2:
 191:         clr     r2              / clear top of shift register
 192:         mov     $16.,r4         / loop 16 times
 193: 3:
 194:         clc                     / shift combined shift register and quotient
 195:         rol     r1              /   left one place
 196:         rol     r0
 197:         rol     r2
 198:         cmp     r3,r2           / How do r2:r0 (hi_sreg) and rhs compare?
 199:         bgt     4f
 200:         blt     5f
 201:         cmp     16.(sp),r0
 202:         blos    5f
 203: 4:
 204:         sob     r4,3b           / r2:r0 (hi_sreg) < rhs:
 205:         br      6f              /   just loop
 206: 5:
 207:         sub     16.(sp),r0      / r2:r0 (hi_sreg) >= rhs
 208:         sbc     r2              /   subtract rhs from r2:r0 (hi_sreg)
 209:         sub     r3,r2
 210:         inc     r1              /   set bit in quotient
 211:         sob     r4,3b           /   and loop
 212: 6:
 213:         clr     r0              / clear upper word of quotient
 214:         tst     (sp)+           / test negative flag
 215:         bge     ret             /   and head off to the appropriate return
 216:         br      negret
 217: #endif

Defined functions

hardldiv defined in line 179; used 1 times
  • in line 62
ldiv defined in line 52; never used
negret defined in line 132; used 1 times
ret defined in line 134; used 2 times

Defined macros

negl defined in line 48; used 4 times
Last modified: 1992-12-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2167
Valid CSS Valid XHTML 1.0 Strict