fdmth086.asm

来自「开放源码的编译器open watcom 1.6.0版的源代码」· 汇编 代码 · 共 1,056 行 · 第 1/3 页

ASM
1,056
字号
          or    SI,CX
          or    SI,DI
          jne   add_norm
          add   SP,8            ; - clean up stack
          pop   DI              ; - restore DI
          pop   BP              ; - restore bp
          sub   AX,AX           ; - set answer to 0
          sub   BX,BX           ; - . . .
          sub   CX,CX           ; - . . .
          sub   DX,DX           ; - . . .
          ret                   ; - return
        _endif
        neg     DH              ; - sign is that of other operand
        not     AL              ; - negate the fraction
        not     BX              ; - . . .
        not     CX              ; - . . .
        not     DI              ; - . . .
        neg     AH              ; - (considering the guard bit as an extension)
        sbb     DI,-1           ; - . . .
        sbb     CX,-1           ; - . . .
        sbb     BX,-1           ; - . . .
        sbb     AL,-1           ; - . . .

add_norm:                       ; normalizes the mantissa against bit 6
        add     BP,0010h        ; prepare exponent

;<> please note that this will overflow if the exponent is very close to its
;<> maximum size but not too large to overflow under normal circumstances.
;<> since we allow an 11 bit exponent, then, the largest exponent one can
;<> handle with this routine is (10^) 1022.

        _shl    AH,1            ; get guard bit
        _loop                   ; loop
          _rcl  DI,1            ; - shift result left
          _rcl  CX,1
          _rcl  BX,1
          _rcl  AL,1
          sub   BP,0010h        ; - decrement exponent
          jbe   add_uflow       ; - ******* handle underflow *******
          test  AL,20h          ; until msb is in bit 6
        _until ne
        and     AL,1Fh          ; turn off implied one bit
        push    DX              ; push sign
        mov     DX,DI
        jmp     fin_up

; over/underflow entry points for __FDA and __FDS

add_oflow:
        mov     AX,DX           ; put sign into ax
        add     SP,8            ; clean up stack
        pop     DI              ; restore DI
        pop     BP              ; restore bp
        jmp     F8OverFlow      ; handle overflow

add_uflow:
        add     SP,8            ; clean up stack
        pop     DI              ; restore DI
        pop     BP              ; restore bp
        jmp     F8UnderFlow     ; handle underflow
        endproc __FDA

;
; __FDM
;
; Note that if the real pointed to by DI has few sig digits,
; a short cut is taken.
;
        defpe   __FDM
        go_to   fdmul

__FDM87:
        fld     qword ptr ss:[SI] ; load operand 2
        push    BP              ; save BP
        mov     BP,SP           ; get access to stack
        push    AX              ; push operand 1
        push    BX              ; . . .
        push    CX              ; . . .
        push    DX              ; . . .
        fmul    qword ptr -8[BP]; - multiply by operand 1
        jmp     _ret87          ; goto common epilogue


__FDMemu:
        push    BP              ; save BP
        push    DI              ; save DI

