diff options
Diffstat (limited to 'private/ntos/rtl/ppc/largeint.s')
-rw-r--r-- | private/ntos/rtl/ppc/largeint.s | 1089 |
1 files changed, 1089 insertions, 0 deletions
diff --git a/private/ntos/rtl/ppc/largeint.s b/private/ntos/rtl/ppc/largeint.s new file mode 100644 index 000000000..c59584fcf --- /dev/null +++ b/private/ntos/rtl/ppc/largeint.s @@ -0,0 +1,1089 @@ +// TITLE("Large Integer Arithmetic") +//++ +// +// Copyright (c) 1993 IBM Corporation +// +// Module Name: +// +// largeint.s +// +// Abstract: +// +// This module implements routines for performing extended integer +// arithmtic. +// +// Author: +// +// David N. Cutler (davec) 18-Apr-1990 +// Converted to PowerPC by Walt Daniels and Norman Cohen Aug 93 +// (from MIPS based code) +// +// References: +// See PowerPC Architecture book Appendix E.2 for 64-bit shifts +// See "Hacker's Delight", Hank Warren, Nov. 91 for fancy divides +// +// Environment: +// +// Any mode. +// +// Revision History: +// Fixed RtlExtendedLargeIntegerDivide (Steve Johns) 18-Feb-94 +// - if divisor >= 2^16 && dividend >= 2^32, quotient incorrect +// - also, removed 6 uncessary occurrences of CMPI +// +//-- + +#include "ksppc.h" + + + +//++ +// +// LARGE_INTEGER +// RtlLargeIntegerAdd ( +// IN LARGE_INTEGER Addend1, +// IN LARGE_INTEGER Addend2 +// ) +// +// Routine Description: +// +// This function adds a signed large integer to a signed large integer and +// returns the signed large integer result. +// +// Arguments: +// +// Addend1 (r.5, r.6) - Supplies the first addend value. +// +// Addend2 (r.7, r.8) - Supplies the second addend value. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlLargeIntegerAdd) + + addc r.5,r.5,r.7 // add low parts of large integer + adde r.6,r.6,r.8 // add high parts with carry + stw r.5,0(r.3) // store low 32-bits + stw r.6,4(r.3) // store high 32-bits + LEAF_EXIT(RtlLargeIntegerAdd) // return + + + +//++ +// +// LARGE_INTEGER +// RtlConvertLongToLargeInteger ( +// IN LONG SignedInteger +// ) +// +// Routine Description: +// +// This function converts the a signed integer to a signed large integer +// and returns the result. +// +// Arguments: +// +// SignedInteger (r.4) - Supplies the value to convert. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlConvertLongToLargeInteger) + + srawi r.5,r.4,31 // compute high part of result + stw r.4,0(r.3) // store low 32-bits + stw r.5,4(r.3) // store high 32-bits + LEAF_EXIT(RtlConvertLongToLargeInteger) // return + + + +//++ +// +// LARGE_INTEGER +// RtlConvertUlongToLargeInteger ( +// IN LONG UnsignedInteger +// ) +// +// Routine Description: +// +// This function converts the an unsigned integer to a signed large +// integer and returns the result. +// +// Arguments: +// +// UnsignedInteger (r.4) - Supplies the value to convert. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlConvertUlongToLargeInteger) + + li r.5,0 // clear high part + stw r.4,0(r.3) // store low 32-bits + stw r.5,4(r.3) // store high 32-bits + LEAF_EXIT(RtlConvertUlongToLargeInteger) // return + + + +//++ +// +// LARGE_INTEGER +// RtlEnlargedIntegerMultiply ( +// IN LONG Multiplicand, +// IN LONG Multiplier +// ) +// +// Routine Description: +// +// This function multiplies a signed integer by an signed integer and +// returns a signed large integer result. +// +// Arguments: +// +// Multiplicand (r.4) - Supplies the multiplicand value. +// +// Multiplier (r.5) - Supplies the multiplier value. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlEnlargedIntegerMultiply) + + mullw r.6,r.4,r.5 // keep low 32-bits of result + mulhw r.7,r.4,r.5 // keep high 32-bits of result + stw r.6,0(r.3) // store low 32-bits + stw r.7,4(r.3) // store high 32-bits + LEAF_EXIT(RtlEnlargedIntegerMultiply) // return + + + +//++ +// +// LARGE_INTEGER +// RtlEnlargedUnsignedMultiply ( +// IN ULONG Multiplicand, +// IN ULONG Multiplier +// ) +// +// Routine Description: +// +// This function multiplies an unsigned integer by an unsigned integer +// and returns a signed large integer result. +// +// Arguments: +// +// Multiplicand (r.4) - Supplies the multiplicand value. +// +// Multiplier (r.5) - Supplies the multiplier value. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlEnlargedUnsignedMultiply) + + mullw r.6,r.4,r.5 // keep low-32-bits + mulhwu r.7,r.4,r.5 // keep high 32-bits + stw r.6,0(r.3) // store low 32-bits + stw r.7,4(r.3) // store high 32-bits + LEAF_EXIT(RtlEnlargedUnsignedMultiply) // return + + + +//++ +// +// ULONG +// RtlEnlargedUnsignedDivide ( +// IN ULARGE_INTEGER Dividend, +// IN ULONG Divisor, +// IN PULONG Remainder. +// ) +// +// Routine Description: +// +// This function divides an unsigned large integer by an unsigned long +// and returns the resultant quotient and optionally the remainder. +// +// N.B. It is assumed that no overflow will occur. +// +// Arguments: +// +// Dividend (r.3, r.4) - Supplies the dividend value. +// (High-order bits in r.4, low-order bits in r.3) +// +// Divisor (r.5) - Supplies the divisor value. +// +// Remainder (r.6) - Supplies an optional pointer to a variable that +// receives the remainder. Ptr is null if not needed. +// +// Return Value: +// +// The unsigned long integer quotient is returned as the function value. +// +//-- + + LEAF_ENTRY(RtlEnlargedUnsignedDivide) + + cmplw r.4,r.5 + bge overflow // catch overflow or division by 0 + cmplwi r.4,0 // test high part for 0 + beq only_32_bits // 32-bit division suffices +// Normalize: Shift divisor and dividend left to get rid of leading zeroes +// in the divisor. Since r.4 < r.5, only zeroes are shifted out of the +// dividend. + cntlzw r.7,r.5 // number of bits to shift (N) + slw r.5,r.5,r.7 // shift divisor + slw r.4,r.4,r.7 // shift upper part of divisor + subfic r.9,r.7,32 // 32-N + srw r.9,r.3,r.9 // leftmost N bits of r.3, slid right + or r.4,r.4,r.9 // and inserted into low end of r.4 + slw r.3,r.3,r.7 // shift lower part of divisor +// Estimate high-order halfword of quotient. If the dividend is +// A0 A1 A2 A3 and the divisor is B0 B1 (where each Ai or Bi is a halfword), +// then the estimate is A0 A1 0000 divided by B0 0000, or A0 A1 divided by B0. +// (r.4 holds A0 A1, r.3 holds A2 A3, and r.5 holds B0 B1.) +// The estimate may be too high because it does not account for B1; in rare +// cases, the estimate will not even fit in a halfword. High estimates are +// corrected for later. + srwi r.8,r.5,16 // r.8 <- B0 + divwu r.12,r.4,r.8 // r.12 <- floor([A0 A1]/B0) +// Subtract partial quotient times divisor from dividend: If Q0 is the quotient +// computed above, this means that Q0 0000 times B0 B1 is subtracted from +// A0 A1 A2 A3. We compute Q0 times B0 B1 and then shift the two-word +// product left 16 bits. + mullw r.9,r.12,r.5 // low word of Q0 times B0 B1 + mulhwu r.10,r.12,r.5 // high word of Q0 times B0 B1 + slwi r.10,r.10,16 // shift high word left 16 bits + inslwi r.10,r.9,16,16 // move 16 bits from left of low word to + // right of high word + slwi r.9,r.9,16 // shift low word left 16 bits + subfc r.3,r.9,r.3 // low word of difference + subfe r.4,r.10,r.4 // high word of difference +// If the estimate for Q0 was too high, the difference will be negative. +// While A0 A1 A2 A3 is negative, repeatedly add B0 B1 0000 to A0 A1 A2 A3 +// and decrement Q0 by one to correct for the overestimate. + cmpwi r.4,0 // A0 A1 A2 A3 is negative iff A0 A1 is + bge Q0_okay // no correction needed + inslwi r.10,r.5,16,16 // high word of B0 B1 0000 (= 0000 B0) + slwi r.9,r.5,16 // low word of B0 B1 0000 (= B1 0000) +adjust_Q0: + addc r.3,r.3,r.9 // add B0 B1 0000 to A0 A1 A2 A3 (low) + adde r.4,r.4,r.10 // add B0 B1 0000 to A0 A1 A2 A3 (high) + cmpwi r.4,0 // Is A0 A1 A2 A3 now nonnegative? + addi r.12,r.12,-1 // decrement Q0 + blt adjust_Q0 // if A0 A1 A2 A3 still negative, repeat +Q0_okay: +// Estimate low-order halfword of quotient. A0 is necessarily 0000 at this +// point, so if the remaining part of the dividend is A0 A1 A2 A3 then the +// estimate is A1 A2 0000 divided by B0 0000, or A1 A2 divided by B0. +// (r.4 holds A0 A1, r.3 holds A2 A3, and r.8 holds B0.) + slwi r.9,r.4,16 // r.9 <- A1 0000 + inslwi r.9,r.3,16,16 // r.9 <- A1 A2 + divwu r.11,r.9,r.8 // r.11 <- floor([A1 A2]/B0) +// Subtract partial quotient times divisor from remaining part of dividend: +// If Q1 is the quotient computed above, this means +// that Q1 times B0 B1 is subtracted from A0 A1 A2 A3. We compute + mullw r.9,r.11,r.5 // low word of Q1 times B0 B1 + mulhwu r.10,r.11,r.5 // high word of Q1 times B0 B1 + subfc r.3,r.9,r.3 // low word of difference + subfe r.4,r.10,r.4 // high word of difference +// If the estimate for Q1 was too high, the difference will be negative. +// While A0 A1 A2 A3 is negative, repeatedly add B0 B1 to A0 A1 A2 A3 +// and decrement Q1 by one to correct for the overestimate. + cmpwi r.4,0 // A0 A1 A2 A3 is negative iff A0 A1 is + bge Q1_okay // no correction needed +adjust_Q1: + addc r.3,r.3,r.5 // add B0 B1 to A0 A1 A2 A3 (low) + addze r.4,r.4 // add B0 B1 to A0 A1 A2 A3 (high) + cmpwi r.4,0 // Is A0 A1 A2 A3 now nonnegative? + addi r.11,r.11,-1 // decrement Q1 + blt adjust_Q1 // if A0 A1 A2 A3 still negative, repeat +Q1_okay: +// Build the results. The desired quotient is Q0 Q1. +// The desired remainder is obtained by shifting A2 A3 right by the number +// of bits by which the dividend and divisor were shifted left in the +// normalization step. The number of bits shifted is still in r.7. + cmplwi r.6,0 // remainder needed? + bne rem1 // if so, go compute it + slwi r.3,r.12,16 // r.3 <- Q0 0000 + or r.3,r.3,r.11 // r.3 <- Q0 Q1 + blr +rem1: + srw r.8,r.3,r.7 // remainder <- [A2 A3] >> (r.7) + slwi r.3,r.12,16 // r.3 <- Q0 0000 + stw r.8,0(r.6) // store remainder + or r.3,r.3,r.11 // r.3 <- Q0 Q1 + blr +// +// End of normal case +// +// The case of a 32-bit dividend: +only_32_bits: + cmplwi r.6,0 // remainder needed? + bne rem2 // if so, go compute quotient+remainder + divwu r.3,r.3,r.5 // result <- dividend/divisor + blr +rem2: + divwu r.7,r.3,r.5 // quotient <- dividend / divisor + mullw r.8,r.7,r.5 // r.8 <- quotient * divisor + subf r.8,r.8,r.3 // remainder<-dividend-quotient*divisor + mr r.3,r.7 // result <- quotient + stw r.8,0(r.6) // store remainder + blr +// The error cases: +overflow: + twi 6,r.5,0 // trap if divide by zero + twi 0x1b,r.5,0 // trap on overflow + + LEAF_EXIT(RtlEnlargedUnsignedDivide) + + +//++ +// +// ULARGE_INTEGER +// RtlExtendedLargeIntegerDivide ( +// IN ULARGE_INTEGER Dividend, +// IN ULONG Divisor, +// IN PULONG Remainder. +// ) +// +// Routine Description: +// +// This function divides an unsigned large integer by an unsigned long +// and returns the resultant quotient and optionally the remainder. +// +// Arguments: +// +// Dividend (r.5, r.6) - Supplies the dividend value. +// +// Divisor (r.7) - Supplies the divisor value. +// +// Remainder (r.8)- Supplies an optional pointer to a variable +// that receives the remainder. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlExtendedLargeIntegerDivide) + + cmplwi r.7,0 // zero divisor? + beq div_zero_s // if so, branch to error exit + cmpwi r.6,0 // check sign of dividend high word + bne big_dividend + +// The high-order word of the dividend is zero, so 32-bit unsigned division +// can be used. + li r.12,0 // upper word of quotient is zero + stw r.12,4(r.3) // store upper word of quotient + divwu r.11,r.5,r.7 // compute lower word of quotient + stw r.11,0(r.3) // store lower word of quotient + cmplwi r.8,0 // remainder needed? + beqlr // if not, return + mullw r.10,r.11,r.7 // quotient * divisor + subf r.9,r.10,r.5 // dividend - quotient * divisor + stw r.9,0(r.8) // store remainder + blr // return + +big_dividend: + srwi. r.0,r.7,16 // upper 16 bits of divisor + bne long_division // if not, must use long division + +// The divisor is only one 16-bit digit long, so use short division: + srwi r.0,r.6,16 // first 16-bit digit of dividend + divwu r.4,r.0,r.7 // first 16-bit digit of quotient + mullw r.10,r.4,r.7 // amount to subtract for remainder + subf r.9,r.10,r.0 // remainder from first digit + insrwi r.6,r.9,16,0 // combine rmndr with 2nd digit of dvdnd + divwu r.12,r.6,r.7 // second digit of quotient + insrwi r.12,r.4,16,0 // high two quotient digits in one word + mullw r.10,r.12,r.7 // amount to subtract for remainder + subf r.9,r.10,r.6 // remainder from second digit + srwi r.0,r.5,16 // third digit of dividend + insrwi r.0,r.9,16,0 // combine rmndr with 3rd digit of dvdnd + divwu r.4,r.0,r.7 // third digit of quotient + mullw r.10,r.4,r.7 // amount to subtract for remainder + subf r.9,r.10,r.0 // remainder from third digit + insrwi r.5,r.9,16,0 // combine rmndr with 4th digit of dvdnd + divwu r.11,r.5,r.7 // fourth digit of quotient + mullw r.10,r.11,r.7 // amount to subtract for remainder + insrwi r.11,r.4,16,0 // low two quotient digits in one word + subf r.9,r.10,r.5 // remainder from fourth digit + b store_results + +long_division: +// Since the divisor is more than one 16-bit digit long, the quotient will +// be of the form 0x0000 Q2 Q3 Q4, where each of Q2, Q3, and Q4 is a 16-bit +// digit. +// +// Normalize the divisor and dividend so that the high-order bit of the +// divisor is 1. This normalization must be undone after the division to +// compute the remainder. Let U1 U2 U3 U4 be the 16-bit digits of the +// unnormalized dividend. Each digit Ui consists of an S-bit high-order part +// UiH and a (16-S)-bit low-order part UiL, where S is the number of leading +// zeroes in the divisor. Thus R6 holds U1H U1L U2H U2L and R5 holds +// U3H U3L U4H U4L. Let N0 N1 N2 N3 N4 be the 16-bit digits of the normalized +// dividend: N0 = U1H, N1 = U1L U2H, N2 = U2L U3H, N3 = U3L U4H, N4 = U4L 0...0. +// Let D1 D2 be the normalized divisor. + cntlzw r.0,r.7 // number of bits to shift left (S) + subfic r.12,r.0,16 // 16-S + subfic r.11,r.0,32 // 32-S + srw r.9,r.6,r.12 // U1H U1L U2H = N0 N1 + srw r.4,r.5,r.11 // U3H + slw r.10,r.6,r.0 // U1L U2H U2L 0...0 + or r.6,r.4,r.10 // U1L U2H U2L U3H = N1 N2 + slw r.4,r.5,r.0 // U3L U4H U4L 0...0 = N3 N4 + slw r.7,r.7,r.0 // normalized divisor (D1 D2) + srwi r.11,r.7,16 // D1 +// Set Q2 = [N0 N1 N2] / [D1 D2]. Start by guessing Q2 = [N0 N1] / D1, then +// adjust if necessary. This guess will occasionally be one too high and +// very rarely two too high, but never higher than that and never too low. +// (See Theorem B in Section 4.3.1 of Knuth, Vol. II, pp. 256-7.) +// Let C N0' N1' N2' be the partial remainder [N0 N1 N2] - Q2 * [D1 D2]. + divwu r.12,r.9,r.11 // guess Q2 = [N0 N1] / D1 + srwi r.10,r.9,16 // 0x0000 N0 + mullw r.5,r.12,r.7 // low word of Q2 * [D1 D2] + subfc r.9,r.5,r.6 // low word of C N0' N1' N2' (N1' N2') + mulhwu r.5,r.12,r.7 // high word of Q2 * [D1 D2] + subfe. r.10,r.5,r.10 // high word of C N0' N1' N2' (C N0') + bge Q2_okay // if difference is >= 0, Q2 was not too high +adjust_Q2: + addc r.9,r.9,r.7 // low word of [C N0' N1' N2']+[D1 D2] + addze. r.10,r.10 // high word of [C N0' N1' N2']+[D1 D2] + addi r.12,r.12,-1 // Q2 - 1 + blt adjust_Q2 // try again if still negative +Q2_okay: +// At this point 0 <= [C N0' N1' N2'] < [D1 D2], so [C N0'] = 0x00000000. +// r.12 holds the upper word of the quotient, 0x0000 Q2. +// Set Q3 = [N1' N2' N3] / [D1 D2] by guessing and adjusting as above. +// Let [N0" N1" N2" N3"] be the partial remainder [N1' N2' N3] - Q3 * [D1 D2]. + divwu r.6,r.9,r.11 // guess Q3 = [N1' N2'] / D1 + srwi r.10,r.9,16 // 0x0000 N1' + slwi r.9,r.9,16 // N2' 0x0000 + inslwi r.9,r.4,16,16 // N2' N3 + mullw r.5,r.6,r.7 // low word of Q3 * [D1 D2] + subfc r.9,r.5,r.9 // N2" N3" + mulhwu r.5,r.6,r.7 // high word of Q3 * [D1 D2] + subfe. r.10,r.5,r.10 // N0" N1" + bge Q3_okay // if difference >= 0, Q3 was not too high +adjust_Q3: + addc r.9,r.9,r.7 // low word of [N0" N1" N2" N3"]+[D1 D2] + addze. r.10,r.10 // high word [N0" N1" N2" N3"]+[D1 D2] + addi r.6,r.6,-1 // Q3 - 1 + blt adjust_Q3 // try again if difference still negative +Q3_okay: +// At this point 0 <= [N0" N1" N2" N3"] < [D1 D2], so [N0" N1"] = 0x00000000. +// Set Q4 = [N2" N3" N4] / [D1 D2] by guessing and adjusting as above. +// Let [R1 R2 R3 R4] be the partial remainder [N2" N3" N4] - Q4 * [D1 D2]. + divwu r.11,r.9,r.11 // guess Q4 = [N2" N3"] / D1 + insrwi r.4,r.9,16,0 // N3" N4 + srwi r.10,r.9,16 // 0x0000 N2" + mullw r.5,r.11,r.7 // low word of Q4 * [D1 D2] + subfc r.9,r.5,r.4 // R3 R4 + mulhwu r.5,r.11,r.7 // high word of Q4 * [D1 D2] + subfe. r.10,r.5,r.10 // R1 R2 + bge Q4_okay // if difference < 0, Q4 was not too high +adjust_Q4: + addc r.9,r.9,r.7 // low word of [R1 R2 R3 R4]+[D1 D2] + addze. r.10,r.10 // high word of [R1 R2 R3 R4]+[D1 D2] + addi r.11,r.11,-1 // Q4 - 1 + blt adjust_Q4 // try again if partial remainder still negative +Q4_okay: +// At this point 0 <= [R1 R2 R3 R4] < [D1 D2], so [R3 R4] is the remainder. + insrwi r.11,r.6,16,0 // low word of quotient: Q3 Q4 + srw r.9,r.9,r.0 // unnormalize remainder + +store_results: + stw r.11,0(r.3) // store low word of quotient + stw r.12,4(r.3) // store high word of quotient + cmplwi r.8,0 // remainder needed? + beqlr // if not, return + stw r.9,0(r.8) // store remainder + blr // return + +div_zero_s: + twi 6,r.7,0 // Trap on divide by zero + + LEAF_EXIT(RtlExtendedLargeIntegerDivide) + + +//++ +// +// LARGE_INTEGER +// RtlExtendedMagicDivide ( +// IN LARGE_INTEGER Dividend, +// IN ULARGE_INTEGER MagicDivisor, +// IN CCHAR ShiftCount +// ) +// +// Routine Description: +// +// This function divides a signed large integer by an unsigned large integer +// and returns the signed large integer result. The division is performed +// using reciprocal multiplication of a signed large integer value by an +// unsigned large integer fraction which represents the most significant +// 64-bits of the reciprocal divisor rounded up in its least significant bit +// and normalized with respect to bit 63. A shift count is also provided +// which is used to truncate the fractional bits from the result value. +// The value returned is the most significant 64 bits of the product +// Dividend*MagicDivisor, shifted right ShiftCount bits. +// +// Arguments: +// +// Dividend (r.5, r.6) - Supplies the dividend value. +// +// MagicDivisor (r.7, r.8) - Supplies the magic divisor value +// which is a 64-bit multiplicative reciprocal. +// +// Shiftcount (r.9) - Supplies the right shift adjustment value, +// assumed to be in the range 0 to 63. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- +// Let Dividend = A B and MagicDivisor = C D, where each of A, B, C, and D is +// a 32-bit word. Then Dividend*MagicDivisor is a 128-bit product, computed +// as follows: +// A B +// x C D +// ========================================================== +// high_word(B*D) low_word(B*D) +// high_word(A*D) low_word(A*D) +// high_word(B*C) low_word(B*C) +// high_word(A*C) low_word(A*C) +// ========================================================== +// P1 P2 P3 P4 +// +// Since the return value is [P1 P2] >> Shift_Count, P3 and P4 need not be +// computed, but the carry out of the P3 column must be computed to compute P2. + + LEAF_ENTRY(RtlExtendedMagicDivide) + +// If the dividend is negative, negate it and record the fact by setting +// cr7 to LT. + crclr 4*cr.7+0 // clear cr.7 LT bit + cmpwi r.6,0 // is high-order word of divisor < 0? + bge divisor_nonnegative // if not, we are ready to compute + crset 4*cr.7+0 // set cr.7 LT bit to mark negation + subfic r.5,r.5,0 // negate lower half of dividend + subfze r.6,r.6 // negate upper half of dividend +divisor_nonnegative: +// To avoid pipeline delays, produce partial products first, in the order they +// will be consumed by the addc and addze instructions below. + mulhwu r.11,r.6,r.7 // high(A*D) + mulhwu r.0,r.5,r.8 // high(B*C) + mulhwu r.12,r.6,r.8 // high(A*C) + mullw r.4,r.6,r.8 // low(A*C) + mulhwu r.10,r.5,r.7 // high(B*D) + mullw r.6,r.6,r.7 // low(A*D) + mullw r.7,r.5,r.8 // low(B*C) +// Now combine the partial products, forming P1 in r.12, P2 in r.11, P3 in r.10: + addc r.11,r.11,r.0 // high(A*D)+high(B*C) + addze r.12,r.12 // high(A*C)+partial carry + addc r.11,r.11,r.4 // high(A*D)+high(B*C)+low(A*C) + addze r.12,r.12 // high(A*C)+partial carry + addc r.10,r.10,r.6 // high(B*D)+low(A*D) + addze r.11,r.11 // hi(A*D)+hi(B*C)+low(A*C)+part. carry + addze r.12,r.12 // high(A*C)+partial carry + addc r.10,r.10,r.7 // high(B*D)+low(A*D)+low(B*C) = P3 + addze r.11,r.11 // hi(A*D)+hi(B*C)+low(A*C)+carry = P2 + addze r.12,r.12 // high(A*C)+carry = P1 +// Shift the 64-bit value whose high half is in r.12 and whose low half is in +// r.11 right by (r.7) bits. The sequence below depends on the fact that +// shift amounts are interpreted mod 64. In particular, a shift amount of +// -N bits, where 0 < N <= 32, specifies a shift of 64-N bits, where +// 32 <= 64-N < 64, and a shift of 32 or more bits always yields zero. +// Let s = (r.9) be the amount to shift right. The sequence below behaves +// differently when s<32, when s=32, and when s>32. When s<32, we view the +// 64-bit value to be shifted as follows: +// +// | r.12 | r.11 | +// +-----------------+------------+-----------------+------------+ +// | T | U | V | W | +// +-----------------+------------+-----------------+------------+ +// |<- (32-s) bits ->|<- s bits ->|<- (32-s) bits ->|<- s bits ->| +// +// When s >= 32, we view the 64-bit value to be shifted as follows: +// +// | r.12 | r.11 | +// +-----------------+------------+------------------------------+ +// | X | Y | Z | +// +-----------------+------------+------------------------------+ +// | |<- (s-32) ->|<------------ 32 ------------>| +// |<- (64-s) bits ->|<--------------- s bits ------------------>| +// + // When s < 32: | When s = 32: | When s > 32: + // -------------+--------------+------------- + subfic r.7,r.9,32 // 32-s (> 0) | 0 | 32-s (< 0) + addi r.8,r.9,-32 // s-32 (< 0) | 0 | s-32 (> 0) + srw r.11,r.11,r.9 // 0...0 V | 0 | 0 + slw r.4,r.12,r.7 // U 0...0 | X (= X Y) | 0 + or r.11,r.11,r.4 // U V | X | 0 + srw r.4,r.12,r.8 // 0 | X | 0...0 X + or r.11,r.11,r.4 // U V | X | 0...0 X + srw r.12,r.12,r.9 // 0...0 T | 0 | 0 + +// If the original dividend was negated, we now negate the result: + bnl cr.7,sign_is_right + subfic r.11,r.11,0 // negate low word + subfze r.12,r.12 // negate high word +sign_is_right: +// Store the result: + stw r.11,0(r.3) // low word of result + stw r.12,4(r.3) // high word of result + blr // return + + LEAF_EXIT(RtlExtendedMagicDivide) + + +//++ +// +// ULARGE_INTEGER +// RtlLargeIntegerDivide ( +// IN ULARGE_INTEGER Dividend, +// IN ULARGE_INTEGER Divisor, +// IN PLARGE_INTEGER Remainder. +// ) +// +// Routine Description: +// +// This function divides an unsigned large integer by an unsigned large +// integer and returns the resultant quotient and optionally the remainder. +// +// Arguments: +// +// Dividend (r.5, r.6) - Supplies the dividend value. +// +// Divisor (r.7, r.8) - Supplies the divisor value. +// +// Remainder (r.9)- Supplies an optional pointer to a variable +// that receives the remainder. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlLargeIntegerDivide) + + or. r.0,r.7,r.8 // combine low and high parts of divisor + beq div0 // if 0, then attempted division by zero + li r.0,64 // set loop count + mtctr r.0 // in the count register + li r.10,0 // clear partial remainder + li r.11,0 // + +// Invariants for the following loop: +// 1. (q<<(CTR)*Divisor) + [r.11 r.10 r.6 r.5]>>(64-(CTR)) = Dividend +// 2. [r.11 r.10] < Divisor +// where q is the rightmost (64-(CTR)) bits of [r.6 r.5] +// Initially, (CTR)=64 and [r.11 r.10] = 0,, so q=0 and +// [r.11 r.10 r.6 r.5]>>(64-(CTR)) = [0 0 r.6 r.5]>>0 = [r.6 r.5], reducing +// the loop invariants to: +// 1. [r.6 r.5] = Dividend +// 2. 0 < Divisor +// At the end of the loop, (CTR)=0, so q=[r.6 r.5] and the loop invariants +// reduce to: +// 1. [r.6 r.5]*Divisor + [r.11 r.10] = Dividend +// 2. [r.11 r.10] < Divisor +// That is, [r.6 r.5] holds the quotient and [r.11 r.10] holds the remainder. +// During execution of the loop, [r.11 r.10] holds the partial remainder, the +// leftmost (CTR) bits of [r.6 r.5] hold the bits of the dividend not yet +// appended to the partial remainder, and the remaining bits of [r.6 r.5] +// hold the leftmost (64-(CTR)) bits of the quotient. + +divl: +// Shift the 128-bit quantity [r.11 r.10 r.6 r.5] left one bit. This has the +// effect of dropping the leftmost bit of the partial remainder (necessarily +// zero), "bringing down" the next bit of the dividend to the right end of the +// partial remainder, and shifting the partial quotient left one bit. + slwi r.11,r.11,1 // shift r.11 left one bit + inslwi r.11,r.10,1,31 // left bit of r.10 to right bit of r.11 + slwi r.10,r.10,1 // shift r.10 left one bit + inslwi r.10,r.6,1,31 // left bit of r.6 to right bit of r.10 + slwi r.6,r.6,1 // shift r.6 left one bit + inslwi r.6,r.5,1,31 // left bit of r.5 to right bit of r.6 + slwi r.5,r.5,1 // shift r.5 left one bit +// If [r.11 r.10] >= Divisor, increment the quotient and subtract the divisor +// from the partial remainder: + cmplw cr.0,r.11,r.8 // high(partial_rem) vs. high(divisor) + cmplw cr.1,r.10,r.7 // low(partial_rem) vs. low(divisor) + bgt cr.0,PR_greater // high(part_rem) > high(divisor) + blt cr.0,endl // high(part_rem) < high(divisor) + blt cr.1,endl // highs =, low(part_rem) < low(divisor) + +PR_greater: + ori r.5,r.5,1 // increment shifted quotient + subfc r.10,r.7,r.10 // low(part_rem-divisor) + subfe r.11,r.8,r.11 // high(part_rem-divisor) + +endl: bdnz divl // decrement CTR and loop + + cmplwi r.9,0 // remainder requested? + beq norem // no remainder + stw r.10,0(r.9) // store low part of remainder + stw r.11,4(r.9) // store high part of remainder +norem: stw r.5,0(r.3) // store low part of quotient + stw r.6,4(r.3) // store high part of quotient + blr + +div0: + twi 6,r.0,0 // Trap on divide by zero + + LEAF_EXIT(RtlLargeIntegerDivide) // + + + +//++ +// +// LARGE_INTEGER +// Rtl ExtendedIntegerMultiply ( +// IN LARGE_INTEGER Multiplicand, +// IN LONG Multiplier +// ) +// +// Routine Description: +// +// This function multiplies a signed large integer by a signed integer and +// returns the signed large integer result. +// +// Arguments: +// +// Multiplicand (r.5, r.6) - Supplies the multiplicand value. +// +// Multiplier (r.7) - Supplies the multiplier value. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlExtendedIntegerMultiply) + +// If A B is the multiplicand and C is the multiplier (where A, B, and C are +// each 32 bits long), the product is computed as follows: +// +// A B +// * C +// ============================= +// high(B*C) low(B*C) +// + high(A*C) low(A*C) +// ============================= +// P1 P2 P3 +// +// Since the high-order bit of B is not a sign bit but the high-order bit of +// C is, we have no multiplication instruction appropriate for computing +// high(B*C) directly. Instead, we negate any negative operand before +// doing the multiplication, multiply using unsigned arithmetic, and then +// negate the product if we had negated exactly one operand. If P1 is +// nonzero before negating the product, the multiplication has overflowed. +// We use the LT bit of cr.7 to track whether exactly one operand has +// been negated. + + crclr 4*cr.7+0 // clear LT bit of cr.7 + cmpwi r.6,0 // test sign of multiplicand + bge multiplicand_adjusted // if nonnegative, proceed + subfic r.5,r.5,0 // negate low part of multiplicand + subfze r.6,r.6 // negate high part of multiplicand + crset 4*cr.7+0 // set LT bit of cr.7 +multiplicand_adjusted: + cmpwi r.7,0 // test sign of multiplier + bge multiplier_adjusted // if nonnegative, proceed + neg r.7,r.7 // negate multiplier + crnot 4*cr.7+0,4*cr.7+0 // invert LT bit of cr.7 +multiplier_adjusted: + mulhwu r.9,r.5,r.7 // high(B*C) + mullw r.10,r.6,r.7 // low(A*C) + mulhwu r.11,r.6,r.7 // high(A*C) + mullw r.8,r.5,r.7 // P3 = low(B*C) + addc r.9,r.9,r.10 // P2 = high(B*C)+low(A*C) + addze r.11,r.11 // P1 = high(A*C)+[carry out of P2] + cmpwi r.11,0 // check for overflow + bne mull_over + bnl cr.7,product_adjusted // was exactly one operand negated? + subfic r.8,r.8,0 // negate low part of product + subfze r.9,r.9 // negate high part of product +product_adjusted: + stw r.8,0(r.3) // store low word of product + stw r.9,4(r.3) // store high word of product + blr +mull_over: + twi 0x1b,r.11,0 // Trap on overflow + + LEAF_EXIT(RtlExtendedIntegerMultiply) + + + +//++ +// +// LARGE_INTEGER +// RtlLargeIntegerNegate ( +// IN LARGE_INTEGER Subtrahend +// ) +// +// Routine Description: +// +// This function negates a signed large integer and returns the signed +// large integer result. +// +// Arguments: +// +// Subtrahend (r.5, r.6) - Supplies the subtrahend value. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlLargeIntegerNegate) + + subfic r.5,r.5,0 // double precision subtract from 0 + subfze r.6,r.6 + stw r.5,0(r.3) // store low part of result + stw r.6,4(r.3) // store high part of result + LEAF_EXIT(RtlLargeIntegerNegate) // return + + + +//++ +// +// LARGE_INTEGER +// RtlLargeIntegerSubtract ( +// IN LARGE_INTEGER Minuend, +// IN LARGE_INTEGER Subtrahend +// ) +// +// Routine Description: +// +// This function subtracts a signed large integer from a signed large +// integer and returns the signed large integer result. +// +// Arguments: +// +// Minuend (r.5, r.6) - Supplies the minuend value. +// +// Subtrahend (r.7, r.8) - Supplies the subtrahend value. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlLargeIntegerSubtract) + + subfc r.5,r.7,r.5 // double precision subtract + subfe r.6,r.8,r.6 + stw r.5,0(r.3) // store low part of result + stw r.6,4(r.3) // store high part of result + LEAF_EXIT(RtlLargeIntegerSubtract) // return + + + +//++ +// +// LARGE_INTEGER +// RtlLargeIntegerShiftLeft ( +// IN LARGE_INTEGER LargeInteger, +// IN CCHAR ShiftCount +// ) +// +// Routine Description: +// +// This function shifts a signed large integer left by an unsigned +// integer modulo 64 and returns the shifted signed large integer +// result. +// +// N.B. No test is made for significant bits shifted out of the result. +// +// Arguments: +// +// LargeInteger (r.5, r.6) - Supplies the large integer to be shifted. +// +// ShiftCount (r.7) - Supplies the left shift count. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlLargeIntegerShiftLeft) + + andi. r.7,r.7,0x3f // mod 64 of shift count + subfic r.8,r.7,32 + slw r.6,r.6,r.7 + srw r.0,r.5,r.8 + or r.6,r.6,r.0 + addic r.8,r.7,-32 + slw r.0,r.5,r.8 + or r.6,r.6,r.0 + slw r.5,r.5,r.7 + stw r.5,0(r.3) // store low result + stw r.6,4(r.3) // store high result + LEAF_EXIT(RtlLargeIntegerShiftLeft) + + + +//++ +// +// LARGE_INTEGER +// RtlLargeIntegerShiftRight ( +// IN LARGE_INTEGER LargeInteger, +// IN CCHAR ShiftCount +// ) +// +// Routine Description: +// +// This function shifts an unsigned large integer right by an unsigned +// integer modulo 64 and returns the shifted unsigned large integer +// result. +// +// Arguments: +// +// LargeInteger (r.5, r.6) - Supplies the large integer to be shifted. +// +// ShiftCount (r.7) - Supplies the right shift count. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlLargeIntegerShiftRight) + + andi. r.7,r.7,0x3f // mod 64 of shift count + +// The sequence below depends on the fact that shift amounts are interpreted +// mod 64. In particular, a shift amount of -N bits, where 0 < N <= 32, +// specifies a shift of 64-N bits, where 32 <= 64-N < 64, and a shift of 32 or +// more bits always yields zero. Let s = (r.7) be the amount to shift right. +// The sequence below behaves differently when s<32, when s=32, and when s>32. +// When s<32, we view the 64-bit value to be shifted as follows: +// +// +// | r.6 | r.5 | +// +-----------------+------------+-----------------+------------+ +// | T | U | V | W | +// +-----------------+------------+-----------------+------------+ +// |<- (32-s) bits ->|<- s bits ->|<- (32-s) bits ->|<- s bits ->| +// +// When s >= 32, we view the 64-bit value to be shifted as follows: +// +// | r.6 | r.5 | +// +-----------------+------------+------------------------------+ +// | X | Y | Z | +// +-----------------+------------+------------------------------+ +// | |<- (s-32) ->|<------------ 32 ------------>| +// |<- (64-s) bits ->|<--------------- s bits ------------------>| +// + // When s < 32: | When s = 32: | When s > 32: + // -------------+--------------+------------- + subfic r.8,r.7,32 // 32-s (> 0) | 0 | 32-s (< 0) + addi r.9,r.7,-32 // s-32 (< 0) | 0 | s-32 (> 0) + srw r.5,r.5,r.7 // 0...0 V | 0 | 0 + slw r.0,r.6,r.8 // U 0...0 | X (= X Y) | 0 + or r.5,r.5,r.0 // U V | X | 0 + srw r.0,r.6,r.9 // 0 | X | 0...0 X + or r.5,r.5,r.0 // U V | X | 0...0 X + srw r.6,r.6,r.7 // 0...0 T | 0 | 0 + + stw r.5,0(r.3) // store low result + stw r.6,4(r.3) // store high result + LEAF_EXIT(RtlLargeIntegerShiftRight) + + + +//++ +// +// LARGE_INTEGER +// RtlLargeIntegerArithmeticShift ( +// IN LARGE_INTEGER LargeInteger, +// IN CCHAR ShiftCount +// ) +// +// Routine Description: +// +// This function shifts a signed large integer right by an unsigned +// integer modulo 64 and returns the shifted signed large integer +// result. +// +// Arguments: +// +// LargeInteger (r.5, r.6) - Supplies the large integer to be shifted. +// +// ShiftCount (r.7) - Supplies the right shift count. +// +// Return Value: +// +// The large integer result is stored at the address supplied by r.3. +// +//-- + + LEAF_ENTRY(RtlLargeIntegerArithmeticShift) + + andi. r.7,r.7,0x3f // mod 64 of shift count + +// The sequence below depends on the fact that shift amounts are interpreted +// mod 64. In particular, a shift amount of -N bits, where 0 < N <= 32, +// specifies a shift of 64-N bits, where 32 <= 64-N < 64, and an arithmetic +// shift of 32 or more bits always yields 32 copies of the original sign bit. +// Let s = (r.7) be the amount to shift right. The sequence below behaves +// differently when s<=32 and when s>32. When s<=32, we view the 64-bit value +// to be shifted as follows: +// +// +// | r.6 | r.5 | +// +-----------------+------------+-----------------+------------+ +// | T | U | V | W | +// +-----------------+------------+-----------------+------------+ +// |<- (32-s) bits ->|<- s bits ->|<- (32-s) bits ->|<- s bits ->| +// +// When s > 32, we view the 64-bit value to be shifted as follows: +// +// | r.6 | r.5 | +// +-----------------+------------+------------------------------+ +// | X | Y | Z | +// +-----------------+------------+------------------------------+ +// | |<- (s-32) ->|<------------ 32 ------------>| +// |<- (64-s) bits ->|<--------------- s bits ------------------>| +// + + // When s <= 32: | When s > 32: + // ----------------------+---------------------- + subfic r.8,r.7,32 // 32-s (>= 0) | 32-s (< 0) + srw r.5,r.5,r.7 // 0...0 V | 0 + slw r.0,r.6,r.8 // U 0...0 | 0 + or r.5,r.5,r.0 // U V | 0 + addic. r.9,r.7,-32 // s-32 (<= 0) | s-32 (> 0) + sraw r.10,r.6,r.9 // sign(TU)...sign(TU) | sign(XY)...sign(XY) X + ble more_than_32 // (CR0 set by addic. two instructions earlier.) + mr r.5,r.10 // [instruction skipped] | sign(XY)...sign(XY) X +more_than_32: // | + sraw r.6,r.6,r.7 // sign(T)...sign(T) T | sign(XY)...sign(XY) + + stw r.5,0(r.3) // store low result + stw r.6,4(r.3) // store high result + LEAF_EXIT(RtlLargeIntegerArithmeticShift) |