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