1 /*******************************************************************************
3 * Module Name: utmath - Integer math support routines
5 ******************************************************************************/
8 * Copyright (C) 2000 - 2005, 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: Dividend - 64-bit 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 dividend
,
79 acpi_integer
*out_quotient
,
82 union uint64_overlay dividend_ovl
;
83 union uint64_overlay quotient
;
87 ACPI_FUNCTION_TRACE ("ut_short_divide");
90 /* Always check for a zero divisor */
93 ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n"));
94 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO
);
97 dividend_ovl
.full
= dividend
;
100 * The quotient is 64 bits, the remainder is always 32 bits,
101 * and is generated by the second divide.
103 ACPI_DIV_64_BY_32 (0, dividend_ovl
.part
.hi
, divisor
,
104 quotient
.part
.hi
, remainder32
);
105 ACPI_DIV_64_BY_32 (remainder32
, dividend_ovl
.part
.lo
, divisor
,
106 quotient
.part
.lo
, remainder32
);
108 /* Return only what was requested */
111 *out_quotient
= quotient
.full
;
114 *out_remainder
= remainder32
;
117 return_ACPI_STATUS (AE_OK
);
121 /*******************************************************************************
123 * FUNCTION: acpi_ut_divide
125 * PARAMETERS: in_dividend - Dividend
126 * in_divisor - Divisor
127 * out_quotient - Pointer to where the quotient is returned
128 * out_remainder - Pointer to where the remainder is returned
130 * RETURN: Status (Checks for divide-by-zero)
132 * DESCRIPTION: Perform a divide and modulo.
134 ******************************************************************************/
138 acpi_integer in_dividend
,
139 acpi_integer in_divisor
,
140 acpi_integer
*out_quotient
,
141 acpi_integer
*out_remainder
)
143 union uint64_overlay dividend
;
144 union uint64_overlay divisor
;
145 union uint64_overlay quotient
;
146 union uint64_overlay remainder
;
147 union uint64_overlay normalized_dividend
;
148 union uint64_overlay normalized_divisor
;
150 union uint64_overlay partial2
;
151 union uint64_overlay partial3
;
154 ACPI_FUNCTION_TRACE ("ut_divide");
157 /* Always check for a zero divisor */
159 if (in_divisor
== 0) {
160 ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
161 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO
);
164 divisor
.full
= in_divisor
;
165 dividend
.full
= in_dividend
;
166 if (divisor
.part
.hi
== 0) {
168 * 1) Simplest case is where the divisor is 32 bits, we can
169 * just do two divides
171 remainder
.part
.hi
= 0;
174 * The quotient is 64 bits, the remainder is always 32 bits,
175 * and is generated by the second divide.
177 ACPI_DIV_64_BY_32 (0, dividend
.part
.hi
, divisor
.part
.lo
,
178 quotient
.part
.hi
, partial1
);
179 ACPI_DIV_64_BY_32 (partial1
, dividend
.part
.lo
, divisor
.part
.lo
,
180 quotient
.part
.lo
, remainder
.part
.lo
);
185 * 2) The general case where the divisor is a full 64 bits
188 quotient
.part
.hi
= 0;
189 normalized_dividend
= dividend
;
190 normalized_divisor
= divisor
;
192 /* Normalize the operands (shift until the divisor is < 32 bits) */
195 ACPI_SHIFT_RIGHT_64 (normalized_divisor
.part
.hi
,
196 normalized_divisor
.part
.lo
);
197 ACPI_SHIFT_RIGHT_64 (normalized_dividend
.part
.hi
,
198 normalized_dividend
.part
.lo
);
200 } while (normalized_divisor
.part
.hi
!= 0);
204 ACPI_DIV_64_BY_32 (normalized_dividend
.part
.hi
,
205 normalized_dividend
.part
.lo
,
206 normalized_divisor
.part
.lo
,
207 quotient
.part
.lo
, partial1
);
210 * The quotient is always 32 bits, and simply requires adjustment.
211 * The 64-bit remainder must be generated.
213 partial1
= quotient
.part
.lo
* divisor
.part
.hi
;
214 partial2
.full
= (acpi_integer
) quotient
.part
.lo
* divisor
.part
.lo
;
215 partial3
.full
= (acpi_integer
) partial2
.part
.hi
+ partial1
;
217 remainder
.part
.hi
= partial3
.part
.lo
;
218 remainder
.part
.lo
= partial2
.part
.lo
;
220 if (partial3
.part
.hi
== 0) {
221 if (partial3
.part
.lo
>= dividend
.part
.hi
) {
222 if (partial3
.part
.lo
== dividend
.part
.hi
) {
223 if (partial2
.part
.lo
> dividend
.part
.lo
) {
225 remainder
.full
-= divisor
.full
;
230 remainder
.full
-= divisor
.full
;
234 remainder
.full
= remainder
.full
- dividend
.full
;
235 remainder
.part
.hi
= (u32
) -((s32
) remainder
.part
.hi
);
236 remainder
.part
.lo
= (u32
) -((s32
) remainder
.part
.lo
);
238 if (remainder
.part
.lo
) {
244 /* Return only what was requested */
247 *out_quotient
= quotient
.full
;
250 *out_remainder
= remainder
.full
;
253 return_ACPI_STATUS (AE_OK
);
258 /*******************************************************************************
260 * FUNCTION: acpi_ut_short_divide, acpi_ut_divide
262 * DESCRIPTION: Native versions of the ut_divide functions. Use these if either
263 * 1) The target is a 64-bit platform and therefore 64-bit
264 * integer math is supported directly by the machine.
265 * 2) The target is a 32-bit or 16-bit platform, and the
266 * double-precision integer math library is available to
267 * perform the divide.
269 ******************************************************************************/
272 acpi_ut_short_divide (
273 acpi_integer in_dividend
,
275 acpi_integer
*out_quotient
,
279 ACPI_FUNCTION_TRACE ("ut_short_divide");
282 /* Always check for a zero divisor */
285 ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n"));
286 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO
);
289 /* Return only what was requested */
292 *out_quotient
= in_dividend
/ divisor
;
295 *out_remainder
= (u32
) in_dividend
% divisor
;
298 return_ACPI_STATUS (AE_OK
);
303 acpi_integer in_dividend
,
304 acpi_integer in_divisor
,
305 acpi_integer
*out_quotient
,
306 acpi_integer
*out_remainder
)
308 ACPI_FUNCTION_TRACE ("ut_divide");
311 /* Always check for a zero divisor */
313 if (in_divisor
== 0) {
314 ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
315 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO
);
319 /* Return only what was requested */
322 *out_quotient
= in_dividend
/ in_divisor
;
325 *out_remainder
= in_dividend
% in_divisor
;
328 return_ACPI_STATUS (AE_OK
);