OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [config/] [m68hc11/] [larith.asm] - Rev 316

Go to most recent revision | Compare with Previous | Blame | View Log

/* libgcc routines for M68HC11 & M68HC12.
   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2008, 2009
   Free Software Foundation, Inc.

This file is part of GCC.

GCC 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 3, or (at your option) any
later version.

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.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

#ifdef __HAVE_SHORT_INT__
        .mode mshort
#else
        .mode mlong
#endif

        .macro declare_near name
        .globl \name
        .type  \name,@function
        .size  \name,.Lend-\name
\name:
        .endm

#if defined(__USE_RTC__)
# define ARG(N) N+1

        .macro ret
#if defined(mc68hc12)
        rtc
#else
        jmp __return_32
#endif
        .endm

        .macro declare name
        .globl \name
        .type  \name,@function
        .size  \name,.Lend-\name
        .far   \name
\name:
        .endm

        .macro farsym name
        .far NAME
        .endm

#else
# define ARG(N) N

        .macro ret
        rts
        .endm

        .macro farsym name
        .endm

        .macro declare name
        .globl \name
        .type  \name,@function
        .size  \name,.Lend-\name
\name:
        .endm

#endif

        .sect .text
        

#define REG(NAME)                       \
NAME:   .dc.w   1;                      \
        .type NAME,@object ;            \
        .size NAME,2

#ifdef L_regs_min
/* Pseudo hard registers used by gcc.
   They should be located in page0.  */

        .sect .softregs
        .globl _.tmp
        .globl _.z,_.xy
REG(_.tmp)
REG(_.z)
REG(_.xy)

#endif

#ifdef L_regs_frame
        .sect .softregs
        .globl _.frame
REG(_.frame)
#endif

#ifdef L_regs_d1_2
        .sect .softregs
        .globl _.d1,_.d2
REG(_.d1)
REG(_.d2)
#endif

#ifdef L_regs_d3_4
        .sect .softregs
        .globl _.d3,_.d4
REG(_.d3)
REG(_.d4)
#endif

#ifdef L_regs_d5_6
        .sect .softregs
        .globl _.d5,_.d6
REG(_.d5)
REG(_.d6)
#endif

#ifdef L_regs_d7_8
        .sect .softregs
        .globl _.d7,_.d8
REG(_.d7)
REG(_.d8)
#endif

#ifdef L_regs_d9_16
/* Pseudo hard registers used by gcc.
   They should be located in page0.  */
        .sect .softregs
        .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 should be located in page0.  */
        .sect .softregs
        .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.
;;
        declare_near    __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)
;; This operation is split in several pieces collected together by
;; the linker script.  This allows to support destructors at the
;; exit stage while not impacting program sizes when there is no
;; destructors.
;;
;; _exit:
;;    *(.fini0)         /* Beginning of finish code (_exit symbol).  */
;;    *(.fini1)         /* Place holder for applications.  */
;;    *(.fini2)         /* C++ destructors.  */
;;    *(.fini3)         /* Place holder for applications.  */
;;    *(.fini4)         /* Runtime exit.  */
;;
        .sect .fini0,"ax",@progbits
        .globl _exit
        .globl exit
        .weak  exit
        farsym  exit
        farsym  _exit
exit:
_exit:

        .sect .fini4,"ax",@progbits
fatal:
        cli
        wai
        bra fatal
#endif

#ifdef L_abort
;;
;; Abort operation.  This is defined for the GCC testsuite.
;;
        declare abort

        ldd     #255            ; 
#ifdef mc68hc12
        trap    #0x30
#else
        .byte 0xCD              ; Generate an illegal instruction trap
        .byte 0x03              ; The simulator catches this and stops.
#endif
        jmp _exit
#endif
        
#ifdef L_cleanup
;;
;; Cleanup operation used by exit().
;;
        declare _cleanup

        ret
#endif

;-----------------------------------------
; required gcclib code
;-----------------------------------------
#ifdef L_memcpy
       declare  memcpy
       declare  __memcpy

        .weak memcpy
