]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - ld/emultempl/spu_ovl.S
New Cell SPU port.
[thirdparty/binutils-gdb.git] / ld / emultempl / spu_ovl.S
1 /* Overlay manager for SPU.
2
3 Copyright 2006 Free Software Foundation, Inc.
4
5 This file is part of GLD, the Gnu Linker.
6
7 GLD is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GLD is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GLD; see the file COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20 02110-1301, USA. */
21
22 /**
23 * MFC DMA defn's.
24 */
25 #define MFC_GET_CMD 0x40
26 #define MFC_MAX_DMA_SIZE 0x4000
27 #define MFC_TAG_UPDATE_ALL 2
28 #define MFC_TAG_ID 0
29
30
31 /**
32 * Temporary register allocations.
33 * These are saved/restored here.
34 */
35 #define tab $75
36 #define cgbits $75
37 #define add64 $75
38 #define ealo $75
39 #define newmask $75
40 #define tagstat $75
41 #define bchn $75
42 #define rv1 $75
43
44 #define off $76
45 #define off64 $76
46 #define maxsize $76
47 #define oldmask $76
48 #define sz $76
49 #define lnkr $76
50 #define rv2 $76
51
52 #define cur $77
53 #define cmp $77
54 #define buf $77
55 #define genwi $77
56 #define tagid $77
57 #define cmd $77
58 #define rv3 $77
59
60 #define cgshuf $78
61
62 #define vma $6
63
64 #define map $7
65 #define size $7
66 #define cmp2 $7
67
68 #define ea64 $8
69 #define retval $8
70
71 #ifdef OVLY_IRQ_SAVE
72 #define irqtmp $8
73 #define irq_stat $9
74 #endif
75
76 .extern _ovly_table
77 .extern _ovly_buf_table
78
79 .text
80 .align 4
81 __rv_pattern:
82 .word 0x00010203, 0x1c1d1e1f, 0x00010203, 0x10111213
83 __cg_pattern:
84 .word 0x04050607, 0x80808080, 0x80808080, 0x80808080
85
86 /**
87 * __ovly_return - stub for returning from overlay functions.
88 *
89 * inputs:
90 * $lr link register
91 *
92 * outputs:
93 * $78 old partition number, to be reloaded
94 * $79 return address in old partion number
95 */
96 .global __ovly_return
97 .type __ovly_return, @function
98
99 .word 0
100 __ovly_return:
101 shlqbyi $78, $lr, 4
102 shlqbyi $79, $lr, 8
103 biz $78, $79
104
105 /**
106 * __ovly_load - copy an overlay partion to local store.
107 *
108 * inputs:
109 * $78 partition number to be loaded.
110 * $79 branch target in new partition.
111 * $lr link register, containing return addr.
112 *
113 * outputs:
114 * $lr new link register, returning through __ovly_return.
115 *
116 * Copy a new overlay partition into local store, or return
117 * immediately if the partition is already resident.
118 */
119 .global __ovly_load
120 .type __ovly_load, @function
121
122 __ovly_load:
123 /* Save temporary registers to stack. */
124 stqd $6, -16($sp)
125 stqd $7, -32($sp)
126 stqd $8, -48($sp)
127
128 #ifdef OVLY_IRQ_SAVE
129 /* Save irq state, then disable interrupts. */
130 stqd $9, -64($sp)
131 ila irqtmp, __ovly_irq_save
132 rdch irq_stat, $SPU_RdMachStat
133 bid irqtmp
134 __ovly_irq_save:
135 #endif
136
137 /* Set branch hint to overlay target. */
138 hbr __ovly_load_ret, $79
139
140 /* Get caller's overlay index by back chaining through stack frames.
141 * Loop until end of stack (back chain all-zeros) or
142 * encountered a link register we set here. */
143 lqd bchn, 0($sp)
144 ila retval, __ovly_return
145
146 __ovly_backchain_loop:
147 lqd lnkr, 16(bchn)
148 lqd bchn, 0(bchn)
149 ceq cmp, lnkr, retval
150 ceqi cmp2, bchn, 0
151 or cmp, cmp, cmp2
152 brz cmp, __ovly_backchain_loop
153
154 /* If we reached the zero back-chain, then lnkr is bogus. Clear the
155 * part of lnkr that we use later (slot 3). */
156 rotqbyi cmp2, cmp2, 4
157 andc lnkr, lnkr, cmp2
158
159 /* Set lr = {__ovly_return, prev ovl ndx, caller return adr, callee ovl ndx}. */
160 lqd rv1, (__rv_pattern-__ovly_return+4)(retval)
161 shufb rv2, retval, lnkr, rv1
162 shufb rv3, $lr, $78, rv1
163 fsmbi rv1, 0xff
164 selb $lr, rv2, rv3, rv1
165
166 /* Branch to $79 if non-overlay */
167 brz $78, __ovly_load_restore
168
169 /* Load values from _ovly_table[$78].
170 * extern struct {
171 * u32 vma;
172 * u32 size;
173 * u32 file_offset;
174 * u32 buf;
175 * } _ovly_table[];
176 */
177 shli off, $78, 4
178 ila tab, _ovly_table - 16
179 lqx vma, tab, off
180 rotqbyi buf, vma, 12
181
182 /* Load values from _ovly_buf_table[buf].
183 * extern struct {
184 * u32 mapped;
185 * } _ovly_buf_table[];
186 */
187 ila tab, _ovly_buf_table
188 ai off, buf, -1
189 shli off, off, 2
190 lqx map, tab, off
191 rotqby cur, map, off
192
193 /* Branch to $79 now if overlay is already mapped. */
194 ceq cmp, $78, cur
195 brnz cmp, __ovly_load_restore
196
197 /* Set _ovly_buf_table[buf].mapped = $78. */
198 cwx genwi, tab, off
199 shufb map, $78, map, genwi
200 stqx map, tab, off
201
202 /* A new partition needs to be loaded. Prepare for DMA loop.
203 * _EAR_ is the 64b base EA, filled in at run time by the
204 * loader, and indicating the value for SPU executable image start.
205 */
206 lqd cgshuf, (__cg_pattern-__ovly_return+4)(retval)
207 rotqbyi size, vma, 4
208 rotqbyi sz, vma, 8
209 lqa ea64, _EAR_
210
211 __ovly_xfer_loop:
212 /* 64b add to compute next ea64. */
213 rotqmbyi off64, sz, -4
214 cg cgbits, ea64, off64
215 shufb add64, cgbits, cgbits, cgshuf
216 addx add64, ea64, off64
217 ori ea64, add64, 0
218
219 /* Setup DMA parameters, then issue DMA request. */
220 rotqbyi ealo, add64, 4
221 ila maxsize, MFC_MAX_DMA_SIZE
222 cgt cmp, size, maxsize
223 selb sz, size, maxsize, cmp
224 ila tagid, MFC_TAG_ID
225 wrch $MFC_LSA, vma
226 wrch $MFC_EAH, ea64
227 wrch $MFC_EAL, ealo
228 wrch $MFC_Size, sz
229 wrch $MFC_TagId, tagid
230 ila cmd, MFC_GET_CMD
231 wrch $MFC_Cmd, cmd
232
233 /* Increment vma, decrement size, branch back as needed. */
234 a vma, vma, sz
235 sf size, sz, size
236 brnz size, __ovly_xfer_loop
237
238 /* Save app's tagmask, wait for DMA complete, restore mask. */
239 rdch oldmask, $MFC_RdTagMask
240 #if MFC_TAG_ID < 16
241 ilh newmask, 1 << MFC_TAG_ID
242 #else
243 ilhu newmask, 1 << (MFC_TAG_ID - 16)
244 #endif
245 wrch $MFC_WrTagMask, newmask
246 ila tagstat, MFC_TAG_UPDATE_ALL
247 wrch $MFC_WrTagUpdate, tagstat
248 rdch tagstat, $MFC_RdTagStat
249 sync
250 wrch $MFC_WrTagMask, oldmask
251
252 .global _ovly_debug_event
253 .type _ovly_debug_event, @function
254 _ovly_debug_event:
255 /* GDB inserts debugger trap here. */
256 nop
257
258 __ovly_load_restore:
259 #ifdef OVLY_IRQ_SAVE
260 /* Conditionally re-enable interrupts. */
261 andi irq_stat, irq_stat, 1
262 ila irqtmp, __ovly_irq_restore
263 binze irq_stat, irqtmp
264 __ovly_irq_restore:
265 lqd $9, -64($sp)
266 #endif
267
268 /* Restore saved registers. */
269 lqd $8, -48($sp)
270 lqd $7, -32($sp)
271 lqd $6, -16($sp)
272
273 __ovly_load_ret:
274 /* Branch to target address. */
275 bi $79