File: lib2funcs.S

package info (click to toggle)
gccxml 0.9.0%2Bcvs20100501-2
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 79,132 kB
  • ctags: 73,371
  • sloc: ansic: 751,436; cpp: 34,175; asm: 26,833; sh: 5,077; makefile: 4,696; lex: 589; awk: 566; perl: 334; yacc: 271; pascal: 86; python: 29
file content (190 lines) | stat: -rw-r--r-- 7,875 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/* Assembly functions for libgcc2.
   Copyright (C) 2001 Free Software Foundation, Inc.
   Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.

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 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 into combinations with other programs,
and to distribute those combinations 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 a combine
executable.)

GCC 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 GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.  */

#include "xtensa-config.h"

/* __xtensa_libgcc_window_spill: This function flushes out all but the
   current register window.  This is used to set up the stack so that
   arbitrary frames can be accessed.  */

        .align        4
        .global        __xtensa_libgcc_window_spill
        .type        __xtensa_libgcc_window_spill,@function
__xtensa_libgcc_window_spill:
        entry        sp, 32
        movi        a2, 0
        syscall
        retw
        .size        __xtensa_libgcc_window_spill,.-__xtensa_libgcc_window_spill


/* __xtensa_nonlocal_goto: This code does all the hard work of a
   nonlocal goto on Xtensa.  It is here in the library to avoid the
   code size bloat of generating it in-line.  There are two
   arguments:

        a2 = frame pointer for the procedure containing the label
        a3 = goto handler address

  This function never returns to its caller but instead goes directly
  to the address of the specified goto handler.  */

        .align        4
        .global        __xtensa_nonlocal_goto
        .type        __xtensa_nonlocal_goto,@function
__xtensa_nonlocal_goto:
        entry        sp, 32

        /* flush registers */
        mov        a5, a2
        movi        a2, 0
        syscall
        mov        a2, a5

        /* Because the save area for a0-a3 is stored one frame below
           the one identified by a2, the only way to restore those
           registers is to unwind the stack.  If alloca() were never
           called, we could just unwind until finding the sp value
           matching a2.  However, a2 is a frame pointer, not a stack
           pointer, and may not be encountered during the unwinding.
           The solution is to unwind until going _past_ the value
           given by a2.  This involves keeping three stack pointer
           values during the unwinding:

                next = sp of frame N-1
                cur = sp of frame N
                prev = sp of frame N+1

           When next > a2, the desired save area is stored relative
           to prev.  At this point, cur will be the same as a2
           except in the alloca() case.

           Besides finding the values to be restored to a0-a3, we also
           need to find the current window size for the target
           function.  This can be extracted from the high bits of the
           return address, initially in a0.  As the unwinding
           proceeds, the window size is taken from the value of a0
           saved _two_ frames below the current frame.  */

        addi        a5, sp, -16                # a5 = prev - save area
        l32i        a6, a5, 4
        addi        a6, a6, -16                # a6 = cur - save area
        mov        a8, a0                        # a8 = return address (for window size)
        j        .Lfirstframe

.Lnextframe:        
        l32i        a8, a5, 0                # next return address (for window size)
        mov        a5, a6                        # advance prev
        addi        a6, a7, -16                # advance cur
.Lfirstframe:        
        l32i        a7, a6, 4                # a7 = next
        bge        a2, a7, .Lnextframe

        /* At this point, prev (a5) points to the save area with the saved
           values of a0-a3.  Copy those values into the save area at the
           current sp so they will be reloaded when the return from this
           function underflows.  We don't have to worry about exceptions
           while updating the current save area, because the windows have
           already been flushed.  */

        addi        a4, sp, -16                # a4 = save area of this function
        l32i        a6, a5, 0
        l32i        a7, a5, 4
        s32i        a6, a4, 0
        s32i        a7, a4, 4
        l32i        a6, a5, 8
        l32i        a7, a5, 12 
        s32i        a6, a4, 8
        s32i        a7, a4, 12
        
        /* Set return address to goto handler.  Use the window size bits
           from the return address two frames below the target.  */
        extui        a8, a8, 30, 2                # get window size from return addr.
        slli        a3, a3, 2                # get goto handler addr. << 2
        ssai        2
        src        a0, a8, a3                # combine them with a funnel shift

        retw
        .size        __xtensa_nonlocal_goto,.-__xtensa_nonlocal_goto


/* __xtensa_sync_caches: This function is called after writing a trampoline
   on the stack to force all the data writes to memory and invalidate the
   instruction cache. a2 is the address of the new trampoline.

   After the trampoline data is written out, it must be flushed out of
   the data cache into memory.  We use DHWB in case we have a writeback
   cache.  At least one DHWB instruction is needed for each data cache
   line which may be touched by the trampoline.  An ISYNC instruction
   must follow the DHWBs.

   We have to flush the i-cache to make sure that the new values get used.
   At least one IHI instruction is needed for each i-cache line which may
   be touched by the trampoline.  An ISYNC instruction is also needed to
   make sure that the modified instructions are loaded into the instruction
   fetch buffer.  */

#define TRAMPOLINE_SIZE 60

        .text
        .align        4
        .global        __xtensa_sync_caches
        .type        __xtensa_sync_caches,@function
__xtensa_sync_caches:
        entry         sp, 32
#if XCHAL_DCACHE_SIZE > 0
        # Flush the trampoline from the data cache
        extui        a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
        addi        a4, a4, TRAMPOLINE_SIZE
        addi        a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1
        srli        a4, a4, XCHAL_DCACHE_LINEWIDTH
        mov        a3, a2
.Ldcache_loop:
        dhwb        a3, 0
        addi        a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH)
        addi        a4, a4, -1
        bnez        a4, .Ldcache_loop
        isync
#endif 
#if XCHAL_ICACHE_SIZE > 0
        # Invalidate the corresponding lines in the instruction cache
        extui        a4, a2, 0, XCHAL_ICACHE_LINEWIDTH
        addi        a4, a4, TRAMPOLINE_SIZE
        addi        a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1
        srli        a4, a4, XCHAL_ICACHE_LINEWIDTH
.Licache_loop:
        ihi        a2, 0
        addi        a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH)
        addi        a4, a4, -1
        bnez        a4, .Licache_loop
        isync
#endif
        retw
        .size        __xtensa_sync_caches,.-__xtensa_sync_caches