;;;
;;; void* memcpy(void*, const void*, size_t)
;;; 
;;; D    = dst  Pmode
;;; 2,sp = src  Pmode
;;; 4,sp = size HImode (size_t)
;;; 
#ifdef mc68hc12
        ldx     ARG(2),sp
        ldy     ARG(4),sp
        pshd
        xgdy
        lsrd
        bcc     Start
        movb    1,x+,1,y+
Start:
        beq     Done
Loop:
        movw    2,x+,2,y+
        dbne    d,Loop
Done:
        puld
        ret
#else
        xgdy
        tsx
        ldd     ARG(4),x
        ldx     ARG(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
        ret
#endif
#endif

#ifdef L_memset
       declare  memset
       declare  __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  = ARG(5)
        size = ARG(6)
#else
;;; D    = dst  Pmode
;;; 2,sp = src  SImode
;;; 6,sp = size HImode (size_t)
        val  = ARG(3)
        size = ARG(4)
#endif
#ifdef mc68hc12
        xgdx
        ldab    val,sp
        ldy     size,sp
        pshx
        beq     End
Loop:
        stab    1,x+
        dbne    y,Loop
End:
        puld
        ret
#else
        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
        ret
#endif
#endif

#ifdef L_adddi3
        declare ___adddi3

        tsx
        xgdy
        ldd     ARG(8),x                ; Add LSB
        addd    ARG(16),x
        std     6,y             ; Save (carry preserved)

        ldd     ARG(6),x
        adcb    ARG(15),x
        adca    ARG(14),x
        std     4,y

        ldd     ARG(4),x
        adcb    ARG(13),x
        adca    ARG(12),x
        std     2,y
        
        ldd     ARG(2),x
        adcb    ARG(11),x               ; Add MSB
        adca    ARG(10),x
        std     0,y

        xgdy
        ret
#endif

#ifdef L_subdi3
        declare ___subdi3

        tsx
        xgdy
        ldd     ARG(8),x                ; Subtract LSB
        subd    ARG(16),x
        std     6,y                     ; Save, borrow preserved

        ldd     ARG(6),x
        sbcb    ARG(15),x
        sbca    ARG(14),x
        std     4,y

        ldd     ARG(4),x
        sbcb    ARG(13),x
        sbca    ARG(12),x
        std     2,y
        
        ldd     ARG(2),x                ; Subtract MSB
        sbcb    ARG(11),x
        sbca    ARG(10),x
        std     0,y

        xgdy                    ;
        ret
#endif
        
#ifdef L_notdi2
        declare ___notdi2

        tsy
        xgdx
        ldd     ARG(8),y
        coma
        comb
        std     6,x
        
        ldd     ARG(6),y
        coma
        comb
        std     4,x

        ldd     ARG(4),y
        coma
        comb
        std     2,x

        ldd     ARG(2),y
        coma
        comb
        std     0,x
        xgdx
        ret
#endif
        
#ifdef L_negsi2
        declare_near ___negsi2

        comb
        coma
        xgdx
        comb
        coma
        inx
        xgdx
        bne     done
        inx
done:
        rts
#endif

#ifdef L_one_cmplsi2
        declare_near ___one_cmplsi2

        comb
        coma
        xgdx
        comb
        coma
        xgdx
        rts
#endif
        
#ifdef L_ashlsi3
        declare_near ___ashlsi3

        xgdy
        clra
        andb    #0x1f
        xgdy
        beq     Return
Loop:
        lsld
        xgdx
        rolb
        rola
        xgdx
        dey
        bne     Loop
Return:
        rts
#endif

#ifdef L_ashrsi3
        declare_near ___ashrsi3

        xgdy
        clra
        andb    #0x1f
        xgdy
        beq     Return
Loop:
        xgdx
        asra
        rorb
        xgdx
        rora
        rorb
        dey
        bne     Loop
Return:
        rts
#endif

#ifdef L_lshrsi3
        declare_near ___lshrsi3

        xgdy
        clra
        andb    #0x1f
        xgdy
        beq     Return
Loop:
        xgdx
        lsrd
        xgdx
        rora
        rorb
        dey
        bne     Loop
Return:
        rts
#endif

#ifdef L_lshrhi3
        declare_near ___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
        declare_near ___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_rotrhi3
        declare_near ___rotrhi3

___rotrhi3:
        xgdx
        clra
        andb    #0x0f
        xgdx
        beq     Return
Loop:
        tap
        rorb
        rora
        dex
        bne     Loop
Return:
        rts
#endif

#ifdef L_rotlhi3
        declare_near ___rotlhi3

___rotlhi3:
        xgdx
        clra
        andb    #0x0f
        xgdx
        beq     Return
Loop:
        asrb
        rolb
        rola
        rolb
        dex
        bne     Loop
Return:
        rts
#endif

#ifdef L_ashrhi3
        declare_near ___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
        declare_near ___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
        declare_near ___lshlqi3

        cmpa    #8
        bge     Return_zero
        tsta
        beq     Return
Loop:
        lslb
        deca
        bne     Loop
Return:
        rts
Return_zero:
        clrb
        rts
#endif

#ifdef L_divmodhi4
#ifndef mc68hc12
/* 68HC12 signed divisions are generated inline (idivs).  */

        declare_near __divmodhi4

;
;; D = numerator
;; X = denominator
;;
;; Result:      D = D / X
;;              X = D % X
;; 
        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 /* !mc68hc12 */
#endif

#ifdef L_mulqi3
        declare_near ___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.
;
        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:
        negb
        mul
        rts
#endif
        
#ifdef L_mulhi3
        declare_near ___mulhi3

;
;
;  unsigned short ___mulhi3(unsigned short a, unsigned short b)
;
;       a = register D
;       b = register X
;
#ifdef mc68hc12
        pshx                    ; Preserve X
        exg     x,y
        emul
        exg     x,y
        pulx
        rts
#else
#ifdef NO_TMP
        ;
        ; 16-bit multiplication without temp memory location.
        ; (smaller but slower)
        ;
        pshx                    ; (4)
        ins                     ; (3)
        pshb                    ; (3)
        psha                    ; (3)
        pshx                    ; (4)
        pula                    ; (4)
        pulx                    ; (5)
        mul                     ; (10) B.high * A.low
        xgdx                    ; (3)
        mul                     ; (10) B.low * A.high
        abx                     ; (3)
        pula                    ; (4)
        pulb                    ; (4)
        mul                     ; (10) B.low * A.low
        pshx                    ; (4) 
        tsx                     ; (3)
        adda    1,x             ; (4)
        pulx                    ; (5)
        rts                     ; (5) 20 bytes
                                ; ---
                                ; 91 cycles
#else
        stx     *_.tmp          ; (4)
        pshb                    ; (3)
        ldab    *_.tmp+1        ; (3)
        mul                     ; (10) A.high * B.low
        ldaa    *_.tmp          ; (3)
        stab    *_.tmp          ; (3)
        pulb                    ; (4)
        pshb                    ; (4)
        mul                     ; (10) A.low * B.high
        addb    *_.tmp          ; (4)
        stab    *_.tmp          ; (3)
        ldaa    *_.tmp+1        ; (3)
        pulb                    ; (4)
        mul                     ; (10) A.low * B.low
        adda    *_.tmp          ; (4)
        rts                     ; (5) 24/32 bytes
                                ; 77/85 cycles
#endif
#endif
#endif

#ifdef L_mulhi32

;
;
;  unsigned long __mulhi32(unsigned short a, unsigned short b)
;
;       a = register D
;       b = value on stack
;
;       +---------------+
;       |  B low        | <- 7,x
;       +---------------+
;       |  B high       | <- 6,x
;       +---------------+
;       |  PC low       |  
;       +---------------+
;       |  PC high      |  
;       +---------------+
;       |  Tmp low      |
;       +---------------+
;       |  Tmp 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
;
        declare_near    __mulhi32

#ifdef mc68hc12
        ldy     2,sp
        emul
        exg     x,y
        rts
#else
        pshx                    ; Room for temp value
        pshb
        psha
        tsx
        ldab    6,x
        mul
        xgdy                    ; A.high * B.high
        ldab    7,x
        pula
        mul                     ; A.high * B.low
        std     2,x
        ldaa    1,x
        ldab    6,x
        mul                     ; A.low * B.high
        addd    2,x
        stab    2,x
        tab
        aby
        bcc     N
        ldab    #0xff
        aby
        iny
N:
        ldab    7,x
        pula
        mul                     ; A.low * B.low
        adda    2,x
        pulx                    ; Drop temp location
        pshy                    ; Put high part in X
        pulx
        bcc     Ret
        inx
Ret:
        rts
#endif  
#endif

#ifdef L_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)
;
;
;

        declare __mulsi3

#ifdef mc68hc12
        pshd                            ; Save A.low
        ldy     ARG(4),sp
        emul                            ; A.low * B.high
        ldy     ARG(6),sp
        exg     x,d
        emul                            ; A.high * B.low
        leax    d,x
        ldy     ARG(6),sp
        puld
        emul                            ; A.low * B.low
        exg     d,y
        leax    d,x
        exg     d,y
        ret
#else
B_low   =       ARG(8)
B_high  =       ARG(6)
A_low   =       0
A_high  =       2
        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)
