summaryrefslogtreecommitdiff
path: root/docs/DSP/free_dsp_rom/dsp_rom.ds
blob: 7ee9b5c5d8ed5ade5b0c40a97375568d0788e746 (plain)
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
IROM_BASE:	equ 0x8000

lri $CR, #0x00ff
lri $SR, #0x2000
si @DMBH, #0x8071
si @DMBL, #0xfeed

mainloop:
	clr $ACC1
	clr $ACC0
	call wait_for_cpu_mbox+#IROM_BASE

;mmem-addr
param1:
	lr $AC1.M, @CMBL
	lri $AC0.M, #0xa001
	cmp
	jnz param2+#IROM_BASE
	call wait_for_cpu_mbox+#IROM_BASE
	lr $IX0, @CMBH
	lr $IX1, @CMBL
	jmp mainloop+#IROM_BASE

;iram-addr
param2:
	lri $AC0.M, #0xc002
	cmp
	jnz param3+#IROM_BASE
	call wait_for_cpu_mbox+#IROM_BASE
	lr $IX2, @CMBL
	jmp mainloop+#IROM_BASE

;iram-length
param3:
	lri $AC0.M, #0xa002
	cmp
	jnz param4+#IROM_BASE
	call wait_for_cpu_mbox+#IROM_BASE
	lr $IX3, @CMBL
	jmp mainloop+#IROM_BASE

;dram-length
param4:
	lri $AC0.M, #0xb002
	cmp
	jnz param5+#IROM_BASE
	call wait_for_cpu_mbox+#IROM_BASE
	lr $AX0.L, @CMBL
	jmp mainloop+#IROM_BASE

;iram-start-addr
param5:
	lri $AC0.M, #0xd001
	cmp
	jnz mainloop+#IROM_BASE
	call wait_for_cpu_mbox+#IROM_BASE
	lr $AR0, @CMBL
	; skip the branch of bootucode that uses the AX registers
	jmp bootucode_ix+#IROM_BASE

wait_dma:
	lrs		$AC0.M, @DSCR
	andcf	$AC0.M, #0x0004
	jlz		wait_dma+#IROM_BASE
	ret

WARNPC 0x78
ORG 0x78
; called by GBA ucode
wait_for_cpu_mbox:
    lrs   $AC0.M, @CMBH
    andcf $AC0.M, #0x8000
    jlnz  wait_for_cpu_mbox+#IROM_BASE
    ret

WARNPC 0x7e
ORG 0x7e
; called by GBA ucode
wait_for_dsp_mbox:
    lrs   $AC0.M, @DMBH
    andcf $AC0.M, #0x8000
    jlz   wait_for_dsp_mbox+#IROM_BASE
    ret

WARNPC 0x8b
ORG 0x8b
; called by GBA ucode
dram_to_cpu:
    sr @DSMAH, $AX0.H
    sr @DSMAL, $AX0.L
    si @DSCR, #0x1
    sr @DSPA, $AX1.H
    sr @DSBL, $AX1.L
    call wait_dma+#IROM_BASE
    ret

WARNPC 0xb5
ORG 0xb5
bootucode:
    set16
    clr  $ACC0
    mrr  $AC0.M, $AX1.L
    andi $AC0.M, #0xffff
    jz bootucode_ix+#IROM_BASE

WARNPC 0xbc
ORG 0xbc
; called by GBA ucode
bootucode_ax:
    lris $AC0.M, #0
    srs @DSCR, $AC0.M
    sr  @DSMAH, $AX0.H
    sr  @DSMAL, $AX0.L
    sr  @DSPA, $AX1.H
    sr  @DSBL, $AX1.L
    call wait_dma+#IROM_BASE

bootucode_ix:
    mrr $AC0.M, $IX3
    andi $AC0.M, #0xffff
    jz bootucode_epilogue+#IROM_BASE
    lris $AC0.M, #0x2
    srs  @DSCR, $AC0.M
    sr   @DSMAH, $IX0
    sr   @DSMAL, $IX1
    sr   @DSPA, $IX2
    sr   @DSBL, $IX3
    call wait_dma+#IROM_BASE

