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