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.

1411 lines
45 KiB

  1. page ,132
  2. subttl emexcept.asm - Microsoft exception handler
  3. ;***
  4. ;emexcept.asm - Microsoft exception handler
  5. ;
  6. ; Copyright (c) 1987-89, Microsoft Corporation
  7. ;
  8. ;Purpose:
  9. ; Microsoft exception handler
  10. ;
  11. ; This Module contains Proprietary Information of Microsoft
  12. ; Corporation and should be treated as Confidential.
  13. ;
  14. ;Revision History: (Also see emulator.hst.)
  15. ;
  16. ; 12-08-89 WAJ Add fld tbyte ptr [mem] denormal check.
  17. ;
  18. ;*******************************************************************************
  19. ;----------------------------------------------------------------------
  20. ; Structure for FSTENV and FLDENV, Store and Load 8087 Environment
  21. ;----------------------------------------------------------------------
  22. glb <ENV_ControlWord,ENV_StatusWord,ENV_TagWord,ENV_IP>
  23. glb <ENV_Opcode,ENV_OperandPointer,ENV_ControlMask>
  24. glb <ENV_CallOffset,ENV_CallSegment,ENV_CallFwait,ENV_Call8087Inst>
  25. glb <ENV_CallLongRet>
  26. ENV_DS EQU -4
  27. ENV_BX EQU -2
  28. ENV_ControlWord EQU 0
  29. ENV_StatusWord EQU 2
  30. ENV_TagWord EQU 4
  31. ENV_IP EQU 6
  32. ENV_Opcode EQU 8
  33. ENV_OperandPointer EQU 10
  34. ENV_ControlMask EQU 16
  35. ENV_Temp EQU 18 ; Note ENV_Temp occupies
  36. ENV_CallOffset EQU 18 ; the same space as ENV_Call*.
  37. ENV_CallSegment EQU 20 ; This is possible because there
  38. ENV_CallFwait EQU 22 ; is never simultaneous use of
  39. ENV_Call8087Inst EQU 23 ; this space
  40. ENV_CallLongRet EQU 25
  41. ENV_OldBP EQU 28
  42. ENV_OldAX EQU 30
  43. ENV_IRETadd EQU 32
  44. ENV_Size EQU 28
  45. ; UNDONE 386 version is bad - 387 environment is longer
  46. PAGE
  47. ;----------------------------------------------------------------------------
  48. ;
  49. ; 8087 EXCEPTION HANDLER - Fields 8087 stack over flow and under flow.
  50. ;
  51. ;----------------------------------------------------------------------------
  52. ;
  53. ; I. The 8087 state vector.
  54. ;
  55. ; Upon the execution of a FSAVE or FSTENV instruction the state of the
  56. ; 8087 is saved in a user defined state vector. The first seven words
  57. ; saved in the state vector by the two instructions are identical. The
  58. ; definition of the words is:
  59. ;
  60. ; Word. Bits. Bytes. Function.
  61. ; ----- ----- ------ ---------
  62. ; 0 15..0 1..0 Control word.
  63. ; 1 15..0 3..2 Status word. ( 8087 stack
  64. ; pointer and condition codes.
  65. ; 2 15..0 5..4 Tag word ( 8087 stack slot usage
  66. ; flags ).
  67. ; 3 15..0 7..6 Instruction pointer. Operator
  68. ; segment offset.
  69. ; 4 15..12 8 Operator paragraph bits ( (
  70. ; bits 16..19 ) of address ).
  71. ; 4 11 8 Always zero.
  72. ; 4 10..8 8 Upper opcode bits ( major opcode ).
  73. ; 4 7..0 9 Lower opcode bits ( minor opcode ).
  74. ; 5 15..0 11..10 Operand Segment offset.
  75. ; 6 15..12 12 Operand paragraph bits.
  76. ; 6 11..0 Not used. Must be zero.
  77. ;
  78. ; II. Restarting instructions.
  79. ;
  80. ; Of interest in this handler is the necessity of restarting
  81. ; 8087 instructions which fail because of 8087 stack overflow
  82. ; and underflow. Even though the 8087 saves enough information
  83. ; to restart an instruction, it is incapable of doing so. The
  84. ; instruction restart must be done in software.
  85. ;
  86. ; There are two cases which must be considered after the stack
  87. ; exception has been dealt with.
  88. ;
  89. ; 1. The faulting instruction deals with top of stack.
  90. ; 2. The faulting instruction deals with memory.
  91. ;
  92. ; The first case is handled by changing the upper five bits (
  93. ; 15..11 ) of vector word four ( 4 ) to "11011B". This changes
  94. ; word four into an "escape opcode" 8087 instruction. The
  95. ; modified opcode is placed in the interrupt code segment and
  96. ; executed.
  97. ;
  98. ; The second case is handled by changing the upper five bits
  99. ; ( 15..11 ) of vector word four ( 4 ) to "11011B", changing
  100. ; the MOD of the opcode to "00B" ( 0 displacement ), loading
  101. ; the operand address into DS:SI, and changing the RM field of
  102. ; the opcode to "100B" (SI+DISP addressing). The faulting
  103. ; instruction may be restarted as above.
  104. ;
  105. ; Instruction restart may also be accomplished by building an
  106. ; instruction stream in the interrupt stack and calling the
  107. ; instruction stream indirectly. This method is the preferred
  108. ; method because it is reentrant.
  109. ;
  110. ; III. Data Segment Considerations.
  111. ;
  112. ; DS is restored from the task interrupt vector. DS is used for
  113. ; stack overflow memory.
  114. ;
  115. ;
  116. ; Documentation of the invalid exception handling code for the stand-alone
  117. ; 8087/80287 emulator
  118. ;
  119. ; The emulator software is being enhanced for the cmerge 4.0 generation of
  120. ; languages to support a larger subset of the numeric processor instruction
  121. ; set. In addition to providing instructions which were not previously
  122. ; emulated, the model for representing the numeric processor stack is also
  123. ; being modified. The 4.0 languages and their predecessors are object compat-
  124. ; ible so it will be possible for programs to be developed which will contain
  125. ; code generated by the old model as well as the new model. For this reason
  126. ; it is important to understand the characteristics of both models and how
  127. ; the two models will interact.
  128. ;
  129. ; I. The Old Model: Infinite Stack
  130. ;
  131. ; The old model used an infinite stack model as the basis of its
  132. ; emulation of the numeric processor. Only the classical stack form of
  133. ; instructions with operands were emulated so only ST(0) (top of stack)
  134. ; and ST(1) (next to top of stack) were referenced by any given instruction.
  135. ; In addition, the stack was allowed to overflow beyond the eight registers
  136. ; available on the chip into a memory stack overflow area. The code genera-
  137. ; tor did not attempt to maintain all of its register data in the first eight
  138. ; register slots but instead made use of this overflow area. In order to
  139. ; maintain compatible behavior with or without the presence of the chip, this
  140. ; model made it necessary to handle and recover from stack overflow exceptions
  141. ; in the case where the chip is present as well as when it is being emulated.
  142. ;
  143. ; This stack overflow exception handling could in turn generate a recoverable
  144. ; stack underflow exception since a situation could arise where a desired
  145. ; operand had been pushed into the memory overflow area (during stack overflow)
  146. ; and was not available in the on-chip register area when needed. This
  147. ; scenario would signal an invalid exception due to stack underflow.
  148. ; It is recoverable because the required operand is still available in the
  149. ; overflow area and simply needs to be moved into a register on the chip.
  150. ;
  151. ; II. The New Model: Finite Stack
  152. ;
  153. ; The new model uses a finite stack model: only the eight registers on the
  154. ; chip are available for use, so in the new model the invalid exception
  155. ; would never be signalled due to stack overflow. In addition, it extends
  156. ; the emulated instruction set to include the general register form of
  157. ; instructions with operands (operands can be ST(i),ST or ST,ST(i)). Since
  158. ; the new code generator is aware of how many items it has placed on the stack,
  159. ; it does not allow stack overflow or stack underflow to occur. It can remove
  160. ; items from the registers either by storing to memory (FST or FSTP), or by
  161. ; using FFREE to mark the register as empty (this instruction is being added
  162. ; to the emulated instruction set). The new model uses FFREE in a well-defined
  163. ; manner: it will only free registers from the boundaries of the block of
  164. ; registers it is using. For example, if the new code is using ST(0)-ST(6),
  165. ; it must free the registers in the order ST(6),ST(5),ST(4),... and so on.
  166. ; It cannot create gaps of free registers within the block of registers
  167. ; it is using.
  168. ;
  169. ; III. The Hybrid Model: Combination of New and Old Code
  170. ;
  171. ; Due to the possibility of mixture of code generated using both of the above
  172. ; models, the new exception handling and emulation software has to be able to
  173. ; handle all situations which can arise as a result of the interaction of the
  174. ; two models. The following summarizes the behavior of the two models and
  175. ; restrictions placed on their interaction.
  176. ;
  177. ; New Code:
  178. ;
  179. ; 1. Cannot call anyone with any active entries on the stack.
  180. ; The new model is always at a conceptual stack level of zero
  181. ; when it makes external calls. Thus old code will never
  182. ; incorrectly make use of register data that was placed on the
  183. ; register stack by new code.
  184. ;
  185. ; 2. May create gaps of free registers in the register stack.
  186. ; It will not create gaps in the memory stack overflow area.
  187. ;
  188. ; 3. Only causes stack overflow by pushing old code entries off of
  189. ; the register stack and into the memory stack overflow area.
  190. ; It will never overflow its own entries into the memory stack
  191. ; overflow area.
  192. ;
  193. ; 4. Cannot cause stack underflow.
  194. ;
  195. ;
  196. ; Old Code:
  197. ;
  198. ; 1. Can only reference ST(0), ST(1).
  199. ;
  200. ; 2. Can cause stack overflow by pushing too many entries onto the
  201. ; register stack.
  202. ;
  203. ; 3. Can cause stack underflow in two situations:
  204. ;
  205. ; a. It is trying to get something that is in the memory stack
  206. ; overflow area (stack overflow occurred previously).
  207. ;
  208. ; b. There are free entries on the chip. This situation could
  209. ; arise if new code creates free entries then calls old code,
  210. ; so this is a situation that could not have existed before
  211. ; the new model was introduced.
  212. ;
  213. ; IV. Stack Overflow/Underflow Exception Handling
  214. ;
  215. ; The following algorithms will be used for detecting and recovering from
  216. ; stack overflow and underflow conditions (signalled via the invalid
  217. ; exception). All invalid exceptions are "before" exceptions so that
  218. ; the instruction has to be reexecuted once the exception has been handled.
  219. ;
  220. ; A. Stack Overflow
  221. ;
  222. ; If ST(7) is used (possible stack overflow) then {
  223. ; check for instructions which could cause stack overflow
  224. ; (includes FLD,FPTAN,...)
  225. ; if instruction could cause stack overflow then {
  226. ; save ST(7) in stack overflow area at [CURstk]
  227. ; mark ST(7) empty
  228. ; if FLD ST(7) instruction then
  229. ; FLD [CURstk] or rotate chip (clear exceptions)
  230. ; else reexecute the instruction with ST(7) empty
  231. ; }
  232. ; }
  233. ;
  234. ; B. Stack Underflow
  235. ;
  236. ; If ST(0) is free then assume stack underflow since the stack
  237. ; overflow case has already been handled (if the invalid
  238. ; is due to a denormal exception, the exception will occur
  239. ; again when the instruction is reexecuted):
  240. ;
  241. ; if chip has any registers in use (check the tag word) then {
  242. ; rotate chip until ST(0) is not empty
  243. ; rotate tag word to reflect state of chip
  244. ; }
  245. ; else (no registers in use)
  246. ; if operand is in stack overflow area then {
  247. ; load into ST(0) from stack overflow area
  248. ; mark ST(0) full
  249. ; }
  250. ; else {
  251. ; indicate true stack underflow
  252. ; go print error
  253. ; }
  254. ; if ST(1) is empty then {
  255. ; if any of ST(2) thru ST(7) are in use then {
  256. ; rotate chip until ST(1) is not empty
  257. ; (to share code with first chip rotation above:
  258. ; store pop st(0) into temp
  259. ; rotate chip until st(0) is not free
  260. ; load st(0) back onto chip)
  261. ; update tag word appropriately
  262. ; }
  263. ; else
  264. ; load ST(1) from overflow area if there
  265. ; }
  266. ;
  267. ; At this point, ST(0) and ST(1) have been filled if possible.
  268. ; Now we must categorize the instructions to determine which
  269. ; of these is required. Then we will either issue true stack
  270. ; underflow or reexecute the instruction with the compressed
  271. ; stack.
  272. ;----------------------------------------------------------------------------
  273. ;
  274. ; References:
  275. ; Intel 8086 Family Numerics Supplement. 121586-001 Rev A.
  276. ; Intel iAPX 86,88 User's Manual.
  277. ;
  278. ;----------------------------------------------------------------------------
  279. ;----------------------------------------------------------------------------
  280. ;
  281. ; All registers must be saved by __FPEXCEPTION87 except CS,IP,SS,SP.
  282. ;
  283. ;----------------------------------------------------------------------------
  284. ifdef WINDOWS
  285. ; stack consists of IRET frame and status word before FCLEX
  286. ;
  287. ; Since the environment is different in protect mode, reconstruct
  288. ; the opcode like in real mode.
  289. lab protiret
  290. iret
  291. lab protexskipsegovr
  292. inc bx ; bump past segment override
  293. jmp short protexsegovr ; try again
  294. public __FPEXCEPTION87P
  295. __FPEXCEPTION87P:
  296. lab protexception
  297. push eax ; save user ax
  298. push ebp
  299. sub esp,ENV_Size ; get Enough bytes for Environment
  300. mov ebp,esp ; set up for rational offsets.
  301. fstenv word ptr [ebp] ; save environment.
  302. mov eax,offset protiret ; set up for near return address
  303. xchg ax,[ebp+ENV_Size+4] ; swap status word and near ret addr
  304. mov ENV_StatusWord[ebp],ax ; save status word into environment
  305. push ebx
  306. push ds ; save a few more registers
  307. lds ebx,dword ptr ENV_IP[ebp] ; get address of instruction
  308. lab protexsegovr
  309. mov ax,[ebx] ; get 1st 2 bytes of instruction
  310. add al,28h ; add -(ESC 0)
  311. jnc protexskipsegovr ; wasn't ESC - skip seg. override
  312. xchg al,ah ; swap bytes to make real opcode
  313. mov ENV_Opcode[ebp],ax ; save it in environment
  314. sti
  315. jmp short exceptionhandler
  316. endif ;WINDOWS
  317. ifdef DOS5
  318. ; stack consists of IRET frame and status word before FCLEX
  319. ;
  320. ; Since the environment is different in protect mode, reconstruct
  321. ; the opcode like in real mode.
  322. lab protiret
  323. iret
  324. lab protexskipsegovr
  325. inc bx ; bump past segment override
  326. jmp short protexsegovr ; try again
  327. lab protexception
  328. push eax ; save user ax
  329. push ebp
  330. sub esp,ENV_Size ; get Enough bytes for Environment
  331. mov ebp,esp ; set up for rational offsets.
  332. fstenv word ptr [ebp] ; save environment.
  333. mov eax,offset protiret ; set up for near return address
  334. xchg ax,[ebp+ENV_Size+4] ; swap status word and near ret addr
  335. mov ENV_StatusWord[ebp],ax ; save status word into environment
  336. push ebx
  337. push ds ; save a few more registers
  338. lds ebx,dword ptr ENV_IP[ebp] ; get address of instruction
  339. lab protexsegovr
  340. mov ax,[ebx] ; get 1st 2 bytes of instruction
  341. add al,28h ; add -(ESC 0)
  342. jnc protexskipsegovr ; wasn't ESC - skip seg. override
  343. xchg al,ah ; swap bytes to make real opcode
  344. mov ENV_Opcode[ebp],ax ; save it in environment
  345. endif ;DOS5
  346. ifdef DOS3and5
  347. jmp short exceptionhandler
  348. endif ;DOS3and5
  349. ifdef DOS3
  350. public __FPEXCEPTION87
  351. __FPEXCEPTION87:
  352. PUSH AX ; Save user's AX next to IRET
  353. PUSH BP
  354. SUB SP,ENV_Size ; Get Enough bytes for Environment
  355. ; 8087 status.
  356. MOV BP,SP ; Set up for rational offsets.
  357. ;Caveat Programmer!
  358. ;FSTENV does an implicit set of all exception masks.
  359. FNSTENV WORD PTR [BP] ; Save environment.
  360. FCLEX ; Clear exceptions.
  361. STI ; Restore host interrupts.
  362. PUSH BX
  363. PUSH DS ; Need access to user data
  364. endif ;DOS3
  365. ;----------------------------------------------------------------------------
  366. ; In a multitasking environment one would not want to restore
  367. ; interrupts at this point. One would wait until the 8087 had been
  368. ; flushed and any operand data copied to a storage area.
  369. ;----------------------------------------------------------------------------
  370. ;---------------
  371. ; Inside of the while exception loop and Redo8087Instruction
  372. ; registers AX and BX must contain the values as described
  373. ; below:
  374. ; AL bit 0 = 1 indicates invalid exception
  375. ; bit 1 = 1 indicates denormal exception
  376. ; bit 2 = 1 indicates divide by zero exception
  377. ; bit 3 = 1 indicates numeric overflow
  378. ; bit 4 = 1 indicates numeric underflow
  379. ; bit 5 = 1 indicates precision loss
  380. ; bit 6 = unused by 8087
  381. ; bit 7 = 1 indicates sqrt of negative number
  382. ; (this flag is not from the NPX status word, but
  383. ; is set after all other exceptions have been
  384. ; handled if the opcode is FSQRT)
  385. ; AH bit 0 = unused
  386. ; bit 1 = 1 indicates stack overflow
  387. ; bit 2 = 1 indicates stack underflow
  388. ; bit 3 = unused
  389. ; bit 4 = unused
  390. ; bit 5 = 1 indicates memory operand
  391. ; bit 6 = 1 indicates instruction was reexcuted
  392. ; bit 7 = 1 indicates ST relative operand
  393. ; BL = The complement of the exception masks copied from
  394. ; UserControlWord altered so that Denormal and Invalid
  395. ; exceptions are always unmasked, while the reserved
  396. ; bits are masked.
  397. ; BH bit 0 = 1 indicates 8087 only invalid handling complete
  398. ; bit 1 = 1 indicates 8087 only denormal handling complete
  399. ; bit 2 = 1 indicates 8087 only divide by zero handling complete
  400. ; bit 3 = 1 indicates 8087 only numeric overflow handling complete
  401. ; bit 4 = 1 indicates 8087 only numeric underflow handling complete
  402. ; bit 5 = 1 indicates 8087 only precision loss handling complete
  403. ; bit 6 = unused
  404. ; bit 7 = unused
  405. ;
  406. ; Algorithm: Handle 8087 exceptions which do not occur in the
  407. ; emulator and then jump to the common exception handling code.
  408. ;
  409. ; To handle 8087 only exceptions we must first determine if the
  410. ; exception occured before the 8087 executed the instruction
  411. ; or afterward. Invalid, denormal (except FLD) and divide by
  412. ; zero exceptions all occur before 8087 instruction execution,
  413. ; others occur afterward. "Before" exceptions must set the
  414. ; "before" flag in AH and then reexecute the instruction. After
  415. ; reexecution (while all exceptions are masked) all of the
  416. ; exceptions resulting from the current 8087 instruction will
  417. ; be known and can be handled as a group. "After" exceptions
  418. ; are handled individually since reexecution of an already
  419. ; executed instruction will destroy the validity of the 8087 stack.
  420. ; A flag in AH is used by Redo8087instruction to avoid reexecuting
  421. ; an instruction twice. At the beginning of Redo8087instruction
  422. ; the flag is checked, and if it is set the instruction is not
  423. ; redone.
  424. ;
  425. ; "Before" exceptions must be reexecuted because it is
  426. ; difficult to determine stack over/underflow if reexecution
  427. ; is not performed. Stack over/underflow is signaled by
  428. ; an invalid exception. The current algorithm for stack over/
  429. ; underflow detection is as follows:
  430. ;
  431. ; ...
  432. ;
  433. ;---------------
  434. ProfBegin EXCEPT
  435. lab exceptionhandler
  436. ifdef MTHREAD
  437. LOADthreadDS ; macro in emthread.asm
  438. ; loads thread's DS; trashes AX
  439. else ;MTHREAD
  440. ifdef standalone
  441. XOR AX,AX ; Prepare to access vector, clear flags
  442. MOV DS,AX
  443. MOV DS,DS:[4*TSKINT+2] ; DS = emulator task data segment
  444. elseifdef _COM_
  445. mov ds, [__EmDataSeg]
  446. xor ax,ax
  447. else
  448. mov ax, edataBASE
  449. mov ds,ax
  450. xor ax,ax
  451. endif
  452. endif ;MTHREAD
  453. MOV AL,ENV_StatusWord[eBP] ; Get 8087 status flags.
  454. XOR BH,BH ; Clear out 8087 handling flags
  455. ;----------------------------------------------------------------------------
  456. ;
  457. ; Can the interrupt be serviced by this routine? Dispatch exceptional
  458. ; conditions.
  459. ;
  460. ; Multi-pass algorithm
  461. ; Handle exception and reexcute instruction if necessary
  462. ; Loop back to WhileException and handle additional exceptions
  463. ;
  464. ; AX = status before exception handling
  465. ; BX = flag indicating exception handled
  466. ;
  467. ;----------------------------------------------------------------------------
  468. cmp [ExtendStack], 0 ; check if the extended stack was
  469. jne WhileException ; turned off.
  470. or bh, Invalid
  471. lab WhileException
  472. ifndef _NOSTKEXCHLR ; no stack overflow/underflow handler
  473. TEST BH,Invalid ; stack over/underflow already handled?
  474. JNZ short NotOverUnderflow ; Yes - forget stack over/underflow
  475. TEST AL,Invalid ; Invalid exception?
  476. JZ short NotOverUnderflow ; No - bypass over/underflow checking
  477. OR BH,Invalid ; Indicate stack over/undeflow checked
  478. JMP ProcessOverUnderflow ; See about stack over/underflow
  479. endif ;_NOSTKEXCHLR
  480. lab NotOverUnderflow
  481. ; Either the exception was not an invalid or stack over/underflow has
  482. ; already been handled.
  483. ; check for denormal exception - completely resolved on pass 1
  484. TEST AL,Denormal ; Denormal exception?
  485. JZ short NotDenormal ; No - bypass denormal handling
  486. JMP ProcessDenormal ; Process the denormal
  487. lab NotDenormal
  488. ; check for zero divide exception
  489. TEST BH,ZeroDivide ; Divide by zero already handled?
  490. JNZ short NotZeroDivide ; Yes - bypass divide by zero handling
  491. TEST AL,ZeroDivide ; Divide by zero exception?
  492. JZ short NotZeroDivide ; No - bypass divide by zero handling
  493. OR BH,ZeroDivide ; Indicate divide by zero handled
  494. CALL ReDo8087Instruction ; Process divide by zero exception
  495. JMP WhileException
  496. lab NotZeroDivide
  497. ; check for numeric overflow exception
  498. TEST BH,Overflow ; Overflow already handled?
  499. JNZ short AllExceptionsHandled ; Yes - bypass overflow handling
  500. TEST AL,Overflow ; Overflow exception?
  501. JZ short AllExceptionsHandled ; No - bypass overflow handling
  502. OR BH,Overflow ; Indicate overflow handled
  503. JMP ProcessNumericOverflow ; Process numeric overflow
  504. lab AllExceptionsHandled
  505. ; We have already handled any exceptions which require instruction
  506. ; reexecution.
  507. ; At this point 8087 instruction reexecution is done. We need
  508. ; to extract a little more information for error message
  509. ; generation.
  510. MOV BL, BYTE PTR UserControlWord ; 8087 exception masks
  511. OR BL, 0C0H ; Mask reserved
  512. AND BL, 0FDH ; Unmask denormal. DON'T unmask invalid
  513. ; here. (Otherwiae user has no way of
  514. ; masking invalids.)
  515. NOT BL ; complement
  516. AND AL, BL ; eliminate all masked exceptions
  517. ; from AL
  518. TEST AL,Invalid ; Possibly square root of neg?
  519. JZ short NotFLDshortorlongNaN ; No - don't set square root flag
  520. PUSH AX ; ... Use AX as scratch ...
  521. MOV AX,ENV_Opcode[eBP] ; Get the instruction op code
  522. AND AH,7 ; Mask off the junk
  523. CMP AX,001FAh ; Square root op code?
  524. JNE short NotSquareRootError ; No - don't set square root flag
  525. POP AX ; ... Restore AX ...
  526. OR AL,SquareRootNeg ; Set the square root flag
  527. JMP short NotFLDshortorlongNaN
  528. ;-----------------------------------------------------------------------------
  529. ; Test for invalid exception caused by an FLD of a NaN underflow or overflow.
  530. ;-----------------------------------------------------------------------------
  531. lab NotSquareRootError ; Next check for FLD of a NaN
  532. ; (only happens for SNaNs on
  533. ; the 80387; not for 8087/287)
  534. MOV AX,ENV_Opcode[eBP]
  535. AND AX,0338h ; Mask off the inessential bits
  536. CMP AX,0100h ; Check for possible FLD
  537. ; of short/long real from memory.
  538. ; We are assuming that an invalid
  539. ; exception means FLD of a NaN
  540. ; since stack over/under-flow
  541. ; has already been dealt with.
  542. ; (we don't handle FLD ST(n) or
  543. ; FLD temp real in this way)
  544. POP AX ; ... Restore AX ...
  545. JNE short NotFLDshortorlongNaN
  546. ;
  547. ; (MOD==11 case: no special code)
  548. ; We don't handle FLD ST(n) here since it isn't properly
  549. ; handled in our stack overlow checking code either and
  550. ; it doesn't generate an invalid in the case of an SNaN
  551. ; without a stack overflow; FFREE ST(n) will not cause
  552. ; an Invalid exception.
  553. ;
  554. ; FLD TBYTE PTR ... shouldn't cause an Invalid due to a NaN
  555. ;
  556. XOR AL,Invalid ; Turn off invalid exception.
  557. ; There should be a NaN in ST(0);
  558. ; we will just leave it there.
  559. lab NotFLDshortorlongNaN
  560. FCLEX
  561. FLDCW ENV_ControlWord[eBP] ; Restore original Control Word
  562. lab CleanUpHost
  563. or [UserStatusWord],ax ; OR into user status word
  564. POP DS
  565. POP eBX
  566. ADD eSP,ENV_Size ; Point to users BP
  567. POP eBP
  568. TEST AX,0FFFFh-Reexecuted ; exceptions?
  569. JNZ Exceptions8087 ; Process other exceptions as emulator
  570. POP eAX ; Now just IRET address on stack
  571. ret ; return to OEM interrupt exit routine
  572. lab Exceptions8087
  573. ; toss OEM routine return address
  574. push eax
  575. push ebx
  576. mov ebx,esp
  577. ; UNDONE - this does not work for 386
  578. mov eax,ss:[ebx+4] ; get original AX
  579. mov ss:[ebx+6],eax ; overwrite OEM routine return address
  580. pop ebx
  581. pop eax
  582. ifdef i386
  583. add esp,4 ; remove original AX
  584. else
  585. add sp,2 ; remove original AX
  586. endif
  587. JMP CommonExceptions
  588. PAGE
  589. ;-----------------------------------------------------------------------------
  590. ; Test for stack underflow or overflow.
  591. ;-----------------------------------------------------------------------------
  592. ; There are eight sets of tag bits in the tag word. Each set
  593. ; denotes the state of one of the 8087 stack elements.
  594. ; 00 - normal
  595. ; 01 - true zero
  596. ; 10 - special: nan,infinity,unnormal
  597. ; 11 - empty
  598. ; If all are empty we have underflow, if all are full we have overflow
  599. ; There was an invalid exception: check to see if it was stack
  600. ; overflow or underflow.
  601. ; Register usage in this code block:
  602. ; BX = tag word, complemented
  603. ; CL = NPX stack ptr
  604. ifndef _NOSTKEXCHLR ; no stack overflow/underflow handler
  605. lab ProcessOverUnderflow
  606. PUSH eSI
  607. PUSH eBX ; Make room for local temps
  608. PUSH eCX
  609. PUSH eDX
  610. PUSH eDI
  611. MOV BX,ENV_TagWord[eBP] ; Get tag word.
  612. MOV CX,ENV_StatusWord[eBP] ; Get status word
  613. NOT BX ; Tag zero means empty, else full
  614. MOV CL,CH ; Get stack pointer into CL
  615. AND CL,038h ; Mask to stack pointer
  616. SHR CL,1
  617. SHR CL,1 ; compute number of bits to shift
  618. ROR BX,CL ; tag ST(0) in low BL.
  619. ; To service stack overflow we must make sure there is an empty space
  620. ; above the top of stack before the instruction is reexecuted. If
  621. ; after reexecution we again get an invalid exception, then we
  622. ; know there was something besides stack overflow causing the invalid
  623. ; exception.
  624. ; We check for stack overflow by seeing if ST(7) is empty. We make
  625. ; the check by testing the complemented, rotated tag word in BX.
  626. TEST BH,0C0h ; Possible stack overflow?
  627. JZ short StackUnderflowCheck ; No - bypass offloading stack
  628. ; ST(7) is not empty, so we may have stack overflow. We verify that
  629. ; we have stack overflow by looking at the instruction to be sure
  630. ; that it can generate stack overflow (i.e., it puts more stuff on
  631. ; the stack than it removes).
  632. ; Note that a subset of the 287 instruction set is being decoded
  633. ; here; only those instructions which can generate invalid exceptions
  634. ; get to this point in the code (see Table 2-14 in the Numeric
  635. ; Supplement for list of instructions and possible exceptions).
  636. ;
  637. ; The instructions which can generate stack overflow are:
  638. ; all memory FLDs,FILDs,FBLDs,constant instructions,
  639. ; FPTAN and FXTRACT
  640. MOV DX,ENV_Opcode[eBP] ; Get the instruction op code
  641. XOR DX,001E0h ; Toggle arith, mod and special bits
  642. ; Test for mod of 0,1, or 2 (indicates memory operand)
  643. TEST DL,0C0h ; Memory operand instruction?
  644. JNZ short MemoryFLDCheck ; Yes - go see what kind
  645. ; Test bits 5 & 8 of instruction opcode: of remaining instructions, only those
  646. ; with stack relative operands do NOT have both of these bits as 1 in the opcode
  647. ; (remember these bits are toggled).
  648. TEST DX,00120h ; ST Relative Op group?
  649. JNZ short StackUnderflowCheck ; Yes - ST Relative Ops
  650. ; cannot cause stack overflow
  651. ; Test bit 4 of the instruction opcode: of remaining instructions, only the
  652. ; transcendentals have this bit set.
  653. TEST DL,010h ; Constant or arith instruction?
  654. JNZ short TransCheck ; No - must be Transcendental
  655. ; Test bit 3 of the instruction opcode: of remaining instructions, only the
  656. ; constant instructions have this bit set.
  657. TEST DL,008h ; Constant instruction?
  658. JNZ short StackOverflowVerified ; Yes, can cause stack overflow
  659. ; The instructions which get to this point are FCHS, FABS, FTST and FXAM.
  660. ; None of these can cause stack overflow.
  661. JMP StackUnderflowCheck ; so go check for stack underflow
  662. lab TransCheck
  663. ; The instruction was a transcendental. Of the transcendentals, only
  664. ; FPTAN and FXTRACT can cause stack overflow, so check for these.
  665. CMP DL,012h ; is this FPTAN
  666. JE short StackOverflowVerified ; yes, can cause stack overflow
  667. CMP DL,014h ; is this FXTRACT
  668. JE short StackOverflowVerified ; yes, can cause stack overflow
  669. JMP StackUnderflowCheck ; not either one, won't cause overflow
  670. lab MemoryFLDCheck
  671. TEST DX,00110h ; FLD memory instruction?
  672. JNZ short StackUnderflowCheck ; no - go check for stack underflow
  673. lab StackOverflowVerified
  674. ; ST(7) was not empty and the instruction can cause stack overflow.
  675. ; To recover from stack overflow, move ST(7) contents to the
  676. ; stack extension area, modifying the tag word appropriately.
  677. AND BH,0FFh-0C0h ; Indicate 1st above TOS is free
  678. PUSHST ; Let PUSHST make room for value.
  679. FDECSTP ; Point to bottom stack element.
  680. FSTP TBYTE PTR [eSI] ; Store out bottom stack element.
  681. JMP InvalidReexecute ; No - reexecute instruction
  682. lab StackUnderflowCheck
  683. ; To service stack underflow we must make sure all the operands the
  684. ; instruction requires are placed on the stack before the instruction
  685. ; is reexecuted. If after reexecution we again get an invalid
  686. ; exception, then its due to something else.
  687. TEST BL,003h ; Is ST(0) empty?
  688. JZ short UFMemoryFLDcheck ; yes - first check for memory FLD
  689. JMP ST1EmptyCheck ; No - Let's try to fill ST(1), too.
  690. ; We may need it!
  691. ;
  692. ; This block of code is for making sure that FLD memory operand is not
  693. ; among those instructions where stack underflow could occur; this is
  694. ; so FLD of SNaN can be detected (under the AllExceptionsHandled
  695. ; section) for the case of the 80387.
  696. ;
  697. lab UFMemoryFLDcheck
  698. MOV DX,ENV_Opcode[eBP] ; Get the instruction opcode
  699. XOR DX,001E0h ; Toggle arith, mod and special bits
  700. TEST DL,0C0h ; Memory operand instruction?
  701. JZ ST0Empty ; No - continue underflow processing
  702. ; Try to fill ST(0)
  703. TEST DX,00110h ; FLD memory instruction?
  704. JNZ ST0Empty ; No - continue underflow processing
  705. ; Try to fill ST(0)
  706. JMP ST1EmptyCheck ; Let's try to fill ST(1), too.
  707. ; We may need it!
  708. ; Formerly we did JMP InvalidReexecute here; but this caused
  709. ; an "invalid" to be reported for instructions with two stack
  710. ; operands. (Doing JMP ST1EMptyCheck fixes this bug:
  711. ; Fortran 4.01 BCP #1767.)
  712. ;
  713. ; This fixes the underflow-handling case of instructions
  714. ; needing both ST0 and ST1 under the conditions that ST0
  715. ; is full but ST1 is empty.
  716. lab ST0Empty
  717. ; assume stack underflow since ST(0) is empty and we did not have
  718. ; stack overflow
  719. OR BX,BX ; Are any registers on the chip in
  720. ; use? (BX = 0 if not)
  721. JZ short LoadST0FromMemory ; No, load ST(0) from memory stack
  722. CALL RotateChip ; yes, then point ST(0) at first
  723. ; valid register and update tag in BX
  724. JMP ST1EmptyCheck ; go check if ST(1) is empty
  725. lab LoadST0FromMemory
  726. MOV eSI,[CURstk] ; Get pointer to memory stack
  727. CMP eSI,[BASstk] ; Anything in memory to load?
  728. JNE short LoadST0 ; Yes, go load it
  729. JMP TrueUnderflow ; No, go issue error
  730. lab LoadST0
  731. OR BL,003h ; Indicate ST(0) is full
  732. FINCSTP ; Avoid altering stack pointer.
  733. FLD TBYTE PTR [eSI] ; Load value from memory.
  734. POPST ; Let POPST decrement memory pointer.
  735. lab ST1EmptyCheck
  736. TEST BL,00Ch ; Is ST(1) empty?
  737. JNZ short EndST1EmptyCheck ; No - so don't load from memory
  738. MOV SI,BX ; move tag word to SI
  739. AND SI,0FFF0h ; mask off ST(0),ST(1)
  740. OR SI,SI ; Are any of ST(2)-ST(7) in use?
  741. ; (SI = 0 if not)
  742. JZ short LoadST1FromMemory ; No, try to get ST(1) from memory
  743. FSTP TBYTE PTR [REG8087ST0] ; offload ST(0) temporarily
  744. SHR BX,1
  745. SHR BX,1 ; ST(1) becomes ST(0) in tag word
  746. CALL RotateChip ; get 1st in-use register into ST(1)
  747. FLD TBYTE PTR [REG8087ST0] ; reload ST(0)
  748. SHL BX,1
  749. SHL BX,1 ; adjust tag word for reloaded ST(0)
  750. OR BL,003h ; Indicate ST(0) is full
  751. JMP SHORT EndST1EmptyCheck ; ST(0) and ST(1) are full
  752. lab LoadST1FromMemory
  753. MOV eSI,[CURstk] ; Get pointer to memory stack
  754. CMP eSI,[BASstk] ; Anything in memory to load?
  755. JE short EndST1EmptyCheck ; No, so don't load it.
  756. OR BL,00Ch ; Indicate ST(1) is full
  757. FINCSTP ; Point to ST(1)
  758. FINCSTP ; Point to ST(2)
  759. FLD TBYTE PTR [eSI] ; Load value from memory into ST(1).
  760. FDECSTP ; Point to ST(0)
  761. POPST ; Let POPST decrement memory pointer.
  762. lab EndST1EmptyCheck
  763. ; At this point we know that ST(0) is full. ST(1) may or may not be full
  764. ; and may or may not be needed.
  765. ; Now we look at the instruction opcode and begin categorizing instructions
  766. ; to determine whether they can cause stack underflow and if so, whether
  767. ; they require ST(0) only or ST(1) as well.
  768. MOV DX,ENV_Opcode[eBP] ; Get the instruction op code
  769. XOR DX,001E0h ; Toggle arith, mod, and special bits
  770. ; Test for mod of 0,1, or 2 (indicates memory operand)
  771. TEST DL,0C0h ; Memory operand instruction?
  772. JNZ short StackUnderflowServiced ; Yes, then stack underflow cannot
  773. ; be a problem since memory instructions
  774. ; require at most one stack operand
  775. ; and we know that ST(0) is full
  776. ; Test bits 5 & 8 of instruction opcode: of remaining instructions, only those
  777. ; with stack relative operands do NOT have both of these bits as 1 in the opcode
  778. ; (remember these bits are toggled).
  779. TEST DX,00120h ; ST Relative Op group?
  780. JNZ short STRelativeOpGroup ; Yes - ST Relative Ops
  781. lab ConstOrTrans
  782. ; Test bit 4 of the instruction opcode: of remaining instructions, only the
  783. ; transcendentals have this bit set.
  784. TEST DL,010h ; Constant or arith instruction?
  785. JNZ short TranscendentalInst ; No - must be Transcendental
  786. ; The instructions that get to here are the constant instructions and
  787. ; FCHS, FABS, FTST and FXAM. The constant instructions do not have any
  788. ; stack operands; the others require ST(0) which we know is valid.
  789. ; Therefore, none of the remaining instructions can cause stack underflow.
  790. lab StackUnderflowServiced
  791. JMP InvalidReexecute ; Stack underflow corrected
  792. ; reexecute instruction
  793. lab TranscendentalInst
  794. ; Transcendentals may require one or two stack elements as operands.
  795. ; Here we decide whether or not ST(1) needs to be present.
  796. MOV CL,DL ; Need low op code in CL
  797. AND CL,00Fh ; Mask to low four bits
  798. ; Read the next block of comments column-wise. It shows the transcendental
  799. ; instructions represented by each bit in the constant loaded into DX below.
  800. ; Note: as it turns out, of the instructions requiring two operands below,
  801. ; only FSCALE and FPREM generate invalid exceptions when the second operand
  802. ; is missing.
  803. ; FFFFFRFFFFFRFFRR
  804. ; 2YPPXEDIPYSERSEE
  805. ; XLTATSENRLQSNCSS
  806. ; M2ATRECCE2REDAEE
  807. ; 1XNAARSSMXTRILRR
  808. ; ...NCVTT.P.VNEVV
  809. ; ....TEPP.1.ET.EE
  810. ; .....D.....D..DD
  811. MOV DX,0101000011000100b ; 1's for 2 operand instructions
  812. SHL DX,CL ; Get corresponding bit into sign
  813. JNS short StackUnderflowServiced ; If just ST(0) needed we're O.K.
  814. TEST BL,00Ch ; ST(1) full?
  815. JNZ short StackUnderflowServiced ; Yes - stack underflow no problem
  816. lab STRelativeOpGroup
  817. ; The following code block handles the general operand ST(x) even though
  818. ; the original code generator only uses ST(0) and ST(1) as operands.
  819. ; The current code generator uses ST(x) but will never cause stack underflow
  820. ; exceptions.
  821. AND DX,00007h ; Mask to relative register number
  822. SHL DL,1 ; Compute tag word shift amount
  823. MOV CX,DX ; Get amount into CL
  824. MOV DX,BX ; Get tag into DX
  825. ROR DX,CL ; Shift operand tag into low DL
  826. TEST DL,003h ; Is operand register empty?
  827. JNZ short InvalidReexecute ; No - go reexecute
  828. ; The following conditions could cause a true underflow error to be
  829. ; erroneously generated at this point:
  830. ; FST ST(x) signals an invalid because ST(0) is empty. ST(0) gets filled
  831. ; by the stack underflow recovery code in this handler, but then
  832. ; the instruction is classified as an STRelative instruction and the
  833. ; above paragraph of code checks if ST(x) is empty. HOWEVER, FST ST(x) does
  834. ; not require ST(x) to be empty so a true underflow error should not occur.
  835. ; This code should be changed if this situation can ever occur.
  836. JMP TrueUnderflow ; true stack underflow
  837. ;*** RotateChip - rotate coprocessor registers
  838. ;
  839. ; ENTRY
  840. ; BX: tag word, complemented
  841. ; ST(0): empty
  842. ; at least one other register on the chip is non-empty
  843. ; (or else this routine will loop infinitely)
  844. ;
  845. ; RETURNS
  846. ; BX: updated tag word, complemented
  847. ; ST(0): non-empty
  848. ;
  849. ; DESCRIPTION
  850. ; This routine rotates the registers on the coprocessor
  851. ; until the first in-use register is in ST(0). This
  852. ; will correct a stack underflow exception which has been
  853. ; caused by old model code encountering a gap of free
  854. ; registers created by new model code. The complemented
  855. ; tag word is also updated appropriately.
  856. ;
  857. lab RotateChip
  858. ROR BX,1 ; Rotate tag word
  859. ROR BX,1
  860. FINCSTP ; Point to new ST(0)
  861. TEST BX,00003h ; Is this register empty?
  862. JZ short RotateChip ; No, go rotate again
  863. RET
  864. lab TrueUnderflow
  865. OR AH,StackUnderflow/256 ; indicate true stack underflow
  866. MOV BYTE PTR ENV_StatusWord[eBP],0 ; Clear exceptions
  867. FLDENV WORD PTR [eBP] ; Restore old environment.
  868. POP eDI
  869. POP eDX
  870. POP eCX
  871. POP eBX
  872. POP eSI
  873. JMP CleanUpHost ; Leave exception handler.
  874. lab InvalidReexecute
  875. AND AL,0FFH-Invalid ; Reset invalid flag.
  876. CALL ReDo8087Instruction ; Was invalid so redo instruction.
  877. POP eDI
  878. POP eDX
  879. POP eCX
  880. POP eBX
  881. POP eSI
  882. JMP WhileException
  883. endif ;_NOSTKEXCHLR
  884. ;----------------------------------------------------------------------------
  885. PAGE
  886. lab ProcessDenormal
  887. ; Correct 8087 bug. The FLD instruction signals a denormal
  888. ; exception AFTER it has completed. Reexecuting FLD for a
  889. ; denormal exception would thus mess up the 8087 stack. INTEL
  890. ; documentation states denormal exceptions are BEFORE
  891. ; exceptions, so there is a contradiction. To avoid reexecution
  892. ; of FLD we do as follows: And op code with 138H to mask out
  893. ; MOD, RM, ESC and memory format bits. Compare with 100H to
  894. ; distinguish FLD from other instructions which could possibly
  895. ; generate a denormal exception.
  896. or byte ptr [UserStatusWord],Denormal ; set denorm bit
  897. push ecx
  898. mov cx,ENV_Opcode[eBP] ; see if we have a reg,reg operation
  899. and cl, bMOD
  900. cmp cl, bMOD ; if MOD = 11b then we have a reg,reg op
  901. je notMemOpDenormal
  902. mov cx,ENV_Opcode[eBP]
  903. and cx, not (0fc00h or bMOD or bRM) ; remove escape, OpSizeBit, MOD and R/M
  904. cmp cx,0008h ; check for FMUL real-memory
  905. je short isMemOpDenormal
  906. cmp cx,0010h ; check for FCOM real-memory
  907. je short isMemOpDenormal
  908. and cl,30h ; clear low opcode bit
  909. cmp cx,0030h ; check for FDIV/FDIVR real-memory
  910. jne short notMemOpDenormal
  911. ; have FDIV/FDIVR real-memory
  912. ; have FMUL real-memory
  913. ; have FCOM real-memory
  914. ;
  915. ; do the following steps
  916. ; 1. free ST(7) if not free to avoid stack overflow
  917. ; 2. change instruction to FLD real-memory and redo
  918. ; 3. normalize TOS
  919. ; 4. change instruction to FMUL or FDIV[R]P ST(1),ST and redo
  920. lab isMemOpDenormal
  921. TEST BH,0C0h ; 1. Possible stack overflow?
  922. JZ short nostkovr ; No - bypass offloading stack
  923. AND BH,0FFh-0C0h ; Indicate 1st above TOS is free
  924. PUSHST ; Let PUSHST make room for value.
  925. FDECSTP ; Point to bottom stack element.
  926. FSTP TBYTE PTR [eSI] ; Store out bottom stack element.
  927. lab nostkovr
  928. mov cx,ENV_Opcode[ebp] ; 2. get original instruction
  929. push cx ; save it for later
  930. and cx,0400h
  931. add cx,0104h ; changed to FLD real DS:[SI]
  932. mov ENV_Opcode[ebp],cx ; change for redo
  933. call ReDoIt ; do FLD denormal
  934. call normalize ; 3. normalize TOS
  935. pop cx ; 4. restore original instruction
  936. and cx,0038h ; reduce to operation
  937. cmp cl,08h ; is it FMUL
  938. je short isFMUL ; yes
  939. cmp cl,10h ; is it FCOM
  940. je short isFCOM ; yes
  941. xor cl,08h ; must be FDIV[R] - flip R bit
  942. lab isFMUL
  943. or cx,06C1h ; or to FoprP ST(1),ST
  944. mov ENV_Opcode[ebp],cx ; change for redo
  945. call ReDo8087Instruction ; do FDIV[R]P ST(1),ST
  946. jmp short denormaldone ; done with FDIV[R] denormal
  947. lab notMemOpDenormal
  948. MOV cx,ENV_Opcode[eBP]
  949. and cx, 0738h
  950. cmp cx, 0328h
  951. je short noredo ; check for FLD long double
  952. AND cx,0138H
  953. CMP cx,0100H ; check for FLD float/double
  954. JZ short noredo
  955. CALL ReDo8087Instruction ; redo other instructions
  956. lab noredo
  957. call normalize
  958. jmp short denormaldone
  959. ; FCOM is a little more complicated to recover because of status
  960. ;
  961. ; FCOM is like FDIV in that the operands need to be exchanged
  962. ; and the value loaded onto the chip needs to be popped.
  963. ;
  964. ; This routine is like a mini ReDo8087Instruction
  965. lab isFCOM
  966. OR AH,Reexecuted/256 ; Flag instruction reexecuted
  967. FCLEX ; clear exceptions
  968. FXCH ; swap ST(0) and ST(1)
  969. FCOM ST(1) ; so that ST(1) is the "source"
  970. FXCH
  971. FSTP ST(0) ; toss stack entry
  972. FSTSW [NewStatusWord] ; get status word
  973. FWAIT
  974. OR AL,BYTE PTR [NewStatusWord] ; Include new with unhandled exceptions
  975. lab denormaldone
  976. pop ecx
  977. AND AL,0FFh-Denormal ; clear denormal exception
  978. jmp WhileException
  979. lab normalize
  980. fstp tbyte ptr ENV_Temp[ebp] ; save denormal/unnormal
  981. fwait
  982. mov cx,ENV_Temp[ebp+8] ; get old exponent
  983. test cx,07FFFh ; test for zero exponent
  984. jz short isdenormal ; denormal temp real
  985. test byte ptr ENV_Temp[ebp+7],80h ; test for unnormal
  986. jnz short isnormal ; no - skip normalization
  987. fild qword ptr ENV_Temp[ebp] ; load mantissa as integer*8
  988. fstp tbyte ptr ENV_Temp[ebp] ; save mantissa
  989. fwait
  990. cmp word ptr ENV_Temp[ebp+8],0 ; check for 0.0
  991. je short isdenormal ; yes - we had a pseudo-zero
  992. sub cx,403Eh ; exponent adjust (3fff+3f)
  993. add ENV_Temp[ebp+8],cx ; add to mantissa exponent
  994. lab isnormal
  995. fld tbyte ptr ENV_Temp[ebp] ; reload normalized number
  996. ret
  997. lab isdenormal
  998. xor cx,cx ; make it into a zero
  999. mov ENV_Temp[ebp],cx
  1000. mov ENV_Temp[ebp+2],cx
  1001. mov ENV_Temp[ebp+4],cx
  1002. mov ENV_Temp[ebp+6],cx
  1003. mov ENV_Temp[ebp+8],cx
  1004. jmp isnormal ; reload it as zero
  1005. PAGE
  1006. lab ProcessNumericOverflow
  1007. ; We must reexecute for numeric overflow only if the instruction
  1008. ; was an FST or FSTP. This is because only these instructions
  1009. ; signal the exception before the instruction is executed.
  1010. ; If we reexecute under other conditions the state of the 8087
  1011. ; will be destroyed. Only memory operand versions of FST and
  1012. ; FSTP can produce the Overflow exception, and of all the
  1013. ; non-arithmetic memory operand instructions, only FST and
  1014. ; FSTP produce overflow exceptions. Thus it is sufficient
  1015. ; to reexecute only in case of non-arithmetic memory operand
  1016. ; instructions. To check for these and the op code with 001C0H
  1017. ; to mask down to the arith and MOD fields, flip the arith
  1018. ; bit by xoring with 00100H and if the result is below 000C0H
  1019. ; then we have a non-arithmetic memory operand instruction.
  1020. PUSH eAX
  1021. MOV AX,ENV_Opcode[eBP]
  1022. AND AX,001C0H
  1023. XOR AH,001H
  1024. CMP AX,000C0H
  1025. POP eAX
  1026. JAE short NumericOverflowRet
  1027. CALL ReDo8087Instruction
  1028. lab NumericOverflowRet
  1029. JMP WhileException
  1030. PAGE
  1031. ;----------------------------------------------------------------------------
  1032. ; Reexecute aborted 8087 instruction, and include any exceptions in ENV [BP]
  1033. ;----------------------------------------------------------------------------
  1034. ifdef WINDOWS
  1035. lab ReDo8087InstructionRet
  1036. ret
  1037. endif
  1038. lab ReDo8087Instruction
  1039. TEST AH,Reexecuted/256 ; Already reexecuted?
  1040. JNZ short ReDo8087InstructionRet ; If so don't do it again
  1041. OR AH,Reexecuted/256 ; Flag instruction reexecuted
  1042. lab ReDoIt
  1043. PUSH DS
  1044. PUSH eDI
  1045. PUSH eSI
  1046. PUSH eCX
  1047. PUSH eBX
  1048. FCLEX ; clear error summary flags
  1049. ifdef WINDOWS
  1050. mov di, ss ; assume SS
  1051. mov bx, __WINFLAGS
  1052. test bx, WF_PMODE
  1053. jz SkipSSAlias
  1054. push es
  1055. ; push ax ; CHICAGO needs 32-bit register saves ...
  1056. ; push dx
  1057. push eax ; for CHICAGO
  1058. push ebx ; for CHICAGO
  1059. push ecx ; for CHICAGO
  1060. push edx ; for CHICAGO
  1061. push ebp ; for CHICAGO
  1062. push esi ; for CHICAGO
  1063. push edi ; for CHICAGO
  1064. push ss
  1065. call ALLOCDSTOCSALIAS
  1066. pop edi ; for CHICAGO
  1067. mov di, ax
  1068. ; pop dx ; CHICAGO needs 32-bit register restores
  1069. ; pop ax
  1070. pop esi ; for CHICAGO
  1071. pop ebp ; for CHICAGO
  1072. pop edx ; for CHICAGO
  1073. pop ecx ; for CHICAGO
  1074. pop ebx ; for CHICAGO
  1075. pop eax ; for CHICAGO
  1076. pop es
  1077. or di, di
  1078. jz ReExecuteRestoreRet
  1079. lab SkipSSAlias
  1080. else ;not WINDOWS
  1081. ifdef DOS3and5
  1082. mov di,ss ; assume SS
  1083. cmp [protmode],0 ; check if protect mode
  1084. je noSSalias ; no - don't get SS alias
  1085. endif ;DOS3and5
  1086. ifdef DOS5
  1087. ifdef SQL_EMMT
  1088. push ax
  1089. push ss ; The SQL server may have switched stacks
  1090. push ds ; so update SSalias.
  1091. mov ax,offset SSalias
  1092. push ax
  1093. os2call DOSCREATECSALIAS
  1094. pop ax
  1095. endif ;SQL_EMMT
  1096. mov di,[SSalias] ; Get segment alias to stack
  1097. endif ;DOS5
  1098. endif ;not WINDOWS
  1099. ifdef DOS3and5
  1100. lab noSSalias
  1101. endif ;DOS3and5
  1102. MOV CX,ENV_Opcode[eBP] ; Get aborted 8087 instruction.
  1103. MOV BX,CX ; Copy instruction.
  1104. AND CH,07H ; Clear upper 5 bits.
  1105. OR CH,0D8H ; "OR" in escape code.
  1106. AND BL,0C0H ; Mask to MOD field.
  1107. XOR BL,0C0H ; If MOD = "11" (no memory operand)
  1108. JZ short REEXECUTE ; then address mode modification code
  1109. ; must be bypassed.
  1110. AND CL,38H ; Clear MOD and RM fields,
  1111. OR CL,4H ; Turn on bits in MOD and RM fields
  1112. ; to force DS:[SI+0] addressing.
  1113. LDS SI,ENV_OperandPointer[eBP] ; DS:SI <-- operand address
  1114. lab REEXECUTE
  1115. XCHG CH,CL ; convert to non-byte swapped
  1116. ; code format
  1117. ;
  1118. ; Stack restart method. Restart instruction in interrupt stack
  1119. ; frame. Code is reentrant.
  1120. ;
  1121. ifdef WINDOWS
  1122. mov ENV_CallSegment[ebp],di ; Code segment alias to stack
  1123. elseifdef DOS5
  1124. mov ENV_CallSegment[ebp],di ; Code segment alias to stack
  1125. else
  1126. MOV ENV_CallSegment[eBP],SS ; Stack segment
  1127. endif
  1128. LEA eDI,ENV_CallFwait[eBP] ; Offset to code in stack.
  1129. MOV ENV_CallOffset[BP],eDI
  1130. MOV BYTE PTR ENV_CallFwait[eBP],09BH ; FWAIT.
  1131. MOV ENV_Call8087Inst[eBP],CX ; 8087 instruction.
  1132. MOV BYTE PTR ENV_CallLongRet[eBP],0CBH ; Intra segment return.
  1133. CALL DWORD PTR ENV_CallOffset[eBP] ; Reexecute instruction.
  1134. ifdef WINDOWS
  1135. mov bx, __WINFLAGS
  1136. test bx, WF_PMODE
  1137. jz ReExecuteRestoreRet
  1138. push es ; if in PMODE, free alias
  1139. ; push ax ; CHICAGO needs 32-bit register saves
  1140. ; push dx
  1141. push eax ; for CHICAGO
  1142. push ebx ; for CHICAGO
  1143. push ecx ; for CHICAGO
  1144. push edx ; for CHICAGO
  1145. push ebp ; for CHICAGO
  1146. push esi ; for CHICAGO
  1147. push edi ; for CHICAGO
  1148. push ENV_CallSegment[eBP]
  1149. call FREESELECTOR
  1150. ; pop dx ; CHICAGO needs 32-bit register restores
  1151. ; pop ax
  1152. pop edi ; for CHICAGO
  1153. pop esi ; for CHICAGO
  1154. pop ebp ; for CHICAGO
  1155. pop edx ; for CHICAGO
  1156. pop ecx ; for CHICAGO
  1157. pop ebx ; for CHICAGO
  1158. pop eax ; for CHICAGO
  1159. pop es
  1160. endif ;WINDOWS
  1161. lab ReExecuteRestoreRet
  1162. POP eBX
  1163. POP eCX
  1164. POP eSI
  1165. POP eDI
  1166. POP DS
  1167. ifdef SQL_EMMT
  1168. push ax ; free the ss alias because we always
  1169. push [SSalias] ; get a new one for the SQL_EMMT
  1170. os2call DOSFREESEG
  1171. pop ax
  1172. endif ;SQL_EMMT
  1173. FSTSW [NewStatusWord] ; 8/18/84 GFW need proper DS set
  1174. FWAIT
  1175. OR AL,BYTE PTR [NewStatusWord] ; Include new with unhandled exceptions
  1176. ifndef WINDOWS
  1177. lab ReDo8087InstructionRet
  1178. endif
  1179. RET
  1180. ProfEnd EXCEPT