1/* Overlay manager for SPU.
2
3   Copyright (C) 2006-2024 Free Software Foundation, Inc.
4
5   This file is part of the GNU Binutils.
6
7   This program 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 3 of the License, or
10   (at your option) any later version.
11
12   This program 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 this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22/* MFC DMA defn's.  */
23#define MFC_GET_CMD           0x40
24#define MFC_MAX_DMA_SIZE      0x4000
25#define MFC_TAG_UPDATE_ALL    2
26#define MFC_TAG_ID            0
27
28/* Register usage.  */
29#define reserved1   $75
30#define parm                  $75
31#define tab1                  reserved1
32#define tab2                  reserved1
33#define vma                   reserved1
34#define oldvma                reserved1
35#define newmask               reserved1
36#define map                   reserved1
37
38#define reserved2   $76
39#define off1                  reserved2
40#define off2                  reserved2
41#define present1    reserved2
42#define present2    reserved2
43#define sz                    reserved2
44#define cmp                   reserved2
45#define add64                 reserved2
46#define cgbits                reserved2
47#define off3                  reserved2
48#define off4                  reserved2
49#define addr4                 reserved2
50#define off5                  reserved2
51#define tagstat               reserved2
52
53#define reserved3   $77
54#define size1                 reserved3
55#define size2                 reserved3
56#define rv3                   reserved3
57#define ealo                  reserved3
58#define cmd                   reserved3
59#define off64                 reserved3
60#define tab3                  reserved3
61#define tab4                  reserved3
62#define tab5                  reserved3
63
64#define reserved4   $78
65#define ovl                   reserved4
66#define rv2                   reserved4
67#define rv5                   reserved4
68#define cgshuf                reserved4
69#define newovl                reserved4
70#define irqtmp1               reserved4
71#define irqtmp2               reserved4
72
73#define reserved5   $79
74#define target                reserved5
75
76#define save1                 $74
77#define rv4                   save1
78#define rv7                   save1
79#define tagid                 save1
80#define maxsize               save1
81#define pbyte                 save1
82#define pbit                  save1
83
84#define save2                 $73
85#define cur                   save2
86#define rv6                   save2
87#define osize                 save2
88#define zovl                  save2
89#define oldovl                save2
90#define newvma                save2
91
92#define save3                 $72
93#define rv1                   save3
94#define ea64                  save3
95#define buf3                  save3
96#define genwi                 save3
97#define newmap                save3
98#define oldmask               save3
99
100#define save4                 $71
101#define irq_stat    save4
102
103          .text
104          .align    4
105          .type     __rv_pattern, @object
106          .size     __rv_pattern, 16
107__rv_pattern:
108          .word     0x00010203, 0x10111213, 0x80808080, 0x80808080
109
110          .type     __cg_pattern, @object
111          .size     __cg_pattern, 16
112__cg_pattern:
113          .word     0x04050607, 0x80808080, 0x80808080, 0x80808080
114
115          .type     __ovly_current, @object
116          .size     __ovly_current, 16
117__ovly_current:
118          .space    16
119
120/*
121 * __ovly_return - stub for returning from overlay functions.
122 *
123 * On entry the four slots of $lr are:
124 *   __ovly_return, prev ovl index, caller return addr, undefined.
125 *
126 * Load the previous overlay and jump to the caller return address.
127 * Updates __ovly_current.
128 */
129          .align    4
130          .global   __ovly_return
131          .type     __ovly_return, @function
132__ovly_return:
133          ila       tab1, _ovly_table - 16                                      # 0,2     0
134          shlqbyi   ovl, $lr, 4                                                 # 1,4     0
135#nop
136          shlqbyi   target, $lr, 8                                              # 1,4     1
137#nop; lnop
138#nop; lnop
139          shli      off1, ovl, 4                                                # 0,4     4
140#lnop
141#nop
142          hbr       ovly_ret9, target                                 # 1,15    5
143#nop; lnop
144#nop; lnop
145#nop
146          lqx       vma, tab1, off1                                             # 1,6     8
147#ifdef OVLY_IRQ_SAVE
148          nop
149          stqd      save4, -64($sp)                                             # 1,6     9
150#else
151#nop; lnop
152#endif
153#nop; lnop
154#nop; lnop
155#nop; lnop
156#nop; lnop
157#nop
158          rotqbyi   size1, vma, 4                                               # 1,4     14
159#nop
160          stqd      save3, -48($sp)                                             # 1,6     15
161#nop
162          stqd      save2, -32($sp)                                             # 1,6     16
163#nop
164          stqd      save1, -16($sp)                                             # 1,6     17
165          andi      present1, size1, 1                                # 0,2     18
166          stqr      ovl, __ovly_current                               # 1,6     18
167#nop; lnop
168#nop
169          brz       present1, do_load                                 # 1,4     20
170ovly_ret9:
171#nop
172          bi        target                                                      # 1,4     21
173
174/*
175 * __ovly_load - copy an overlay partion to local store.
176 *
177 * On entry $75 points to a word consisting of the overlay index in
178 * the top 14 bits, and the target address in the bottom 18 bits.
179 *
180 * Sets up $lr to return via __ovly_return.  If $lr is already set
181 * to return via __ovly_return, don't change it.  In that case we
182 * have a tail call from one overlay function to another.
183 * Updates __ovly_current.
184 */
185          .align  3
186          .global   __ovly_load
187          .type     __ovly_load, @function
188__ovly_load:
189#if OVL_STUB_SIZE == 8
190########
191#nop
192          lqd       target, 0(parm)                                             # 1,6     -11
193#nop; lnop
194#nop; lnop
195#nop; lnop
196#nop; lnop
197#nop; lnop
198#nop
199          rotqby    target, target, parm                                        # 1,4     -5
200          ila       tab2, _ovly_table - 16                                      # 0,2     -4
201          stqd      save3, -48($sp)                                             # 1,6     -4
202#nop
203          stqd      save2, -32($sp)                                             # 1,6     -3
204#nop
205          stqd      save1, -16($sp)                                             # 1,6     -2
206          rotmi     ovl, target, -18                                  # 0,4     -1
207          hbr       ovly_load9, target                                # 1,15    -1
208          ila       rv1, __ovly_return                                # 0,2     0
209#lnop
210#nop; lnop
211#nop
212          lqr       cur, __ovly_current                               # 1,6     2
213          shli      off2, ovl, 4                                                # 0,4     3
214          stqr      ovl, __ovly_current                               # 1,6     3
215          ceq       rv2, $lr, rv1                                               # 0,2     4
216          lqr       rv3, __rv_pattern                                 # 1,6     4
217#nop; lnop
218#nop; lnop
219#nop
220          lqx       vma, tab2, off2                                             # 1,6     7
221########
222#else /* OVL_STUB_SIZE == 16 */
223########
224          ila       tab2, _ovly_table - 16                                      # 0,2     0
225          stqd      save3, -48($sp)                                             # 1,6     0
226          ila       rv1, __ovly_return                                # 0,2     1
227          stqd      save2, -32($sp)                                             # 1,6     1
228          shli      off2, ovl, 4                                                # 0,4     2
229          lqr       cur, __ovly_current                               # 1,6     2
230          nop
231          stqr      ovl, __ovly_current                               # 1,6     3
232          ceq       rv2, $lr, rv1                                               # 0,2     4
233          lqr       rv3, __rv_pattern                                 # 1,6     4
234#nop
235          hbr       ovly_load9, target                                # 1,15    5
236#nop
237          lqx       vma, tab2, off2                                             # 1,6     6
238#nop
239          stqd      save1, -16($sp)                                             # 1,6     7
240########
241#endif
242
243#nop; lnop
244#nop; lnop
245#nop
246          shufb     rv4, rv1, cur, rv3                                # 1,4     10
247#nop
248          fsmb      rv5, rv2                                          # 1,4     11
249#nop
250          rotqmbyi rv6, $lr, -8                                                 # 1,4     12
251#nop
252          rotqbyi   size2, vma, 4                                               # 1,4     13
253#nop
254          lqd       save3, -48($sp)                                             # 1,6     14
255#nop; lnop
256          or        rv7, rv4, rv6                                               # 0,2     16
257          lqd       save2, -32($sp)                                             # 1,6     16
258          andi      present2, size2, 1                                # 0,2     17
259#ifdef OVLY_IRQ_SAVE
260          stqd      save4, -64($sp)                                             # 1,6     17
261#else
262          lnop                                                                  # 1,0     17
263#endif
264          selb      $lr, rv7, $lr, rv5                                # 0,2     18
265          lqd       save1, -16($sp)                                             # 1,6     18
266#nop
267          brz       present2, do_load                                 # 1,4     19
268ovly_load9:
269#nop
270          bi        target                                                      # 1,4     20
271
272/* If we get here, we are about to load a new overlay.
273 * "vma" contains the relevant entry from _ovly_table[].
274 *        extern struct {
275 *                  u32 vma;
276 *                  u32 size;
277 *                  u32 file_offset;
278 *                  u32 buf;
279 *        } _ovly_table[];
280 */
281          .align  3
282          .global   __ovly_load_event
283          .type     __ovly_load_event, @function
284__ovly_load_event:
285do_load:
286#ifdef OVLY_IRQ_SAVE
287          ila       irqtmp1, do_load10                                # 0,2     -5
288          rotqbyi   sz, vma, 8                                                  # 1,4     -5
289#nop
290          rdch      irq_stat, $SPU_RdMachStat                         # 1,6     -4
291#nop
292          bid       irqtmp1                                                     # 1,4     -3
293do_load10:
294          nop
295#else
296#nop
297          rotqbyi   sz, vma, 8                                                  # 1,4     0
298#endif
299          rotqbyi   osize, vma, 4                                               # 1,4     1
300#nop
301          lqa       ea64, _EAR_                                                 # 1,6     2
302#nop
303          lqr       cgshuf, __cg_pattern                                        # 1,6     3
304
305/* We could predict the branch at the end of this loop by adding a few
306   instructions, and there are plenty of free cycles to do so without
307   impacting loop execution time.  However, it doesn't make a great
308   deal of sense since we need to wait for the dma to complete anyway.  */
309__ovly_xfer_loop:
310#nop
311          rotqmbyi off64, sz, -4                                                # 1,4     4
312#nop; lnop
313#nop; lnop
314#nop; lnop
315          cg        cgbits, ea64, off64                               # 0,2     8
316#lnop
317#nop; lnop
318#nop
319          shufb     add64, cgbits, cgbits, cgshuf                     # 1,4     10
320#nop; lnop
321#nop; lnop
322#nop; lnop
323          addx      add64, ea64, off64                                # 0,2     14
324#lnop
325          ila       maxsize, MFC_MAX_DMA_SIZE                         # 0,2     15
326          lnop
327          ori       ea64, add64, 0                                              # 0,2     16
328          rotqbyi   ealo, add64, 4                                              # 1,4     16
329          cgt       cmp, osize, maxsize                               # 0,2     17
330          wrch      $MFC_LSA, vma                                               # 1,6     17
331#nop; lnop
332          selb      sz, osize, maxsize, cmp                                     # 0,2     19
333          wrch      $MFC_EAH, ea64                                              # 1,6     19
334          ila       tagid, MFC_TAG_ID                                 # 0,2     20
335          wrch      $MFC_EAL, ealo                                              # 1,6     20
336          ila       cmd, MFC_GET_CMD                                  # 0,2     21
337          wrch      $MFC_Size, sz                                               # 1,6     21
338          sf        osize, sz, osize                                  # 0,2     22
339          wrch      $MFC_TagId, tagid                                 # 1,6     22
340          a         vma, vma, sz                                                # 0,2     23
341          wrch      $MFC_Cmd, cmd                                               # 1,6     23
342#nop
343          brnz      osize, __ovly_xfer_loop                                     # 1,4     24
344
345/* Now update our data structions while waiting for DMA to complete.
346   Low bit of .size needs to be cleared on the _ovly_table entry
347   corresponding to the evicted overlay, and set on the entry for the
348   newly loaded overlay.  Note that no overlay may in fact be evicted
349   as _ovly_buf_table[] starts with all zeros.  Don't zap .size entry
350   for zero index!  Also of course update the _ovly_buf_table entry.  */
351#nop
352          lqr       newovl, __ovly_current                                      # 1,6     25
353#nop; lnop
354#nop; lnop
355#nop; lnop
356#nop; lnop
357#nop; lnop
358          shli      off3, newovl, 4                                             # 0,4     31
359#lnop
360          ila       tab3, _ovly_table - 16                                      # 0,2     32
361#lnop
362#nop
363          fsmbi     pbyte, 0x100                                                # 1,4     33
364#nop; lnop
365#nop
366          lqx       vma, tab3, off3                                             # 1,6     35
367#nop; lnop
368          andi      pbit, pbyte, 1                                              # 0,2     37
369          lnop
370#nop; lnop
371#nop; lnop
372#nop; lnop
373          or        newvma, vma, pbit                                 # 0,2     41
374          rotqbyi   buf3, vma, 12                                               # 1,4     41
375#nop; lnop
376#nop
377          stqx      newvma, tab3, off3                                # 1,6     43
378#nop; lnop
379          shli      off4, buf3, 2                                               # 1,4     45
380#lnop
381          ila       tab4, _ovly_buf_table - 4                         # 0,2     46
382#lnop
383#nop; lnop
384#nop; lnop
385#nop
386          lqx       map, tab4, off4                                             # 1,6     49
387#nop
388          cwx       genwi, tab4, off4                                 # 1,4     50
389          a         addr4, tab4, off4                                 # 0,2     51
390#lnop
391#nop; lnop
392#nop; lnop
393#nop; lnop
394#nop
395          rotqby    oldovl, map, addr4                                # 1,4     55
396#nop
397          shufb     newmap, newovl, map, genwi                        # 0,4     56
398#if MFC_TAG_ID < 16
399          ila       newmask, 1 << MFC_TAG_ID                          # 0,2     57
400#else
401          ilhu      newmask, 1 << (MFC_TAG_ID - 16)                             # 0,2     57
402#endif
403#lnop
404#nop; lnop
405#nop; lnop
406          stqd      newmap, 0(addr4)                                  # 1,6     60
407
408/* Save app's tagmask, wait for DMA complete, restore mask.  */
409          ila       tagstat, MFC_TAG_UPDATE_ALL                       # 0,2     61
410          rdch      oldmask, $MFC_RdTagMask                                     # 1,6     61
411#nop
412          wrch      $MFC_WrTagMask, newmask                                     # 1,6     62
413#nop
414          wrch      $MFC_WrTagUpdate, tagstat                         # 1,6     63
415#nop
416          rdch      tagstat, $MFC_RdTagStat                                     # 1,6     64
417#nop
418          sync                                                                  # 1,4     65
419/* Any hint prior to the sync is lost.  A hint here allows the branch
420   to complete 15 cycles after the hint.  With no hint the branch will
421   take 18 or 19 cycles.  */
422          ila       tab5, _ovly_table - 16                                      # 0,2     66
423          hbr       do_load99, target                                 # 1,15    66
424          shli      off5, oldovl, 4                                             # 0,4     67
425          wrch      $MFC_WrTagMask, oldmask                                     # 1,6     67
426          ceqi      zovl, oldovl, 0                                             # 0,2     68
427#lnop
428#nop; lnop
429#nop
430          fsm       zovl, zovl                                                  # 1,4     70
431#nop
432          lqx       oldvma, tab5, off5                                # 1,6     71
433#nop
434          lqd       save3, -48($sp)                                             # 1,6     72
435#nop; lnop
436          andc      pbit, pbit, zovl                                  # 0,2     74
437          lqd       save2, -32($sp)                                             # 1,6     74
438#ifdef OVLY_IRQ_SAVE
439          ila       irqtmp2, do_load90                                # 0,2     75
440#lnop
441          andi      irq_stat, irq_stat, 1                                       # 0,2     76
442#lnop
443#else
444#nop; lnop
445#nop; lnop
446#endif
447          andc      oldvma, oldvma, pbit                                        # 0,2     77
448          lqd       save1, -16($sp)                                             # 1,6     77
449          nop                                                                   # 0,0     78
450#lnop
451#nop
452          stqx      oldvma, tab5, off5                                # 1,6     79
453#nop
454#ifdef OVLY_IRQ_SAVE
455          binze     irq_stat, irqtmp2                                 # 1,4     80
456do_load90:
457#nop
458          lqd       save4, -64($sp)                                             # 1,6     84
459#else
460#nop; lnop
461#endif
462
463          .global   _ovly_debug_event
464          .type     _ovly_debug_event, @function
465_ovly_debug_event:
466          nop
467/* Branch to target address. */
468do_load99:
469          bi        target                                                      # 1,4     81/85
470
471          .size     __ovly_load, . - __ovly_load
472