1 .file "reg_u_add.S" 2/*---------------------------------------------------------------------------+ 3 | reg_u_add.S | 4 | | 5 | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the | 6 | result in a destination FPU_REG. | 7 | | 8 | Copyright (C) 1992,1993,1995,1997 | 9 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | 10 | E-mail billm@suburbia.net | 11 | | 12 | Call from C as: | 13 | int FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | 14 | int control_w) | 15 | Return value is the tag of the answer, or-ed with FPU_Exception if | 16 | one was raised, or -1 on internal error. | 17 | | 18 +---------------------------------------------------------------------------*/ 19 20/* 21 | Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ). 22 | Takes two valid reg f.p. numbers (TAG_Valid), which are 23 | treated as unsigned numbers, 24 | and returns their sum as a TAG_Valid or TAG_Special f.p. number. 25 | The returned number is normalized. 26 | Basic checks are performed if PARANOID is defined. 27 */ 28 29#include "exception.h" 30#include "fpu_emu.h" 31#include "control_w.h" 32 33.text 34ENTRY(FPU_u_add) 35 pushl %ebp 36 movl %esp,%ebp 37 pushl %esi 38 pushl %edi 39 pushl %ebx 40 41 movl PARAM1,%esi /* source 1 */ 42 movl PARAM2,%edi /* source 2 */ 43 44 movl PARAM6,%ecx 45 movl %ecx,%edx 46 subl PARAM7,%ecx /* exp1 - exp2 */ 47 jge L_arg1_larger 48 49 /* num1 is smaller */ 50 movl SIGL(%esi),%ebx 51 movl SIGH(%esi),%eax 52 53 movl %edi,%esi 54 movl PARAM7,%edx 55 negw %cx 56 jmp L_accum_loaded 57 58L_arg1_larger: 59 /* num1 has larger or equal exponent */ 60 movl SIGL(%edi),%ebx 61 movl SIGH(%edi),%eax 62 63L_accum_loaded: 64 movl PARAM3,%edi /* destination */ 65 movw %dx,EXP(%edi) /* Copy exponent to destination */ 66 67 xorl %edx,%edx /* clear the extension */ 68 69#ifdef PARANOID 70 testl $0x80000000,%eax 71 je L_bugged 72 73 testl $0x80000000,SIGH(%esi) 74 je L_bugged 75#endif /* PARANOID */ 76 77/* The number to be shifted is in %eax:%ebx:%edx */ 78 cmpw $32,%cx /* shrd only works for 0..31 bits */ 79 jnc L_more_than_31 80 81/* less than 32 bits */ 82 shrd %cl,%ebx,%edx 83 shrd %cl,%eax,%ebx 84 shr %cl,%eax 85 jmp L_shift_done 86 87L_more_than_31: 88 cmpw $64,%cx 89 jnc L_more_than_63 90 91 subb $32,%cl 92 jz L_exactly_32 93 94 shrd %cl,%eax,%edx 95 shr %cl,%eax 96 orl %ebx,%ebx 97 jz L_more_31_no_low /* none of the lowest bits is set */ 98 99 orl $1,%edx /* record the fact in the extension */ 100 101L_more_31_no_low: 102 movl %eax,%ebx 103 xorl %eax,%eax 104 jmp L_shift_done 105 106L_exactly_32: 107 movl %ebx,%edx 108 movl %eax,%ebx 109 xorl %eax,%eax 110 jmp L_shift_done 111 112L_more_than_63: 113 cmpw $65,%cx 114 jnc L_more_than_64 115 116 movl %eax,%edx 117 orl %ebx,%ebx 118 jz L_more_63_no_low 119 120 orl $1,%edx 121 jmp L_more_63_no_low 122 123L_more_than_64: 124 movl $1,%edx /* The shifted nr always at least one '1' */ 125 126L_more_63_no_low: 127 xorl %ebx,%ebx 128 xorl %eax,%eax 129 130L_shift_done: 131 /* Now do the addition */ 132 addl SIGL(%esi),%ebx 133 adcl SIGH(%esi),%eax 134 jnc L_round_the_result 135 136 /* Overflow, adjust the result */ 137 rcrl $1,%eax 138 rcrl $1,%ebx 139 rcrl $1,%edx 140 jnc L_no_bit_lost 141 142 orl $1,%edx 143 144L_no_bit_lost: 145 incw EXP(%edi) 146 147L_round_the_result: 148 jmp fpu_reg_round /* Round the result */ 149 150 151 152#ifdef PARANOID 153/* If we ever get here then we have problems! */ 154L_bugged: 155 pushl EX_INTERNAL|0x201 156 call EXCEPTION 157 pop %ebx 158 movl $-1,%eax 159 jmp L_exit 160 161L_exit: 162 popl %ebx 163 popl %edi 164 popl %esi 165 leave 166 ret 167#endif /* PARANOID */ 168