1 /* libgcc routines for M68HC11
& M68HC12.
2 Copyright
(C
) 1999, 2000, 2001, 2002, 2003 Free Software Foundation
, Inc.
4 This file is part of GCC.
6 GCC 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
, 51 Franklin Street
, Fifth Floor
,
27 Boston
, MA
02110-1301, 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.
*/
38 #ifdef __HAVE_SHORT_INT__
44 .
macro declare_near
name
47 .
size \name
,.Lend
-\name
51 #if defined
(__USE_RTC__
)
65 .
size \name
,.Lend
-\name
87 .
size \name
,.Lend
-\name
98 .
type NAME,@object ; \
102 /* Pseudo hard registers used by gcc.
103 They should be located
in page0.
*/
149 /* Pseudo hard registers used by gcc.
150 They should be located
in page0.
*/
152 .globl _.d9
,_.d10
,_.d11
,_.d12
,_.d13
,_.d14
166 /* Pseudo hard registers used by gcc.
167 They should be located
in page0.
*/
169 .globl _.d17
,_.d18
,_.d19
,_.d20
,_.d21
,_.d22
170 .globl _.d23
,_.d24
,_.d25
,_.d26
,_.d27
,_.d28
171 .globl _.d29
,_.d30
,_.d31
,_.d32
192 ;; Specific initialization for 68hc11 before the main.
193 ;; Nothing special for a generic routine; Just enable interrupts.
195 declare_near __premain
197 tap
; Clear both I and X.
203 ;; Exit operation. Just loop forever and wait for interrupts.
204 ;; (no other place to go)
205 ;; This operation is split in several pieces collected together by
206 ;; the linker script. This allows to support destructors at the
207 ;; exit stage while not impacting program sizes when there is no
211 ;; *(.fini0) /* Beginning of finish code (_exit symbol). */
212 ;; *(.fini1) /* Place holder for applications. */
213 ;; *(.fini2) /* C++ destructors. */
214 ;; *(.fini3) /* Place holder for applications. */
215 ;; *(.fini4) /* Runtime exit. */
217 .sect .fini0
,"ax",@progbits
226 .sect .fini4
,"ax",@progbits
235 ;; Abort operation. This is defined for the GCC testsuite.
243 .
byte 0xCD ; Generate an illegal instruction trap
244 .
byte 0x03 ; The simulator catches this and stops.
251 ;; Cleanup operation used by exit().
258 ;-----------------------------------------
259 ; required gcclib code
260 ;-----------------------------------------
267 ;;; void* memcpy(void*, const void*, size_t)
271 ;;; 4,sp = size HImode (size_t)
293 ldx ARG
(2),x
; SRC = X, DST = Y
297 inca
; Correction for the deca below
299 psha
; Save high-counter part
301 ldaa
0,x
; Copy up to 256 bytes
310 puly
; Restore Y to return the DST
321 ;;; void* memset(void*, int value, size_t)
323 #ifndef __HAVE_SHORT_INT__
325 ;;; 2,sp = src SImode
326 ;;; 6,sp = size HImode (size_t)
331 ;;; 2,sp = src SImode
332 ;;; 6,sp = size HImode (size_t)
352 ldy
size,y
; DST = X, CNT = Y
356 stab
0,x
; Fill up to 256 bytes
360 pulx
; Restore X to return the DST
372 ldd ARG
(8),x
; Add LSB
374 std 6,y
; Save (carry preserved)
387 adcb ARG
(11),x
; Add MSB
400 ldd ARG
(8),x
; Subtract LSB
402 std 6,y
; Save, borrow preserved
414 ldd ARG
(2),x
; Subtract MSB
452 declare_near ___negsi2
468 declare_near ___one_cmplsi2
480 declare_near ___ashlsi3
500 declare_near ___ashrsi3
521 declare_near ___lshrsi3
541 declare_near ___lshrhi3
560 declare_near ___lshlhi3
579 declare_near ___rotrhi3
598 declare_near ___rotlhi3
618 declare_near ___ashrhi3
621 bge Return_minus_1_or_zero
631 Return_minus_1_or_zero:
642 declare_near ___ashrqi3
645 bge Return_minus_1_or_zero
654 Return_minus_1_or_zero:
665 declare_near ___lshlqi3
684 /* 68HC
12 signed divisions are generated inline
(idivs
).
*/
686 declare_near __divmodhi4
697 comb
; D = -D <=> D = (~D) + 1
702 bpl Numerator_neg_denominator_pos
703 Numerator_neg_denominator_neg:
711 xgdx
; Remainder <= 0 and result >= 0
715 Numerator_pos_denominator_pos:
718 xgdx
; Both values are >= 0
724 bpl Numerator_pos_denominator_pos
725 Numerator_pos_denominator_neg:
731 xgdx
; Remainder >= 0 but result <= 0
737 Numerator_neg_denominator_pos:
740 coma
; One value is > 0 and the other < 0
741 comb
; Change the sign of result and remainder
748 #endif
/* !mc68hc12
*/
752 declare_near ___mulqi3
755 ; short __mulqi3(signed char a, signed char b);
757 ; signed char a -> register A
758 ; signed char b -> register B
760 ; returns the signed result of A * B in register D.
788 declare_near ___mulhi3
792 ; unsigned short ___mulhi3(unsigned short a, unsigned short b)
807 ; 16 bit multiplication without temp memory location.
808 ; (smaller but slower)
817 mul ; (10) B.high * A.low
819 mul ; (10) B.low * A.high
823 mul ; (10) B.low * A.low
835 mul ; (10) A.high * B.low
840 mul ; (10) A.low * B.high
845 mul ; (10) A.low * B.low
847 rts
; (5) 24/32 bytes
857 ; unsigned long __mulhi32(unsigned short a, unsigned short b)
878 ; +---------------+ <- 0,x
887 declare_near __mulhi32
895 pshx
; Room for temp value
901 xgdy
; A.high * B.high
922 pulx
; Drop temp location
923 pshy
; Put high part in X
946 ; (((A.low * B.high) + (A.high * B.low)) << 16) + (A.low * B.low)
956 emul
; A.low * B.high
959 emul
; A.high * B.low
978 ; If B.low is 0, optimize into: (A.low * B.high) << 16
983 ; If A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
987 bsr ___mulhi3
; A.high * B.low
989 ; If A.low is 0, optimize into: (A.high * B.low) << 16
992 beq A_low_zero
; X = 0, D = A.high * B.low
995 ; If B.high is 0, we can avoid the (A.low * B.high) << 16 term.
999 bsr ___mulhi3
; A.low * B.high
1003 ; Here, we know that A.low and B.low are not 0.
1006 ldd B_low
,y
; A.low is on the stack
1007 bsr __mulhi32
; A.low * B.low
1009 tsy
; Y was clobbered, get it back
1011 A_low_zero: ; See A_low_zero_non_optimized below
1021 ; A_low_zero_non_optimized:
1023 ; At this step, X = 0 and D = (A.high * B.low)
1024 ; Optimize into: (A.high * B.low) << 16
1027 ; clra ; Since X was 0, clearing D is superfuous.
1031 ; B.low == 0, the result is: (A.low * B.high) << 16
1036 ; A.low is at A_low,y ?
1037 ; B.low is at B_low,y ?
1052 ; A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
1057 ; A.low is at A_low,y ?
1058 ; B.low is at B_low,y ?
1063 ldx B_high
,y
; B.high
1067 bra B_high_zero
; Do the (A.low * B.low) and the add.
1070 ; A.high and B.high are 0 optimize into: (A.low * B.low)
1075 ; A.low is at A_low,y != 0
1076 ; B.high is at B_high,y = 0
1079 ldd B_low
,y
; A.low is on the stack
1087 .sect .install2
,"ax",@progbits
1088 .globl __map_data_section
1091 .globl __data_section_size
1096 ldy #__data_section_start
1097 ldd #__data_section_size
1104 ldy #__data_section_start
1112 cpx #__data_image_end
1121 .sect .install2
,"ax",@progbits
1122 .globl __init_bss_section
1144 ; End of constructor table
1145 .sect .install3
,"ax",@progbits
1146 .globl __do_global_ctors
1149 ; Start from the end - sizeof(void*)
1167 .sect .fini3
,"ax",@progbits
1168 .globl __do_global_dtors
1171 ;; This piece of code is inserted in the _exit() code by the linker.
1174 pshb
; Save exit code
1188 pula
; Restore exit code
1195 .sect .tramp
,"ax",@progbits
1196 .globl __far_trampoline
1198 ;; This is a trampoline used by the linker to invoke a function
1199 ;; using rtc to return and being called with jsr/bsr.
1200 ;; The trampoline generated is:
1204 ;; call __far_trampoline,page(foo)
1206 ;; The linker transforms:
1213 ;; The linker generated trampoline and _far_trampoline must be in
1214 ;; non-banked memory.
1217 movb
0,sp, 2,sp ; Copy page register below the caller's return
1218 leas
2,sp ; address.
1219 jmp 0,y
; We have a 'call/rtc' stack layout now
1220 ; and can jump to the far handler
1221 ; (whose memory bank is mapped due to the
1222 ; call to the trampoline).
1226 .sect .tramp
,"ax",@progbits
1227 .globl __far_trampoline
1229 ;; Trampoline generated by gcc for 68HC11:
1232 ;; ldab #%page(func)
1234 ;; jmp __far_trampoline
1237 psha
; (2) Save function parameter (high)
1238 ;; <Read current page in A>
1240 ;; <Set currenge page from B>
1243 ldab
4,x
; (4) Restore function parameter (low)
1244 ldaa
2,x
; (4) Get saved page number
1245 staa
4,x
; (4) Save it below return PC
1248 pula
; (3) Restore function parameter (high)
1255 .sect .tramp
,"ax",@progbits
1259 ;; The call methods are used for 68HC11 to support memory bank switching.
1260 ;; Every far call is redirected to these call methods. Its purpose is to:
1262 ;; 1/ Save the current page on the stack (1 byte to follow 68HC12 call frame)
1263 ;; 2/ Install the new page
1264 ;; 3/ Jump to the real function
1266 ;; The page switching (get/save) is board dependent. The default provided
1267 ;; here does nothing (just create the appropriate call frame).
1269 ;; Call sequence (10 bytes, 13 cycles):
1273 ;; jsr __call_a16 ; (6)
1275 ;; Call trampoline (11 bytes, 19 cycles):
1279 ;; <Read current page in A> ; (3) ldaa _current_page
1281 ;; <Set current page from B> ; (4) staa _current_page
1286 ;; Call sequence (10 bytes, 14 cycles):
1291 ;; jsr __call_a32 ; (6)
1293 ;; Call trampoline (87 bytes, 57 cycles):
1298 ;; <Read current page in A> ; (3) ldaa _current_page
1300 ;; <Set current page from B> ; (4) staa _current_page
1302 ldab
6,x
; (4) Restore function parameter
1303 ldaa
5,x
; (4) Move PC return at good place
1317 .sect .tramp
,"ax",@progbits
1318 .globl __return_void
1324 ;; <Set current page from B> (Board specific)
1329 ;; <Set current page from B> (Board specific)
1335 ;; <Set current page from B> (Board specific)
1343 ;-----------------------------------------
1344 ; end required gcclib code
1345 ;-----------------------------------------