libretro-dolphin/docs/DSP/free_dsp_rom/dsp_rom.ds
Michael M fcb1eb9d3b dsp_rom: skip bootucode_ax when running from entrypoint
This could cause the first branch of the bootucode procedure, which
takes its parameters from the AX registers, to run during the ROM init
sequence. Since the ROM doesn't set any of the AX registers, the values
aren't meaningful, and can cause bad DMA transfers and crashes.
2017-08-10 10:53:12 -07:00

312 lines
6.8 KiB
Plaintext

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:
srs @DSMAH, $AX0.H
srs @DSMAL, $AX0.L
si @DSCR, #0x1
srs @DSPA, $AX1.H
srs @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
srs @DSMAH, $AX0.H
srs @DSMAL, $AX0.L
srs @DSPA, $AX1.H
srs @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
mix_two_add:
call mix_add+#IROM_BASE
iar $AR1
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
mix_add:
lrri $AX1.L, @$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
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
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 $AX1.H, $AR3
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