;
        cpx     #0
        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
        ret
;
; 
; 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
#endif

#ifdef L_map_data

        .sect   .install2,"ax",@progbits
        .globl  __map_data_section
        .globl __data_image
#ifdef mc68hc12
        .globl __data_section_size
#endif
__map_data_section:
#ifdef mc68hc12
        ldx     #__data_image
        ldy     #__data_section_start
        ldd     #__data_section_size
        beq     Done
Loop:
        movb    1,x+,1,y+
        dbne    d,Loop
#else
        ldx     #__data_image
        ldy     #__data_section_start
        bra     Start_map
Loop:
        ldaa    0,x
        staa    0,y
        inx
        iny
Start_map:
        cpx     #__data_image_end
        blo     Loop
#endif
Done:

#endif

#ifdef L_init_bss

        .sect   .install2,"ax",@progbits
        .globl  __init_bss_section

__init_bss_section:
        ldd     #__bss_size
        beq     Done
        ldx     #__bss_start
Loop:
#ifdef mc68hc12
        clr     1,x+
        dbne    d,Loop
#else
        clr     0,x
        inx
        subd    #1
        bne     Loop
#endif
Done:

#endif

#ifdef L_ctor

; End of constructor table
        .sect   .install3,"ax",@progbits
        .globl  __do_global_ctors

