;       SCCSID = @(#)store.asm	6.1 92/01/29
title   store.asm
page    55,132
;***************************************************************************
;
;                       S T O R E . M O D
;                       ==================
;
;       =============================================================
;               INTEL CORPORATION PROPRIETARY INFORMATION
;    This software  is  supplied  under  the  terms  of  a  license
;    agreement  or non-disclosure agreement  with Intel Corporation
;    and  may not be copied nor disclosed except in accordance with
;    the terms of that agreement.
;       ===============================================================
;
;       FUNCTION:
;               IMPLEMENTS 80387 STORE, FIX, AND STOREX INSTRUCTIONS.
;
;       PUBLIC PROCEDURES:
;               STORE   FIX16   FIX32   FIX64   MOVE_OP_TO_OP
;
;       INTERNAL PROCEDURES:
;               EXTENDED_STORE          BCD_STORE
;               SINGLE_REAL_STORE       DOUBLE_REAL_STORE
;               STORE_VALID             INT64_STORE
;               INT16_STORE             INT32_STORE
;
;************************************************************************
;
;...DECEMBER 12, 1986..
;
; 12-18-91 mth removed intel and unix ifdef's
;
;------------------------------------------------
                NAME    A?MSO
                .386P
                .XLIST
                INCLUDE E80387.INC
                include icmacros.inc
                .LIST


EMULATOR_DATA   segment dword public 'FAR_DATA'
        EXTRN   SR_MASKS:BYTE,SR_FLAGS:BYTE,SR_ERRORS:BYTE,SR_CONTROLS:BYTE
        EXTRN   SR_MEM_OFFSET:DWORD
EMULATOR_DATA    ends
                ASSUME DS:EMULATOR_DATA

createSeg EMULATOR_CODE, A?MED, dword, public, CODE, FLAT
defgrp FLAT, <A?MED>

EMULATOR_CODE    SEGMENT dword  public  'CODE'
                ASSUME CS:FLAT

;
        EXTRN   POP_FREE:NEAR, CLEAR_6W:NEAR, TEST_3W:NEAR, SUBADD:NEAR
        EXTRN   GRADUAL_UNDERFLOW:NEAR, RIGHT_SHIFT_FRAC2_CL:NEAR
        EXTRN   SPECIAL_ROUND_TEST:NEAR, DIRECTED_ROUND_TEST:NEAR
        EXTRN   RIGHT_SHIFT_RESULT_CL:NEAR, SET_UP_INDEFINITE:NEAR
        EXTRN   RIGHT_SHIFT_FRAC1_CL:NEAR, STICKY_RIGHT_SHIFT:NEAR
        EXTRN   LEFT_SHIFT_FRAC1_CL:NEAR, LEFT_SHIFT_RESULT_CL:NEAR
        EXTRN   PUT_OP1_RESULT:NEAR, DIVID:NEAR, ADDITION_NORMALIZE:NEAR
        EXTRN   ROUND:NEAR, GET_PRECISION:NEAR, GET_RND_CONTROL:NEAR
        EXTRN   STORE_PRECISION:NEAR, SET_I_ERROR:NEAR, I_MASKED?:NEAR
        EXTRN   SET_O_ERROR:NEAR, O_MASKED?:NEAR, SET_P_ERROR:NEAR
        EXTRN   SET_U_ERROR:NEAR, TEST_4W:NEAR, SUBTRACTION_NORMALIZE:NEAR
        EXTRN   P_ERROR?:NEAR, CLEAR_P_ERROR:NEAR, ADD_TO_FRAC:NEAR
        EXTRN   MOVE_CONSTANT:NEAR, SET_STK_U_ERROR:NEAR, NORM_DENORM:NEAR
;

        PUBLIC  STORE, FIX16, FIX32, FIX64, MOVE_OP_TO_OP

PAGE


STORE_ROUTINE   DD      A?MEDOFFSET SINGLE_REAL_STORE
                DD      A?MEDOFFSET DOUBLE_REAL_STORE
                DD      A?MEDOFFSET INT16_STORE
                DD      A?MEDOFFSET INT32_STORE
                DD      A?MEDOFFSET INT64_STORE
                DD      A?MEDOFFSET EXTENDED_STORE
                DD      A?MEDOFFSET INT16_STORE
                DD      A?MEDOFFSET INT16_STORE
                DD      A?MEDOFFSET BCD_STORE


;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                             STORE:
;
;      FUNCTION:
;               IMPLEMENTS ALL STORE INSTRUCTIONS .
;
;      INPUTS:
;               OPERAND1; FORMAT OF RESULT.
;
;      OUTPUTS:
;               OPERAND IN "RESULT_FORMAT" STORED IN MEMORY
;               DESTINATION POINTED TO BY ES:DI.
;
;      DATA ACCESSED:
;                     - RESULT_REC_OFFSET     RESULT_FORMAT
;                     - OFFSET_OPERAND1
;
;      DATA CHANGED:
;                     - RESULT RECORD
;
;      PROCEDURES CALLED:
;
;               SET_UP_INDEFINITE       STORE ROUTINE [RESULT FORMAT]
;               I_MASKED?
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
STORE           PROC

        JZ      NO_UNMASKED_STACK_ERROR         ; BRANCH IF NO STACK ERROR

        CALL    SET_STK_U_ERROR                 ; STACK UNDERFLOW OCCURRED
        TEST    SR_MASKS,INVALID_MASK           ; IF UNMASKED,JUST EXIT
        JZ      RETURN                          ; ELSE,STORE INDEF SET UP

NO_UNMASKED_STACK_ERROR:                        ; IN OPERAND1 BY FETCH_AN_OP

        AND     SR_FLAGS,NOT A_MASK             ; CLEAR A-BIT
GET_RESULT_LOC:
        CMP     [EBP].RESULT_LOCATION,REG
        JNE     STORE_TO_MEMORY                 ; BRANCH IF MEMOP

        CALL    PUT_OP1_RESULT                  ; GIVE OPND1 AS RESULT
        JMP     POP_FREE

STORE_TO_MEMORY:
        MOVZX   EBX,BYTE PTR [EBP].RESULT_FORMAT ; CALL A DIFFERENT RTN
        SHL     EBX,2                           ; FOR EACH OF THE
        CMP     EBX,8
        JGE     GO_TO_STORER                    ; DO STORE OF TEMPORARY REAL

        CMP     [EBP].TAG1,UNSUPP               ; DETECT UNSUPPORTED PATTERN
        JNE     GO_TO_STORER

        OR      SR_ERRORS,INVALID_MASK          ; SET I_ERROR
        TEST    SR_MASKS,INVALID_MASK           ; IF UNMASKED,JUST EXIT
        JZ      RETURN                          ; ELSE,SET UP INDEF IN

        MOV     EDI,OFFSET_OPERAND1             ; OPERAND1.
        CALL    SET_UP_INDEFINITE

GO_TO_STORER:

        JMP     CS:STORE_ROUTINE[EBX]              ; OUTPUT FORMATS

STORE           ENDP

PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                           MOVE_OP_TO_OP:
;
;   FUNCTION:
;            MOVES OPERAND RECORD (OP1,OP2,RESULT_OP,RESULT2_OP) TO
;            ANOTHER OP.
;
;   INPUTS:
;           SS:ESI POINTS TO THE SOURCE,AND
;           SS:EDI POINTS TO THE DESTINATION
;   OUTPUTS:
;           OPERAND RECORD IN DESTINATION
;
;   DATA ACCESSED:
;                 OPERAND OR RESULT VARIABLES
;
;   DATA CHANGED:
;                 OPERAND OR RESULT VARIABLES
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
MOVE_OP_TO_OP   PROC

        PUSH    DS      ; SAVE A?MSR

        PUSH    SS
        POP     DS
        PUSH    SS
        POP     ES
        MOV     ECX,(OFFSET SIGN2 - OFFSET SIGN1)/4 ; SET RECORD LENGTH
        REP     MOVSD

        POP     DS      ; RELOAD A?MSR
RETURN:
        RET

MOVE_OP_TO_OP   ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                               EXTENDED_STORE:
;
;  FUNCTION:
;            STORES INTO DOUBLE EXTENDED FORMAT.
;
;  INPUTS:
;          OPERAND1
;
;  OUTPUTS:
;          DOUBLE EXTENDED OPERAND IN MEMORY.
;          STACK POPPED IF INDICATED
;
;  DATA ACCESSED:
;                 - MEM_OPERAND_POINTER    SIGN1
;                 - EXPON1                 WORD_FRAC1
;
;  DATA CHANGED:
;
;  PROCEDURES CALLED:
;                     POP_FREE
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
EXTENDED_STORE  PROC

        LES     EDI,FWORD PTR [EBP].MEM_OPERAND_POINTER ;MOVE FRAC TO MEMORY

        PUSH    DS                      ; SAVE A?MSR
        PUSH    SS
        POP     DS                      ; SET UP SOURCE POINTER
        LEA     ESI,WORD_FRAC1 + 2
        MOV     ECX,0002H
        REP     MOVSD
        POP     DS                      ; RELOAD A?MSR
        MOV     AH,[EBP].SIGN1          ; MERGE SIGN & EXPONENT
        AND     AX,8000H                ; AND MOVE TO MEMORY
        OR      AX,[EBP].EXPON1
        MOV     ES:[EDI],AX
        JMP     POP_FREE                ; POP STACK,IF NEEDED

EXTENDED_STORE  ENDP

PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                               BCD_STORE:
;
;  FUNCTION:
;       STORES INTO BCD FORMAT
;
;  INPUTS:
;       OPERAND1
;
;  OUTPUTS:
;       BCD OPERAND IN MEMORY; STACK POPPED
;
;  DATA ACCESSED:
;       - MEM_OPERAND_POINTER           OPERATION_TYPE
;       - OFFSET_OPERAND1       SIGN1
;       - TAG1          WORD_FRAC1
;       - MSB_FRAC1     OFFSET_OPERAND1
;       - OFFSET_OPERAND2       SIGN2
;       - EXPON2        WORD_FRAC2
;       - OFFSET_OPERAND2       OFFSET_RESULT
;       - RESULT_EXPON          RESULT_WORD_FRAC
;       - MSB_RESULT            OFFSET_RESULT
;
;  DATA CHANGED:
;       - OPERATION_TYPE        WORD_FRAC1
;       - MSB_FRAC1     SIGN2
;       - EXPON2        WORD_FRAC2
;       - RESULT_WORD_FRAC      MSB_RESULT
;
;  PROCEDURES CALLED:
;       MOVE_OP_TO_OP           RIGHT_SHIFT_FRAC1_CL
;       RIGHT_SHIFT_FRAC2_CL    RIGHT_SHIFT_RESULT_CL
;       LEFT_SHIFT_FRAC1_CL     LEFT_SHIFT_RESULT_CL
;       DIVID                   CLEAR_6W
;       POP_FREE                TEST_4W
;       ADD_TO_FRAC             MOVE_CONSTANT
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
TEN_18  DW      0000H,0000H,0000H,7640H,6B3AH,0DE0BH    ; FRAC FOR 10**18

BCD_STORE       PROC

        PUSH    DWORD PTR SR_MASKS      ; SAVE CURRENT PRECISION
        OR      SR_CONTROLS,PREC64      ; AND SET TO 64-BIT
        CMP     [EBP].TAG1,SPECIAL      ; SEPARATE BCD CASES
        JNE     FINITE_VALUE?

        JMP     STORE_SIGNED_BCD

FINITE_VALUE?:
        CMP     DWORD_EXPON1,07FFFH     ; IS IT A FINITE NUMBER?
        JNE     CHECK_BCD_DENORM        ; YES,BRANCH TO VALID

INVALID_BCD:
        OR      SR_ERRORS,INVALID_MASK  ; SET I_ERROR
        TEST    SR_MASKS,INVALID_MASK   ; IS I_ERROR UNMASKED?
        JNZ     STORE_BCD_INDEF

        JMP     BCD_STORE_DONE          ; NO,SO EXIT AT ONCE

STORE_BCD_INDEF:                        ; YES,STORE BCD_INDEF
        MOV     [EBP].DWORD_FRAC1 + FRAC80,0     ; CLEAR LOW FRAC
        MOV     [EBP].DWORD_FRAC1 + 6,080000000H ; SET ONLY MS BIT OF HI FRAC
        MOV     WORD_FRAC1 + 8,0FFFFH   ; SET MSW TO ALL ONES,
        JMP     STORE_BCD_RESULT        ; AND GIVE AS ANSWER

CHECK_BCD_DENORM:
        CMP     [EBP].TAG1,DENORMD      ; SEPARATE BCD CASES
        JNE     ROUND_TO_INT

        MOV     DWORD_EXPON1,0001H      ; IF MASKED D-ERROR,MAKE VALID
        MOV     [EBP].TAG1,VALID

ROUND_TO_INT:
        MOV     EAX,403EH
        CMP     DWORD_EXPON1,EAX        ; IF EXPON >= 63,THEN NUMBER
        JGE     INVALID_BCD             ; IS ALREADY TOO BIG FOR BCD

        MOV     EDI,OFFSET_OPERAND1     ; GRADUAL UFLOW UNTIL EXPON=63
        PUSH    EDI
        CALL    GRADUAL_UNDERFLOW
        POP     EDI                     ; ROUND TO PRECISION 64
        MOV     DL,PREC64
        MOV     AL,FALSE
        CALL    ROUND
DETECT_ZERO:
        XOR     EAX,EAX
        MOV     EDI,OFFSET DWORD_FRAC1 + 4  ; IF FRACTION = 0,RESULT = 0
        CALL    TEST_4W
        JNZ     BELOW_10_TO_18?

        MOV     DWORD_EXPON1,EAX        ; SET RESULT TO TRUE ZERO
        MOV     [EBP].TAG1,SPECIAL
        JMP     STORE_BCD_ROUND_DATA

BELOW_10_TO_18?:
        MOV     EDX,DWORD PTR [EBP + EDI + 4]
        CMP     EDX,0DE0B6B3H
        JA      INVALID_BCD

        MOV     EAX,DWORD PTR [EBP + EDI]
        JB      DIVIDE_BY_10_TO_9

        CMP     EAX,0A7640000H
        JAE     INVALID_BCD

DIVIDE_BY_10_TO_9:

        MOV     DWORD PTR [EBP + EDI + 4],0   ; CLEAR HIGH DWORD OF FRAC1

        MOV     DWORD PTR [EBP + EDI],0 ; CLEAR  LOW DWORD OF 8 BYTE FRAC1
        SUB     EDI,2                   ; MAKE EDI POINT TO 10 BYTE FRAC1
        MOV     EBX,3B9ACA00H           ; TEN TO THE 9TH,AS HEX ORDINAL
        DIV     EBX
        PUSH    EAX                     ; SAVE QUOTIENT
        MOV     ECX,4
        MOV     EBX,100

NEXT_PAIR_NIBBLES:
        MOV     EAX,EDX
        XOR     EDX,EDX
        DIV     EBX
        XCHG    EAX,EDX
        AAM
SECOND_HALF_LOOP_START:
        SHL     AH,4
        OR      AL,AH
        MOV     BYTE PTR [EBP + EDI],AL
        INC     EDI
        LOOP    NEXT_PAIR_NIBBLES

DO_SECOND_HALF?:
        POP     EAX
        OR      EAX,EAX                 ; IS EAX 0?
        MOV     BYTE PTR [EBP + EDI],DL
        JZ      STORE_BCD_ROUND_DATA

        PUSH    EDX
        XOR     EDX,EDX
        MOV     ECX,10
        DIV     ECX
        XCHG    EAX,EDX
        POP     ECX
        MOV     AH,AL
        MOV     AL,CL
        PUSH    0
        MOV     ECX,5
        JMP     SHORT   SECOND_HALF_LOOP_START

STORE_BCD_ROUND_DATA:
        CMP     RND1_INEXACT,TRUE
        JNE     STORE_SIGNED_BCD

        OR      SR_ERRORS,INEXACT_MASK
        CMP     ADDED_ONE,TRUE
        JNE     STORE_SIGNED_BCD

        OR      SR_FLAGS,A_MASK
STORE_SIGNED_BCD:
        MOV     AH,[EBP].SIGN1          ; SET SIGN IN BCD NUMBER
        AND     AH,080H
        MOV     MSB_FRAC1,AH

STORE_BCD_RESULT:
        LES     EDI,FWORD PTR SR_MEM_OFFSET     ;MOVE FRAC1 TO MEMORY
        PUSH    DS                              ; SAVE A?MSR
        PUSH    SS
        POP     DS
        LEA     ESI,WORD_FRAC1
        MOV     ECX,5
        REP     MOVSW
        POP     DS                      ; RELOAD A?MSR
        CALL    POP_FREE
BCD_STORE_DONE:
        POP     DWORD PTR SR_MASKS      ; RESTORE OLD SETTING
        RET

BCD_STORE       ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                          SINGLE_REAL_STORE:
;
;  FUNCTION:
;       IMPLEMENTS STORE TO SINGLE-PRECISION REAL FORMAT
;
;  INPUTS:
;       OPERAND1
;
;  OUTPUTS:
;       SINGLE_PRECISION REAL IN MEMORY;
;       STACK POPPED IF INDICATED.
;
;  DATA ACCESSED:
;       - MEM_OPERAND_POINTER           OFFSET_OPERAND1
;       - SIGN1         TAG1
;       - EXPON1        WORD_FRAC
;       - MSB_FRAC1
;
;  DATA CHANGED:
;
;  PROCEDURES CALLED:
;       ROUND                   STORE_VALID
;       ADDITION_NORMALIZED     SPECIAL_ROUND_TEST
;       DIRECTED_ROUND_TEST     GRADUAL_UNDERFLOW
;       POP_FREE                TEST_3W
;       U_MASKED?               SET_O_ERROR
;       O_MASKED?               SET_P_ERROR
;       SET_U_ERROR             SET_I_MASKED?
;       STORE_DENORMD
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
SINGLE_REAL_STORE       PROC

        PUSH    OFFSET CS:POP_FREE         ; RETURN TO POP_FREE

        LES     EDI,FWORD PTR [EBP].MEM_OPERAND_POINTER ;SET ES:DI TO MEMOP

        MOV     ESI,LOW_EXTENDED_EXPON_FOR_SINGLE

        MOV     DL,PREC24               ; 24-BIT PRECISION
        MOV     AL,[EBP].TAG1           ; LOAD OP1 TAG
        CMP     AL,VALID
        JE      SINGLE_VALID            ; DETECT VALID,INFINITY,

        CMP     AL,DENORMD              ; DENORMD,INVALID,AND
        JE      SINGLE_DENORMD          ; SPECIAL CASES

        CMP     AL,INV                  ; CHECK WHETHER OP1 IS NAN
        JNE     SINGLE_SPECIAL          ; BRANCH UNLESS OP1 IS NAN

        TEST    MSB_FRAC1,40H           ; CHECK WHETHER NAN IS QUIET
        JNZ     SINGLE_SPECIAL          ; BRANCH IF NAN IS QUIET

        OR      SR_ERRORS,INVALID_MASK  ; SET I_ERROR FOR SNAN
        TEST    SR_MASKS,INVALID_MASK   ; IF UNMASKED,JUST EXIT
        JZ      SPECIAL_RETURN          ; ELSE,CHANGE TO QNAN

        OR      MSB_FRAC1,40H
SINGLE_SPECIAL:
        MOV     ECX,DWORD PTR [EBP].DWORD_FRAC1 + FRAC32 + 1
        AND     ECX,807FFFFFH
        MOVZX   EAX,BYTE PTR [EBP].EXPON1
        SHL     EAX,23
        OR      EAX,ECX
        MOV     ES:[EDI],EAX

SPECIAL_RETURN:

        RET

SINGLE_DENORMD:
        MOV     EDI,OFFSET_OPERAND1     ; OP1 IS DENORMAL OR PSEUDO-DENORMAL
        CALL    NORM_DENORM             ; DON'T SET D_ERROR; JUST NORMALIZE
SINGLE_VALID:
        MOV     EDI,HIGH_EXTENDED_EXPON_FOR_SINGLE      ; LOAD PARAMETER
        CALL    STORE_VALID
        LES     EDI,FWORD PTR [EBP].MEM_OPERAND_POINTER  ; ES:EDI --> MEMOP

        JZ      SINGLE_INFINITY         ; ZF = 1 => STORE INFINITY
        JS      SINGLE_MAX              ; SF = 1 => STORE MAX

SINGLE_STORE:
        MOV     EAX,DWORD PTR [EBP].DWORD_FRAC1 + FRAC32 + 1
        AND     EAX,80FFFFFFH
        TEST    EAX,00FFFFFFH
        JZ      SINGLE_STORE_IT

        AND     EAX,807FFFFFH
        MOVZX   ECX,BYTE PTR [EBP].EXPON1
        ADD     CL,80H
        SHL     ECX,23
        OR      EAX,ECX
SINGLE_STORE_IT:
        MOV     ES:[EDI],EAX
        RET                             ;DO NEEDED POP OR FREE

SINGLE_MAX:
        MOV     EAX,7FFFFF7FH
        JMP     SHORT   SINGLE_SIGN_ON

SINGLE_INFINITY:
        MOV     EAX,8000007FH
SINGLE_SIGN_ON:
        OR      AL,[EBP].SIGN1
        ROR     EAX,8
        JMP     SHORT   SINGLE_STORE_IT

STORE_VALID:
        PUSH    EDI                     ; STACK HIGH_EXPON
        PUSH    ESI                     ; STACK LOW_EXPON
        PUSH    EDX                     ; STACK PREC CONTROL
        MOV     AL,FALSE                ; NOT SECOND ROUNDING
        MOV     EDI,OFFSET_OPERAND1     ; ROUND TO PREC (DL)
        CALL    ROUND
        CALL    ADDITION_NORMALIZE      ; AND RENORMALIZE
        POP     EDX                     ; UNSTACK PREC CONTROL
        POP     ESI                     ; UNSTACK LOW_EXPON
        POP     EDI                     ; UNSTACK HIGH_EXPON
        CMP     DWORD_EXPON1,ESI        ; IS UNDERFLOW POSSIBLE?
        JL      STORE_UNDERFLOW?        ; < LOW_EXPON,SO UNDERFLOW POSSIBLE

        JE      DECREMENT_EXPONENT      ; NO,= LOW_EXPON?

        CMP     DWORD_EXPON1,EDI        ; NO,> HIGH_EXPON?
        JLE     DO_STORE_VALID          ; NO,STORE NUMBER

        OR      SR_ERRORS,OVERFLOW_MASK ; SET O_ERROR
        TEST    SR_MASKS,OVERFLOW_MASK  ; IF UNMASKED,VIOLATE IEEE STANDARD
        JNZ     MASKED_OVERFLOW         ; AND ABORT WITHOUT ROUNDING SOURCE

POP_TWICE_ABORT:
        POP     EAX
        POP     EAX
        RET
;
; THE COMMENTIZED INSTRUCTIONS IMMEDIATELY FOLLOWING ARE APPROPRIATE FOR
; UNMASKED OVER/UNDERFLOW RESPONSE IN ACCORD WITH THE IEEE STANDARD.  ON THE
; 80387,UNMASKED OVER/UNDERFLOWS ON CONVERSION LEAVE FOR THE TRAP HANDLER THE
; SOURCE OPERAND,UNMODIFIED BY ROUNDING,EXPONENT REBIASING,OR ANYTHING ELSE.
; THEREFORE,TO REPORT THAT PRELIMINARY ROUNDING WAS INEXACT OR ACHIEVED BY
; INCREASING THE SOURCE SEEMS INCONSISTENT WITH THE 80387'S PHILOSOPHY
; OF ENTERING AN OVER/UNDERFLOW TRAP HANDLER WITH THE 80387'S STATE CHANGED
; ONLY INSOFAR AS THE OVER/UNDERFLOW FLAG HAS BEEN SET,SO SKIP THAT REPORT.
;
;UNMASKED_OV_UNDERFLOW:
;       CMP     RND1_INEXACT,TRUE       ; DETECT INEXACT RESULT
;       JNE     MOVE_OP1_TO_87_TOS      ; IF EXACT,BRANCH TO REPLACE SOURCE
;       OR      SR_ERRORS,INEXACT_MASK  ; ELSE,SET I_ERROR
;       CMP     ADDED_ONE,TRUE          ; WAS ROUNDING DONE BY ADDING ONE?
;       JNE     MOVE_OP1_TO_87_TOS      ; IF NOT,BRANCH TO REPLACE SOURCE
;       OR      SR_FLAGS,A_MASK         ; ELSE,SET A_BIT
;MOVE_OP1_TO_87_TOS:
;       MOV     [EBP].RESULT_LOCATION,STACK_TOP
;       POP     EDI                     ; DISCARD CALLER'S RETURN ADDRESS
;       POP     EDI                     ; DISCARD POP_FREE ADDRESS
;       JMP     PUT_OP1_RESULT
;-----------------------------------------------------------------------
MASKED_OVERFLOW:
        OR      SR_ERRORS,INEXACT_MASK  ; SET INEXACT_ERROR
        MOV     AL,SR_CONTROLS          ; load control byte
        AND     AL,RND_CONTROL_MASK     ; mask in rounding control
        MOV     AH,RND_UP
        CMP     AH,AL
        JS      STORE_VALID_DONE        ; BRANCH IF ZF = 0 & SF = 1

        MOV     AL,[EBP].SIGN1          ; GET SIGN OF OP1
        CALL    SPECIAL_ROUND_TEST      ; AFTER ROUND TEST,CF=0
        PUSHFD                          ;  (ZF=0 SF=1)/(ZF=1 SF=0)
        JS      POP_STORE_VALID_DONE    ; SF = 1 => STORE MAX

        OR      SR_FLAGS,A_MASK         ; SET A_BIT

POP_STORE_VALID_DONE:
        POPFD                           ; RELOAD FLAGS

STORE_VALID_DONE:
        RET                             ; EXIT

STORE_UNDERFLOW?:
        TEST    SR_MASKS,UNDERFLOW_MASK   ; IF UNDERFLOW MASKED,
        JNZ     CHECK_MASKED_UNDERFLOW    ; THEN BRANCH TO CHECK FOR INEXACT
        OR      SR_ERRORS,UNDERFLOW_MASK  ; ELSE,SET U_ERROR
;
; AFTER THE UNDERFLOW EXCEPTION HAS BEEN SET,THE RESPONSE TO UNMASKED
; UNDERFLOW OUGHT TO BE THE SAME AS THAT TO UNMASKED OVERFLOW.
;       JMP     SHORT   UNMASKED_OV_UNDERFLOW
;

        JMP     SHORT   POP_TWICE_ABORT ; AND ABORT WITHOUT ROUNDING SOURCE

CHECK_MASKED_UNDERFLOW:
        MOV     EDI,OFFSET_OPERAND1     ; LOAD OP1 OFFSET
        MOV     EAX,ESI                 ; LOAD LOW EXPONENT
        PUSH    EDI                     ; SAVE OP1 OFFSET
        PUSH    EDX                     ; SAVE PREC CONTROL
        CALL    GRADUAL_UNDERFLOW       ; DO GRADUAL UNDERFLOW
        POP     EDX                     ; RELOAD PREC CONTROL
        POP     EDI                     ; RELOAD OP1 OFFSET
        MOV     AL,TRUE                 ; PERFORM SECOND ROUND
        CALL    ROUND
        CMP     RND_HISTORY,0           ; SIGNAL_U_ERROR?
        JE      DECREMENT_EXPONENT

        OR      SR_ERRORS,UNDERFLOW_MASK + INEXACT_MASK
DECREMENT_EXPONENT:
        TEST    MSB_FRAC1,80H           ; TEST MSB OF FRACTION
        JNZ     DO_STORE_VALID          ; DON'T DECREMENT IF 800..0H

        DEC     [EBP].EXPON1            ; ELSE,DECREMENT EXPON
DO_STORE_VALID:
        CMP     RND_HISTORY,0           ; SIGNAL_P_ERROR?
        JE      ADJUST_FLAGS

        OR      SR_ERRORS,INEXACT_MASK  ; SIGNAL_P_ERROR.
        CMP     ADDED_ONE,TRUE          ; WAS ROUNDING DONE BY ADDING ONE?
        JNE     ADJUST_FLAGS            ; IF NOT,BRANCH TO ADJUST FLAGS

        OR      SR_FLAGS,A_MASK         ; ELSE,SET A_BIT
ADJUST_FLAGS:
        XOR     EAX,EAX                 ; CF = 0,SF = 0,ZF = 0 FOR
        INC     EAX                     ; STORE VALID EXIT
        RET

SINGLE_REAL_STORE       ENDP

PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                            DOUBLE_REAL_STORE:
;
;   FUNCTION:
;       IMPLEMENTS STORE TO DOUBLE-PRECISION REAL FORMAT
;
;   INPUTS:
;       OPERAND1
;
;   OUTPUTS:
;       DOUBLE PRECISION REAL IN MEMORY;
;       STACK POPPED IF INDICATED.
;
;   DATA ACCESSED:
;       - MEM_OPERAND_POINTER           OFFSET_OPERAND1
;       - SIGN1         TAG1
;       - EXPON1        WORD_FRAC1
;       - MSB_FRAC1     OFFSET_OPERAND1
;
;   DATA CHANGED:
;       - SIGN1         WORD_FRAC1
;
;   PROCEDURES CALLED:
;       TEST_3W                 STORE_VALID
;       RIGHT_SHIFT_FRAC1_CL    POP_FREE
;       DOUBLE_ZERO             DOUBLE_FILL
;       STORE_DENORMD           DOUBLE_FRAC_MEM
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
DOUBLE_REAL_STORE       PROC

        PUSH    OFFSET CS:POP_FREE         ; RETURN TO POP_FREE
        MOV     ESI,LOW_EXTENDED_EXPON_FOR_DOUBLE
        MOV     DL,PREC53               ; 53-BIT PRECISION
        MOV     AL,[EBP].TAG1           ; SEPARATE SPECIAL CASES
        CMP     AL,VALID
        JE      DOUBLE_VALID

        CMP     AL,DENORMD
        JE      DOUBLE_DENORMD

        CMP     AL,SPECIAL
        JNE     INV_OR_INF

        MOV     [EBP].EXPON1,3C00H
        JMP     SHORT   DOUBLE_FRAC_MEM

INV_OR_INF:
        CMP     AL,INV
        JNE     DOUBLE_SPECIAL

        TEST    MSB_FRAC1,40H           ; CHECK WHETHER NAN IS QUIET
        JNZ     DOUBLE_SPECIAL          ; BRANCH IF NAN IS QUIET

        OR      SR_ERRORS,INVALID_MASK  ; SET I_ERROR FOR SNAN
        TEST    SR_MASKS,INVALID_MASK   ; IF UNMASKED,JUST EXIT
        JNZ     MAKE_DBL_QNAN           ; ELSE,CHANGE TO QNAN

DBL_SPECIAL_RETURN:
        RET

MAKE_DBL_QNAN:
        OR      MSB_FRAC1,40H
DOUBLE_SPECIAL:
        MOV     [EBP].EXPON1,3C00H + 07FFH
        JMP     SHORT DOUBLE_FRAC_MEM   ; STORE FRAC TO MEMORY

DOUBLE_DENORMD:
        MOV     EDI,OFFSET_OPERAND1     ; OP1 IS DENORMAL OR PSEUDO-DENORMAL
        CALL    NORM_DENORM             ; DON'T SET D_ERROR; JUST NORMALIZE
DOUBLE_VALID:
        MOV     EDI,HIGH_EXTENDED_EXPON_FOR_DOUBLE

        CALL    STORE_VALID
        JZ      DOUBLE_INFINITY         ; ZF = 1 ==> STORE INFINITY
        JS      DOUBLE_MAX              ; SF = 1 ==> STORE MAX

DOUBLE_STORE:
        MOV     AL,LSB_FRAC1 + 3        ; ELSE STORE DOUBLE
        CBW
        MOV     EDI,OFFSET DWORD_FRAC1 + 6
        CALL    TEST_3W
        JZ      DOUBLE_ZERO             ; STORE SIGNED ZERO

DOUBLE_FRAC_MEM:
        MOV     CL,3                    ; START BY SHIFTING
        CALL    RIGHT_SHIFT_FRAC1_CL    ; FRACTION RIGHT 3 BITS
        LES     EDI,FWORD PTR [EBP].MEM_OPERAND_POINTER ; ES:EDI POINTS TO MEMOP
        PUSH    DS                      ; SAVE A?MSR
        PUSH    SS
        POP     DS                      ; SET UP SOURCE POINTER
        LEA     ESI,WORD_FRAC1 + 3      ; MOVE FRAC TO MEMORY
        MOV     ECX,3
        REP     MOVSW
        POP     DS                      ; RELOAD A?MSR
        MOV     AX,[EBP].EXPON1         ; FETCH HIGH-ORDER WORD,
        SUB     AX,3C00H                ; WITH EXPON,SIGN,AND
        SHL     AX,4                    ; TOP 4 BITS OF FRACTION
        AND     MSB_FRAC1,0FH
        OR      AL,MSB_FRAC1
        AND     [EBP].SIGN1,80H
        OR      AH,[EBP].SIGN1
        MOV     ES:[EDI],AX             ; ES:DI POINTS TO EXPON

        RET                             ; DO POP OR FREE

DOUBLE_ZERO:
        XOR     EAX,EAX                 ; STORE +/- 0 TO MEMORY
DOUBLE_FILL:
        LES     EDI,FWORD PTR [EBP].MEM_OPERAND_POINTER ; ES:EDI POINTS TO MEMOP
        MOV     ES:[EDI],EAX
        MOV     ES:[EDI + 4],AX
        MOV     AH,[EBP].SIGN1
        AND     AH,80H
DOUBLE_EXPON:
        MOV     ES:[EDI + 6],AX         ; STORE THE EXPONENT
        RET

DOUBLE_MAX:
        MOV     EAX,0FFFFFFFFH          ; SET FRACTION TO FF..F
        CALL    DOUBLE_FILL
        MOV     AX,7FEFH                ; SET EXPONENT TO 7FEH
        OR      AH,[EBP].SIGN1          ; OR SIGN BIT
        JMP     SHORT   DOUBLE_EXPON

DOUBLE_INFINITY:
        CALL    DOUBLE_ZERO                     ; FIRST CLEAR THE MEMOP
        OR      WORD PTR ES:[EDI + 6],7FF0H     ; ES:DI -> MEMOP
        RET

DOUBLE_REAL_STORE       ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                              FIX16:
;
;   FUNCTION:
;        FIXES VALID NUMBER TO A 16-BIT INTEGER.
;
;   INPUTS:
;        OPERAND1
;
;   OUTPUTS:
;       16-BIT INTEGER IN WORD_FRAC1 + 8;
;       OVERFLOW INDICATION IN ZF (ZF:1 => NO OVERFLOW)
;
;   DATA ACCESSED:
;       - OFFSET_OPERAND1       SIGN1
;       - EXPON1        WORD_FRAC1
;       - OFFSET_OPERAND1
;
;   DATA CHANGED:
;       - WORD_FRAC1            EXTRA_WORD_REG
;
;   PROCEDURES CALLED:
;       STICKY_RIGHT_SHIFT      ROUND
;       CAREFUL_ROUND           P_ERROR?
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
FIX16 PROC

        MOV     ECX,HIGH_INT16_EXPONENT         ; CALC SHIFT AMOUNT
        SUB     ECX,DWORD_EXPON1                ; IF EXPON1 > HIGH EXPON
        JS      NO_FIX16_OVF                    ; THEN OVERFLOW (ZF=0)

        CMP     ECX,MAX_INT16_SHIFT             ; DON'T LET SHIFT AMOUNT
        JBE     DO_SHIFT_16                     ; EXCEED MAX_INT16_SHIFT

        MOV     ECX,MAX_INT16_SHIFT
DO_SHIFT_16:
        MOV     EDI,OFFSET_OPERAND1             ; SHIFT FRAC1 BY CL
        XOR     AL,AL
        CALL    STICKY_RIGHT_SHIFT
        MOV     EDI,OFFSET_OPERAND1             ; ROUND TO 16-BIT PREC
        MOV     DL,PREC16
        MOV     AL,FALSE
        CALL    ROUND
        CMP     AL,FALSE                        ; OVERFLOW IF AL=TRUE
        JNZ     NO_FIX16_OVF                    ; ROUND CY OUT (ZF=1)

        CMP     WORD_FRAC1 + 8,8000H
        JB      CHECK_SIGN_16                   ; NO OVERFLOW IF < 8000H
        JA      NO_FIX16_OVF                    ; ELSE,OVERFLOW (ZF=0)

        CMP     [EBP].SIGN1,NEGATIVE            ; OFLOW IF = 8000H AND
        JNZ     NO_FIX16_OVF                    ; SIGN1 = POS (ZF=0)

CHECK_SIGN_16:
        MOV     AL,POSITIVE                     ; AL IS OVERFLOW FLAG
        CMP     AL,[EBP].SIGN1                  ; NEGATE INTEGER IF
        JZ      NO_FIX16_OVF                    ; SIGN IS NEG (ZF=1)

        NEG     WORD_FRAC1 + 8
        XOR     AL,AL                           ; NO OVERFLOW (ZF=1)

NO_FIX16_OVF:
        RET

FIX16   ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                           INT16_STORE:
;
;  FUNCTION:
;       STORES INTO 16-BIT INTEGER FORMAT
;
;  INPUTS:
;       OPERAND1
;
;  OUTPUTS:
;       16-BIT INTEGER IN MEMORY OPERAND LOCATION
;
;  DATA ACCESSED:
;       - MEM_OPERAND_POINTER   TAG1
;       - WORD_FRAC1            MSB_FRAC1
;       - OFFSET_OPERAND1       EXTRA_WORD_REG
;
;  DATA CHANGED:
;
;  PROCEDURES CALLED:
;       FIX16                   POP_FREE
;       INVALID_OR_SPECIAL      GET_RND_CONTROL
;       SET_I_ERROR             I_MASKED?
;       SET_P_ERROR             CLEAR_P_ERROR
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
INT16_STORE     PROC
;
        CMP     [EBP].TAG1,VALID
        JE      VALID_16

        CMP     [EBP].TAG1,DENORMD
        JNE     SPECIAL_16

VALID_16:
        CALL    FIX16                   ; MAKE OP1 A 16-BIT INT
        JNZ     SPECIAL_16              ; IF ZF=0,OFLOW ON FIX

        CMP     RND_HISTORY,0
        JE      STORE_16

        OR      SR_ERRORS,INEXACT_MASK
        CMP     ADDED_ONE,TRUE
        JNE     STORE_16

        OR      SR_FLAGS,A_MASK
STORE_16:
        MOV     AX,WORD_FRAC1 + 8       ; MOVE INTEGER TO MEMORY
POINTER_16:
        LES     EDI,FWORD PTR [EBP].MEM_OPERAND_POINTER ;SET ES:DI TO LOCATION
FINISH_16:
        MOV     ES:[EDI],AX             ; STORE INTEGER TO MEM
        JMP     POP_FREE                ; POP STACK AND GO HOME

SPECIAL_16:
        XOR     AX,AX
        CMP     [EBP].TAG1,SPECIAL      ; IS OPERAND TAGGED SPECIAL?
        JE      POINTER_16              ; YES,LOAD MEMOP PTR AND EXIT

        OR      SR_ERRORS,INVALID_MASK  ; NO,SET INVALID ERROR
        MOV     AX,8000H                ; LOAD INV CONSTANT INTO AX
        TEST    SR_MASKS,INVALID_MASK   ; IS INVALID ERROR MASKED?
        JNZ     POINTER_16              ; YES,STORE INVALID CONSTANT

        RET

INT16_STORE     ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                            FIX32:
;
;  FUNCTION:
;        FIXES VALID NUMBER TO A 32-BIT INTEGER.
;
;  INPUTS:
;        OPERAND1
;
;  OUTPUTS:
;       32-BIT INTEGER IN WORD_FRAC1 + 6;
;       OVERFLOW INDICATION IN ZF (ZF:1 => NO OVERFLOW)
;
;  DATA ACCESSED:
;       - OFFSET_OPERAND1       SIGN1
;       - DWORD_EXPON1          WORD_FRAC1
;       - OFFSET_OPERAND1
;
;  DATA CHANGED:
;       - WORD_FRAC1
;
;  PROCEDURES CALLED:
;       STICKY_RIGHT_SHIFT      ROUND
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
FIX32 PROC

        MOV     ECX,HIGH_INT32_EXPONENT ; CALC SHIFT AMOUNT
        SUB     ECX,DWORD_EXPON1        ; IF EXPON1 > HIGH EXPON
        JS      NO_FIX32_OVF            ; THEN OVERFLOW (ZF=0)

        CMP     ECX,MAX_INT32_SHIFT     ; DON'T LET SHIFT AMOUNT
        JBE     DO_SHIFT_32             ; EXCEED MAX_INT32_SHIFT

        MOV     ECX,MAX_INT32_SHIFT
DO_SHIFT_32:
        MOV     EDI,OFFSET_OPERAND1     ; SHIFT FRAC1 BY CL
        XOR     AL,AL
        CALL    STICKY_RIGHT_SHIFT
        MOV     EDI,OFFSET_OPERAND1     ; ROUND TO 16-BIT PREC
        MOV     DL,PREC32
        MOV     AL,FALSE
        CALL    ROUND
        CMP     AL,FALSE                ; OVERFLOW IF AL=TRUE
        JNZ     NO_FIX32_OVF            ; ROUND CY OUT (ZF=1)

        CMP     DWORD PTR [EBP].DWORD_FRAC1 + FRAC32,080000000H

        JB      CHECK_SIGN_32           ; NO OVERFLOW IF < 80000000H
        JA      NO_FIX32_OVF            ; ELSE,OVERFLOW (ZF=0)

        CMP     [EBP].SIGN1,NEGATIVE    ; OFLOW IF = 80000000H AND
        JNZ     NO_FIX32_OVF            ; SIGN1 = POS (ZF=0)

CHECK_SIGN_32:
        MOV     AL,POSITIVE             ; AL IS OVERFLOW FLAG
        CMP     AL,[EBP].SIGN1          ; NEGATE INTEGER IF
        JZ      NO_FIX32_OVF            ; SIGN IS NEG (ZF=1)

        NEG     DWORD PTR [EBP].DWORD_FRAC1 + FRAC32
        XOR     AL,AL                   ; NO OVERFLOW (ZF=1)
NO_FIX32_OVF:
        RET

FIX32           ENDP

PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                              INT32_STORE:
;
;  FUNCTION:
;       STORES INTO 32-BIT INTEGER FORMAT
;
;  INPUT:
;       OPERAND1
;
;  OUTPUT:
;       32-BIT INTEGER IN LOCATION POINTED TO BY ES:DI.
;
;  DATA ACCESSED:
;       - MEM_OPERAND_POINTER           OFFSET_OPERAND1
;       - SIGN1         TAG1
;       - EXPON1        WORD_FRAC1
;       - MSB_FRAC1     OFFSET_OPERAND1
;
;  DATA CHANGED:
;       - WORD_FRAC1
;
;  PROCEDURES CALLED:
;       POP_FREE
;       FIX32
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
INT32_STORE     PROC

        CMP     [EBP].TAG1,VALID
        JE      VALID_32

        CMP     [EBP].TAG1,DENORMD
        JNE     SPECIAL_32

VALID_32:
        CALL    FIX32                   ; MAKE OP1 A 32-BIT INT
        JNZ     SPECIAL_32              ; IF ZF=0,OFLOW ON FIX

        CMP     RND_HISTORY,0
        JE      STORE_32

        OR      SR_ERRORS,INEXACT_MASK
        CMP     ADDED_ONE,TRUE
        JNE     STORE_32

        OR      SR_FLAGS,A_MASK
STORE_32:
        MOV     EAX,[EBP].DWORD_FRAC1 + FRAC32      ; MOVE INTEGER TO EAX
POINTER_32:
        LES     EDI,FWORD PTR [EBP].MEM_OPERAND_POINTER ;SET ES:DI TO LOCATION
FINISH_32:
        MOV     ES:[EDI],EAX            ; STORE INTEGER TO MEM
        JMP     POP_FREE                ; POP STACK AND GO HOME

SPECIAL_32:
        XOR     EAX,EAX
        CMP     [EBP].TAG1,SPECIAL      ; IS OPERAND TAGGED SPECIAL?
        JE      POINTER_32              ; YES,LOAD MEMOP PTR AND EXIT

        OR      SR_ERRORS,INVALID_MASK  ; NO,SET INVALID ERROR
        MOV     EAX,080000000H          ; LOAD INV CONSTANT INTO AX
        TEST    SR_MASKS,INVALID_MASK   ; IS INVALID ERROR MASKED?
        JNZ     POINTER_32              ; YES,STORE INVALID CONSTANT

        RET

INT32_STORE     ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                                FIX64:
;
;  FUNCTION:
;        FIXES VALID NUMBER TO A 64-BIT INTEGER.
;
;  INPUTS:
;        OPERAND1
;
;  OUTPUTS:
;       64-BIT INTEGER IN WORD_FRAC1 + 2;
;       OVERFLOW INDICATION IN ZF (ZF:1 => NO OVERFLOW)
;
;  DATA ACCESSED:
;       - OFFSET_OPERAND1       SIGN1
;       - DWORD_EXPON1          WORD_FRAC1
;       - OFFSET_OPERAND1
;
;  DATA CHANGED:
;       - WORD_FRAC1
;
;  PROCEDURES CALLED:
;       STICKY_RIGHT_SHIFT      ROUND
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
FIX64 PROC

        MOV     ECX,HIGH_INT64_EXPONENT         ; CALC SHIFT AMOUNT
        SUB     ECX,DWORD_EXPON1                ; IF EXPON1 > HIGH EXPON
        JS      NO_FIX64_OVF                    ; THEN OVERFLOW (ZF=0)

        CMP     ECX,MAX_INT64_SHIFT             ; DON'T LET SHIFT AMOUNT
        JBE     DO_SHIFT_64                     ; EXCEED MAX_INT64_SHIFT

        MOV     ECX,MAX_INT64_SHIFT
DO_SHIFT_64:
        MOV     EDI,OFFSET_OPERAND1             ; SHIFT FRAC1 BY CL
        XOR     AL,AL
        CALL    STICKY_RIGHT_SHIFT
        MOV     EDI,OFFSET_OPERAND1             ; ROUND TO 64-BIT PREC
        MOV     DL,PREC64
        MOV     AL,FALSE
        CALL    ROUND
        CMP     AL,FALSE                        ; OVERFLOW IF AL=TRUE
        JNZ     NO_FIX64_OVF                    ; ROUND CY OUT (ZF=1)

        CMP     DWORD PTR [EBP].DWORD_FRAC1 + FRAC32,080000000H

        JB      CHECK_SIGN_64                   ; NO OVERFLOW IF < 80000000H
        JA      NO_FIX64_OVF                    ; ELSE,OVERFLOW (ZF=0)

        CMP     DWORD PTR [EBP].DWORD_FRAC1 + FRAC64,0
        JNZ     NO_FIX64_OVF

        CMP     [EBP].SIGN1,NEGATIVE            ; OFLOW IF = 800..0H AND
        JNZ     NO_FIX64_OVF                    ; SIGN1 = POS (ZF=0)

CHECK_SIGN_64:
        MOV     AL,POSITIVE                     ; AL IS OVERFLOW FLAG
        CMP     AL,[EBP].SIGN1                  ; NEGATE INTEGER IF
        JZ      NO_FIX64_OVF                    ; SIGN IS NEG (ZF=1)

        XOR     EAX,EAX
        NEG     DWORD PTR [EBP].DWORD_FRAC1 + FRAC64
        SBB     EAX,DWORD PTR [EBP].DWORD_FRAC1 + FRAC32
        MOV     DWORD PTR [EBP].DWORD_FRAC1 + FRAC32,EAX

        XOR     AL,AL                           ; NO OVERFLOW (ZF=1)

NO_FIX64_OVF:
        RET

FIX64           ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                              INT64_STORE:
;
;  FUNCTION:
;       STORES INTO 64-BIT INTEGER FORMAT
;
;  INPUT:
;       OPERAND1
;
;  OUTPUT:
;       64-BIT INTEGER IN MEMORY LOCATION POINTED TO BY ES:EDI.
;
;  DATA ACCESSED:
;       - MEM_OPERAND_POINTER           OFFSET_OPERAND1
;       - SIGN1         TAG1
;       - EXPON1        WORD_FRAC1
;       - MSB_FRAC1     OFFSET_OPERAND1
;
;  DATA CHANGED:
;       - WORD_FRAC1
;
;  PROCEDURES CALLED:
;       POP_FREE
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
INT64_STORE     PROC
        CMP     [EBP].TAG1,VALID
        JE      VALID_64

        CMP     [EBP].TAG1,DENORMD
        JNE     SPECIAL_64

VALID_64:
        CALL    FIX64                   ; MAKE OP1 A 64-BIT INT
        JNZ     SPECIAL_64              ; IF ZF=0,OFLOW ON FIX

        CMP     RND_HISTORY,0
        JE      STORE_64

        OR      SR_ERRORS,INEXACT_MASK
        CMP     ADDED_ONE,TRUE
        JNE     STORE_64

        OR      SR_FLAGS,A_MASK
STORE_64:
        MOV     EAX,[EBP].DWORD_FRAC1 + FRAC64      ; MOVE INTEGER TO EDX:EAX
        MOV     EDX,[EBP].DWORD_FRAC1 + FRAC32      ; MOVE INTEGER TO EDX:EAX
POINTER_64:
        LES     EDI,FWORD PTR [EBP].MEM_OPERAND_POINTER ;SET ES:EDI TO LOCATION
FINISH_64:
        MOV     ES:[EDI],EAX            ; STORE LOW INTEGER TO LOW MEM
        MOV     ES:[EDI+4],EDX          ; STORE HIGH INTEGER TO HIGH MEM
        JMP     POP_FREE                ; POP STACK AND GO HOME

SPECIAL_64:
        XOR     EAX,EAX
        CDQ
        CMP     [EBP].TAG1,SPECIAL      ; IS OPERAND TAGGED SPECIAL?
        JE      POINTER_64              ; YES,LOAD MEMOP PTR AND EXIT

        OR      SR_ERRORS,INVALID_MASK  ; NO,SET INVALID ERROR
        MOV     EDX,080000000H          ; LOAD INV CONSTANT INTO AX
        TEST    SR_MASKS,INVALID_MASK   ; IS INVALID ERROR MASKED?
        JNZ     POINTER_64              ; YES,STORE INVALID CONSTANT

        RET

INT64_STORE     ENDP
;
EMULATOR_CODE ends
;
        END
