/* libgcc routines for R8C/M16C/M32C
   Copyright (C) 2005-2023 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