__do_global_ctors:
        ; Start from the end - sizeof(void*)
        ldx     #__CTOR_END__-2
ctors_loop:
        cpx     #__CTOR_LIST__
        blo     ctors_done
        pshx
        ldx     0,x
        jsr     0,x
        pulx
        dex
        dex
        bra     ctors_loop
ctors_done:

#endif

#ifdef L_dtor

        .sect   .fini3,"ax",@progbits
        .globl  __do_global_dtors

;;
;; This piece of code is inserted in the _exit() code by the linker.
;;
__do_global_dtors:
        pshb    ; Save exit code
        psha
        ldx     #__DTOR_LIST__
dtors_loop:
        cpx     #__DTOR_END__
        bhs     dtors_done
        pshx
        ldx     0,x
        jsr     0,x
        pulx
        inx
        inx
        bra     dtors_loop
dtors_done:
        pula    ; Restore exit code
        pulb

#endif

#ifdef L_far_tramp
#ifdef mc68hc12
        .sect   .tramp,"ax",@progbits
        .globl  __far_trampoline

;; This is a trampoline used by the linker to invoke a function
;; using rtc to return and being called with jsr/bsr.
;; The trampoline generated is:
;;
;;      foo_tramp:
;;              ldy     #foo
;;              call    __far_trampoline,page(foo)
;;
;; The linker transforms:
;;
;;              jsr     foo
;;
;; into
;;              jsr     foo_tramp
;;
;; The linker generated trampoline and _far_trampoline must be in 
;; non-banked memory.
;;
__far_trampoline:
        movb    0,sp, 2,sp      ; Copy page register below the caller's return
        leas    2,sp            ; address.
        jmp     0,y             ; We have a 'call/rtc' stack layout now
                                ; and can jump to the far handler
                                ; (whose memory bank is mapped due to the
                                ; call to the trampoline).
