Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
5.4 KiB

  1. /*++
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. fpubcd.c
  5. Abstract:
  6. Floating point BCD fragments (FBLD, FBSTP)
  7. Author:
  8. 05-Oct-1995 BarryBo
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <float.h>
  16. #include <math.h>
  17. #include <errno.h>
  18. #include <stdio.h>
  19. #include "wx86.h"
  20. #include "fragp.h"
  21. #include "fpufrags.h"
  22. #include "fpufragp.h"
  23. typedef VOID (*NpxPutBCD)(PCPUDATA cpu, PFPREG Fp, PBYTE pop1);
  24. #define NPXPUTBCD(name) VOID name(PCPUDATA cpu, PFPREG Fp, PBYTE pop1)
  25. NPXPUTBCD(FBSTP_VALID);
  26. NPXPUTBCD(FBSTP_ZERO);
  27. NPXPUTBCD(FBSTP_SPECIAL);
  28. NPXPUTBCD(FBSTP_EMPTY);
  29. const NpxPutBCD FBSTPTable[TAG_MAX] = {
  30. FBSTP_VALID,
  31. FBSTP_ZERO,
  32. FBSTP_SPECIAL,
  33. FBSTP_EMPTY
  34. };
  35. const double BCDMax=999999999999999999.0;
  36. VOID
  37. StoreIndefiniteBCD(
  38. PBYTE pop1
  39. )
  40. /*++
  41. Routine Description:
  42. Write out the BCD encoding for INDEFINITE.
  43. Note that ntos\dll\i386\emlsbcd.asm writes out a different
  44. bit-pattern than the 487 does! The value written here matches
  45. a Pentium's response.
  46. Arguments:
  47. pop1 - address of BCD to write to
  48. Return Value:
  49. None
  50. --*/
  51. {
  52. //
  53. // Write out: 0xffff c0000000 00000000
  54. // emlsbcd.asm writes: 0xffff 00000000 00000000
  55. // ^
  56. //
  57. PUT_LONG(pop1, 0);
  58. PUT_LONG(pop1+4, 0xc0000000);
  59. PUT_SHORT(pop1+8, 0xffff);
  60. }
  61. FRAG1(FBLD, BYTE)
  62. {
  63. FpArithDataPreamble(cpu, pop1);
  64. cpu->FpStatusC1 = 0; // assume no error
  65. if (cpu->FpStack[ST(7)].Tag != TAG_EMPTY) {
  66. HandleStackFull(cpu, &cpu->FpStack[ST(7)]);
  67. } else {
  68. LONGLONG I64;
  69. DWORD dw0;
  70. INT Bytes;
  71. BYTE Val;
  72. PFPREG ST0;
  73. //
  74. // Get the BCD value into the FPU
  75. //
  76. dw0 = GET_LONG(pop1);
  77. PUSHFLT(ST0);
  78. if (dw0 == 0) {
  79. DWORD dw1 = GET_LONG(pop1+4);
  80. USHORT us0 = GET_SHORT(pop1+8);
  81. if (dw1 == 0xc0000000 && us0 == 0xffff) {
  82. //
  83. // The value is INDEFINITE
  84. //
  85. SetIndefinite(ST0);
  86. return;
  87. } else if (dw1 == 0 && (us0 & 0xff) == 0) {
  88. //
  89. // The value is +/- 0
  90. //
  91. ST0->Tag = TAG_ZERO;
  92. ST0->r64 = 0;
  93. ST0->rb[7] = (us0 >> 8); // copy in the sign bit
  94. return;
  95. }
  96. }
  97. //
  98. // Otherwise, the BCD value is TAG_VALID - load the digits in
  99. //
  100. I64 = 0;
  101. for (Bytes=8; Bytes>=0; --Bytes) {
  102. Val = GET_BYTE(pop1+Bytes);
  103. I64 = I64*100 + (Val>>4)*10 + (Val&0x0f);
  104. }
  105. //
  106. // Get the sign bit
  107. //
  108. Val = GET_BYTE(pop1+9) & 0x80;
  109. //
  110. // Set up the FP reg
  111. //
  112. ST0->Tag = TAG_VALID;
  113. ST0->r64 = (double)I64;
  114. ST0->rb[7] |= Val; // copy in the sign bit
  115. }
  116. }
  117. NPXPUTBCD(FBSTP_VALID)
  118. {
  119. BYTE Sign = Fp->rb[7] & 0x80; // preserve the R8 sign
  120. BYTE Val;
  121. INT Bytes;
  122. LONGLONG I64;
  123. LONGLONG NewI64;
  124. DOUBLE r64;
  125. //
  126. // Take the absolute value of the R8 by clearing its sign bit
  127. //
  128. r64 = Fp->r64;
  129. *((PBYTE)&r64+7) &= 0x7f;
  130. //
  131. // Check the range of the R8
  132. //
  133. if (r64 > BCDMax) {
  134. //
  135. // Overflow - write out BCD indefinite.
  136. //
  137. StoreIndefiniteBCD(pop1);
  138. return;
  139. }
  140. //
  141. // Convert to an integer according the the current rounding mode
  142. //
  143. I64 = (LONGLONG)r64;
  144. //
  145. // Convert the integer to BCD, two digits at a time, and store it
  146. //
  147. for (Bytes = 0; Bytes < 9; ++Bytes) {
  148. NewI64 = I64 / 10;
  149. Val = (BYTE)(I64 - NewI64*10); // low nibble Val = I64 mod 10
  150. // high nibble Val = 0
  151. I64 = NewI64 / 10;
  152. Val += 16*(BYTE)(NewI64 - I64*10); // low nibble Val = I64 mod 10
  153. // high nibble Val = (I64/10) mod 10
  154. //
  155. // Store the two BCD digits
  156. //
  157. PUT_BYTE(pop1, Val);
  158. //
  159. // I64 has been divided by 100 since the top of the loop, so
  160. // there is nothing to do to it in order to loop again. Update
  161. // the address we are writing to, then loop.
  162. //
  163. pop1++;
  164. }
  165. //
  166. // Store the sign bit, along with 7 zero bits in the top byte
  167. //
  168. PUT_BYTE(pop1, Sign);
  169. POPFLT;
  170. }
  171. NPXPUTBCD(FBSTP_ZERO)
  172. {
  173. // Store out the signed zero value
  174. memset(pop1, 0, 9);
  175. PUT_BYTE(pop1+9, Fp->rb[7]);
  176. POPFLT;
  177. }
  178. NPXPUTBCD(FBSTP_SPECIAL)
  179. {
  180. if (Fp->TagSpecial) {
  181. FBSTP_VALID(cpu, Fp, pop1);
  182. } else {
  183. //
  184. // INFINITY and NANs are invalid, and the masked behavior is
  185. // to write out INDEFINITE.
  186. //
  187. if (!HandleInvalidOp(cpu)) {
  188. StoreIndefiniteBCD(pop1);
  189. POPFLT;
  190. }
  191. }
  192. }
  193. NPXPUTBCD(FBSTP_EMPTY)
  194. {
  195. if (!HandleStackEmpty(cpu, Fp)) {
  196. StoreIndefiniteBCD(pop1);
  197. }
  198. }
  199. FRAG1(FBSTP, BYTE)
  200. {
  201. PFPREG ST0;
  202. FpArithDataPreamble(cpu, pop1);
  203. ST0 = cpu->FpST0;
  204. (*FBSTPTable[ST0->Tag])(cpu, ST0, pop1);
  205. }