diff options
Diffstat (limited to 'gcc/config/m68hc11/larith.asm')
-rw-r--r-- | gcc/config/m68hc11/larith.asm | 968 |
1 files changed, 968 insertions, 0 deletions
diff --git a/gcc/config/m68hc11/larith.asm b/gcc/config/m68hc11/larith.asm new file mode 100644 index 00000000000..e75772964f1 --- /dev/null +++ b/gcc/config/m68hc11/larith.asm @@ -0,0 +1,968 @@ +/* libgcc1 routines for M68HC11. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +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. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + + .file "larith.asm" + + .sect .text + + +#define REG(NAME) \ +NAME: .word 0; \ + .type NAME,@object ; \ + .size NAME,2 + +#ifdef L_regs_min +/* Pseudo hard registers used by gcc. + They must be located in page0. + They will normally appear at the end of .page0 section. */ + .sect .page0 + .globl _.tmp,_.frame + .globl _.z,_.xy +REG(_.tmp) +REG(_.z) +REG(_.xy) +REG(_.frame) + +#endif + +#ifdef L_regs_d1_8 +/* Pseudo hard registers used by gcc. + They must be located in page0. + They will normally appear at the end of .page0 section. */ + .sect .page0 + .globl _.d1,_.d2,_.d3,_.d4,_.d5,_.d6 + .globl _.d7,_.d8 +REG(_.d1) +REG(_.d2) +REG(_.d3) +REG(_.d4) +REG(_.d5) +REG(_.d6) +REG(_.d7) +REG(_.d8) + +#endif + +#ifdef L_regs_d8_16 +/* Pseudo hard registers used by gcc. + They must be located in page0. + They will normally appear at the end of .page0 section. */ + .sect .page0 + .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 must be located in page0. + They will normally appear at the end of .page0 section. */ + .sect .page0 + .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. +;; + .sect .text + .globl __premain +__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) +;; + .sect .text + .globl _exit + .globl exit + .weak exit +exit: +_exit: +fatal: + cli + wai + bra fatal +#endif + +#ifdef L_abort +;; +;; Abort operation. This is defined for the GCC testsuite. +;; + .sect .text + .globl abort +abort: + ldd #255 ; + .byte 0xCD ; Generate an illegal instruction trap + .byte 0x03 ; The simulator catches this and stops. + jmp _exit +#endif + +#ifdef L_cleanup +;; +;; Cleanup operation used by exit(). +;; + .sect .text + .globl _cleanup +_cleanup: + rts +#endif + +;----------------------------------------- +; required gcclib code +;----------------------------------------- +#ifdef L_memcpy + .sect .text + .weak memcpy + .globl memcpy + .globl __memcpy +;;; +;;; void* memcpy(void*, const void*, size_t) +;;; +;;; D = dst Pmode +;;; 2,sp = src Pmode +;;; 4,sp = size HImode (size_t) +;;; +__memcpy: +memcpy: + xgdy + tsx + ldd 4,x + ldx 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 + rts +#endif + +#ifdef L_memset + .sect .text + .globl memset + .globl __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 = 5 + size = 6 +#else +;;; D = dst Pmode +;;; 2,sp = src SImode +;;; 6,sp = size HImode (size_t) + val = 3 + size = 4 +#endif +__memset: +memset: + 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 + rts +#endif + +#ifdef L_adddi3 + .sect .text + .globl ___adddi3 + +___adddi3: + tsx + tsy + pshb + psha + ldd 8,x + addd 16,y + pshb + psha + + ldd 6,x + adcb 15,y + adca 14,y + pshb + psha + + ldd 4,x + adcb 13,y + adca 12,y + pshb + psha + + ldd 2,x + adcb 11,y + adca 10,y + tsx + ldy 6,x + + std 0,y + pulx + stx 2,y + pulx + stx 4,y + pulx + stx 6,y + pulx + rts +#endif + +#ifdef L_subdi3 + .sect .text + .globl ___subdi3 + +___subdi3: + tsx + tsy + pshb + psha + ldd 8,x + subd 16,y + pshb + psha + + ldd 6,x + sbcb 15,y + sbca 14,y + pshb + psha + + ldd 4,x + sbcb 13,y + sbca 12,y + pshb + psha + + ldd 2,x + sbcb 11,y + sbca 10,y + + tsx + ldy 6,x + + std 0,y + pulx + stx 2,y + pulx + stx 4,y + pulx + stx 6,y + pulx + rts +#endif + +#ifdef L_notdi2 + .sect .text + .globl ___notdi2 + +___notdi2: + tsy + xgdx + ldd 8,y + coma + comb + std 6,x + + ldd 6,y + coma + comb + std 4,x + + ldd 4,y + coma + comb + std 2,x + + ldd 2,y + coma + comb + std 0,x + rts +#endif + +#ifdef L_negsi2 + .sect .text + .globl ___negsi2 + +___negsi2: + comb + coma + addd #1 + xgdx + eorb #0xFF + eora #0xFF + adcb #0 + adca #0 + xgdx + rts +#endif + +#ifdef L_one_cmplsi2 + .sect .text + .globl ___one_cmplsi2 + +___one_cmplsi2: + comb + coma + xgdx + comb + coma + xgdx + rts +#endif + +#ifdef L_ashlsi3 + .sect .text + .globl ___ashlsi3 + +___ashlsi3: + xgdy + clra + andb #0x1f + xgdy + beq Return +Loop: + lsld + xgdx + rolb + rola + xgdx + dey + bne Loop +Return: + rts +#endif + +#ifdef L_ashrsi3 + .sect .text + .globl ___ashrsi3 + +___ashrsi3: + xgdy + clra + andb #0x1f + xgdy + beq Return +Loop: + xgdx + asra + rorb + xgdx + rora + rorb + dey + bne Loop +Return: + rts +#endif + +#ifdef L_lshrsi3 + .sect .text + .globl ___lshrsi3 + +___lshrsi3: + xgdy + clra + andb #0x1f + xgdy + beq Return +Loop: + xgdx + lsrd + xgdx + rora + rorb + dey + bne Loop +Return: + rts +#endif + +#ifdef L_lshrhi3 + .sect .text + .globl ___lshrhi3 + +___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 + .sect .text + .globl ___lshlhi3 + +___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_ashrhi3 + .sect .text + .globl ___ashrhi3 + +___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 + .sect .text + .globl ___ashrqi3 + +___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 + .sect .text + .globl ___lshlqi3 + +___lshlqi3: + cmpa #8 + bge Return_zero + tsta + beq Return +Loop: + lslb + deca + bne Loop +Return: + rts +Return_zero: + clrb + rts +#endif + +#ifdef L_divmodhi4 + .sect .text + .globl __divmodhi4 + +; +;; D = numerator +;; X = denominator +;; +;; Result: D = D / X +;; X = D % X +;; +__divmodhi4: + 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 + +#ifdef L_mulqi3 + .sect .text + .globl __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. +; +__mulqi3: + 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: + nega + negb + mul + rts +#endif + +#ifdef L_mulhi3 + .sect .text + .globl ___mulhi3 + +; +; +; unsigned short ___mulhi3(unsigned short a, unsigned short b) +; +; a = register D +; b = register X +; +___mulhi3: + stx *_.tmp + pshb + ldab *_.tmp+1 + mul ; A.high * B.low + ldaa *_.tmp + stab *_.tmp + pulb + pshb + mul ; A.low * B.high + addb *_.tmp + stab *_.tmp + ldaa *_.tmp+1 + pulb + mul ; A.low * B.low + adda *_.tmp + rts +#endif + +#ifdef L_mulhi32 + .sect .text + .globl __mulhi32 + +; +; +; unsigned long __mulhi32(unsigned short a, unsigned short b) +; +; a = register D +; b = value on stack +; +; +---------------+ +; | B low | <- 5,x +; +---------------+ +; | B high | <- 4,x +; +---------------+ +; | PC low | +; +---------------+ +; | PC 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 +; +__mulhi32: + pshb + psha + tsx + ldab 4,x + mul + xgdy ; A.high * B.high + ldab 5,x + pula + mul ; A.high * B.low + std *_.tmp + ldaa 1,x + ldab 4,x + mul ; A.low * B.high + addd *_.tmp + stab *_.tmp + tab + aby + bcc N + ldab #0xff + aby + iny +N: + ldab 5,x + pula + mul ; A.low * B.low + adda *_.tmp + bcc Ret + iny +Ret: + pshy + pulx + rts + +#endif + +#ifdef L_mulsi3 + .sect .text + .globl __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) +; +; +; + +B_low = 8 +B_high = 6 +A_low = 0 +A_high = 2 +__mulsi3: + 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) +; + stx *_.tmp + 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 + rts +; +; +; 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 + +#ifdef L_map_data + + .sect .install3,"ax",@progbits + .globl __map_data_section + +__map_data_section: + ldd #__data_section_size + beq Done + ldx #__data_image + ldy #__data_section_start +Loop: + psha + ldaa 0,x + staa 0,y + pula + inx + iny + subd #1 + bne Loop +Done: + +#endif + +#ifdef L_init_bss + + .sect .install3,"ax",@progbits + .globl __init_bss_section + +__init_bss_section: + ldd #__bss_size + beq Done + ldx #__bss_start +Loop: + clr 0,x + inx + subd #1 + bne Loop +Done: + +#endif + +;----------------------------------------- +; end required gcclib code +;----------------------------------------- |