#endif

#ifdef mc68hc11
        .sect   .tramp,"ax",@progbits
        .globl __far_trampoline

;; Trampoline generated by gcc for 68HC11:
;;
;;      pshb
;;      ldab    #%page(func)
;;      ldy     #%addr(func)
;;      jmp     __far_trampoline
;;
__far_trampoline:
        psha                            ; (2) Save function parameter (high)
        ;; <Read current page in A>
        psha                            ; (2)
        ;; <Set currenge page from B>
        pshx                            ; (4)
        tsx                             ; (3)
        ldab    4,x                     ; (4) Restore function parameter (low)
        ldaa    2,x                     ; (4) Get saved page number
        staa    4,x                     ; (4) Save it below return PC
        pulx                            ; (5)
        pula                            ; (3)
        pula                            ; (3) Restore function parameter (high)
        jmp     0,y                     ; (4)
#endif
#endif

#ifdef L_call_far
#ifdef mc68hc11
        .sect   .tramp,"ax",@progbits
        .globl __call_a16
        .globl __call_a32
;;
;; The call methods are used for 68HC11 to support memory bank switching.
;; Every far call is redirected to these call methods.  Its purpose is to:
;;
;;  1/ Save the current page on the stack (1 byte to follow 68HC12 call frame)
;;  2/ Install the new page
;;  3/ Jump to the real function
;;
;; The page switching (get/save) is board dependent.  The default provided
;; here does nothing (just create the appropriate call frame).
;;
;; Call sequence (10 bytes, 13 cycles):
;;
;;      ldx #page                       ; (3)
;;      ldy #func                       ; (4)
;;      jsr __call_a16                  ; (6)
;;
;; Call trampoline (11 bytes, 19 cycles):
;;
__call_a16:
        ;; xgdx                         ; (3)
        ;; <Read current page in A>     ; (3) ldaa _current_page
        psha                            ; (2)
        ;; <Set current page from B>    ; (4) staa _current_page
        ;; xgdx                         ; (3)
        jmp 0,y                         ; (4)

;;
;; Call sequence (10 bytes, 14 cycles):
;;
;;      pshb                            ; (2)
;;      ldab #page                      ; (2)
;;      ldy  #func                      ; (4)
;;      jsr __call_a32                  ; (6)
;;
;; Call trampoline (87 bytes, 57 cycles):
;;
__call_a32:
        pshx                            ; (4)
        psha                            ; (2)
        ;; <Read current page in A>     ; (3) ldaa _current_page
        psha                            ; (2)
        ;; <Set current page from B>    ; (4) staa _current_page
        tsx                             ; (3)
        ldab    6,x                     ; (4) Restore function parameter
        ldaa    5,x                     ; (4) Move PC return at good place
        staa    6,x                     ; (4)
        ldaa    4,x                     ; (4)
        staa    5,x                     ; (4)
        pula                            ; (3)
        staa    4,x                     ; (4)
        pula                            ; (3)
        pulx                            ; (5)
        jmp     0,y                     ; (4)
#endif
#endif

#ifdef L_return_far
#ifdef mc68hc11
        .sect   .tramp,"ax",@progbits
       .globl __return_void
       .globl __return_16
       .globl __return_32

__return_void:
        ;; pulb
        ;; <Set current page from B> (Board specific)
        ;; rts
__return_16:
        ;; xgdx
        ;; pulb
        ;; <Set current page from B> (Board specific)
        ;; xgdx
        ;; rts
__return_32:
        ;; xgdy
        ;; pulb
        ;; <Set current page from B> (Board specific)
        ;; xgdy
        ;; rts
        ins
        rts
#endif
#endif
.Lend:
;-----------------------------------------
; end required gcclib code
;-----------------------------------------

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.