Replace occurrences of #elif with #if...#endif.
[official-gcc.git] / gcc / config / m68hc11 / larith.asm
blob4c24dccfa82b49c1d1d1c98b9529e09de42b8313
1 /* libgcc routines for M68HC11 & M68HC12.
2 Copyright (C) 1999, 2000, 2001 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
9 later version.
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. */
36 .file "larith.asm"
38 .sect .text
41 #define REG(NAME) \
42 NAME: .word 0; \
43 .type NAME,@object ; \
44 .size NAME,2
46 #ifdef L_regs_min
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. */
50 #ifdef mc68hc12
51 .sect .bss
52 #else
53 .sect .page0
54 #endif
55 .globl _.tmp
56 .globl _.z,_.xy
57 REG(_.tmp)
58 REG(_.z)
59 REG(_.xy)
61 #endif
63 #ifdef L_regs_frame
64 #ifdef mc68hc12
65 .sect .bss
66 #else
67 .sect .page0
68 #endif
69 .globl _.frame
70 REG(_.frame)
71 #endif
73 #ifdef L_regs_d1_2
74 #ifdef mc68hc12
75 .sect .bss
76 #else
77 .sect .page0
78 #endif
79 .globl _.d1,_.d2
80 REG(_.d1)
81 REG(_.d2)
82 #endif
84 #ifdef L_regs_d3_4
85 #ifdef mc68hc12
86 .sect .bss
87 #else
88 .sect .page0
89 #endif
90 .globl _.d3,_.d4
91 REG(_.d3)
92 REG(_.d4)
93 #endif
95 #ifdef L_regs_d5_6
96 #ifdef mc68hc12
97 .sect .bss
98 #else
99 .sect .page0
100 #endif
101 .globl _.d5,_.d6
102 REG(_.d5)
103 REG(_.d6)
104 #endif
106 #ifdef L_regs_d7_8
107 #ifdef mc68hc12
108 .sect .bss
109 #else
110 .sect .page0
111 #endif
112 .globl _.d7,_.d8
113 REG(_.d7)
114 REG(_.d8)
115 #endif
117 #ifdef L_regs_d9_16
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. */
121 .sect .page0
122 .globl _.d9,_.d10,_.d11,_.d12,_.d13,_.d14
123 .globl _.d15,_.d16
124 REG(_.d9)
125 REG(_.d10)
126 REG(_.d11)
127 REG(_.d12)
128 REG(_.d13)
129 REG(_.d14)
130 REG(_.d15)
131 REG(_.d16)
133 #endif
135 #ifdef L_regs_d17_32
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. */
139 #ifdef mc68hc12
140 .sect .bss
141 #else
142 .sect .page0
143 #endif
144 .globl _.d17,_.d18,_.d19,_.d20,_.d21,_.d22
145 .globl _.d23,_.d24,_.d25,_.d26,_.d27,_.d28
146 .globl _.d29,_.d30,_.d31,_.d32
147 REG(_.d17)
148 REG(_.d18)
149 REG(_.d19)
150 REG(_.d20)
151 REG(_.d21)
152 REG(_.d22)
153 REG(_.d23)
154 REG(_.d24)
155 REG(_.d25)
156 REG(_.d26)
157 REG(_.d27)
158 REG(_.d28)
159 REG(_.d29)
160 REG(_.d30)
161 REG(_.d31)
162 REG(_.d32)
163 #endif
165 #ifdef L_premain
167 ;; Specific initialization for 68hc11 before the main.
168 ;; Nothing special for a generic routine; Just enable interrupts.
170 .sect .text
171 .globl __premain
172 __premain:
173 clra
174 tap ; Clear both I and X.
176 #endif
178 #ifdef L__exit
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
185 ;; destructors.
187 ;; _exit:
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
195 .globl _exit
196 .globl exit
197 .weak exit
198 exit:
199 _exit:
201 .sect .fini4,"ax",@progbits
202 fatal:
205 bra fatal
206 #endif
208 #ifdef L_abort
210 ;; Abort operation. This is defined for the GCC testsuite.
212 .sect .text
213 .globl abort
214 abort:
215 ldd #255 ;
216 #ifdef mc68hc12
217 trap #0x30
218 #else
219 .byte 0xCD ; Generate an illegal instruction trap
220 .byte 0x03 ; The simulator catches this and stops.
221 #endif
222 jmp _exit
223 #endif
225 #ifdef L_cleanup
227 ;; Cleanup operation used by exit().
229 .sect .text
230 .globl _cleanup
231 _cleanup:
233 #endif
235 ;-----------------------------------------
236 ; required gcclib code
237 ;-----------------------------------------
238 #ifdef L_memcpy
239 .sect .text
240 .weak memcpy
241 .globl memcpy
242 .globl __memcpy
244 ;;; void* memcpy(void*, const void*, size_t)
245 ;;;
246 ;;; D = dst Pmode
247 ;;; 2,sp = src Pmode
248 ;;; 4,sp = size HImode (size_t)
249 ;;;
250 __memcpy:
251 memcpy:
252 #ifdef mc68hc12
253 ldx 2,sp
254 ldy 4,sp
255 pshd
256 xgdy
257 lsrd
258 bcc Start
259 movb 1,x+,1,y+
260 Start:
261 beq Done
262 Loop:
263 movw 2,x+,2,y+
264 dbne d,Loop
265 Done:
266 puld
268 #else
269 xgdy
271 ldd 4,x
272 ldx 2,x ; SRC = X, DST = Y
273 cpd #0
274 beq End
275 pshy
276 inca ; Correction for the deca below
278 psha ; Save high-counter part
280 ldaa 0,x ; Copy up to 256 bytes
281 staa 0,y
284 decb
285 bne L1
286 pula
287 deca
288 bne L0
289 puly ; Restore Y to return the DST
290 End:
291 xgdy
293 #endif
294 #endif
296 #ifdef L_memset
297 .sect .text
298 .globl memset
299 .globl __memset
301 ;;; void* memset(void*, int value, size_t)
302 ;;;
303 #ifndef __HAVE_SHORT_INT__
304 ;;; D = dst Pmode
305 ;;; 2,sp = src SImode
306 ;;; 6,sp = size HImode (size_t)
307 val = 5
308 size = 6
309 #else
310 ;;; D = dst Pmode
311 ;;; 2,sp = src SImode
312 ;;; 6,sp = size HImode (size_t)
313 val = 3
314 size = 4
315 #endif
316 __memset:
317 memset:
318 #ifdef mc68hc12
319 xgdx
320 ldab val,sp
321 ldy size,sp
322 pshx
323 beq End
324 Loop:
325 stab 1,x+
326 dbne y,Loop
327 End:
328 puld
330 #else
331 xgdx
333 ldab val,y
334 ldy size,y ; DST = X, CNT = Y
335 beq End
336 pshx
338 stab 0,x ; Fill up to 256 bytes
341 bne L0
342 pulx ; Restore X to return the DST
343 End:
344 xgdx
346 #endif
347 #endif
349 #ifdef L_adddi3
350 .sect .text
351 .globl ___adddi3
353 ___adddi3:
355 pshb
356 psha
357 ldd 8,x
358 addd 16,x
359 pshb
360 psha
362 ldd 6,x
363 adcb 15,x
364 adca 14,x
365 pshb
366 psha
368 ldd 4,x
369 adcb 13,x
370 adca 12,x
371 pshb
372 psha
374 ldd 2,x
375 adcb 11,x
376 adca 10,x
378 ldy 6,x
380 std 0,y
381 pulx
382 stx 2,y
383 pulx
384 stx 4,y
385 pulx
386 stx 6,y
387 pulx
389 #endif
391 #ifdef L_subdi3
392 .sect .text
393 .globl ___subdi3
395 ___subdi3:
397 pshb
398 psha
399 ldd 8,x
400 subd 16,x
401 pshb
402 psha
404 ldd 6,x
405 sbcb 15,x
406 sbca 14,x
407 pshb
408 psha
410 ldd 4,x
411 sbcb 13,x
412 sbca 12,x
413 pshb
414 psha
416 ldd 2,x
417 sbcb 11,x
418 sbca 10,x
421 ldy 6,x
423 std 0,y
424 pulx
425 stx 2,y
426 pulx
427 stx 4,y
428 pulx
429 stx 6,y
430 pulx
432 #endif
434 #ifdef L_notdi2
435 .sect .text
436 .globl ___notdi2
438 ___notdi2:
440 xgdx
441 ldd 8,y
442 coma
443 comb
444 std 6,x
446 ldd 6,y
447 coma
448 comb
449 std 4,x
451 ldd 4,y
452 coma
453 comb
454 std 2,x
456 ldd 2,y
457 coma
458 comb
459 std 0,x
461 #endif
463 #ifdef L_negsi2
464 .sect .text
465 .globl ___negsi2
467 ___negsi2:
468 comb
469 coma
470 addd #1
471 xgdx
472 eorb #0xFF
473 eora #0xFF
474 adcb #0
475 adca #0
476 xgdx
478 #endif
480 #ifdef L_one_cmplsi2
481 .sect .text
482 .globl ___one_cmplsi2
484 ___one_cmplsi2:
485 comb
486 coma
487 xgdx
488 comb
489 coma
490 xgdx
492 #endif
494 #ifdef L_ashlsi3
495 .sect .text
496 .globl ___ashlsi3
498 ___ashlsi3:
499 xgdy
500 clra
501 andb #0x1f
502 xgdy
503 beq Return
504 Loop:
505 lsld
506 xgdx
507 rolb
508 rola
509 xgdx
511 bne Loop
512 Return:
514 #endif
516 #ifdef L_ashrsi3
517 .sect .text
518 .globl ___ashrsi3
520 ___ashrsi3:
521 xgdy
522 clra
523 andb #0x1f
524 xgdy
525 beq Return
526 Loop:
527 xgdx
528 asra
529 rorb
530 xgdx
531 rora
532 rorb
534 bne Loop
535 Return:
537 #endif
539 #ifdef L_lshrsi3
540 .sect .text
541 .globl ___lshrsi3
543 ___lshrsi3:
544 xgdy
545 clra
546 andb #0x1f
547 xgdy
548 beq Return
549 Loop:
550 xgdx
551 lsrd
552 xgdx
553 rora
554 rorb
556 bne Loop
557 Return:
559 #endif
561 #ifdef L_lshrhi3
562 .sect .text
563 .globl ___lshrhi3
565 ___lshrhi3:
566 cpx #16
567 bge Return_zero
568 cpx #0
569 beq Return
570 Loop:
571 lsrd
573 bne Loop
574 Return:
576 Return_zero:
577 clra
578 clrb
580 #endif
582 #ifdef L_lshlhi3
583 .sect .text
584 .globl ___lshlhi3
586 ___lshlhi3:
587 cpx #16
588 bge Return_zero
589 cpx #0
590 beq Return
591 Loop:
592 lsld
594 bne Loop
595 Return:
597 Return_zero:
598 clra
599 clrb
601 #endif
603 #ifdef L_ashrhi3
604 .sect .text
605 .globl ___ashrhi3
607 ___ashrhi3:
608 cpx #16
609 bge Return_minus_1_or_zero
610 cpx #0
611 beq Return
612 Loop:
613 asra
614 rorb
616 bne Loop
617 Return:
619 Return_minus_1_or_zero:
620 clrb
621 tsta
622 bpl Return_zero
623 comb
624 Return_zero:
627 #endif
629 #ifdef L_ashrqi3
630 .sect .text
631 .globl ___ashrqi3
633 ___ashrqi3:
634 cmpa #8
635 bge Return_minus_1_or_zero
636 tsta
637 beq Return
638 Loop:
639 asrb
640 deca
641 bne Loop
642 Return:
644 Return_minus_1_or_zero:
645 clrb
646 tstb
647 bpl Return_zero
648 coma
649 Return_zero:
652 #endif
654 #ifdef L_lshlqi3
655 .sect .text
656 .globl ___lshlqi3
658 ___lshlqi3:
659 cmpa #8
660 bge Return_zero
661 tsta
662 beq Return
663 Loop:
664 lslb
665 deca
666 bne Loop
667 Return:
669 Return_zero:
670 clrb
672 #endif
674 #ifdef L_divmodhi4
675 #ifndef mc68hc12
676 /* 68HC12 signed divisions are generated inline (idivs). */
678 .sect .text
679 .globl __divmodhi4
682 ;; D = numerator
683 ;; X = denominator
685 ;; Result: D = D / X
686 ;; X = D % X
688 __divmodhi4:
689 tsta
690 bpl Numerator_pos
691 comb ; D = -D <=> D = (~D) + 1
692 coma
693 xgdx
695 tsta
696 bpl Numerator_neg_denominator_pos
697 Numerator_neg_denominator_neg:
698 comb ; X = -X
699 coma
700 addd #1
701 xgdx
702 idiv
703 coma
704 comb
705 xgdx ; Remainder <= 0 and result >= 0
709 Numerator_pos_denominator_pos:
710 xgdx
711 idiv
712 xgdx ; Both values are >= 0
715 Numerator_pos:
716 xgdx
717 tsta
718 bpl Numerator_pos_denominator_pos
719 Numerator_pos_denominator_neg:
720 coma ; X = -X
721 comb
722 xgdx
724 idiv
725 xgdx ; Remainder >= 0 but result <= 0
726 coma
727 comb
728 addd #1
731 Numerator_neg_denominator_pos:
732 xgdx
733 idiv
734 coma ; One value is > 0 and the other < 0
735 comb ; Change the sign of result and remainder
736 xgdx
738 coma
739 comb
740 addd #1
742 #endif /* !mc68hc12 */
743 #endif
745 #ifdef L_mulqi3
746 .sect .text
747 .globl __mulqi3
750 ; short __mulqi3(signed char a, signed char b);
752 ; signed char a -> register A
753 ; signed char b -> register B
755 ; returns the signed result of A * B in register D.
757 __mulqi3:
758 tsta
759 bmi A_neg
760 tstb
761 bmi B_neg
764 B_neg:
765 negb
766 bra A_or_B_neg
767 A_neg:
768 nega
769 tstb
770 bmi AB_neg
771 A_or_B_neg:
773 coma
774 comb
775 addd #1
777 AB_neg:
778 negb
781 #endif
783 #ifdef L_mulhi3
784 .sect .text
785 .globl ___mulhi3
789 ; unsigned short ___mulhi3(unsigned short a, unsigned short b)
791 ; a = register D
792 ; b = register X
794 ___mulhi3:
795 #ifdef mc68hc12
796 pshx ; Preserve X
797 exg x,y
798 emul
799 exg x,y
800 pulx
801 #else
802 stx *_.tmp
803 pshb
804 ldab *_.tmp+1
805 mul ; A.high * B.low
806 ldaa *_.tmp
807 stab *_.tmp
808 pulb
809 pshb
810 mul ; A.low * B.high
811 addb *_.tmp
812 stab *_.tmp
813 ldaa *_.tmp+1
814 pulb
815 mul ; A.low * B.low
816 adda *_.tmp
817 #endif
819 #endif
821 #ifdef L_mulhi32
822 .sect .text
823 .globl __mulhi32
827 ; unsigned long __mulhi32(unsigned short a, unsigned short b)
829 ; a = register D
830 ; b = value on stack
832 ; +---------------+
833 ; | B low | <- 5,x
834 ; +---------------+
835 ; | B high | <- 4,x
836 ; +---------------+
837 ; | PC low |
838 ; +---------------+
839 ; | PC high |
840 ; +---------------+
841 ; | A low |
842 ; +---------------+
843 ; | A high |
844 ; +---------------+ <- 0,x
847 ; <B-low> 5,x
848 ; <B-high> 4,x
849 ; <ret> 2,x
850 ; <A-low> 1,x
851 ; <A-high> 0,x
853 __mulhi32:
854 #ifdef mc68hc12
855 ldy 2,sp
856 emul
857 exg x,y
858 #else
859 pshb
860 psha
862 ldab 4,x
864 xgdy ; A.high * B.high
865 ldab 5,x
866 pula
867 mul ; A.high * B.low
868 std *_.tmp
869 ldaa 1,x
870 ldab 4,x
871 mul ; A.low * B.high
872 addd *_.tmp
873 stab *_.tmp
876 bcc N
877 ldab #0xff
881 ldab 5,x
882 pula
883 mul ; A.low * B.low
884 adda *_.tmp
885 bcc Ret
887 Ret:
888 pshy
889 pulx
890 #endif
893 #endif
895 #ifdef L_mulsi3
896 .sect .text
897 .globl __mulsi3
900 ; <B-low> 8,y
901 ; <B-high> 6,y
902 ; <ret> 4,y
903 ; <tmp> 2,y
904 ; <A-low> 0,y
906 ; D,X -> A
907 ; Stack -> B
909 ; The result is:
911 ; (((A.low * B.high) + (A.high * B.low)) << 16) + (A.low * B.low)
916 __mulsi3:
917 #ifdef mc68hc12
918 pshd ; Save A.low
919 ldy 4,sp
920 emul ; A.low * B.high
921 ldy 6,sp
922 exg x,d
923 emul ; A.high * B.low
924 leax d,x
925 ldy 6,sp
926 puld
927 emul ; A.low * B.low
928 exg d,y
929 leax d,x
930 exg d,y
932 #else
933 B_low = 8
934 B_high = 6
935 A_low = 0
936 A_high = 2
937 pshx
938 pshb
939 psha
942 ; If B.low is 0, optimize into: (A.low * B.high) << 16
944 ldd B_low,y
945 beq B_low_zero
947 ; If A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
949 stx *_.tmp
950 beq A_high_zero
951 bsr ___mulhi3 ; A.high * B.low
953 ; If A.low is 0, optimize into: (A.high * B.low) << 16
955 ldx A_low,y
956 beq A_low_zero ; X = 0, D = A.high * B.low
957 std 2,y
959 ; If B.high is 0, we can avoid the (A.low * B.high) << 16 term.
961 ldd B_high,y
962 beq B_high_zero
963 bsr ___mulhi3 ; A.low * B.high
964 addd 2,y
965 std 2,y
967 ; Here, we know that A.low and B.low are not 0.
969 B_high_zero:
970 ldd B_low,y ; A.low is on the stack
971 bsr __mulhi32 ; A.low * B.low
972 xgdx
973 tsy ; Y was clobbered, get it back
974 addd 2,y
975 A_low_zero: ; See A_low_zero_non_optimized below
976 xgdx
977 Return:
985 ; A_low_zero_non_optimized:
987 ; At this step, X = 0 and D = (A.high * B.low)
988 ; Optimize into: (A.high * B.low) << 16
990 ; xgdx
991 ; clra ; Since X was 0, clearing D is superfuous.
992 ; clrb
993 ; bra Return
994 ; ----------------
995 ; B.low == 0, the result is: (A.low * B.high) << 16
997 ; At this step:
998 ; D = B.low = 0
999 ; X = A.high ?
1000 ; A.low is at A_low,y ?
1001 ; B.low is at B_low,y ?
1003 B_low_zero:
1004 ldd A_low,y
1005 beq Zero1
1006 ldx B_high,y
1007 beq Zero2
1008 bsr ___mulhi3
1009 Zero1:
1010 xgdx
1011 Zero2:
1012 clra
1013 clrb
1014 bra Return
1015 ; ----------------
1016 ; A.high is 0, optimize into: (A.low * B.high) << 16 + (A.low * B.low)
1018 ; At this step:
1019 ; D = B.low != 0
1020 ; X = A.high = 0
1021 ; A.low is at A_low,y ?
1022 ; B.low is at B_low,y ?
1024 A_high_zero:
1025 ldd A_low,y ; A.low
1026 beq Zero1
1027 ldx B_high,y ; B.high
1028 beq A_low_B_low
1029 bsr ___mulhi3
1030 std 2,y
1031 bra B_high_zero ; Do the (A.low * B.low) and the add.
1033 ; ----------------
1034 ; A.high and B.high are 0 optimize into: (A.low * B.low)
1036 ; At this step:
1037 ; D = B.high = 0
1038 ; X = A.low != 0
1039 ; A.low is at A_low,y != 0
1040 ; B.high is at B_high,y = 0
1042 A_low_B_low:
1043 ldd B_low,y ; A.low is on the stack
1044 bsr __mulhi32
1045 bra Return
1046 #endif
1047 #endif
1049 #ifdef L_map_data
1051 .sect .install2,"ax",@progbits
1052 .globl __map_data_section
1054 __map_data_section:
1055 ldd #__data_section_size
1056 beq Done
1057 ldx #__data_image
1058 ldy #__data_section_start
1059 Loop:
1060 #ifdef mc68hc12
1061 movb 1,x+,1,y+
1062 dbne d,Loop
1063 #else
1064 psha
1065 ldaa 0,x
1066 staa 0,y
1067 pula
1070 subd #1
1071 bne Loop
1072 #endif
1073 Done:
1075 #endif
1077 #ifdef L_init_bss
1079 .sect .install2,"ax",@progbits
1080 .globl __init_bss_section
1082 __init_bss_section:
1083 ldd #__bss_size
1084 beq Done
1085 ldx #__bss_start
1086 Loop:
1087 #ifdef mc68hc12
1088 clr 1,x+
1089 dbne d,Loop
1090 #else
1091 clr 0,x
1093 subd #1
1094 bne Loop
1095 #endif
1096 Done:
1098 #endif
1100 #ifdef L_ctor
1102 ; End of constructor table
1103 .sect .install3,"ax",@progbits
1104 .globl __do_global_ctors
1106 __do_global_ctors:
1107 ; Start from the end - sizeof(void*)
1108 ldx #__CTOR_END__-2
1109 ctors_loop:
1110 cpx #__CTOR_LIST__
1111 blt ctors_done
1112 pshx
1113 ldx 0,x
1114 jsr 0,x
1115 pulx
1118 bra ctors_loop
1119 ctors_done:
1121 #endif
1123 #ifdef L_dtor
1125 .sect .fini3,"ax",@progbits
1126 .globl __do_global_dtors
1129 ;; This piece of code is inserted in the _exit() code by the linker.
1131 __do_global_dtors:
1132 pshb ; Save exit code
1133 psha
1134 ldx #__DTOR_LIST__
1135 dtors_loop:
1136 cpx #__DTOR_END__
1137 bge dtors_done
1138 pshx
1139 ldx 0,x
1140 jsr 0,x
1141 pulx
1144 bra dtors_loop
1145 dtors_done:
1146 pula ; Restore exit code
1147 pulb
1149 #endif
1151 ;-----------------------------------------
1152 ; end required gcclib code
1153 ;-----------------------------------------