utmath.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*******************************************************************************
  2.  *
  3.  * Module Name: utmath - Integer math support routines
  4.  *              $Revision: 7 $
  5.  *
  6.  ******************************************************************************/
  7. /*
  8.  *  Copyright (C) 2000, 2001 R. Byron Moore
  9.  *
  10.  *  This program is free software; you can redistribute it and/or modify
  11.  *  it under the terms of the GNU General Public License as published by
  12.  *  the Free Software Foundation; either version 2 of the License, or
  13.  *  (at your option) any later version.
  14.  *
  15.  *  This program is distributed in the hope that it will be useful,
  16.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  *  GNU General Public License for more details.
  19.  *
  20.  *  You should have received a copy of the GNU General Public License
  21.  *  along with this program; if not, write to the Free Software
  22.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  23.  */
  24. #include "acpi.h"
  25. #define _COMPONENT          ACPI_UTILITIES
  26.  MODULE_NAME         ("utmath")
  27. /*
  28.  * Support for double-precision integer divide.  This code is included here
  29.  * in order to support kernel environments where the double-precision math
  30.  * library is not available.
  31.  */
  32. #ifndef ACPI_USE_NATIVE_DIVIDE
  33. /*******************************************************************************
  34.  *
  35.  * FUNCTION:    Acpi_ut_short_divide
  36.  *
  37.  * PARAMETERS:  In_dividend         - Pointer to the dividend
  38.  *              Divisor             - 32-bit divisor
  39.  *              Out_quotient        - Pointer to where the quotient is returned
  40.  *              Out_remainder       - Pointer to where the remainder is returned
  41.  *
  42.  * RETURN:      Status (Checks for divide-by-zero)
  43.  *
  44.  * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits)
  45.  *              divide and modulo.  The result is a 64-bit quotient and a
  46.  *              32-bit remainder.
  47.  *
  48.  ******************************************************************************/
  49. acpi_status
  50. acpi_ut_short_divide (
  51. acpi_integer            *in_dividend,
  52. u32                     divisor,
  53. acpi_integer            *out_quotient,
  54. u32                     *out_remainder)
  55. {
  56. uint64_overlay          dividend;
  57. uint64_overlay          quotient;
  58. u32                     remainder32;
  59. FUNCTION_TRACE ("Ut_short_divide");
  60. dividend.full = *in_dividend;
  61. /* Always check for a zero divisor */
  62. if (divisor == 0) {
  63. REPORT_ERROR (("Acpi_ut_short_divide: Divide by zeron"));
  64. return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
  65. }
  66. /*
  67.  * The quotient is 64 bits, the remainder is always 32 bits,
  68.  * and is generated by the second divide.
  69.  */
  70. ACPI_DIV_64_BY_32 (0, dividend.part.hi, divisor,
  71.   quotient.part.hi, remainder32);
  72. ACPI_DIV_64_BY_32 (remainder32, dividend.part.lo,  divisor,
  73.   quotient.part.lo, remainder32);
  74. /* Return only what was requested */
  75. if (out_quotient) {
  76. *out_quotient = quotient.full;
  77. }
  78. if (out_remainder) {
  79. *out_remainder = remainder32;
  80. }
  81. return_ACPI_STATUS (AE_OK);
  82. }
  83. /*******************************************************************************
  84.  *
  85.  * FUNCTION:    Acpi_ut_divide
  86.  *
  87.  * PARAMETERS:  In_dividend         - Pointer to the dividend
  88.  *              In_divisor          - Pointer to the divisor
  89.  *              Out_quotient        - Pointer to where the quotient is returned
  90.  *              Out_remainder       - Pointer to where the remainder is returned
  91.  *
  92.  * RETURN:      Status (Checks for divide-by-zero)
  93.  *
  94.  * DESCRIPTION: Perform a divide and modulo.
  95.  *
  96.  ******************************************************************************/
  97. acpi_status
  98. acpi_ut_divide (
  99. acpi_integer            *in_dividend,
  100. acpi_integer            *in_divisor,
  101. acpi_integer            *out_quotient,
  102. acpi_integer            *out_remainder)
  103. {
  104. uint64_overlay          dividend;
  105. uint64_overlay          divisor;
  106. uint64_overlay          quotient;
  107. uint64_overlay          remainder;
  108. uint64_overlay          normalized_dividend;
  109. uint64_overlay          normalized_divisor;
  110. u32                     partial1;
  111. uint64_overlay          partial2;
  112. uint64_overlay          partial3;
  113. FUNCTION_TRACE ("Ut_divide");
  114. /* Always check for a zero divisor */
  115. if (*in_divisor == 0) {
  116. REPORT_ERROR (("Acpi_ut_divide: Divide by zeron"));
  117. return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
  118. }
  119. divisor.full  = *in_divisor;
  120. dividend.full = *in_dividend;
  121. if (divisor.part.hi == 0) {
  122. /*
  123.  * 1) Simplest case is where the divisor is 32 bits, we can
  124.  * just do two divides
  125.  */
  126. remainder.part.hi = 0;
  127. /*
  128.  * The quotient is 64 bits, the remainder is always 32 bits,
  129.  * and is generated by the second divide.
  130.  */
  131. ACPI_DIV_64_BY_32 (0, dividend.part.hi, divisor.part.lo,
  132.   quotient.part.hi, partial1);
  133. ACPI_DIV_64_BY_32 (partial1, dividend.part.lo, divisor.part.lo,
  134.   quotient.part.lo, remainder.part.lo);
  135. }
  136. else {
  137. /*
  138.  * 2) The general case where the divisor is a full 64 bits
  139.  * is more difficult
  140.  */
  141. quotient.part.hi   = 0;
  142. normalized_dividend = dividend;
  143. normalized_divisor = divisor;
  144. /* Normalize the operands (shift until the divisor is < 32 bits) */
  145. do {
  146. ACPI_SHIFT_RIGHT_64 (normalized_divisor.part.hi,
  147.  normalized_divisor.part.lo);
  148. ACPI_SHIFT_RIGHT_64 (normalized_dividend.part.hi,
  149.  normalized_dividend.part.lo);
  150. } while (normalized_divisor.part.hi != 0);
  151. /* Partial divide */
  152. ACPI_DIV_64_BY_32 (normalized_dividend.part.hi,
  153.   normalized_dividend.part.lo,
  154.   normalized_divisor.part.lo,
  155.   quotient.part.lo, partial1);
  156. /*
  157.  * The quotient is always 32 bits, and simply requires adjustment.
  158.  * The 64-bit remainder must be generated.
  159.  */
  160. partial1      = quotient.part.lo * divisor.part.hi;
  161. partial2.full = (acpi_integer) quotient.part.lo * divisor.part.lo;
  162. partial3.full = partial2.part.hi + partial1;
  163. remainder.part.hi = partial3.part.lo;
  164. remainder.part.lo = partial2.part.lo;
  165. if (partial3.part.hi == 0) {
  166. if (partial3.part.lo >= dividend.part.hi) {
  167. if (partial3.part.lo == dividend.part.hi) {
  168. if (partial2.part.lo > dividend.part.lo) {
  169. quotient.part.lo--;
  170. remainder.full -= divisor.full;
  171. }
  172. }
  173. else {
  174. quotient.part.lo--;
  175. remainder.full -= divisor.full;
  176. }
  177. }
  178. remainder.full    = remainder.full - dividend.full;
  179. remainder.part.hi = -((s32) remainder.part.hi);
  180. remainder.part.lo = -((s32) remainder.part.lo);
  181. if (remainder.part.lo) {
  182. remainder.part.hi--;
  183. }
  184. }
  185. }
  186. /* Return only what was requested */
  187. if (out_quotient) {
  188. *out_quotient = quotient.full;
  189. }
  190. if (out_remainder) {
  191. *out_remainder = remainder.full;
  192. }
  193. return_ACPI_STATUS (AE_OK);
  194. }
  195. #else
  196. /*******************************************************************************
  197.  *
  198.  * FUNCTION:    Acpi_ut_short_divide, Acpi_ut_divide
  199.  *
  200.  * DESCRIPTION: Native versions of the Ut_divide functions. Use these if either
  201.  *              1) The target is a 64-bit platform and therefore 64-bit
  202.  *                 integer math is supported directly by the machine.
  203.  *              2) The target is a 32-bit or 16-bit platform, and the
  204.  *                 double-precision integer math library is available to
  205.  *                 perform the divide.
  206.  *
  207.  ******************************************************************************/
  208. acpi_status
  209. acpi_ut_short_divide (
  210. acpi_integer            *in_dividend,
  211. u32                     divisor,
  212. acpi_integer            *out_quotient,
  213. u32                     *out_remainder)
  214. {
  215. FUNCTION_TRACE ("Ut_short_divide");
  216. /* Always check for a zero divisor */
  217. if (divisor == 0) {
  218. REPORT_ERROR (("Acpi_ut_short_divide: Divide by zeron"));
  219. return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
  220. }
  221. /* Return only what was requested */
  222. if (out_quotient) {
  223. *out_quotient = *in_dividend / divisor;
  224. }
  225. if (out_remainder) {
  226. *out_remainder = (u32) *in_dividend % divisor;
  227. }
  228. return_ACPI_STATUS (AE_OK);
  229. }
  230. acpi_status
  231. acpi_ut_divide (
  232. acpi_integer            *in_dividend,
  233. acpi_integer            *in_divisor,
  234. acpi_integer            *out_quotient,
  235. acpi_integer            *out_remainder)
  236. {
  237. FUNCTION_TRACE ("Ut_divide");
  238. /* Always check for a zero divisor */
  239. if (*in_divisor == 0) {
  240. REPORT_ERROR (("Acpi_ut_divide: Divide by zeron"));
  241. return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
  242. }
  243. /* Return only what was requested */
  244. if (out_quotient) {
  245. *out_quotient = *in_dividend / *in_divisor;
  246. }
  247. if (out_remainder) {
  248. *out_remainder = *in_dividend % *in_divisor;
  249. }
  250. return_ACPI_STATUS (AE_OK);
  251. }
  252. #endif