1 /*******************************************************************************
3 * Module Name: utmath - Integer math support routines
5 ******************************************************************************/
8 * Copyright (C) 2000 - 2004, R. Byron Moore
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
45 #include <acpi/acpi.h>
48 #define _COMPONENT ACPI_UTILITIES
49 ACPI_MODULE_NAME ("utmath")
52 * Support for double-precision integer divide. This code is included here
53 * in order to support kernel environments where the double-precision math
54 * library is not available.
57 #ifndef ACPI_USE_NATIVE_DIVIDE
58 /*******************************************************************************
60 * FUNCTION: acpi_ut_short_divide
62 * PARAMETERS: in_dividend - Pointer to the dividend
63 * Divisor - 32-bit divisor
64 * out_quotient - Pointer to where the quotient is returned
65 * out_remainder - Pointer to where the remainder is returned
67 * RETURN: Status (Checks for divide-by-zero)
69 * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits)
70 * divide and modulo. The result is a 64-bit quotient and a
73 ******************************************************************************/
76 acpi_ut_short_divide (
77 acpi_integer *in_dividend,
79 acpi_integer *out_quotient,
82 union uint64_overlay dividend;
83 union uint64_overlay quotient;
87 ACPI_FUNCTION_TRACE ("ut_short_divide");
89 dividend.full = *in_dividend;
91 /* Always check for a zero divisor */
94 ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n"));
95 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
99 * The quotient is 64 bits, the remainder is always 32 bits,
100 * and is generated by the second divide.
102 ACPI_DIV_64_BY_32 (0, dividend.part.hi, divisor,
103 quotient.part.hi, remainder32);
104 ACPI_DIV_64_BY_32 (remainder32, dividend.part.lo, divisor,
105 quotient.part.lo, remainder32);
107 /* Return only what was requested */
110 *out_quotient = quotient.full;
113 *out_remainder = remainder32;
116 return_ACPI_STATUS (AE_OK);
120 /*******************************************************************************
122 * FUNCTION: acpi_ut_divide
124 * PARAMETERS: in_dividend - Pointer to the dividend
125 * in_divisor - Pointer to the divisor
126 * out_quotient - Pointer to where the quotient is returned
127 * out_remainder - Pointer to where the remainder is returned
129 * RETURN: Status (Checks for divide-by-zero)
131 * DESCRIPTION: Perform a divide and modulo.
133 ******************************************************************************/
137 acpi_integer *in_dividend,
138 acpi_integer *in_divisor,
139 acpi_integer *out_quotient,
140 acpi_integer *out_remainder)
142 union uint64_overlay dividend;
143 union uint64_overlay divisor;
144 union uint64_overlay quotient;
145 union uint64_overlay remainder;
146 union uint64_overlay normalized_dividend;
147 union uint64_overlay normalized_divisor;
149 union uint64_overlay partial2;
150 union uint64_overlay partial3;
153 ACPI_FUNCTION_TRACE ("ut_divide");
156 /* Always check for a zero divisor */
158 if (*in_divisor == 0) {
159 ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
160 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
163 divisor.full = *in_divisor;
164 dividend.full = *in_dividend;
165 if (divisor.part.hi == 0) {
167 * 1) Simplest case is where the divisor is 32 bits, we can
168 * just do two divides
170 remainder.part.hi = 0;
173 * The quotient is 64 bits, the remainder is always 32 bits,
174 * and is generated by the second divide.
176 ACPI_DIV_64_BY_32 (0, dividend.part.hi, divisor.part.lo,
177 quotient.part.hi, partial1);
178 ACPI_DIV_64_BY_32 (partial1, dividend.part.lo, divisor.part.lo,
179 quotient.part.lo, remainder.part.lo);
184 * 2) The general case where the divisor is a full 64 bits
187 quotient.part.hi = 0;
188 normalized_dividend = dividend;
189 normalized_divisor = divisor;
191 /* Normalize the operands (shift until the divisor is < 32 bits) */
194 ACPI_SHIFT_RIGHT_64 (normalized_divisor.part.hi,
195 normalized_divisor.part.lo);
196 ACPI_SHIFT_RIGHT_64 (normalized_dividend.part.hi,
197 normalized_dividend.part.lo);
199 } while (normalized_divisor.part.hi != 0);
203 ACPI_DIV_64_BY_32 (normalized_dividend.part.hi,
204 normalized_dividend.part.lo,
205 normalized_divisor.part.lo,
206 quotient.part.lo, partial1);
209 * The quotient is always 32 bits, and simply requires adjustment.
210 * The 64-bit remainder must be generated.
212 partial1 = quotient.part.lo * divisor.part.hi;
213 partial2.full = (acpi_integer) quotient.part.lo * divisor.part.lo;
214 partial3.full = (acpi_integer) partial2.part.hi + partial1;
216 remainder.part.hi = partial3.part.lo;
217 remainder.part.lo = partial2.part.lo;
219 if (partial3.part.hi == 0) {
220 if (partial3.part.lo >= dividend.part.hi) {
221 if (partial3.part.lo == dividend.part.hi) {
222 if (partial2.part.lo > dividend.part.lo) {
224 remainder.full -= divisor.full;
229 remainder.full -= divisor.full;
233 remainder.full = remainder.full - dividend.full;
234 remainder.part.hi = (u32) -((s32) remainder.part.hi);
235 remainder.part.lo = (u32) -((s32) remainder.part.lo);
237 if (remainder.part.lo) {
243 /* Return only what was requested */
246 *out_quotient = quotient.full;
249 *out_remainder = remainder.full;
252 return_ACPI_STATUS (AE_OK);
257 /*******************************************************************************
259 * FUNCTION: acpi_ut_short_divide, acpi_ut_divide
261 * DESCRIPTION: Native versions of the ut_divide functions. Use these if either
262 * 1) The target is a 64-bit platform and therefore 64-bit
263 * integer math is supported directly by the machine.
264 * 2) The target is a 32-bit or 16-bit platform, and the
265 * double-precision integer math library is available to
266 * perform the divide.
268 ******************************************************************************/
271 acpi_ut_short_divide (
272 acpi_integer *in_dividend,
274 acpi_integer *out_quotient,
278 ACPI_FUNCTION_TRACE ("ut_short_divide");
281 /* Always check for a zero divisor */
284 ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n"));
285 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
288 /* Return only what was requested */
291 *out_quotient = *in_dividend / divisor;
294 *out_remainder = (u32) *in_dividend % divisor;
297 return_ACPI_STATUS (AE_OK);
302 acpi_integer *in_dividend,
303 acpi_integer *in_divisor,
304 acpi_integer *out_quotient,
305 acpi_integer *out_remainder)
307 ACPI_FUNCTION_TRACE ("ut_divide");
310 /* Always check for a zero divisor */
312 if (*in_divisor == 0) {
313 ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
314 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
318 /* Return only what was requested */
321 *out_quotient = *in_dividend / *in_divisor;
324 *out_remainder = *in_dividend % *in_divisor;
327 return_ACPI_STATUS (AE_OK);