blob: 160ee17f6568a31a2f18c0e49ad49f60a9f8870d [file] [log] [blame]
/* libgcc routines for R8C/M16C/M32C
Copyright (C) 2005-2021 Free Software Foundation, Inc.
Contributed by Red Hat.
This file is part of GCC.
GCC 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.
GCC 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/>. */
#if defined(__r8c_cpu__) || defined(__m16c_cpu__)
#define A16
#define A(n,w) n
#define W w
#else
#define A24
#define A(n,w) w
#define W l
#endif
#ifdef L__m32c_memregs
/* Warning: these memory locations are used as a register bank. They
*must* end up consecutive in any final executable, so you may *not*
use the otherwise obvious ".comm" directive to allocate space for
them. */
.bss
.global mem0
mem0: .space 1
.global mem1
mem1: .space 1
.global mem2
mem2: .space 1
.global mem3
mem3: .space 1
.global mem4
mem4: .space 1
.global mem5
mem5: .space 1
.global mem6
mem6: .space 1
.global mem7
mem7: .space 1
.global mem8
mem8: .space 1
.global mem9
mem9: .space 1
.global mem10
mem10: .space 1
.global mem11
mem11: .space 1
.global mem12
mem12: .space 1
.global mem13
mem13: .space 1
.global mem14
mem14: .space 1
.global mem15
mem15: .space 1
#endif
#ifdef L__m32c_eh_return
.text
.global __m32c_eh_return
__m32c_eh_return:
/* At this point, r0 has the stack adjustment, r1r3 has the
address to return to. The stack looks like this:
old_ra
old_fp
<- unwound sp
...
fb
through
r0
<- sp
What we need to do is restore all the registers, update the
stack, and return to the right place.
*/
stc sp,a0
add.W A(#16,#24),a0
/* a0 points to the current stack, just above the register
save areas */
mov.w a0,a1
exts.w r0
sub.W A(r0,r2r0),a1
sub.W A(#3,#4),a1
/* a1 points to the new stack. */
/* This is for the "rts" below. */
mov.w r1,[a1]
#ifdef A16
mov.w r2,r1
mov.b r1l,2[a1]
#else
mov.w r2,2[a1]
#endif
/* This is for the "popc sp" below. */
mov.W a1,[a0]
popm r0,r1,r2,r3,a0,a1,sb,fb
popc sp
rts
#endif
/* SImode arguments for SI foo(SI,SI) functions. */
#ifdef A16
#define SAL 5[fb]
#define SAH 7[fb]
#define SBL 9[fb]
#define SBH 11[fb]
#else
#define SAL 8[fb]
#define SAH 10[fb]
#define SBL 12[fb]
#define SBH 14[fb]
#endif
#ifdef L__m32c_mulsi3
.text
.global ___mulsi3
___mulsi3:
enter #0
push.w r2
mov.w SAL,r0
mulu.w SBL,r0 /* writes to r2r0 */
mov.w r0,mem0
mov.w r2,mem2
mov.w SAL,r0
mulu.w SBH,r0 /* writes to r2r0 */
add.w r0,mem2
mov.w SAH,r0
mulu.w SBL,r0 /* writes to r2r0 */
add.w r0,mem2
pop.w r2
exitd
#endif
#ifdef L__m32c_cmpsi2
.text
.global ___cmpsi2
___cmpsi2:
enter #0
cmp.w SBH,SAH
jgt cmpsi_gt
jlt cmpsi_lt
cmp.w SBL,SAL
jgt cmpsi_gt
jlt cmpsi_lt
mov.w #1,r0
exitd
cmpsi_gt:
mov.w #2,r0
exitd
cmpsi_lt:
mov.w #0,r0
exitd
#endif
#ifdef L__m32c_ucmpsi2
.text
.global ___ucmpsi2
___ucmpsi2:
enter #0
cmp.w SBH,SAH
jgtu cmpsi_gt
jltu cmpsi_lt
cmp.w SBL,SAL
jgtu cmpsi_gt
jltu cmpsi_lt
mov.w #1,r0
exitd
cmpsi_gt:
mov.w #2,r0
exitd
cmpsi_lt:
mov.w #0,r0
exitd
#endif
#ifdef L__m32c_jsri16
.text
#ifdef A16
.global m32c_jsri16
m32c_jsri16:
add.w #-1, sp
/* Read the address (16 bits) and return address (24 bits) off
the stack. */
mov.w 4[sp], r0
mov.w 1[sp], r3
mov.b 3[sp], a0 /* This zero-extends, so the high byte has
zero in it. */
/* Write the return address, then new address, to the stack. */
mov.w a0, 1[sp] /* Just to get the zero in 2[sp]. */
mov.w r0, 0[sp]
mov.w r3, 3[sp]
mov.b a0, 5[sp]
/* This "returns" to the target address, leaving the pending
return address on the stack. */
rts
#endif
#endif