Source code of Windows XP (NT5)
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.

1761 lines
44 KiB

  1. /*++
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. fpuarith.c
  5. Abstract:
  6. Floating point arithmetic fragments (Add/Sub/Mul/Div/Com/Tst)
  7. Author:
  8. 04-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 "cpuassrt.h"
  21. #include "fragp.h"
  22. #include "fpufrags.h"
  23. #include "fpufragp.h"
  24. #include "fpuarith.h"
  25. ASSERTNAME;
  26. #define CALLNPXFUNC2(table, lTag, rTag, l, r) { \
  27. NpxFunc2 *p = (NpxFunc2 *)(table); \
  28. (*(p + (lTag)*TAG_MAX + (rTag)))(cpu, l, r); \
  29. }
  30. #define CALLNPXFUNC3(table, lTag, rTag, d, l, r) { \
  31. NpxFunc3 *p = (NpxFunc3 *)(table); \
  32. (*(p + (lTag)*TAG_MAX + (rTag)))(cpu, d, l, r); \
  33. }
  34. //
  35. // Forward declarations
  36. //
  37. NPXFUNC2(FpAdd32_VALID_VALID);
  38. NPXFUNC2(FpAdd32_VALID_SPECIAL);
  39. NPXFUNC2(FpAdd32_SPECIAL_VALID);
  40. NPXFUNC2(FpAdd32_SPECIAL_SPECIAL);
  41. NPXFUNC2(FpAdd_ANY_EMPTY);
  42. NPXFUNC2(FpAdd_EMPTY_ANY);
  43. NPXFUNC2(FpAdd64_VALID_VALID);
  44. NPXFUNC2(FpAdd64_VALID_SPECIAL);
  45. NPXFUNC2(FpAdd64_SPECIAL_VALID);
  46. NPXFUNC2(FpAdd64_SPECIAL_SPECIAL);
  47. NPXFUNC3(FpDiv32_VALID_VALID);
  48. NPXFUNC3(FpDiv32_VALID_SPECIAL);
  49. NPXFUNC3(FpDiv32_SPECIAL_VALID);
  50. NPXFUNC3(FpDiv32_SPECIAL_SPECIAL);
  51. NPXFUNC3(FpDiv_ANY_EMPTY);
  52. NPXFUNC3(FpDiv_EMPTY_ANY);
  53. NPXFUNC3(FpDiv64_VALID_VALID);
  54. NPXFUNC3(FpDiv64_VALID_SPECIAL);
  55. NPXFUNC3(FpDiv64_SPECIAL_VALID);
  56. NPXFUNC3(FpDiv64_SPECIAL_SPECIAL);
  57. NPXFUNC2(FpMul32_VALID_VALID);
  58. NPXFUNC2(FpMul32_VALID_SPECIAL);
  59. NPXFUNC2(FpMul32_SPECIAL_VALID);
  60. NPXFUNC2(FpMul32_SPECIAL_SPECIAL);
  61. NPXFUNC2(FpMul_ANY_EMPTY);
  62. NPXFUNC2(FpMul_EMPTY_ANY);
  63. NPXFUNC2(FpMul64_VALID_VALID);
  64. NPXFUNC2(FpMul64_VALID_SPECIAL);
  65. NPXFUNC2(FpMul64_SPECIAL_VALID);
  66. NPXFUNC2(FpMul64_SPECIAL_SPECIAL);
  67. NPXFUNC3(FpSub32_VALID_VALID);
  68. NPXFUNC3(FpSub32_VALID_SPECIAL);
  69. NPXFUNC3(FpSub32_SPECIAL_VALID);
  70. NPXFUNC3(FpSub32_SPECIAL_SPECIAL);
  71. NPXFUNC3(FpSub_ANY_EMPTY);
  72. NPXFUNC3(FpSub_EMPTY_ANY);
  73. NPXFUNC3(FpSub64_VALID_VALID);
  74. NPXFUNC3(FpSub64_VALID_SPECIAL);
  75. NPXFUNC3(FpSub64_SPECIAL_VALID);
  76. NPXFUNC3(FpSub64_SPECIAL_SPECIAL);
  77. NPXCOMFUNC(FpCom_VALID_VALID);
  78. NPXCOMFUNC(FpCom_VALID_SPECIAL);
  79. NPXCOMFUNC(FpCom_SPECIAL_VALID);
  80. NPXCOMFUNC(FpCom_SPECIAL_SPECIAL);
  81. NPXCOMFUNC(FpCom_VALID_EMPTY);
  82. NPXCOMFUNC(FpCom_EMPTY_VALID);
  83. NPXCOMFUNC(FpCom_EMPTY_SPECIAL);
  84. NPXCOMFUNC(FpCom_SPECIAL_EMPTY);
  85. NPXCOMFUNC(FpCom_EMPTY_EMPTY);
  86. //
  87. // Jump tables
  88. //
  89. const NpxFunc2 FpAdd32Table[TAG_MAX][TAG_MAX] = {
  90. // Left is TAG_VALID, Right is...
  91. {FpAdd32_VALID_VALID, FpAdd32_VALID_VALID, FpAdd32_VALID_SPECIAL, FpAdd_ANY_EMPTY},
  92. // Left is TAG_ZERO, Right is...
  93. {FpAdd32_VALID_VALID, FpAdd32_VALID_VALID, FpAdd32_VALID_SPECIAL, FpAdd_ANY_EMPTY},
  94. // Left is TAG_SPECIAL, Right is...
  95. {FpAdd32_SPECIAL_VALID, FpAdd32_SPECIAL_VALID, FpAdd32_SPECIAL_SPECIAL, FpAdd_ANY_EMPTY},
  96. // Left is TAG_EMPTY, Right is...
  97. {FpAdd_EMPTY_ANY, FpAdd_EMPTY_ANY, FpAdd_EMPTY_ANY, FpAdd_EMPTY_ANY}
  98. };
  99. const NpxFunc2 FpAdd64Table[TAG_MAX][TAG_MAX] = {
  100. // Left is TAG_VALID, Right is...
  101. {FpAdd64_VALID_VALID, FpAdd64_VALID_VALID, FpAdd64_VALID_SPECIAL, FpAdd_ANY_EMPTY},
  102. // Left is TAG_ZERO, Right is...
  103. {FpAdd64_VALID_VALID, FpAdd64_VALID_VALID, FpAdd64_VALID_SPECIAL, FpAdd_ANY_EMPTY},
  104. // Left is TAG_SPECIAL, Right is...
  105. {FpAdd64_SPECIAL_VALID, FpAdd64_SPECIAL_VALID, FpAdd64_SPECIAL_SPECIAL, FpAdd_ANY_EMPTY},
  106. // Left is TAG_EMPTY, Right is...
  107. {FpAdd_EMPTY_ANY, FpAdd_EMPTY_ANY, FpAdd_EMPTY_ANY, FpAdd_EMPTY_ANY}
  108. };
  109. const NpxFunc3 FpDiv32Table[TAG_MAX][TAG_MAX] = {
  110. // Left is TAG_VALID, Right is...
  111. {FpDiv32_VALID_VALID, FpDiv32_VALID_VALID, FpDiv32_VALID_SPECIAL, FpDiv_ANY_EMPTY},
  112. // Left is TAG_ZERO, Right is...
  113. {FpDiv32_VALID_VALID, FpDiv32_VALID_VALID, FpDiv32_VALID_SPECIAL, FpDiv_ANY_EMPTY},
  114. // Left is TAG_SPECIAL, Right is...
  115. {FpDiv32_SPECIAL_VALID, FpDiv32_SPECIAL_VALID, FpDiv32_SPECIAL_SPECIAL, FpDiv_ANY_EMPTY},
  116. // Left is TAG_EMPTY, Right is...
  117. {FpDiv_EMPTY_ANY, FpDiv_EMPTY_ANY, FpDiv_EMPTY_ANY, FpDiv_EMPTY_ANY}
  118. };
  119. const NpxFunc3 FpDiv64Table[TAG_MAX][TAG_MAX] = {
  120. // Left is TAG_VALID, Right is...
  121. {FpDiv64_VALID_VALID, FpDiv64_VALID_VALID, FpDiv64_VALID_SPECIAL, FpDiv_ANY_EMPTY},
  122. // Left is TAG_ZERO, Right is...
  123. {FpDiv64_VALID_VALID, FpDiv64_VALID_VALID, FpDiv64_VALID_SPECIAL, FpDiv_ANY_EMPTY},
  124. // Left is TAG_SPECIAL, Right is...
  125. {FpDiv64_SPECIAL_VALID, FpDiv64_SPECIAL_VALID, FpDiv64_SPECIAL_SPECIAL, FpDiv_ANY_EMPTY},
  126. // Left is TAG_EMPTY, Right is...
  127. {FpDiv_EMPTY_ANY, FpDiv_EMPTY_ANY, FpDiv_EMPTY_ANY, FpDiv_EMPTY_ANY}
  128. };
  129. const NpxFunc2 FpMul32Table[TAG_MAX][TAG_MAX] = {
  130. // Left is TAG_VALID, Right is...
  131. {FpMul32_VALID_VALID, FpMul32_VALID_VALID, FpMul32_VALID_SPECIAL, FpMul_ANY_EMPTY},
  132. // Left is TAG_ZERO, Right is...
  133. {FpMul32_VALID_VALID, FpMul32_VALID_VALID, FpMul32_VALID_SPECIAL, FpMul_ANY_EMPTY},
  134. // Left is TAG_SPECIAL, Right is...
  135. {FpMul32_SPECIAL_VALID, FpMul32_SPECIAL_VALID, FpMul32_SPECIAL_SPECIAL, FpMul_ANY_EMPTY},
  136. // Left is TAG_EMPTY, Right is...
  137. {FpMul_EMPTY_ANY, FpMul_EMPTY_ANY, FpMul_EMPTY_ANY, FpMul_EMPTY_ANY}
  138. };
  139. const NpxFunc2 FpMul64Table[TAG_MAX][TAG_MAX] = {
  140. // Left is TAG_VALID, Right is...
  141. {FpMul64_VALID_VALID, FpMul64_VALID_VALID, FpMul64_VALID_SPECIAL, FpMul_ANY_EMPTY},
  142. // Left is TAG_ZERO, Right is...
  143. {FpMul64_VALID_VALID, FpMul64_VALID_VALID, FpMul64_VALID_SPECIAL, FpMul_ANY_EMPTY},
  144. // Left is TAG_SPECIAL, Right is...
  145. {FpMul64_SPECIAL_VALID, FpMul64_SPECIAL_VALID, FpMul64_SPECIAL_SPECIAL, FpMul_ANY_EMPTY},
  146. // Left is TAG_EMPTY, Right is...
  147. {FpMul_EMPTY_ANY, FpMul_EMPTY_ANY, FpMul_EMPTY_ANY, FpMul_EMPTY_ANY}
  148. };
  149. const NpxFunc3 FpSub32Table[TAG_MAX][TAG_MAX] = {
  150. // Left is TAG_VALID, Right is...
  151. {FpSub32_VALID_VALID, FpSub32_VALID_VALID, FpSub32_VALID_SPECIAL, FpSub_ANY_EMPTY},
  152. // Left is TAG_ZERO, Right is...
  153. {FpSub32_VALID_VALID, FpSub32_VALID_VALID, FpSub32_VALID_SPECIAL, FpSub_ANY_EMPTY},
  154. // Left is TAG_SPECIAL, Right is...
  155. {FpSub32_SPECIAL_VALID, FpSub32_SPECIAL_VALID, FpSub32_SPECIAL_SPECIAL, FpSub_ANY_EMPTY},
  156. // Left is TAG_EMPTY, Right is...
  157. {FpSub_EMPTY_ANY, FpSub_EMPTY_ANY, FpSub_EMPTY_ANY, FpSub_EMPTY_ANY}
  158. };
  159. const NpxFunc3 FpSub64Table[TAG_MAX][TAG_MAX] = {
  160. // Left is TAG_VALID, Right is...
  161. {FpSub64_VALID_VALID, FpSub64_VALID_VALID, FpSub64_VALID_SPECIAL, FpSub_ANY_EMPTY},
  162. // Left is TAG_ZERO, Right is...
  163. {FpSub64_VALID_VALID, FpSub64_VALID_VALID, FpSub64_VALID_SPECIAL, FpSub_ANY_EMPTY},
  164. // Left is TAG_SPECIAL, Right is...
  165. {FpSub64_SPECIAL_VALID, FpSub64_SPECIAL_VALID, FpSub64_SPECIAL_SPECIAL, FpSub_ANY_EMPTY},
  166. // Left is TAG_EMPTY, Right is...
  167. {FpSub_EMPTY_ANY, FpSub_EMPTY_ANY, FpSub_EMPTY_ANY, FpSub_EMPTY_ANY}
  168. };
  169. const NpxComFunc FpComTable[TAG_MAX][TAG_MAX] = {
  170. // Left is TAG_VALID, Right is...
  171. {FpCom_VALID_VALID, FpCom_VALID_VALID, FpCom_VALID_SPECIAL, FpCom_VALID_EMPTY},
  172. // Left is TAG_ZERO, Right is...
  173. {FpCom_VALID_VALID, FpCom_VALID_VALID, FpCom_VALID_SPECIAL, FpCom_VALID_EMPTY},
  174. // Left is TAG_SPECIAL, Right is...
  175. {FpCom_SPECIAL_VALID, FpCom_SPECIAL_VALID, FpCom_SPECIAL_SPECIAL, FpCom_SPECIAL_EMPTY},
  176. // Left is TAG_EMPTY, Right is...
  177. {FpCom_EMPTY_VALID, FpCom_EMPTY_VALID, FpCom_EMPTY_SPECIAL, FpCom_EMPTY_EMPTY}
  178. };
  179. VOID
  180. ChangeFpPrecision(
  181. PCPUDATA cpu,
  182. INT NewPrecision
  183. )
  184. /*++
  185. Routine Description:
  186. Called to modify the floating-point precision. It modifies per-thread
  187. jump tables used by instructions which are sensitive to the FP
  188. precision bits.
  189. Arguments:
  190. cpu - per-thread data
  191. NewPrecision - new precision value
  192. Return Value:
  193. None
  194. --*/
  195. {
  196. cpu->FpControlPrecision = NewPrecision;
  197. if (NewPrecision == 0) {
  198. //
  199. // New precision is 32-bit
  200. //
  201. cpu->FpAddTable = FpAdd32Table;
  202. cpu->FpSubTable = FpSub32Table;
  203. cpu->FpMulTable = FpMul32Table;
  204. cpu->FpDivTable = FpDiv32Table;
  205. } else {
  206. //
  207. // New precision is 24, 64, or 80-bit - treat all as 64-bit
  208. //
  209. cpu->FpAddTable = FpAdd64Table;
  210. cpu->FpSubTable = FpSub64Table;
  211. cpu->FpMulTable = FpMul64Table;
  212. cpu->FpDivTable = FpDiv64Table;
  213. }
  214. }
  215. NPXFUNC2(FpAdd32_VALID_VALID)
  216. {
  217. //UNDONE: If 487 overflow exceptions are unmasked and an overflow occurs,
  218. //UNDONE: a different value is written to 'l' than if the exception
  219. //UNDONE: was masked. To get this right, we need to install an
  220. //UNDONE: exception handler around the addition and run the native FPU
  221. //UNDONE: with overflow exceptions unmasked. The trap handler must then
  222. //UNDONE: map the exception back into FpStatus->ES so the next Intel
  223. //UNDONE: FP instruction can get the Intel exception as expected. Gross!
  224. //UNDONE: Read Intel 16-24 for the gory details.
  225. l->r64 = (DOUBLE)( (FLOAT)l->r64 + (FLOAT)r->r64 );
  226. // Compute the new tag value
  227. SetTag(l);
  228. }
  229. NPXFUNC2(FpAdd64_VALID_VALID)
  230. {
  231. //UNDONE: If 487 overflow exceptions are unmasked and an overflow occurs,
  232. //UNDONE: a different value is written to 'l' than if the exception
  233. //UNDONE: was masked. To get this right, we need to install an
  234. //UNDONE: exception handler around the addition and run the native FPU
  235. //UNDONE: with overflow exceptions unmasked. The trap handler must then
  236. //UNDONE: map the exception back into FpStatus->ES so the next Intel
  237. //UNDONE: FP instruction can get the Intel exception as expected. Gross!
  238. //UNDONE: Read Intel 16-24 for the gory details.
  239. l->r64 = l->r64 + r->r64;
  240. // Compute the new tag value
  241. SetTag(l);
  242. }
  243. NPXFUNC2(FpAdd32_VALID_SPECIAL)
  244. {
  245. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  246. return;
  247. }
  248. //
  249. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  250. // TAG_SPECIAL_INFINITY have no special handling - just use the
  251. // VALID_VALID code.
  252. FpAdd32_VALID_VALID(cpu, l, r);
  253. }
  254. NPXFUNC2(FpAdd64_VALID_SPECIAL)
  255. {
  256. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  257. return;
  258. }
  259. //
  260. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  261. // TAG_SPECIAL_INFINITY have no special handling - just use the
  262. // VALID_VALID code.
  263. FpAdd64_VALID_VALID(cpu, l, r);
  264. }
  265. NPXFUNC2(FpAdd32_SPECIAL_VALID)
  266. {
  267. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  268. return;
  269. }
  270. //
  271. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  272. // TAG_SPECIAL_INFINITY have no special handling - just use the
  273. // VALID_VALID code.
  274. FpAdd32_VALID_VALID(cpu, l, r);
  275. }
  276. NPXFUNC2(FpAdd64_SPECIAL_VALID)
  277. {
  278. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  279. return;
  280. }
  281. //
  282. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  283. // TAG_SPECIAL_INFINITY have no special handling - just use the
  284. // VALID_VALID code.
  285. FpAdd64_VALID_VALID(cpu, l, r);
  286. }
  287. NPXFUNC2(FpAdd32_SPECIAL_SPECIAL)
  288. {
  289. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  290. return;
  291. }
  292. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  293. return;
  294. }
  295. //
  296. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  297. // TAG_SPECIAL_INFINITY have no special handling - just use the
  298. // VALID_VALID code.
  299. FpAdd32_VALID_VALID(cpu, l, r);
  300. }
  301. NPXFUNC2(FpAdd64_SPECIAL_SPECIAL)
  302. {
  303. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  304. return;
  305. }
  306. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  307. return;
  308. }
  309. //
  310. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  311. // TAG_SPECIAL_INFINITY have no special handling - just use the
  312. // VALID_VALID code.
  313. FpAdd64_VALID_VALID(cpu, l, r);
  314. }
  315. NPXFUNC2(FpAdd_ANY_EMPTY)
  316. {
  317. if (!HandleStackEmpty(cpu, r)) {
  318. CALLNPXFUNC2(cpu->FpAddTable, l->Tag, TAG_SPECIAL, l, r);
  319. }
  320. }
  321. NPXFUNC2(FpAdd_EMPTY_ANY)
  322. {
  323. if (!HandleStackEmpty(cpu, l)) {
  324. CALLNPXFUNC2(cpu->FpAddTable, TAG_SPECIAL, r->Tag, l, r);
  325. }
  326. }
  327. VOID
  328. FpAddCommon(
  329. PCPUDATA cpu,
  330. PFPREG l,
  331. PFPREG r
  332. )
  333. /*++
  334. Routine Description:
  335. Implements l += r.
  336. Arguments:
  337. cpu - per-thread data
  338. l - left-hand FP register
  339. r - right-hand FP register
  340. Return Value:
  341. None. l is updated to contain the value of l+r.
  342. --*/
  343. {
  344. CALLNPXFUNC2(cpu->FpAddTable, l->Tag, r->Tag, l, r);
  345. }
  346. NPXFUNC3(FpDiv32_VALID_VALID)
  347. {
  348. //UNDONE: If 487 overflow exceptions are unmasked and an overflow occurs,
  349. //UNDONE: a different value is written to 'l' than if the exception
  350. //UNDONE: was masked. To get this right, we need to install an
  351. //UNDONE: exception handler around the addition and run the native FPU
  352. //UNDONE: with overflow exceptions unmasked. The trap handler must then
  353. //UNDONE: map the exception back into FpStatus->ES so the next Intel
  354. //UNDONE: FP instruction can get the Intel exception as expected. Gross!
  355. //UNDONE: Read Intel 16-24 for the gory details.
  356. dest->r64 = (DOUBLE)( (FLOAT)l->r64 / (FLOAT)r->r64 );
  357. // Compute the new tag value
  358. SetTag(dest);
  359. }
  360. NPXFUNC3(FpDiv64_VALID_VALID)
  361. {
  362. //UNDONE: If 487 overflow exceptions are unmasked and an overflow occurs,
  363. //UNDONE: a different value is written to 'l' than if the exception
  364. //UNDONE: was masked. To get this right, we need to install an
  365. //UNDONE: exception handler around the addition and run the native FPU
  366. //UNDONE: with overflow exceptions unmasked. The trap handler must then
  367. //UNDONE: map the exception back into FpStatus->ES so the next Intel
  368. //UNDONE: FP instruction can get the Intel exception as expected. Gross!
  369. //UNDONE: Read Intel 16-24 for the gory details.
  370. dest->r64 = l->r64 / r->r64;
  371. // Compute the new tag value
  372. SetTag(dest);
  373. }
  374. NPXFUNC3(FpDiv32_VALID_SPECIAL)
  375. {
  376. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  377. return;
  378. }
  379. //
  380. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  381. // TAG_SPECIAL_INFINITY have no special handling - just use the
  382. // VALID_VALID code.
  383. FpDiv32_VALID_VALID(cpu, dest, l, r);
  384. }
  385. NPXFUNC3(FpDiv64_VALID_SPECIAL)
  386. {
  387. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  388. return;
  389. }
  390. //
  391. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  392. // TAG_SPECIAL_INFINITY have no special handling - just use the
  393. // VALID_VALID code.
  394. FpDiv64_VALID_VALID(cpu, dest, l, r);
  395. }
  396. NPXFUNC3(FpDiv32_SPECIAL_VALID)
  397. {
  398. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  399. return;
  400. }
  401. //
  402. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  403. // TAG_SPECIAL_INFINITY have no special handling - just use the
  404. // VALID_VALID code.
  405. FpDiv32_VALID_VALID(cpu, dest, l, r);
  406. }
  407. NPXFUNC3(FpDiv64_SPECIAL_VALID)
  408. {
  409. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  410. return;
  411. }
  412. //
  413. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  414. // TAG_SPECIAL_INFINITY have no special handling - just use the
  415. // VALID_VALID code.
  416. FpDiv64_VALID_VALID(cpu, dest, l, r);
  417. }
  418. NPXFUNC3(FpDiv32_SPECIAL_SPECIAL)
  419. {
  420. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  421. return;
  422. }
  423. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  424. return;
  425. }
  426. //
  427. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  428. // TAG_SPECIAL_INFINITY have no special handling - just use the
  429. // VALID_VALID code.
  430. FpDiv32_VALID_VALID(cpu, dest, l, r);
  431. }
  432. NPXFUNC3(FpDiv64_SPECIAL_SPECIAL)
  433. {
  434. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  435. return;
  436. }
  437. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  438. return;
  439. }
  440. //
  441. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  442. // TAG_SPECIAL_INFINITY have no special handling - just use the
  443. // VALID_VALID code.
  444. FpDiv64_VALID_VALID(cpu, dest, l, r);
  445. }
  446. NPXFUNC3(FpDiv_ANY_EMPTY)
  447. {
  448. if (!HandleStackEmpty(cpu, r)) {
  449. CALLNPXFUNC3(cpu->FpDivTable, l->Tag, TAG_SPECIAL, dest, l, r);
  450. }
  451. }
  452. NPXFUNC3(FpDiv_EMPTY_ANY)
  453. {
  454. if (!HandleStackEmpty(cpu, l)) {
  455. CALLNPXFUNC3(cpu->FpDivTable, TAG_SPECIAL, r->Tag, dest, l, r);
  456. }
  457. }
  458. VOID
  459. FpDivCommon(
  460. PCPUDATA cpu,
  461. PFPREG dest,
  462. PFPREG l,
  463. PFPREG r
  464. )
  465. /*++
  466. Routine Description:
  467. Implements dest = l/r
  468. Arguments:
  469. cpu - per-thread data
  470. l - left-hand FP register
  471. r - right-hand FP register
  472. Return Value:
  473. None. l is updated to contain the value of l+r.
  474. --*/
  475. {
  476. CALLNPXFUNC3(cpu->FpDivTable, l->Tag, r->Tag, dest, l, r);
  477. }
  478. NPXFUNC2(FpMul32_VALID_VALID)
  479. {
  480. //UNDONE: If 487 overflow exceptions are unmasked and an overflow occurs,
  481. //UNDONE: a different value is written to 'l' than if the exception
  482. //UNDONE: was masked. To get this right, we need to install an
  483. //UNDONE: exception handler around the addition and run the native FPU
  484. //UNDONE: with overflow exceptions unmasked. The trap handler must then
  485. //UNDONE: map the exception back into FpStatus->ES so the next Intel
  486. //UNDONE: FP instruction can get the Intel exception as expected. Gross!
  487. //UNDONE: Read Intel 16-24 for the gory details.
  488. l->r64 = (DOUBLE)( (FLOAT)l->r64 * (FLOAT)r->r64 );
  489. // Compute the new tag value
  490. SetTag(l);
  491. }
  492. NPXFUNC2(FpMul64_VALID_VALID)
  493. {
  494. //UNDONE: If 487 overflow exceptions are unmasked and an overflow occurs,
  495. //UNDONE: a different value is written to 'l' than if the exception
  496. //UNDONE: was masked. To get this right, we need to install an
  497. //UNDONE: exception handler around the addition and run the native FPU
  498. //UNDONE: with overflow exceptions unmasked. The trap handler must then
  499. //UNDONE: map the exception back into FpStatus->ES so the next Intel
  500. //UNDONE: FP instruction can get the Intel exception as expected. Gross!
  501. //UNDONE: Read Intel 16-24 for the gory details.
  502. l->r64 = l->r64 * r->r64;
  503. // Compute the new tag value
  504. SetTag(l);
  505. }
  506. NPXFUNC2(FpMul32_VALID_SPECIAL)
  507. {
  508. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  509. return;
  510. }
  511. //
  512. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  513. // TAG_SPECIAL_INFINITY have no special handling - just use the
  514. // VALID_VALID code.
  515. FpMul32_VALID_VALID(cpu, l, r);
  516. }
  517. NPXFUNC2(FpMul64_VALID_SPECIAL)
  518. {
  519. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  520. return;
  521. }
  522. //
  523. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  524. // TAG_SPECIAL_INFINITY have no special handling - just use the
  525. // VALID_VALID code.
  526. FpMul64_VALID_VALID(cpu, l, r);
  527. }
  528. NPXFUNC2(FpMul32_SPECIAL_VALID)
  529. {
  530. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  531. return;
  532. }
  533. //
  534. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  535. // TAG_SPECIAL_INFINITY have no special handling - just use the
  536. // VALID_VALID code.
  537. FpMul32_VALID_VALID(cpu, l, r);
  538. }
  539. NPXFUNC2(FpMul64_SPECIAL_VALID)
  540. {
  541. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  542. return;
  543. }
  544. //
  545. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  546. // TAG_SPECIAL_INFINITY have no special handling - just use the
  547. // VALID_VALID code.
  548. FpMul64_VALID_VALID(cpu, l, r);
  549. }
  550. NPXFUNC2(FpMul32_SPECIAL_SPECIAL)
  551. {
  552. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  553. return;
  554. }
  555. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  556. return;
  557. }
  558. //
  559. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  560. // TAG_SPECIAL_INFINITY have no special handling - just use the
  561. // VALID_VALID code.
  562. FpMul32_VALID_VALID(cpu, l, r);
  563. }
  564. NPXFUNC2(FpMul64_SPECIAL_SPECIAL)
  565. {
  566. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  567. return;
  568. }
  569. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  570. return;
  571. }
  572. //
  573. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  574. // TAG_SPECIAL_INFINITY have no special handling - just use the
  575. // VALID_VALID code.
  576. FpMul64_VALID_VALID(cpu, l, r);
  577. }
  578. NPXFUNC2(FpMul_ANY_EMPTY)
  579. {
  580. if (!HandleStackEmpty(cpu, r)) {
  581. CALLNPXFUNC2(cpu->FpMulTable, l->Tag, TAG_SPECIAL, l, r);
  582. }
  583. }
  584. NPXFUNC2(FpMul_EMPTY_ANY)
  585. {
  586. if (!HandleStackEmpty(cpu, l)) {
  587. CALLNPXFUNC2(cpu->FpMulTable, TAG_SPECIAL, r->Tag, l, r);
  588. }
  589. }
  590. VOID
  591. FpMulCommon(
  592. PCPUDATA cpu,
  593. PFPREG l,
  594. PFPREG r
  595. )
  596. /*++
  597. Routine Description:
  598. Implements l += r.
  599. Arguments:
  600. cpu - per-thread data
  601. l - left-hand FP register
  602. r - right-hand FP register
  603. Return Value:
  604. None. l is updated to contain the value of l+r.
  605. --*/
  606. {
  607. CALLNPXFUNC2(cpu->FpMulTable, l->Tag, r->Tag, l, r);
  608. }
  609. NPXFUNC3(FpSub32_VALID_VALID)
  610. {
  611. //UNDONE: If 487 overflow exceptions are unmasked and an overflow occurs,
  612. //UNDONE: a different value is written to 'l' than if the exception
  613. //UNDONE: was masked. To get this right, we need to install an
  614. //UNDONE: exception handler around the addition and run the native FPU
  615. //UNDONE: with overflow exceptions unmasked. The trap handler must then
  616. //UNDONE: map the exception back into FpStatus->ES so the next Intel
  617. //UNDONE: FP instruction can get the Intel exception as expected. Gross!
  618. //UNDONE: Read Intel 16-24 for the gory details.
  619. dest->r64 = (DOUBLE)( (FLOAT)l->r64 - (FLOAT)r->r64 );
  620. // Compute the new tag value
  621. SetTag(dest);
  622. }
  623. NPXFUNC3(FpSub64_VALID_VALID)
  624. {
  625. //UNDONE: If 487 overflow exceptions are unmasked and an overflow occurs,
  626. //UNDONE: a different value is written to 'l' than if the exception
  627. //UNDONE: was masked. To get this right, we need to install an
  628. //UNDONE: exception handler around the addition and run the native FPU
  629. //UNDONE: with overflow exceptions unmasked. The trap handler must then
  630. //UNDONE: map the exception back into FpStatus->ES so the next Intel
  631. //UNDONE: FP instruction can get the Intel exception as expected. Gross!
  632. //UNDONE: Read Intel 16-24 for the gory details.
  633. dest->r64 = l->r64 - r->r64;
  634. // Compute the new tag value
  635. SetTag(dest);
  636. }
  637. NPXFUNC3(FpSub32_VALID_SPECIAL)
  638. {
  639. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  640. return;
  641. }
  642. //
  643. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  644. // TAG_SPECIAL_INFINITY have no special handling - just use the
  645. // VALID_VALID code.
  646. FpSub32_VALID_VALID(cpu, dest, l, r);
  647. }
  648. NPXFUNC3(FpSub64_VALID_SPECIAL)
  649. {
  650. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  651. return;
  652. }
  653. //
  654. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  655. // TAG_SPECIAL_INFINITY have no special handling - just use the
  656. // VALID_VALID code.
  657. FpSub64_VALID_VALID(cpu, dest, l, r);
  658. }
  659. NPXFUNC3(FpSub32_SPECIAL_VALID)
  660. {
  661. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  662. return;
  663. }
  664. //
  665. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  666. // TAG_SPECIAL_INFINITY have no special handling - just use the
  667. // VALID_VALID code.
  668. FpSub32_VALID_VALID(cpu, dest, l, r);
  669. }
  670. NPXFUNC3(FpSub64_SPECIAL_VALID)
  671. {
  672. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  673. return;
  674. }
  675. //
  676. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  677. // TAG_SPECIAL_INFINITY have no special handling - just use the
  678. // VALID_VALID code.
  679. FpSub64_VALID_VALID(cpu, dest, l, r);
  680. }
  681. NPXFUNC3(FpSub32_SPECIAL_SPECIAL)
  682. {
  683. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  684. return;
  685. }
  686. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  687. return;
  688. }
  689. //
  690. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  691. // TAG_SPECIAL_INFINITY have no special handling - just use the
  692. // VALID_VALID code.
  693. FpSub32_VALID_VALID(cpu, dest, l, r);
  694. }
  695. NPXFUNC3(FpSub64_SPECIAL_SPECIAL)
  696. {
  697. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  698. return;
  699. }
  700. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  701. return;
  702. }
  703. //
  704. // TAG_SPECIAL_INDEF, TAG_SPECIAL_QNAN, TAG_SPECIAL_DENORM, and
  705. // TAG_SPECIAL_INFINITY have no special handling - just use the
  706. // VALID_VALID code.
  707. FpSub64_VALID_VALID(cpu, dest, l, r);
  708. }
  709. NPXFUNC3(FpSub_ANY_EMPTY)
  710. {
  711. if (!HandleStackEmpty(cpu, r)) {
  712. CALLNPXFUNC3(cpu->FpSubTable, l->Tag, TAG_SPECIAL, dest, l, r);
  713. }
  714. }
  715. NPXFUNC3(FpSub_EMPTY_ANY)
  716. {
  717. if (!HandleStackEmpty(cpu, l)) {
  718. CALLNPXFUNC3(cpu->FpSubTable, TAG_SPECIAL, r->Tag, dest, l, r);
  719. }
  720. }
  721. VOID
  722. FpSubCommon(
  723. PCPUDATA cpu,
  724. PFPREG dest,
  725. PFPREG l,
  726. PFPREG r
  727. )
  728. /*++
  729. Routine Description:
  730. Implements dest = l-r
  731. Arguments:
  732. cpu - per-thread data
  733. dest - destination FP register
  734. l - left-hand FP register
  735. r - right-hand FP register
  736. Return Value:
  737. None. l is updated to contain the value of l+r.
  738. --*/
  739. {
  740. CALLNPXFUNC3(cpu->FpSubTable, l->Tag, r->Tag, dest, l, r);
  741. }
  742. NPXCOMFUNC(FpCom_VALID_VALID)
  743. {
  744. //
  745. // Note that this function is called when one or both of the values
  746. // is zero - the sign of 0.0 is ignored in the comparison, so the
  747. // C language '==' and '<' operators do the Right Thing.
  748. //
  749. if (l->r64 == r->r64) {
  750. cpu->FpStatusC3 = 1;
  751. cpu->FpStatusC2 = 0;
  752. cpu->FpStatusC0 = 0;
  753. } else if (l->r64 < r->r64) {
  754. cpu->FpStatusC3 = 0;
  755. cpu->FpStatusC2 = 0;
  756. cpu->FpStatusC0 = 1;
  757. } else {
  758. cpu->FpStatusC3 = 0;
  759. cpu->FpStatusC2 = 0;
  760. cpu->FpStatusC0 = 0;
  761. }
  762. }
  763. NPXCOMFUNC(FpCom_VALID_SPECIAL)
  764. {
  765. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  766. return;
  767. }
  768. if (r->TagSpecial == TAG_SPECIAL_QNAN || r->TagSpecial == TAG_SPECIAL_INDEF) {
  769. //
  770. // Cannot compare a VALID to a QNAN/INDEF
  771. //
  772. if (!fUnordered && HandleInvalidOp(cpu)) {
  773. // abort the FCOM/FTST instruction - Illegal opcode is unmasked
  774. return;
  775. }
  776. // Otherwise, FCOM's illegal opcode is masked, or the instruction
  777. // is FUCOM, for which QNANs are uncomparable. Return "Not comparable"
  778. cpu->FpStatusC3 = 1;
  779. cpu->FpStatusC2 = 1;
  780. cpu->FpStatusC0 = 1;
  781. return;
  782. }
  783. CPUASSERT(r->TagSpecial == TAG_SPECIAL_DENORM || r->TagSpecial == TAG_SPECIAL_INFINITY);
  784. FpCom_VALID_VALID(cpu, l, r, FALSE);
  785. }
  786. NPXCOMFUNC(FpCom_SPECIAL_VALID)
  787. {
  788. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  789. return;
  790. }
  791. if (l->TagSpecial == TAG_SPECIAL_QNAN || l->TagSpecial == TAG_SPECIAL_INDEF) {
  792. //
  793. // Cannot compare a VALID to a QNAN/INDEF
  794. //
  795. if (!fUnordered && HandleInvalidOp(cpu)) {
  796. // abort the FCOM/FTST instruction - Illegal opcode is unmasked
  797. return;
  798. }
  799. // Otherwise, FCOM's illegal opcode is masked, or the instruction
  800. // is FUCOM, for which QNANs are uncomparable. Return "Not comparable"
  801. cpu->FpStatusC3 = 1;
  802. cpu->FpStatusC2 = 1;
  803. cpu->FpStatusC0 = 1;
  804. return;
  805. }
  806. CPUASSERT(l->TagSpecial == TAG_SPECIAL_DENORM || l->TagSpecial == TAG_SPECIAL_INFINITY);
  807. FpCom_VALID_VALID(cpu, l, r, FALSE);
  808. }
  809. NPXCOMFUNC(FpCom_SPECIAL_SPECIAL)
  810. {
  811. if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) {
  812. return;
  813. }
  814. if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) {
  815. return;
  816. }
  817. if (l->TagSpecial == TAG_SPECIAL_QNAN || l->TagSpecial == TAG_SPECIAL_INDEF ||
  818. r->TagSpecial == TAG_SPECIAL_QNAN || r->TagSpecial == TAG_SPECIAL_INDEF) {
  819. //
  820. // Cannot compare a VALID to a QNAN/INDEF
  821. //
  822. if (!fUnordered && HandleInvalidOp(cpu)) {
  823. // abort the FCOM/FTST instruction - Illegal opcode is unmasked
  824. return;
  825. }
  826. // Otherwise, FCOM's illegal opcode is masked, or the instruction
  827. // is FUCOM, for which QNANs are uncomparable. Return "Not comparable"
  828. cpu->FpStatusC3 = 1;
  829. cpu->FpStatusC2 = 1;
  830. cpu->FpStatusC0 = 1;
  831. return;
  832. }
  833. CPUASSERT((l->TagSpecial == TAG_SPECIAL_DENORM || l->TagSpecial == TAG_SPECIAL_INFINITY) &&
  834. (r->TagSpecial == TAG_SPECIAL_DENORM || r->TagSpecial == TAG_SPECIAL_INFINITY));
  835. FpCom_VALID_VALID(cpu, l, r, FALSE);
  836. }
  837. NPXCOMFUNC(FpCom_VALID_EMPTY)
  838. {
  839. if (!HandleStackEmpty(cpu, r)) {
  840. //
  841. // r is now Indefinite, which can't be compared.
  842. //
  843. CPUASSERT(r->Tag == TAG_SPECIAL && r->TagSpecial == TAG_SPECIAL_INDEF);
  844. if (!fUnordered && HandleInvalidOp(cpu)) {
  845. // abort the FCOM/FTST instruction - Illegal opcode is unmasked
  846. return;
  847. }
  848. // Otherwise, FCOM's illegal opcode is masked, or the instruction
  849. // is FUCOM, for which QNANs are uncomparable. Return "Not comparable"
  850. cpu->FpStatusC3 = 1;
  851. cpu->FpStatusC2 = 1;
  852. cpu->FpStatusC0 = 1;
  853. }
  854. }
  855. NPXCOMFUNC(FpCom_EMPTY_VALID)
  856. {
  857. if (!HandleStackEmpty(cpu, l)) {
  858. //
  859. // l is now Indefinite, which can't be compared.
  860. //
  861. CPUASSERT(l->Tag == TAG_SPECIAL && l->TagSpecial == TAG_SPECIAL_INDEF);
  862. if (!fUnordered && HandleInvalidOp(cpu)) {
  863. // abort the FCOM/FTST instruction - Illegal opcode is unmasked
  864. return;
  865. }
  866. // Otherwise, FCOM's illegal opcode is masked, or the instruction
  867. // is FUCOM, for which QNANs are uncomparable. Return "Not comparable"
  868. cpu->FpStatusC3 = 1;
  869. cpu->FpStatusC2 = 1;
  870. cpu->FpStatusC0 = 1;
  871. }
  872. }
  873. NPXCOMFUNC(FpCom_EMPTY_SPECIAL)
  874. {
  875. if (!HandleStackEmpty(cpu, l)) {
  876. (*FpComTable[TAG_SPECIAL][r->Tag])(cpu, l, r, fUnordered);
  877. }
  878. }
  879. NPXCOMFUNC(FpCom_SPECIAL_EMPTY)
  880. {
  881. if (!HandleStackEmpty(cpu, r)) {
  882. (*FpComTable[r->Tag][TAG_SPECIAL])(cpu, l, r, fUnordered);
  883. }
  884. }
  885. NPXCOMFUNC(FpCom_EMPTY_EMPTY)
  886. {
  887. if (!HandleStackEmpty(cpu, l) && !HandleStackEmpty(cpu, r)) {
  888. //
  889. // l and r are both now Indefinite, which can't be compared.
  890. //
  891. CPUASSERT(l->Tag == TAG_SPECIAL && l->TagSpecial == TAG_SPECIAL_INDEF);
  892. CPUASSERT(r->Tag == TAG_SPECIAL && r->TagSpecial == TAG_SPECIAL_INDEF);
  893. if (!fUnordered && HandleInvalidOp(cpu)) {
  894. // abort the FCOM/FTST instruction - Illegal opcode is unmasked
  895. return;
  896. }
  897. // Otherwise, FCOM's illegal opcode is masked, or the instruction
  898. // is FUCOM, for which QNANs are uncomparable. Return "Not comparable"
  899. cpu->FpStatusC3 = 1;
  900. cpu->FpStatusC2 = 1;
  901. cpu->FpStatusC0 = 1;
  902. }
  903. }
  904. VOID
  905. FpComCommon(
  906. PCPUDATA cpu,
  907. PFPREG l,
  908. PFPREG r,
  909. BOOL fUnordered
  910. )
  911. /*++
  912. Routine Description:
  913. Implements l += r.
  914. Arguments:
  915. cpu - per-thread data
  916. l - left-hand FP register
  917. r - right-hand FP register
  918. fUnordered - TRUE for unordered compares
  919. Return Value:
  920. None. l is updated to contain the value of l+r.
  921. --*/
  922. {
  923. cpu->FpStatusC1 = 0; // assume no error
  924. (*FpComTable[l->Tag][r->Tag])(cpu, l, r, fUnordered);
  925. }
  926. FRAG1(FADD32, FLOAT) // FADD m32real
  927. {
  928. FPREG m32real;
  929. FpArithDataPreamble(cpu, pop1);
  930. GetIntelR4(&m32real, pop1);
  931. FpAddCommon(cpu, cpu->FpST0, &m32real);
  932. }
  933. FRAG1(FADD64, DOUBLE) // FADD m64real
  934. {
  935. FPREG m64real;
  936. FpArithDataPreamble(cpu, pop1);
  937. GetIntelR8(&m64real, pop1);
  938. FpAddCommon(cpu, cpu->FpST0, &m64real);
  939. }
  940. FRAG1IMM(FADD_STi_ST, INT) // FADD ST(i), ST = add ST to ST(i)
  941. {
  942. FpArithPreamble(cpu);
  943. FpAddCommon(cpu, &cpu->FpStack[ST(op1)], cpu->FpST0);
  944. }
  945. FRAG1IMM(FADD_ST_STi, INT) // FADD ST, ST(i) = add ST(i) to ST
  946. {
  947. FpArithPreamble(cpu);
  948. FpAddCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(op1)]);
  949. }
  950. FRAG1IMM(FADDP_STi_ST, INT) // FADDP ST(i), ST = add ST to ST(i) and pop ST
  951. {
  952. FpArithPreamble(cpu);
  953. FpAddCommon(cpu, &cpu->FpStack[ST(op1)], cpu->FpST0);
  954. POPFLT;
  955. }
  956. FRAG1(FIADD16, USHORT) // FIADD m16int
  957. {
  958. FPREG m16int;
  959. short s;
  960. FpArithDataPreamble(cpu, pop1);
  961. s = (short)GET_SHORT(pop1);
  962. if (s) {
  963. m16int.r64 = (DOUBLE)s;
  964. m16int.Tag = TAG_VALID;
  965. } else {
  966. m16int.r64 = 0.0;
  967. m16int.Tag = TAG_ZERO;
  968. }
  969. FpAddCommon(cpu, cpu->FpST0, &m16int);
  970. }
  971. FRAG1(FIADD32, ULONG) // FIADD m32int
  972. {
  973. FPREG m32int;
  974. long l;
  975. FpArithDataPreamble(cpu, pop1);
  976. l = (long)GET_LONG(pop1);
  977. if (l) {
  978. m32int.r64 = (DOUBLE)l;
  979. m32int.Tag = TAG_VALID;
  980. } else {
  981. m32int.r64 = 0.0;
  982. m32int.Tag = TAG_ZERO;
  983. }
  984. FpAddCommon(cpu, cpu->FpST0, &m32int);
  985. }
  986. FRAG1(FCOM32, FLOAT) // FCOM m32real
  987. {
  988. FPREG m32real;
  989. FpArithDataPreamble(cpu, pop1);
  990. GetIntelR4(&m32real, pop1);
  991. FpComCommon(cpu, cpu->FpST0, &m32real, FALSE);
  992. }
  993. FRAG1(FCOM64, DOUBLE) // FCOM m64real
  994. {
  995. FPREG m64real;
  996. FpArithDataPreamble(cpu, pop1);
  997. GetIntelR8(&m64real, pop1);
  998. FpComCommon(cpu, cpu->FpST0, &m64real, FALSE);
  999. }
  1000. FRAG1IMM(FCOM_STi, INT) // FCOM ST(i)
  1001. {
  1002. FpArithPreamble(cpu);
  1003. FpComCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(op1)], FALSE);
  1004. }
  1005. FRAG1(FCOMP32, FLOAT) // FCOMP m32real
  1006. {
  1007. FPREG m32real;
  1008. FpArithDataPreamble(cpu, pop1);
  1009. GetIntelR4(&m32real, pop1);
  1010. FpComCommon(cpu, cpu->FpST0, &m32real, FALSE);
  1011. POPFLT;
  1012. }
  1013. FRAG1(FCOMP64, DOUBLE) // FCOMP m64real
  1014. {
  1015. FPREG m64real;
  1016. FpArithDataPreamble(cpu, pop1);
  1017. GetIntelR8(&m64real, pop1);
  1018. FpComCommon(cpu, cpu->FpST0, &m64real, FALSE);
  1019. POPFLT;
  1020. }
  1021. FRAG1IMM(FCOMP_STi, INT) // FCOMP ST(i)
  1022. {
  1023. FpArithPreamble(cpu);
  1024. FpComCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(op1)], FALSE);
  1025. POPFLT;
  1026. }
  1027. FRAG0(FCOMPP)
  1028. {
  1029. FpArithPreamble(cpu);
  1030. FpComCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(1)], FALSE);
  1031. POPFLT;
  1032. POPFLT;
  1033. }
  1034. FRAG1(FDIV32, FLOAT) // FDIV m32real
  1035. {
  1036. FPREG m32real;
  1037. FpArithDataPreamble(cpu, pop1);
  1038. GetIntelR4(&m32real, pop1);
  1039. FpDivCommon(cpu, cpu->FpST0, cpu->FpST0, &m32real);
  1040. }
  1041. FRAG1(FDIV64, DOUBLE) // FDIV m64real
  1042. {
  1043. FPREG m64real;
  1044. FpArithDataPreamble(cpu, pop1);
  1045. GetIntelR8(&m64real, pop1);
  1046. FpDivCommon(cpu, cpu->FpST0, cpu->FpST0, &m64real);
  1047. }
  1048. FRAG1IMM(FDIV_ST_STi, INT) // FDIV ST, ST(i)
  1049. {
  1050. FpArithPreamble(cpu);
  1051. FpDivCommon(cpu, cpu->FpST0, cpu->FpST0, &cpu->FpStack[ST(op1)]);
  1052. }
  1053. FRAG1IMM(FDIV_STi_ST, INT) // FDIV ST(i), ST
  1054. {
  1055. FpArithPreamble(cpu);
  1056. FpDivCommon(cpu, &cpu->FpStack[ST(op1)], cpu->FpST0, &cpu->FpStack[ST(op1)]);
  1057. }
  1058. FRAG1(FIDIV16, USHORT) // FIDIV m16int
  1059. {
  1060. FPREG m16int;
  1061. short s;
  1062. FpArithDataPreamble(cpu, pop1);
  1063. s = (short)GET_SHORT(pop1);
  1064. if (s) {
  1065. m16int.r64 = (DOUBLE)s;
  1066. m16int.Tag = TAG_VALID;
  1067. } else {
  1068. m16int.r64 = 0.0;
  1069. m16int.Tag = TAG_ZERO;
  1070. }
  1071. FpDivCommon(cpu, cpu->FpST0, cpu->FpST0, &m16int);
  1072. }
  1073. FRAG1(FIDIV32, ULONG) // FIDIV m32int
  1074. {
  1075. FPREG m32int;
  1076. long l;
  1077. FpArithDataPreamble(cpu, pop1);
  1078. l = (long)GET_LONG(pop1);
  1079. if (l) {
  1080. m32int.r64 = (DOUBLE)l;
  1081. m32int.Tag = TAG_VALID;
  1082. } else {
  1083. m32int.r64 = 0.0;
  1084. m32int.Tag = TAG_ZERO;
  1085. }
  1086. FpDivCommon(cpu, cpu->FpST0, cpu->FpST0, &m32int);
  1087. }
  1088. FRAG1IMM(FDIVP_STi_ST, INT) // FDIVP ST(i), ST
  1089. {
  1090. FpArithPreamble(cpu);
  1091. FpDivCommon(cpu, &cpu->FpStack[ST(op1)], cpu->FpST0, &cpu->FpStack[ST(op1)]);
  1092. POPFLT;
  1093. }
  1094. FRAG1(FDIVR32, FLOAT) // FDIVR m32real
  1095. {
  1096. FPREG m32real;
  1097. FpArithDataPreamble(cpu, pop1);
  1098. GetIntelR4(&m32real, pop1);
  1099. FpDivCommon(cpu, cpu->FpST0, &m32real, cpu->FpST0);
  1100. }
  1101. FRAG1(FDIVR64, DOUBLE) // FDIVR m64real
  1102. {
  1103. FPREG m64real;
  1104. FpArithDataPreamble(cpu, pop1);
  1105. GetIntelR8(&m64real, pop1);
  1106. FpDivCommon(cpu, cpu->FpST0, &m64real, cpu->FpST0);
  1107. }
  1108. FRAG1IMM(FDIVR_ST_STi, INT) // FDIVR ST, ST(i)
  1109. {
  1110. FpArithPreamble(cpu);
  1111. FpDivCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(op1)], cpu->FpST0);
  1112. }
  1113. FRAG1IMM(FDIVR_STi_ST, INT) // FDIVR ST(i), ST
  1114. {
  1115. FpArithPreamble(cpu);
  1116. FpDivCommon(cpu, &cpu->FpStack[ST(op1)], &cpu->FpStack[ST(op1)], cpu->FpST0);
  1117. }
  1118. FRAG1IMM(FDIVRP_STi_ST, INT) // FDIVRP ST(i)
  1119. {
  1120. FpArithPreamble(cpu);
  1121. FpDivCommon(cpu, &cpu->FpStack[ST(op1)], &cpu->FpStack[ST(op1)], cpu->FpST0);
  1122. POPFLT;
  1123. }
  1124. FRAG1(FIDIVR16, USHORT) // FIDIVR m16int
  1125. {
  1126. FPREG m16int;
  1127. short s;
  1128. FpArithDataPreamble(cpu, pop1);
  1129. s = (short)GET_SHORT(pop1);
  1130. if (s) {
  1131. m16int.r64 = (DOUBLE)s;
  1132. m16int.Tag = TAG_VALID;
  1133. } else {
  1134. m16int.r64 = 0.0;
  1135. m16int.Tag = TAG_ZERO;
  1136. }
  1137. FpDivCommon(cpu, cpu->FpST0, &m16int, cpu->FpST0);
  1138. }
  1139. FRAG1(FIDIVR32, ULONG) // FIDIVR m32int
  1140. {
  1141. FPREG m32int;
  1142. long l;
  1143. FpArithDataPreamble(cpu, pop1);
  1144. l = (long)GET_LONG(pop1);
  1145. if (l) {
  1146. m32int.r64 = (DOUBLE)l;
  1147. m32int.Tag = TAG_VALID;
  1148. } else {
  1149. m32int.r64 = 0.0;
  1150. m32int.Tag = TAG_ZERO;
  1151. }
  1152. FpDivCommon(cpu, cpu->FpST0, &m32int, cpu->FpST0);
  1153. }
  1154. FRAG1(FICOM16, USHORT) // FICOM m16int (Intel docs say m16real)
  1155. {
  1156. FPREG m16int;
  1157. short s;
  1158. FpArithDataPreamble(cpu, pop1);
  1159. s = (short)GET_SHORT(pop1);
  1160. if (s) {
  1161. m16int.r64 = (DOUBLE)s;
  1162. m16int.Tag = TAG_VALID;
  1163. } else {
  1164. m16int.r64 = 0.0;
  1165. m16int.Tag = TAG_ZERO;
  1166. }
  1167. FpComCommon(cpu, cpu->FpST0, &m16int, FALSE);
  1168. }
  1169. FRAG1(FICOM32, ULONG) // FICOM m32int (Intel docs say m32real)
  1170. {
  1171. FPREG m32int;
  1172. long l;
  1173. FpArithDataPreamble(cpu, pop1);
  1174. l = (long)GET_LONG(pop1);
  1175. if (l) {
  1176. m32int.r64 = (DOUBLE)l;
  1177. m32int.Tag = TAG_VALID;
  1178. } else {
  1179. m32int.r64 = 0.0;
  1180. m32int.Tag = TAG_ZERO;
  1181. }
  1182. FpComCommon(cpu, cpu->FpST0, &m32int, FALSE);
  1183. }
  1184. FRAG1(FICOMP16, USHORT) // FICOMP m16int
  1185. {
  1186. FPREG m16int;
  1187. short s;
  1188. FpArithDataPreamble(cpu, pop1);
  1189. s = (short)GET_SHORT(pop1);
  1190. if (s) {
  1191. m16int.r64 = (DOUBLE)s;
  1192. m16int.Tag = TAG_VALID;
  1193. } else {
  1194. m16int.r64 = 0.0;
  1195. m16int.Tag = TAG_ZERO;
  1196. }
  1197. FpComCommon(cpu, cpu->FpST0, &m16int, FALSE);
  1198. POPFLT;
  1199. }
  1200. FRAG1(FICOMP32, ULONG) // FICOMP m32int
  1201. {
  1202. FPREG m32int;
  1203. long l;
  1204. FpArithDataPreamble(cpu, pop1);
  1205. l = (long)GET_LONG(pop1);
  1206. if (l) {
  1207. m32int.r64 = (DOUBLE)l;
  1208. m32int.Tag = TAG_VALID;
  1209. } else {
  1210. m32int.r64 = 0.0;
  1211. m32int.Tag = TAG_ZERO;
  1212. }
  1213. FpComCommon(cpu, cpu->FpST0, &m32int, FALSE);
  1214. POPFLT;
  1215. }
  1216. FRAG1(FMUL32, FLOAT) // FMUL m32real
  1217. {
  1218. FPREG m32real;
  1219. FpArithDataPreamble(cpu, pop1);
  1220. GetIntelR4(&m32real, pop1);
  1221. FpMulCommon(cpu, cpu->FpST0, &m32real);
  1222. }
  1223. FRAG2(FMUL64, DOUBLE) // FMUL m64real
  1224. {
  1225. FPREG m64real;
  1226. FpArithDataPreamble(cpu, pop1);
  1227. GetIntelR8(&m64real, pop1);
  1228. FpMulCommon(cpu, cpu->FpST0, &m64real);
  1229. }
  1230. FRAG1IMM(FMUL_STi_ST, INT) // FMUL ST(i), ST
  1231. {
  1232. FpArithPreamble(cpu);
  1233. FpMulCommon(cpu, &cpu->FpStack[ST(op1)], cpu->FpST0);
  1234. }
  1235. FRAG1IMM(FMUL_ST_STi, INT) // FMUL ST, ST(i)
  1236. {
  1237. FpArithPreamble(cpu);
  1238. FpMulCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(op1)]);
  1239. }
  1240. FRAG1IMM(FMULP_STi_ST, INT) // FMULP ST(i), ST
  1241. {
  1242. FpArithPreamble(cpu);
  1243. FpMulCommon(cpu, &cpu->FpStack[ST(op1)], cpu->FpST0);
  1244. POPFLT;
  1245. }
  1246. FRAG1(FIMUL16, USHORT) // FIMUL m16int
  1247. {
  1248. FPREG m16int;
  1249. short s;
  1250. FpArithDataPreamble(cpu, pop1);
  1251. s = (short)GET_SHORT(pop1);
  1252. if (s) {
  1253. m16int.r64 = (DOUBLE)s;
  1254. m16int.Tag = TAG_VALID;
  1255. } else {
  1256. m16int.r64 = 0.0;
  1257. m16int.Tag = TAG_ZERO;
  1258. }
  1259. FpMulCommon(cpu, cpu->FpST0, &m16int);
  1260. }
  1261. FRAG1(FIMUL32, ULONG) // FIMUL m32int
  1262. {
  1263. FPREG m32int;
  1264. long l;
  1265. FpArithDataPreamble(cpu, pop1);
  1266. l = (long)GET_LONG(pop1);
  1267. if (l) {
  1268. m32int.r64 = (DOUBLE)l;
  1269. m32int.Tag = TAG_VALID;
  1270. } else {
  1271. m32int.r64 = 0.0;
  1272. m32int.Tag = TAG_ZERO;
  1273. }
  1274. FpMulCommon(cpu, cpu->FpST0, &m32int);
  1275. }
  1276. FRAG1(FSUB32, FLOAT) // FSUB m32real
  1277. {
  1278. FPREG m32real;
  1279. FpArithDataPreamble(cpu, pop1);
  1280. GetIntelR4(&m32real, pop1);
  1281. FpSubCommon(cpu, cpu->FpST0, cpu->FpST0, &m32real);
  1282. }
  1283. FRAG1(FSUBP32, FLOAT) // FSUBP m32real
  1284. {
  1285. FPREG m32real;
  1286. FpArithDataPreamble(cpu, pop1);
  1287. GetIntelR4(&m32real, pop1);
  1288. FpSubCommon(cpu, cpu->FpST0, cpu->FpST0, &m32real);
  1289. POPFLT;
  1290. }
  1291. FRAG1(FSUB64, DOUBLE) // FSUB m64real
  1292. {
  1293. FPREG m64real;
  1294. FpArithDataPreamble(cpu, pop1);
  1295. GetIntelR8(&m64real, pop1);
  1296. FpSubCommon(cpu, cpu->FpST0, cpu->FpST0, &m64real);
  1297. }
  1298. FRAG1(FSUBP64, DOUBLE) // FSUBP m64real
  1299. {
  1300. FPREG m64real;
  1301. FpArithDataPreamble(cpu, pop1);
  1302. GetIntelR8(&m64real, pop1);
  1303. FpSubCommon(cpu, cpu->FpST0, cpu->FpST0, &m64real);
  1304. POPFLT;
  1305. }
  1306. FRAG1IMM(FSUB_ST_STi, INT) // FSUB ST, ST(i)
  1307. {
  1308. FpArithPreamble(cpu);
  1309. FpSubCommon(cpu, cpu->FpST0, cpu->FpST0, &cpu->FpStack[ST(op1)]);
  1310. }
  1311. FRAG1IMM(FSUB_STi_ST, INT) // FSUB ST(i), ST
  1312. {
  1313. FpArithPreamble(cpu);
  1314. FpSubCommon(cpu, &cpu->FpStack[ST(op1)], cpu->FpST0, &cpu->FpStack[ST(op1)]);
  1315. }
  1316. FRAG1IMM(FSUBP_STi_ST, INT) // FSUBP ST(i), ST
  1317. {
  1318. FpArithPreamble(cpu);
  1319. FpSubCommon(cpu, &cpu->FpStack[ST(op1)], cpu->FpST0, &cpu->FpStack[ST(op1)]);
  1320. POPFLT;
  1321. }
  1322. FRAG1(FISUB16, USHORT) // FISUB m16int
  1323. {
  1324. FPREG m16int;
  1325. short s;
  1326. FpArithDataPreamble(cpu, pop1);
  1327. s = (short)GET_SHORT(pop1);
  1328. if (s) {
  1329. m16int.r64 = (DOUBLE)s;
  1330. m16int.Tag = TAG_VALID;
  1331. } else {
  1332. m16int.r64 = 0.0;
  1333. m16int.Tag = TAG_ZERO;
  1334. }
  1335. FpSubCommon(cpu, cpu->FpST0, cpu->FpST0, &m16int);
  1336. }
  1337. FRAG1(FISUB32, ULONG) // FISUB m32int
  1338. {
  1339. FPREG m32int;
  1340. long l;
  1341. FpArithDataPreamble(cpu, pop1);
  1342. l = (long)GET_LONG(pop1);
  1343. if (l) {
  1344. m32int.r64 = (DOUBLE)l;
  1345. m32int.Tag = TAG_VALID;
  1346. } else {
  1347. m32int.r64 = 0.0;
  1348. m32int.Tag = TAG_ZERO;
  1349. }
  1350. FpSubCommon(cpu, cpu->FpST0, cpu->FpST0, &m32int);
  1351. }
  1352. FRAG1(FSUBR32, FLOAT) // FSUBR m32real
  1353. {
  1354. FPREG m32real;
  1355. FpArithDataPreamble(cpu, pop1);
  1356. GetIntelR4(&m32real, pop1);
  1357. FpSubCommon(cpu, cpu->FpST0, &m32real, cpu->FpST0);
  1358. }
  1359. FRAG1(FSUBR64, DOUBLE) // FSUBR m64real
  1360. {
  1361. FPREG m64real;
  1362. FpArithDataPreamble(cpu, pop1);
  1363. GetIntelR8(&m64real, pop1);
  1364. FpSubCommon(cpu, cpu->FpST0, &m64real, cpu->FpST0);
  1365. }
  1366. FRAG1IMM(FSUBR_ST_STi, INT) // FSUBR ST, ST(i)
  1367. {
  1368. FpArithPreamble(cpu);
  1369. FpSubCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(op1)], cpu->FpST0);
  1370. }
  1371. FRAG1IMM(FSUBR_STi_ST, INT) // FSUBR ST(i), ST
  1372. {
  1373. FpArithPreamble(cpu);
  1374. FpSubCommon(cpu, &cpu->FpStack[ST(op1)], &cpu->FpStack[ST(op1)], cpu->FpST0);
  1375. }
  1376. FRAG1IMM(FSUBRP_STi_ST, INT) // FSUBRP ST(i)
  1377. {
  1378. FpArithPreamble(cpu);
  1379. FpSubCommon(cpu, &cpu->FpStack[ST(op1)], &cpu->FpStack[ST(op1)], cpu->FpST0);
  1380. POPFLT;
  1381. }
  1382. FRAG1(FISUBR16, USHORT)
  1383. {
  1384. FPREG m16int;
  1385. short s;
  1386. FpArithDataPreamble(cpu, pop1);
  1387. s = (short)GET_SHORT(pop1);
  1388. if (s) {
  1389. m16int.r64 = (DOUBLE)s;
  1390. m16int.Tag = TAG_VALID;
  1391. } else {
  1392. m16int.r64 = 0.0;
  1393. m16int.Tag = TAG_ZERO;
  1394. }
  1395. FpSubCommon(cpu, cpu->FpST0, &m16int, cpu->FpST0);
  1396. }
  1397. FRAG1(FISUBR32, ULONG)
  1398. {
  1399. FPREG m32int;
  1400. long l;
  1401. FpArithDataPreamble(cpu, pop1);
  1402. l = (long)GET_LONG(pop1);
  1403. if (l) {
  1404. m32int.r64 = (DOUBLE)l;
  1405. m32int.Tag = TAG_VALID;
  1406. } else {
  1407. m32int.r64 = 0.0;
  1408. m32int.Tag = TAG_ZERO;
  1409. }
  1410. FpSubCommon(cpu, cpu->FpST0, &m32int, cpu->FpST0);
  1411. }
  1412. FRAG0(FTST)
  1413. {
  1414. FPREG Zero;
  1415. FpArithPreamble(cpu);
  1416. Zero.r64 = 0.0;
  1417. Zero.Tag = TAG_ZERO;
  1418. FpComCommon(cpu, cpu->FpST0, &Zero, FALSE);
  1419. }
  1420. FRAG1IMM(FUCOM, INT) // FUCOM ST(i) / FUCOM
  1421. {
  1422. FpArithPreamble(cpu);
  1423. FpComCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(op1)], TRUE);
  1424. }
  1425. FRAG1IMM(FUCOMP, INT) // FUCOMP ST(i) / FUCOMP
  1426. {
  1427. FpArithPreamble(cpu);
  1428. FpComCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(op1)], TRUE);
  1429. POPFLT;
  1430. }
  1431. FRAG0(FUCOMPP)
  1432. {
  1433. FpArithPreamble(cpu);
  1434. FpComCommon(cpu, cpu->FpST0, &cpu->FpStack[ST(1)], TRUE);
  1435. POPFLT;
  1436. POPFLT;
  1437. }