1@ libgcc1 routines for ARM cpu. 2@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) 3 4/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. 5 6This file is free software; you can redistribute it and/or modify it 7under the terms of the GNU General Public License as published by the 8Free Software Foundation; either version 2, or (at your option) any 9later version. 10 11In addition to the permissions in the GNU General Public License, the 12Free Software Foundation gives you unlimited permission to link the 13compiled version of this file with other programs, and to distribute 14those programs without any restriction coming from the use of this 15file. (The General Public License restrictions do apply in other 16respects; for example, they cover modification of the file, and 17distribution when not linked into another program.) 18 19This file is distributed in the hope that it will be useful, but 20WITHOUT ANY WARRANTY; without even the implied warranty of 21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22General Public License for more details. 23 24You should have received a copy of the GNU General Public License 25along with this program; see the file COPYING. If not, write to 26the Free Software Foundation, 59 Temple Place - Suite 330, 27Boston, MA 02111-1307, USA. */ 28 29/* As a special exception, if you link this library with other files, 30 some of which are compiled with GCC, to produce an executable, 31 this library does not by itself cause the resulting executable 32 to be covered by the GNU General Public License. 33 This exception does not however invalidate any other reasons why 34 the executable file might be covered by the GNU General Public License. 35 */ 36/* This code is derived from gcc 2.95.3 */ 37/* I Molton 29/07/01 */ 38 39#include <linux/linkage.h> 40#include <asm/assembler.h> 41#include <asm/hardware.h> 42 43#define RET movs 44#define RETc(x) mov##x##s 45#define RETCOND ^ 46 47dividend .req r0 48divisor .req r1 49result .req r2 50overdone .req r2 51curbit .req r3 52ip .req r12 53sp .req r13 54lr .req r14 55pc .req r15 56 57ENTRY(__udivsi3) 58 cmp divisor, #0 59 beq Ldiv0 60 mov curbit, #1 61 mov result, #0 62 cmp dividend, divisor 63 bcc Lgot_result_udivsi3 641: 65 @ Unless the divisor is very big, shift it up in multiples of 66 @ four bits, since this is the amount of unwinding in the main 67 @ division loop. Continue shifting until the divisor is 68 @ larger than the dividend. 69 cmp divisor, #0x10000000 70 cmpcc divisor, dividend 71 movcc divisor, divisor, lsl #4 72 movcc curbit, curbit, lsl #4 73 bcc 1b 74 752: 76 @ For very big divisors, we must shift it a bit at a time, or 77 @ we will be in danger of overflowing. 78 cmp divisor, #0x80000000 79 cmpcc divisor, dividend 80 movcc divisor, divisor, lsl #1 81 movcc curbit, curbit, lsl #1 82 bcc 2b 83 843: 85 @ Test for possible subtractions, and note which bits 86 @ are done in the result. On the final pass, this may subtract 87 @ too much from the dividend, but the result will be ok, since the 88 @ "bit" will have been shifted out at the bottom. 89 cmp dividend, divisor 90 subcs dividend, dividend, divisor 91 orrcs result, result, curbit 92 cmp dividend, divisor, lsr #1 93 subcs dividend, dividend, divisor, lsr #1 94 orrcs result, result, curbit, lsr #1 95 cmp dividend, divisor, lsr #2 96 subcs dividend, dividend, divisor, lsr #2 97 orrcs result, result, curbit, lsr #2 98 cmp dividend, divisor, lsr #3 99 subcs dividend, dividend, divisor, lsr #3 100 orrcs result, result, curbit, lsr #3 101 cmp dividend, #0 @ Early termination? 102 movnes curbit, curbit, lsr #4 @ No, any more bits to do? 103 movne divisor, divisor, lsr #4 104 bne 3b 105Lgot_result_udivsi3: 106 mov r0, result 107 RET pc, lr 108 109Ldiv0: 110 str lr, [sp, #-4]! 111 bl __div0 112 mov r0, #0 @ about as wrong as it could be 113 ldmia sp!, {pc}RETCOND 114 115/* __umodsi3 ----------------------- */ 116 117ENTRY(__umodsi3) 118 cmp divisor, #0 119 beq Ldiv0 120 mov curbit, #1 121 cmp dividend, divisor 122 RETc(cc) pc, lr 1231: 124 @ Unless the divisor is very big, shift it up in multiples of 125 @ four bits, since this is the amount of unwinding in the main 126 @ division loop. Continue shifting until the divisor is 127 @ larger than the dividend. 128 cmp divisor, #0x10000000 129 cmpcc divisor, dividend 130 movcc divisor, divisor, lsl #4 131 movcc curbit, curbit, lsl #4 132 bcc 1b 133 1342: 135 @ For very big divisors, we must shift it a bit at a time, or 136 @ we will be in danger of overflowing. 137 cmp divisor, #0x80000000 138 cmpcc divisor, dividend 139 movcc divisor, divisor, lsl #1 140 movcc curbit, curbit, lsl #1 141 bcc 2b 142 1433: 144 @ Test for possible subtractions. On the final pass, this may 145 @ subtract too much from the dividend, so keep track of which 146 @ subtractions are done, we can fix them up afterwards... 147 mov overdone, #0 148 cmp dividend, divisor 149 subcs dividend, dividend, divisor 150 cmp dividend, divisor, lsr #1 151 subcs dividend, dividend, divisor, lsr #1 152 orrcs overdone, overdone, curbit, ror #1 153 cmp dividend, divisor, lsr #2 154 subcs dividend, dividend, divisor, lsr #2 155 orrcs overdone, overdone, curbit, ror #2 156 cmp dividend, divisor, lsr #3 157 subcs dividend, dividend, divisor, lsr #3 158 orrcs overdone, overdone, curbit, ror #3 159 mov ip, curbit 160 cmp dividend, #0 @ Early termination? 161 movnes curbit, curbit, lsr #4 @ No, any more bits to do? 162 movne divisor, divisor, lsr #4 163 bne 3b 164 165 @ Any subtractions that we should not have done will be recorded in 166 @ the top three bits of "overdone". Exactly which were not needed 167 @ are governed by the position of the bit, stored in ip. 168 @ If we terminated early, because dividend became zero, 169 @ then none of the below will match, since the bit in ip will not be 170 @ in the bottom nibble. 171 ands overdone, overdone, #0xe0000000 172 RETc(eq) pc, lr @ No fixups needed 173 tst overdone, ip, ror #3 174 addne dividend, dividend, divisor, lsr #3 175 tst overdone, ip, ror #2 176 addne dividend, dividend, divisor, lsr #2 177 tst overdone, ip, ror #1 178 addne dividend, dividend, divisor, lsr #1 179 RET pc, lr 180 181ENTRY(__divsi3) 182 eor ip, dividend, divisor @ Save the sign of the result. 183 mov curbit, #1 184 mov result, #0 185 cmp divisor, #0 186 rsbmi divisor, divisor, #0 @ Loops below use unsigned. 187 beq Ldiv0 188 cmp dividend, #0 189 rsbmi dividend, dividend, #0 190 cmp dividend, divisor 191 bcc Lgot_result_divsi3 192 1931: 194 @ Unless the divisor is very big, shift it up in multiples of 195 @ four bits, since this is the amount of unwinding in the main 196 @ division loop. Continue shifting until the divisor is 197 @ larger than the dividend. 198 cmp divisor, #0x10000000 199 cmpcc divisor, dividend 200 movcc divisor, divisor, lsl #4 201 movcc curbit, curbit, lsl #4 202 bcc 1b 203 2042: 205 @ For very big divisors, we must shift it a bit at a time, or 206 @ we will be in danger of overflowing. 207 cmp divisor, #0x80000000 208 cmpcc divisor, dividend 209 movcc divisor, divisor, lsl #1 210 movcc curbit, curbit, lsl #1 211 bcc 2b 212 2133: 214 @ Test for possible subtractions, and note which bits 215 @ are done in the result. On the final pass, this may subtract 216 @ too much from the dividend, but the result will be ok, since the 217 @ "bit" will have been shifted out at the bottom. 218 cmp dividend, divisor 219 subcs dividend, dividend, divisor 220 orrcs result, result, curbit 221 cmp dividend, divisor, lsr #1 222 subcs dividend, dividend, divisor, lsr #1 223 orrcs result, result, curbit, lsr #1 224 cmp dividend, divisor, lsr #2 225 subcs dividend, dividend, divisor, lsr #2 226 orrcs result, result, curbit, lsr #2 227 cmp dividend, divisor, lsr #3 228 subcs dividend, dividend, divisor, lsr #3 229 orrcs result, result, curbit, lsr #3 230 cmp dividend, #0 @ Early termination? 231 movnes curbit, curbit, lsr #4 @ No, any more bits to do? 232 movne divisor, divisor, lsr #4 233 bne 3b 234Lgot_result_divsi3: 235 mov r0, result 236 cmp ip, #0 237 rsbmi r0, r0, #0 238 RET pc, lr 239 240ENTRY(__modsi3) 241 mov curbit, #1 242 cmp divisor, #0 243 rsbmi divisor, divisor, #0 @ Loops below use unsigned. 244 beq Ldiv0 245 @ Need to save the sign of the dividend, unfortunately, we need 246 @ ip later on; this is faster than pushing lr and using that. 247 str dividend, [sp, #-4]! 248 cmp dividend, #0 249 rsbmi dividend, dividend, #0 250 cmp dividend, divisor 251 bcc Lgot_result_modsi3 252 2531: 254 @ Unless the divisor is very big, shift it up in multiples of 255 @ four bits, since this is the amount of unwinding in the main 256 @ division loop. Continue shifting until the divisor is 257 @ larger than the dividend. 258 cmp divisor, #0x10000000 259 cmpcc divisor, dividend 260 movcc divisor, divisor, lsl #4 261 movcc curbit, curbit, lsl #4 262 bcc 1b 263 2642: 265 @ For very big divisors, we must shift it a bit at a time, or 266 @ we will be in danger of overflowing. 267 cmp divisor, #0x80000000 268 cmpcc divisor, dividend 269 movcc divisor, divisor, lsl #1 270 movcc curbit, curbit, lsl #1 271 bcc 2b 272 2733: 274 @ Test for possible subtractions. On the final pass, this may 275 @ subtract too much from the dividend, so keep track of which 276 @ subtractions are done, we can fix them up afterwards... 277 mov overdone, #0 278 cmp dividend, divisor 279 subcs dividend, dividend, divisor 280 cmp dividend, divisor, lsr #1 281 subcs dividend, dividend, divisor, lsr #1 282 orrcs overdone, overdone, curbit, ror #1 283 cmp dividend, divisor, lsr #2 284 subcs dividend, dividend, divisor, lsr #2 285 orrcs overdone, overdone, curbit, ror #2 286 cmp dividend, divisor, lsr #3 287 subcs dividend, dividend, divisor, lsr #3 288 orrcs overdone, overdone, curbit, ror #3 289 mov ip, curbit 290 cmp dividend, #0 @ Early termination? 291 movnes curbit, curbit, lsr #4 @ No, any more bits to do? 292 movne divisor, divisor, lsr #4 293 bne 3b 294 295 @ Any subtractions that we should not have done will be recorded in 296 @ the top three bits of "overdone". Exactly which were not needed 297 @ are governed by the position of the bit, stored in ip. 298 @ If we terminated early, because dividend became zero, 299 @ then none of the below will match, since the bit in ip will not be 300 @ in the bottom nibble. 301 ands overdone, overdone, #0xe0000000 302 beq Lgot_result_modsi3 303 tst overdone, ip, ror #3 304 addne dividend, dividend, divisor, lsr #3 305 tst overdone, ip, ror #2 306 addne dividend, dividend, divisor, lsr #2 307 tst overdone, ip, ror #1 308 addne dividend, dividend, divisor, lsr #1 309Lgot_result_modsi3: 310 ldr ip, [sp], #4 311 cmp ip, #0 312 rsbmi dividend, dividend, #0 313 RET pc, lr 314