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 !!! */
87 memmove (mm, nn, nl*BN_DIGIT_SIZE/BN_BYTE_SIZE);
99 /***************************************/
103 void BnnSetDigit (nn, d)
109 * Sets a single digit of N to the passed value
116 /***************************************/
119 BigNumDigit BnnGetDigit (nn)
124 * Returns the single digit pointed by N
131 /***************************************/
135 BigNumLength BnnNumDigits (nn, nl)
141 * Returns the number of digits of N, not counting leading zeros
147 while (nl != 0 && *--nn == 0)
150 return (nl == 0 ? 1 : nl);
153 /***************************************/
156 BigNumDigit BnnNumLeadingZeroBitsInDigit (d)
161 * Returns the number of leading zero bits in a digit
165 register BigNumDigit mask = 1 << (BN_DIGIT_SIZE - 1);
170 return (BN_DIGIT_SIZE);
172 while ((d & mask) == 0)
181 /***************************************/
184 /************** Predicates on one digit ***************/
187 Boolean BnnDoesDigitFitInWord (d)
192 * Returns TRUE iff the digit can be represented in just BN_WORD_SIZE bits
195 /* The C compiler must evaluate the predicate at compile time */
196 if (BN_DIGIT_SIZE > BN_WORD_SIZE)
197 return (d >= 1 << BN_WORD_SIZE ? FALSE : TRUE);
202 /***************************************/
205 Boolean BnnIsDigitZero (d)
209 /* Returns TRUE iff digit = 0 */
215 /***************************************/
218 Boolean BnnIsDigitNormalized (d)
223 * Returns TRUE iff Base/2 <= digit < Base
224 * i.e., if digit's leading bit is 1
228 return (d & (1 << (BN_DIGIT_SIZE - 1)) ? TRUE : FALSE);
231 /***************************************/
234 Boolean BnnIsDigitOdd (d)
239 * Returns TRUE iff digit is odd
243 return (d & 1 ? TRUE : FALSE);
246 /***************************************/
249 BigNumCmp BnnCompareDigits (d1, d2)
254 * Returns BN_GREATER if digit1 > digit2
255 * BN_EQUAL if digit1 = digit2
256 * BN_LESS if digit1 < digit2
260 return (d1 > d2 ? BN_GT : (d1 == d2 ? BN_EQ : BN_LT));
263 /***************** Logical operations ********************/
266 void BnnComplement (nn, nl)
272 * Performs the computation BBase(N) - N - 1 => N
280 /***************************************/
284 void BnnAndDigits (n, d)
290 * Returns the logical computation n[0] AND d in n[0]
297 /***************************************/
300 void BnnOrDigits (n, d)
306 * Returns the logical computation n[0] OR d2 in n[0].
313 /***************************************/
316 void BnnXorDigits (n, d)
322 * Returns the logical computation n[0] XOR d in n[0].
329 /***************************************/
332 /****************** Shift operations *******************/
335 BigNumDigit BnnShiftLeft (mm, ml, nbits)
342 * Shifts M left by "nbits", filling with 0s.
343 * Returns the leftmost "nbits" of M in a digit.
344 * Assumes 0 <= nbits < BN_DIGIT_SIZE.
348 register BigNumDigit res = 0, save;
354 rnbits = BN_DIGIT_SIZE - nbits;
359 *mm++ = (save << nbits) | res;
360 res = save >> rnbits;
367 /***************************************/
371 BigNumDigit BnnShiftRight (mm, ml, nbits)
378 * Shifts M right by "nbits", filling with 0s.
379 * Returns the rightmost "nbits" of M in a digit.
380 * Assumes 0 <= nbits < BN_DIGIT_SIZE.
384 register BigNumDigit res = 0, save;
391 lnbits = BN_DIGIT_SIZE - nbits;
396 *mm = (save >> nbits) | res;
397 res = save << lnbits;
404 /***************************************/
408 /******************* Additions **************************/
411 BigNumCarry BnnAddCarry (nn, nl, carryin)
418 * Performs the sum N + CarryIn => N.
419 * Returns the CarryOut.
429 while (--nl >= 0 && !(++(*nn++)))
432 return (nl >= 0 ? 0 : 1);
435 /***************************************/
439 BigNumCarry BnnAdd (mm, ml, nn, nl, carryin)
441 register BigNum mm, nn;
447 * Performs the sum M + N + CarryIn => M.
448 * Returns the CarryOut.
449 * Assumes Size(M) >= Size(N).
453 register BigNumProduct c = carryin;
457 /* test computed at compile time */
458 if (sizeof (BigNumProduct) > sizeof (BigNumDigit))
469 register BigNumProduct save;
485 c = (c < save) ? 1 : 0;
490 return (BnnAddCarry (mm, ml, (BigNumCarry) c));
493 /***************************************/
496 /****************** Subtraction *************************/
500 BigNumCarry BnnSubtractBorrow (nn, nl, carryin)
507 * Performs the difference N + CarryIn - 1 => N.
508 * Returns the CarryOut.
518 while (--nl >= 0 && !(*nn)--) nn++;
520 while (--nl >= 0 && !((*nn++)--))
524 return (nl >= 0 ? 1 : 0);
527 /***************************************/
531 BigNumCarry BnnSubtract (mm, ml, nn, nl, carryin)
533 register BigNum mm, nn;
539 * Performs the difference M - N + CarryIn - 1 => M.
540 * Returns the CarryOut.
541 * Assumes Size(M) >= Size(N).
545 register BigNumProduct c = carryin;
546 register BigNumDigit invn;
550 /* test computed at compile time */
551 if (sizeof (BigNumProduct) > sizeof (BigNumDigit))
563 register BigNumProduct save;
580 c = (c < invn) ? 1 : 0;
585 return (BnnSubtractBorrow (mm, ml, (BigNumCarry) c)); }
588 /***************************************/
591 /***************** Multiplication ************************/
594 BigNumCarry BnnMultiplyDigit (pp, pl, mm, ml, d)
596 register BigNum pp, mm;
601 * Performs the product:
605 * Q div BB => CarryOut
606 * Returns the CarryOut.
607 * Assumes Size(P) >= Size(M) + 1.
611 register BigNumProduct c = 0;
618 return (BnnAdd (pp, pl, mm, ml, (BigNumCarry) 0));
621 /* test computed at compile time */
622 if (sizeof (BigNumProduct) > sizeof (BigNumDigit))
627 c += *pp + (d * (*(mm++)));
643 /* help for stupid compilers--may actually be counter
644 productive on pipelined machines with decent register allocation!! */
648 register BigNumDigit Lm, Hm, Ld, Hd, X0, X2 /*, X1, X3 */;
650 Ld = d & ((1 << (BN_DIGIT_SIZE / 2)) -1);
651 Hd = d >> (BN_DIGIT_SIZE / 2);
656 Lm = m_digit & ((1 << (BN_DIGIT_SIZE / 2)) -1);
657 Hm = m_digit >> (BN_DIGIT_SIZE / 2);
663 if ((c += X0) < X0) X3++;
664 if ((X1 += X2) < X2) X3 += (1<<(BN_DIGIT_SIZE / 2));
665 X3 += (X1 >> (BN_DIGIT_SIZE / 2));
666 X1 <<= (BN_DIGIT_SIZE / 2);
667 if ((c += X1) < X1) X3++;
668 if ((*pp += c) < c) X3++;
685 while (pl != 0 && !(++(*pp++)))
688 return (pl != 0 ? 0 : 1);
693 BigNumCarry BnnMultiply2Digit (pp, pl, mm, ml, d0, d1)
695 register BigNum pp, mm;
700 * Provided for compatibility with mips assembler implementation.
701 * Performs the product:
705 * Q div BB => CarryOut
706 * Returns the CarryOut.
707 * Assumes Size(P) >= Size(M) + 1.
712 BnnMultiplyDigit (pp, pl, mm, ml, d0)
713 + BnnMultiplyDigit (pp+1, pl-1, mm, ml, d1);
717 /***************************************/
720 /********************** Division *************************/
724 #define SUB(xh,xl,yh,yl) if (yl > xl) {xl -= yl; xh -= yh + 1;}\
725 else {xl -= yl; xh -= yh;}
727 #define LOW(x) (x & ((1 << (BN_DIGIT_SIZE / 2)) -1))
728 #define HIGH(x) (x >> (BN_DIGIT_SIZE / 2))
729 #define L2H(x) (x << (BN_DIGIT_SIZE / 2))
732 BigNumDigit BnnDivideDigit (qq, nn, nl, d)
734 register BigNum qq, nn;
738 /* Performs the quotient: N div d => Q
739 * Returns R = N mod d
740 * Assumes leading digit of N < d, and d > 0.
744 /* test computed at compile time */
745 if (sizeof (BigNumProduct) > sizeof (BigNumDigit))
747 register BigNumProduct quad;
758 quad = (quad << BN_DIGIT_SIZE) | *(--nn);
769 BigNumDigit rh; /* Two halves of current remainder */
770 BigNumDigit rl; /* Correspond to quad above */
771 register BigNumDigit qa; /* Current appr. to quotient */
772 register BigNumDigit ph, pl; /* product of c and qa */
773 BigNumDigit ch, cl, prev_qq;
776 /* Normalize divisor */
777 k = BnnNumLeadingZeroBitsInDigit (d);
783 BnnShiftLeft (nn, nl, k);
800 qa = rh / ch; /* appr. quotient */
808 /* While ph:pl > rh:rl, decrement qa, adjust qh:ql */
809 while (ph > rh || ph == rh && pl > rl)
812 SUB (ph, pl, ch, L2H (cl));
815 SUB (rh, rl, ph, pl);
817 /* Top half of quotient is correct; save it */
819 qa = (L2H (rh) | HIGH (rl)) / ch;
821 /* Approx low half of q */
822 /* Compute ph, pl, again */
826 pl = LOW (pl) | L2H (LOW (ph));
829 /* While ph:pl > rh:rl, decrement qa, adjust qh:ql */
830 while (ph > rh || ph == rh && pl > rl)
836 /* Subtract ph:pl from rh:rl; we know rh will be 0 */
841 /* Denormalize dividend */
843 if((qq > nn) && (qq < &nn[orig_nl])) {
844 /* Overlap between qq and nn. Care of *qq! */
846 BnnShiftRight (nn, orig_nl, k);
847 nn[orig_nl - 1] = prev_qq;
848 } else if(qq == nn) {
849 BnnShiftRight(&nn[orig_nl - 1], 1, k);
851 BnnShiftRight (nn, orig_nl, k);
857 /***************************************/