1 /* libgcc routines for M68HC11 & M68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
4 This file is part of GNU CC.
6 GNU CC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file with other programs, and to distribute
14 those programs without any restriction coming from the use of this
15 file. (The General Public License restrictions do apply in other
16 respects; for example, they cover modification of the file, and
17 distribution when not linked into another program.)
19 This file is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA. */
29 /* As a special exception, if you link this library with other files,
30 some of which are compiled with GCC, to produce an executable,
31 this library does not by itself cause the resulting executable
32 to be covered by the GNU General Public License.
33 This exception does not however invalidate any other reasons why
34 the executable file might be covered by the GNU General Public License. */
43 .type NAME,@object ; \
47 /* Pseudo hard registers used by gcc.
48 They must be located in page0.
49 They will normally appear at the end of .page0 section. */
118 /* Pseudo hard registers used by gcc.
119 They must be located in page0.
120 They will normally appear at the end of .page0 section. */
122 .globl _.d9,_.d10,_.d11,_.d12,_.d13,_.d14
136 /* Pseudo hard registers used by gcc.
137 They must be located in page0.
138 They will normally appear at the end of .page0 section. */
144 .globl _.d17,_.d18,_.d19,_.d20,_.d21,_.d22
145 .globl _.d23,_.d24,_.d25,_.d26,_.d27,_.d28
146 .globl _.d29,_.d30,_.d31,_.d32
167 ;; Specific initialization for 68hc11 before the main.
168 ;; Nothing special for a generic routine; Just enable interrupts.
174 tap ; Clear both I and X.
180 ;; Exit operation. Just loop forever and wait for interrupts.
181 ;; (no other place to go)
182 ;; This operation is split in several pieces collected together by
183 ;; the linker script. This allows to support destructors at the
184 ;; exit stage while not impacting program sizes when there is no
188 ;; *(.fini0) /* Beginning of finish code (_exit symbol). */
189 ;; *(.fini1) /* Place holder for applications. */
190 ;; *(.fini2) /* C++ destructors. */
191 ;; *(.fini3) /* Place holder for applications. */
192 ;; *(.fini4) /* Runtime exit. */
194 .sect .fini0,"ax",@progbits
201 .sect .fini4,"ax",@progbits
210 ;; Abort operation. This is defined for the GCC testsuite.
219 .byte 0xCD ; Generate an illegal instruction trap
220 .byte 0x03 ; The simulator catches this and stops.
227 ;; Cleanup operation used by exit().
235 ;-----------------------------------------
236 ; required gcclib code
237 ;-----------------------------------------
244 ;;; void* memcpy(void*, const void*, size_t)
248 ;;; 4,sp = size HImode (size_t)
272 ldx 2,x ; SRC = X, DST = Y
276 inca ; Correction for the deca below
278 psha ; Save high-counter part
280 ldaa 0,x ; Copy up to 256 bytes
289 puly ; Restore Y to return the DST
301 ;;; void* memset(void*, int value, size_t)
303 #ifndef __HAVE_SHORT_INT__
305 ;;; 2,sp = src SImode
306 ;;; 6,sp = size HImode (size_t)
311 ;;; 2,sp = src SImode
312 ;;; 6,sp = size HImode (size_t)
334 ldy size,y ; DST = X, CNT = Y
338 stab 0,x ; Fill up to 256 bytes
342 pulx ; Restore X to return the DST
358 std 6,y ; Save (carry preserved)
386 ldd 8,x ; Subtract LSB
388 std 6,y ; Save, borrow preserved
400 ldd 2,x ; Subtract MSB
459 .globl ___one_cmplsi2
586 bge Return_minus_1_or_zero
596 Return_minus_1_or_zero:
612 bge Return_minus_1_or_zero
621 Return_minus_1_or_zero:
653 /* 68HC12 signed divisions are generated inline (idivs). */
668 comb ; D = -D <=> D = (~D) + 1
673 bpl Numerator_neg_denominator_pos
674 Numerator_neg_denominator_neg:
682 xgdx ; Remainder <= 0 and result >= 0
686 Numerator_pos_denominator_pos:
689 xgdx ; Both values are >= 0
695 bpl Numerator_pos_denominator_pos
696 Numerator_pos_denominator_neg:
702 xgdx ; Remainder >= 0 but result <= 0
708 Numerator_neg_denominator_pos:
711 coma ; One value is > 0 and the other < 0
712 comb ; Change the sign of result and remainder
719 #endif /* !mc68hc12 */
727 ; short __mulqi3(signed char a, signed char b);
729 ; signed char a -> register A
730 ; signed char b -> register B
732 ; returns the signed result of A * B in register D.
766 ; unsigned short ___mulhi3(unsigned short a, unsigned short b)
782 ; 16 bit multiplication without temp memory location.
783 ; (smaller but slower)
792 mul ; (10) B.high * A.low
794 mul ; (10) B.low * A.high
798 mul ; (10) B.low * A.low
810 mul ; (10) B.high * A.low
814 mul ; (10) B.low * A.high
817 mul ; (10) B.low * A.low
820 rts ; (5) 20/26 bytes
828 mul ; (10) A.high * B.low
833 mul ; (10) A.low * B.high
838 mul ; (10) A.low * B.low
840 rts ; (5) 24/32 bytes
853 ; unsigned long __mulhi32(unsigned short a, unsigned short b)
874 ; +---------------+ <- 0,x
890 pshx ; Room for temp value
896 xgdy ; A.high * B.high
917 pulx ; Drop temp location
918 pshy ; Put high part in X
943 ; (((A.low * B.high) + (A.high * B.low)) << 16) + (A.low * B.low)
952 emul ; A.low * B.high
955 emul ; A.high * B.low
974 ; If B.low is 0, optimize into: (A.low * B.high) << 16
979 ; If A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
983 bsr ___mulhi3 ; A.high * B.low
985 ; If A.low is 0, optimize into: (A.high * B.low) << 16
988 beq A_low_zero ; X = 0, D = A.high * B.low
991 ; If B.high is 0, we can avoid the (A.low * B.high) << 16 term.
995 bsr ___mulhi3 ; A.low * B.high
999 ; Here, we know that A.low and B.low are not 0.
1002 ldd B_low,y ; A.low is on the stack
1003 bsr __mulhi32 ; A.low * B.low
1005 tsy ; Y was clobbered, get it back
1007 A_low_zero: ; See A_low_zero_non_optimized below
1017 ; A_low_zero_non_optimized:
1019 ; At this step, X = 0 and D = (A.high * B.low)
1020 ; Optimize into: (A.high * B.low) << 16
1023 ; clra ; Since X was 0, clearing D is superfuous.
1027 ; B.low == 0, the result is: (A.low * B.high) << 16
1032 ; A.low is at A_low,y ?
1033 ; B.low is at B_low,y ?
1048 ; A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
1053 ; A.low is at A_low,y ?
1054 ; B.low is at B_low,y ?
1059 ldx B_high,y ; B.high
1063 bra B_high_zero ; Do the (A.low * B.low) and the add.
1066 ; A.high and B.high are 0 optimize into: (A.low * B.low)
1071 ; A.low is at A_low,y != 0
1072 ; B.high is at B_high,y = 0
1075 ldd B_low,y ; A.low is on the stack
1083 .sect .install2,"ax",@progbits
1084 .globl __map_data_section
1087 .globl __data_section_size
1092 ldy #__data_section_start
1093 ldd #__data_section_size
1100 ldy #__data_section_start
1108 cpx #__data_image_end
1117 .sect .install2,"ax",@progbits
1118 .globl __init_bss_section
1140 ; End of constructor table
1141 .sect .install3,"ax",@progbits
1142 .globl __do_global_ctors
1145 ; Start from the end - sizeof(void*)
1163 .sect .fini3,"ax",@progbits
1164 .globl __do_global_dtors
1167 ;; This piece of code is inserted in the _exit() code by the linker.
1170 pshb ; Save exit code
1184 pula ; Restore exit code
1189 ;-----------------------------------------
1190 ; end required gcclib code
1191 ;-----------------------------------------