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