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
