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.

528 lines
16 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. floatfns.c
  5. Abstract:
  6. Floating point instruction decoder.
  7. Author:
  8. 16-Aug-1995 BarryBo
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <stdio.h>
  16. #include "threadst.h"
  17. #include "instr.h"
  18. #include "decoderp.h"
  19. extern DWORD pfnNPXNPHandler;
  20. extern BOOLEAN fUseNPXEM;
  21. typedef float *PFLOAT;
  22. typedef double *PDOUBLE;
  23. typedef void (*pfnFrag0)(PCPUDATA);
  24. typedef void (*pfnFrag1INT)(PCPUDATA, INT);
  25. typedef void (*pfnFrag1FLOAT)(PCPUDATA, PFLOAT);
  26. typedef void (*pfnFrag1DOUBLE)(PCPUDATA, PDOUBLE);
  27. typedef void (*pfnFrag1PLONG)(PCPUDATA, PLONG);
  28. typedef void (*pfnFrag2INTINT)(PCPUDATA, INT, INT);
  29. typedef void (*pfnFrag1PUSHORT)(PCPUDATA, PUSHORT);
  30. OPERATION GP0Mem[8] = {OP_FP_FADD32,
  31. OP_FP_FMUL32,
  32. OP_FP_FCOM32,
  33. OP_FP_FCOMP32,
  34. OP_FP_FSUB32,
  35. OP_FP_FSUBR32,
  36. OP_FP_FDIV32,
  37. OP_FP_FDIVR32};
  38. OPERATION GP0Top[8] = {OP_FP_FADD_ST_STi,
  39. OP_FP_FMUL_ST_STi,
  40. OP_FP_FCOM_STi,
  41. OP_FP_FCOMP_STi,
  42. OP_FP_FSUB_ST_STi,
  43. OP_FP_FSUBR_ST_STi,
  44. OP_FP_FDIV_ST_STi,
  45. OP_FP_FDIVR_ST_STi};
  46. OPERATION GP1GroupFCHS[8] = {OP_FP_FCHS,
  47. OP_FP_FABS,
  48. OP_BadInstruction,
  49. OP_BadInstruction,
  50. OP_FP_FTST,
  51. OP_FP_FXAM,
  52. OP_BadInstruction,
  53. OP_BadInstruction};
  54. OPERATION GP1GroupFLD1[8] = {OP_FP_FLD1,
  55. OP_FP_FLDL2T,
  56. OP_FP_FLDL2E,
  57. OP_FP_FLDPI,
  58. OP_FP_FLDLG2,
  59. OP_FP_FLDLN2,
  60. OP_FP_FLDZ,
  61. OP_BadInstruction};
  62. OPERATION GP1GroupF2XM1[8] = {OP_FP_F2XM1,
  63. OP_FP_FYL2X,
  64. OP_FP_FPTAN,
  65. OP_FP_FPATAN,
  66. OP_FP_FXTRACT,
  67. OP_FP_FPREM1,
  68. OP_FP_FDECSTP,
  69. OP_FP_FINCSTP};
  70. OPERATION GP1GroupFPREM[8] = {OP_FP_FPREM,
  71. OP_FP_FYL2XP1,
  72. OP_FP_FSQRT,
  73. OP_FP_FSINCOS,
  74. OP_FP_FRNDINT,
  75. OP_FP_FSCALE,
  76. OP_FP_FSIN,
  77. OP_FP_FCOS};
  78. OPERATION GP1Mem[8] = {OP_FP_FLD32,
  79. OP_BadInstruction, // never called
  80. OP_FP_FST32,
  81. OP_FP_FSTP32,
  82. OP_FP_FLDENV,
  83. OP_FP_FLDCW,
  84. OP_FP_FNSTENV,
  85. OP_FP_FNSTCW};
  86. OPERATION GP2Mem[8] = {OP_FP_FIADD32,
  87. OP_FP_FIMUL32,
  88. OP_FP_FICOM32,
  89. OP_FP_FICOMP32,
  90. OP_FP_FISUB32,
  91. OP_FP_FISUBR32,
  92. OP_FP_FIDIV32,
  93. OP_FP_FIDIVR32};
  94. OPERATION GP4Mem[8] = {OP_FP_FADD64,
  95. OP_FP_FMUL64,
  96. OP_FP_FCOM64,
  97. OP_FP_FCOMP64,
  98. OP_FP_FSUB64,
  99. OP_FP_FSUBR64,
  100. OP_FP_FDIV64,
  101. OP_FP_FDIVR64};
  102. OPERATION GP4Reg[8] = {OP_FP_FADD_STi_ST,
  103. OP_FP_FMUL_STi_ST,
  104. OP_FP_FCOM_STi,
  105. OP_FP_FCOMP_STi,
  106. OP_FP_FSUB_STi_ST,
  107. OP_FP_FSUBR_STi_ST,
  108. OP_FP_FDIV_STi_ST,
  109. OP_FP_FDIVR_STi_ST};
  110. OPERATION GP5Mem[8] = {OP_FP_FLD64,
  111. OP_BadInstruction,
  112. OP_FP_FST64,
  113. OP_FP_FSTP64,
  114. OP_FP_FRSTOR,
  115. OP_BadInstruction,
  116. OP_FP_FNSAVE,
  117. OP_FP_FNSTSW};
  118. OPERATION GP5Reg[8] = {OP_FP_FFREE,
  119. OP_FP_FXCH_STi,
  120. OP_FP_FST_STi,
  121. OP_FP_FSTP_STi,
  122. OP_FP_FUCOM,
  123. OP_FP_FUCOMP,
  124. OP_BadInstruction,
  125. OP_BadInstruction};
  126. OPERATION GP6Mem[8] = {OP_FP_FIADD16,
  127. OP_FP_FIMUL16,
  128. OP_FP_FICOM16,
  129. OP_FP_FICOMP16,
  130. OP_FP_FISUB16,
  131. OP_FP_FISUBR16,
  132. OP_FP_FIDIV16,
  133. OP_FP_FIDIVR16};
  134. OPERATION GP6Reg[8] = {OP_FP_FADDP_STi_ST,
  135. OP_FP_FMULP_STi_ST,
  136. OP_FP_FCOMP_STi,
  137. OP_FP_FCOMPP,
  138. OP_FP_FSUBP_STi_ST,
  139. OP_FP_FSUBRP_STi_ST,
  140. OP_FP_FDIVP_STi_ST,
  141. OP_FP_FDIVRP_STi_ST};
  142. OPERATION GP7Mem[8] = {OP_FP_FILD16,
  143. OP_BadInstruction,
  144. OP_FP_FIST16,
  145. OP_FP_FISTP16,
  146. OP_FP_FBLD,
  147. OP_FP_FILD64,
  148. OP_FP_FBSTP,
  149. OP_FP_FISTP64};
  150. OPERATION GP7Reg[8] = {OP_FP_FFREE, // not in Intel docs, but NTSD knows it
  151. OP_FP_FXCH_STi, // not in Intel docs, but NTSD knows it
  152. OP_FP_FST_STi,
  153. OP_FP_FSTP_STi,
  154. OP_BadInstruction,
  155. OP_BadInstruction,
  156. OP_BadInstruction,
  157. OP_BadInstruction};
  158. //***************************************************************************
  159. DISPATCH(FLOAT_GP0) // d8 XX
  160. {
  161. BYTE secondByte;
  162. secondByte = *((PBYTE)(eipTemp+1));
  163. if (secondByte < 0xc0) {
  164. // memory format
  165. int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
  166. Instr->Operation = GP0Mem[(secondByte>>3) & 7];
  167. Instr->Size = cbInstr+1;
  168. } else {
  169. // register format
  170. Instr->Operation = GP0Top[(secondByte>>3) & 7];
  171. Instr->Operand1.Type = OPND_IMM;
  172. Instr->Operand1.Immed = secondByte & 7;
  173. Instr->Size = 2;
  174. }
  175. if (fUseNPXEM) {
  176. // generate a "CALL pfnNPXNPHandler" instruction, with a length
  177. // the same as the FP instruction we're emulating.
  178. Instr->Operation = OP_CTRL_UNCOND_Call;
  179. Instr->Operand1.Type = OPND_IMM;
  180. Instr->Operand1.Immed = pfnNPXNPHandler; // dest of call
  181. Instr->Operand2.Type = OPND_IMM;
  182. Instr->Operand2.Immed = eipTemp; // addr of FP instr
  183. }
  184. }
  185. DISPATCH(FLOAT_GP1) // d9 XX
  186. {
  187. BYTE secondByte, inst;
  188. secondByte = *((PBYTE)(eipTemp+1));
  189. inst = (secondByte>>3) & 7;
  190. if (secondByte < 0xc0) {
  191. // memory format
  192. if (inst == 1) {
  193. Instr->Operation = OP_BadInstruction;
  194. } else {
  195. int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
  196. Instr->Operation = GP1Mem[(secondByte>>3) & 7];
  197. Instr->Size = cbInstr+1;
  198. }
  199. } else {
  200. // register format
  201. switch ( inst ) {
  202. case 0: // d9 c0+i
  203. Instr->Operation = OP_FP_FLD_STi;
  204. Instr->Operand1.Type = OPND_IMM;
  205. Instr->Operand1.Immed = secondByte & 7;
  206. break;
  207. case 1: // d9 c8+i
  208. Instr->Operation = OP_FP_FXCH_STi;
  209. Instr->Operand1.Type = OPND_IMM;
  210. Instr->Operand1.Immed = secondByte & 7;
  211. break;
  212. case 2:
  213. if (secondByte == 0xd0) {
  214. Instr->Operation = OP_FP_FNOP; // FNOP (d9 d0)
  215. } else {
  216. Instr->Operation = OP_BadInstruction; // (d9 d1..d7)
  217. }
  218. break;
  219. case 3: // d9 d8+i
  220. Instr->Operation = OP_BadInstruction;
  221. //UNDONE: emstore.asm says FSTP Special Form 1
  222. break;
  223. case 4: // d9 e0+i
  224. Instr->Operation = GP1GroupFCHS[secondByte&7];
  225. break;
  226. case 5:
  227. Instr->Operation = GP1GroupFLD1[secondByte&7];
  228. break;
  229. case 6:
  230. Instr->Operation = GP1GroupF2XM1[secondByte&7];
  231. break;
  232. default:
  233. case 7:
  234. Instr->Operation = GP1GroupFPREM[secondByte&7];
  235. break;
  236. }
  237. Instr->Size = 2;
  238. }
  239. if (fUseNPXEM) {
  240. // generate a "CALL pfnNPXNPHandler" instruction, with a length
  241. // the same as the FP instruction we're emulating.
  242. Instr->Operation = OP_CTRL_UNCOND_Call;
  243. Instr->Operand1.Type = OPND_IMM;
  244. Instr->Operand1.Immed = pfnNPXNPHandler;
  245. Instr->Operand2.Type = OPND_IMM;
  246. Instr->Operand2.Immed = eipTemp; // addr of FP instr
  247. }
  248. }
  249. DISPATCH(FLOAT_GP2) // da XX
  250. {
  251. BYTE secondByte;
  252. secondByte = *((PBYTE)(eipTemp+1));
  253. if (secondByte < 0xc0) {
  254. // memory format
  255. int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
  256. Instr->Operation = GP2Mem[(secondByte>>3) & 7];
  257. Instr->Size = cbInstr+1;
  258. } else if (secondByte == 0xe9) {
  259. Instr->Operation = OP_FP_FUCOMPP;
  260. Instr->Size = 2;
  261. } else {
  262. Instr->Operation = OP_BadInstruction;
  263. }
  264. if (fUseNPXEM) {
  265. // generate a "CALL pfnNPXNPHandler" instruction, with a length
  266. // the same as the FP instruction we're emulating.
  267. Instr->Operation = OP_CTRL_UNCOND_Call;
  268. Instr->Operand1.Type = OPND_IMM;
  269. Instr->Operand1.Immed = pfnNPXNPHandler;
  270. Instr->Operand2.Type = OPND_IMM;
  271. Instr->Operand2.Immed = eipTemp; // addr of FP instr
  272. }
  273. }
  274. DISPATCH(FLOAT_GP3) // db XX
  275. {
  276. BYTE secondByte;
  277. secondByte = *((PBYTE)(eipTemp+1));
  278. if (secondByte < 0xc0) {
  279. // memory format
  280. int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
  281. switch ((secondByte>>3) & 7) {
  282. case 0:
  283. Instr->Operation = OP_FP_FILD32;
  284. break;
  285. case 1:
  286. case 4:
  287. case 6:
  288. Instr->Operation = OP_BadInstruction;
  289. break;
  290. case 2:
  291. Instr->Operation = OP_FP_FIST32;
  292. break;
  293. case 3:
  294. Instr->Operation = OP_FP_FISTP32;
  295. break;
  296. case 5:
  297. Instr->Operation = OP_FP_FLD80;
  298. break;
  299. case 7:
  300. Instr->Operation = OP_FP_FSTP80;
  301. break;
  302. }
  303. Instr->Size = cbInstr+1;
  304. } else {
  305. Instr->Size = 2;
  306. if (secondByte == 0xe2) {
  307. Instr->Operation = OP_FP_FNCLEX;
  308. } else if (secondByte == 0xe3) {
  309. Instr->Operation = OP_FP_FNINIT;
  310. } else {
  311. Instr->Operation = OP_FP_FNOP; // FDISI, FENI, FSETPM are 2-byte FNOPs
  312. }
  313. }
  314. if (fUseNPXEM) {
  315. // generate a "CALL pfnNPXNPHandler" instruction, with a length
  316. // the same as the FP instruction we're emulating.
  317. Instr->Operation = OP_CTRL_UNCOND_Call;
  318. Instr->Operand1.Type = OPND_IMM;
  319. Instr->Operand1.Immed = pfnNPXNPHandler;
  320. Instr->Operand2.Type = OPND_IMM;
  321. Instr->Operand2.Immed = eipTemp; // addr of FP instr
  322. }
  323. }
  324. DISPATCH(FLOAT_GP4) // dc XX
  325. {
  326. BYTE secondByte;
  327. secondByte = *((PBYTE)(eipTemp+1));
  328. if (secondByte < 0xc0) {
  329. // memory format
  330. int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
  331. Instr->Operation = GP4Mem[(secondByte>>3) & 7];
  332. Instr->Size = cbInstr+1;
  333. } else {
  334. // register format - "OP ST(i)"
  335. Instr->Operation = GP4Reg[(secondByte>>3) & 7];
  336. Instr->Operand1.Type = OPND_IMM;
  337. Instr->Operand1.Immed = secondByte & 7;
  338. Instr->Size = 2;
  339. }
  340. if (fUseNPXEM) {
  341. // generate a "CALL pfnNPXNPHandler" instruction, with a length
  342. // the same as the FP instruction we're emulating.
  343. Instr->Operation = OP_CTRL_UNCOND_Call;
  344. Instr->Operand1.Type = OPND_IMM;
  345. Instr->Operand1.Immed = pfnNPXNPHandler;
  346. Instr->Operand2.Type = OPND_IMM;
  347. Instr->Operand2.Immed = eipTemp; // addr of FP instr
  348. }
  349. }
  350. DISPATCH(FLOAT_GP5) // dd XX
  351. {
  352. BYTE secondByte;
  353. secondByte = *((PBYTE)(eipTemp+1));
  354. if (secondByte < 0xc0) {
  355. // memory format
  356. int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
  357. Instr->Operation = GP5Mem[(secondByte>>3)&7];
  358. Instr->Size = cbInstr+1;
  359. } else {
  360. // register format "OP ST(i)"
  361. Instr->Operation = GP5Reg[(secondByte>>3)&7];
  362. Instr->Operand1.Type = OPND_IMM;
  363. Instr->Operand1.Immed = secondByte & 7;
  364. Instr->Size = 2;
  365. }
  366. if (fUseNPXEM) {
  367. // generate a "CALL pfnNPXNPHandler" instruction, with a length
  368. // the same as the FP instruction we're emulating.
  369. Instr->Operation = OP_CTRL_UNCOND_Call;
  370. Instr->Operand1.Type = OPND_IMM;
  371. Instr->Operand1.Immed = pfnNPXNPHandler;
  372. Instr->Operand2.Type = OPND_IMM;
  373. Instr->Operand2.Immed = eipTemp; // addr of FP instr
  374. }
  375. }
  376. DISPATCH(FLOAT_GP6) // de XX
  377. {
  378. BYTE secondByte, inst;
  379. secondByte = *((PBYTE)(eipTemp+1));
  380. inst = (secondByte>>3) & 7;
  381. if (secondByte < 0xc0) {
  382. // memory format
  383. int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
  384. Instr->Operation = GP6Mem[(secondByte>>3)&7];
  385. Instr->Size = cbInstr+1;
  386. } else {
  387. // register format
  388. if (inst == 3 && secondByte != 0xd9) {
  389. Instr->Operation = OP_BadInstruction;
  390. } else {
  391. Instr->Operation = GP6Reg[inst];
  392. Instr->Operand1.Type = OPND_IMM;
  393. Instr->Operand1.Immed = secondByte & 7;
  394. Instr->Size = 2;
  395. }
  396. }
  397. if (fUseNPXEM) {
  398. // generate a "CALL pfnNPXNPHandler" instruction, with a length
  399. // the same as the FP instruction we're emulating.
  400. Instr->Operation = OP_CTRL_UNCOND_Call;
  401. Instr->Operand1.Type = OPND_IMM;
  402. Instr->Operand1.Immed = pfnNPXNPHandler;
  403. Instr->Operand2.Type = OPND_IMM;
  404. Instr->Operand2.Immed = eipTemp; // addr of FP instr
  405. }
  406. }
  407. DISPATCH(FLOAT_GP7) // df XX
  408. {
  409. BYTE secondByte, inst;
  410. secondByte = *((PBYTE)(eipTemp+1));
  411. inst = (secondByte>>3) & 7;
  412. if (secondByte < 0xc0) {
  413. // memory format
  414. int cbInstr = mod_rm_reg32(State, &Instr->Operand1, NULL);
  415. Instr->Operation = GP7Mem[(secondByte>>3)&7];
  416. Instr->Size = cbInstr+1;
  417. } else {
  418. // register format
  419. if (inst == 4) {
  420. Instr->Operation = OP_FP_FNSTSW;
  421. Instr->Operand1.Type = OPND_REGREF;
  422. Instr->Operand1.Reg = GP_AX;
  423. } else {
  424. Instr->Operation = GP7Reg[inst];
  425. Instr->Operand1.Type = OPND_IMM;
  426. Instr->Operand1.Immed = secondByte & 7;
  427. }
  428. Instr->Size = 2;
  429. }
  430. if (fUseNPXEM) {
  431. // generate a "CALL pfnNPXNPHandler" instruction, with a length
  432. // the same as the FP instruction we're emulating.
  433. Instr->Operation = OP_CTRL_UNCOND_Call;
  434. Instr->Operand1.Type = OPND_IMM;
  435. Instr->Operand1.Immed = pfnNPXNPHandler;
  436. Instr->Operand2.Type = OPND_IMM;
  437. Instr->Operand2.Immed = eipTemp; // addr of FP instr
  438. }
  439. }