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.

1913 lines
46 KiB

  1. /*++
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. fpufrags.c
  5. Abstract:
  6. Floating point instruction fragments
  7. Author:
  8. 06-Jul-1995 BarryBo
  9. Revision History:
  10. 24-Aug-1999 [askhalid] copied from 32-bit wx86 directory and make work for 64bit.
  11. --*/
  12. /*
  13. * Important design considerations:
  14. *
  15. * 1. Floating-point precision 32/64/80-bits.
  16. * On a 487, all operations use 80-bit precision except for ADD, SUB(R),
  17. * MUL, DIV(R), and SQRT, which use the precision control.
  18. *
  19. * The emulator uses 64-bit precision for all operations except for those
  20. * listed above, where 32-bit precision will be used if the app enables it.
  21. *
  22. * 2. Unmasked FP exceptions.
  23. * The native FPU is set to mask *ALL* FP exceptions. The emulator polls
  24. * for exceptions at the ends of emulated instructions and simulates
  25. * masked/unmasked exceptions as required. If this is not done, the
  26. * following scenerio can occur:
  27. *
  28. * 1. App unmasks all exceptions
  29. * 2. App loads two SNANS
  30. * 3. App performs FADD ST, ST(1)
  31. * 4. The emulated FADD is implemented as NATIVE FADD, plus NATIVE FST.
  32. * The NATIVE FADD will set an unmaked exception and the NATIVE FST
  33. * will raise the exception. On Intel, the FADD is a single FP
  34. * instruction, and the exception will not be raised until the next
  35. * Intel instruction.
  36. *
  37. * 3. INDEFINITE/QNAN/SNAN.
  38. * MIPS and PPC have a different representation for NANs than Intel/Alpha.
  39. * Within the FpRegs array, NANs are stored in the native RISC format.
  40. * All loads and stores of native values to Intel memory must use
  41. * PutIntelR4/PutIntelR8 and GetIntelR4/GetIntelR8, which hide the
  42. * conversion to/from native format.
  43. * See \\orville\razzle\src\crtw32\fpw32\include\trans.h.
  44. *
  45. * 4. Floating-point Tag Word.
  46. * For speed, the emulator keeps richer information about the values
  47. * than the 487 does. TAG_SPECIAL is further classified into
  48. * INDEFINITE, QNAN, SNAN, or INFINITY.
  49. *
  50. * 5. Raising an FP exception.
  51. * The 487 keeps track of the address of the last FP instruction and
  52. * the Effective Address used to point to its operand. The instruction
  53. * opcode is also stored. This information is required because the 486
  54. * integer unit is operating concurrently and probably has updated
  55. * EIP before the 487 raised the exception.
  56. *
  57. * The CPU emulator must make EIP available to the 487 emulator for
  58. * this purpose, too. The Effective Address is passed as a parameter to
  59. * instructions which care, so there is no issue (which is why all
  60. * FP fragments take BYREF parameters instead of BYVAL).
  61. *
  62. * Note that EIP must point to the first prefix for the instruction, not
  63. * the opcode itself.
  64. *
  65. * Data pointer is not affected by FINIT, FLDCW, FSTCW, FSTSW, FCLEX,
  66. * FSTENV, FLDENV, FSAVE, and FRSTOR. Data pointer is UNDEFINED if
  67. * the instruction did not have a memory operand.
  68. *
  69. * 6. Thread initialization.
  70. * The per-thread initialization performs no floating-point operations
  71. * so that integer-only threads do not incur any overhead in NT. For
  72. * example, on an Intel MP box, any thread which executes a single FP
  73. * instruction incurs additional overhead during context-switch for that
  74. * thread. We only want to add that overhead if the Intel app being
  75. * emulated actually uses FP instructions.
  76. *
  77. * 7. Floating-point formats:
  78. * Figure 15-10 and Table 15-3 (Intel page 15-12) describe the formats.
  79. * WARNING: Figure 15-10 indicates the highest addressed byte is at
  80. * the right. In fact, the the sign bit is in the highest-
  81. * addressed byte! The mantissa is in the lowest bytes,
  82. * followed by the exponent (Bias = 127,1023,16383), followed
  83. * by the sign bit.
  84. *
  85. * ie. memory = 0x00 0x00 0x00 0x00 0x00 0x00 0x08 0x40
  86. * means, reverse the byte order:
  87. * 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00
  88. * convert to binary:
  89. * 4 0 0 8 0 0
  90. * 0100 0000 0000 1000 0000 0000 ....
  91. * ||-----------| |------------- .... |
  92. * | exponent mantissa
  93. * sign
  94. *
  95. * To get the unbiased exponent, subtract off the bias (1023 for R8)
  96. * E = e-bias = 1024 - 1023 = 1
  97. *
  98. * To get the mantissa, there is an implicit leading '1' (except R10)
  99. * mantissa = 1 concatenated with 1000 0000 .... = 11 = 1.5(decimal)
  100. *
  101. * Therefore, the value is +2^1*1.5 = 3
  102. *
  103. *
  104. */
  105. //UNDONE: handle loading of unsupported format numbers. TimP converts them
  106. // silently to INDEFINITE (the masked exception behavior)
  107. //UNDONE: Fix the DENORMAL cases so they throw exceptions if needed.
  108. #include <nt.h>
  109. #include <ntrtl.h>
  110. #include <nturtl.h>
  111. #include <windows.h>
  112. #include <float.h>
  113. #include <math.h>
  114. #include <errno.h>
  115. #include <stdio.h>
  116. #include <limits.h>
  117. #include "wx86.h"
  118. #include "cpuassrt.h"
  119. #include "config.h"
  120. #include "fragp.h"
  121. #include "fpufrags.h"
  122. #include "fpufragp.h"
  123. #include "fpuarith.h"
  124. ASSERTNAME;
  125. DWORD pfnNPXNPHandler; // Address of x86 NPX emulator entrypoint
  126. //
  127. // Bit-patterns for +INFINITY and -INFINITY
  128. //
  129. const BYTE R8PositiveInfinityVal[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f };
  130. const BYTE R8NegativeInfinityVal[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff };
  131. //
  132. // Sets floating-point ES bit in status word based on current control reg
  133. // and status reg.
  134. //
  135. #define SetErrorSummary(cpu) { \
  136. if (!(cpu)->FpControlMask & (cpu)->FpStatusExceptions) {\
  137. (cpu)->FpStatusES = 1; \
  138. } else { \
  139. (cpu)->FpStatusES = 0; \
  140. } \
  141. }
  142. //
  143. // Forward declarations
  144. //
  145. VOID
  146. StoreEnvironment(
  147. PCPUDATA cpu,
  148. DWORD *pEnv
  149. );
  150. // in fraglib\{mips|ppc|alpha}\fphelp.s:
  151. VOID
  152. SetNativeRoundingMode(
  153. DWORD x86RoundingMode
  154. );
  155. #ifdef ALPHA
  156. unsigned int GetNativeFPStatus(void);
  157. #endif
  158. NPXFUNC1(FRNDINT_VALID);
  159. NPXFUNC1(FRNDINT_ZERO);
  160. NPXFUNC1(FRNDINT_SPECIAL);
  161. NPXFUNC1(FRNDINT_EMPTY);
  162. NPXFUNC2(FSCALE_VALID_VALID);
  163. NPXFUNC2(FSCALE_VALIDORZERO_VALIDORZERO);
  164. NPXFUNC2(FSCALE_SPECIAL_VALIDORZERO);
  165. NPXFUNC2(FSCALE_VALIDORZERO_SPECIAL);
  166. NPXFUNC2(FSCALE_SPECIAL_SPECIAL);
  167. NPXFUNC2(FSCALE_ANY_EMPTY);
  168. NPXFUNC2(FSCALE_EMPTY_ANY);
  169. NPXFUNC1(FSQRT_VALID);
  170. NPXFUNC1(FSQRT_ZERO);
  171. NPXFUNC1(FSQRT_SPECIAL);
  172. NPXFUNC1(FSQRT_EMPTY);
  173. NPXFUNC1(FXTRACT_VALID);
  174. NPXFUNC1(FXTRACT_ZERO);
  175. NPXFUNC1(FXTRACT_SPECIAL);
  176. NPXFUNC1(FXTRACT_EMPTY);
  177. const NpxFunc1 FRNDINTTable[TAG_MAX] = {
  178. FRNDINT_VALID,
  179. FRNDINT_ZERO,
  180. FRNDINT_SPECIAL,
  181. FRNDINT_EMPTY
  182. };
  183. const NpxFunc2 FSCALETable[TAG_MAX][TAG_MAX] = {
  184. // left is TAG_VALID, right is ...
  185. { FSCALE_VALID_VALID, FSCALE_VALIDORZERO_VALIDORZERO, FSCALE_VALIDORZERO_SPECIAL, FSCALE_ANY_EMPTY},
  186. // left is TAG_ZERO, right is ...
  187. { FSCALE_VALIDORZERO_VALIDORZERO, FSCALE_VALIDORZERO_VALIDORZERO, FSCALE_VALIDORZERO_SPECIAL, FSCALE_ANY_EMPTY},
  188. // left is TAG_SPECIAL, right is ...
  189. { FSCALE_SPECIAL_VALIDORZERO, FSCALE_SPECIAL_VALIDORZERO, FSCALE_SPECIAL_SPECIAL, FSCALE_ANY_EMPTY},
  190. // left is TAG_EMPTY, right is ...
  191. { FSCALE_EMPTY_ANY, FSCALE_ANY_EMPTY, FSCALE_ANY_EMPTY, FSCALE_EMPTY_ANY}
  192. };
  193. const NpxFunc1 FSQRTTable[TAG_MAX] = {
  194. FSQRT_VALID,
  195. FSQRT_ZERO,
  196. FSQRT_SPECIAL,
  197. FSQRT_EMPTY,
  198. };
  199. const NpxFunc1 FXTRACTTable[TAG_MAX] = {
  200. FXTRACT_VALID,
  201. FXTRACT_ZERO,
  202. FXTRACT_SPECIAL,
  203. FXTRACT_EMPTY
  204. };
  205. FRAG0(FpuInit)
  206. /*++
  207. Routine Description:
  208. Initialize the FPU emulator to match the underlying FPU hardware's state.
  209. Called once per thread.
  210. Arguments:
  211. cpu - per-thread data
  212. Return Value:
  213. None
  214. --*/
  215. {
  216. int i;
  217. ANSI_STRING ProcName;
  218. NTSTATUS Status;
  219. // IMPORTANT: Read note (6), above, before adding any new code here!
  220. // Initialize the non-zero values here.
  221. cpu->FpControlMask = FPCONTROL_IM|
  222. FPCONTROL_DM|
  223. FPCONTROL_ZM|
  224. FPCONTROL_OM|
  225. FPCONTROL_UM|
  226. FPCONTROL_PM;
  227. cpu->FpST0 = &cpu->FpStack[0];
  228. for (i=0; i<8; ++i) {
  229. cpu->FpStack[i].Tag = TAG_EMPTY;
  230. }
  231. ChangeFpPrecision(cpu, 2);
  232. }
  233. FRAG1(FpuSaveContext, BYTE)
  234. /*++
  235. Routine Description:
  236. Store the CPU's state to memory. The format is the same as FNSAVE and
  237. winnt.h's FLOATING_SAVE_AREA expect.
  238. Arguments:
  239. cpu - per-thread data
  240. pop1 - destination where context is to be written.
  241. Return Value:
  242. None
  243. --*/
  244. {
  245. INT i, ST;
  246. StoreEnvironment(cpu, (DWORD *)pop1);
  247. pop1+=28; // move pop1 past the 28-byte Instruction and Data Pointer image
  248. for (i=0; i<8; ++i) {
  249. ST = ST(i);
  250. if (cpu->FpStack[ST].Tag == TAG_EMPTY) {
  251. // special case: writing out a TAG_EMPTY from FNSAVE should
  252. // not change the value to INDEFINITE - it should write out
  253. // the bits as if they were really a properly-tagged R8.
  254. FPREG Fp;
  255. Fp.r64 = cpu->FpStack[ST].r64;
  256. SetTag(&Fp);
  257. PutIntelR10(pop1, &Fp);
  258. } else {
  259. PutIntelR10(pop1, &cpu->FpStack[ST]);
  260. }
  261. pop1+=10;
  262. }
  263. }
  264. VOID
  265. SetIndefinite(
  266. PFPREG FpReg
  267. )
  268. /*++
  269. Routine Description:
  270. Writes an INDEFINITE to an FP register.
  271. Arguments:
  272. FpReg - register to write the INDEFINITE to.
  273. Return Value:
  274. None
  275. --*/
  276. {
  277. FpReg->Tag = TAG_SPECIAL;
  278. FpReg->TagSpecial = TAG_SPECIAL_INDEF;
  279. #if NATIVE_NAN_IS_INTEL_FORMAT
  280. FpReg->rdw[0] = 0;
  281. FpReg->rdw[1] = 0xfff80000;
  282. #else
  283. FpReg->rdw[0] = 0xffffffff;
  284. FpReg->rdw[1] = 0x7ff7ffff;
  285. #endif
  286. }
  287. VOID
  288. FpControlPreamble2(
  289. PCPUDATA cpu
  290. )
  291. /*++
  292. Routine Description:
  293. If any FP exceptions are pending from the previous FP instruction, raise
  294. them now. Called at the top of each non-control FP instruction, if
  295. any floating-point exception is unmasked.
  296. Arguments:
  297. cpu - per-thread data
  298. Return Value:
  299. None
  300. --*/
  301. {
  302. //
  303. // Copy the RISC FP status register into the x86 FP status register
  304. //
  305. UpdateFpExceptionFlags(cpu);
  306. //
  307. // If there is an error (FpStatusES != FALSE), then raise the
  308. // unmasked exception if there is one.
  309. //
  310. if (cpu->FpStatusES) {
  311. EXCEPTION_RECORD ExRec;
  312. DWORD Exception = (~cpu->FpControlMask) & cpu->FpStatusExceptions;
  313. //
  314. // There was an unmasked FP exception set by the previous instruction.
  315. // Raise the exception now. The order the bits are checked is
  316. // the same as Kt0720 in ntos\ke\i386\trap.asm checks them.
  317. //
  318. //
  319. // in ntos\ke\i386\trap.asm, floating-point exceptions all vector
  320. // to CommonDispatchException1Arg0d, which creates a 1-parameter
  321. // exception with 0 as the first dword of data. Code in
  322. // \nt\private\sdktools\vctools\crt\fpw32\tran\i386\filter.c cares.
  323. // See _fpieee_flt(), where the line reads "if (pinfo[0]) {".
  324. //
  325. ExRec.NumberParameters = 1; // 1 parameter
  326. ExRec.ExceptionInformation[0]=0; // 0 = raised by hardware
  327. if (Exception & FPCONTROL_IM) { // invalid operation
  328. if (cpu->FpStatusSF) {
  329. //
  330. // Can't use STATUS_FLOAT_STACK_CHECK, 'cause on RISC
  331. // nt kernel uses it to indicate the float instruction
  332. // needs to be emulated. The Wx86 exception filters
  333. // know how to handle this.
  334. //
  335. ExRec.ExceptionCode = STATUS_WX86_FLOAT_STACK_CHECK;
  336. //
  337. // STATUS_FLOAT_STACK_CHECK has two parameters:
  338. // First is 0
  339. // Second is the data offset
  340. //
  341. ExRec.NumberParameters = 2;
  342. ExRec.ExceptionInformation[1] = (DWORD)(ULONGLONG)cpu->FpData;
  343. } else {
  344. ExRec.ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
  345. }
  346. } else if (Exception & FPCONTROL_ZM) { // zero divide
  347. ExRec.ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
  348. } else if (Exception & FPCONTROL_DM) { // denormal
  349. ExRec.ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
  350. } else if (Exception & FPCONTROL_OM) { // overflow
  351. ExRec.ExceptionCode = STATUS_FLOAT_OVERFLOW;
  352. } else if (Exception & FPCONTROL_UM) { // underflow
  353. ExRec.ExceptionCode = STATUS_FLOAT_UNDERFLOW;
  354. } else if (!cpu->FpControlMask & FPCONTROL_PM) { // precision
  355. ExRec.ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
  356. } else {
  357. //
  358. // ES is set, but all pending exceptions are masked.
  359. // ie. ES is set because ZE is set, but only the
  360. // FpControlDM exception is unmasked.
  361. // Nothing to do, so return.
  362. //
  363. return;
  364. }
  365. ExRec.ExceptionFlags = 0; // continuable exception
  366. ExRec.ExceptionRecord = NULL;
  367. ExRec.ExceptionAddress = (PVOID)cpu->FpEip; // addr of faulting instr
  368. CpupRaiseException(&ExRec);
  369. }
  370. }
  371. VOID
  372. FpControlPreamble(
  373. PCPUDATA cpu
  374. )
  375. /*++
  376. Routine Description:
  377. If any FP exceptions are pending from the previous FP instruction, raise
  378. them now. Called at the top of each non-control FP instruction. This
  379. routine is kept small so it can be inlined by the C compiler. Most of
  380. the time, FP exceptions are masked, so there is no work to do.
  381. Arguments:
  382. cpu - per-thread data
  383. Return Value:
  384. None
  385. --*/
  386. {
  387. if (cpu->FpControlMask == (FPCONTROL_IM|
  388. FPCONTROL_DM|
  389. FPCONTROL_ZM|
  390. FPCONTROL_OM|
  391. FPCONTROL_UM|
  392. FPCONTROL_PM)) {
  393. //
  394. // All FP exceptions are masked. Nothing to do.
  395. //
  396. return;
  397. }
  398. FpControlPreamble2(cpu);
  399. }
  400. VOID
  401. FpArithPreamble(
  402. PCPUDATA cpu
  403. )
  404. /*++
  405. Routine Description:
  406. Called at the start of every arithmetic instruction which has no data
  407. pointer. Calls FpControlPreamble() to handle any pending exceptions,
  408. then records the EIP and FP opcode for later exception handling.
  409. See Intel 16-2 for the list of arithmetic vs. nonarithmetic instructions.
  410. Arguments:
  411. cpu - per-thread data
  412. Return Value:
  413. None
  414. --*/
  415. {
  416. FpControlPreamble(cpu);
  417. // Save the EIP value for this instruction
  418. cpu->FpEip = eip;
  419. // Set the data pointer to 0 - this instruction doesn't have an EA
  420. cpu->FpData = NULL;
  421. }
  422. VOID
  423. FpArithDataPreamble(
  424. PCPUDATA cpu,
  425. PVOID FpData
  426. )
  427. /*++
  428. Routine Description:
  429. Called at the start of every arithmetic instruction which has a data
  430. pointer. Calls FpArithPreamble() and FpControlPreamble().
  431. Arguments:
  432. cpu - per-thread data
  433. FpData - pointer to data for this instruction
  434. Return Value:
  435. None
  436. --*/
  437. {
  438. FpControlPreamble(cpu);
  439. // Save the EIP value for this instruction
  440. cpu->FpEip = eip;
  441. // Save the data pointer for this instruction
  442. cpu->FpData = FpData;
  443. }
  444. VOID
  445. UpdateFpExceptionFlags(
  446. PCPUDATA cpu
  447. )
  448. /*++
  449. Routine Description:
  450. Copies native RISC Fp status bits into the x86 Fp status register.
  451. Arguments:
  452. cpu - per-thread data
  453. Return Value:
  454. None
  455. --*/
  456. {
  457. unsigned int NativeStatus;
  458. //
  459. // Get the current native FP status word, then clear it.
  460. // UNDONE: For speed, consider using native instructions to get and
  461. // clear the status bits, rather than waiting for the C runtime
  462. // to reformat the bits into the machine-independent format.
  463. // This is especially true for _clearfp(), which returns the old
  464. // fp status bits (except for those dealing with handled
  465. // exceptions - the ones we want to look at).
  466. //
  467. #ifdef ALPHA
  468. #define SW_FPCR_STATUS_INVALID 0x00020000
  469. #define SW_FPCR_STATUS_DIVISION_BY_ZERO 0x00040000
  470. #define SW_FPCR_STATUS_OVERFLOW 0x00080000
  471. #define SW_FPCR_STATUS_UNDERFLOW 0x00100000
  472. #define SW_FPCR_STATUS_INEXACT 0x00200000
  473. NativeStatus = GetNativeFPStatus();
  474. #else
  475. #define SW_FPCR_STATUS_INVALID _SW_INVALID
  476. #define SW_FPCR_STATUS_DIVISION_BY_ZERO _SW_ZERODIVIDE
  477. #define SW_FPCR_STATUS_OVERFLOW _SW_OVERFLOW
  478. #define SW_FPCR_STATUS_UNDERFLOW _SW_UNDERFLOW
  479. #define SW_FPCR_STATUS_INEXACT _SW_INEXACT
  480. NativeStatus = _statusfp();
  481. _clearfp();
  482. #endif
  483. //
  484. // Decide what exceptions have happened during the instruction.
  485. // Exceptions are rare, so assume there are none by testing to see if
  486. // any exception is pending before checking each individual bit.
  487. //
  488. if (NativeStatus & (SW_FPCR_STATUS_INVALID|
  489. SW_FPCR_STATUS_DIVISION_BY_ZERO|
  490. SW_FPCR_STATUS_OVERFLOW|
  491. #ifndef ALPHA
  492. _SW_DENORMAL|
  493. #endif
  494. SW_FPCR_STATUS_UNDERFLOW)) {
  495. DWORD Mask = cpu->FpControlMask;
  496. DWORD Exceptions = cpu->FpStatusExceptions;
  497. if (NativeStatus & SW_FPCR_STATUS_INVALID) {
  498. if (!(Mask & FPCONTROL_IM)) {
  499. cpu->FpStatusES = 1; // Unmasked exception
  500. }
  501. Exceptions |= FPCONTROL_IM; // Invalid instruction
  502. cpu->FpStatusSF = 0; // Invalid operand, not stack overflow/underflow
  503. }
  504. if (NativeStatus & SW_FPCR_STATUS_DIVISION_BY_ZERO) {
  505. if (!(Mask & FPCONTROL_ZM)) {
  506. cpu->FpStatusES = 1; // Unmasked exception
  507. }
  508. Exceptions |= FPCONTROL_ZM;
  509. }
  510. #ifndef ALPHA
  511. if (NativeStatus & _SW_DENORMAL) {
  512. if (!(Mask & FPCONTROL_DM)) {
  513. cpu->FpStatusES = 1; // Unmasked exception
  514. }
  515. Exceptions |= FPCONTROL_DM;
  516. }
  517. #endif
  518. if (NativeStatus & SW_FPCR_STATUS_OVERFLOW) {
  519. if (!(Mask & FPCONTROL_OM)) {
  520. cpu->FpStatusES = 1; // Unmasked exception
  521. }
  522. Exceptions |= FPCONTROL_OM;
  523. }
  524. if (NativeStatus & SW_FPCR_STATUS_UNDERFLOW) {
  525. if (!(Mask & FPCONTROL_UM)) {
  526. cpu->FpStatusES = 1; // Unmasked exception
  527. }
  528. Exceptions |= FPCONTROL_UM;
  529. }
  530. cpu->FpStatusExceptions = Exceptions;
  531. }
  532. }
  533. USHORT
  534. GetControlReg(
  535. PCPUDATA cpu
  536. )
  537. /*++
  538. Routine Description:
  539. Creates the USHORT 487 Control Register from the current CPU state.
  540. Arguments:
  541. cpu - per-thread data
  542. Return Value:
  543. USHORT value of the 487 Control Register.
  544. --*/
  545. {
  546. USHORT c;
  547. c = (cpu->FpControlInfinity << 12) |
  548. (cpu->FpControlRounding << 10) |
  549. (cpu->FpControlPrecision << 8) |
  550. (1 << 6) | // this reserved bit is 1 on 487 chips
  551. (USHORT)cpu->FpControlMask;
  552. return c;
  553. }
  554. VOID
  555. SetControlReg(
  556. PCPUDATA cpu,
  557. USHORT NewControl
  558. )
  559. /*++
  560. Routine Description:
  561. Sets the FPU Control Register to the specified value. The native FPU
  562. is set to match.
  563. Arguments:
  564. cpu - per-thread data
  565. NewControl - new value for the Control Register.
  566. Return Value:
  567. None.
  568. --*/
  569. {
  570. INT NewPrecision;
  571. // Break the Intel Control Word into component parts
  572. cpu->FpControlMask = NewControl & (FPCONTROL_IM|
  573. FPCONTROL_DM|
  574. FPCONTROL_ZM|
  575. FPCONTROL_OM|
  576. FPCONTROL_UM|
  577. FPCONTROL_PM);
  578. cpu->FpControlRounding = (NewControl>>10) & 3;
  579. cpu->FpControlInfinity = (NewControl>>12) & 3;
  580. NewPrecision = (NewControl>>8) & 3;
  581. if (NewPrecision != cpu->FpControlPrecision) {
  582. //
  583. // Modify jump tables for instructions which are sensitive
  584. // to the floating-point precision.
  585. //
  586. ChangeFpPrecision(cpu, NewPrecision);
  587. }
  588. // Set the native FPU to the correct rounding mode. Precision
  589. // is emulated in software.
  590. SetNativeRoundingMode(cpu->FpControlRounding);
  591. // Setting the 487 control word may have masked or unmasked exceptions.
  592. SetErrorSummary(cpu);
  593. }
  594. USHORT
  595. GetStatusReg(
  596. PCPUDATA cpu
  597. )
  598. /*++
  599. Routine Description:
  600. Creates the USHORT 487 Status Register from the current CPU state.
  601. Arguments:
  602. cpu - per-thread data
  603. Return Value:
  604. USHORT value of the 487 Status Register.
  605. --*/
  606. {
  607. USHORT s;
  608. UpdateFpExceptionFlags(cpu);
  609. s = (cpu->FpStatusES << 15) | // The 'B' bit is a mirror of 'ES'
  610. (cpu->FpStatusC3 << 14) |
  611. (cpu->FpTop << 11) |
  612. (cpu->FpStatusC2 << 10) |
  613. (cpu->FpStatusC1 << 9) |
  614. (cpu->FpStatusC0 << 8) |
  615. (cpu->FpStatusES << 7) |
  616. (cpu->FpStatusSF << 6) |
  617. (USHORT)cpu->FpStatusExceptions;
  618. // the PE bit in the status word is hard-wired to 0, so mask it now.
  619. return s & ~FPCONTROL_PM;
  620. }
  621. VOID
  622. SetStatusReg(
  623. PCPUDATA cpu,
  624. USHORT NewStatus
  625. )
  626. /*++
  627. Routine Description:
  628. Sets the FPU Status Register to the specified value.
  629. Arguments:
  630. cpu - per-thread data
  631. NewStatus - new value for the Status Register.
  632. Return Value:
  633. None.
  634. --*/
  635. {
  636. //
  637. // Break the Intel Status Word into component parts
  638. //
  639. cpu->FpStatusExceptions = NewStatus & (FPCONTROL_IM|
  640. FPCONTROL_DM|
  641. FPCONTROL_ZM|
  642. FPCONTROL_OM|
  643. FPCONTROL_UM);
  644. cpu->FpStatusSF = (NewStatus >> 6) & 1;
  645. cpu->FpStatusC0 = (NewStatus >> 8) & 1;
  646. cpu->FpStatusC1 = (NewStatus >> 9) & 1;
  647. cpu->FpStatusC2 = (NewStatus >> 10) & 1;
  648. cpu->FpTop = (NewStatus >> 11) & 7;
  649. cpu->FpST0 = &cpu->FpStack[cpu->FpTop];
  650. cpu->FpStatusC3 = (NewStatus >> 14) & 1;
  651. //
  652. // ES (and B) are recomputed based on the mask bits in the control word.
  653. // The caller must do that by calling SetErrorSummary().
  654. //
  655. }
  656. USHORT
  657. GetTagWord(
  658. PCPUDATA cpu
  659. )
  660. /*++
  661. Routine Description:
  662. Creates the USHORT 487 Tag Word from the current CPU state.
  663. Arguments:
  664. cpu - per-thread data
  665. Return Value:
  666. USHORT value of the 487 Tag Word.
  667. --*/
  668. {
  669. USHORT s;
  670. INT i;
  671. s = 0;
  672. for (i=7; i >= 0; --i) {
  673. s = (s << 2) | (USHORT)cpu->FpStack[i].Tag;
  674. }
  675. return s;
  676. }
  677. VOID
  678. SetTagWord(
  679. PCPUDATA cpu,
  680. USHORT s
  681. )
  682. /*++
  683. Routine Description:
  684. Given a new Tag Word and the FP stack, recomputes the Tag field for each entry
  685. in the FP stack.
  686. Arguments:
  687. cpu - per-thread data
  688. s - new Tag word
  689. Return Value:
  690. None.
  691. --*/
  692. {
  693. INT i;
  694. BYTE Tag;
  695. for(i=0; i < 8; ++i) {
  696. Tag = (BYTE)(s & 3);
  697. s >>= 2;
  698. if (Tag == TAG_EMPTY) {
  699. cpu->FpStack[i].Tag = TAG_EMPTY;
  700. } else {
  701. // Special value - must reclassify into the richer set of tags,
  702. // or the caller is setting the tags to valid or zero. We must
  703. // reclassify them in case the value in the register is not what
  704. // the caller said it was.
  705. SetTag(&cpu->FpStack[i]);
  706. }
  707. }
  708. }
  709. VOID GetEnvironment(
  710. PCPUDATA cpu,
  711. DWORD *pEnv
  712. )
  713. /*++
  714. Routine Description:
  715. Implements the core of FLDENV
  716. Arguments:
  717. cpu - per-thread data
  718. pEnv - destination to load FP environment from
  719. Return Value:
  720. None.
  721. --*/
  722. {
  723. SetControlReg(cpu, (USHORT)GET_LONG(pEnv));
  724. SetStatusReg(cpu, (USHORT)GET_LONG(pEnv+1));
  725. SetErrorSummary(cpu);
  726. SetTagWord(cpu, (USHORT)GET_LONG(pEnv+2));
  727. cpu->FpEip = GET_LONG(pEnv+3);
  728. // ignore CS = GET_LONG(pEnv+4);
  729. cpu->FpData = (PVOID)GET_LONG(pEnv+5);
  730. // ignore DS = GET_LONG(pEnv+6);
  731. }
  732. VOID
  733. StoreEnvironment(
  734. PCPUDATA cpu,
  735. DWORD *pEnv
  736. )
  737. /*++
  738. Routine Description:
  739. Implements the core of FSTENV, FNSTENV
  740. Arguments:
  741. cpu - per-thread data
  742. pEnv - destination to store FP environment to
  743. Return Value:
  744. None.
  745. --*/
  746. {
  747. PUT_LONG(pEnv, (DWORD)GetControlReg(cpu));
  748. PUT_LONG(pEnv+1, (DWORD)GetStatusReg(cpu));
  749. PUT_LONG(pEnv+2, (DWORD)GetTagWord(cpu));
  750. PUT_LONG(pEnv+3, cpu->FpEip);
  751. //
  752. // If FpEip is zero, then assume the FPU is uninitialized (ie. app
  753. // has run FNINIT but no other FP instructions). In that case, FNINIT
  754. // is supposed to have set FpCS and FpDS to 0. We don't want to add
  755. // the extra overhead of settings FpCS and FpDS on each FP instruction.
  756. // Instead, we simulate this situation by writing 0 for the selector
  757. // values.
  758. //
  759. //
  760. if (cpu->FpEip) {
  761. PUT_LONG(pEnv+4, (DWORD)CS);
  762. PUT_LONG(pEnv+6, (DWORD)DS);
  763. } else {
  764. PUT_LONG(pEnv+4, 0);
  765. PUT_LONG(pEnv+6, 0);
  766. }
  767. PUT_LONG(pEnv+5, (DWORD)(ULONGLONG)cpu->FpData);
  768. // Mask all exceptions
  769. cpu->FpControlMask = FPCONTROL_IM|
  770. FPCONTROL_DM|
  771. FPCONTROL_ZM|
  772. FPCONTROL_OM|
  773. FPCONTROL_UM|
  774. FPCONTROL_PM;
  775. }
  776. BOOL
  777. HandleStackEmpty(
  778. PCPUDATA cpu,
  779. PFPREG FpReg
  780. )
  781. /*++
  782. Routine Description:
  783. Handles FP stack underflow errors. If Invalid Instruction Exceptions
  784. are masked, writes an INDEFINITE into the register. Otherwise it records
  785. a pending exception and aborts the instruction.
  786. Arguments:
  787. cpu - per-thread data
  788. FpReg - reg to set to INDEFINITE if the exception is masked.
  789. Return Value:
  790. None.
  791. --*/
  792. {
  793. cpu->FpStatusExceptions |= FPCONTROL_IM;
  794. cpu->FpStatusC1 = 0; // O/U# = 0 = underflow
  795. cpu->FpStatusSF = 1; // stack overflow/underflow, not invalid operand
  796. if (cpu->FpControlMask & FPCONTROL_IM) {
  797. // Invalid Operation is masked - handle it by returning INDEFINITE
  798. SetIndefinite(FpReg);
  799. return FALSE;
  800. } else {
  801. cpu->FpStatusES = 1;
  802. return TRUE;
  803. }
  804. }
  805. VOID
  806. HandleStackFull(
  807. PCPUDATA cpu,
  808. PFPREG FpReg
  809. )
  810. /*++
  811. Routine Description:
  812. Handles FP stack overflow errors. If Invalid Instruction Exceptions
  813. are masked, writes an INDEFINITE into the register. Otherwise it records
  814. a pending exception and aborts the instruction.
  815. Arguments:
  816. cpu - per-thread data
  817. FpReg - register which caused the error.
  818. Return Value:
  819. None.
  820. --*/
  821. {
  822. CPUASSERT(FpReg->Tag != TAG_EMPTY);
  823. cpu->FpStatusExceptions |= FPCONTROL_IM;
  824. cpu->FpStatusC1 = 1; // O/U# = 1 = overflow
  825. cpu->FpStatusSF = 1; // stack overflow/underflow, not invalid operand
  826. if (cpu->FpControlMask & FPCONTROL_IM) {
  827. // Invalid Operation is masked - handle it by returning INDEFINITE
  828. SetIndefinite(FpReg);
  829. } else {
  830. cpu->FpStatusES = 1;
  831. }
  832. }
  833. BOOL
  834. HandleInvalidOp(
  835. PCPUDATA cpu
  836. )
  837. /*++
  838. Routine Description:
  839. Called whenever an instruction handles an invalid operation. If exceptions
  840. are masked, it is a no-op. Otherwise it records a pending excption and
  841. aborts the operation.
  842. Arguments:
  843. cpu - per-thread data
  844. Return Value:
  845. BOOL - TRUE if instruction should be aborted due to unmasked exception.
  846. --*/
  847. {
  848. cpu->FpStatusExceptions |= FPCONTROL_IM;
  849. cpu->FpStatusSF = 0; // invalid operand, not stack overflow/underflow
  850. if (cpu->FpControlMask & FPCONTROL_IM) {
  851. // Invalid Operation is masked - continue instruction
  852. return FALSE;
  853. } else {
  854. // Unmasked exception - abort instruction
  855. cpu->FpStatusES = 1;
  856. return TRUE;
  857. }
  858. }
  859. BOOL
  860. HandleSnan(
  861. PCPUDATA cpu,
  862. PFPREG FpReg
  863. )
  864. /*++
  865. Routine Description:
  866. Handles the case when an SNAN (Signalling NAN) is detected. If exceptions
  867. are masked, converts the SNAN to a QNAN with the same mantissa. Otherwise,
  868. it records a pending exception and aborts the instruction.
  869. Arguments:
  870. cpu - per-thread data
  871. FpReg - register which caused the error.
  872. Return Value:
  873. BOOL - TRUE if instruction should be aborted due to unmasked exception.
  874. --*/
  875. {
  876. BOOL fAbort;
  877. CPUASSERT(FpReg->Tag == TAG_SPECIAL && FpReg->TagSpecial == TAG_SPECIAL_SNAN);
  878. #if NATIVE_NAN_IS_INTEL_FORMAT
  879. CPUASSERT((FpReg->rdw[1] & 0x00080000) == 0); // FP value is not a SNAN
  880. #else
  881. CPUASSERT(FpReg->rdw[1] & 0x00080000); // FP value is not a SNAN
  882. #endif
  883. fAbort = HandleInvalidOp(cpu);
  884. if (!fAbort) {
  885. // Invalid Operation is masked - handle it by converting to QNAN
  886. FpReg->rdw[1] ^= 0x00080000; // invert the top bit of the mantissa
  887. FpReg->TagSpecial = TAG_SPECIAL_QNAN;
  888. }
  889. return fAbort;
  890. }
  891. FRAG0(FABS)
  892. {
  893. PFPREG ST0;
  894. FpArithPreamble(cpu);
  895. cpu->FpStatusC1 = 0; // assume no error
  896. ST0 = cpu->FpST0;
  897. switch (ST0->Tag) {
  898. case TAG_VALID:
  899. case TAG_ZERO:
  900. //
  901. // Clear the sign bit for NANs, VALID, ZERO, INFINITY, etc.
  902. //
  903. ST0->rdw[1] &= 0x7fffffff;
  904. break;
  905. case TAG_EMPTY:
  906. if (HandleStackEmpty(cpu, ST0)) {
  907. break;
  908. }
  909. // else fall through to TAG_SPECIAL
  910. case TAG_SPECIAL:
  911. //
  912. // Clear the sign bit for NANs, VALID, ZERO, INFINITY, etc.
  913. //
  914. ST0->rdw[1] &= 0x7fffffff;
  915. if (ST0->TagSpecial == TAG_SPECIAL_INDEF) {
  916. //
  917. // INDEFINITE with its sign changed to POSITIVE becomes just a QNAN
  918. //
  919. ST0->TagSpecial = TAG_SPECIAL_QNAN;
  920. }
  921. break;
  922. }
  923. }
  924. FRAG0(FCHS)
  925. {
  926. PFPREG ST0;
  927. FpArithPreamble(cpu);
  928. cpu->FpStatusC1 = 0; // assume no error
  929. ST0 = cpu->FpST0;
  930. switch (ST0->Tag) {
  931. case TAG_VALID:
  932. case TAG_ZERO:
  933. // toggle the sign bit for NANs, VALID, ZERO, INFINITY, etc.
  934. ST0->rdw[1] ^= 0x80000000;
  935. break;
  936. case TAG_EMPTY:
  937. if (HandleStackEmpty(cpu, ST0)) {
  938. break;
  939. }
  940. // else fall through to TAG_SPECIAL
  941. case TAG_SPECIAL:
  942. // toggle the sign bit for NANs, VALID, ZERO, INFINITY, etc.
  943. ST0->rdw[1] ^= 0x80000000;
  944. if (ST0->TagSpecial == TAG_SPECIAL_INDEF) {
  945. //
  946. // INDEFINITE with its sign changed to POSITIVE becomes
  947. // just a QNAN
  948. //
  949. ST0->TagSpecial = TAG_SPECIAL_QNAN;
  950. } else if (ST0->TagSpecial == TAG_SPECIAL_QNAN &&
  951. ST0->rdw[0] == 0 &&
  952. ST0->rdw[1] == 0xfff80000) {
  953. //
  954. // this particular QNAN becames INDEFINITE
  955. //
  956. ST0->TagSpecial = TAG_SPECIAL_INDEF;
  957. }
  958. break;
  959. }
  960. }
  961. FRAG0(FNCLEX)
  962. {
  963. // NOWAIT flavor, so no preamble
  964. cpu->FpStatusES = 0;
  965. cpu->FpStatusExceptions = 0;
  966. }
  967. FRAG0(FDECSTP)
  968. {
  969. FpArithPreamble(cpu);
  970. cpu->FpStatusC1 = 0; // assume no error
  971. PUSHFLT(cpu->FpST0);
  972. }
  973. FRAG1IMM(FFREE, INT)
  974. {
  975. FpArithPreamble(cpu);
  976. CPUASSERT((op1 & 0x07) == op1);
  977. cpu->FpStack[ST(op1)].Tag = TAG_EMPTY;
  978. }
  979. FRAG0(FINCSTP)
  980. {
  981. FpArithPreamble(cpu);
  982. cpu->FpStatusC1 = 0; // assume no error
  983. INCFLT;
  984. }
  985. FRAG0(FNINIT)
  986. {
  987. int i;
  988. SetControlReg(cpu, 0x37f);
  989. SetStatusReg(cpu, 0);
  990. cpu->FpStatusES = 0;
  991. for (i=0; i<8; ++i) {
  992. cpu->FpStack[i].Tag = TAG_EMPTY;
  993. }
  994. cpu->FpEip = 0;
  995. cpu->FpData = 0;
  996. }
  997. FRAG1(FLDCW, USHORT*)
  998. {
  999. FpControlPreamble(cpu);
  1000. SetControlReg(cpu, GET_SHORT(pop1));
  1001. }
  1002. FRAG1(FLDENV, BYTE)
  1003. {
  1004. // Intel instruction set docs don't define the layout for the structure.
  1005. // This code is copied from ntos\dll\i386\emlsenv.asm.
  1006. GetEnvironment(cpu, (DWORD *)pop1);
  1007. }
  1008. NPXFUNC1(FRNDINT_VALID)
  1009. {
  1010. double fraction;
  1011. fraction = modf(Fp->r64, &Fp->r64);
  1012. switch (cpu->FpControlRounding) {
  1013. case 0: // _RC_NEAR
  1014. if (fraction <= -0.5) {
  1015. // Fp->r64 is negative and the fraction is >= 0.5
  1016. Fp->r64-=1.0;
  1017. } else if (fraction >= 0.5) {
  1018. // Fp->r64 is positive and the fraction is >= 0.5
  1019. Fp->r64+=1.0;
  1020. }
  1021. break;
  1022. case 1: // _RC_DOWN
  1023. if (fraction < 0.0) {
  1024. // Fp->r64 is negative and there is a fraction. Round down
  1025. Fp->r64-=1.0;
  1026. }
  1027. break;
  1028. case 2: // _RC_UP
  1029. if (fraction > 0.0) {
  1030. // Fp->r64 is positive and there is a fraction. Round up
  1031. Fp->r64+=1.0;
  1032. }
  1033. break;
  1034. case 3: // _RC_CHOP
  1035. // nothing to do - modf chops
  1036. break;
  1037. default:
  1038. CPUASSERT(FALSE);
  1039. }
  1040. if (Fp->r64 == 0.0) {
  1041. Fp->Tag = TAG_ZERO;
  1042. } else {
  1043. Fp->Tag = TAG_VALID;
  1044. }
  1045. }
  1046. NPXFUNC1(FRNDINT_ZERO)
  1047. {
  1048. // nothing to do - zero is already an integer!
  1049. }
  1050. NPXFUNC1(FRNDINT_SPECIAL)
  1051. {
  1052. switch (Fp->TagSpecial) {
  1053. case TAG_SPECIAL_DENORM:
  1054. FRNDINT_VALID(cpu, Fp);
  1055. break;
  1056. case TAG_SPECIAL_SNAN:
  1057. HandleSnan(cpu, Fp);
  1058. break;
  1059. case TAG_SPECIAL_QNAN:
  1060. case TAG_SPECIAL_INDEF:
  1061. case TAG_SPECIAL_INFINITY:
  1062. // infinity and NANs are unchanged
  1063. break;
  1064. }
  1065. }
  1066. NPXFUNC1(FRNDINT_EMPTY)
  1067. {
  1068. HandleStackEmpty(cpu, Fp);
  1069. }
  1070. FRAG0(FRNDINT)
  1071. {
  1072. PFPREG ST0;
  1073. FpArithPreamble(cpu);
  1074. ST0 = cpu->FpST0;
  1075. (*FRNDINTTable[ST0->Tag])(cpu, ST0);
  1076. }
  1077. FRAG1(FRSTOR, BYTE)
  1078. {
  1079. INT i;
  1080. PBYTE DataImagePtr = pop1;
  1081. //
  1082. // Load the status register first, so that the ST(i) calculation
  1083. // is correct.
  1084. //
  1085. SetStatusReg(cpu, (USHORT)GET_LONG(pop1+4));
  1086. // Intel instruction set docs don't define the layout for the structure.
  1087. // This code is copied from ntos\dll\i386\emlsenv.asm.
  1088. pop1 += 28; // move past the Numeric Instruction and Data Pointer image
  1089. for (i=0; i<8; ++i) {
  1090. LoadIntelR10ToR8(cpu, pop1, &cpu->FpStack[ST(i)]);
  1091. pop1+=10;
  1092. }
  1093. //
  1094. // Setting tags requires looking at the R8 values on the FP stack, so do this
  1095. // after loading the FP stack from memory
  1096. //
  1097. GetEnvironment(cpu, (DWORD *)DataImagePtr);
  1098. }
  1099. FRAG1(FNSAVE, BYTE)
  1100. {
  1101. FpuSaveContext(cpu, pop1);
  1102. FNINIT(cpu);
  1103. }
  1104. NPXFUNC2(FSCALE_VALID_VALID)
  1105. {
  1106. l->r64 = _scalb(l->r64, (long)r->r64);
  1107. //
  1108. // Assume the scaling did not overflow
  1109. //
  1110. SetTag(l);
  1111. if (errno == ERANGE) {
  1112. if (l->r64 == HUGE_VAL) {
  1113. //
  1114. // The scaling overflowed - fix up the result
  1115. //
  1116. l->r64 = R8PositiveInfinity;
  1117. l->Tag = TAG_SPECIAL;
  1118. l->TagSpecial = TAG_SPECIAL_INFINITY;
  1119. } else if (l->r64 == -HUGE_VAL) {
  1120. //
  1121. // The scaling overflowed - fix up the result
  1122. //
  1123. l->r64 = R8NegativeInfinity;
  1124. l->Tag = TAG_SPECIAL;
  1125. l->TagSpecial = TAG_SPECIAL_INFINITY;
  1126. }
  1127. }
  1128. }
  1129. NPXFUNC2(FSCALE_VALIDORZERO_VALIDORZERO)
  1130. {
  1131. // no work to do - either: adding 0 to the exponent
  1132. // or: adding nonzero to the exponent on 0
  1133. }
  1134. NPXFUNC2(FSCALE_SPECIAL_VALIDORZERO)
  1135. {
  1136. switch (l->TagSpecial) {
  1137. case TAG_SPECIAL_DENORM:
  1138. FSCALE_VALID_VALID(cpu, l, r);
  1139. break;
  1140. case TAG_SPECIAL_INFINITY:
  1141. // no change if adjusting the exponent of INFINITY
  1142. break;
  1143. case TAG_SPECIAL_SNAN:
  1144. HandleSnan(cpu, l);
  1145. // fall into TAG_SPECIAL_QNAN
  1146. case TAG_SPECIAL_QNAN:
  1147. case TAG_SPECIAL_INDEF:
  1148. break;
  1149. }
  1150. }
  1151. NPXFUNC2(FSCALE_VALIDORZERO_SPECIAL)
  1152. {
  1153. switch (r->TagSpecial) {
  1154. case TAG_SPECIAL_DENORM:
  1155. FSCALE_VALID_VALID(cpu, l, r);
  1156. break;
  1157. case TAG_SPECIAL_INFINITY:
  1158. if (l->Tag != TAG_ZERO) {
  1159. // scaling VALID by INFINITY - return INDEFINITE
  1160. SetIndefinite(l);
  1161. }
  1162. // else scaling ZERO by INFINITY - return ZERO
  1163. break;
  1164. case TAG_SPECIAL_SNAN:
  1165. HandleSnan(cpu, r);
  1166. // fall into TAG_SPECIAL_QNAN:
  1167. case TAG_SPECIAL_QNAN:
  1168. case TAG_SPECIAL_INDEF:
  1169. break;
  1170. }
  1171. }
  1172. NPXFUNC2(FSCALE_SPECIAL_SPECIAL)
  1173. {
  1174. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, l)) {
  1175. return;
  1176. }
  1177. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, r)) {
  1178. return;
  1179. }
  1180. if (l->TagSpecial == TAG_SPECIAL_DENORM) {
  1181. (*FSCALETable[TAG_VALID][r->Tag])(cpu, l, r);
  1182. return;
  1183. }
  1184. if (r->TagSpecial == TAG_SPECIAL_DENORM) {
  1185. (*FSCALETable[l->Tag][TAG_VALID])(cpu, l, r);
  1186. return;
  1187. }
  1188. if (l->TagSpecial == TAG_SPECIAL_INFINITY) {
  1189. if (r->TagSpecial == TAG_SPECIAL_INFINITY) {
  1190. // two infinities - return INDEFINITE
  1191. SetIndefinite(l);
  1192. } else {
  1193. CPUASSERT(IS_TAG_NAN(r));
  1194. // Copy the NAN from r to l, to return it
  1195. l->r64 = r->r64;
  1196. l->TagSpecial = r->TagSpecial;
  1197. }
  1198. } else {
  1199. CPUASSERT(IS_TAG_NAN(l));
  1200. if (r->TagSpecial == TAG_SPECIAL_INFINITY) {
  1201. //
  1202. // l already has the NAN to return
  1203. //
  1204. } else {
  1205. CPUASSERT(IS_TAG_NAN(r));
  1206. //
  1207. // Return the largest of the two NANs
  1208. //
  1209. l->r64 = r->r64 + l->r64;
  1210. SetTag(l);
  1211. }
  1212. }
  1213. }
  1214. NPXFUNC2(FSCALE_ANY_EMPTY)
  1215. {
  1216. if (!HandleStackEmpty(cpu, r)) {
  1217. (*FSCALETable[l->Tag][TAG_SPECIAL])(cpu, l, r);
  1218. }
  1219. }
  1220. NPXFUNC2(FSCALE_EMPTY_ANY)
  1221. {
  1222. if (!HandleStackEmpty(cpu, l)) {
  1223. (*FSCALETable[TAG_SPECIAL][r->Tag])(cpu, l, r);
  1224. }
  1225. }
  1226. FRAG0(FSCALE)
  1227. {
  1228. PFPREG l, r;
  1229. FpArithPreamble(cpu);
  1230. l = cpu->FpST0;
  1231. r = &cpu->FpStack[ST(1)];
  1232. (*FSCALETable[l->Tag][r->Tag])(cpu, l, r);
  1233. }
  1234. NPXFUNC1(FSQRT_VALID)
  1235. {
  1236. if (Fp->rb[7] & 0x80) {
  1237. // value is negative - return INDEFINITE
  1238. if (!HandleInvalidOp(cpu)) {
  1239. SetIndefinite(Fp);
  1240. }
  1241. } else {
  1242. Fp->r64 = sqrt(Fp->r64);
  1243. SetTag(Fp);
  1244. }
  1245. }
  1246. NPXFUNC1(FSQRT_ZERO)
  1247. {
  1248. // according to the docs, sqrt(-0.0) is -0.0, so there is nothing to do
  1249. }
  1250. NPXFUNC1(FSQRT_SPECIAL)
  1251. {
  1252. switch (Fp->TagSpecial) {
  1253. case TAG_SPECIAL_DENORM:
  1254. FSQRT_VALID(cpu, Fp);
  1255. break;
  1256. case TAG_SPECIAL_INFINITY:
  1257. if (Fp->rb[7] & 0x80) {
  1258. // negative infinity - invalid op
  1259. SetIndefinite(Fp);
  1260. }
  1261. // else positive infinity, which is preserved
  1262. break;
  1263. case TAG_SPECIAL_SNAN:
  1264. HandleSnan(cpu, Fp);
  1265. break;
  1266. case TAG_SPECIAL_QNAN:
  1267. case TAG_SPECIAL_INDEF:
  1268. break;
  1269. }
  1270. }
  1271. NPXFUNC1(FSQRT_EMPTY)
  1272. {
  1273. HandleStackEmpty(cpu, Fp);
  1274. // nothing else to do
  1275. }
  1276. FRAG0(FSQRT)
  1277. {
  1278. PFPREG ST0;
  1279. FpArithPreamble(cpu);
  1280. ST0 = cpu->FpST0;
  1281. (*FSQRTTable[ST0->Tag])(cpu, ST0);
  1282. }
  1283. FRAG1(FNSTCW, USHORT)
  1284. {
  1285. // No-wait flavor - no preamble required.
  1286. PUT_SHORT(pop1, GetControlReg(cpu));
  1287. }
  1288. FRAG1(FNSTENV, BYTE)
  1289. {
  1290. // No-wait flavor - no preamble required.
  1291. StoreEnvironment(cpu, (DWORD *)pop1);
  1292. }
  1293. FRAG1(FNSTSW, USHORT)
  1294. {
  1295. // No-wait flavor - no preamble required
  1296. PUT_SHORT(pop1, GetStatusReg(cpu));
  1297. }
  1298. FRAG0(OPT_FNSTSWAxSahf)
  1299. {
  1300. DWORD Status;
  1301. // No-wait flavor - no preamble required
  1302. Status = GetStatusReg(cpu);
  1303. ax = (USHORT)Status;
  1304. SET_CFLAG(Status << (31-8)); // FLAG_CF==1<<0
  1305. SET_PFLAG(!(Status & (FLAG_PF<<8))); // flag_pf contains an index into ParityBit[] array
  1306. SET_AUXFLAG(Status >> 8); // AUX bit is already in the right place
  1307. SET_ZFLAG(!(Status & (FLAG_ZF<<8))); // zf has inverse logic
  1308. SET_SFLAG(Status << (31-7-8)); // SFLAG is bit 7 in AH
  1309. }
  1310. FRAG0(FXAM)
  1311. {
  1312. PFPREG ST0;
  1313. FpArithPreamble(cpu);
  1314. ST0 = cpu->FpST0;
  1315. // C1 = sign bit
  1316. cpu->FpStatusC1 = ST0->rdw[1] >> 31;
  1317. // Set C3, C2, C0 based on the type of the number
  1318. switch (ST0->Tag) {
  1319. case TAG_VALID:
  1320. cpu->FpStatusC3 = 0; cpu->FpStatusC2 = 1; cpu->FpStatusC0 = 0;
  1321. break;
  1322. case TAG_ZERO:
  1323. cpu->FpStatusC3 = 1; cpu->FpStatusC2 = 0; cpu->FpStatusC0 = 0;
  1324. break;
  1325. case TAG_EMPTY:
  1326. cpu->FpStatusC3 = 1; cpu->FpStatusC2 = 0; cpu->FpStatusC0 = 1;
  1327. break;
  1328. case TAG_SPECIAL:
  1329. switch (cpu->FpST0->TagSpecial) {
  1330. case TAG_SPECIAL_DENORM:
  1331. cpu->FpStatusC3 = 1; cpu->FpStatusC2 = 1; cpu->FpStatusC0 = 0;
  1332. break;
  1333. case TAG_SPECIAL_SNAN:
  1334. case TAG_SPECIAL_QNAN:
  1335. case TAG_SPECIAL_INDEF:
  1336. cpu->FpStatusC3 = 0; cpu->FpStatusC2 = 0; cpu->FpStatusC0 = 1;
  1337. break;
  1338. case TAG_SPECIAL_INFINITY:
  1339. cpu->FpStatusC3 = 0; cpu->FpStatusC2 = 1; cpu->FpStatusC0 = 1;
  1340. break;
  1341. }
  1342. break;
  1343. }
  1344. }
  1345. FRAG1IMM(FXCH_STi, INT)
  1346. {
  1347. PFPREG pReg;
  1348. PFPREG ST0;
  1349. FPREG Temp;
  1350. FpArithPreamble(cpu);
  1351. CPUASSERT( (op1&0x07)==op1 );
  1352. ST0 = cpu->FpST0;
  1353. if (ST0->Tag == TAG_EMPTY) {
  1354. if (HandleStackEmpty(cpu, ST0)) {
  1355. // unmasked exception - abort the instruction
  1356. return;
  1357. }
  1358. }
  1359. pReg = &cpu->FpStack[ST(op1)];
  1360. if (pReg->Tag == TAG_EMPTY) {
  1361. if (HandleStackEmpty(cpu, pReg)) {
  1362. // unmasked exception - abort the instruction
  1363. return;
  1364. }
  1365. }
  1366. Temp.Tag = pReg->Tag;
  1367. Temp.TagSpecial = pReg->TagSpecial;
  1368. Temp.r64 = pReg->r64;
  1369. pReg->Tag = ST0->Tag;
  1370. pReg->TagSpecial = ST0->TagSpecial;
  1371. pReg->r64 = ST0->r64;
  1372. ST0->Tag = Temp.Tag;
  1373. ST0->TagSpecial = Temp.TagSpecial;
  1374. ST0->r64 = Temp.r64;
  1375. }
  1376. NPXFUNC1(FXTRACT_VALID)
  1377. {
  1378. DOUBLE Significand;
  1379. int Exponent;
  1380. Exponent = (int)_logb(Fp->r64);
  1381. Significand = _scalb(Fp->r64, (long)-Exponent);
  1382. //
  1383. // Place the exponent in what will become ST(1)
  1384. //
  1385. Fp->r64 = (DOUBLE)Exponent;
  1386. if (Exponent == 0) {
  1387. Fp->Tag = TAG_ZERO;
  1388. } else {
  1389. Fp->Tag = TAG_VALID;
  1390. }
  1391. //
  1392. // Place the mantissa in ST, with the same sign as the original value
  1393. //
  1394. PUSHFLT(Fp);
  1395. Fp->r64 = Significand;
  1396. if (Significand == 0.0) {
  1397. Fp->Tag = TAG_ZERO;
  1398. } else {
  1399. Fp->Tag = TAG_VALID;
  1400. }
  1401. }
  1402. NPXFUNC1(FXTRACT_ZERO)
  1403. {
  1404. DWORD Sign;
  1405. //
  1406. // ST(1) gets -infinity, ST gets 0 with same sign as the original value
  1407. //
  1408. Sign = Fp->rdw[1] & 0x80000000;
  1409. Fp->r64 = R8NegativeInfinity;
  1410. Fp->Tag = TAG_SPECIAL;
  1411. Fp->TagSpecial = TAG_SPECIAL_INFINITY;
  1412. PUSHFLT(Fp);
  1413. Fp->rdw[0] = 0;
  1414. Fp->rdw[1] = Sign;
  1415. Fp->Tag = TAG_ZERO;
  1416. //
  1417. // Raise the zero-divide exception
  1418. //
  1419. if (!(cpu->FpControlMask & FPCONTROL_ZM)) {
  1420. cpu->FpStatusES = 1; // Unmasked exception
  1421. }
  1422. cpu->FpStatusExceptions |= FPCONTROL_ZM;
  1423. }
  1424. NPXFUNC1(FXTRACT_SPECIAL)
  1425. {
  1426. DOUBLE Temp;
  1427. FPTAG TempTagSpecial;
  1428. switch (Fp->TagSpecial) {
  1429. case TAG_SPECIAL_DENORM:
  1430. FXTRACT_VALID(cpu, Fp);
  1431. break;
  1432. case TAG_SPECIAL_INFINITY:
  1433. //
  1434. // According to ntos\dll\i386\emxtract.asm, ST(0) = infinity (same sign)
  1435. // and ST(1) = +infinity
  1436. //
  1437. Temp = Fp->r64;
  1438. Fp->r64 = R8PositiveInfinity;
  1439. CPUASSERT(Fp->Tag == TAG_SPECIAL && Fp->TagSpecial == TAG_SPECIAL_INFINITY);
  1440. PUSHFLT(Fp);
  1441. Fp->r64 = Temp;
  1442. Fp->Tag = TAG_SPECIAL;
  1443. Fp->TagSpecial = TAG_SPECIAL_INFINITY;
  1444. break;
  1445. case TAG_SPECIAL_SNAN:
  1446. if (HandleSnan(cpu, Fp)) {
  1447. return;
  1448. }
  1449. // else fall thru to TAG_SPECIAL_QNAN
  1450. case TAG_SPECIAL_QNAN:
  1451. case TAG_SPECIAL_INDEF:
  1452. //
  1453. // Copy the QNAN to both ST(1) and ST
  1454. //
  1455. Temp = Fp->r64;
  1456. TempTagSpecial = Fp->TagSpecial;
  1457. PUSHFLT(Fp);
  1458. Fp->r64 = Temp;
  1459. Fp->Tag = TAG_SPECIAL;
  1460. Fp->TagSpecial = TempTagSpecial;
  1461. break;
  1462. }
  1463. }
  1464. NPXFUNC1(FXTRACT_EMPTY)
  1465. {
  1466. CPUASSERT(FALSE); // this was taken care of by the real FXTRACT
  1467. }
  1468. FRAG0(FXTRACT)
  1469. {
  1470. PFPREG ST0;
  1471. FpArithPreamble(cpu);
  1472. cpu->FpStatusC1 = 0; // assume no error
  1473. ST0 = cpu->FpST0;
  1474. //
  1475. // We must take care of this case first, so that the check for ST(7)
  1476. // can occur next, before any other exception handling takes place.
  1477. //
  1478. if (ST0->Tag == TAG_EMPTY) {
  1479. if (HandleStackEmpty(cpu, ST0)) {
  1480. // unmasked exception - abort the instruction
  1481. return;
  1482. }
  1483. }
  1484. if (cpu->FpStack[ST(7)].Tag != TAG_EMPTY) {
  1485. HandleStackFull(cpu, &cpu->FpStack[ST(7)]);
  1486. return;
  1487. }
  1488. (*FXTRACTTable[ST0->Tag])(cpu, ST0);
  1489. }
  1490. FRAG0(WaitFrag)
  1491. {
  1492. FpControlPreamble(cpu);
  1493. }
  1494. FRAG0(FNOP)
  1495. {
  1496. FpArithPreamble(cpu);
  1497. }