diff gcc/config/m68hc11/larith.asm @ 0:a06113de4d67

first commit
author kent <kent@cr.ie.u-ryukyu.ac.jp>
date Fri, 17 Jul 2009 14:47:48 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/config/m68hc11/larith.asm	Fri Jul 17 14:47:48 2009 +0900
@@ -0,0 +1,1333 @@
+/* libgcc routines for M68HC11 & M68HC12.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2008, 2009
+   Free Software Foundation, Inc.
+
+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.
+
+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 __HAVE_SHORT_INT__
+	.mode mshort
+#else
+	.mode mlong
+#endif
+
+	.macro declare_near name
+	.globl \name
+	.type  \name,@function
+	.size  \name,.Lend-\name
+\name:
+	.endm
+
+#if defined(__USE_RTC__)
+# define ARG(N) N+1
+
+	.macro ret
+#if defined(mc68hc12)
+	rtc
+#else
+	jmp __return_32
+#endif
+	.endm
+
+	.macro declare name
+	.globl \name
+	.type  \name,@function
+	.size  \name,.Lend-\name
+	.far   \name
+\name:
+	.endm
+
+	.macro farsym name
+	.far NAME
+	.endm
+
+#else
+# define ARG(N) N
+
+	.macro ret
+	rts
+	.endm
+
+	.macro farsym name
+	.endm
+
+	.macro declare name
+	.globl \name
+	.type  \name,@function
+	.size  \name,.Lend-\name
+\name:
+	.endm
+
+#endif
+
+	.sect .text
+	
+
+#define REG(NAME)			\
+NAME:	.dc.w	1;			\
+	.type NAME,@object ;		\
+	.size NAME,2
+
+#ifdef L_regs_min
+/* Pseudo hard registers used by gcc.
+   They should be located in page0.  */
+
+	.sect .softregs
+	.globl _.tmp
+	.globl _.z,_.xy
+REG(_.tmp)
+REG(_.z)
+REG(_.xy)
+
+#endif
+
+#ifdef L_regs_frame
+	.sect .softregs
+	.globl _.frame
+REG(_.frame)
+#endif
+
+#ifdef L_regs_d1_2
+	.sect .softregs
+	.globl _.d1,_.d2
+REG(_.d1)
+REG(_.d2)
+#endif
+
+#ifdef L_regs_d3_4
+	.sect .softregs
+	.globl _.d3,_.d4
+REG(_.d3)
+REG(_.d4)
+#endif
+
+#ifdef L_regs_d5_6
+	.sect .softregs
+	.globl _.d5,_.d6
+REG(_.d5)
+REG(_.d6)
+#endif
+
+#ifdef L_regs_d7_8
+	.sect .softregs
+	.globl _.d7,_.d8
+REG(_.d7)
+REG(_.d8)
+#endif
+
+#ifdef L_regs_d9_16
+/* Pseudo hard registers used by gcc.
+   They should be located in page0.  */
+	.sect .softregs
+	.globl _.d9,_.d10,_.d11,_.d12,_.d13,_.d14
+	.globl _.d15,_.d16
+REG(_.d9)
+REG(_.d10)
+REG(_.d11)
+REG(_.d12)
+REG(_.d13)
+REG(_.d14)
+REG(_.d15)
+REG(_.d16)
+
+#endif
+
+#ifdef L_regs_d17_32
+/* Pseudo hard registers used by gcc.
+   They should be located in page0.  */
+	.sect .softregs
+	.globl _.d17,_.d18,_.d19,_.d20,_.d21,_.d22
+	.globl _.d23,_.d24,_.d25,_.d26,_.d27,_.d28
+	.globl _.d29,_.d30,_.d31,_.d32
+REG(_.d17)
+REG(_.d18)
+REG(_.d19)
+REG(_.d20)
+REG(_.d21)
+REG(_.d22)
+REG(_.d23)
+REG(_.d24)
+REG(_.d25)
+REG(_.d26)
+REG(_.d27)
+REG(_.d28)
+REG(_.d29)
+REG(_.d30)
+REG(_.d31)
+REG(_.d32)
+#endif
+
+#ifdef L_premain
+;;
+;; Specific initialization for 68hc11 before the main.
+;; Nothing special for a generic routine; Just enable interrupts.
+;;
+	declare_near	__premain
+	clra
+	tap	; Clear both I and X.
+	rts
+#endif
+
+#ifdef L__exit
+;;
+;; Exit operation.  Just loop forever and wait for interrupts.
+;; (no other place to go)
+;; This operation is split in several pieces collected together by
+;; the linker script.  This allows to support destructors at the
+;; exit stage while not impacting program sizes when there is no
+;; destructors.
+;;
+;; _exit:
+;;    *(.fini0)		/* Beginning of finish code (_exit symbol).  */
+;;    *(.fini1)		/* Place holder for applications.  */
+;;    *(.fini2)		/* C++ destructors.  */
+;;    *(.fini3)		/* Place holder for applications.  */
+;;    *(.fini4)		/* Runtime exit.  */
+;;
+	.sect .fini0,"ax",@progbits
+	.globl _exit
+	.globl exit
+	.weak  exit
+	farsym  exit
+	farsym  _exit
+exit:
+_exit:
+
+	.sect .fini4,"ax",@progbits
+fatal:
+	cli
+	wai
+	bra fatal
+#endif
+
+#ifdef L_abort
+;;
+;; Abort operation.  This is defined for the GCC testsuite.
+;;
+	declare	abort
+
+	ldd	#255		; 
+#ifdef mc68hc12
+	trap	#0x30
+#else
+	.byte 0xCD		; Generate an illegal instruction trap
+	.byte 0x03		; The simulator catches this and stops.
+#endif
+	jmp _exit
+#endif
+	
+#ifdef L_cleanup
+;;
+;; Cleanup operation used by exit().
+;;
+	declare	_cleanup
+
+	ret
+#endif
+
+;-----------------------------------------
+; required gcclib code
+;-----------------------------------------
+#ifdef L_memcpy
+       declare	memcpy
+       declare	__memcpy
+
+	.weak memcpy
+;;;
+;;; void* memcpy(void*, const void*, size_t)
+;;; 
+;;; D    = dst	Pmode
+;;; 2,sp = src	Pmode
+;;; 4,sp = size	HImode (size_t)
+;;; 
+#ifdef mc68hc12
+	ldx	ARG(2),sp
+	ldy	ARG(4),sp
+	pshd
+	xgdy
+	lsrd
+	bcc	Start
+	movb	1,x+,1,y+
+Start:
+	beq	Done
+Loop:
+	movw	2,x+,2,y+
+	dbne	d,Loop
+Done:
+	puld
+	ret
+#else
+	xgdy
+	tsx
+	ldd	ARG(4),x
+	ldx	ARG(2),x	; SRC = X, DST = Y
+	cpd	#0
+	beq	End
+	pshy
+	inca			; Correction for the deca below
+L0:
+	psha			; Save high-counter part
+L1:
+	ldaa	0,x		; Copy up to 256 bytes
+	staa	0,y
+	inx
+	iny
+	decb
+	bne	L1
+	pula
+	deca
+	bne	L0
+	puly			; Restore Y to return the DST
+End:
+	xgdy
+	ret
+#endif
+#endif
+
+#ifdef L_memset
+       declare	memset
+       declare	__memset
+;;;
+;;; void* memset(void*, int value, size_t)
+;;; 
+#ifndef __HAVE_SHORT_INT__
+;;; D    = dst	Pmode
+;;; 2,sp = src	SImode
+;;; 6,sp = size	HImode (size_t)
+	val  = ARG(5)
+	size = ARG(6)
+#else
+;;; D    = dst	Pmode
+;;; 2,sp = src	SImode
+;;; 6,sp = size	HImode (size_t)
+	val  = ARG(3)
+	size = ARG(4)
+#endif
+#ifdef mc68hc12
+	xgdx
+	ldab	val,sp
+	ldy	size,sp
+	pshx
+	beq	End
+Loop:
+	stab	1,x+
+	dbne	y,Loop
+End:
+	puld
+	ret
+#else
+	xgdx
+	tsy
+	ldab	val,y
+	ldy	size,y		; DST = X, CNT = Y
+	beq	End
+	pshx
+L0:
+	stab	0,x		; Fill up to 256 bytes
+	inx
+	dey
+	bne	L0
+	pulx			; Restore X to return the DST
+End:
+	xgdx
+	ret
+#endif
+#endif
+
+#ifdef L_adddi3
+	declare	___adddi3
+
+	tsx
+	xgdy
+	ldd	ARG(8),x		; Add LSB
+	addd	ARG(16),x
+	std	6,y		; Save (carry preserved)
+
+	ldd	ARG(6),x
+	adcb	ARG(15),x
+	adca	ARG(14),x
+	std	4,y
+
+	ldd	ARG(4),x
+	adcb	ARG(13),x
+	adca	ARG(12),x
+	std	2,y
+	
+	ldd	ARG(2),x
+	adcb	ARG(11),x		; Add MSB
+	adca	ARG(10),x
+	std	0,y
+
+	xgdy
+	ret
+#endif
+
+#ifdef L_subdi3
+	declare	___subdi3
+
+	tsx
+	xgdy
+	ldd	ARG(8),x		; Subtract LSB
+	subd	ARG(16),x
+	std	6,y			; Save, borrow preserved
+
+	ldd	ARG(6),x
+	sbcb	ARG(15),x
+	sbca	ARG(14),x
+	std	4,y
+
+	ldd	ARG(4),x
+	sbcb	ARG(13),x
+	sbca	ARG(12),x
+	std	2,y
+	
+	ldd	ARG(2),x		; Subtract MSB
+	sbcb	ARG(11),x
+	sbca	ARG(10),x
+	std	0,y
+
+	xgdy			;
+	ret
+#endif
+	
+#ifdef L_notdi2
+	declare	___notdi2
+
+	tsy
+	xgdx
+	ldd	ARG(8),y
+	coma
+	comb
+	std	6,x
+	
+	ldd	ARG(6),y
+	coma
+	comb
+	std	4,x
+
+	ldd	ARG(4),y
+	coma
+	comb
+	std	2,x
+
+	ldd	ARG(2),y
+	coma
+	comb
+	std	0,x
+	xgdx
+	ret
+#endif
+	
+#ifdef L_negsi2
+	declare_near ___negsi2
+
+	comb
+	coma
+	xgdx
+	comb
+	coma
+	inx
+	xgdx
+	bne	done
+	inx
+done:
+	rts
+#endif
+
+#ifdef L_one_cmplsi2
+	declare_near ___one_cmplsi2
+
+	comb
+	coma
+	xgdx
+	comb
+	coma
+	xgdx
+	rts
+#endif
+	
+#ifdef L_ashlsi3
+	declare_near ___ashlsi3
+
+	xgdy
+	clra
+	andb	#0x1f
+	xgdy
+	beq	Return
+Loop:
+	lsld
+	xgdx
+	rolb
+	rola
+	xgdx
+	dey
+	bne	Loop
+Return:
+	rts
+#endif
+
+#ifdef L_ashrsi3
+	declare_near ___ashrsi3
+
+	xgdy
+	clra
+	andb	#0x1f
+	xgdy
+	beq	Return
+Loop:
+	xgdx
+	asra
+	rorb
+	xgdx
+	rora
+	rorb
+	dey
+	bne	Loop
+Return:
+	rts
+#endif
+
+#ifdef L_lshrsi3
+	declare_near ___lshrsi3
+
+	xgdy
+	clra
+	andb	#0x1f
+	xgdy
+	beq	Return
+Loop:
+	xgdx
+	lsrd
+	xgdx
+	rora
+	rorb
+	dey
+	bne	Loop
+Return:
+	rts
+#endif
+
+#ifdef L_lshrhi3
+	declare_near ___lshrhi3
+
+	cpx	#16
+	bge	Return_zero
+	cpx	#0
+	beq	Return
+Loop:
+	lsrd
+	dex
+	bne	Loop
+Return:
+	rts
+Return_zero:
+	clra
+	clrb
+	rts
+#endif
+	
+#ifdef L_lshlhi3
+	declare_near ___lshlhi3
+
+	cpx	#16
+	bge	Return_zero
+	cpx	#0
+	beq	Return
+Loop:
+	lsld
+	dex
+	bne	Loop
+Return:
+	rts
+Return_zero:
+	clra
+	clrb
+	rts
+#endif
+
+#ifdef L_rotrhi3
+	declare_near ___rotrhi3
+
+___rotrhi3:
+	xgdx
+	clra
+	andb	#0x0f
+	xgdx
+	beq	Return
+Loop:
+	tap
+	rorb
+	rora
+	dex
+	bne	Loop
+Return:
+	rts
+#endif
+
+#ifdef L_rotlhi3
+	declare_near ___rotlhi3
+
+___rotlhi3:
+	xgdx
+	clra
+	andb	#0x0f
+	xgdx
+	beq	Return
+Loop:
+	asrb
+	rolb
+	rola
+	rolb
+	dex
+	bne	Loop
+Return:
+	rts
+#endif
+
+#ifdef L_ashrhi3
+	declare_near ___ashrhi3
+
+	cpx	#16
+	bge	Return_minus_1_or_zero
+	cpx	#0
+	beq	Return
+Loop:
+	asra
+	rorb
+	dex
+	bne	Loop
+Return:
+	rts
+Return_minus_1_or_zero:
+	clrb
+	tsta
+	bpl	Return_zero
+	comb
+Return_zero:
+	tba
+	rts
+#endif
+	
+#ifdef L_ashrqi3
+	declare_near ___ashrqi3
+
+	cmpa	#8
+	bge	Return_minus_1_or_zero
+	tsta
+	beq	Return
+Loop:
+	asrb
+	deca
+	bne	Loop
+Return:
+	rts
+Return_minus_1_or_zero:
+	clrb
+	tstb
+	bpl	Return_zero
+	coma
+Return_zero:
+	tab
+	rts
+#endif
+
+#ifdef L_lshlqi3
+	declare_near ___lshlqi3
+
+	cmpa	#8
+	bge	Return_zero
+	tsta
+	beq	Return
+Loop:
+	lslb
+	deca
+	bne	Loop
+Return:
+	rts
+Return_zero:
+	clrb
+	rts
+#endif
+
+#ifdef L_divmodhi4
+#ifndef mc68hc12
+/* 68HC12 signed divisions are generated inline (idivs).  */
+
+	declare_near __divmodhi4
+
+;
+;; D = numerator
+;; X = denominator
+;;
+;; Result:	D = D / X
+;;		X = D % X
+;; 
+	tsta
+	bpl	Numerator_pos
+	comb			; D = -D <=> D = (~D) + 1
+	coma
+	xgdx
+	inx
+	tsta
+	bpl	Numerator_neg_denominator_pos
+Numerator_neg_denominator_neg:
+	comb			; X = -X
+	coma
+	addd	#1
+	xgdx
+	idiv
+	coma
+	comb
+	xgdx			; Remainder <= 0 and result >= 0
+	inx
+	rts
+
+Numerator_pos_denominator_pos:
+	xgdx
+	idiv
+	xgdx			; Both values are >= 0
+	rts
+	
+Numerator_pos:
+	xgdx
+	tsta
+	bpl	Numerator_pos_denominator_pos
+Numerator_pos_denominator_neg:
+	coma			; X = -X
+	comb
+	xgdx
+	inx
+	idiv
+	xgdx			; Remainder >= 0 but result <= 0
+	coma
+	comb
+	addd	#1
+	rts
+	
+Numerator_neg_denominator_pos:
+	xgdx
+	idiv
+	coma			; One value is > 0 and the other < 0
+	comb			; Change the sign of result and remainder
+	xgdx
+	inx
+	coma
+	comb
+	addd	#1
+	rts
+#endif /* !mc68hc12 */
+#endif
+
+#ifdef L_mulqi3
+	declare_near ___mulqi3
+
+;
+; short __mulqi3(signed char a, signed char b);
+;
+;	signed char a	-> register A
+;	signed char b	-> register B
+;
+; returns the signed result of A * B in register D.
+;
+	tsta
+	bmi	A_neg
+	tstb
+	bmi	B_neg
+	mul
+	rts
+B_neg:
+	negb
+	bra	A_or_B_neg
+A_neg:
+	nega
+	tstb
+	bmi	AB_neg
+A_or_B_neg:
+	mul
+	coma
+	comb
+	addd	#1
+	rts
+AB_neg:
+	negb
+	mul
+	rts
+#endif
+	
+#ifdef L_mulhi3
+	declare_near ___mulhi3
+
+;
+;
+;  unsigned short ___mulhi3(unsigned short a, unsigned short b)
+;
+;	a = register D
+;	b = register X
+;
+#ifdef mc68hc12
+	pshx			; Preserve X
+	exg	x,y
+	emul
+	exg	x,y
+	pulx
+	rts
+#else
+#ifdef NO_TMP
+	;
+	; 16-bit multiplication without temp memory location.
+	; (smaller but slower)
+	;
+	pshx			; (4)
+	ins			; (3)
+	pshb			; (3)
+	psha			; (3)
+	pshx			; (4)
+	pula			; (4)
+	pulx			; (5)
+	mul			; (10) B.high * A.low
+	xgdx			; (3)
+	mul			; (10) B.low * A.high
+	abx			; (3)
+	pula			; (4)
+	pulb			; (4)
+	mul			; (10) B.low * A.low
+	pshx			; (4) 
+	tsx			; (3)
+	adda	1,x		; (4)
+	pulx			; (5)
+	rts			; (5) 20 bytes
+				; ---
+				; 91 cycles
+#else
+	stx	*_.tmp		; (4)
+	pshb			; (3)
+	ldab	*_.tmp+1	; (3)
+	mul			; (10) A.high * B.low
+	ldaa	*_.tmp		; (3)
+	stab	*_.tmp		; (3)
+	pulb			; (4)
+	pshb			; (4)
+	mul			; (10) A.low * B.high
+	addb	*_.tmp		; (4)
+	stab	*_.tmp		; (3)
+	ldaa	*_.tmp+1	; (3)
+	pulb			; (4)
+	mul			; (10) A.low * B.low
+	adda	*_.tmp		; (4)
+	rts			; (5) 24/32 bytes
+				; 77/85 cycles
+#endif
+#endif
+#endif
+
+#ifdef L_mulhi32
+
+;
+;
+;  unsigned long __mulhi32(unsigned short a, unsigned short b)
+;
+;	a = register D
+;	b = value on stack
+;
+;	+---------------+
+;       |  B low	| <- 7,x
+;	+---------------+
+;       |  B high	| <- 6,x
+;	+---------------+
+;       |  PC low	|  
+;	+---------------+
+;       |  PC high	|  
+;	+---------------+
+;	|  Tmp low	|
+;	+---------------+
+;	|  Tmp high     |
+;	+---------------+
+;	|  A low	|
+;	+---------------+
+;	|  A high	|
+;	+---------------+  <- 0,x
+;
+;
+;      <B-low>    5,x
+;      <B-high>   4,x
+;      <ret>      2,x
+;      <A-low>    1,x
+;      <A-high>   0,x
+;
+	declare_near	__mulhi32
+
+#ifdef mc68hc12
+	ldy	2,sp
+	emul
+	exg	x,y
+	rts
+#else
+	pshx			; Room for temp value
+	pshb
+	psha
+	tsx
+	ldab	6,x
+	mul
+	xgdy			; A.high * B.high
+	ldab	7,x
+	pula
+	mul			; A.high * B.low
+	std	2,x
+	ldaa	1,x
+	ldab	6,x
+	mul			; A.low * B.high
+	addd	2,x
+	stab	2,x
+	tab
+	aby
+	bcc	N
+	ldab	#0xff
+	aby
+	iny
+N:
+	ldab	7,x
+	pula
+	mul			; A.low * B.low
+	adda	2,x
+	pulx			; Drop temp location
+	pshy			; Put high part in X
+	pulx
+	bcc	Ret
+	inx
+Ret:
+	rts
+#endif	
+#endif
+
+#ifdef L_mulsi3
+
+;
+;      <B-low>    8,y
+;      <B-high>   6,y
+;      <ret>      4,y
+;	<tmp>	  2,y
+;      <A-low>    0,y
+;
+; D,X   -> A
+; Stack -> B
+;
+; The result is:
+;
+;	(((A.low * B.high) + (A.high * B.low)) << 16) + (A.low * B.low)
+;
+;
+;
+
+	declare	__mulsi3
+
+#ifdef mc68hc12
+	pshd				; Save A.low
+	ldy	ARG(4),sp
+	emul				; A.low * B.high
+	ldy	ARG(6),sp
+	exg	x,d
+	emul				; A.high * B.low
+	leax	d,x
+	ldy	ARG(6),sp
+	puld
+	emul				; A.low * B.low
+	exg	d,y
+	leax	d,x
+	exg	d,y
+	ret
+#else
+B_low	=	ARG(8)
+B_high	=	ARG(6)
+A_low	=	0
+A_high	=	2
+	pshx
+	pshb
+	psha
+	tsy
+;
+; If B.low is 0, optimize into: (A.low * B.high) << 16
+;
+	ldd	B_low,y
+	beq	B_low_zero
+;
+; If A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
+;
+	cpx	#0
+	beq	A_high_zero
+	bsr	___mulhi3		; A.high * B.low
+;
+; If A.low is 0, optimize into: (A.high * B.low) << 16
+;
+	ldx	A_low,y
+	beq	A_low_zero		; X = 0, D = A.high * B.low
+	std	2,y
+;
+; If B.high is 0, we can avoid the (A.low * B.high) << 16 term.
+;
+	ldd	B_high,y
+	beq	B_high_zero
+	bsr	___mulhi3		; A.low * B.high
+	addd	2,y
+	std	2,y
+;
+; Here, we know that A.low and B.low are not 0.
+;
+B_high_zero:
+	ldd	B_low,y			; A.low is on the stack
+	bsr	__mulhi32		; A.low * B.low
+	xgdx
+	tsy				; Y was clobbered, get it back
+	addd	2,y
+A_low_zero:				; See A_low_zero_non_optimized below
+	xgdx
+Return:
+	ins
+	ins
+	ins
+	ins
+	ret
+;
+; 
+; A_low_zero_non_optimized:
+;
+; At this step, X = 0 and D = (A.high * B.low)
+; Optimize into: (A.high * B.low) << 16
+;
+;	xgdx
+;	clra			; Since X was 0, clearing D is superfuous.
+;	clrb
+;	bra	Return
+; ----------------
+; B.low == 0, the result is:	(A.low * B.high) << 16
+;
+; At this step:
+;   D = B.low				= 0 
+;   X = A.high				?
+;       A.low is at A_low,y		?
+;       B.low is at B_low,y		?
+;
+B_low_zero:
+	ldd	A_low,y
+	beq	Zero1
+	ldx	B_high,y
+	beq	Zero2
+	bsr	___mulhi3
+Zero1:
+	xgdx
+Zero2:
+	clra
+	clrb
+	bra	Return
+; ----------------
+; A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
+;
+; At this step:
+;   D = B.low				!= 0 
+;   X = A.high				= 0
+;       A.low is at A_low,y		?
+;       B.low is at B_low,y		?
+;
+A_high_zero:
+	ldd	A_low,y		; A.low
+	beq	Zero1
+	ldx	B_high,y	; B.high
+	beq	A_low_B_low
+	bsr	___mulhi3
+	std	2,y
+	bra	B_high_zero	; Do the (A.low * B.low) and the add.
+
+; ----------------
+; A.high and B.high are 0 optimize into: (A.low * B.low)
+;
+; At this step:
+;   D = B.high				= 0 
+;   X = A.low				!= 0
+;       A.low is at A_low,y		!= 0
+;       B.high is at B_high,y		= 0
+;
+A_low_B_low:
+	ldd	B_low,y			; A.low is on the stack
+	bsr	__mulhi32
+	bra	Return
+#endif
+#endif
+
+#ifdef L_map_data
+
+	.sect	.install2,"ax",@progbits
+	.globl	__map_data_section
+	.globl __data_image
+#ifdef mc68hc12
+	.globl __data_section_size
+#endif
+__map_data_section:
+#ifdef mc68hc12
+	ldx	#__data_image
+	ldy	#__data_section_start
+	ldd	#__data_section_size
+	beq	Done
+Loop:
+	movb	1,x+,1,y+
+	dbne	d,Loop
+#else
+	ldx	#__data_image
+	ldy	#__data_section_start
+	bra	Start_map
+Loop:
+	ldaa	0,x
+	staa	0,y
+	inx
+	iny
+Start_map:
+	cpx	#__data_image_end
+	blo	Loop
+#endif
+Done:
+
+#endif
+
+#ifdef L_init_bss
+
+	.sect	.install2,"ax",@progbits
+	.globl	__init_bss_section
+
+__init_bss_section:
+	ldd	#__bss_size
+	beq	Done
+	ldx	#__bss_start
+Loop:
+#ifdef mc68hc12
+	clr	1,x+
+	dbne	d,Loop
+#else
+	clr	0,x
+	inx
+	subd	#1
+	bne	Loop
+#endif
+Done:
+
+#endif
+
+#ifdef L_ctor
+
+; End of constructor table
+	.sect	.install3,"ax",@progbits
+	.globl	__do_global_ctors
+
+__do_global_ctors:
+	; Start from the end - sizeof(void*)
+	ldx	#__CTOR_END__-2
+ctors_loop:
+	cpx	#__CTOR_LIST__
+	blo	ctors_done
+	pshx
+	ldx	0,x
+	jsr	0,x
+	pulx
+	dex
+	dex
+	bra	ctors_loop
+ctors_done:
+
+#endif
+
+#ifdef L_dtor
+
+	.sect	.fini3,"ax",@progbits
+	.globl	__do_global_dtors
+
+;;
+;; This piece of code is inserted in the _exit() code by the linker.
+;;
+__do_global_dtors:
+	pshb	; Save exit code
+	psha
+	ldx	#__DTOR_LIST__
+dtors_loop:
+	cpx	#__DTOR_END__
+	bhs	dtors_done
+	pshx
+	ldx	0,x
+	jsr	0,x
+	pulx
+	inx
+	inx
+	bra	dtors_loop
+dtors_done:
+	pula	; Restore exit code
+	pulb
+
+#endif
+
+#ifdef L_far_tramp
+#ifdef mc68hc12
+	.sect	.tramp,"ax",@progbits
+	.globl	__far_trampoline
+
+;; This is a trampoline used by the linker to invoke a function
+;; using rtc to return and being called with jsr/bsr.
+;; The trampoline generated is:
+;;
+;;	foo_tramp:
+;;		ldy	#foo
+;;		call	__far_trampoline,page(foo)
+;;
+;; The linker transforms:
+;;
+;;		jsr	foo
+;;
+;; into
+;;		jsr	foo_tramp
+;;
+;; The linker generated trampoline and _far_trampoline must be in 
+;; non-banked memory.
+;;
+__far_trampoline:
+	movb	0,sp, 2,sp	; Copy page register below the caller's return
+	leas	2,sp		; address.
+	jmp	0,y		; We have a 'call/rtc' stack layout now
+				; and can jump to the far handler
+				; (whose memory bank is mapped due to the
+				; call to the trampoline).
+#endif
+
+#ifdef mc68hc11
+	.sect	.tramp,"ax",@progbits
+	.globl __far_trampoline
+
+;; Trampoline generated by gcc for 68HC11:
+;;
+;;	pshb
+;;	ldab	#%page(func)
+;;	ldy	#%addr(func)
+;;	jmp	__far_trampoline
+;;
+__far_trampoline:
+	psha				; (2) Save function parameter (high)
+	;; <Read current page in A>
+	psha				; (2)
+	;; <Set currenge page from B>
+	pshx				; (4)
+	tsx				; (3)
+	ldab	4,x			; (4) Restore function parameter (low)
+	ldaa	2,x			; (4) Get saved page number
+	staa	4,x			; (4) Save it below return PC
+	pulx				; (5)
+	pula				; (3)
+	pula				; (3) Restore function parameter (high)
+	jmp	0,y			; (4)
+#endif
+#endif
+
+#ifdef L_call_far
+#ifdef mc68hc11
+	.sect	.tramp,"ax",@progbits
+	.globl __call_a16
+	.globl __call_a32
+;;
+;; The call methods are used for 68HC11 to support memory bank switching.
+;; Every far call is redirected to these call methods.  Its purpose is to:
+;;
+;;  1/ Save the current page on the stack (1 byte to follow 68HC12 call frame)
+;;  2/ Install the new page
+;;  3/ Jump to the real function
+;;
+;; The page switching (get/save) is board dependent.  The default provided
+;; here does nothing (just create the appropriate call frame).
+;;
+;; Call sequence (10 bytes, 13 cycles):
+;;
+;;	ldx #page			; (3)
+;;	ldy #func			; (4)
+;;	jsr __call_a16			; (6)
+;;
+;; Call trampoline (11 bytes, 19 cycles):
+;;
+__call_a16:
+	;; xgdx				; (3)
+	;; <Read current page in A>	; (3) ldaa _current_page
+	psha				; (2)
+	;; <Set current page from B>	; (4) staa _current_page
+	;; xgdx				; (3)
+	jmp 0,y				; (4)
+
+;;
+;; Call sequence (10 bytes, 14 cycles):
+;;
+;;	pshb				; (2)
+;;	ldab #page			; (2)
+;;	ldy  #func			; (4)
+;;	jsr __call_a32			; (6)
+;;
+;; Call trampoline (87 bytes, 57 cycles):
+;;
+__call_a32:
+	pshx				; (4)
+	psha				; (2)
+	;; <Read current page in A>	; (3) ldaa _current_page
+	psha				; (2)
+	;; <Set current page from B>	; (4) staa _current_page
+	tsx				; (3)
+	ldab	6,x			; (4) Restore function parameter
+	ldaa	5,x			; (4) Move PC return at good place
+	staa	6,x			; (4)
+	ldaa	4,x			; (4)
+	staa	5,x			; (4)
+	pula				; (3)
+	staa	4,x			; (4)
+	pula				; (3)
+	pulx				; (5)
+	jmp	0,y			; (4)
+#endif
+#endif
+
+#ifdef L_return_far
+#ifdef mc68hc11
+	.sect	.tramp,"ax",@progbits
+       .globl __return_void
+       .globl __return_16
+       .globl __return_32
+
+__return_void:
+	;; pulb
+	;; <Set current page from B> (Board specific)
+	;; rts
+__return_16:
+	;; xgdx
+	;; pulb
+	;; <Set current page from B> (Board specific)
+	;; xgdx
+	;; rts
+__return_32:
+	;; xgdy
+	;; pulb
+	;; <Set current page from B> (Board specific)
+	;; xgdy
+	;; rts
+	ins
+	rts
+#endif
+#endif
+.Lend:
+;-----------------------------------------
+; end required gcclib code
+;-----------------------------------------