bootucode_epilogue:
    clr  $ACC1
    lr   $AC1.M, @DSBL
    jmpr $AR0

WARNPC 0xe7
ORG 0xe7
; Args:
; AR0 points to the 32 input 1 samples (s16)
; AR1 points to the volume data (init1, delta1, init2, delta2)
; AR2 points to the already mixed samples for output 1 (s32)
; AR3 points to where the output 1 should be stored (s32)
; IX0 points to the 32 input 2 samples (s16)
; IX1 points to where the output 2 should be stored (s32)
;
; Returns:
; AX0.L is the value of the last sample from input 1
; AX1.H is the value of the last sample from input 2
;
; for i = 0..31:
;   ar3[i] = ((ar2[i] << 16) + ar0[i] * ar1[0]) >> 16
; for i = 0..31:
;   ix1[i] = ((ix1[i] << 16) + ix0[i] * ar1[2]) >> 16
; ax0.l = ar0[31] * ar1[0]
; ax1.h = ix0[31] * ar1[2]
mix_two_add:
    call mix_add+#IROM_BASE
    mrr $AR0, $IX0
    mrr $AR2, $IX1
    mrr $AR3, $IX1
    mrr $IX0, $AX0.L
    call mix_add+#IROM_BASE
    mrr $AX1.H, $AX0.L
    mrr $AX0.L, $IX0
    ret

WARNPC 0x1f4
ORG 0x1f4
; used by GBA ucode for joyboot length and is the end of some mixing function
; (for an example of hitting the full function, try running the main menu of
; Metroid Prime using the Nintendo DSP ROM).
sub_81f4:
    asr16'ir $ACC1 : $AR1
    clr's $ACC0 : @$AR3, $AC1.M ; AC1.M is always #0x0 here.
    ; necessary both to match register state of official ROM, and for the
    ; following mul. could also be mrr $AX1.H, $AC0.M (before clearing ACC0).
    mrr $AX1.H, $AX0.H
    ; make the product register match.
    mul's $AX1.L, $AX1.H : @$AR3, $AC1.L
    ret

WARNPC 0x1f9
ORG 0x1f9
; Args:
; AR0 points to the 32 input samples (s16)
; AR1 points to the volume data (init, delta)
; AR2 points to the already mixed samples (s32)
; AR3 points to where the output should be stored (s32)
;
; Returns:
; AX0.L is the value of the last sample
; AX1.H is the first address after the output
;
; for i = 0..31:
;   ar3[i] = ((ar2[i] << 16) + ar0[i] * ar1[0]) >> 16
; ax0.l = ar0[31] * ar1[0]
; ax1.h = ar3 + 32 // assuming ar3 is a s32 pointer
mix_add:
    lrri $AX1.L, @$AR1
    iar $AR1
    bloopi #32, ____mix_add_end_loop+#IROM_BASE
        lrri $AC0.M, @$AR2
        lrri $AC0.L, @$AR2
        lsl16 $ACC0
        lrri $AX0.H, @$AR0
        mulx $AX0.H, $AX1.L
        addp $ACC0
        asr16 $ACC0
        srri @$AR3, $AC0.M
____mix_add_end_loop:
        srri @$AR3, $AC0.L
    movp $ACC0
    mrr $AX0.L, $AC0.M
    mrr $AX1.H, $AR3
    ret

WARNPC 0x282
ORG 0x282
; for i = 0..31:
;   ar3[i] = ar1[0] + i * ar1[1]
;   ar2[i] = ((ar2[i] << 16) + ar0[i] * ar3[i]) >> 16
;   ar3[i+32] = ar1[2] + i * ar1[3]
;   ix1[i] = ((ix1[i] << 16) + ix0[i] * ar3[i+32]) >> 16
; ax0.l = ar0[31] * ar3[31]
; ax1.h = ix0[31] * ar3[63]
mix_two_add_ramp:
    call mix_add_ramp+#IROM_BASE
    mrr $AR0, $IX0
    mrr $AR2, $IX1
    mrr $IX1, $AX0.L
    call mix_add_ramp+#IROM_BASE
    mrr $AX1.H, $AX0.L
    mrr $AX0.L, $IX1
    ret

