/* * Copyright (c) 2014 ARM Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the company may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* An executable stack is *not* required for these functions. */ .section .note.GNU-stack,"",%progbits .previous .eabi_attribute 25, 1 /* ANSI concatenation macros. */ #define CONCAT1(a, b) CONCAT2(a, b) #define CONCAT2(a, b) a ## b /* Use the right prefix for global labels. */ #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) #define TYPE(x) .type SYM(x),function #define SIZE(x) .size SYM(x), . - SYM(x) #define LSYM(x) .x .macro cfi_start start_label, end_label .pushsection .debug_frame LSYM(Lstart_frame): .4byte LSYM(Lend_cie) - LSYM(Lstart_cie) LSYM(Lstart_cie): .4byte 0xffffffff .byte 0x1 .ascii "\0" .uleb128 0x1 .sleb128 -4 .byte 0xe .byte 0xc .uleb128 0xd .uleb128 0x0 .align 2 LSYM(Lend_cie): .4byte LSYM(Lend_fde)-LSYM(Lstart_fde) LSYM(Lstart_fde): .4byte LSYM(Lstart_frame) .4byte \start_label .4byte \end_label-\start_label .popsection .endm .macro cfi_end end_label .pushsection .debug_frame .align 2 LSYM(Lend_fde): .popsection \end_label: .endm .macro THUMB_LDIV0 name signed push {r0, lr} movs r0, #0 bl SYM(__aeabi_idiv0) pop {r1, pc} .endm .macro FUNC_END name SIZE (__\name) .endm .macro DIV_FUNC_END name signed cfi_start __\name, LSYM(Lend_div0) LSYM(Ldiv0): THUMB_LDIV0 \name \signed cfi_end LSYM(Lend_div0) FUNC_END \name .endm .macro THUMB_FUNC_START name .globl SYM (\name) TYPE (\name) .thumb_func SYM (\name): .endm .macro FUNC_START name .text .globl SYM (__\name) TYPE (__\name) .align 0 .force_thumb .thumb_func .syntax unified SYM (__\name): .endm .macro FUNC_ALIAS new old .globl SYM (__\new) .thumb_set SYM (__\new), SYM (__\old) .endm /* Register aliases. */ work .req r4 dividend .req r0 divisor .req r1 overdone .req r2 result .req r2 curbit .req r3 /* ------------------------------------------------------------------------ */ /* Bodies of the division and modulo routines. */ /* ------------------------------------------------------------------------ */ .macro BranchToDiv n, label lsrs curbit, dividend, \n cmp curbit, divisor bcc \label .endm .macro DoDiv n lsrs curbit, dividend, \n cmp curbit, divisor bcc 1f lsls curbit, divisor, \n subs dividend, dividend, curbit 1: adcs result, result .endm .macro THUMB1_Div_Positive movs result, #0 BranchToDiv #1, LSYM(Lthumb1_div1) BranchToDiv #4, LSYM(Lthumb1_div4) BranchToDiv #8, LSYM(Lthumb1_div8) BranchToDiv #12, LSYM(Lthumb1_div12) BranchToDiv #16, LSYM(Lthumb1_div16) LSYM(Lthumb1_div_large_positive): movs result, #0xff lsls divisor, divisor, #8 rev result, result lsrs curbit, dividend, #16 cmp curbit, divisor bcc 1f asrs result, #8 lsls divisor, divisor, #8 beq LSYM(Ldivbyzero_waypoint) 1: lsrs curbit, dividend, #12 cmp curbit, divisor bcc LSYM(Lthumb1_div12) b LSYM(Lthumb1_div16) LSYM(Lthumb1_div_loop): lsrs divisor, divisor, #8 LSYM(Lthumb1_div16): Dodiv #15 Dodiv #14 Dodiv #13 Dodiv #12 LSYM(Lthumb1_div12): Dodiv #11 Dodiv #10 Dodiv #9 Dodiv #8 bcs LSYM(Lthumb1_div_loop) LSYM(Lthumb1_div8): Dodiv #7 Dodiv #6 Dodiv #5 LSYM(Lthumb1_div5): Dodiv #4 LSYM(Lthumb1_div4): Dodiv #3 LSYM(Lthumb1_div3): Dodiv #2 LSYM(Lthumb1_div2): Dodiv #1 LSYM(Lthumb1_div1): subs divisor, dividend, divisor bcs 1f mov divisor, dividend 1: adcs result, result mov dividend, result bx lr LSYM(Ldivbyzero_waypoint): b LSYM(Ldiv0) .endm .macro THUMB1_Div_Negative lsrs result, divisor, #31 beq 1f rsbs divisor, divisor, #0 1: asrs curbit, dividend, #32 bcc 2f rsbs dividend, dividend, #0 2: eors curbit, result movs result, #0 mov ip, curbit BranchToDiv #4, LSYM(Lthumb1_div_negative4) BranchToDiv #8, LSYM(Lthumb1_div_negative8) LSYM(Lthumb1_div_large): movs result, #0xfc lsls divisor, divisor, #6 rev result, result lsrs curbit, dividend, #8 cmp curbit, divisor bcc LSYM(Lthumb1_div_negative8) lsls divisor, divisor, #6 asrs result, result, #6 cmp curbit, divisor bcc LSYM(Lthumb1_div_negative8) lsls divisor, divisor, #6 asrs result, result, #6 cmp curbit, divisor bcc LSYM(Lthumb1_div_negative8) lsls divisor, divisor, #6 beq LSYM(Ldivbyzero_negative) asrs result, result, #6 b LSYM(Lthumb1_div_negative8) LSYM(Lthumb1_div_negative_loop): lsrs divisor, divisor, #6 LSYM(Lthumb1_div_negative8): DoDiv #7 DoDiv #6 DoDiv #5 DoDiv #4 LSYM(Lthumb1_div_negative4): DoDiv #3 DoDiv #2 bcs LSYM(Lthumb1_div_negative_loop) DoDiv #1 subs divisor, dividend, divisor bcs 1f mov divisor, dividend 1: mov curbit, ip adcs result, result asrs curbit, curbit, #1 mov dividend, result bcc 2f rsbs dividend, dividend, #0 cmp curbit, #0 2: bpl 3f rsbs divisor, divisor, #0 3: bx lr LSYM(Ldivbyzero_negative): mov curbit, ip asrs curbit, curbit, #1 bcc LSYM(Ldiv0) rsbs dividend, dividend, #0 .endm /* ------------------------------------------------------------------------ */ /* Start of the Real Functions */ /* ------------------------------------------------------------------------ */ FUNC_START aeabi_idiv0 bx lr FUNC_END aeabi_idiv0 FUNC_START divsi3 FUNC_ALIAS aeabi_idiv divsi3 LSYM(divsi3_skip_div0_test): mov curbit, dividend orrs curbit, divisor bmi LSYM(Lthumb1_div_negative) LSYM(Lthumb1_div_positive): THUMB1_Div_Positive LSYM(Lthumb1_div_negative): THUMB1_Div_Negative DIV_FUNC_END divsi3 signed FUNC_START aeabi_idivmod cmp r1, #0 beq LSYM(Ldiv0) push {r0, r1, lr} bl LSYM(divsi3_skip_div0_test) POP {r1, r2, r3} mul r2, r0 sub r1, r1, r2 bx r3 FUNC_END aeabi_idivmod /* ------------------------------------------------------------------------ */