1 /* Copyright Digital Equipment Corporation & INRIA 1988, 1989 */
2 /* Last modified_on Fri Mar 2 16:49:23 GMT+1:00 1990 by herve */
3 /* modified_on Mon Feb 19 20:22:20 GMT+1:00 1990 by shand */
6 /* KerN.c: the kernel written in C */
9 * Description of types and constants.
11 * Several conventions are used in the commentary:
12 * A "BigNum" is the name for an infinite-precision number.
13 * Capital letters (e.g., "N") are used to refer to the value of BigNums.
14 * The word "digit" refers to a single BigNum digit.
15 * The notation "Size(N)" refers to the number of digits in N,
16 * which is typically passed to the subroutine as "nl".
17 * The notation "Length(N)" refers to the number of digits in N,
18 * not including any leading zeros.
19 * The word "Base" is used for the number 2 ** BN_DIGIT_SIZE, where
20 * BN_DIGIT_SIZE is the number of bits in a single BigNum digit.
21 * The expression "BBase(N)" is used for Base ** NumDigits(N).
22 * The term "leading zeros" refers to any zeros before the most
23 * significant digit of a number.
26 * In the code, we have:
28 * "nn" is a pointer to a big number,
29 * "nl" is the number of digits from nn,
44 static char copyright[]="@(#)KerN.c: copyright Digital Equipment Corporation & INRIA 1988, 1989\n";
47 /******* non arithmetic access to digits ********/
50 void BnnSetToZero (nn, nl)
56 * Sets all the specified digits of the BigNum to 0
64 memset (nn, 0, nl*BN_DIGIT_SIZE/BN_BYTE_SIZE);
68 /***************************************/
71 void BnnAssign (mm, nn, nl)
73 register BigNum mm, nn;
81 if (mm < nn || mm > nn+nl)
86 /* be care: bcopy (SRC, DEST, L): SRC-->DEST !!! */
88 memmove (mm, nn, nl*BN_DIGIT_SIZE/BN_BYTE_SIZE);
90 bcopy (nn, mm, nl*BN_DIGIT_SIZE/BN_BYTE_SIZE);
103 /***************************************/
107 void BnnSetDigit (nn, d)
113 * Sets a single digit of N to the passed value
120 /***************************************/
123 BigNumDigit BnnGetDigit (nn)
128 * Returns the single digit pointed by N
135 /***************************************/
139 BigNumLength BnnNumDigits (nn, nl)
145 * Returns the number of digits of N, not counting leading zeros
151 while (nl != 0 && *--nn == 0)
154 return (nl == 0 ? 1 : nl);
157 /***************************************/
160 BigNumDigit BnnNumLeadingZeroBitsInDigit (d)
165 * Returns the number of leading zero bits in a digit
169 register BigNumDigit mask = 1 << (BN_DIGIT_SIZE - 1);
174 return (BN_DIGIT_SIZE);
176 while ((d & mask) == 0)
185 /***************************************/
188 /************** Predicates on one digit ***************/
191 Boolean BnnDoesDigitFitInWord (d)
196 * Returns TRUE iff the digit can be represented in just BN_WORD_SIZE bits
199 /* The C compiler must evaluate the predicate at compile time */
200 if (BN_DIGIT_SIZE > BN_WORD_SIZE)
201 return (d >= 1 << BN_WORD_SIZE ? FALSE : TRUE);
206 /***************************************/
209 Boolean BnnIsDigitZero (d)
213 /* Returns TRUE iff digit = 0 */
219 /***************************************/
222 Boolean BnnIsDigitNormalized (d)
227 * Returns TRUE iff Base/2 <= digit < Base
228 * i.e., if digit's leading bit is 1
232 return (d & (1 << (BN_DIGIT_SIZE - 1)) ? TRUE : FALSE);
235 /***************************************/
238 Boolean BnnIsDigitOdd (d)
243 * Returns TRUE iff digit is odd
247 return (d & 1 ? TRUE : FALSE);
250 /***************************************/
253 BigNumCmp BnnCompareDigits (d1, d2)
258 * Returns BN_GREATER if digit1 > digit2
259 * BN_EQUAL if digit1 = digit2
260 * BN_LESS if digit1 < digit2
264 return (d1 > d2 ? BN_GT : (d1 == d2 ? BN_EQ : BN_LT));
267 /***************** Logical operations ********************/
270 void BnnComplement (nn, nl)
276 * Performs the computation BBase(N) - N - 1 => N
284 /***************************************/
288 void BnnAndDigits (n, d)
294 * Returns the logical computation n[0] AND d in n[0]
301 /***************************************/
304 void BnnOrDigits (n, d)
310 * Returns the logical computation n[0] OR d2 in n[0].
317 /***************************************/
320 void BnnXorDigits (n, d)
326 * Returns the logical computation n[0] XOR d in n[0].
333 /***************************************/
336 /****************** Shift operations *******************/
339 BigNumDigit BnnShiftLeft (mm, ml, nbits)
346 * Shifts M left by "nbits", filling with 0s.
347 * Returns the leftmost "nbits" of M in a digit.
348 * Assumes 0 <= nbits < BN_DIGIT_SIZE.
352 register BigNumDigit res = 0, save;
358 rnbits = BN_DIGIT_SIZE - nbits;
363 *mm++ = (save << nbits) | res;
364 res = save >> rnbits;
371 /***************************************/
375 BigNumDigit BnnShiftRight (mm, ml, nbits)
382 * Shifts M right by "nbits", filling with 0s.
383 * Returns the rightmost "nbits" of M in a digit.
384 * Assumes 0 <= nbits < BN_DIGIT_SIZE.
388 register BigNumDigit res = 0, save;
395 lnbits = BN_DIGIT_SIZE - nbits;
400 *mm = (save >> nbits) | res;
401 res = save << lnbits;
408 /***************************************/
412 /******************* Additions **************************/
415 BigNumCarry BnnAddCarry (nn, nl, carryin)
422 * Performs the sum N + CarryIn => N.
423 * Returns the CarryOut.
433 while (--nl >= 0 && !(++(*nn++)))
436 return (nl >= 0 ? 0 : 1);
439 /***************************************/
443 BigNumCarry BnnAdd (mm, ml, nn, nl, carryin)
445 register BigNum mm, nn;
451 * Performs the sum M + N + CarryIn => M.
452 * Returns the CarryOut.
453 * Assumes Size(M) >= Size(N).
457 register BigNumProduct c = carryin;
461 /* test computed at compile time */
462 if (sizeof (BigNumProduct) > sizeof (BigNumDigit))
473 register BigNumProduct save;
489 c = (c < save) ? 1 : 0;
494 return (BnnAddCarry (mm, ml, (BigNumCarry) c));
497 /***************************************/
500 /****************** Subtraction *************************/
504 BigNumCarry BnnSubtractBorrow (nn, nl, carryin)
511 * Performs the difference N + CarryIn - 1 => N.
512 * Returns the CarryOut.
522 while (--nl >= 0 && !(*nn)--) nn++;
524 while (--nl >= 0 && !((*nn++)--))
528 return (nl >= 0 ? 1 : 0);
531 /***************************************/
535 BigNumCarry BnnSubtract (mm, ml, nn, nl, carryin)
537 register BigNum mm, nn;
543 * Performs the difference M - N + CarryIn - 1 => M.
544 * Returns the CarryOut.
545 * Assumes Size(M) >= Size(N).
549 register BigNumProduct c = carryin;
550 register BigNumDigit invn;
554 /* test computed at compile time */
555 if (sizeof (BigNumProduct) > sizeof (BigNumDigit))
567 register BigNumProduct save;
584 c = (c < invn) ? 1 : 0;
589 return (BnnSubtractBorrow (mm, ml, (BigNumCarry) c)); }
592 /***************************************/
595 /***************** Multiplication ************************/
598 BigNumCarry BnnMultiplyDigit (pp, pl, mm, ml, d)
600 register BigNum pp, mm;
605 * Performs the product:
609 * Q div BB => CarryOut
610 * Returns the CarryOut.
611 * Assumes Size(P) >= Size(M) + 1.
615 register BigNumProduct c = 0;
622 return (BnnAdd (pp, pl, mm, ml, (BigNumCarry) 0));
625 /* test computed at compile time */
626 if (sizeof (BigNumProduct) > sizeof (BigNumDigit))
631 c += *pp + (d * (*(mm++)));
647 /* help for stupid compilers--may actually be counter
648 productive on pipelined machines with decent register allocation!! */
652 register BigNumDigit Lm, Hm, Ld, Hd, X0, X2 /*, X1, X3 */;
654 Ld = d & ((1 << (BN_DIGIT_SIZE / 2)) -1);
655 Hd = d >> (BN_DIGIT_SIZE / 2);
660 Lm = m_digit & ((1 << (BN_DIGIT_SIZE / 2)) -1);
661 Hm = m_digit >> (BN_DIGIT_SIZE / 2);
667 if ((c += X0) < X0) X3++;
668 if ((X1 += X2) < X2) X3 += (1<<(BN_DIGIT_SIZE / 2));
669 X3 += (X1 >> (BN_DIGIT_SIZE / 2));
670 X1 <<= (BN_DIGIT_SIZE / 2);
671 if ((c += X1) < X1) X3++;
672 if ((*pp += c) < c) X3++;
689 while (pl != 0 && !(++(*pp++)))
692 return (pl != 0 ? 0 : 1);
697 BigNumCarry BnnMultiply2Digit (pp, pl, mm, ml, d0, d1)
699 register BigNum pp, mm;
704 * Provided for compatibility with mips assembler implementation.
705 * Performs the product:
709 * Q div BB => CarryOut
710 * Returns the CarryOut.
711 * Assumes Size(P) >= Size(M) + 1.
716 BnnMultiplyDigit (pp, pl, mm, ml, d0)
717 + BnnMultiplyDigit (pp+1, pl-1, mm, ml, d1);
721 /***************************************/
724 /********************** Division *************************/
728 #define SUB(xh,xl,yh,yl) if (yl > xl) {xl -= yl; xh -= yh + 1;}\
729 else {xl -= yl; xh -= yh;}
731 #define LOW(x) (x & ((1 << (BN_DIGIT_SIZE / 2)) -1))
732 #define HIGH(x) (x >> (BN_DIGIT_SIZE / 2))
733 #define L2H(x) (x << (BN_DIGIT_SIZE / 2))
736 BigNumDigit BnnDivideDigit (qq, nn, nl, d)
738 register BigNum qq, nn;
742 /* Performs the quotient: N div d => Q
743 * Returns R = N mod d
744 * Assumes leading digit of N < d, and d > 0.
748 /* test computed at compile time */
749 if (sizeof (BigNumProduct) > sizeof (BigNumDigit))
751 register BigNumProduct quad;
762 quad = (quad << BN_DIGIT_SIZE) | *(--nn);
773 BigNumDigit rh; /* Two halves of current remainder */
774 BigNumDigit rl; /* Correspond to quad above */
775 register BigNumDigit qa; /* Current appr. to quotient */
776 register BigNumDigit ph, pl; /* product of c and qa */
777 BigNumDigit ch, cl, prev_qq;
780 /* Normalize divisor */
781 k = BnnNumLeadingZeroBitsInDigit (d);
787 BnnShiftLeft (nn, nl, k);
804 qa = rh / ch; /* appr. quotient */
812 /* While ph:pl > rh:rl, decrement qa, adjust qh:ql */
813 while (ph > rh || ph == rh && pl > rl)
816 SUB (ph, pl, ch, L2H (cl));
819 SUB (rh, rl, ph, pl);
821 /* Top half of quotient is correct; save it */
823 qa = (L2H (rh) | HIGH (rl)) / ch;
825 /* Approx low half of q */
826 /* Compute ph, pl, again */
830 pl = LOW (pl) | L2H (LOW (ph));
833 /* While ph:pl > rh:rl, decrement qa, adjust qh:ql */
834 while (ph > rh || ph == rh && pl > rl)
840 /* Subtract ph:pl from rh:rl; we know rh will be 0 */
845 /* Denormalize dividend */
847 if((qq > nn) && (qq < &nn[orig_nl])) {
848 /* Overlap between qq and nn. Care of *qq! */
850 BnnShiftRight (nn, orig_nl, k);
851 nn[orig_nl - 1] = prev_qq;
852 } else if(qq == nn) {
853 BnnShiftRight(&nn[orig_nl - 1], 1, k);
855 BnnShiftRight (nn, orig_nl, k);
861 /***************************************/