WARNPC 0x458
ORG 0x458
; used by GBA ucode for joyboot length
sub_8458:
    ; AC1.L after = AC1.M before + 7. this looks really stupid, but matches
    ; captured traces and seems to work.
    addis $AC1.M, #0x7
    asr16 $ACC1
    srri @$AR3, $AC1.M ; or just #0x0.
    srri @$AR3, $AC1.L
    ret

WARNPC 0x45d
ORG 0x45d
; for i = 0..31:
;   ar3[i] = ar1[0] + i * ar1[1]
;   ar2[i] = ((ar2[i] << 16) + ar0[i] * ar3[i]) >> 16
; ax0.l = ar0[31] * ar3[31]
mix_add_ramp:
    clr $ACC0
    clr $ACC1
    lrri $AC0.L, @$AR1
    lrrd $AC1.L, @$AR1
    mrr $IX2, $AR3

    bloopi #32, ____mix_add_ramp_end_ramp+#IROM_BASE
        srri @$AR3, $AC0.L
____mix_add_ramp_end_ramp:
        add $ACC0, $ACC1

    srri @$AR1, $AC0.L
    iar $AR1
    mrr $IX3, $AR1
    mrr $AR1, $IX2
    mrr $AR3, $AR2

    bloopi #32, ____mix_add_ramp_end_loop+#IROM_BASE
        lrri $AC0.M, @$AR2
        lrri $AC0.L, @$AR2
        lsl16 $ACC0
        lrri $AX0.H, @$AR0
        lrri $AX1.L, @$AR1
        mulx $AX0.H, $AX1.L
        addp $ACC0
        asr16 $ACC0
        srri @$AR3, $AC0.M
____mix_add_ramp_end_loop:
        srri @$AR3, $AC0.L
    movp $ACC0
    mrr $AX0.L, $AC0.M
    mrr $AR1, $IX3
    mrr $AR3, $IX2
    ret

WARNPC 0x723
ORG 0x723
; called by GBA ucode
sub_8723:
    ; in GBA-HLE, the nonce challenge is XOR'd with 0x6f646573, which happens
    ; to match the values of the AX1.H register across these two calls.
    xorr $AC1.M, $AX1.H
    ; the value of @AR2 is always the same as AC1.M after
    srrd @$AR2, $AC1.M
    ret

WARNPC 0x809
ORG 0x809
; called by GBA ucode
sub_8809:
    ; AR2 is the only addressing register that corresponds to the dmem writes
    ; could be AC1.L or AX0.L in the second call, but can't be AX0.L in the
    ; third call.
    srr @$AR2, $AC1.L
    ; AC1.M after calling always look like either AC1.M | AC0.M or
    ; AC1.M | AX0.H. TODO: Why pick AX0.H?
    orr $AC1.M, $AX0.H
    ; the second dmem write is incremented only in calls #3A and #3B. There,
    ; IX2 is the only register set to 1, and it's specifically set to 1 in the
    ; ucode. It's set to 0 in the first two calls.
    addarn $AR2, $IX2
    ; obvious
    srri @$AR2, $AC1.M
    ret

WARNPC 0x8e5
ORG 0x8e5
; used by GBA ucode for challenge nonce, logo palette/speed, and joyboot length
sub_88e5:
    dar $AR1 ; always gets decremented, no effect on rest of function
    lrri $AC1.M, @$AR2
    lrrd $AC1.L, @$AR2
    add $ACC0, $ACC1 ; signed addition
    orr $AC0.M, $AX0.H
    srri @$AR2, $AC0.M
    srr @$AR2, $AC0.L
    ret

WARNPC 0x1000
ORG 0x1000