;       SCCSID = @(#)trans.asm	6.1 92/01/29
title   trans.asm
page    55,132
;*****************************************************************************
;
;                       T R A N S . 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.
;       ===============================================================
;
; PUBLIC PROCEDURES:
;    TWO_ARG_TRANS,EXP,LOG,SPLOG,TAN,MOVE_10_BYTES
;    MOVE_CONSTANT,TEST_5W,,TEST_6W,TEST_4W,TEST_3W,CLEAR_5W,CLEAR_6W
;    SET_5W,SET_6W,SET_4W,SET_3W,LEFT_SHIFT_RESULT_CL
;    LEFT_SHIFT_FRAC1_CL,LEFT_SHIFT_FRAC2_CL
;    RIGHT_SHIFT_RESULT_CL,RIGHT_SHIFT_FRAC1_CL
;    RIGHT_SHIFT_FRAC2_CL,RIGHT_SHIFT,LEFT_SHIFT
;    STICKY_RIGHT_SHIFT,ADDITION_NORMALIZE
;    SUBTRACTION_NORMALIZE,ONE_LEFT_NORMALIZE
;    GRADUAL_UNDERFLOW,LEFT_SHIFT_FRAC1_1,SIN,COS,SINCOS
;
;*****************************************************************************
;
;...FEBRUARY 20,1987...
;
; 12-18-91 mth remove USE16 and INTEL ifdef's
;
;---------------------------------------------

                NAME    A?MTR
                .386P
                .XLIST
                INCLUDE E80387.INC
                include  icmacros.inc

                .LIST
EMULATOR_DATA   segment dword public 'FAR_DATA'
        EXTRN   SR_MASKS:BYTE,SR_ERRORS:BYTE,SR_FLAGS:BYTE
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   PUT_SI_RESULT:NEAR, DO_EXCHANGE:NEAR, ADDX:NEAR, SUBX:NEAR
    EXTRN   DIVX:NEAR, DIVID:NEAR, ROUND:NEAR, UNDERFLOW_RESPONSE:NEAR
    EXTRN   ACCEL_DIVX:NEAR, LOG_DIVX:NEAR, DECOMPOSE:NEAR, MULT:NEAR
    EXTRN   MULX:NEAR
    EXTRN   OVERFLOW_RESPONSE:NEAR, SP_SUBADD:NEAR, STACK_FULL?:NEAR
    EXTRN   POP_FREE:NEAR, PUT_OP1_RESULT:NEAR, SET_P_ERROR:NEAR
    EXTRN   SET_U_ERROR:NEAR, GET_PRECISION:NEAR, MOVE_OP_TO_OP:NEAR
    EXTRN   SUBADD:NEAR, SET_UP_INDEFINITE:NEAR, SET_STK_U_ERROR:NEAR
    EXTRN   NORM_DENORM:NEAR, PUT_RESULT:NEAR, REMRX:NEAR
    EXTRN   PUT_INDEFINITE:NEAR
    EXTRN   PUT_ARITH_RESULT:NEAR, SET_UP_NAN_RETURN:NEAR
    EXTRN   DO_EXCHANGE_LEAVE_A_BIT:NEAR
;
    PUBLIC  TWO_ARG_TRANS, EXP, LOG, SPLOG, MOVE_10_BYTES
    PUBLIC  TAN, MOVE_CONSTANT, TEST_5W, TEST_6W, TEST_4W, TEST_3W
    PUBLIC  CLEAR_5W, CLEAR_6W, SET_5W, SET_6W, SET_4W, SET_3W
    PUBLIC  LEFT_SHIFT_FRAC1_CL
    PUBLIC  LEFT_SHIFT_RESULT_CL, LEFT_SHIFT_FRAC2_CL
    PUBLIC  RIGHT_SHIFT_FRAC1_CL, RIGHT_SHIFT_FRAC2_CL
    PUBLIC  RIGHT_SHIFT_RESULT_CL, RIGHT_SHIFT, LEFT_SHIFT
    PUBLIC  GRADUAL_UNDERFLOW, ADDITION_NORMALIZE
    PUBLIC  STICKY_RIGHT_SHIFT, ONE_LEFT_NORMALIZE
    PUBLIC  SUBTRACTION_NORMALIZE, LEFT_SHIFT_FRAC1_1
    PUBLIC  SIN, COS, SINCOS


PAGE
;
ADD_HALF_PATTERN        DW      80H,0,0,0,0
ADD_HALF_PATTERN_1      DW      8000H,0,0,0,0
CONSTANT_LN2_OV_6       DW      0,0,0,1FF5H,0EC98H
CONSTANT_2_OV_LN2       DW      0BBC0H,17F0H,295CH,0AA3BH,00B8H
CONSTANT_ONE            DW      0,0,0,0,100H
CONSTANT_SIX            DW      0,0,0,0,0C000H
CONSTANT_SQRT_OF_2      DW      8400H,0DE64H,33F9H,04F3H,0B5H
CONSTANT_3_OV_LN2       DW      0,0F48DH,0511H,0AC5FH,8A7FH
CONSTANT_ONE_1          DW      0,0,0,0,8000H

;----------------------------------------------------
; THIS CONSTANT HAS BEEN DECREASED BY 1 TO COMPENSATE
; FOR THE BITS LOST DURING RIGHT SHIFT.
;
CONSTANT_C0H    DW      0FF00H,0FFFFH,0FFFFH,0FFFFH,0BFH
;
LOG_CONSTANT    DW      09FA0H,0D687H,039FBH,0C01AH,095H        ;1
                DW      0F260H,0DC57H,05E68H,0D3C2H,0A4H        ;2
                DW      0FD20H,0B43CH,0CFDEH,000D1H,0AEH        ;3
                DW      0E680H,098B3H,0D648H,01FB7H,0B3H        ;4
                DW      089C0H,0EC39H,0AC77H,0D69BH,0B5H        ;5
                DW      05380H,0914CH,02E16H,03CB4H,0B7H        ;6
                DW      0FC80H,0428BH,0B778H,0F285H,0B7H        ;7
                DW      056E0H,063BAH,06BD5H,04E23H,0B8H        ;8
                DW      031E0H,0AB26H,0F853H,07C1FH,0B8H        ;9
                DW      0FD60H,0A2A0H,0BA1FH,09329H,0B8H        ;A
                DW      057C0H,0BE18H,07BCAH,09EB1H,0B8H        ;B
                DW      070A0H,0FE44H,0150DH,0A476H,0B8H        ;C
                DW      0AA60H,09B1BH,08FD2H,0A758H,0B8H        ;D
                DW      09460H,09AE9H,0D8BEH,0A8C9H,0B8H        ;E
                DW      03380H,02572H,08017H,0A982H,0B8H        ;F
;
TAN_CONSTANT    DW      034C0H,068C2H,0A221H,00FDAH,0C9H        ;0
                DW      04580H,0DA7BH,02B0DH,06338H,0EDH        ;1
                DW      01560H,006EBH,0C964H,0DBAFH,0FAH        ;2
                DW      032C0H,07B6EH,0D561H,0ADD4H,0FEH        ;3
                DW      036C0H,0EF4EH,0B967H,0AADDH,0FFH        ;4
                DW      04280H,0B125H,0DD4BH,0EAADH,0FFH        ;5
                DW      0BBE0H,094D5H,0DDDBH,0FAAAH,0FFH        ;6
                DW      06800H,0D4B9H,0ADDDH,0FEAAH,0FFH        ;7
                DW      04BC0H,0DDB9H,0AADDH,0FFAAH,0FFH        ;8
                DW      04BA0H,0DDDDH,0AAADH,0FFEAH,0FFH        ;9
                DW      0DBA0H,0DDDDH,0AAAAH,0FFFAH,0FFH        ;A
                DW      0DDE0H,0ADDDH,0AAAAH,0FFFEH,0FFH        ;B
                DW      0DDE0H,0AADDH,0AAAAH,0FFFFH,0FFH        ;C
                DW      0DDE0H,0AAADH,0EAAAH,0FFFFH,0FFH        ;D
                DW      0DDE0H,0AAAAH,0FAAAH,0FFFFH,0FFH        ;E
                DW      0ADE0H,0AAAAH,0FEAAH,0FFFFH,0FFH        ;F
PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;

AT_CASE_TABLE           DD      A?MEDOFFSET AT_ROUND
                        DD      A?MEDOFFSET CASE_1
                        DD      A?MEDOFFSET CASE_2
                        DD      A?MEDOFFSET CASE_3


TWO_ARG_TRANS_TABLE     DD      A?MEDOFFSET AT_NON_0
                        DD      A?MEDOFFSET LOG
                        DD      A?MEDOFFSET SPLOG


;...THE FOLLOWING JUMP TABLES REFER TO THE FOLLOWING OP1/OP2 CASES
;
;   (WHERE V=VALID,Z=ZERO,F=INFINITY,AND D=DENORMAL):
;     V/V,V/Z,V/F,V/D,Z/V,Z/Z,Z/F,Z/D,F/V,F/Z,F/F,F/D,D/V,D/Z,D/F AND D/D,
;     IN THAT ORDER ..
;
; ARCTAN2_TABLE IS FIRST

SPECIAL_TABLE   DD      A?MEDOFFSET HANDLE_NON_SPECIAL_CASES
                DD      A?MEDOFFSET SIGN_Y_HAPI
                DD      A?MEDOFFSET SIGN_Y_PI_OR_0
                DD      A?MEDOFFSET ONLY_OP2_DENORMD
                DD      A?MEDOFFSET SIGN_Y_PI_OR_0
                DD      A?MEDOFFSET AT_BOTH_0
                DD      A?MEDOFFSET SIGN_Y_PI_OR_0
                DD      A?MEDOFFSET DERROR_SIGN_Y_PI_OR_0
                DD      A?MEDOFFSET SIGN_Y_HAPI
                DD      A?MEDOFFSET SIGN_Y_HAPI
                DD      A?MEDOFFSET HANDLE_NON_SPECIAL_CASES
                DD      A?MEDOFFSET DERROR_SIGN_Y_HAPI
                DD      A?MEDOFFSET ONLY_OP1_DENORMD
                DD      A?MEDOFFSET DERROR_SIGN_Y_HAPI
                DD      A?MEDOFFSET DERROR_SIGN_Y_PI_OR_0
                DD      A?MEDOFFSET BOTH_OPS_DENORMD
;
; LOG_TABLE IS SECOND,64 BYTES AFTER ARCTAN2_TABLE
;
                DD      A?MEDOFFSET HANDLE_NON_SPECIAL_CASES
                DD      A?MEDOFFSET OP2_SIGNED_BY_OP1_VS_1
                DD      A?MEDOFFSET INV_OR_OP2_SIGNED_BY_OP1_VS_1
                DD      A?MEDOFFSET ONLY_OP2_DENORMD
                DD      A?MEDOFFSET ZERROR_FLIP_SIGN_Y_INF
                DD      A?MEDOFFSET OP_UNSUPP
                DD      A?MEDOFFSET ZERROR_FLIP_SIGN_OP2
                DD      A?MEDOFFSET ZERROR_FLIP_SIGN_Y_INF
                DD      A?MEDOFFSET SIGN_Y_OP1
                DD      A?MEDOFFSET OP_UNSUPP
                DD      A?MEDOFFSET OP2
                DD      A?MEDOFFSET DERROR_SIGN_Y_OP1
                DD      A?MEDOFFSET ONLY_OP1_DENORMD
                DD      A?MEDOFFSET DERROR_FLIP_SIGN_OP2
                DD      A?MEDOFFSET DERROR_FLIP_SIGN_OP2
                DD      A?MEDOFFSET BOTH_OPS_DENORMD
;
; SPLOG_TABLE IS THIRD (AND LAST),128 BYTES AFTER ARCTAN2_TABLE
;
                DD      A?MEDOFFSET HANDLE_NON_SPECIAL_CASES
                DD      A?MEDOFFSET EXOR_SIGNED_OP2
                DD      A?MEDOFFSET EXOR_SIGNED_OP2
                DD      A?MEDOFFSET ONLY_OP2_DENORMD
                DD      A?MEDOFFSET EXOR_SIGNED_OP1
                DD      A?MEDOFFSET EXOR_SIGNED_OP2
                DD      A?MEDOFFSET OP_UNSUPP
                DD      A?MEDOFFSET DERROR_EXOR_SIGNED_OP1
                DD      A?MEDOFFSET SIGN_Y_OP1
                DD      A?MEDOFFSET OP_UNSUPP
                DD      A?MEDOFFSET OP2
                DD      A?MEDOFFSET DERROR_SIGN_Y_OP1
                DD      A?MEDOFFSET ONLY_OP1_DENORMD
                DD      A?MEDOFFSET DERROR_EXOR_SIGNED_OP2
                DD      A?MEDOFFSET DERROR_EXOR_SIGNED_OP2
                DD      A?MEDOFFSET BOTH_OPS_DENORMD

;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                       ATAN_CORE:
;                       """""""""
;
;       FUNCTION:
;               CALCULATES ARC TANGENT OF (Y/X),WHERE
;               0 < Y/X < 1 ;  OP2 = X, OP1 = Y.
;
;       INPUTS:
;               ASSUMES THAT OPERAND1 AND OPERAND2 ARE SET UP.
;
;       OUTPUTS:
;               RESULT IN GLOBAL RECORD 12; POSSIBLE UNDERFLOW
;               AND INEXACT ERRORS.
;
;       DATA ACCESSED:
;               - EXPON1                WORD_FRAC1
;               - LSB_FRAC1             MSB_FRAC1
;               - OFFSET_OPERAND1       EXPON2
;               - LSB_FRAC2             OFFSET_OPERAND2
;               - OFFSET_RESULT         RESULT_SIGN
;               - RESULT_TAG            RESULT_EXPON
;               - RESULT_WORD_FRAC      MSB_RESULT
;               - OFFSET_OF_RESULT_FRAC OFFSET_COP
;               - OFFSET_DOP            SISO
;
;       DATA CHANGED:
;               - EXPON1                FRAC1
;               - FRAC2                 RESULT_SIGN
;               - RESULT_EXPON          RESULT_FRAC
;               - SISO
;
;       PROCEDURES CALLED:
;
;  PUT_SI_RESULT           RIGHT_SHIFT             LEFT_SHIFT
;  MOVE_10_BYTES           MOVE_CONSTANT           ADDX
;  SUBX                    MULX                    ACCEL_DIVX (replaces DIVX)
;  DIVID                   ONE_LEFT_NORMALIZE      ROUND
;  ADDITION_NORMALIZE      UNDERFLOW_RESPONSE      POP_FREE
;  TEST_5W                 SET_P_ERROR             SET_U_ERROR
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
ATAN_CORE               PROC

        PUSH    DWORD PTR SR_MASKS          ; SAVE PRECISION CONTROL
        OR      DWORD PTR SR_MASKS,0300H    ; SET PRECISION CONTROL TO PREC64
        OR      SR_ERRORS,INEXACT_MASK      ; ALWAYS INEXACT
        MOV     [EBP].RESULT_SIGN,POSITIVE  ; RESULT IS ALWAYS POSITIVE
        MOV     SISO,0                      ; CLEAR SISO
        MOV     EAX,DWORD_EXPON2
        SUB     EAX,DWORD_EXPON1
        MOV     DWORD_EXP_TMP,EAX
        CMP     EAX,15
        JLE     ATN_PSEUDO_DIV

        CMP     EAX,63
;
;TINY ARGUMENT
;
        JG      ATN_DIVIDE

        JMP     ATN_RAT_APPX

ATN_DIVIDE:
        CALL    DIVID                   ; FLOATING-POINT DIVIDE
;
;POST OPERATION ROUNDING
;
        CALL    POST_OP_ROUND           ; D.E. PRECISION ROUNDING
;
;ERROR CHECK
;
        MOV     EAX,DWORD_RESULT_EXPON
        CMP     EAX,0
        JG      ATN_PUT_ATN_F
        JL      ATN_PUT_ATN                ; UNDERFLOW OF CORE HAS OCCURRED.

        MOV     EDI,OFFSET_RESULT + FRAC64
        CALL    TEST_4W                    ; NOTE THAT AX IS 0 HERE.
        JNZ     ATN_PUT_ATN                ; UNDERFLOW OF CORE HAS OCCURRED.

ATN_ZERO:
        MOV     [EBP].RESULT_TAG,SPECIAL
        JMP     ATN_PUT_ATN

ATN_PSEUDO_DIV:
        CALL    RIGHT_SHIFT_FRAC2_8
        CALL    RIGHT_SHIFT_FRAC1_8
ATN_LOOP_BACK_1:
        CALL    SUBX
        SHL     SISO,1
        CMP     MSB_RESULT,0
        JNZ     ATN_SHIFT_LEFT

        CALL    MOVE_RESULT_COP                 ; COP IS 67 BITS TEMP
        MOV     EDI,OFFSET_OPERAND1
        CALL    RIGHT_SHIFT_DWORD_EXP_TMP
        CALL    ADDX
        CALL    MOVE_RESULT_FRAC1
        MOV     ESI,A?MEDOFFSET ADD_HALF_PATTERN
        CALL    ADD_FRAC2                       ; ADD 1/2 ROUND
        CALL    MOVE_RESULT_FRAC2
        AND     DWORD PTR [EBP].DWORD_FRAC2,0FF000000H  ; FRAC2 = 64 BITS X
        CALL    MOVE_COP_FRAC1                          ; FRAC1 = 67 BITS Y
        INC     SISO
        CMP     MSB_RESULT,0
        JE      ATN_SHIFT_LEFT

        MOV     ECX,1
        CALL    RIGHT_SHIFT_FRAC2_CL
        AND     DWORD PTR [EBP].DWORD_FRAC2,0FF000000H
        JMP     SHORT ATN_MERGE_0

ATN_SHIFT_LEFT:
        CALL    LEFT_SHIFT_FRAC1_1
ATN_MERGE_0:
        INC     DWORD_EXP_TMP
        CMP     DWORD_EXP_TMP,15
        JNA     ATN_LOOP_BACK_1

        MOV     ECX,7
        CALL    LEFT_SHIFT_FRAC1_CL
        AND     [EBP].DWORD_FRAC1,0E0000000H
        MOV     DWORD_EXP_TMP,15
        CALL    LEFT_SHIFT_FRAC2_8
ATN_RAT_APPX:
; The following call used to be to DIVX instead of ACCEL_DIVX:
        CALL    ACCEL_DIVX                              ; Y/X --> Z (67)
        CALL    MOVE_RESULT_FRAC1
        MOV     ECX,9
        CALL    RIGHT_SHIFT_FRAC1_CL
        AND     [EBP].DWORD_FRAC1,0FFE00000H
        CALL    MOVE_RESULT_FRAC2
        CALL    RIGHT_SHIFT_FRAC2_8
        AND     [EBP].DWORD_FRAC2,0FFE00000H
        AND     [EBP].RESULT_DWORD_FRAC,0E0000000H      ; MASK RESULT FRAC
        CALL    MOVE_RESULT_COP
        CALL    ADDX
        CALL    MOVE_RESULT_DOP                 ;DOP = NEW Y (67)
        CALL    MOVE_COP_FRAC1
        CALL    MOVE_COP_FRAC2
        MOV     ECX,30
        CALL    RIGHT_SHIFT_FRAC1_CL            ; PERFORM SHORT MULTIPLY
        MOV     [EBP].DWORD_FRAC1,0
        MOV     ECX,30
        CALL    LEFT_SHIFT_FRAC1_CL
        CALL    MULX
        MOV     EDI,OFFSET_RESULT
        CALL    RIGHT_SHIFT_DWORD_EXP_TMP
        MOV     MSB_RESULT,0C0H
        CALL    MOVE_RESULT_FRAC2               ; NEW X (64)
        AND     [EBP].DWORD_FRAC2,0E0000000H
        CMP     MSB_DOP,0
        MOV     AL,1
        MOV     ECX,7
        JNE     ATN_MERGE_1

        MOV     AL,0
        MOV     ECX,8

ATN_MERGE_1:
        PUSH    EAX                             ;SAVE AL
        MOV     EDI,OFFSET_DOP + FRAC80
        CALL    LEFT_SHIFT
        CALL    MOVE_DOP_FRAC1
; The following call used to be to DIVX instead of ACCEL_DIVX:
        CALL    ACCEL_DIVX
        AND     [EBP].RESULT_DWORD_FRAC,0E0000000H      ; THETA IS HERE
        POP     EAX
        SHR     AL,1
        MOV     ECX,7
        JNB     ATN_MERGE_2

        MOV     ECX,6

ATN_MERGE_2:
        CALL    RIGHT_SHIFT_RESULT_CL
        CALL    MOVE_RESULT_FRAC1
ATN_LOOP_BACK_2:
        SHR     SISO,1
        JNB     ATN_Q_BIT_NOT_SET

        MOV     EAX,10
        MUL     DWORD_EXP_TMP
        ADD     EAX,A?MEDOFFSET TAN_CONSTANT
        MOV     ESI,EAX
        CALL    ADD_FRAC2
        CALL    MOVE_RESULT_FRAC1
ATN_Q_BIT_NOT_SET:
        CMP     SISO,0
        JZ      ATN_END_LOOP

        MOV     ECX,1
        CALL    RIGHT_SHIFT_FRAC1_CL
        AND     [EBP].DWORD_FRAC1,0FFE00000H
        DEC     DWORD_EXP_TMP
        JMP     ATN_LOOP_BACK_2

ATN_END_LOOP:
        CMP     MSB_FRAC1,0
        MOV     ECX,8
        JE      ATN_MERGE_3

        MOV     ECX,7
        DEC     DWORD_EXP_TMP

ATN_MERGE_3:
        CALL    LEFT_SHIFT_FRAC1_CL
        MOV     DWORD_EXPON1,3FFEH
        MOV     EAX,DWORD_EXP_TMP
        SUB     DWORD_EXPON1,EAX
        MOV     EDI,OFFSET_OPERAND1
        CALL    ONE_LEFT_NORMALIZE
        CALL    MOVE_FRAC1_RESULT   ; ADDED WHEN ADD_HALF1_FRAC BELOW WAS CUT
        MOV     EAX,DWORD_EXPON1
        MOV     DWORD_RESULT_EXPON,EAX

ATN_PUT_ATN_F:

        MOV     [EBP].RESULT_TAG,VALID          ; VALID RESULT

ATN_PUT_ATN:

        POP     DWORD PTR SR_MASKS              ; RESTORE PRECISION CONTROL
        RET

ATAN_CORE       ENDP

PAGE
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
MOVE_UNPACKED_0_TO_EDI          PROC

        MOV     DWORD PTR [EBP + EDI],0
        MOV     DWORD PTR [EBP + EDI + FRAC64],0
        MOV     DWORD PTR [EBP + EDI + FRAC32],0
        MOV     DWORD PTR [EBP + EDI + SIGN],POSITIVE + 10000H*SPECIAL
        MOV     DWORD PTR [EBP + EDI + EXPON],0
        RET

MOVE_UNPACKED_0_TO_EDI          ENDP
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
MOVE_UNPACKED_HAPI_TO_EDI       PROC

        MOV     DWORD PTR [EBP + EDI],0
        MOV     DWORD PTR [EBP + EDI + FRAC64],2168C235H
        MOV     DWORD PTR [EBP + EDI + FRAC32],0C90FDAA2H
        MOV     DWORD PTR [EBP + EDI + SIGN],POSITIVE + 10000H*VALID
        MOV     DWORD PTR [EBP + EDI + EXPON],3FFFH
        RET

MOVE_UNPACKED_HAPI_TO_EDI       ENDP
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
PAGE
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

AT_NON_0        PROC

        MOV     DL,[EBP].SIGN1
        MOV     DH,[EBP].SIGN2
        MOV     [EBP].SIGN1,POSITIVE
        MOV     [EBP].SIGN2,POSITIVE
        MOV     BL,DH
        AND     EBX,8
AT_CMPR_OPS:                            ; THIS COMPARE ASSUMES SAME-
                                        ; SIGNED,NORMALIZED COMPARANDS
        MOV     EAX,DWORD_EXPON2
        CMP     EAX,DWORD_EXPON1
        JG      TAKE_ATAN
        JL      AT_SWITCH_OPS

        MOV     EAX,DWORD PTR [EBP].DWORD_FRAC1 + FRAC32
        CMP     EAX,DWORD PTR [EBP].DWORD_FRAC2 + FRAC32
        JG      TAKE_ATAN
        JL      AT_SWITCH_OPS

        MOV     EAX,DWORD PTR [EBP].DWORD_FRAC1 + FRAC64
        CMP     EAX,DWORD PTR [EBP].DWORD_FRAC2 + FRAC64
        JG      TAKE_ATAN
        JL      AT_SWITCH_OPS

AT_OPS_EQL:
        MOV     EDI,OFFSET_RESULT
        CALL    MOVE_UNPACKED_HAPI_TO_EDI
        DEC     DWORD_RESULT_EXPON              ; MAKE PI/4
        OR      EBX,EBX
        JZ      AT_SIGN_ADJUST

        JMP     SHORT HAPI_TO_OP1

AT_SWITCH_OPS:
        PUSH    EBX
        CALL    SWAP_OPS                ; EDX PRESERVED
        POP     EBX
        OR      EBX,4
TAKE_ATAN:
        PUSH    EBX                     ; SAVE OPERAND SIGNS
        PUSH    EDX                     ; SAVE TABLE INDEX
        CALL    ATAN_CORE
        POP     EDX
        POP     EBX
        OR      EBX,EBX
        JNZ     HAPI_TO_OP1

AT_UNDERFLOW?:
        MOV     EAX,DWORD_RESULT_EXPON
        CMP     EAX,0
        JG      AT_ROUND
        JL      AT_UNDERFLOW

        CMP     [EBP].RESULT_TAG,SPECIAL
        JE      AT_ROUND_REPORT

AT_UNDERFLOW:                                   ; UNDERFLOW
        PUSH    EDX                             ; SAVE SIGN INFO
        CALL    UNDERFLOW_RESPONSE
        POP     EDX                             ; RESTORE SIGN INFO
        OR      SR_ERRORS,UNDERFLOW_MASK
        JMP     SHORT AT_SIGN_ADJUST

HAPI_TO_OP1:
        MOV     EDI,OFFSET_OPERAND1
        CALL    MOVE_UNPACKED_HAPI_TO_EDI
        JMP     CS:AT_CASE_TABLE[EBX]

CASE_3:
        MOV     [EBP].OPERATION_TYPE,ADD_OP
        JMP     SHORT AT_TO_OP2

CASE_2:
        INC     DWORD_EXPON1                    ; MAKE PI
CASE_1:
        MOV     [EBP].OPERATION_TYPE,SUB_OP

AT_TO_OP2:
        PUSH    EDX
        LEA     EDI,[EBP].DWORD_FRAC2
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        CALL    MOVE_OP_TO_OP
        CALL    SUBADD
        POP     EDX

AT_ROUND:
        PUSH    DWORD PTR SR_MASKS
        OR      DWORD PTR SR_MASKS,0300H   ; SET PRECISION CONTROL TO PREC64
        PUSH    EDX
        CALL    POST_OP_ROUND
        POP     EDX
        POP     DWORD PTR SR_MASKS

AT_ROUND_REPORT:
        CMP     RND_HISTORY,0
        JE      AT_SIGN_ADJUST

        OR      SR_ERRORS,INEXACT_MASK
        CMP     ADDED_ONE,TRUE
        JNE     AT_SIGN_ADJUST

        OR      SR_FLAGS,A_MASK
AT_SIGN_ADJUST:

        MOV     [EBP].RESULT_SIGN,DL
AT_EXIT:
        RET

AT_NON_0        ENDP

;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
PAGE
;
TWO_ARG_TRANS           PROC

        JZ      TWO_ARG_SPECIAL_CASE?   ; BRANCH IF NO STACK ERROR

        CALL    SET_STK_U_ERROR         ; STACK UNDERFLOW OCCURRED
        TEST    SR_MASKS,INVALID_MASK   ; IF UNMASKED,JUST RETURN
        JNZ     RETURN_INDEF            ; ELSE,RETURN INDEFINITE

TWO_ARG_UNMASKED_EXIT:
        RET

RETURN_INDEF:
        CALL    PUT_INDEFINITE
        JMP     GET_RESULT_PTR

TWO_ARG_SPECIAL_CASE?:
        AND     SR_FLAGS,NOT A_MASK     ; CLEAR A-BIT INITIALLY
        MOVZX   EBX,[EBP].TAG1          ; BOTH OPERANDS VALID?
        OR      BL,[EBP].TAG2
        JNZ     TWO_ARG_SPECIAL_CASE

HANDLE_NON_SPECIAL_CASES:
        MOVZX   EBX,[EBP].OPERATION_TYPE        ; CALL LOG/SPLOG/ARCTAN2
        SUB     BL,ARCTAN_OP                    ; TO DO THE OPERATION
        JE      MAIN_CALL              ; EBX HAS OFFSET OF AT_NON_0 CONTAINER

        CMP     BL,LOG_OP - ARCTAN_OP
        JE      LOG_OF_NEG_NUM?

        CMP     DWORD_EXPON1,3FFFH
        JG      OP_UNSUPP
        JL      GET_SPLOG_OFFSET

WEED_OUT_NEG_1:
        CMP     [EBP].SIGN1,POSITIVE
        JE      OP_UNSUPP

        CMP     [EBP].DWORD_FRAC1 + FRAC32,080000000H
        JNE     OP_UNSUPP

        CMP     [EBP].DWORD_FRAC1 + FRAC64,0
        JNE     OP_UNSUPP

        JMP     ZERROR_FLIP_SIGN_Y_INF

GET_SPLOG_OFFSET:
        MOV     EBX,8                   ; EBX HAS OFFSET OF SPLOG CONTAINER
        JMP     SHORT MAIN_CALL

LOG_OF_NEG_NUM?:
        CMP     [EBP].SIGN1,POSITIVE
        JNE     OP_UNSUPP

        MOV     EBX,4                   ; EBX HAS OFFSET OF LOG CONTAINER
MAIN_CALL:
        CALL    CS:TWO_ARG_TRANS_TABLE[EBX]
GET_RESULT_PTR:
        MOV     EDI,OFFSET_RESULT
GOT_RESULT_PTR:
        MOV     ESI,OFFSET_RESULT_REC
        JMP     PUT_ARITH_RESULT
;
BOTH_OPS_DENORMD:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

        MOV     EDI,OFFSET_OPERAND1
        CALL    NORM_DENORM
OP2_DENORMD:
        MOV     EDI,OFFSET_OPERAND2
        CALL    NORM_DENORM
        JMP     HANDLE_NON_SPECIAL_CASES

ONLY_OP1_DENORMD:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

        MOV     EDI,OFFSET_OPERAND1
        CALL    NORM_DENORM
        JMP     HANDLE_NON_SPECIAL_CASES

ONLY_OP2_DENORMD:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT
        JMP     SHORT OP2_DENORMD

TWO_ARG_SPECIAL_CASE:
        TEST    BL,10H     ; AL CONTAINS [EBP].TAG1 or [EBP].TAG2
        JZ      OP1_NAN?

OP_UNSUPP:
        OR      SR_ERRORS,INVALID_MASK  ; HERE,AT LEAST ONE OP IS UNSUPPORTED.
        TEST    SR_MASKS,INVALID_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

        JMP     RETURN_INDEF

OP1_NAN?:                               ; HERE,NEITHER OP IS UNSUPPORTED.
        CMP     [EBP].TAG1,INV
        JE      OP1_SNAN?

        CMP     [EBP].TAG2,INV
        JNE     NON_NAN_SUPP_OPS

        JMP SHORT  SIGNAL_INVALID?

OP1_SNAN?:
        TEST    MSB_FRAC1,40H
        JZ      INVALID_OPERAND

OP2_ALSO_NAN?:
        CMP     [EBP].TAG2,INV
        JNE     JMP_SET_UP_NAN_RETURN

SIGNAL_INVALID?:
        TEST    MSB_FRAC2,40H
        JNZ     JMP_SET_UP_NAN_RETURN

INVALID_OPERAND:
        OR      SR_ERRORS,INVALID_MASK  ; INVALID OPERAND SETS
        TEST    SR_MASKS,INVALID_MASK
        JZ      TWO_ARG_UNMASKED_EXIT   ; I-ERROR,IF UNMASKED

JMP_SET_UP_NAN_RETURN:
        JMP     SET_UP_NAN_RETURN

NON_NAN_SUPP_OPS:
        MOV     BH,[EBP].TAG1
        MOVZX   EAX,[EBP].OPERATION_TYPE
        SUB     AL,ARCTAN_OP
        JE      GET_TAG2                ; EAX NOW HOLDS BASE OF ARCTAN TABLE

        CMP     AL,LOG_OP - ARCTAN_OP
        JE      ONLY_NEG_0_OK

        CMP     DWORD_EXPON1,3FFFH
        JL      GET_SPLOG_TABLE
        JE      WEED_OUT_NEG_1

        CMP     DWORD_EXPON1,7FFFH
        JNE     OP_UNSUPP

        CMP     [EBP].SIGN1,POSITIVE
        JNE     OP_UNSUPP

GET_SPLOG_TABLE:
        MOV     EAX,128                 ; EAX NOW HOLDS BASE OF SPLOG TABLE
        JMP     SHORT GET_TAG2

ONLY_NEG_0_OK:
        CMP     [EBP].SIGN1,POSITIVE
        JE      LOG_TABLE_BASE_TO_EAX

        CMP     BH,SPECIAL
        JNE     OP_UNSUPP

LOG_TABLE_BASE_TO_EAX:
        MOV     EAX,64                  ; EAX NOW HOLDS BASE OF LOG TABLE
GET_TAG2:
        MOV     BL,[EBP].TAG2
        TEST    BH,04H
        JZ      OP2_DENORM?

        MOV     BH,3                    ; INDICATE OP1 IS DENORM
OP2_DENORM?:
        TEST    BL,04H
        JZ      GET_INDEX

        MOV     BL,3                    ; INDICATE OP2 IS DENORM
GET_INDEX:
        AND     EBX,0303H       ; FORM INDEX TO SPECIAL OPERATION TABLE
                                ; BX=4*(4*MASKED_TAG1 + MASKED_TAG2),
                                ; WHERE MASKED_TAG =    0 FOR VALID,
        SHL     BH,2            ;                       1 FOR ZERO,
                                ;                       2 FOR INFINITY
        ADD     BL,BH           ;                       3 FOR DENORMD
        XOR     BH,BH
        SHL     EBX,2
ADD_BASE:
        ADD     EBX,EAX                 ; (E)BX = CASE OFFSET
        JMP     CS:SPECIAL_TABLE[EBX]   ; JUMP TO SPECIAL CASE

DERROR_SIGN_Y_PI_OR_0:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT   ; IF UNMASKED,RETURN

SIGN_Y_PI_OR_0:
        CMP     [EBP].SIGN2,POSITIVE
        JE      SIGN_Y_0

SIGN_Y_PI:
        MOV     EDI,OFFSET_RESULT
        CALL    MOVE_UNPACKED_HAPI_TO_EDI
        INC     DWORD_RESULT_EXPON              ; MAKE PI
        JMP     SHORT AT_SPCL_SIGN_ADJUST

DERROR_SIGN_Y_HAPI:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT           ; IF UNMASKED,RETURN

SIGN_Y_HAPI:
        MOV     EDI,OFFSET_RESULT
        CALL    MOVE_UNPACKED_HAPI_TO_EDI
        JMP     SHORT AT_SPCL_SIGN_ADJUST

AT_BOTH_0:
        CMP     [EBP].SIGN2,POSITIVE
        JNE     SIGN_Y_PI

SIGN_Y_0:
        MOV     EDI,OFFSET_RESULT
        CALL    MOVE_UNPACKED_0_TO_EDI

AT_SPCL_SIGN_ADJUST:
        MOV     DL,[EBP].SIGN1
        MOV     [EBP].RESULT_SIGN,DL
        JMP     GET_RESULT_PTR

ZERROR_FLIP_SIGN_Y_INF:
        OR      SR_ERRORS,ZERO_DIVIDE_MASK
        TEST    SR_MASKS,ZERO_DIVIDE_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

FLIP_SIGN_Y_INF:
        MOV     [EBP].DWORD_FRAC1 + FRAC32,080000000H
        MOV     DWORD PTR [EBP].SIGN1,POSITIVE + INFINTY*10000H
        MOV     DWORD_EXPON1,7FFFH
FLIP_SIGN_Y_OP1:
        MOV     EDI,OFFSET_OPERAND1
FLIP_SIGN_Y_TO_EDI:
        MOV     DL,[EBP].SIGN2
        NOT     DL
        MOV     [EBP + EDI + SIGN],DL
        JMP     GOT_RESULT_PTR

;ZERROR_DERROR_FLIP_SIGN_Y_INF:
;               OR      SR_ERRORS,ZERO_DIVIDE_MASK
;               TEST    SR_MASKS,ZERO_DIVIDE_MASK
;               JZ      TWO_ARG_UNMASKED_EXIT
;               OR      SR_ERRORS,DENORM_MASK
;               TEST    SR_MASKS,DENORM_MASK
;               JZ      TWO_ARG_UNMASKED_EXIT
;               JMP     SHORT FLIP_SIGN_Y_INF

DERROR_SIGN_Y_OP1:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

SIGN_Y_OP1:
        MOV     EDI,OFFSET_OPERAND1
SIGN_Y_TO_EDI:
        MOV     DL,[EBP].SIGN2
        MOV     [EBP + EDI + SIGN],DL
        JMP     GOT_RESULT_PTR

INV_OR_OP2_SIGNED_BY_OP1_VS_1:
        CMP     DWORD_EXPON1,3FFFH
        JG      OP2
        JL      FLIP_SIGN_OP2

        CMP     [EBP].DWORD_FRAC1 + FRAC32,80000000H
        JA      OP2

        CMP     [EBP].DWORD_FRAC1 + FRAC64,0
        JNE     OP2
        JMP     OP_UNSUPP

ZERROR_FLIP_SIGN_OP2:
        OR      SR_ERRORS,ZERO_DIVIDE_MASK
        TEST    SR_MASKS,ZERO_DIVIDE_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

        JMP     SHORT FLIP_SIGN_OP2

OP2_SIGNED_BY_OP1_VS_1:
        CMP     DWORD_EXPON1,3FFFH
        JGE     OP2

FLIP_SIGN_OP2:
        NOT     BYTE PTR [EBP].SIGN2
OP2:
        MOV     EDI,OFFSET_OPERAND2
        JMP     GOT_RESULT_PTR

DERROR_FLIP_SIGN_OP2:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

        JMP     SHORT FLIP_SIGN_OP2

DERROR_EXOR_SIGNED_OP2:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

EXOR_SIGNED_OP2:
        MOV     DL,[EBP].SIGN1
        XOR     [EBP].SIGN2,DL
        JMP     SHORT OP2

DERROR_EXOR_SIGNED_OP1:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      TWO_ARG_UNMASKED_EXIT

EXOR_SIGNED_OP1:
        MOV     DL,[EBP].SIGN2
        XOR     [EBP].SIGN1,DL
OP1:
        MOV     EDI,OFFSET_OPERAND1
        JMP     GOT_RESULT_PTR


TWO_ARG_TRANS           ENDP
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
PUSH_5_DW_AT_ESI        PROC

        POP     EBX                     ; EBX  <-- RETURN ADDRESS
        PUSH    DWORD PTR [EBP + ESI]
        PUSH    DWORD PTR [EBP + ESI + FRAC64]
        PUSH    DWORD PTR [EBP + ESI + FRAC32]
        PUSH    DWORD PTR [EBP + ESI + SIGN]
        PUSH    DWORD PTR [EBP + ESI + EXPON]
        JMP     EBX

PUSH_5_DW_AT_ESI        ENDP
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
POP_5_DW_AT_ESI PROC

        POP     EBX                     ;EBX  <-- RETURN ADDRESS

        POP     DWORD PTR [EBP + ESI + EXPON]
        POP     DWORD PTR [EBP + ESI + SIGN]
        POP     DWORD PTR [EBP + ESI + FRAC32]
        POP     DWORD PTR [EBP + ESI + FRAC64]
        POP     DWORD PTR [EBP + ESI]

        JMP     EBX

POP_5_DW_AT_ESI ENDP
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
MOVE_UNPACKED_1_TO_ESI  PROC

        MOV     DWORD PTR [EBP + ESI],0
        MOV     DWORD PTR [EBP + ESI + FRAC64],0
        MOV     DWORD PTR [EBP + ESI + FRAC32],080000000H
        MOV     DWORD PTR [EBP + ESI + SIGN],POSITIVE + 10000H*VALID
        MOV     DWORD PTR [EBP + ESI + EXPON],3FFFH

        RET

MOVE_UNPACKED_1_TO_ESI  ENDP
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                       EXP:
;                       """
;       FUNCTION:
;               CALCULATES 2**X - 1,WHERE 0 <= X < 1/2.
;       INPUTS:
;               ASSUMES THAT OPERAND1 IS SET UP.
;
;       OUTPUTS:
;               RESULT IN GLOBAL RECORD 12; POSSIBLE UNDERFLOW
;               AND INEXACT ERRORS.
;
;       DATA ACCESSED:
;               - OFFSET_OPERAND1               TAG1
;               - EXPON1                        WORD_FRAC1
;               - LSB_FRAC1                     OFFSET_OPERAND1
;               - SIGN2                         EXPON2
;               - OFFSET_OPERAND2               OFFSET_RESULT
;               - RESULT_TAG                    RESULT_EXPON
;               - LSB_RESULT                    MSB_RESULT
;               - OFFSET_RESULT         SISO
;               - OFFSET_COP
;
;       DATA CHANGED:
;               - EXPON1                        LSB_FRAC1
;               - SIGN2                         EXPON2
;               - RESULT_TAG                    MSB_RESULT
;               - SISO
;
;       PROCEDURES CALLED:
;               PUT_SI_RESULT           RIGHT_SHIFT             LEFT_SHIFT
;               MOVE_10_BYTES           MOVE_CONSTANT           ADDX
;               SUBX                    MULX                    DIVX
;               ADDITION_NORMALIZE      ROUND                   DIVID
;               LOG_CONSTANT            UNDERFLOW_RESPONSE      SET_P_ERROR
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
EXP_CORE        PROC
;
;PSEUDO_DIVISION
;
        MOV     SISO,0                  ; CLEAR SISO
        MOV     EAX,3FFFH
        SUB     EAX,DWORD_EXPON1        ; DWORD_EXPON1 < 3FFFH
        CMP     EAX,63
        JG      EXP_TINY_ARGUMENT

        MOV     DWORD_EXPON1,EAX
        CMP     EAX,15
        JA      EXP_RAT_APPX            ; IMPOSSIBLE THAT EAX <= 0

        CALL    RIGHT_SHIFT_FRAC1_8
EXP_LOOP_BACK_1:
        MOV     EAX,10
        MUL     DWORD_EXPON1
        ADD     EAX,A?MEDOFFSET LOG_CONSTANT - 10
        MOV     ESI,EAX
        CALL    SUB_FRAC2
        SHL     SISO,1
        CMP     MSB_RESULT,0
        JNE     EXP_MERGE_0

        CALL    MOVE_RESULT_FRAC1
        AND     DWORD PTR [EBP].DWORD_FRAC1,0FFE00000H
        INC     SISO
EXP_MERGE_0:
        INC     DWORD_EXPON1
        CMP     DWORD_EXPON1,15
        JA      EXP_BRANCH_1

        CALL    LEFT_SHIFT_FRAC1_1
        JMP     EXP_LOOP_BACK_1

EXP_TINY_ARGUMENT:
        MOV     [EBP].SIGN2,POSITIVE
        MOV     DWORD_EXPON2,3FFFH
        MOV     ESI,A?MEDOFFSET CONSTANT_2_OV_LN2
        CALL    MOVE_CONSTANT_FRAC2
        CALL    LEFT_SHIFT_FRAC2_8      ; TINY ARGUMENT
        CALL    DIVID                   ; FLOATING-POINT DIVIDE
        CALL    POST_OP_ROUND

EXP_PUT_EXP_JMP:

        JMP     EXP_PUT_EXP_F
;
;PRE_RAT_APPX
;
EXP_BRANCH_1:
        MOV     DWORD_EXPON1,15
        CALL    LEFT_SHIFT_FRAC1_8
EXP_RAT_APPX:
        CALL    MOVE_FRAC1_COP
;
;80287 SHORT MULTIPLY (DOES 67-BIT BY 34-BIT MULTIPLICATION ONLY).
;
        MOV     CL,30
        CALL    RIGHT_SHIFT_FRAC1_CL
        AND     DWORD PTR [EBP].DWORD_FRAC1,0
        MOV     CL,30
        CALL    LEFT_SHIFT_FRAC1_CL
        CALL    MULX
        CALL    MOVE_RESULT_FRAC1
        AND     DWORD PTR [EBP].DWORD_FRAC1,0E0000000H
        MOV     ESI,A?MEDOFFSET CONSTANT_LN2_OV_6
        CALL    MUL_FRAC2
        MOV     ECX,DWORD_EXPON1
        ADD     ECX,10
        CALL    RIGHT_SHIFT_RESULT_CL
        AND     DWORD PTR [EBP].RESULT_DWORD_FRAC,0FFE00000H
        CALL    MOVE_COP_FRAC1
        CALL    RIGHT_SHIFT_FRAC1_8
        CALL    MOVE_RESULT_FRAC2
        CALL    SUBX
        MOV     ECX,DWORD_EXPON1
        INC     ECX
        CALL    RIGHT_SHIFT_RESULT_CL
        AND     DWORD PTR [EBP].RESULT_DWORD_FRAC,0FFE00000H
        CALL    MOVE_RESULT_FRAC2
        MOV     ESI,A?MEDOFFSET CONSTANT_2_OV_LN2
        CALL    SUB_FRAC1
        CALL    MOVE_COP_FRAC1
        CALL    MOVE_RESULT_FRAC2
        CALL    LEFT_SHIFT_FRAC2_8
; The following call used to be to DIVX instead of ACCEL_DIVX:
        CALL    ACCEL_DIVX
        MOV     ECX,8
        CALL    RIGHT_SHIFT_RESULT_CL
        AND     DWORD PTR [EBP].RESULT_DWORD_FRAC,0FFE00000H

;
;PSEUDO_MULTIPLY
;
EXP_LOOP_BACK_2:
        SHR     SISO,1
        JNB     EXP_MERGE_2
        CALL    MOVE_RESULT_FRAC1
        CALL    MOVE_RESULT_FRAC2
        MOV     ECX,DWORD_EXPON1
        CALL    RIGHT_SHIFT_FRAC2_CL
        AND     DWORD PTR [EBP].DWORD_FRAC2,0FFE00000H
        OR      WORD_FRAC2 + 8,80H
        CALL    ADDX
EXP_MERGE_2:
        CMP     SISO,0
        JE      EXP_ALMOST_END

        CALL    RIGHT_SHIFT_RESULT_1
        AND     DWORD PTR [EBP].RESULT_DWORD_FRAC,0FFE00000H
        DEC     DWORD_EXPON1
        JMP     EXP_LOOP_BACK_2

EXP_ALMOST_END:
        MOV     CL,8
        CMP     MSB_RESULT,0
        JE      EXP_MERGE_3

        MOV     CL,7
        DEC     DWORD_EXPON1
EXP_MERGE_3:
        CALL    LEFT_SHIFT_RESULT_CL
        MOV     EAX,3FFFH
        SUB     EAX,DWORD_EXPON1
        MOV     DWORD_RESULT_EXPON,EAX
        MOV     DWORD PTR [EBP].RESULT_SIGN,POSITIVE + VALID*10000H
        TEST    MSB_RESULT,80H
        JNE     EXP_ADD_HALF_ROUND
;
;NORMALIZE X
;
        MOV     CL,1
        CALL    LEFT_SHIFT_RESULT_CL
        DEC     DWORD_RESULT_EXPON
EXP_ADD_HALF_ROUND:
        CALL    MOVE_RESULT_FRAC1
        CALL    ADD_HALF1_FRAC2

EXP_PUT_EXP_F:

        RET

EXP_CORE        ENDP
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
NEG_EXP_CORE    PROC
        NOT     [EBP].SIGN1
        CALL    EXP_CORE
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC2
        CALL    MOVE_OP_TO_OP
        MOV     ESI,OFFSET_OPERAND1
        CALL    MOVE_UNPACKED_1_TO_ESI
        MOV     [EBP].SIGN1,NEGATIVE
        MOV     [EBP].OPERATION_TYPE,SUB_OP
        MOV     ESI,OFFSET_RESULT
        CALL    PUSH_5_DW_AT_ESI
        CALL    SUBADD
        CALL    POST_OP_ROUND
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC2
        CALL    MOVE_OP_TO_OP
        MOV     ESI,OFFSET_OPERAND1
        CALL    POP_5_DW_AT_ESI
        CALL    DIVID                   ; FLOATING-POINT DIVIDE
        CALL    POST_OP_ROUND

EXP_NEG_CORE_EXIT:

        RET

NEG_EXP_CORE    ENDP
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
EXP     PROC
        CALL    ONE_RESULT_OP1_CHK
        JNZ     EXP_NON_ZERO

GARB_OUT:
        JMP     PUT_OP1_RESULT
;
EXP_NON_ZERO:
        CMP     DWORD_EXPON1,3FFFH
        JG      GARB_OUT
        JL      MORE_THAN_HALF?

MORE_THAN_1?:
        CMP     [EBP].DWORD_FRAC1 + FRAC32,080000000H
        JA      GARB_OUT

        CMP     [EBP].DWORD_FRAC1 + FRAC64,0
        JNE     GARB_OUT

        CMP     [EBP].SIGN1,POSITIVE
        JE      GARB_OUT                ; ANSWER IS 1,ALREADY IN OP1

        DEC     DWORD_EXPON1
        JMP     SHORT GARB_OUT          ; ANSWER IS -1/2.

MORE_THAN_HALF?:
        OR      SR_ERRORS,INEXACT_MASK  ; SET INEXACT ERROR FLAG
        PUSH    DWORD PTR SR_MASKS          ; SAVE PRECISION CONTROL
        OR      DWORD PTR SR_MASKS,0300H    ; SET PRECISION CONTROL TO PREC64

        AND     DWORD PTR SR_MASKS,0FFFFF3FFH   ; SET RC = TO_NEAREST
        CMP     DWORD_EXPON1,3FFEH
        JE      MAYBE_HALF

        CMP     [EBP].SIGN1,POSITIVE
        JNE     TWEEN_NEG_HALF_AND_0
        JMP     SHORT TWEEN_0_AND_HALF

MAYBE_HALF:
        CMP     [EBP].DWORD_FRAC1 + FRAC32,080000000H
        JA      TWEEN_HALF_AND_1

        CMP     [EBP].DWORD_FRAC1 + FRAC64,0
        JNE     TWEEN_HALF_AND_1

        CMP     [EBP].SIGN1,POSITIVE
        JNE     TWEEN_NEG_HALF_AND_0

TWEEN_0_AND_HALF:
        CALL    EXP_CORE
;
;ERROR CHECKING
;
EXP_UFLOW?:
        MOV     EAX ,DWORD_RESULT_EXPON
        CMP     EAX,0
        JG      EXP_VALID_TAG
        JL      EXP_UNDERFLOW

        MOV     EDI,OFFSET_RESULT + FRAC64
        CALL    TEST_4W                         ; NOTE THAT AX IS 0 HERE.
        JNZ     EXP_UNDERFLOW

EXP_ZERO_TAG:
        OR      SR_ERRORS,UNDERFLOW_MASK
        MOV     [EBP].RESULT_TAG,SPECIAL
        JMP     SHORT EXP_EXIT

EXP_UNDERFLOW:
        CALL    UNDERFLOW_RESPONSE
        OR      SR_ERRORS,UNDERFLOW_MASK
        JMP     SHORT EXP_EXIT

EXP_VALID_TAG:
        MOV     [EBP].RESULT_TAG,VALID          ;VALID RESULT
EXP_EXIT:
        CMP     ADDED_ONE,TRUE
        JNE     EXP_RESTORE

        OR      SR_FLAGS,A_MASK
EXP_RESTORE:
        POP     DWORD PTR SR_MASKS  ; RESTORE PRECISION AND ROUNDING CONTROLS
        MOV     EDI,OFFSET_RESULT
        JMP     PUT_SI_RESULT

TWEEN_NEG_HALF_AND_0:
        CALL    NEG_EXP_CORE
        JMP     SHORT EXP_UFLOW?

TWEEN_HALF_AND_1:
        CMP     [EBP].SIGN1,POSITIVE
        JNE     TWEEN_NEG_1_AND_NEG_HALF

        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        MOV     [EBP].OPERATION_TYPE,SUB_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        CALL    NEG_EXP_CORE
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        MOV     [EBP].OPERATION_TYPE,ADD_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND
        INC     DWORD_RESULT_EXPON
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        MOV     [EBP].OPERATION_TYPE,SUB_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND
        JMP     EXP_VALID_TAG

TWEEN_NEG_1_AND_NEG_HALF:
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        MOV     [EBP].OPERATION_TYPE,ADD_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        CALL    EXP_CORE
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        MOV     [EBP].OPERATION_TYPE,ADD_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        DEC     DWORD_EXPON1
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        MOV     [EBP].OPERATION_TYPE,SUB_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND
        JMP     EXP_VALID_TAG

EXP     ENDP
PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                       LOG:
;                       """
;       FUNCTION:
;               CALCULATES Y TIMES LOG(X) OR Y TIMES LOG(1 + X).
;
;       INPUTS:
;               ASSUMES THAT OPERAND1 AND OPERAND2 ARE SET UP;
;               OP1 = X,OP2 = Y.
;
;       OUTPUTS:
;               POSSIBLE UNDERFLOW,OVERFLOW,OR INEXACT ERRORS
;
;       DATA ACCESSED:
;               - OPERATION_TYPE                OFFSET_RESULT_REC
;               - SIGN1                         EXPON1
;               - OFFSET_OPERAND1               OFFSET_OPERAND2
;               - TAG2                          SIGN2
;               - EXPON2                        WORD_FRAC2
;               - MSB_FRAC2                     OFFSET_OPERAND2
;               - OFFSET_RESULT                 RESULT_TAG
;               - RESULT_SIGN                   RESULT_EXPON
;               - RESULT_WORD_FRAC              MSB_RESULT
;               - MSB_RESULT                    OFFSET_RESULT
;               - RESULT2_TAG                   RESULT2_SIGN
;               - MSB_RESULT2                   LOG_LOOP_CT
;               - OFFSET_COP                    OFFSET_DOP
;               - SISO
;
;       DATA CHANGED:
;               - SIGN1                         SIGN2
;               - MSB_FRAC2                     WORD_FRAC2
;               - RESULT_TAG                    RESULT_SIGN
;               - RESULT_FRAC                   OFFSET_RESULT
;               - RESULT2_TAG                   RESULT2_SIGN
;               - MSB_RESULT2                   LOG_LOOP_CT
;               - SISO
;
;       PROCEDURES CALLED:
;
;   PUT_RESULT              RIGHT_SHIFT             LEFT_SHIFT
;   MOVE_10_BYTES           MOVE_CONSTANT           ADDX
;   SUBX                    MULX                    ACCEL_DIVX (for LOG_DIVX)
;   ONE_LEFT_NORMALIZE      ADDITION_NORMALIZE      LOG_CONSTANT
;   TEST_5W                 SUBTRACTION_NORMALIZE   TEST_4W
;   UNDERFLOW_RESPONSE      OVERFLOW_RESPONSE       DECOMPOSE
;   POP_FREE                SP_SUBADD               MULT
;   ROUND                   GET_PRECISION           SET_P_ERROR
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
LOG     PROC

        MOV     [EBP].RESULT2_TAG,VALID
        JMP     SHORT LOG_ENTRY

SPLOG:
        MOV     [EBP].RESULT2_TAG,SPECIAL       ; FLAG FOR SPECIAL LOG

LOG_ENTRY:
        PUSH    DWORD PTR SR_MASKS              ; SAVE PRECISION CONTROL
        OR      DWORD PTR SR_MASKS,0300H      ;SET PRECISION CONTROL TO PREC64
        MOV     EDI,OFFSET_COP + FRAC80
        CALL    MOVE_FRAC2                      ; TEMP STORE Y,COP <- FRAC(Y)
        MOV     AL,[EBP].TAG2
        MOV     LSB_COP,AL
        MOV     EAX,DWORD_EXPON2                ; LOG_LOOP_CT <- EXPO(Y)
        MOV     LOG_LOOP_CT,EAX
        MOV     AL,[EBP].SIGN2                  ; LSB_RESULT2 <- SIGN2
        MOV     LSB_RESULT2,AL
        MOV     [EBP].RESULT2_SIGN,POSITIVE     ; USED FOR SIGN OF RESULT
        CMP     [EBP].RESULT2_TAG,VALID         ; AFTER LOG CORE
        JNZ     LOG_SPECIAL_LOG                 ; RESULT SIGN SAME AS RESULT2

        CALL    RIGHT_SHIFT_FRAC1_8
        MOV     ESI,A?MEDOFFSET CONSTANT_SQRT_OF_2
        CALL    SUB_FRAC2
        CMP     MSB_RESULT,0
        JNE     LOG_SMALL_LG
        JMP     LOG_LARGE_LG

LOG_SP_NEGATIVE_X:
        CALL    MOVE_FRAC1_RESULT
        MOV     [EBP].RESULT2_SIGN,NEGATIVE
        JMP     LOG_CORE

LOG_SPECIAL_LOG:
        MOV     EAX,DWORD_EXPON1                ; LOG X NOT 0
        MOV     DWORD_RESULT_EXPON,EAX
        CMP     [EBP].SIGN1,POSITIVE
        JNE     LOG_SP_NEGATIVE_X

        CALL    MOVE_FRAC1_FRAC2
        MOV     ECX,3FFFH
        SUB     ECX,DWORD_EXPON1
        CMP     ECX,72
        JBE     LOG_SP_LABEL_1

        MOV     ECX,72
LOG_SP_LABEL_1:
        CALL    RIGHT_SHIFT_FRAC2_CL
        MOV     CX,WORD_FRAC2
        AND     ECX,1FFFH
        OR      EDX,ECX
        JZ      LOG_NON_STICKY

        OR      WORD_FRAC2,2000H
LOG_NON_STICKY:
        OR      MSB_FRAC2,80H
        AND     [EBP].DWORD_FRAC2,0E0000000H
        JMP     SHORT LOG_DIV

; FRAC(X) < SQRT(2)
;
LOG_SMALL_LG:
        CALL    LEFT_SHIFT_FRAC1_8
        CALL    MOVE_FRAC1_RESULT
        MOV     ECX,1
        CALL    LEFT_SHIFT_RESULT_CL
        MOV     EDI,OFFSET_RESULT + FRAC80
        CALL    TEST_5W
        JZ      LOG_POWER_OF_TWO

        MOV     DWORD_RESULT_EXPON,3FFEH
        MOV     EDI,OFFSET_RESULT
        CALL    SUBTRACTION_NORMALIZE
        CALL    MOVE_FRAC1_FRAC2
        CALL    MOVE_RESULT_FRAC1
LOG_DIV:
; The following call used to be to LOG_DIVX instead of ACCEL_DIVX:
        PUSH    LOG_LOOP_CT
        CALL    ACCEL_DIVX
        POP     LOG_LOOP_CT
        AND     [EBP].RESULT_DWORD_FRAC,0E0000000H      ; MASK RESULT FRAC
        JMP     LOG_MERGE_LG
;
; X = 2 ** N
;
LOG_POWER_OF_TWO:
        CALL    DECOMPOSE
LOG_MUL:
        MOV     EDI,OFFSET_OPERAND1 + FRAC80
        CALL    TEST_5W
        JNZ     LOG_X_NOT_0

LOG_SPLOG_ZERO:
        MOV     BYTE PTR [EBP].TAG1,SPECIAL     ; ZERO TAG
        MOV     AL,LSB_RESULT2
        XOR     [EBP].SIGN1,AL
        LEA     ESI,[EBP].DWORD_FRAC1
        LEA     EDI,[EBP].RESULT_DWORD_FRAC
        CALL    MOVE_OP_TO_OP
        JMP     LOG_RESTORE_USER_CONTROLS

LOG_X_NOT_0:
        AND     [EBP].DWORD_COP,0FF000000H
        CALL    MOVE_COP_FRAC2                  ; RESTORE Y INTO OP2
        MOV     EAX,LOG_LOOP_CT
        MOV     DWORD_EXPON2,EAX
        MOV     AL,LSB_RESULT2
        MOV     [EBP].SIGN2,AL
        CALL    MULT
        CALL    POST_OP_ROUND                   ; ROUND THE RESULT
;
;ERROR CHECKING
;
        MOV     EAX,DWORD_RESULT_EXPON
        CMP     EAX,7FFEH
        JG      LOG_OVERFLOW

        CMP     EAX,0
        JL      LOG_UNDERFLOW
        JG      LOG_SET_TAG_VALID

        MOV     EDI,OFFSET_RESULT + FRAC64
        CALL    TEST_4W                         ; EAX = 0 HERE
        JNZ     LOG_UNDERFLOW
;
;ZERO RESULT
;
        MOV     [EBP].RESULT_TAG,SPECIAL
        JMP     SHORT LOG_ROUND_REPORT

LOG_SET_TAG_VALID:
        MOV     [EBP].RESULT_TAG,VALID
LOG_ROUND_REPORT:
        CMP     RND_HISTORY,0
        JE      LOG_RESTORE_USER_CONTROLS

        OR      SR_ERRORS,INEXACT_MASK
        CMP     ADDED_ONE,TRUE
        JNE     LOG_RESTORE_USER_CONTROLS

        OR      SR_FLAGS,A_MASK
LOG_RESTORE_USER_CONTROLS:
        POP     DWORD PTR SR_MASKS
LOG_EXIT:
        RET

LOG_OVERFLOW:
        CALL    OVERFLOW_RESPONSE
        JMP     SHORT LOG_RESTORE_USER_CONTROLS

LOG_UNDERFLOW:
        CALL    UNDERFLOW_RESPONSE
        JMP     SHORT LOG_RESTORE_USER_CONTROLS

;FRAC(X) > SQRT(2)
;
LOG_LARGE_LG:
        INC     DWORD_EXPON1
        CALL    MOVE_FRAC1_FRAC2
        MOV     ESI,A?MEDOFFSET CONSTANT_ONE
        CALL    SUB_FRAC1
        MOV     ECX,7
        CALL    LEFT_SHIFT_RESULT_CL
        MOV     [EBP].RESULT2_SIGN,NEGATIVE     ; SET FLAG FOR LARGE LOG
        MOV     DWORD_RESULT_EXPON,3FFFH
LOG_MERGE_LG:
        MOV     EDI,OFFSET_RESULT + FRAC80      ; DON'T NORMALIZE A ZERO
        CALL    TEST_5W                         ; IS THE RESULT ZERO?
        JZ      LOG_CORE                        ; YES,NO NEED TO NORMALIZE
        MOV     EDI,OFFSET_RESULT
        CALL    SUBTRACTION_NORMALIZE
LOG_CORE:
        CALL    MOVE_RESULT_FRAC2
        MOV     SISO,0                          ; CLEAR SISO
        MOV     EAX,3FFFH
        SUB     EAX,DWORD_RESULT_EXPON
        MOV     DWORD_EXP_TMP,EAX
        CMP     EAX,15
        JA      LOG_RAT_APX

        CALL    MOVE_RESULT_FRAC1               ; LOG PSEUDO DIVIDE
        MOV     ECX,7
        ADD     ECX,DWORD_EXP_TMP
        CALL    RIGHT_SHIFT_FRAC1_CL
        CALL    RIGHT_SHIFT_FRAC2_8
        CALL    ADDX
        CMP     MSB_RESULT,0
        JE      LOG_LOOP_BACK_1

        AND     [EBP].RESULT_DWORD_FRAC,0FFE00000H
        MOV     MSB_RESULT,0
        CALL    MOVE_RESULT_FRAC2
        MOV     SISO,1
LOG_LOOP_BACK_1:
        SHL     SISO,1
        CALL    MOVE_FRAC2_FRAC1
        MOV     ECX,DWORD_EXP_TMP
        CALL    RIGHT_SHIFT_FRAC1_CL
        OR      DWORD PTR [EBP].DWORD_FRAC1 + FRAC32,00800000H
        CALL    ADDX
        CMP     MSB_RESULT,0
        JE      LOG_MERGE_2

        AND     DWORD PTR [EBP].RESULT_DWORD_FRAC,0FFE00000H
        MOV     MSB_RESULT,0
        CALL    MOVE_RESULT_FRAC2
        INC     SISO
LOG_MERGE_2:
        MOV     ECX,1
        CALL    LEFT_SHIFT_FRAC2_CL
        INC     DWORD_EXP_TMP
        CMP     DWORD_EXP_TMP,15
        JBE     LOG_LOOP_BACK_1

        CALL    LEFT_SHIFT_FRAC2_8
;
;RATIONAL APPROXIMATION
;
LOG_RAT_APX:
        OR      SR_ERRORS,INEXACT_MASK          ; SET P FLAG
        CALL    MOVE_FRAC2_FRAC1
        CALL    MULX
        MOV     ECX,DWORD_EXP_TMP
        CMP     ECX,72
        JBE     LOG_LABEL_4

        MOV     ECX,72
LOG_LABEL_4:
        CALL    RIGHT_SHIFT_RESULT_CL
        AND     [EBP].RESULT_DWORD_FRAC,0E0000000H      ; MASK RESULT FRAC
        CALL    MOVE_RESULT_FRAC2
        CALL    SUBX
        CALL    MOVE_RESULT_DOP
        MOV     ECX,DWORD_EXP_TMP
        CMP     ECX,72
        JBE     LOG_LABEL_5

        MOV     ECX,72
LOG_LABEL_5:
        CALL    RIGHT_SHIFT_FRAC1_CL
        AND     [EBP].DWORD_FRAC1,0E0000000H
        CALL    MOVE_FRAC1_FRAC2
        MOV     ESI,A?MEDOFFSET CONSTANT_SIX
        CALL    SUB_FRAC1
        CALL    MOVE_RESULT_FRAC1
        CALL    MOVE_DOP_FRAC2
        MOV     ECX,DWORD_EXP_TMP
        INC     ECX
        CMP     ECX,72
        JBE     LOG_LABEL_6

        MOV     ECX,72
LOG_LABEL_6:
        CALL    RIGHT_SHIFT_FRAC2_CL
        AND     [EBP].DWORD_FRAC2,0F0000000H
        CALL    SUBX
        AND     [EBP].RESULT_DWORD_FRAC,0E0000000H      ; MASK RESULT FRAC
        CALL    MOVE_DOP_FRAC1
        CALL    MOVE_RESULT_FRAC2
; The following call used to be to LOG_DIVX instead of ACCEL_DIVX:
        PUSH    LOG_LOOP_CT
        CALL    ACCEL_DIVX
        POP     LOG_LOOP_CT
        AND     [EBP].RESULT_DWORD_FRAC,0E0000000H      ; MASK RESULT FRAC
        CALL    MOVE_RESULT_FRAC1
        MOV     ESI,A?MEDOFFSET CONSTANT_3_OV_LN2
        CALL    MUL_FRAC2
        MOV     ECX,7
        CALL    RIGHT_SHIFT_RESULT_CL
        DEC     DWORD_EXP_TMP
LOG_LOOP_BACK_2:
        SHR     SISO,1
        JNB     LOG_NO_CARRY

        MOV     ESI,DWORD_EXP_TMP
        DEC     ESI
        MOV     EAX,10
        MUL     ESI
        MOV     ESI,EAX
        ADD     ESI,A?MEDOFFSET LOG_CONSTANT
        CALL    MOVE_CONSTANT_FRAC2
        CALL    MOVE_RESULT_FRAC1
        CALL    ADDX
LOG_NO_CARRY:
        CMP     SISO,0
        JZ      LOG_END_LOOP

        CALL    RIGHT_SHIFT_RESULT_1
        DEC     DWORD_EXP_TMP
        JMP     SHORT LOG_LOOP_BACK_2

LOG_END_LOOP:
        MOV     EAX,4007H                       ;4007 = 3FFF + 8
        SUB     EAX,DWORD_EXP_TMP
        MOV     DWORD_RESULT_EXPON,EAX
        AND     [EBP].RESULT_DWORD_FRAC,0FFE00000H
        MOV     EDI,OFFSET_RESULT               ; DON'T NORMALIZE A ZERO
        CALL    TEST_6W                         ; IS THE RESULT ZERO?
        JZ      LOG_END_LOG_CORE                ; YES,NO NEED TO NORMALIZE

        MOV     EDI,OFFSET_RESULT
        CALL    SUBTRACTION_NORMALIZE
LOG_END_LOG_CORE:
        CMP     [EBP].RESULT2_TAG,VALID
        JNZ     LOG_SPECIAL_LOG_END

        CALL    DECOMPOSE
        CALL    MOVE_RESULT_FRAC2
        MOV     EAX,DWORD_RESULT_EXPON
        MOV     DWORD_EXPON2,EAX
        MOV     [EBP].OPERATION_TYPE,ADD_OP
        MOV     AL,[EBP].RESULT2_SIGN
        MOV     [EBP].SIGN2,AL
        CALL    SP_SUBADD
LOG_MERGE_4:
        CALL    MOVE_RESULT_FRAC1
        MOV     AL,[EBP].RESULT_SIGN
        MOV     [EBP].SIGN1,AL
        MOV     EAX,DWORD_RESULT_EXPON
        MOV     DWORD_EXPON1,EAX
        JMP     LOG_MUL

LOG_SPECIAL_LOG_END:
        MOV     AL,[EBP].RESULT2_SIGN
        MOV     [EBP].RESULT_SIGN,AL
        JMP     LOG_MERGE_4

;DO ROUND               ; MADE INTO COMMON SUBROUTINE FOR ALL
;
LOG_ROUND:
        MOV     LSB_RESULT,1            ; FIXED UP SUCH THAT
;       CALL    GET_PRECISION
POST_OP_ROUND:
        MOV     DL,PREC64
        MOV     EDI,OFFSET_RESULT       ; S = 1 ALWAYS
        MOV     AL,FALSE                ; NOT SECOND ROUNDING
        CALL    ROUND
        MOV     EDI,OFFSET_RESULT
        MOV     AH,4                    ; FALL THROUGH

LOG     ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
;               ADDITION_NORMALIZE:
;
;       FUNCTION:
;               PERFORMS NORMALIZATION AFTER ADDITION IF NECESSARY.
;
;       INPUTS:
;               CARRY-OUT FROM ADDITION IN AL UPON ENTRY.
;               FRACTION OFFSET IN DI.
;
;       OUTPUTS:
;               INCREMENTS EXPONENT AND SHIFTS 1 BIT IN FROM LEFT IF AL=1.
;
;       DATA ACCESSED:
;
;       DATA CHANGED:
;
;       PROCEDURES CALLED:
;               STICKY_RIGHT_SHIFT
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
ADDITION_NORMALIZE      PROC

        TEST    AL,01H                  ;IF LOW BIT OF AL = 1,
        JNZ     RIGHT_SHIFT_1           ; THEN SHIFT RIGHT 1

        RET                             ; ELSE,EXIT

RIGHT_SHIFT_1:
        INC     DWORD PTR [EBP + EDI + EXPON]   ;INCREMENT EXPONENT
        MOV     CL,1                            ;SHIFT RIGHT 1 BIT

ADDITION_NORMALIZE      ENDP            ; STICKY_RIGHT_SHIFT

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                       STICKY_RIGHT_SHIFT:
;                       """"""""""""""""""
;       FUNCTION:
;               SHIFTS A 10-BYTE NUMBER RIGHT BY AMOUNT IN
;               CL REGISTER.  DI CONTAINS OFFSET OF NUMBER.
;
;       INPUTS:
;               LOW BIT OF AL CONTAINS BIT TO INJECT FROM LEFT.
;               (FOR SHIFTS OF MORE THAN ONE,THE RESULT IS UNDEFINED
;               UNLESS AL CONTAINS ZERO).
;
;       OUTPUTS:
;               THE LOW-ORDER BIT OF THE NUMBER IS "STICKY",IE,IT IS
;               LEFT AS A ONE IF ANY ONES WERE SHIFTED OUT.
;
;       DATA ACCESSED:
;
;       DATA CHANGED:
;
;       PROCEDURES CALLED:
;               RIGHT_SHIFT
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
STICKY_RIGHT_SHIFT      PROC

        CALL    RIGHT_SHIFT                             ;DO RIGHT SHIFT
        AND     EDX,EDX                                 ;EDX <> 0 IF 1'S LOST
        JZ      STICKY_RIGHT_SHIFT_DONE                 ;DONE IF NO 1'S LOST

        OR      BYTE PTR [EBP + EDI + FRAC80],01H       ;ELSE,SET STICKY BIT

STICKY_RIGHT_SHIFT_DONE:

        RET

STICKY_RIGHT_SHIFT      ENDP

PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                           GRADUAL_UNDERFLOW:
;
;       FUNCTION:
;               CHANGES AN "UNDERFLOWED" NUMBER TO A LEGAL,
;               DENORMALIZED NUMBER.
;
;       INPUT:
;               ADDRESS OF EXPONENT AND FRACTION IN OPERANDS OR RESULT
;               (PTR IN DI REGISTER); MINIMUM LEGAL EXPONENT(IN
;               AX REGISTER).
;
;       OUTPUT:
;               DENORMALIZED FRACTION AND ADJUSTED EXPONENT (IN INPUT
;               RECORD)
;
;       DATA ACCESSED:;         - EXPON                 WORD_FRAC
;
;       DATA CHANGED:
;               - EXPON                 WORD_FRAC
;
;       PROCEDURES CALLED:
;               STICKY_RIGHT_SHIFT
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
GRADUAL_UNDERFLOW       PROC

        MOV     ECX,EAX                 ; SET EXPONENT TO MINIMUM
        XCHG    EAX,[EBP + EDI + EXPON]
        SUB     ECX,EAX                 ; FORM SHIFT AMOUNT
        CMP     ECX,67                  ; (EXPONENT - MINIMUM EXPONENT)
        JLE     DO_RIGHT_SHIFT

        MOV     ECX,67                  ; SHIFT AMOUNT MUST BE <= 67
DO_RIGHT_SHIFT:
        XOR     AL,AL                   ; BYTE TO BE SHIFTED IN FROM
        JMP SHORT STICKY_RIGHT_SHIFT    ; THE LEFT

GRADUAL_UNDERFLOW       ENDP
PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                                       TWO_RESULT_OP1_CHK
;
; ACTION:
;     FOR SINCOS AND (TWO RESULT) TAN, CHECKS THE FOLLOWING AND RESPONDS AS
;     DESCRIBED:
;     1.  WHETHER FETCH_AN_OP DISCOVERED THAT THE SOURCE FROM WHICH
;     OPERAND1 WAS TO HAVE BEEN TAKEN WAS EMPTY.  IF SO,SETS STACK
;     UNDERFLOW EXCEPTION,CLEARS C-FLAG (INDICATING NOT INCOMPLETE
;     REDUCTION),POPS THE RETURN ADDRESS OF ITS CALLER SO THAT IT
;     RETURNS DIRECTLY TO THE E80387 EXECUTIVE ROUTINE,AND,IF THE
;     INVALID EXCEPTION IS UNMASKED,MAKES THAT RETURN FORTHWITH.
;     IF THE INVALID EXCEPTION IS MASKED,THIS PROCEDURE PREPARES TO
;     RETURN VIA A JUMP TO PUT_RESULT BY FIRST SETTING EDI SO THAT
;     THE NAN INDEFINITE PUT IN OPERAND1 BY FETCH_AN_OP WILL BE
;     RETURNED,AND SETTING ESI SO THAT THIS RETURNED VALUE WILL BE
;     PUSHED ONTO THE STACK.  NOTE THAT AFTER THIS PUSH,THE FORMER
;     STACK TOP IS UNCHANGED; I.E.,IF IT WAS EMPTY AS STACK TOP,IT'S
;     STILL EMPTY AS ST(1).
;     2.  IF OPERAND1 WAS FETCHED FROM A NON-EMPTY SOURCE,CLEARS
;     C-FLAG (INDICATING NOT INCOMPLETE REDUCTION) AND THEN CHECKS
;     WHETHER A PUSH WILL BE TO A FULL POSITION.  IF SO,SETS ZF SO
;     THAT RETURN TO E80387 EXECUTIVE AFTER POPPING CALLER'S RETURN
;     ADDRESS AND JUMPING TO PUT_RESULT DOES NOT FALSELY SIGNAL
;     MASKED STACK UNDERFLOW INSTEAD OF CORRECTLY SIGNALING STACK
;     OVERFLOW.
;     3.  IF PUSH WOULD BE TO AN EMPTY POSITION,INITIALIZES THE
;     BEFORE_ERROR_SIGNALS USED BY PUT_RESULT,CLEARS THE A-FLAG,
;     AND CHECKS TAG OF OPERAND1.
;             A.  IF TAG IS UNSUPP OR INFINTY,REPLACES OPERAND1 BY
;             THE NAN INDEFINITE,THEN CHECKS WHETHER INVALID OPERATION
;             IS MASKED.  IF NOT MASKED,SETS INVALID OPERATION EXCEPTION
;             FLAG AND POPS CALLER'S RETURN ADDRESS SO THAT RETURN IS TO
;             E80387 EXECUTIVE.  IF MASKED,COPIES THE QUIET NAN IN
;             OPERAND1 TO OPERAND2,SETS THE SIGNAL_I_ERROR? COMPONENT OF
;             BEFORE_ERROR_SIGNALS TO TRUE,AND RETURNS TO E80387
;             EXECUTIVE BY POPPING CALLER'S RETURN ADDRESS AND JUMPING TO
;             DO_EXCHANGE.
;             B.  IF TAG IS INV,CHECKS WHETHER THE NAN IN OPERAND1 IS
;             SIGNALING.  IF NOT,SETS ZF,POPS CALLER'S RETURN ADDRESS,
;             SETS EDI AND ESI SO THAT JUMP TO PUT_RESULT CAUSES THE
;             QUIET NAN IN OPERAND1 TO BE PUSHED ONTO '87 STACK.  IF THE
;             NAN IS SIGNALING,SETS ITS LEADING FRACTION BIT,THEREBY
;             "QUIETING" IT,AND PROCEEDS AS IN "A" ABOVE,BUT WITH THE
;             "QUIETIZED" NAN IN PLACE OF THE NAN INDEFINITE.
;             C.  IF TAG IS DENORMD,CHECKS WHETHER DENORMAL EXCEPTION
;             IS MASKED.  IF NOT MASKED,SETS DENORMAL EXCEPTION FLAG AND
;             POPS CALLER'S RETURN ADDRESS SO THAT RETURN IS TO E80387
;             EXECUTIVE.  IF MASKED,SETS THE SIGNAL_D_ERROR COMPONENT OF
;             BEFORE_ERROR_SIGNALS TO TRUE,NORMALIZES OPERAND1 AND FORCES
;             ZF = 0 (INDICATING NON-ZERO OPERAND1) BEFORE RETURNING TO
;             CALLER.
;             D.  IF TAG IS VALID OR SPECIAL (SIGNED,TRUE ZERO),RETURNS
;             TO CALLER WITH ZF CLEAR OR SET,RESPECTIVELY.
;
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
TWO_RESULT_OP1_CHK     PROC

        JZ     IS_STACK_FULL?           ; IF NO STACK UNDERFLOW,GO ON

        CALL   SET_STK_U_ERROR          ; ELSE,PREPARE FOR ERROR EXIT
        AND    SR_FLAGS,NOT C_MASK      ; CLEAR '87 C-FLAG
        TEST   SR_MASKS,INVALID_MASK
        JNZ    PUSH_OP1                 ; MASKED STACK ERROR,SO RETURN INDEF

UNMASKED_EXIT:
        POP    EAX              ; POP ADDRESS OF TRANSCENDENTAL CALLER SO

TWO_RES_QUIK_EXIT:              ; RETURN IS TO E80387 EXECUTIVE PROCEDURE.

        RET

PUSH_OP1:
        MOV    EDI,OFFSET_OPERAND1
        MOV    ESI,OFFSET_RESULT2_REC
        POP    EAX              ; POP ADDRESS OF TRANSCENDENTAL CALLER
        LAHF                    ; SAVE ZF TO SHOW IF MASKED STACK UNDERFLOW
        JMP    PUT_RESULT       ; RETURN IS TO E80387 EXECUTIVE PROCEDURE.

IS_STACK_FULL?:
        AND    SR_FLAGS,NOT C_MASK      ; CLEAR '87 C-FLAG
        CALL   STACK_FULL?
        JZ     CNTNU_CHK

SET_ZF:
        XOR    EAX,EAX
        JMP    SHORT PUSH_OP1

CNTNU_CHK:
        MOV    [EBP].BEFORE_ERROR_SIGNALS,0
        AND    SR_FLAGS,NOT A_MASK
        MOV    AL,[EBP].TAG1            ; LOAD TAG FOR OP1
        CMP    AL,SPECIAL
        JBE    OK_OP

        CMP    AL,DENORMD
        JB     INV_OP
        JE     SIGNAL_D_ERROR      ; ELSIF DENORMALIZED,THEN SIGNAL D_ERROR

        MOV    EDI,OFFSET_OPERAND1      ; INFINITY OR UNSUPPORTED,
        CALL   SET_UP_INDEFINITE        ; SET UP MASKED RESULT
        JMP     SHORT TEST_INVALID_MASK

INV_OP:
        TEST    MSB_FRAC1,40H           ; ELSIF OP1 NAN,FIND WHAT KIND
        JNZ     SET_ZF                  ; OP1 IS A  QNAN,SO LOAD IT TO TOS

        OR      MSB_FRAC1,40H           ; MAKE NAN QUIET
TEST_INVALID_MASK:
        TEST    SR_MASKS,INVALID_MASK
        JNZ     COPY_NAN

        OR      SR_ERRORS,INVALID_MASK
        JMP     SHORT UNMASKED_EXIT

COPY_NAN:
        LEA     ESI,[EBP].DWORD_FRAC1   ; COPY OP1 TO OP2
        LEA     EDI,[EBP].DWORD_FRAC2
        CALL    MOVE_OP_TO_OP
SIGNAL_I_ERROR:
        MOV     SIGNAL_I_ERROR?,TRUE
        POP     EAX
        JMP     DO_EXCHANGE

SIGNAL_D_ERROR:
        TEST    SR_MASKS,DENORM_MASK
        JNZ     SET_UP_D_ERROR

        OR      SR_ERRORS,DENORM_MASK
        JMP     UNMASKED_EXIT

SET_UP_D_ERROR:
        MOV     SIGNAL_D_ERROR?,TRUE; OP1 IS DENORMAL OR PSEUDO-DENORMAL
        MOV     EDI,OFFSET_OPERAND1
        CALL    NORM_DENORM             ; IF D_ERROR MASKED,MAKE VALID
        OR      EAX,1                   ; FORCE ZF = 0
OK_OP:
        RET                             ; ZF = 1 IFF OP1 IS TRUE ZERO

TWO_RESULT_OP1_CHK      ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                                  ONE_RESULT_OP1_CHK
;
;  ACTION:
;      FOR SIN AND COS,CHECKS THE FOLLOWING AND RESPONDS AS
;      DESCRIBED:
;      1.  WHETHER FETCH_AN_OP DISCOVERED THAT THE SOURCE FROM WHICH
;      OPERAND1 WAS TO HAVE BEEN TAKEN WAS EMPTY.  IF SO,SETS STACK
;      UNDERFLOW EXCEPTION,CLEARS C-FLAG (INDICATING NOT INCOMPLETE
;      REDUCTION),POPS THE RETURN ADDRESS OF ITS CALLER SO THAT IT
;      RETURNS DIRECTLY TO THE E80387 EXECUTIVE ROUTINE,AND,IF THE
;      INVALID EXCEPTION IS UNMASKED,MAKES THAT RETURN FORTHWITH.
;      IF THE INVALID EXCEPTION IS MASKED,THIS PROCEDURE PREPARES TO
;      RETURN VIA A JUMP TO PUT_RESULT BY FIRST SETTING EDI SO THAT
;      THE NAN INDEFINITE PUT IN OPERAND1 BY FETCH_AN_OP WILL BE
;      RETURNED,AND SETTING ESI SO THAT THIS RETURNED VALUE WILL BE
;      PUSHED ONTO THE STACK.  NOTE THAT AFTER THIS PUSH,THE FORMER
;      STACK TOP IS UNCHANGED; I.E.,IF IT WAS EMPTY AS STACK TOP,IT'S
;      STILL EMPTY AS ST(1).
;      2.  IF OPERAND1 WAS FETCHED FROM A NON-EMPTY SOURCE,CLEARS
;      C-FLAG (INDICATING NOT INCOMPLETE REDUCTION) AND THEN CHECKS
;      WHETHER A PUSH WILL BE TO A FULL POSITION.  IF SO,SETS ZF SO
;      THAT RETURN TO E80387 EXECUTIVE AFTER POPPING CALLER'S RETURN
;      ADDRESS AND JUMPING TO PUT_RESULT DOES NOT FALSELY SIGNAL
;      MASKED STACK UNDERFLOW INSTEAD OF CORRECTLY SIGNALING STACK
;      OVERFLOW.
;      3.  IF PUSH WOULD BE TO AN EMPTY POSITION,INITIALIZES THE
;      BEFORE_ERROR_SIGNALS USED BY PUT_RESULT,CLEARS THE A-FLAG,
;      AND CHECKS TAG OF OPERAND1.
;          A.  IF TAG IS UNSUPP OR INFINTY,REPLACES OPERAND1 BY
;          THE NAN INDEFINITE,THEN CHECKS WHETHER INVALID OPERATION
;          IS MASKED.  IF NOT MASKED,SETS INVALID OPERATION EXCEPTION
;          FLAG AND POPS CALLER'S RETURN ADDRESS SO THAT RETURN IS TO
;          E80387 EXECUTIVE.  IF MASKED,COPIES THE QUIET NAN IN
;          OPERAND1 TO OPERAND2,SETS THE SIGNAL_I_ERROR? COMPONENT OF
;          BEFORE_ERROR_SIGNALS TO TRUE,AND RETURNS TO E80387
;          EXECUTIVE BY POPPING CALLER'S RETURN ADDRESS AND JUMPING TO
;          DO_EXCHANGE.
;          B.  IF TAG IS INV,CHECKS WHETHER THE NAN IN OPERAND1 IS
;          SIGNALING.  IF NOT,SETS ZF,POPS CALLER'S RETURN ADDRESS,
;          SETS EDI AND ESI SO THAT JUMP TO PUT_RESULT CAUSES THE
;          QUIET NAN IN OPERAND1 TO BE PUSHED ONTO '87 STACK.  IF THE
;          NAN IS SIGNALING,SETS ITS LEADING FRACTION BIT,THEREBY
;          "QUIETING" IT,AND PROCEEDS AS IN "A" ABOVE,BUT WITH THE
;          "QUIETIZED" NAN IN PLACE OF THE NAN INDEFINITE.
;          C.  IF TAG IS DENORMD,CHECKS WHETHER DENORMAL EXCEPTION
;          IS MASKED.  IF NOT MASKED,SETS DENORMAL EXCEPTION FLAG AND
;          POPS CALLER'S RETURN ADDRESS SO THAT RETURN IS TO E80387
;          EXECUTIVE.  IF MASKED,SETS THE SIGNAL_D_ERROR COMPONENT OF
;          BEFORE_ERROR_SIGNALS TO TRUE,NORMALIZES OPERAND1 AND FORCES
;          ZF = 0 (INDICATING NON-ZERO OPERAND1) BEFORE RETURNING TO
;          CALLER.
;          D.  IF TAG IS VALID OR SPECIAL (SIGNED,TRUE ZERO),RETURNS
;          TO CALLER WITH ZF CLEAR OR SET,RESPECTIVELY.
;
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
ONE_RESULT_OP1_CHK      PROC

        JZ      CHECK_TAG1              ; IF NO STACK UNDERFLOW,GO ON

        CALL    SET_STK_U_ERROR         ; ELSE,PREPARE FOR ERROR EXIT
        AND     SR_FLAGS,NOT C_MASK     ; CLEAR '87 C-FLAG
        TEST    SR_MASKS,INVALID_MASK
        JNZ     GIVE_OP1                ; MASKED STACK ERROR,SO RETURN INDEF

ONE_RES_UNMASKED_EXIT:
        POP     EAX             ; POP ADDRESS OF TRANSCENDENTAL CALLER SO
ONE_RES_QUIK_EXIT:              ; RETURN IS TO E80387 EXECUTIVE PROCEDURE.
        RET

GIVE_OP1:
        POP     EAX                ; POP ADDRESS OF TRANSCENDENTAL CALLER SO
        JMP     PUT_OP1_RESULT     ; RETURN IS TO E80387 EXECUTIVE PROCEDURE.

CHECK_TAG1:
        AND     SR_FLAGS,NOT (A_MASK + C_MASK)
        MOV     AL,[EBP].TAG1                   ; LOAD TAG FOR OP1
        CMP     AL,SPECIAL
        JLE     OP1_OK

        CMP     AL,DENORMD
        JL      OP1_INV
        JE      OP1_DEN           ; ELSIF DENORMALIZED,THEN SIGNAL D_ERROR

        CMP     [EBP].OPERATION_TYPE,EXP_OP
        JNE     ONE_RES_UNSUP

        CMP     AL,UNSUPP
        JE      ONE_RES_UNSUP

        CMP     [EBP].SIGN1,POSITIVE    ; OP1 IS +/- INFINITY
        JE      GIVE_OP1

        MOV     DWORD_EXPON1,3FFFH
        JMP     SHORT GIVE_OP1

ONE_RES_UNSUP:
        MOV     EDI,OFFSET_OPERAND1     ; INFINITY OR UNSUPPORTED,
        CALL    SET_UP_INDEFINITE       ; SET UP MASKED RESULT
        JMP     SHORT INVALID_MASKED?

OP1_INV:
        TEST    MSB_FRAC1,40H           ; ELSIF OP1 NAN,FIND WHAT KIND
        JNZ     GIVE_OP1                ; OP1 IS A  QNAN,SO RETURN IT

        OR      MSB_FRAC1,40H           ; MAKE NAN QUIET
INVALID_MASKED?:
        OR      SR_ERRORS,INVALID_MASK
        TEST    SR_MASKS,INVALID_MASK
        JZ      ONE_RES_UNMASKED_EXIT
        JMP     SHORT GIVE_OP1

OP1_DEN:
        OR      SR_ERRORS,DENORM_MASK
        TEST    SR_MASKS,DENORM_MASK
        JZ      ONE_RES_UNMASKED_EXIT

        MOV     EDI,OFFSET_OPERAND1
        CALL    NORM_DENORM             ; IF D_ERROR MASKED,MAKE VALID
        OR      EAX,1                   ; FORCE ZF = 0
OP1_OK:
        RET                             ; ZF = 1 IFF OP1 IS TRUE ZERO

ONE_RESULT_OP1_CHK      ENDP
PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
MOD_QRTR_PI     PROC

        ; '87 C-FLAG HAS TO HAVE BEEN CLEARED BY THIS ENTRY POINT

        XOR     EAX,EAX
        MOV     AL,[EBP].OPERATION_TYPE
        MOV     AH,[EBP].SIGN1
        MOV     TRANS_INFO,EAX          ; INITIALIZE COFUNC_FLAG FALSE (00H)
                                        ; AND COS_SIGN POSITIVE (00H)
        MOV     [EBP].SIGN1,POSITIVE    ; TAKE ABSOLUTE VALUE OF OP1
        MOV     EXP_TMP,0               ; INITIALIZE Q AND HI_Q TO 0.
        MOV     EAX,DWORD_EXPON1
        SUB     EAX,3FFEH
        JL      REDUCTION_DONE

        CMP     EAX,63
        JLE     DO_REDUCTION

        OR      SR_FLAGS,C_MASK         ; INDICATE INCOMPLETE REDUCTION
        POP     EAX                     ; GET RID OF CALLER'S RETURN ADDRESS
        RET

DO_REDUCTION:
        MOV     DWORD PTR [EBP].DWORD_FRAC2 + FRAC64,2168C235H
        MOV     DWORD PTR [EBP].DWORD_FRAC2 + FRAC32,0C90FDAA2H
        MOV     DWORD PTR [EBP].DWORD_FRAC2 + SIGN,POSITIVE + 10000H*VALID
        MOV     DWORD_EXPON2,3FFEH
        SUB     DWORD_EXPON1,EAX
        INC     EAX
        CALL    REMRX
        MOV     EAX,DWORD PTR [EBP].DWORD_FRAC1 + FRAC64
        OR      EAX,DWORD PTR [EBP].DWORD_FRAC1 + FRAC32
        JNZ     MOD_NOT_0

        MOV     [EBP].DWORD_FRAC1,EAX   ; HERE,EAX = 0
        MOV     DWORD_EXPON1,EAX
        MOV     [EBP].DWORD_FRAC1 + TAG,SPECIAL
        JMP     SHORT REDUCE_PI

MOD_NOT_0:
        MOV     EDI,OFFSET_OPERAND1
        CALL    SUBTRACTION_NORMALIZE   ; RETURNS WITH ZF = 0.
REDUCTION_DONE:
        OR      SR_ERRORS,INEXACT_MASK  ; PRECISION ERROR UNLESS ZERO MOD
REDUCE_PI:
        TEST    Q,4
        JZ      REDUCE_HAPI

        NOT     RES_SIGNS               ; FLIP SIGN FOR BOTH SIN AND COS
REDUCE_HAPI:
        TEST    Q,2
        JZ      REDUCE_QRPI

        NOT     COFUNC_FLAG
        NOT     COS_SIGN
REDUCE_QRPI:
        TEST    Q,1
        JNZ     LAST_REDUC

        RET                             ; ZF IS SET HERE

LAST_REDUC:
        NOT     COFUNC_FLAG
        CMP     [EBP].TAG1,SPECIAL
        JNE     MOD_SET_INEXACT

        CMP     OP_TYPE,TAN_OP
        JNE     MOD_SET_INEXACT

        MOV     MSB_FRAC1,80H
        MOV     [EBP].TAG1,VALID
        MOV     DWORD_EXPON1,3FFFH
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        ADD     ESP,4                   ; GET RID OF RETURN ADDRESS
        JMP     ADJUST_SIGN

MOD_SET_INEXACT:                        ; A ZERO MOD WILL BE CHANGED HERE
        OR      SR_ERRORS,INEXACT_MASK  ; TO QRTR_PI,SO PRECISION ERROR
COMPLEMENTARY_ANGLE:
        MOV     DWORD PTR [EBP].DWORD_FRAC2,0
        MOV     DWORD PTR [EBP].DWORD_FRAC2 + FRAC64,2168C235H
        MOV     DWORD PTR [EBP].DWORD_FRAC2 + FRAC32,0C90FDAA2H
        MOV     DWORD PTR [EBP].DWORD_FRAC2 + SIGN,POSITIVE + 10000H*VALID
        MOV     DWORD_EXPON2,3FFEH
        MOV     [EBP].SIGN1,NEGATIVE
        MOV     [EBP].OPERATION_TYPE,ADD_OP
        CALL    SUBADD
        PUSH    DWORD PTR SR_MASKS
        AND     DWORD PTR SR_MASKS,0FFFFF3FFH   ; SET RC = TO_NEAREST
        CALL    POST_OP_ROUND
        POP     DWORD PTR SR_MASKS
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        RET

MOD_QRTR_PI     ENDP
PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
TAN_PSEUDO_DIVIDE       PROC

        MOV     SISO,0                  ; CLEAR SISO
        MOV     DWORD_EXPON1,EAX
        CMP     EAX,16
        JG      TAN_RAT_APPX

        DEC     DWORD_EXPON1            ; DECREMENT EXPON1
        CALL    RIGHT_SHIFT_FRAC1_8
TAN_LOOP_BACK_1:
        MOV     EAX,10
        MUL     DWORD_EXPON1
        ADD     EAX,A?MEDOFFSET TAN_CONSTANT
        MOV     ESI,EAX
        CALL    SUB_FRAC2
        SHL     SISO,1
        CMP     MSB_RESULT,0
        JNE     TAN_MERGE_0

        CALL    MOVE_RESULT_FRAC1
        AND     [EBP].DWORD_FRAC1,0FFE00000H
        INC     SISO
TAN_MERGE_0:
        INC     DWORD_EXPON1
        CMP     DWORD_EXPON1,15
        JA      TAN_BRANCH_1

        CALL    LEFT_SHIFT_FRAC1_1
        JMP     TAN_LOOP_BACK_1

TAN_BRANCH_1:
        CALL    LEFT_SHIFT_FRAC1_8
        MOV     [EBP].DWORD_FRAC1,0
TAN_RAT_APPX:
        CALL    MOVE_FRAC1_COP          ; COP <- THETA,COP TMP
        CALL    MULX                    ; THETA * THETA
        MOV     ECX,DWORD_EXPON1
        SHL     ECX,1
        ADD     ECX,8
        CALL    RIGHT_SHIFT_RESULT_CL
        AND     [EBP].RESULT_DWORD_FRAC,0FF000000H      ; 64 BITS ONLY
        CALL    MOVE_RESULT_FRAC2
        MOV     ESI,A?MEDOFFSET CONSTANT_C0H
        CALL    SUB_FRAC1               ; X <- 1.1 - THETA*THETA
        CALL    MOVE_COP_FRAC2
        CALL    RIGHT_SHIFT_FRAC2_8
        CALL    MOVE_COP_FRAC1
        MOV     CL,9
        CALL    RIGHT_SHIFT_FRAC1_CL
        CALL    MOVE_RESULT_COP         ; COP <- X
        CALL    ADDX                    ; Y <- Y' + THETA
        CALL    RIGHT_SHIFT_RESULT_1
        CALL    MOVE_RESULT_DOP         ; DOP <- Y,DOP
        DEC     DWORD_EXPON1            ; IS A 67 BITS TEMP
;
;PSEUDO_MULTIPLY
;
TAN_LOOP_BACK_2:
        SHR     SISO,1
        JNB     TAN_MERGE_2
        CALL    MOVE_COP_FRAC1          ; X
        CALL    MOVE_DOP_FRAC2          ; Y
        CALL    ADDX                    ; X + Y
        CALL    MOVE_RESULT_DOP         ; -> DOP
        MOV     ECX,DWORD_EXPON1
        SHL     ECX,1
        CALL    RIGHT_SHIFT_FRAC2_CL
        AND     [EBP].DWORD_FRAC2,0FFE00000H
        CALL    SUBX                            ; X - Y*2(-2EXP)
        CALL    MOVE_RESULT_COP                 ; -> COP
        AND     [EBP].DWORD_COP,0FF000000H
TAN_MERGE_2:
        CMP     SISO,0
        JE      TAN_ALMOST_END

        MOV     CL,1
        MOV     EDI,OFFSET_DOP
        CALL    RIGHT_SHIFT_AL0
        AND     [EBP].DWORD_DOP,0FFE00000H
        DEC     DWORD_EXPON1
        JMP     SHORT TAN_LOOP_BACK_2

TAN_ALMOST_END:
        MOV     CL,8
        CMP     MSB_DOP,0
        JE      TAN_MERGE_3

        MOV     CL,7
        DEC     DWORD_EXPON1
TAN_MERGE_3:
        MOV     EDI,OFFSET_DOP + FRAC80
        CALL    LEFT_SHIFT
        CALL    MOVE_DOP_FRAC1
        MOV     EAX,3FFFH
        SUB     EAX,DWORD_EXPON1
        MOV     DWORD_EXPON1,EAX
;
;NORMALIZE Y
;
        MOV     EDI,OFFSET_OPERAND1
        CALL    SUBTRACTION_NORMALIZE
;
;NOW X
;
        CALL    MOVE_COP_FRAC2
        CALL    LEFT_SHIFT_FRAC2_8
        MOV     DWORD_EXPON2,3FFFH
        MOV     DWORD PTR [EBP].SIGN2,POSITIVE + VALID*10000H
;
;NORMALIZE X
;
        MOV     EDI,OFFSET_OPERAND2
        CALL    SUBTRACTION_NORMALIZE
        RET

TAN_PSEUDO_DIVIDE       ENDP

PAGE
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
;                       TAN:
;
;       FUNCTION:
;               CALCULATES Y AND X SUCH THAT Y/X = TAN(THETA)
;
;       INPUTS:
;               ASSUMES THAT OPERAND1 IS SET UP (THETA).
;
;       OUTPUTS:
;               RESULTS IN RESULT RECORDS;  Y = RESULT,X = RESULT2.
;               ERROR CHECKING DONE.
;
;       DATA ACCESSED:
;               - RESULT_REC_OFFSET             RESULT2_REC_OFFSET
;               - OFFSET_OPERAND1               EXPON1
;               - WORD_FRAC1                    LSB_FRAC1
;               - OFFSET_OPERAND1               OFFSET_OPERAND2
;               - SIGN2                         TAG2
;               - EXPON2                        LSB_FRAC2
;               - MSB_FRAC2                     OFFSET_OPERAND2
;               - LSB_RESULT                    MSB_RESULT
;               - OFFSET_RESULT                 SISO
;               - OFFSET_COP                    LSB_COP
;               - OFFSET_DOP                    LSB_DOP
;               - MSB_DOP
;
;       DATA CHANGED:
;               - EXPON1                        WORD_FRAC1
;               - LSB_FRAC1                     SIGN2
;               - TAG2                          EXPON2
;               - LSB_FRAC2                     MSB_RESULT
;               - LSB_COP                       LSB_DOP
;               - SISO
;
;       PROCEDURES CALLED:
;          DO_EXCHANGE             STACK_FULL?             RIGHT_SHIFT
;          LEFT_SHIFT              MOVE_10_BYTES           MOVE_CONSTANT
;          ADDX                    SUBX                    MULX
;          SUBTRACTION_NORMALIZE   TEST_5W                 SET_P_ERROR
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
TAN     PROC

        CALL    TWO_RESULT_OP1_CHK
GET_REPORT:
        JNZ     REDUCE_OP1

ZERO_MODULUS:
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        JMP     DO_EXCHANGE

REDUCE_OP1:
        CALL    MOD_QRTR_PI
        CMP     [EBP].TAG1,SPECIAL
        JNE     TAN_TINY?

        CMP     COFUNC_FLAG,TRUE
        JNE     ZERO_MODULUS

        MOV     DWORD PTR [EBP].DWORD_FRAC1,0
        MOV     DWORD PTR [EBP].DWORD_FRAC1 + FRAC64,0
        MOV     DWORD PTR [EBP].DWORD_FRAC1 + FRAC32,080000000H
        MOV     DWORD PTR [EBP].DWORD_FRAC1 + SIGN,POSITIVE + 10000H*INFINTY
        MOV     DWORD PTR [EBP].DWORD_FRAC1 + EXPON,7FFFH
        MOV     SIGNAL_Z_ERROR?,TRUE
        JMP     SHORT ZERO_MODULUS

TAN_TINY?:
        MOV     EAX,3FFFH
        SUB     EAX,DWORD_EXPON1
        CMP     EAX,63
        JLE     TAN_CALC

TAN_TINY_ARGUMENT:
        CMP     EAX,3FFFH
        JL      OP2_GETS_1

        MOV     AL,SIN_SIGN
        MOV     [EBP].SIGN1,AL
        OR      SR_ERRORS,UNDERFLOW_MASK
        TEST    SR_MASKS,UNDERFLOW_MASK
        JNZ     NEED_GRAD_UFLOW

        ADD     DWORD_EXPON1,WRAP_AROUND_CONSTANT
        JMP     ZERO_MODULUS

NEED_GRAD_UFLOW:
        MOV     EDI,OFFSET_OPERAND1
        MOV     EAX,1
        CALL    GRADUAL_UNDERFLOW
        MOV     DWORD_EXPON1,0
        MOV     [EBP].TAG1,DENORMD
        JMP     ZERO_MODULUS

OP2_GETS_1:
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        CMP     COFUNC_FLAG,TRUE
        JNE     ADJUST_SIGN             ; STRAIGHT DIVIDE SUPERFLUOUS

        MOV     AX,RES_SIGNS
        MOV     [EBP].SIGN1,AL
        MOV     [EBP].SIGN2,AH
        PUSH    DWORD PTR SR_MASKS
        OR      DWORD PTR SR_MASKS,0300H        ; SET PRECISION CONTROL TO PREC64
        PUSH    TRANS_INFO
        JMP     REVERSE_DIV

TAN_CALC:
        PUSH    DWORD PTR SR_MASKS
        OR      DWORD PTR SR_MASKS,0300H   ; SET PRECISION CONTROL TO PREC64
        PUSH    TRANS_INFO
        CALL    TAN_PSEUDO_DIVIDE
        POP     TRANS_INFO
COTAN?:
        MOV     AX,RES_SIGNS
        MOV     [EBP].SIGN1,AL
        MOV     [EBP].SIGN2,AH
        PUSH    TRANS_INFO
        CMP     COFUNC_FLAG,TRUE
        JNE     STRAIGHT_DIV

REVERSE_DIV:
        CALL    OP1_INTO_OP2
        JMP     SHORT GET_A_BIT

STRAIGHT_DIV:
        CALL    OP2_INTO_OP1
GET_A_BIT:
        CMP     ADDED_ONE,TRUE
        JNE     MOVE_TAN_RESULT

        OR      SR_FLAGS,A_MASK
MOVE_TAN_RESULT:
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
        POP     TRANS_INFO
        POP     DWORD PTR SR_MASKS
ADJUST_SIGN:
        MOV   AL,SIN_SIGN
        XOR   AL,COS_SIGN
        MOV   BYTE PTR [EBP].SIGN1,AL

;; BUG FIX (??)
;;
;;  If garbage happens to be in the tags field of result,it can be
;;  transferred to the tags field of the answer stored under dword_frac1.
;;  In this function,the tags field of the result does not specifically
;;  get set elsewhere,so I will do it here in an attempt to  get rid of this
;;  bug. This soultion should be looked as in closer detail at a later date.
;;
;; This bug fix assumes that if the program has gotten to this point without
;; error that nothing has gone wrong. This may be a bad assumption.


        MOV  BYTE PTR [EBP].TAG1,VALID


JUMP_DO_EXCHANGE:
        JMP     DO_EXCHANGE_LEAVE_A_BIT

TAN     ENDP
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
SWAP_OPS        PROC

        MOV     ESI,OFFSET_OPERAND1
        CALL    PUSH_5_DW_AT_ESI
        LEA     ESI,[EBP].DWORD_FRAC2
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP
        MOV     ESI,OFFSET_OPERAND2
        CALL    POP_5_DW_AT_ESI
        RET

SWAP_OPS        ENDP
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
OP1_INTO_OP2    PROC

        CALL    SWAP_OPS

OP2_INTO_OP1:

        PUSH    DWORD PTR SR_MASKS
        OR      DWORD PTR SR_MASKS,0300H   ; SET PRECISION CONTROL TO PREC64
        CALL    DIVID                      ; FLOATING-POINT DIVIDE
        CALL    POST_OP_ROUND
        POP     DWORD PTR SR_MASKS

        RET

OP1_INTO_OP2    ENDP
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
PAGE
;
SIN_SPECIFIC    PROC

        MOV     ESI,OFFSET_RESULT
        CALL    PUSH_5_DW_AT_ESI                ; SAVE (X/Y)
        CALL    OP2_INTO_OP1                    ; RESULT <-- (Y/X)
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP                   ; OP1 <-- (Y/X)
        MOV     ESI,OFFSET_OPERAND2
        CALL    POP_5_DW_AT_ESI                 ; OP2 <-- (X/Y)
        OR      DWORD PTR SR_MASKS,0F00H        ; SET RC TO CHOP!
        MOV     [EBP].OPERATION_TYPE,ADD_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC2
        CALL    MOVE_OP_TO_OP           ; OP2 <-- CHOP(X/Y + Y/X)
        MOV     ESI,OFFSET_OPERAND1
        CALL    MOVE_UNPACKED_1_TO_ESI  ; OP1 <-- 1
        INC     DWORD_EXPON1            ; OP1 <-- 2
        CALL    OP2_INTO_OP1            ; RES <-- CHOP{2/CHOP(X/Y + Y/X)}

        RET

SIN_SPECIFIC    ENDP
PAGE
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;
;                       SIN:
;
SIN     PROC

        CALL    ONE_RESULT_OP1_CHK
SIN_REPORT:
        JNZ     SIN_REDUCE_OP1

        MOV     OP_TYPE,SIN_OP
        MOV     AL,BYTE PTR [EBP].SIGN1
        MOV     SIN_SIGN,AL
SIN_0_MODULUS:
        LEA     ESI,[EBP].DWORD_FRAC1
        LEA     EDI,[EBP].RESULT_DWORD_FRAC
        CALL    MOVE_OP_TO_OP
        JMP     CHECK_OP_TYPE

SIN_REDUCE_OP1:
        CALL    MOD_QRTR_PI
        CMP     [EBP].TAG1,SPECIAL
        JNE     SIN_TINY?

;SIN_COFUNC?:
        CMP     COFUNC_FLAG,TRUE
        JNE     SIN_0_MODULUS

        JMP     COS_0_MODULUS

SIN_TINY?:
        CMP     COFUNC_FLAG,TRUE
        JE      CHECK_COS_LIM

CHECK_SIN_LIM:
        MOV     EAX,3FFFH
        SUB     EAX,DWORD_EXPON1
        CMP     EAX,30
        JL      SIN_CALC
        JG      SIN_TINY_ARGUMENT

        CMP     [EBP].DWORD_FRAC1 + FRAC32,08D100000H
        JA      SIN_CALC
        JB      SIN_0_MODULUS

        CMP     [EBP].DWORD_FRAC1 + FRAC64,0
        JE      SIN_0_MODULUS

SIN_TINY_ARGUMENT:
        CMP     EAX,3FFFH
        JL      SIN_0_MODULUS

        OR      SR_ERRORS,UNDERFLOW_MASK
        TEST    SR_MASKS,UNDERFLOW_MASK
        JNZ     SIN_GRAD_UFLOW

        ADD     DWORD_EXPON1,WRAP_AROUND_CONSTANT
        JMP     SIN_0_MODULUS

SIN_GRAD_UFLOW:
        MOV     EDI,OFFSET_OPERAND1
        MOV     EAX,1
        CALL    GRADUAL_UNDERFLOW
        MOV     DWORD_EXPON1,0
        MOV     [EBP].TAG1,DENORMD
        JMP     SIN_0_MODULUS

SIN_CALC:
        PUSH    TRANS_INFO
        PUSH    DWORD PTR SR_MASKS
        AND     DWORD PTR SR_MASKS,0FFFFF3FFH   ; SET RC = TO_NEAREST
        OR      DWORD PTR SR_MASKS,0300H   ; SET PRECISION CONTROL TO PREC64
        INC     EAX                     ; EAX HOLDS -(TRUE_EXPON)
        CALL    TAN_PSEUDO_DIVIDE
        MOV     ESI,OFFSET_OPERAND1
        CALL    PUSH_5_DW_AT_ESI        ; SAVE Y
        MOV     ESI,OFFSET_OPERAND2
        CALL    PUSH_5_DW_AT_ESI        ; SAVE X
        CALL    OP1_INTO_OP2            ; RESULT <-- X/Y
        MOV     ESI,OFFSET_OPERAND2
        CALL    POP_5_DW_AT_ESI         ; OP2 <-- X
        MOV     ESI,OFFSET_OPERAND1
        CALL    POP_5_DW_AT_ESI         ; OP1 <-- Y
        CALL    SIN_SPECIFIC
        POP     DWORD PTR SR_MASKS
        POP     TRANS_INFO
        AND     SR_FLAGS,NOT A_MASK
        CMP     ADDED_ONE,TRUE
        JNE     CHECK_OP_TYPE

        OR      SR_FLAGS,A_MASK
        JMP     CHECK_OP_TYPE

SIN     ENDP

;-----------------------------------------------------------------------
;               COS:
;
;-----------------------------------------------------------------------
;
COS_SPECIFIC    PROC

        LEA     ESI,[EBP].DWORD_FRAC1
        LEA     EDI,[EBP].DWORD_FRAC2
        CALL    MOVE_OP_TO_OP                   ; OP2 <-- X/Y
        CALL    MULT                            ; RES <-- (X/Y)**2
        CALL    POST_OP_ROUND
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP                   ; OP1 <-- (X/Y)**2
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI          ; OP2 <-- 1
        MOV     [EBP].OPERATION_TYPE,ADD_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND                   ; RES <-- 1 + (X/Y)**2
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC2
        CALL    MOVE_OP_TO_OP                   ; OP2 <-- 1 + (X/Y)**2
        MOV     ESI,OFFSET_OPERAND1
        CALL    MOVE_UNPACKED_1_TO_ESI          ; OP1 <-- 1
        INC     DWORD_EXPON1                    ; OP1 <-- 2
        CALL    OP2_INTO_OP1                    ; RES <-- 2/(1 + (X/Y)**2)
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC2
        CALL    MOVE_OP_TO_OP                   ; OP2 <-- 2/(1 + (X/Y)**2)
        MOV     ESI,OFFSET_OPERAND1
        CALL    MOVE_UNPACKED_1_TO_ESI          ; OP1 <-- 1
        MOV     [EBP].OPERATION_TYPE,SUB_OP
        CALL    SUBADD
        CALL    POST_OP_ROUND           ; RES <-- 1 - {2/(1 + (X/Y)**2)}

        RET

COS_SPECIFIC    ENDP
;
;-----------------------------------------------------------------------
;
COS     PROC

        CALL    ONE_RESULT_OP1_CHK
COS_REPORT:
        JNZ     COS_REDUCE_OP1

        MOV     OP_TYPE,COS_OP
        MOV     COS_SIGN,POSITIVE
COS_0_MODULUS:
        MOV     ESI,OFFSET_RESULT
        CALL    MOVE_UNPACKED_1_TO_ESI
CHECK_OP_TYPE:
        CMP     OP_TYPE,COS_OP
        JE      ATTACH_COS_SIGN

ATTACH_SIN_SIGN:
        MOV     AL,SIN_SIGN
        JMP     SHORT SIGN_DONE

ATTACH_COS_SIGN:
        MOV     AL,COS_SIGN
SIGN_DONE:
        MOV     [EBP].RESULT_SIGN,AL
SEND_RESULT:
        MOV     EDI,OFFSET_RESULT
        JMP     PUT_SI_RESULT

COS_REDUCE_OP1:
        CALL    MOD_QRTR_PI
        CMP     [EBP].TAG1,SPECIAL
        JNE     COS_TINY?

        CMP     COFUNC_FLAG,TRUE
        JNE     COS_0_MODULUS

        MOV     DWORD PTR [EBP].RESULT_DWORD_FRAC,0
        MOV     DWORD PTR [EBP].RESULT_DWORD_FRAC + FRAC64,0
        MOV     DWORD PTR [EBP].RESULT_DWORD_FRAC + FRAC32,0
        MOV     DWORD PTR [EBP].RESULT_SIGN,POSITIVE + (SPECIAL*10000H)
        MOV     DWORD_RESULT_EXPON,0
        JMP     SHORT ATTACH_COS_SIGN

COS_TINY?:
        CMP     COFUNC_FLAG,TRUE
        JE      CHECK_SIN_LIM

CHECK_COS_LIM:
        MOV     EAX,3FFFH
        SUB     EAX,DWORD_EXPON1
        CMP     EAX,62
        JL      COS_CALC
        JG      COS_0_MODULUS

        CMP     [EBP].DWORD_FRAC1 + FRAC32,080000000H
        JA      COS_CALC

        CMP     [EBP].DWORD_FRAC1 + FRAC64,0
        JE      COS_0_MODULUS

COS_CALC:
        PUSH    TRANS_INFO
        PUSH    DWORD PTR SR_MASKS
        AND     DWORD PTR SR_MASKS,0FFFFF3FFH   ; SET RC = TO_NEAREST
        OR      DWORD PTR SR_MASKS,0300H    ; SET PRECISION CONTROL TO PREC64
        INC     EAX                         ; EAX HOLDS -(TRUE_EXPON)
        CALL    TAN_PSEUDO_DIVIDE
        CALL    OP1_INTO_OP2                ; RESULT <-- X/Y
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC1
        CALL    MOVE_OP_TO_OP           ; OP1 <-- X/Y
        CALL    COS_SPECIFIC            ; RESULT <-- COS
        POP     DWORD PTR SR_MASKS
        POP     TRANS_INFO
        AND     SR_FLAGS,NOT A_MASK
        CMP     ADDED_ONE,TRUE
        JNE     CHECK_OP_TYPE

        OR      SR_FLAGS,A_MASK
        JMP     CHECK_OP_TYPE

COS     ENDP


PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;               SINCOS:

SINCOS          PROC

        CALL    TWO_RESULT_OP1_CHK
COMBO_GET_REPORT:
        JNZ     COMBO_REDUCE_OP1

        XOR     EAX,EAX
        MOV     AH,[EBP].SIGN1
        MOV     TRANS_INFO,EAX
COMBO_0_MOD:
        MOV     ESI,OFFSET_OPERAND2
        CALL    MOVE_UNPACKED_1_TO_ESI
COMBO_COFUNC?:
        CMP     COFUNC_FLAG,TRUE
        JNE     ATTACH_SIGNS

SWITCH_OPS:
        CALL    SWAP_OPS
ATTACH_SIGNS:
        MOV     AX,RES_SIGNS
        MOV     [EBP].SIGN1,AL
        MOV     [EBP].SIGN2,AH
RESULTS_SENT:
        JMP     DO_EXCHANGE

COMBO_REDUCE_OP1:
        CALL    MOD_QRTR_PI
        CMP     [EBP].TAG1,SPECIAL
        JZ      COMBO_0_MOD

COMBO_TINY?:
        MOV     EAX,3FFFH
        SUB     EAX,DWORD_EXPON1
        CMP     EAX,62
        JL      COMBO_SIN_CALC
        JG      COMBO_TINY_ARG

        CMP     [EBP].DWORD_FRAC1 + FRAC32,080000000H
        JA      COMBO_SIN_CALC

        CMP     [EBP].DWORD_FRAC1 + FRAC64,0
        JNE     COMBO_SIN_CALC

COMBO_TINY_ARG:
        CMP     EAX,3FFFH
        JL      COMBO_0_MOD

        OR      SR_ERRORS,UNDERFLOW_MASK
        TEST    SR_MASKS,UNDERFLOW_MASK
        JNZ     COMBO_GRAD_UFLOW

        ADD     DWORD_EXPON1,WRAP_AROUND_CONSTANT
        JMP     COMBO_0_MOD

COMBO_GRAD_UFLOW:
        MOV     EDI,OFFSET_OPERAND1
        MOV     EAX,1
        CALL    GRADUAL_UNDERFLOW
        MOV     DWORD_EXPON1,0
        MOV     [EBP].TAG1,DENORMD
        JMP     COMBO_0_MOD

COMBO_SIN_CALC:
        PUSH    TRANS_INFO
        PUSH    DWORD PTR SR_MASKS
        AND     DWORD PTR SR_MASKS,0FFFFF3FFH   ; SET RC = TO_NEAREST
        OR      DWORD PTR SR_MASKS,0300H    ; SET PRECISION CONTROL TO PREC64
        CMP     EAX,30
        JL      PUSH_FLAGS
        JG      FORCE_ZF_1

        CMP     [EBP].DWORD_FRAC1 + FRAC32,08D100000H
        JA      PUSH_FLAGS
        JB      FORCE_ZF_1

        CMP     [EBP].DWORD_FRAC1 + FRAC64,0
        JNE     PUSH_FLAGS

FORCE_ZF_1:
        XOR     EBX,EBX                 ; ZF SET IFF ARG IS TINY FOR SIN
        MOV     ESI,OFFSET_OPERAND1     ; SAVE TINY OP1 AS SIN(OP1)
        CALL    PUSH_5_DW_AT_ESI        ; DOES NOT AFFECT FLAGS OR EAX
PUSH_FLAGS:
        PUSHFD
        INC     EAX                     ; EAX HOLDS -(TRUE_EXPON)
        CALL    TAN_PSEUDO_DIVIDE
        POPFD
        JZ      CALC_X_OVER_Y

        MOV     ESI,OFFSET_OPERAND1
        CALL    PUSH_5_DW_AT_ESI        ; SAVE Y
        MOV     ESI,OFFSET_OPERAND2
        CALL    PUSH_5_DW_AT_ESI        ; SAVE X
CALC_X_OVER_Y:
        PUSHFD
        CALL    OP1_INTO_OP2            ; RESULT <-- X/Y
        POPFD
        JZ      SAVE_X_OVER_Y

        MOV     ESI,OFFSET_OPERAND2
        CALL    POP_5_DW_AT_ESI         ; OP2 <-- X
        MOV     ESI,OFFSET_OPERAND1
        CALL    POP_5_DW_AT_ESI         ; OP1 <-- Y
SAVE_X_OVER_Y:
        MOV     ESI,OFFSET_RESULT
        CALL    PUSH_5_DW_AT_ESI        ; SAVE  X/Y
        JZ      COMBO_COS_CALC

        PUSHFD
        CALL    SIN_SPECIFIC            ; RESULT <-- SIN
        POPFD
COMBO_COS_CALC:
        MOV     ESI,OFFSET_OPERAND1
        CALL    POP_5_DW_AT_ESI         ; OP1 <-- X/Y
        JZ      TINY_SIN_COS_ENTRY

        MOV     ESI,OFFSET_RESULT
        CALL    PUSH_5_DW_AT_ESI        ; SAVE  COMPUTED SIN
TINY_SIN_COS_ENTRY:
        CALL    COS_SPECIFIC            ; RESULT <-- COS
        MOV     ESI,OFFSET_OPERAND1
        CALL    POP_5_DW_AT_ESI         ; OP1 <-- SIN
        LEA     ESI,[EBP].RESULT_DWORD_FRAC
        LEA     EDI,[EBP].DWORD_FRAC2
        CALL    MOVE_OP_TO_OP           ; OP2 <-- COS
        POP     DWORD PTR SR_MASKS
        POP     TRANS_INFO

        JMP     COMBO_COFUNC?

SINCOS          ENDP


PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;               TEST_5W,TEST_4W,TEST_3W
;
;       FUNCTION:
;               TEST 3,4,OR 5 CONSECUTIVE WORDS FOR ZERO
;
;       INPUTS:
;               LEAST SIGNIFICANT WORD POINTED TO BY SS:[BP + DI]
;               AX MUST BE CLEAR UPON ENTRY FOR TEST_4W AND TEST_3W
;
;       OUTPUTS:
;               IF VARIABLE = 0,AX = 00000H; ZF = 1
;               OTHERWISE,AX = 0FFFFH; ZF = 0
;
;       DATA ACCESSED:
;
;       DATA CHANGED:
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
TEST_5W         PROC

        MOV     AX,[EBP + EDI + 8]      ; dump the data into AX
TEST_4W:
        OR      AX,[EBP + EDI + 6]
TEST_3W:
        OR      AX,[EBP + EDI + 4]
        OR      AX,[EBP + EDI + 2]
        OR      AX,[EBP + EDI]
        JNZ     ITS_NOT_ZERO            ; branch if the number is nonzero

        RET                             ; return with AX = 00000H,ZF = 1

ITS_NOT_ZERO:
        MOV     AX,0FFFFH               ; return with AX = 0FFFFH,ZF = 0
        RET

TEST_5W         ENDP

TEST_6W PROC

        MOV     EAX,[EBP + EDI]         ; dump the data into AX
        OR      EAX,[EBP + EDI + 4]
        OR      EAX,[EBP + EDI + 8]
        JNZ     NON_0                   ; branch if the number is nonzero

        RET                             ; return with EAX = 000000000H,ZF = 1

NON_0:
        MOV     EAX,0FFFFFFFFH          ; return with EAX = 0FFFFFFFFH,ZF = 0
        RET

TEST_6W ENDP

PAGE
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                       CLEAR_5W,SET_5W,SET__4W,SET_3W
;
;       FUNCTION:
;               SETS 3,4,OR 5 CONSECUTIVE WORDS TO ZERO OR GIVEN VALUE
;
;       INPUTS:
;               LEAST SIGNIFICANT WORD POINTED TO BY SS:[EBP + EDI]
;               AX CONTAINS VALUE GIVEN TO STORE FOR SET ROUTINES
;
;       OUTPUTS:
;               AX CONTAINS ZERO FOR THE CLEAR_5W ROUTINE
;               EAX "        "    "   "  CLEAR_6W    "
;       DATA ACCESSED:
;
;       DATA CHANGED:
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
CLEAR_6W        PROC

        XOR     EAX,EAX
SET_6W:
        MOV     [EBP + EDI],EAX         ; store the value in EAX
        MOV     [EBP + EDI + 4],EAX
        MOV     [EBP + EDI + 8],EAX
        RET

CLEAR_6W        ENDP

CLEAR_5W        PROC

        XOR     AX,AX
SET_5W:
        MOV     [EBP + EDI + 8],AX      ; store the value in AX
SET_4W:
        MOV     [EBP + EDI + 6],AX
SET_3W:
        MOV     [EBP + EDI + 4],AX
        MOV     [EBP + EDI + 2],AX
        MOV     [EBP + EDI],AX
        RET

CLEAR_5W        ENDP

PAGE
;
; Common entries to shift and move subroutines
;
; RIGHT_SHIFT Group
;
RIGHT_SHIFT_DWORD_EXP_TMP:
        MOV    ECX,DWORD_EXP_TMP
        SHL    CL,1
        JMP    SHORT RIGHT_SHIFT_AL0

RIGHT_SHIFT_RESULT_1:
        MOV    CL,1
RIGHT_SHIFT_RESULT_CL:
        MOV    EDI,OFFSET_RESULT
        JMP    SHORT RIGHT_SHIFT_AL0

RIGHT_SHIFT_FRAC2_8:
        MOV    CL,8
RIGHT_SHIFT_FRAC2_CL:
        MOV    EDI,OFFSET_OPERAND2
        JMP    SHORT RIGHT_SHIFT_AL0

RIGHT_SHIFT_FRAC1_8:
        MOV    CL,8
RIGHT_SHIFT_FRAC1_CL:
        MOV    EDI,OFFSET_OPERAND1
RIGHT_SHIFT_AL0:
        MOV    AL,0

;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                             RIGHT_SHIFT:
;
;    FUNCTION:
;        SHIFTS A 12-BYTE NUMBER RIGHT BY AMOUNT IN ECX REGISTER.
;
;    INPUTS:
;        LOW BIT OF AL CONTAINS BIT TO INJECT FROM LEFT.
;        EDI CONTAINS THE OFFSET OF THE LEAST SIGNIFICANT BYTE
;        OF THE 12-BYTE NUMBER.
;
;    OUTPUTS:
;        ON RETURN,EDX IS NON-ZERO IF ANY ONES HAVE BEEN SHIFTED OUT.
;                EDI HAS THE SAME VALUE IT HAD UPON ENTRY.
;    DATA ACCESSED:
;
;    DATA CHANGED:
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
RIGHT_SHIFT    PROC

        XOR     EDX,EDX         ; INITIALIZE EDX,THE "STICKY WORD"
        ROR     AL,1            ; MOVE LSB TO MSB
        MOVSX   EAX,AL          ; TRANSMIT SIGN TO AH AND HI_WORD(EAX)
        PUSH    EAX             ; STACK INSERT BIT REPLICA
        MOV     CH,2            ; ONE LESS THAN # OF DWORDS TO GET BIT-SHIFTED
        CMP     CL,32           ; DOES SHIFT_COUNT EXCEED 31?
        JB      BITS_SHFT_RT    ; IF NOT,JUST DO THE BIT SHIFTING;

        CMP     CL,96           ; DOES SHIFT_COUNT EXCEED 95?
        JB      DWORDS_SHFT_RT  ; IF NOT,PROCEED WITH DWORD SHIFTS;
        JE      GET_OUT_SHFTS   ; ELSE,IF SHIFT_COUNT EXCEEDS 96

        OR      DX,AX           ; THEN BIT SHIFTED IN IS ALSO SHIFTED OUT
GET_OUT_SHFTS:
        OR      EDX,[EBP + EDI]     ; ALL 3 DWORDS ARE "SHIFTED OUT,"
        OR      EDX,[EBP + EDI + 4] ; AND OR'D TO EDX
        OR      EDX,[EBP + EDI + 8]
        MOV     AL,AH               ; COPY INSERT BIT THROUGHOUT EAX
        MOV     [EBP + EDI],EAX
        MOV     [EBP + EDI + 4],EAX
        MOV     [EBP + EDI + 8],EAX ; REPLACE ALL 96 BITS BY INSERT BIT.
        POP     EAX

        RET
;
DWORDS_SHFT_RT:
        PUSH    DS              ; SAVE A?MSR
        PUSH    SS              ; COPY STACK SEGMENT
        POP     DS              ; TO DS
        PUSH    SS
        POP     ES              ; AND ES
        ADD     EDI,EBP
        MOV     ESI,EDI
        MOV     BL,CL           ; SAVE BIT_SHFT_COUNT IN BL
        AND     ECX,60H         ; GET DWORD_SHFT_COUNT
        SHR     ECX,5           ; NORMALIZE DWORD_SHFT_COUNT
        MOV     AL,CL           ; SAVE DWORD_SHFT_COUNT IN AL
DWORD_SHFT_CHK:
        OR      EDX,[ESI]
        ADD     ESI,4
        LOOP    DWORD_SHFT_CHK
        MOV     CX,3
        SUB     CL,AL
        MOV     BH,CL
        REP     MOVSD
        MOV     CL,AL
        MOV     AL,AH
        REP     STOSD
        SUB     EDI,12          ; ADJUST EDI
        SUB     EDI,EBP         ; TO VALUE IT HAD AT ENTRY
        POP     DS
        MOV     CX,BX
BITS_SHFT_RT:
        POP     EAX
        PUSH    EDI
        PUSH    EAX
        MOV     EAX,[EBP + EDI]
        XOR     EBX,EBX
        SHRD    EBX,EAX,CL      ; CL IS INTERPRETED MOD 32
        OR      EDX,EBX
BIT_SHFT_LOOP:
        MOV     EAX,[EBP + EDI + 4]
        SHRD    DWORD PTR [EBP + EDI],EAX,CL
        ADD     EDI,4
        DEC     CH
        JNZ     BIT_SHFT_LOOP

        POP     EAX
        MOV     AL,AH
        SHRD    DWORD PTR [EBP + EDI],EAX,CL
        POP     EDI

RIGHT_SHIFT_DONE:

        CLC
        RET

RIGHT_SHIFT    ENDP

PAGE

;-----------------
; LEFT_SHIFT Group
;
LEFT_SHIFT_RESULT_CL:

        MOV     EDI,OFFSET_RESULT + FRAC80
        JMP     SHORT LEFT_SHIFT

LEFT_SHIFT_FRAC2_8:

        MOV     CL,8
LEFT_SHIFT_FRAC2_CL:

        MOV     EDI,OFFSET_OPERAND2 + FRAC80
        JMP     SHORT LEFT_SHIFT

LEFT_SHIFT_FRAC1_8:

        MOV     CL,8
        JMP     SHORT LEFT_SHIFT_FRAC1_CL

LEFT_SHIFT_FRAC1_1:

        MOV     CL,1

LEFT_SHIFT_FRAC1_CL:

        MOV     EDI,OFFSET_OPERAND1 + FRAC80

;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                       LEFT_SHIFT:
;
;       FUNCTION:
;               SHIFTS A 10-BYTE NUMBER LEFT BY AMOUNT IN CL REG.
;
;       INPUT:
;               DI CONTAINS OFFSET OF LOW-BYTE.
;
;       OUTPUTS:
;               BITS SHIFTED OFF THE LEFT END ARE LOST.
;
;       DATA ACCESSED:
;
;       DATA CHANGED:
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
LEFT_SHIFT      PROC

        CMP     CL,80           ; more than 80 bits?
        JLE     LEFT_COUNT      ; no,form left count

        MOV     CL,80           ; yes,80 is the max
LEFT_COUNT:
        MOV     AL,CL           ; FORM BYTE COUNT
        AND     AL,78H          ; = BITS 3-6 OF AMOUNT
        JZ      LEFTOVER_BITS           ; BRANCH IF COUNT < 8

        PUSH    ECX             ; STACK BIT COUNT
        PUSH    EDI             ; STACK FRAC OFFSET
        PUSH    DS              ; SAVE A?MSR
        CBW                     ; CLEAR AH
        SHR     AX,3            ; NORMALIZE BYTE COUNT
        DEC     AX
        MOV     ECX,0009H       ; COUNT = 10 - AX
        ADD     EDI,ECX
        MOVSX   EAX,AX
        SUB     ECX,EAX         ; DEST = SS:BP+SI
        ADD     EDI,EBP
        MOV     ESI,EDI         ; DEST = SS:BP+DI
        SUB     ESI,EAX
        DEC     ESI
        PUSH    SS              ; COPY SS TO DS AND ES
        POP     DS
        PUSH    SS
        POP     ES
        STD                     ; SET DIRECTION FLAG
        REP     MOVSB           ; SHIFT BYTES LEFT
        MOV     [EDI],CL        ; CLEAR NEXT BYTE
        MOV     ECX,EAX         ; FORM ZERO COUNT
        MOV     ESI,EDI         ; FORM STRING OFFSETS
        DEC     EDI
        REP     MOVSB           ; CLEAR REST OF STRING
        CLD                     ; CLEAR DIRECTION FLAG
        POP     DS              ; RELOAD A?MSR
        POP     EDI             ; RELOAD FRAC OFFSET
        POP     ECX             ; RELOAD BIT COUNT
LEFTOVER_BITS:
        AND     ECX,00000007H           ; BITS 0-2 = BIT COUNT
        JZ      LEFT_SHIFT_DONE         ; EXIT IF ALL DONE

LEFT_SHIFT_BITS:
        SHL     WORD PTR [EBP + EDI],1          ; SHIFT FIVE WORDS
        RCL     WORD PTR [EBP + EDI + 2],1      ; ONE BIT LEFT,USING
        RCL     WORD PTR [EBP + EDI + 4],1      ; THE CARRY FLAG OUT
        RCL     WORD PTR [EBP + EDI + 6],1
        RCL     WORD PTR [EBP + EDI + 8],1
        LOOP    LEFT_SHIFT_BITS                 ; LOOP BIT COUNT TIMES

LEFT_SHIFT_DONE:
        RET

LEFT_SHIFT      ENDP

PAGE

;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                       ONE_LEFT_NORMALIZE:
;
;       FUNCTION:
;               NORMALIZES FOLLOWING A MULTIPLICATION.
;
;       INPUTS:
;               ASSUMES FRACTION IS NOT ZERO.  DI = FRAC OFFSET.
;
;       OUTPUTS:
;               SHIFTS FRACTION LEFT AND DECREMENTS EXPONENT UNTIL
;               FRACTION NORMALIZED,BUT NO MORE THAN ONE LEFT SHIFT.
;               ZF IS RESET IF THE FRACTION IS NORMALIZED UPON RETURN.
;
;       DATA ACCESSED:
;
;       DATA CHANGED:
;
;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
ONE_LEFT_NORMALIZE      PROC

        TEST    BYTE PTR [EBP + EDI + FRAC80 + 9],80H   ;NORMALIZED?
        JNZ     ONE_LEFT_NORM_DONE                      ;QUIT IF NORMALIZED.

        PUSH    EDI                                     ; SAVE FRAC OFFSET
        MOV     ECX,00000001H                           ; LOAD LOOP COUNT
        ADD     EDI,2
        CALL    LEFT_SHIFT_BITS                         ;SHIFT 5 WORDS LEFT 1
        POP     EDI                                     ; RELOAD FRAC OFFSET
        DEC     DWORD PTR [EBP + EDI + EXPON]           ;DECREMENT EXPONENT
        TEST    BYTE PTR [EBP + EDI + FRAC80 + 9],80H   ;NORMALIZED?

ONE_LEFT_NORM_DONE:

        RET

ONE_LEFT_NORMALIZE      ENDP
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
;                       SUBTRACTION_NORMALIZE:
;
;       FUNCTION:
;               NORMALIZES FOLLOWING A SUBTRACTION.
;
;       INPUTS:
;               ASSUMES FRACTION IS NOT ZERO.  DI = FRAC OFFSET
;
;       OUTPUTS:
;               SHIFTS FRACTION LEFT AND DECREMENTS EXPONENT
;               UNTIL FRACTION NORMALIZED.
;
;       DATA ACCESSED:
;
;       DATA CHANGED:
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
SUBTRACTION_NORMALIZE   PROC

        CALL    ONE_LEFT_NORMALIZE              ; NORMALIZE ONE BIT
        JZ      SUBTRACTION_NORMALIZE           ;QUIT WHEN NORMALIZED.

        RET

SUBTRACTION_NORMALIZE   ENDP


PAGE
;
; MOVE_10_BYTES Group
;
MOVE_FRAC2_FRAC1:

        MOV     EDI,OFFSET_OPERAND1 + 2

MOVE_FRAC2:

        MOV     ESI,OFFSET_OPERAND2 + 2
        JMP     SHORT MOVE_10_BYTES

MOVE_FRAC1_RESULT:

        MOV     EDI,OFFSET_RESULT + 2
        JMP     SHORT MOVE_FRAC1

MOVE_FRAC1_COP:

        MOV     EDI,OFFSET_COP + 2
        CALL    MOVE_FRAC1

MOVE_FRAC1_FRAC2:

        MOV     EDI,OFFSET_OPERAND2 + 2

MOVE_FRAC1:

        MOV     ESI,OFFSET_OPERAND1 + 2
        JMP     SHORT MOVE_10_BYTES

MOVE_DOP_FRAC2:

        MOV     EDI,OFFSET_OPERAND2 + 2
        JMP     SHORT MOVE_DOP

MOVE_DOP_FRAC1:

        MOV     EDI,OFFSET_OPERAND1 + 2

MOVE_DOP:

        MOV     ESI,OFFSET_DOP + 2
        JMP     SHORT MOVE_10_BYTES

MOVE_COP_FRAC2:

        MOV     EDI,OFFSET_OPERAND2 + 2
        JMP     SHORT MOVE_COP

MOVE_COP_FRAC1:

        MOV     EDI,OFFSET_OPERAND1 + 2

MOVE_COP:

        MOV     ESI,OFFSET_COP + 2
        JMP     SHORT MOVE_10_BYTES

MOVE_RESULT_COP:

        MOV     EDI,OFFSET_COP + 2
        JMP     SHORT MOVE_RESULT

MOVE_RESULT_DOP:

        MOV     EDI,OFFSET_DOP + 2
        JMP     SHORT MOVE_RESULT

MOVE_RESULT_FRAC2:

        MOV     EDI,OFFSET_OPERAND2 + 2
        JMP     SHORT MOVE_RESULT

MOVE_RESULT_FRAC1:

        MOV     EDI,OFFSET_OPERAND1 + 2

MOVE_RESULT:

        MOV     ESI,OFFSET_RESULT + 2

MOVE_10_BYTES:

        ADD     ESI,EBP         ; add global record offset
        PUSH    DS              ; SAVE A?MSR
        PUSH    SS              ; load source segment register

SET_DESTINATION:

        POP     DS
        PUSH    SS              ; load destination segment register
        POP     ES              ; into ES
        ADD     EDI,EBP         ; add global record offset
        MOV     ECX,5           ; move five words
        REP     MOVSW
        POP     DS              ; RELOAD A?MSR

        RET

;--------------------------------
; ADD,SUB,MUL,MOVE_CONSTANT Group
;
ADD_HALF1_FRAC2:

        MOV     ESI,A?MEDOFFSET ADD_HALF_PATTERN_1
        CALL    ADD_FRAC2
        MOV     EDI,OFFSET_RESULT

        JMP     ADDITION_NORMALIZE

ADD_FRAC2:

        CALL    MOVE_CONSTANT_FRAC2
        JMP     ADDX

SUB_FRAC1:

        MOV     EDI,OFFSET_OPERAND1 + 2

SUB_CONSTANT:

        CALL    MOVE_CONSTANT
        JMP     SUBX

SUB_FRAC2:

        MOV     EDI,OFFSET_OPERAND2 + 2
        JMP     SUB_CONSTANT

MUL_FRAC2:

        CALL    MOVE_CONSTANT_FRAC2
        JMP     MULX

MOVE_CONSTANT_FRAC2:

        MOV     EDI,OFFSET_OPERAND2 + 2

MOVE_CONSTANT:

        PUSH    DS              ; SAVE A?MSR
        PUSH    CS              ; load code segment base into DS
        JMP     SET_DESTINATION ; move five words

EMULATOR_CODE ends

        END
