summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/haleagle/ppc/pxmisc.s
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/haleagle/ppc/pxmisc.s')
-rw-r--r--private/ntos/nthals/haleagle/ppc/pxmisc.s183
1 files changed, 183 insertions, 0 deletions
diff --git a/private/ntos/nthals/haleagle/ppc/pxmisc.s b/private/ntos/nthals/haleagle/ppc/pxmisc.s
new file mode 100644
index 000000000..8e3b58ac7
--- /dev/null
+++ b/private/ntos/nthals/haleagle/ppc/pxmisc.s
@@ -0,0 +1,183 @@
+//++
+//
+// Copyright (c) 1993 IBM Corporation
+//
+// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file
+// contains copyrighted material. Use of this file is restricted
+// by the provisions of a Motorola Software License Agreement.
+//
+// Module Name:
+//
+// pxmisc.s
+//
+// Abstract:
+//
+// This module implements miscellaneous routines on the PowerPC.
+//
+// Author:
+//
+// Steve Johns (sjohns@pets.sps.mot.com) August 1994
+//
+// Environment:
+//
+// Kernel mode only.
+//
+
+#include "kxppc.h"
+
+ .set HID0, 1008 // SPR # for HID0
+
+
+ LEAF_ENTRY(HalpGetHID0)
+
+ mfspr r.3, HID0
+
+ LEAF_EXIT(HalpGetHID0)
+
+
+
+
+ LEAF_ENTRY(HalpSetHID0)
+
+ mtspr HID0, r.3
+
+ LEAF_EXIT(HalpSetHID0)
+
+
+
+
+// ULONG HalpDivide (
+// IN ULARGE_INTEGER Dividend,
+// IN ULONG Divisor)
+//
+// Routine Description:
+//
+// This function divides an unsigned large integer by an unsigned long
+// and returns the resultant quotient.
+//
+// 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.
+//
+// Return Value:
+//
+// The ULONG quotient is returned as the function value.
+//
+//--
+
+
+
+ .set Quotient, r.3
+ .set DividendLo, r.3
+ .set DividendHi, r.4
+ .set Divisor, r.5
+ .set Q1, r.11
+ .set N, r.12
+ .set Q0, N // Use of N & Q0 don't overlap
+
+ LEAF_ENTRY(HalpDivide)
+
+
+ cmplw DividendHi,Divisor
+ bge overflow // catch overflow or division by 0
+ cmplwi DividendHi,0 // test high part for 0
+ bne Divide64Bits
+
+// High 32 bits of Dividend == 0, so use 32 bit division.
+ divwu Quotient,DividendLo,Divisor // Quotient = Dividend/Divisor
+ blr
+
+Divide64Bits:
+
+
+// Normalize: Shift divisor and dividend left to get rid of leading zeroes
+// in the divisor. Since DividendHi < Divisor, only zeroes are shifted out
+// of the dividend.
+ cntlzw N,Divisor // number of bits to shift (N)
+ slw Divisor,Divisor,N // shift divisor
+ slw DividendHi,DividendHi,N // shift upper part of dividend
+ mr r.8, DividendLo // Save unshifted DividendLo
+ slw DividendLo,DividendLo,N // shift lower part of dividend
+ subfic N,N,32 // 32-N
+ srw N,r.8,N // leftmost N bits of DividendLo, slid right
+ or DividendHi,DividendHi,N // and inserted into low end of DividendHi
+
+// 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.
+// (DividendHi holds A0 A1, DividendLo holds A2 A3, and Divisor 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,Divisor,16 // r.8 <- B0
+ divwu Q0,DividendHi,r.8 // Q0 <- 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,Q0,Divisor // low word of Q0 times B0 B1
+ mulhwu r.10,Q0,Divisor // 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 DividendLo,r.9,DividendLo // low word of difference
+ subfe DividendHi,r.10,DividendHi // 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 DividendHi,0 // A0 A1 A2 A3 is negative iff A0 A1 is
+ bge Q0_okay // no correction needed
+ inslwi r.10,Divisor,16,16 // high word of B0 B1 0000 (= 0000 B0)
+ slwi r.9,Divisor,16 // low word of B0 B1 0000 (= B1 0000)
+adjust_Q0:
+ addc DividendLo,DividendLo,r.9 // add B0 B1 0000 to A0 A1 A2 A3 (low)
+ adde DividendHi,DividendHi,r.10 // add B0 B1 0000 to A0 A1 A2 A3 (high)
+ cmpwi DividendHi,0 // Is A0 A1 A2 A3 now nonnegative?
+ addi Q0,Q0,-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.
+// (DividendHi holds A0 A1, DividendLo holds A2 A3, and r.8 holds B0.)
+ slwi r.9,DividendHi,16 // r.9 <- A1 0000
+ inslwi r.9,DividendLo,16,16 // r.9 <- A1 A2
+ divwu Q1,r.9,r.8 // Q1 <- 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,Q1,Divisor // low word of Q1 times B0 B1
+ mulhwu r.10,Q1,Divisor // high word of Q1 times B0 B1
+ subfc DividendLo,r.9,DividendLo // low word of difference
+ subfe DividendHi,r.10,DividendHi // 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 DividendHi,0 // A0 A1 A2 A3 is negative iff A0 A1 is
+ bge Q1_okay // no correction needed
+adjust_Q1:
+ addc DividendLo,DividendLo,Divisor // add B0 B1 to A0 A1 A2 A3 (low)
+ addze DividendHi,DividendHi // add B0 B1 to A0 A1 A2 A3 (high)
+ cmpwi DividendHi,0 // Is A0 A1 A2 A3 now nonnegative?
+ addi Q1,Q1,-1 // decrement Q1
+ blt adjust_Q1 // if A0 A1 A2 A3 still negative, repeat
+Q1_okay:
+ slwi Quotient,Q0,16 // Quotient <- Q0 A1
+ or Quotient,Quotient,Q1
+ blr
+
+
+// The error cases:
+overflow:
+ li Quotient, 0 // return(0);
+ LEAF_EXIT(HalpDivide)
+
+
+
+