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.

603 lines
9.6 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. addops.c
  5. Abstract:
  6. This module implements the code to emulate the add, sub, adc, sbb,
  7. inc, dec, and neg opcodes.
  8. Author:
  9. David N. Cutler (davec) 2-Sep-1994
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "nthal.h"
  15. #include "emulate.h"
  16. //
  17. // Define forward referenced prototypes.
  18. //
  19. VOID
  20. XmAddOperands (
  21. IN PRXM_CONTEXT P,
  22. IN ULONG Carry
  23. );
  24. VOID
  25. XmSubOperands (
  26. IN PRXM_CONTEXT P,
  27. IN ULONG Borrow
  28. );
  29. VOID
  30. XmAddOp (
  31. IN PRXM_CONTEXT P
  32. )
  33. /*++
  34. Routine Description:
  35. This function emulates an add opcode.
  36. Arguments:
  37. P - Supplies a pointer to the emulation context structure.
  38. Return Value:
  39. None.
  40. --*/
  41. {
  42. //
  43. // Add operands and store result.
  44. //
  45. XmAddOperands(P, 0);
  46. return;
  47. }
  48. VOID
  49. XmAdcOp (
  50. IN PRXM_CONTEXT P
  51. )
  52. /*++
  53. Routine Description:
  54. This function emulates an add with carry opcode.
  55. Arguments:
  56. P - Supplies a pointer to the emulation context structure.
  57. Return Value:
  58. None.
  59. --*/
  60. {
  61. //
  62. // Add operands with carry and store result.
  63. //
  64. XmAddOperands(P, P->Eflags.EFLAG_CF);
  65. return;
  66. }
  67. VOID
  68. XmSbbOp (
  69. IN PRXM_CONTEXT P
  70. )
  71. /*++
  72. Routine Description:
  73. This function emulates a subtract with borrow opcode.
  74. Arguments:
  75. P - Supplies a pointer to the emulation context structure.
  76. Return Value:
  77. None.
  78. --*/
  79. {
  80. ULONG Source;
  81. //
  82. // Subtract operands with borrow and store result.
  83. //
  84. XmSubOperands(P, P->Eflags.EFLAG_CF);
  85. return;
  86. }
  87. VOID
  88. XmSubOp (
  89. IN PRXM_CONTEXT P
  90. )
  91. /*++
  92. Routine Description:
  93. This function emulates a subtract opcode.
  94. Arguments:
  95. P - Supplies a pointer to the emulation context structure.
  96. Return Value:
  97. None.
  98. --*/
  99. {
  100. //
  101. // Subtract operands and store result.
  102. //
  103. XmSubOperands(P, 0);
  104. return;
  105. }
  106. VOID
  107. XmCmpOp (
  108. IN PRXM_CONTEXT P
  109. )
  110. /*++
  111. Routine Description:
  112. This function emulates a cmp opcode.
  113. Arguments:
  114. P - Supplies a pointer to the emulation context structure.
  115. Return Value:
  116. None.
  117. --*/
  118. {
  119. //
  120. // Subtract operands to perform comparison operation.
  121. //
  122. XmSubOperands(P, 0);
  123. return;
  124. }
  125. VOID
  126. XmCmpxchgOp (
  127. IN PRXM_CONTEXT P
  128. )
  129. /*++
  130. Routine Description:
  131. This function emulates a cmpxchg opcode.
  132. Arguments:
  133. P - Supplies a pointer to the emulation context structure.
  134. Return Value:
  135. None.
  136. --*/
  137. {
  138. ULONG Accumulator;
  139. ULONG Destination;
  140. //
  141. // Compare the destination with the accumulator. If the destination
  142. // operand is equal to the accumulator, then set ZF and store the
  143. // source operand value in the destination opperand. Otherwise, clear
  144. // ZF and store the destination operand in the accumlator.
  145. //
  146. Destination = P->DstValue.Long;
  147. if (P->DataType == BYTE_DATA) {
  148. Accumulator = P->Gpr[AL].Xl;
  149. } else if (P->DataType == LONG_DATA) {
  150. Accumulator = P->Gpr[EAX].Exx;
  151. } else {
  152. Accumulator = P->Gpr[AX].Xx;
  153. }
  154. if (Destination == Accumulator) {
  155. P->Eflags.EFLAG_ZF = 1;
  156. XmStoreResult(P, P->SrcValue.Long);
  157. } else {
  158. P->Eflags.EFLAG_ZF = 0;
  159. P->DstLong = (ULONG UNALIGNED *)(&P->Gpr[EAX].Exx);
  160. XmStoreResult(P, P->DstValue.Long);
  161. }
  162. //
  163. // Subtract operands to perform comparison operation.
  164. //
  165. P->SrcValue.Long = P->DstValue.Long;
  166. P->DstValue.Long = Accumulator;
  167. XmSubOperands(P, 0);
  168. return;
  169. }
  170. VOID
  171. XmDecOp (
  172. IN PRXM_CONTEXT P
  173. )
  174. /*++
  175. Routine Description:
  176. This function emulates a decrement opcode.
  177. Arguments:
  178. P - Supplies a pointer to the emulation context structure.
  179. Return Value:
  180. None.
  181. --*/
  182. {
  183. //
  184. // Subtract operands and store result.
  185. //
  186. //
  187. P->SrcValue.Long = 1;
  188. XmSubOperands(P, 0);
  189. return;
  190. }
  191. VOID
  192. XmIncOp (
  193. IN PRXM_CONTEXT P
  194. )
  195. /*++
  196. Routine Description:
  197. This function emulates an increment opcode.
  198. Arguments:
  199. P - Supplies a pointer to the emulation context structure.
  200. Return Value:
  201. None.
  202. --*/
  203. {
  204. //
  205. // Add operands and store result.
  206. //
  207. P->SrcValue.Long = 1;
  208. XmAddOperands(P, 0);
  209. return;
  210. }
  211. VOID
  212. XmNegOp (
  213. IN PRXM_CONTEXT P
  214. )
  215. /*++
  216. Routine Description:
  217. This function emulates a neg opcode.
  218. Arguments:
  219. P - Supplies a pointer to the emulation context structure.
  220. Return Value:
  221. None.
  222. --*/
  223. {
  224. //
  225. // Subtract operand from zero and store result.
  226. //
  227. P->SrcValue.Long = P->DstValue.Long;
  228. P->DstValue.Long = 0;
  229. XmSubOperands(P, 0);
  230. return;
  231. }
  232. VOID
  233. XmXaddOp (
  234. IN PRXM_CONTEXT P
  235. )
  236. /*++
  237. Routine Description:
  238. This function emulates an xadd opcode.
  239. Arguments:
  240. P - Supplies a pointer to the emulation context structure.
  241. Return Value:
  242. None.
  243. --*/
  244. {
  245. ULONG Destination;
  246. //
  247. // Exchange add operands and store result.
  248. //
  249. Destination = P->DstValue.Long;
  250. XmAddOperands(P, 0);
  251. P->DstLong = P->SrcLong;
  252. XmStoreResult(P, Destination);
  253. return;
  254. }
  255. VOID
  256. XmAddOperands (
  257. IN PRXM_CONTEXT P,
  258. IN ULONG Carry
  259. )
  260. /*++
  261. Routine Description:
  262. This function adds two operands and computes the resulting condition
  263. codes.
  264. Arguments:
  265. P - Supplies a pointer to the emulation context structure.
  266. Carry - Supplies the carry value.
  267. Return Value:
  268. None.
  269. --*/
  270. {
  271. ULONG CarryFlag;
  272. ULONG Shift;
  273. union {
  274. UCHAR ResultByte;
  275. ULONG ResultLong;
  276. USHORT ResultWord;
  277. } u;
  278. u.ResultLong = 0;
  279. if (P->DataType == BYTE_DATA) {
  280. u.ResultByte = P->SrcValue.Byte + (UCHAR)Carry;
  281. CarryFlag = u.ResultByte < (UCHAR)Carry;
  282. u.ResultByte += P->DstValue.Byte;
  283. CarryFlag |= (u.ResultByte < P->DstValue.Byte);
  284. Shift = 7;
  285. } else if (P->DataType == LONG_DATA) {
  286. u.ResultLong = P->SrcValue.Long + Carry;
  287. CarryFlag = (u.ResultLong < Carry);
  288. u.ResultLong += P->DstValue.Long;
  289. CarryFlag |= (u.ResultLong < P->DstValue.Long);
  290. Shift = 31;
  291. } else {
  292. u.ResultWord = P->SrcValue.Word + (USHORT)Carry;
  293. CarryFlag = (u.ResultWord < (USHORT)Carry);
  294. u.ResultWord += P->DstValue.Word;
  295. CarryFlag |= (u.ResultWord < P->DstValue.Word);
  296. Shift = 15;
  297. }
  298. //
  299. // Store the result.
  300. //
  301. XmStoreResult(P, u.ResultLong);
  302. //
  303. // If the function is not an increment, then store the carry flag.
  304. //
  305. if (P->FunctionIndex != X86_INC_OP) {
  306. P->Eflags.EFLAG_CF = CarryFlag;
  307. }
  308. //
  309. // Compute and store the parity and auxiliary carry flags.
  310. //
  311. P->Eflags.EFLAG_PF = XmComputeParity(u.ResultLong);
  312. P->Eflags.EFLAG_AF = ((P->DstValue.Byte & 0xf) +
  313. (P->SrcValue.Long & 0xf) + Carry) >> 4;
  314. //
  315. // Compute and store the zero and sign flags.
  316. //
  317. P->Eflags.EFLAG_ZF = (u.ResultLong == 0);
  318. P->Eflags.EFLAG_SF = u.ResultLong >> Shift;
  319. //
  320. // The overflow flag is computed as the carry into the sign bit
  321. // compared with the carry out of the sign bit.
  322. //
  323. P->Eflags.EFLAG_OF = (((P->SrcValue.Long ^ P->DstValue.Long) ^
  324. u.ResultLong) >> Shift) ^ CarryFlag;
  325. return;
  326. }
  327. VOID
  328. XmSubOperands (
  329. IN PRXM_CONTEXT P,
  330. IN ULONG Borrow
  331. )
  332. /*++
  333. Routine Description:
  334. This function adds to operands and computes the resulting condition
  335. codes.
  336. Arguments:
  337. P - Supplies a pointer to the emulation context structure.
  338. Borrow - Supplies the boorow value.
  339. Return Value:
  340. None.
  341. --*/
  342. {
  343. ULONG CarryFlag;
  344. ULONG Shift;
  345. union {
  346. UCHAR ResultByte;
  347. ULONG ResultLong;
  348. USHORT ResultWord;
  349. } u;
  350. u.ResultLong = 0;
  351. if (P->DataType == BYTE_DATA) {
  352. CarryFlag = (P->DstValue.Byte < (UCHAR)Borrow);
  353. u.ResultByte = P->DstValue.Byte - (UCHAR)Borrow;
  354. CarryFlag |= (u.ResultByte < P->SrcValue.Byte);
  355. u.ResultByte -= P->SrcValue.Byte;
  356. Shift = 7;
  357. } else if (P->DataType == LONG_DATA) {
  358. CarryFlag = (P->DstValue.Long < Borrow);
  359. u.ResultLong = P->DstValue.Long - Borrow;
  360. CarryFlag |= (u.ResultLong < P->SrcValue.Long);
  361. u.ResultLong -= P->SrcValue.Long;
  362. Shift = 31;
  363. } else {
  364. CarryFlag = (P->DstValue.Word < (USHORT)Borrow);
  365. u.ResultWord = P->DstValue.Word - (USHORT)Borrow;
  366. CarryFlag |= (u.ResultWord < P->SrcValue.Word);
  367. u.ResultWord -= P->SrcValue.Word;
  368. Shift = 15;
  369. }
  370. //
  371. // If the fucntion is not a compare or a compare and swap, then store
  372. // result.
  373. //
  374. if ((P->FunctionIndex != X86_CMP_OP) && (P->FunctionIndex != X86_CMPXCHG_OP)) {
  375. XmStoreResult(P, u.ResultLong);
  376. }
  377. //
  378. // If the function is not a decrement, then store the carry flag.
  379. //
  380. if (P->FunctionIndex != X86_DEC_OP) {
  381. P->Eflags.EFLAG_CF = CarryFlag;
  382. }
  383. //
  384. // Compute and store the parity and auxiliary carry flags.
  385. //
  386. P->Eflags.EFLAG_PF = XmComputeParity(u.ResultLong);
  387. P->Eflags.EFLAG_AF = ((P->DstValue.Byte & 0xf) -
  388. (P->SrcValue.Byte & 0xf) - Borrow) >> 4;
  389. //
  390. // If the function is not a compare and swap, then compute the zero flag.
  391. //
  392. if (P->FunctionIndex != X86_CMPXCHG_OP) {
  393. P->Eflags.EFLAG_ZF = (u.ResultLong == 0);
  394. }
  395. //
  396. // Compute and store the sign flag.
  397. //
  398. P->Eflags.EFLAG_SF = u.ResultLong >> Shift;
  399. //
  400. // The overflow flag is computed as the borrow from the sign bit
  401. // compared with the borrow into the sign bit.
  402. //
  403. P->Eflags.EFLAG_OF = (((P->SrcValue.Long ^ P->DstValue.Long) ^ u.ResultLong) >> Shift) ^ CarryFlag;
  404. return;
  405. }