mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-27 14:50:23 +00:00
319 lines
5.6 KiB
ArmAsm
319 lines
5.6 KiB
ArmAsm
/* Miscellaneous BPABI functions. ARMv6M implementation
|
|
|
|
Copyright (C) 2006, 2008, 2009, 2010 Free Software Foundation, Inc.
|
|
Contributed by CodeSourcery.
|
|
|
|
This file is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 3, or (at your option) any
|
|
later version.
|
|
|
|
This file is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
Under Section 7 of GPL version 3, you are granted additional
|
|
permissions described in the GCC Runtime Library Exception, version
|
|
3.1, as published by the Free Software Foundation.
|
|
|
|
You should have received a copy of the GNU General Public License and
|
|
a copy of the GCC Runtime Library Exception along with this program;
|
|
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#ifdef __ARM_EABI__
|
|
/* Some attributes that are common to all routines in this file. */
|
|
/* Tag_ABI_align_needed: This code does not require 8-byte
|
|
alignment from the caller. */
|
|
/* .eabi_attribute 24, 0 -- default setting. */
|
|
/* Tag_ABI_align_preserved: This code preserves 8-byte
|
|
alignment in any callee. */
|
|
.eabi_attribute 25, 1
|
|
#endif /* __ARM_EABI__ */
|
|
|
|
#ifdef L_aeabi_lcmp
|
|
|
|
FUNC_START aeabi_lcmp
|
|
cmp xxh, yyh
|
|
beq 1f
|
|
bgt 2f
|
|
mov r0, #1
|
|
neg r0, r0
|
|
RET
|
|
2:
|
|
mov r0, #1
|
|
RET
|
|
1:
|
|
sub r0, xxl, yyl
|
|
beq 1f
|
|
bhi 2f
|
|
mov r0, #1
|
|
neg r0, r0
|
|
RET
|
|
2:
|
|
mov r0, #1
|
|
1:
|
|
RET
|
|
FUNC_END aeabi_lcmp
|
|
|
|
#endif /* L_aeabi_lcmp */
|
|
|
|
#ifdef L_aeabi_ulcmp
|
|
|
|
FUNC_START aeabi_ulcmp
|
|
cmp xxh, yyh
|
|
bne 1f
|
|
sub r0, xxl, yyl
|
|
beq 2f
|
|
1:
|
|
bcs 1f
|
|
mov r0, #1
|
|
neg r0, r0
|
|
RET
|
|
1:
|
|
mov r0, #1
|
|
2:
|
|
RET
|
|
FUNC_END aeabi_ulcmp
|
|
|
|
#endif /* L_aeabi_ulcmp */
|
|
|
|
.macro test_div_by_zero signed
|
|
cmp yyh, #0
|
|
bne 7f
|
|
cmp yyl, #0
|
|
bne 7f
|
|
cmp xxh, #0
|
|
bne 2f
|
|
cmp xxl, #0
|
|
2:
|
|
.ifc \signed, unsigned
|
|
beq 3f
|
|
mov xxh, #0
|
|
mvn xxh, xxh @ 0xffffffff
|
|
mov xxl, xxh
|
|
3:
|
|
.else
|
|
beq 5f
|
|
blt 6f
|
|
mov xxl, #0
|
|
mvn xxl, xxl @ 0xffffffff
|
|
lsr xxh, xxl, #1 @ 0x7fffffff
|
|
b 5f
|
|
6: mov xxh, #0x80
|
|
lsl xxh, xxh, #24 @ 0x80000000
|
|
mov xxl, #0
|
|
5:
|
|
.endif
|
|
@ tailcalls are tricky on v6-m.
|
|
push {r0, r1, r2}
|
|
ldr r0, 1f
|
|
adr r1, 1f
|
|
add r0, r1
|
|
str r0, [sp, #8]
|
|
@ We know we are not on armv4t, so pop pc is safe.
|
|
pop {r0, r1, pc}
|
|
.align 2
|
|
1:
|
|
.word __aeabi_ldiv0 - 1b
|
|
7:
|
|
.endm
|
|
|
|
#ifdef L_aeabi_ldivmod
|
|
|
|
FUNC_START aeabi_ldivmod
|
|
test_div_by_zero signed
|
|
|
|
push {r0, r1}
|
|
mov r0, sp
|
|
push {r0, lr}
|
|
ldr r0, [sp, #8]
|
|
bl SYM(__gnu_ldivmod_helper)
|
|
ldr r3, [sp, #4]
|
|
mov lr, r3
|
|
add sp, sp, #8
|
|
pop {r2, r3}
|
|
RET
|
|
FUNC_END aeabi_ldivmod
|
|
|
|
#endif /* L_aeabi_ldivmod */
|
|
|
|
#ifdef L_aeabi_uldivmod
|
|
|
|
FUNC_START aeabi_uldivmod
|
|
test_div_by_zero unsigned
|
|
|
|
push {r0, r1}
|
|
mov r0, sp
|
|
push {r0, lr}
|
|
ldr r0, [sp, #8]
|
|
bl SYM(__gnu_uldivmod_helper)
|
|
ldr r3, [sp, #4]
|
|
mov lr, r3
|
|
add sp, sp, #8
|
|
pop {r2, r3}
|
|
RET
|
|
FUNC_END aeabi_uldivmod
|
|
|
|
#endif /* L_aeabi_uldivmod */
|
|
|
|
#ifdef L_arm_addsubsf3
|
|
|
|
FUNC_START aeabi_frsub
|
|
|
|
push {r4, lr}
|
|
mov r4, #1
|
|
lsl r4, #31
|
|
eor r0, r0, r4
|
|
bl __aeabi_fadd
|
|
pop {r4, pc}
|
|
|
|
FUNC_END aeabi_frsub
|
|
|
|
#endif /* L_arm_addsubsf3 */
|
|
|
|
#ifdef L_arm_cmpsf2
|
|
|
|
FUNC_START aeabi_cfrcmple
|
|
|
|
mov ip, r0
|
|
mov r0, r1
|
|
mov r1, ip
|
|
b 6f
|
|
|
|
FUNC_START aeabi_cfcmpeq
|
|
FUNC_ALIAS aeabi_cfcmple aeabi_cfcmpeq
|
|
|
|
@ The status-returning routines are required to preserve all
|
|
@ registers except ip, lr, and cpsr.
|
|
6: push {r0, r1, r2, r3, r4, lr}
|
|
bl __lesf2
|
|
@ Set the Z flag correctly, and the C flag unconditionally.
|
|
cmp r0, #0
|
|
@ Clear the C flag if the return value was -1, indicating
|
|
@ that the first operand was smaller than the second.
|
|
bmi 1f
|
|
mov r1, #0
|
|
cmn r0, r1
|
|
1:
|
|
pop {r0, r1, r2, r3, r4, pc}
|
|
|
|
FUNC_END aeabi_cfcmple
|
|
FUNC_END aeabi_cfcmpeq
|
|
FUNC_END aeabi_cfrcmple
|
|
|
|
FUNC_START aeabi_fcmpeq
|
|
|
|
push {r4, lr}
|
|
bl __eqsf2
|
|
neg r0, r0
|
|
add r0, r0, #1
|
|
pop {r4, pc}
|
|
|
|
FUNC_END aeabi_fcmpeq
|
|
|
|
.macro COMPARISON cond, helper, mode=sf2
|
|
FUNC_START aeabi_fcmp\cond
|
|
|
|
push {r4, lr}
|
|
bl __\helper\mode
|
|
cmp r0, #0
|
|
b\cond 1f
|
|
mov r0, #0
|
|
pop {r4, pc}
|
|
1:
|
|
mov r0, #1
|
|
pop {r4, pc}
|
|
|
|
FUNC_END aeabi_fcmp\cond
|
|
.endm
|
|
|
|
COMPARISON lt, le
|
|
COMPARISON le, le
|
|
COMPARISON gt, ge
|
|
COMPARISON ge, ge
|
|
|
|
#endif /* L_arm_cmpsf2 */
|
|
|
|
#ifdef L_arm_addsubdf3
|
|
|
|
FUNC_START aeabi_drsub
|
|
|
|
push {r4, lr}
|
|
mov r4, #1
|
|
lsl r4, #31
|
|
eor xxh, xxh, r4
|
|
bl __aeabi_dadd
|
|
pop {r4, pc}
|
|
|
|
FUNC_END aeabi_drsub
|
|
|
|
#endif /* L_arm_addsubdf3 */
|
|
|
|
#ifdef L_arm_cmpdf2
|
|
|
|
FUNC_START aeabi_cdrcmple
|
|
|
|
mov ip, r0
|
|
mov r0, r2
|
|
mov r2, ip
|
|
mov ip, r1
|
|
mov r1, r3
|
|
mov r3, ip
|
|
b 6f
|
|
|
|
FUNC_START aeabi_cdcmpeq
|
|
FUNC_ALIAS aeabi_cdcmple aeabi_cdcmpeq
|
|
|
|
@ The status-returning routines are required to preserve all
|
|
@ registers except ip, lr, and cpsr.
|
|
6: push {r0, r1, r2, r3, r4, lr}
|
|
bl __ledf2
|
|
@ Set the Z flag correctly, and the C flag unconditionally.
|
|
cmp r0, #0
|
|
@ Clear the C flag if the return value was -1, indicating
|
|
@ that the first operand was smaller than the second.
|
|
bmi 1f
|
|
mov r1, #0
|
|
cmn r0, r1
|
|
1:
|
|
pop {r0, r1, r2, r3, r4, pc}
|
|
|
|
FUNC_END aeabi_cdcmple
|
|
FUNC_END aeabi_cdcmpeq
|
|
FUNC_END aeabi_cdrcmple
|
|
|
|
FUNC_START aeabi_dcmpeq
|
|
|
|
push {r4, lr}
|
|
bl __eqdf2
|
|
neg r0, r0
|
|
add r0, r0, #1
|
|
pop {r4, pc}
|
|
|
|
FUNC_END aeabi_dcmpeq
|
|
|
|
.macro COMPARISON cond, helper, mode=df2
|
|
FUNC_START aeabi_dcmp\cond
|
|
|
|
push {r4, lr}
|
|
bl __\helper\mode
|
|
cmp r0, #0
|
|
b\cond 1f
|
|
mov r0, #0
|
|
pop {r4, pc}
|
|
1:
|
|
mov r0, #1
|
|
pop {r4, pc}
|
|
|
|
FUNC_END aeabi_dcmp\cond
|
|
.endm
|
|
|
|
COMPARISON lt, le
|
|
COMPARISON le, le
|
|
COMPARISON gt, ge
|
|
COMPARISON ge, ge
|
|
|
|
#endif /* L_arm_cmpdf2 */
|