1 /* libgcc routines for M68HC11 & M68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2008, 2009
3 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3, or (at your option) any
12 This file is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #ifdef __HAVE_SHORT_INT__
32 .macro declare_near name
35 .size \name,.Lend-\name
39 #if defined(__USE_RTC__)
53 .size \name,.Lend-\name
75 .size \name,.Lend-\name
86 .type NAME,@object ; \
90 /* Pseudo hard registers used by gcc.
91 They should be located in page0. */
137 /* Pseudo hard registers used by gcc.
138 They should be located in page0. */
140 .globl _.d9,_.d10,_.d11,_.d12,_.d13,_.d14
154 /* Pseudo hard registers used by gcc.
155 They should be located in page0. */
157 .globl _.d17,_.d18,_.d19,_.d20,_.d21,_.d22
158 .globl _.d23,_.d24,_.d25,_.d26,_.d27,_.d28
159 .globl _.d29,_.d30,_.d31,_.d32
180 ;; Specific initialization for 68hc11 before the main.
181 ;; Nothing special for a generic routine; Just enable interrupts.
183 declare_near __premain
185 tap ; Clear both I and X.
191 ;; Exit operation. Just loop forever and wait for interrupts.
192 ;; (no other place to go)
193 ;; This operation is split in several pieces collected together by
194 ;; the linker script. This allows to support destructors at the
195 ;; exit stage while not impacting program sizes when there is no
199 ;; *(.fini0) /* Beginning of finish code (_exit symbol). */
200 ;; *(.fini1) /* Place holder for applications. */
201 ;; *(.fini2) /* C++ destructors. */
202 ;; *(.fini3) /* Place holder for applications. */
203 ;; *(.fini4) /* Runtime exit. */
205 .sect .fini0,"ax",@progbits
214 .sect .fini4,"ax",@progbits
223 ;; Abort operation. This is defined for the GCC testsuite.
231 .byte 0xCD ; Generate an illegal instruction trap
232 .byte 0x03 ; The simulator catches this and stops.
239 ;; Cleanup operation used by exit().
246 ;-----------------------------------------
247 ; required gcclib code
248 ;-----------------------------------------
255 ;;; void* memcpy(void*, const void*, size_t)
259 ;;; 4,sp = size HImode (size_t)
281 ldx ARG(2),x ; SRC = X, DST = Y
285 inca ; Correction for the deca below
287 psha ; Save high-counter part
289 ldaa 0,x ; Copy up to 256 bytes
298 puly ; Restore Y to return the DST
309 ;;; void* memset(void*, int value, size_t)
311 #ifndef __HAVE_SHORT_INT__
313 ;;; 2,sp = src SImode
314 ;;; 6,sp = size HImode (size_t)
319 ;;; 2,sp = src SImode
320 ;;; 6,sp = size HImode (size_t)
340 ldy size,y ; DST = X, CNT = Y
344 stab 0,x ; Fill up to 256 bytes
348 pulx ; Restore X to return the DST
360 ldd ARG(8),x ; Add LSB
362 std 6,y ; Save (carry preserved)
375 adcb ARG(11),x ; Add MSB
388 ldd ARG(8),x ; Subtract LSB
390 std 6,y ; Save, borrow preserved
402 ldd ARG(2),x ; Subtract MSB
440 declare_near ___negsi2
456 declare_near ___one_cmplsi2
468 declare_near ___ashlsi3
488 declare_near ___ashrsi3
509 declare_near ___lshrsi3
529 declare_near ___lshrhi3
548 declare_near ___lshlhi3
567 declare_near ___rotrhi3
586 declare_near ___rotlhi3
606 declare_near ___ashrhi3
609 bge Return_minus_1_or_zero
619 Return_minus_1_or_zero:
630 declare_near ___ashrqi3
633 bge Return_minus_1_or_zero
642 Return_minus_1_or_zero:
653 declare_near ___lshlqi3
672 /* 68HC12 signed divisions are generated inline (idivs). */
674 declare_near __divmodhi4
685 comb ; D = -D <=> D = (~D) + 1
690 bpl Numerator_neg_denominator_pos
691 Numerator_neg_denominator_neg:
699 xgdx ; Remainder <= 0 and result >= 0
703 Numerator_pos_denominator_pos:
706 xgdx ; Both values are >= 0
712 bpl Numerator_pos_denominator_pos
713 Numerator_pos_denominator_neg:
719 xgdx ; Remainder >= 0 but result <= 0
725 Numerator_neg_denominator_pos:
728 coma ; One value is > 0 and the other < 0
729 comb ; Change the sign of result and remainder
736 #endif /* !mc68hc12 */
740 declare_near ___mulqi3
743 ; short __mulqi3(signed char a, signed char b);
745 ; signed char a -> register A
746 ; signed char b -> register B
748 ; returns the signed result of A * B in register D.
776 declare_near ___mulhi3
780 ; unsigned short ___mulhi3(unsigned short a, unsigned short b)
795 ; 16-bit multiplication without temp memory location.
796 ; (smaller but slower)
805 mul ; (10) B.high * A.low
807 mul ; (10) B.low * A.high
811 mul ; (10) B.low * A.low
823 mul ; (10) A.high * B.low
828 mul ; (10) A.low * B.high
833 mul ; (10) A.low * B.low
835 rts ; (5) 24/32 bytes
845 ; unsigned long __mulhi32(unsigned short a, unsigned short b)
866 ; +---------------+ <- 0,x
875 declare_near __mulhi32
883 pshx ; Room for temp value
889 xgdy ; A.high * B.high
910 pulx ; Drop temp location
911 pshy ; Put high part in X
934 ; (((A.low * B.high) + (A.high * B.low)) << 16) + (A.low * B.low)
944 emul ; A.low * B.high
947 emul ; A.high * B.low
966 ; If B.low is 0, optimize into: (A.low * B.high) << 16
971 ; If A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
975 bsr ___mulhi3 ; A.high * B.low
977 ; If A.low is 0, optimize into: (A.high * B.low) << 16
980 beq A_low_zero ; X = 0, D = A.high * B.low
983 ; If B.high is 0, we can avoid the (A.low * B.high) << 16 term.
987 bsr ___mulhi3 ; A.low * B.high
991 ; Here, we know that A.low and B.low are not 0.
994 ldd B_low,y ; A.low is on the stack
995 bsr __mulhi32 ; A.low * B.low
997 tsy ; Y was clobbered, get it back
999 A_low_zero: ; See A_low_zero_non_optimized below
1009 ; A_low_zero_non_optimized:
1011 ; At this step, X = 0 and D = (A.high * B.low)
1012 ; Optimize into: (A.high * B.low) << 16
1015 ; clra ; Since X was 0, clearing D is superfuous.
1019 ; B.low == 0, the result is: (A.low * B.high) << 16
1024 ; A.low is at A_low,y ?
1025 ; B.low is at B_low,y ?
1040 ; A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
1045 ; A.low is at A_low,y ?
1046 ; B.low is at B_low,y ?
1051 ldx B_high,y ; B.high
1055 bra B_high_zero ; Do the (A.low * B.low) and the add.
1058 ; A.high and B.high are 0 optimize into: (A.low * B.low)
1063 ; A.low is at A_low,y != 0
1064 ; B.high is at B_high,y = 0
1067 ldd B_low,y ; A.low is on the stack
1075 .sect .install2,"ax",@progbits
1076 .globl __map_data_section
1079 .globl __data_section_size
1084 ldy #__data_section_start
1085 ldd #__data_section_size
1092 ldy #__data_section_start
1100 cpx #__data_image_end
1109 .sect .install2,"ax",@progbits
1110 .globl __init_bss_section
1132 ; End of constructor table
1133 .sect .install3,"ax",@progbits
1134 .globl __do_global_ctors
1137 ; Start from the end - sizeof(void*)
1155 .sect .fini3,"ax",@progbits
1156 .globl __do_global_dtors
1159 ;; This piece of code is inserted in the _exit() code by the linker.
1162 pshb ; Save exit code
1176 pula ; Restore exit code
1183 .sect .tramp,"ax",@progbits
1184 .globl __far_trampoline
1186 ;; This is a trampoline used by the linker to invoke a function
1187 ;; using rtc to return and being called with jsr/bsr.
1188 ;; The trampoline generated is:
1192 ;; call __far_trampoline,page(foo)
1194 ;; The linker transforms:
1201 ;; The linker generated trampoline and _far_trampoline must be in
1202 ;; non-banked memory.
1205 movb 0,sp, 2,sp ; Copy page register below the caller's return
1206 leas 2,sp ; address.
1207 jmp 0,y ; We have a 'call/rtc' stack layout now
1208 ; and can jump to the far handler
1209 ; (whose memory bank is mapped due to the
1210 ; call to the trampoline).
1214 .sect .tramp,"ax",@progbits
1215 .globl __far_trampoline
1217 ;; Trampoline generated by gcc for 68HC11:
1220 ;; ldab #%page(func)
1222 ;; jmp __far_trampoline
1225 psha ; (2) Save function parameter (high)
1226 ;; <Read current page in A>
1228 ;; <Set currenge page from B>
1231 ldab 4,x ; (4) Restore function parameter (low)
1232 ldaa 2,x ; (4) Get saved page number
1233 staa 4,x ; (4) Save it below return PC
1236 pula ; (3) Restore function parameter (high)
1243 .sect .tramp,"ax",@progbits
1247 ;; The call methods are used for 68HC11 to support memory bank switching.
1248 ;; Every far call is redirected to these call methods. Its purpose is to:
1250 ;; 1/ Save the current page on the stack (1 byte to follow 68HC12 call frame)
1251 ;; 2/ Install the new page
1252 ;; 3/ Jump to the real function
1254 ;; The page switching (get/save) is board dependent. The default provided
1255 ;; here does nothing (just create the appropriate call frame).
1257 ;; Call sequence (10 bytes, 13 cycles):
1261 ;; jsr __call_a16 ; (6)
1263 ;; Call trampoline (11 bytes, 19 cycles):
1267 ;; <Read current page in A> ; (3) ldaa _current_page
1269 ;; <Set current page from B> ; (4) staa _current_page
1274 ;; Call sequence (10 bytes, 14 cycles):
1279 ;; jsr __call_a32 ; (6)
1281 ;; Call trampoline (87 bytes, 57 cycles):
1286 ;; <Read current page in A> ; (3) ldaa _current_page
1288 ;; <Set current page from B> ; (4) staa _current_page
1290 ldab 6,x ; (4) Restore function parameter
1291 ldaa 5,x ; (4) Move PC return at good place
1305 .sect .tramp,"ax",@progbits
1306 .globl __return_void
1312 ;; <Set current page from B> (Board specific)
1317 ;; <Set current page from B> (Board specific)
1323 ;; <Set current page from B> (Board specific)
1331 ;-----------------------------------------
1332 ; end required gcclib code
1333 ;-----------------------------------------