;       f8split

        push    AX              ; push operand 1 onto stack
        push    BX              ; . . .
        push    CX              ; . . .
        push    DX              ; . . .
        mov     DI,SP           ; get address of operand 1
        _guess                  ; guess
          mov   BX,AX           ; - get most sig word of op1
          mov   AX,ss:6[SI]     ; - get most sig word of op2
          mov   DL,AL           ; - save mantissa-holding part
          mov   DH,BL           ; - save mantissa-holding part
          mov   cl,bh           ; - save sign
          and   BX,7FF0h        ; - isolate exponent
          _quif e               ; - quif zero
          mov   ch,ah           ; - save sign
          and   AX,7FF0h        ; - isolate exponent
          _quif e               ; - quif zero
          and   cx,8080h        ; - only want sign bits
          xor   dx,1010h        ; - set implied one bit of mant.
          xor   DL,AL           ; - . . .
          xor   DH,BL           ; - . . .
        _admit                  ; admit: one operand is zero
          add   SP,8            ; - clean up stack
          pop   DI              ; - restore DI
          pop   BP              ; - restore bp
          sub   AX,AX           ; - set result to 0
          sub   BX,BX           ; - . . .
          sub   CX,CX           ; - . . .
          sub   DX,DX           ; - . . .
          ret                   ; - return
        _endguess               ; endguess
        add     CH,CL           ; determine sign of result
        _guess                  ; guess: OK
          add   AX,BX           ; - determine exponent of result
          sub   ax,3ff0h        ; - remove extra bias
          _quif e               ; - FP underflow if exponent = 0
          cmp   ax,0c000h       ; - if exponent >= $c000
          _quif ae              ; - then FP underflow
        _admit                  ; admit: underflow
          add   SP,8            ; - clean up stack
          pop   DI              ; - restore DI
          pop   BP              ; - restore bp
          jmp   F8UnderFlow
        _endguess               ; endguess
        cmp     ax,7ff0h        ; if $7ff0 >= exponent > $c000
        _if     ae              ; then FP overflow
          mov   AX,CX           ; - put sign into ax
          add   SP,8            ; - clean up stack
          pop   DI              ; - restore DI
          pop   BP              ; - restore bp
          jmp   F8OverFlow      ; - handle overflow
        _endif                  ; endif
        push    CX              ; push sign
        push    AX              ; push exponent

        mov     BX,ss:[DI]      ; get low order word of op_1
        or      BX,BX           ; if it is zero
        _if     e               ; then
          xchg  SI,DI           ; - flip op_1 and op_2 around
          xchg  DL,DH           ; - . . .
        _endif                  ; endif
        sub     AX,AX           ; clear out AX
        mov     AL,DH           ; set AX up with high order mant of op_1
        push    AX              ; save high order mant
        push    ss:4[DI]        ; save rest of op_1
        push    ss:2[DI]        ; . . .
        push    ss:[DI]         ; . . .
        sub     BX,BX           ; clear out a word
        push    BX              ; move two clear words onto stack
        push    BX
        mov     BP,SP           ; BP points at empty word and op_1
        mov     AL,DL           ; set AX up with high order mant of op_2
        push    AX              ; save high order mant
        push    ss:4[SI]        ; save rest of op_2
        push    ss:2[SI]        ; . . .
        mov     BX,ss:[SI]      ; . . .
        _guess                  ; guess: multiplier has lots of 0's in it
          mov   CX,0300h        ; - set loop count
          or    BX,BX           ; - check multiplier
          _quif ne              ; - quit if not zero
          pop   BX              ; - get next word of multiplier
          mov   CH,2            ; - set loop count
          or    BX,BX           ; - check multiplier
          _quif ne              ; - quit if not zero
          pop   BX              ; - get next word of multiplier
          mov   CH,1            ; - set loop count
        _endguess               ; endguess

; result will be kept in CL:DI:SI:2[BP]:0[BP]

        sub     SI,SI           ; clear out SI
        mov     DI,SI           ; clear out DI
        or      BX,BX           ; if low order multiplier non-zero
        _if     ne              ; then
          mov   AX,4[BP]        ; - get low word of op_1
          mul   BX              ; - multiply low word by A
          mov   0[BP],DX        ; - save high order word of result
          mov   AX,6[BP]        ; - get next lowest word of op_1
          mul   BX              ; - multiply this word by A
          add   0[BP],AX        ; - add product onto result
          adc   DI,DX           ; - . . .

          mov   AX,8[BP]        ; - get next lowest word of op_1
          mul   BX              ; - multiply this word by A
          add   DI,AX           ; - add product onto result
          adc   SI,DX           ; - . . .
          mov   2[BP],DI        ; - save result
          sub   DI,DI           ; - set back to 0

          mov   AX,10[BP]       ; - get highest word of op_1
          mul   BX              ; - multiply this word by A
          add   SI,AX           ; - add product onto result
          adc   DI,DX           ; - . . .
        _endif                  ; endif

        _loop                   ; loop
          dec   CH              ; - decrement loop count
          pop   BX              ; - lowest word of op_1 not used so far
          or    BX,BX           ; - check it (call it A) for zero
          je    shift_16        ; - skip and shift result right if 0
          mov   AX,4[BP]        ; - get low word of op_1
          mul   BX              ; - multiply low word by A
          add    [BP],AX        ; - add product onto result
          adc   2[BP],DX        ; - . . .
          adc   SI,0            ; - carry through as neccesary
          adc   DI,0            ; - . . .

          mov   AX,6[BP]        ; - get next lowest word of op_1
          mul   BX              ; - multiply this word by A
          add   2[BP],AX        ; - add product onto result
          adc   SI,DX           ; - . . .
          adc   DI,0            ; - carry through as necessary

          mov   AX,8[BP]        ; - get next lowest word of op_1
          mul   BX              ; - multiply this word by A
          add   SI,AX           ; - add product onto result
          adc   DI,DX           ; - . . .
          adc   CL,0            ; - carry through as necessary

          mov   AX,10[BP]       ; - get highest word of op_1
          cmp   CH,0            ; - check loop count
          _quif e               ; - quit if muliplied 4 times

          mul   BX              ; - multiply this word by A
          add   DI,AX           ; - add product onto result
          adc   CL,DL           ; - . . .

