.file "reg_u_sub.S"1/*---------------------------------------------------------------------------+2| reg_u_sub.S |3| |4| Core floating point subtraction routine. |5| |6| Copyright (C) 1992,1993,1995,1997 |7| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |8| E-mail [email protected] |9| |10| Call from C as: |11| int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |12| int control_w) |13| Return value is the tag of the answer, or-ed with FPU_Exception if |14| one was raised, or -1 on internal error. |15| |16+---------------------------------------------------------------------------*/1718/*19| Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ).20| Takes two valid reg f.p. numbers (TAG_Valid), which are21| treated as unsigned numbers,22| and returns their difference as a TAG_Valid or TAG_Zero f.p.23| number.24| The first number (arg1) must be the larger.25| The returned number is normalized.26| Basic checks are performed if PARANOID is defined.27*/2829#include "exception.h"30#include "fpu_emu.h"31#include "control_w.h"3233.text34ENTRY(FPU_u_sub)35pushl %ebp36movl %esp,%ebp37pushl %esi38pushl %edi39pushl %ebx4041movl PARAM1,%esi /* source 1 */42movl PARAM2,%edi /* source 2 */4344movl PARAM6,%ecx45subl PARAM7,%ecx /* exp1 - exp2 */4647#ifdef PARANOID48/* source 2 is always smaller than source 1 */49js L_bugged_15051testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */52je L_bugged_25354testl $0x80000000,SIGH(%esi)55je L_bugged_256#endif /* PARANOID */5758/*--------------------------------------+59| Form a register holding the |60| smaller number |61+--------------------------------------*/62movl SIGH(%edi),%eax /* register ms word */63movl SIGL(%edi),%ebx /* register ls word */6465movl PARAM3,%edi /* destination */66movl PARAM6,%edx67movw %dx,EXP(%edi) /* Copy exponent to destination */6869xorl %edx,%edx /* register extension */7071/*--------------------------------------+72| Shift the temporary register |73| right the required number of |74| places. |75+--------------------------------------*/7677cmpw $32,%cx /* shrd only works for 0..31 bits */78jnc L_more_than_317980/* less than 32 bits */81shrd %cl,%ebx,%edx82shrd %cl,%eax,%ebx83shr %cl,%eax84jmp L_shift_done8586L_more_than_31:87cmpw $64,%cx88jnc L_more_than_638990subb $32,%cl91jz L_exactly_329293shrd %cl,%eax,%edx94shr %cl,%eax95orl %ebx,%ebx96jz L_more_31_no_low /* none of the lowest bits is set */9798orl $1,%edx /* record the fact in the extension */99100L_more_31_no_low:101movl %eax,%ebx102xorl %eax,%eax103jmp L_shift_done104105L_exactly_32:106movl %ebx,%edx107movl %eax,%ebx108xorl %eax,%eax109jmp L_shift_done110111L_more_than_63:112cmpw $65,%cx113jnc L_more_than_64114115/* Shift right by 64 bits */116movl %eax,%edx117orl %ebx,%ebx118jz L_more_63_no_low119120orl $1,%edx121jmp L_more_63_no_low122123L_more_than_64:124jne L_more_than_65125126/* Shift right by 65 bits */127/* Carry is clear if we get here */128movl %eax,%edx129rcrl %edx130jnc L_shift_65_nc131132orl $1,%edx133jmp L_more_63_no_low134135L_shift_65_nc:136orl %ebx,%ebx137jz L_more_63_no_low138139orl $1,%edx140jmp L_more_63_no_low141142L_more_than_65:143movl $1,%edx /* The shifted nr always at least one '1' */144145L_more_63_no_low:146xorl %ebx,%ebx147xorl %eax,%eax148149L_shift_done:150L_subtr:151/*------------------------------+152| Do the subtraction |153+------------------------------*/154xorl %ecx,%ecx155subl %edx,%ecx156movl %ecx,%edx157movl SIGL(%esi),%ecx158sbbl %ebx,%ecx159movl %ecx,%ebx160movl SIGH(%esi),%ecx161sbbl %eax,%ecx162movl %ecx,%eax163164#ifdef PARANOID165/* We can never get a borrow */166jc L_bugged167#endif /* PARANOID */168169/*--------------------------------------+170| Normalize the result |171+--------------------------------------*/172testl $0x80000000,%eax173jnz L_round /* no shifting needed */174175orl %eax,%eax176jnz L_shift_1 /* shift left 1 - 31 bits */177178orl %ebx,%ebx179jnz L_shift_32 /* shift left 32 - 63 bits */180181/*182* A rare case, the only one which is non-zero if we got here183* is: 1000000 .... 0000184* -0111111 .... 1111 1185* --------------------186* 0000000 .... 0000 1187*/188189cmpl $0x80000000,%edx190jnz L_must_be_zero191192/* Shift left 64 bits */193subw $64,EXP(%edi)194xchg %edx,%eax195jmp fpu_reg_round196197L_must_be_zero:198#ifdef PARANOID199orl %edx,%edx200jnz L_bugged_3201#endif /* PARANOID */202203/* The result is zero */204movw $0,EXP(%edi) /* exponent */205movl $0,SIGL(%edi)206movl $0,SIGH(%edi)207movl TAG_Zero,%eax208jmp L_exit209210L_shift_32:211movl %ebx,%eax212movl %edx,%ebx213movl $0,%edx214subw $32,EXP(%edi) /* Can get underflow here */215216/* We need to shift left by 1 - 31 bits */217L_shift_1:218bsrl %eax,%ecx /* get the required shift in %ecx */219subl $31,%ecx220negl %ecx221shld %cl,%ebx,%eax222shld %cl,%edx,%ebx223shl %cl,%edx224subw %cx,EXP(%edi) /* Can get underflow here */225226L_round:227jmp fpu_reg_round /* Round the result */228229230#ifdef PARANOID231L_bugged_1:232pushl EX_INTERNAL|0x206233call EXCEPTION234pop %ebx235jmp L_error_exit236237L_bugged_2:238pushl EX_INTERNAL|0x209239call EXCEPTION240pop %ebx241jmp L_error_exit242243L_bugged_3:244pushl EX_INTERNAL|0x210245call EXCEPTION246pop %ebx247jmp L_error_exit248249L_bugged_4:250pushl EX_INTERNAL|0x211251call EXCEPTION252pop %ebx253jmp L_error_exit254255L_bugged:256pushl EX_INTERNAL|0x212257call EXCEPTION258pop %ebx259jmp L_error_exit260261L_error_exit:262movl $-1,%eax263264#endif /* PARANOID */265266L_exit:267popl %ebx268popl %edi269popl %esi270leave271ret272273274