shift_16:
          mov   AX,2[BP]        ; - shift result right by 1 word
          mov    [BP],AX        ; - . . .
          mov   2[BP],SI        ; - . . .
          mov   SI,DI           ; - . . .
          mov   DI,CX           ; - . . .
          and   DI,00FFh        ; (we only move low word)
          mov   CL,0            ; - . . .
        _endloop                ; endloop
        mul     BL              ; mulitply 2 most significant bytes
        add     AX,DI           ; and add to the result

        pop     DX              ; get low order words of result
        pop     CX              ; . . .
        mov     BX,SI           ; . . .

        add     SP,8            ; remove operand from stack

        shr     AX,1            ; - shift result right 3 times
        rcr     BX,1            ; - . . .
        rcr     CX,1            ; - . . .
        rcr     DX,1            ; - . . .

        shr     AX,1            ; - . . .
        rcr     BX,1            ; - . . .
        rcr     CX,1            ; - . . .
        rcr     DX,1            ; - . . .

        shr     AX,1            ; - . . .
        rcr     BX,1            ; - . . .
        rcr     CX,1            ; - . . .
        rcr     DX,1            ; - . . .

        pop     BP              ; get exponent

        test    AL,40h          ; find out how many sig bits we got
        _if     ne
          add   BP,0010h        ; - increment exponent
          shr   AL,1            ; - move bits to correct pos in words
          rcr   BX,1            ; - . . .
          rcr   CX,1            ; - . . .
          rcr   DX,1            ; - . . .
        _endif                  ; endif
        and     AL,1Fh          ; clear out implied '1' bit
        jmp     fin_up          ; go to general finish up routine
        endproc __FDM


;
; __FDD
;

        defpe   __FDD
        go_to   fddiv

__FDDbad_div:
        fld     qword ptr ss:[SI] ; load operand 2
        push    BP              ; save BP
        mov     BP,SP           ; get access to stack
        push    AX              ; push operand 1
        push    BX              ; . . .
        push    CX              ; . . .
        push    DX              ; . . .
        call    __fdiv_m64r     ; divide op 1 by op 2
        sub     sp,8            ; rtn popped parm, _ret87 wants it
        jmp     _ret87          ; goto common epilogue

__FDD87:
        fld     qword ptr ss:[SI] ; load operand 2
        push    BP              ; save BP
        mov     BP,SP           ; get access to stack
        push    AX              ; push operand 1
        push    BX              ; . . .
        push    CX              ; . . .
        push    DX              ; . . .
        fdivr   qword ptr -8[BP]; divide operand 1 by operand 2
        jmp     _ret87          ; goto common epilogue

__FDDemu:
        push    BP              ; save BP
        push    DI              ; save DI

;       f8split

        push    AX              ; push operand 1 onto stack
        push    BX              ; . . .
        push    CX              ; . . .
        push    DX              ; . . .
        mov     DI,SP           ; get address of operand 1
        _guess                  ; guess
          mov   BX,AX           ; - get most sig word of op1
          mov   AX,ss:6[SI]     ; - get most sig word of op2
          mov   DL,AL           ; - save mantissa-holding part
          mov   DH,BL           ; - save mantissa-holding part
          mov   cl,bh           ; - save sign
          and   BX,7FF0h        ; - isolate exponent
          _quif e               ; - quif zero
          mov   ch,ah           ; - save sign
          and   AX,7FF0h        ; - isolate exponent
          _quif e               ; - quif zero
          and   cx,8080h        ; - only want sign bits
          xor   dx,1010h        ; - set implied one bit of mant.
          xor   DL,AL           ; - . . .
          xor   DH,BL           ; - . . .
        _admit                  ; admit: one of the operands is 0
          add   SP,8            ; - clean up the stack
          pop   DI              ; - restore DI
          pop   BP              ; - restore BP
          or    ax,ax           ; - if the divisor is zero
          _if   e               ; - then
            mov ah,cl           ; - - set sign of inf
            jmp F8DivZero       ; - - return div by zero status
          _endif                ; - endif
          sub   AX,AX           ; - set result to 0
          sub   BX,BX           ; - . . .
          sub   CX,CX           ; - . . .
          sub   DX,DX           ; - . . .

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?