aboutsummaryrefslogtreecommitdiff
path: root/lib/snesapu/SNES/SNESAPU/APU.Asm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snesapu/SNES/SNESAPU/APU.Asm')
-rw-r--r--lib/snesapu/SNES/SNESAPU/APU.Asm423
1 files changed, 423 insertions, 0 deletions
diff --git a/lib/snesapu/SNES/SNESAPU/APU.Asm b/lib/snesapu/SNES/SNESAPU/APU.Asm
new file mode 100644
index 0000000000..e7fad1f16f
--- /dev/null
+++ b/lib/snesapu/SNES/SNESAPU/APU.Asm
@@ -0,0 +1,423 @@
+;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
+;Super Nintendo Entertainment System(tm) Audio Processing Unit Emulator
+; Copyright (C)2003-06 Alpha-II Productions
+;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
+
+CPU 386
+BITS 32
+
+
+;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
+;Header files
+
+%include "../../Macro.Inc"
+%include "SPC700.Inc"
+%include "DSP.Inc"
+%define INTERNAL
+%include "APU.Inc"
+
+%if DSPINTEG
+EXTERN SetEmuDSP ;DSP.Asm - Used to set EmuDSP parameters
+%endif
+
+
+
+;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
+; Data and Variables
+
+SECTION .bss ALIGN=4
+
+ cycLeft resd 1 ;Clock cycles left to emulate in EmuAPU loop
+ smpDec resd 1 ;Unused clocks from cycle to sample conversion
+ smpRate resd 1 ;Output sample rate (used by sound card and DSP)
+ smpRAdj resd 1 ;Sample rate adjustment (16.16)
+
+
+
+;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
+; Code
+
+SECTION .text ALIGN=16
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Initialize Audio Processing Unit
+
+PROC InitAPU
+
+ Call InitSPC
+ Call InitDSP
+
+ Mov dword [smpRate],32000
+ Mov dword [smpRAdj],10000h
+
+ Call SetAPUSmpClk,[smpRAdj]
+
+ Mov EAX, \
+ CPU_CYC | \
+ (DEBUG << 8) | (DSPINTEG << 9) | \
+ (HALFC << 16) | (CNTBK << 17) | (SPEED << 18) | (IPLW << 19) | (DSPBK << 20) | (PROFILE << 21) | \
+ (MMETER << 24) | (VMETER << 25) | (STEREO << 26)
+
+ENDP
+
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Reset Audio Processor
+
+PROC ResetAPU
+
+ Call ResetSPC
+ Call ResetDSP
+
+ And dword [cycLeft],0
+ And dword [smpDec],0
+
+ENDP
+
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Load SPC File
+
+PROC LoadSPCFile, pFile
+USES ALL
+
+ Call ResetAPU
+
+ Mov ESI,[%$pFile]
+
+ Add ESI,100h ;memcpy(pAPURAM, &spc[0x100], 0x10000)
+ Mov EDI,[pAPURAM]
+ Mov ECX,10000h / 4
+ Rep MovSD
+
+ Mov EDI,dsp ;memcpy(&dsp, &spc[0x10100], 128)
+ Or ECX,128 / 4
+ Rep MovSD
+
+ Add ESI,40h ;memcpy(xram, &spc[0x101C0], 64)
+ Mov EDI,[pAPURAM]
+ Add EDI,-80h
+ Or ECX,40h / 4
+ Rep MovSD
+
+ Mov ESI,[%$pFile]
+ MovZX EAX,byte [2Bh+ESI] ;SP
+ MovZX ECX,byte [2Ah+ESI] ;PSW
+ MovZX EDX,byte [28h+ESI] ;X
+ MovZX EBX,byte [29h+ESI] ;Y
+ MovZX EDI,byte [27h+ESI] ;A
+ MovZX ESI,word [25h+ESI] ;PC
+ Call FixSPCLoad,ESI,EDI,EBX,EDX,ECX,EAX
+ Call FixDSPLoad
+
+ Call SetDSPAAR,-1,-1,-1,-1
+
+ENDP
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Save Audio Processor State
+
+PROC SaveAPU, pSPC, pDSP
+
+ Mov EAX,[%$pSPC]
+ Test EAX,EAX
+ JZ short .NoSPC
+ Call SaveSPC,EAX
+ .NoSPC:
+
+ Mov EAX,[%$pDSP]
+ Test EAX,EAX
+ JZ short .NoDSP
+ Call SaveDSP,EAX
+ .NoDSP:
+
+ENDP
+
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Restore Audio Processor State
+
+PROC RestoreAPU, pSPC, pDSP
+
+ Mov EAX,[%$pSPC]
+ Test EAX,EAX
+ JZ short .NoSPC
+ Call RestoreSPC,EAX
+ .NoSPC:
+
+ Mov EAX,[%$pDSP]
+ Test EAX,EAX
+ JZ short .NoDSP
+ Call RestoreDSP,EAX
+ .NoDSP:
+
+ENDP
+
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Set Audio Processor Options
+
+PROC SetAPUOpt, mixtype, chn, bits, rate, inter, opts
+
+ Mov EAX,[%$rate] ;Is a rate specified?
+ Cmp EAX,-1 ;if (rate!=-1)
+ JE short .KeepRate
+
+ Push ECX,EDX
+ Mov EAX,[%$rate]
+
+ Mov ECX,8000 ;if (rate < 8000) rate = 8000;
+ Sub EAX,ECX
+ CDQ
+ Not EDX
+ And EAX,EDX
+ Add EAX,ECX
+
+ Mov ECX,192000 ;if (rate > 192000) rate = 192000;
+ Sub EAX,ECX
+ CDQ
+ And EAX,EDX
+ Add EAX,ECX
+
+ Mov [smpRate],EAX
+ Pop EDX,ECX
+
+ .KeepRate:
+
+ Pop EBP
+ Jmp SetDSPOpt ;Set options in DSP emulator
+
+ENDP
+
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Set Audio Processor Sample Clock
+
+PROC SetAPUSmpClk, speed
+USES EDX,ECX
+
+ Mov EAX,[%$speed]
+
+ Mov ECX,1000h ;if (speed < 4096) speed = 4096;
+ Sub EAX,ECX
+ CDQ
+ Not EDX
+ And EAX,EDX
+ Add EAX,ECX
+
+ Mov ECX,100000h ;if (speed > 1048576) speed = 1048576;
+ Sub EAX,ECX
+ CDQ
+ And EAX,EDX
+ Add EAX,ECX
+
+ Mov [smpRAdj],EAX
+
+ENDP
+
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Emulate Audio Processing Unit
+
+PROC EmuAPU, pBuf, cyc, smp
+LOCALS rate,fcw
+USES ECX,EDX,EBX,EDI
+
+%if PROFILE
+ Call StartAPUProfile,Profile.apuTSC
+%endif
+
+ ;Switch the FPU into single precision mode
+ ;According to the Intel docs, this is faster since the floating-point mixing routine only
+ ; requires single precision accuracy. However, on my Pentium 4 the greatest performance
+ ; increase I've seen is 4 percent.
+
+ FStCW [%$fcw]
+ FStCW [2+%$fcw]
+ And word [%$fcw],~0300h ;Switch to single precision operation
+ FLdCW [%$fcw]
+
+ Mov EAX,[smpRate] ;rate = (smpRate << 16) / smpRAdj
+ Mov EDX,EAX
+ ShL EAX,16
+ ShR EDX,16
+ Div dword [smpRAdj]
+ Mov EBX,EAX
+
+ Mov ECX,APU_CLK
+
+%if DSPINTEG
+ ;Fixup samples/cycles --------------------
+ Cmp dword [%$smp],0
+ JZ short .NoSamples
+
+ Call SetEmuDSP,[%$pBuf],[%$smp],EBX
+
+ Mov EAX,[%$cyc]
+ Test EAX,EAX
+ JNZ short .Cycles
+
+ Mov EAX,[%$smp] ;Calculate number of cycles based on samples
+ Mul ECX ;cycles = (APU_CLK * len) / smpREmu
+ Div EBX
+
+ .Cycles:
+ Add [cycLeft],EAX
+ JLE short .NoCycles
+ Jmp short .Emulate
+
+ .NoSamples: ;Calculate number of samples based on cycles
+ Mov EAX,[%$cyc]
+ Add [cycLeft],EAX
+ Retc LE
+
+ Mov EAX,[cycLeft]
+ Mul EBX ;samples = (smpREmu * len) / APU_CLK
+ Div ECX
+ Call SetEmuDSP,[%$pBuf],EAX,EBX
+
+ .Emulate:
+
+ ;Emulate APU -----------------------------
+ Call EmuSPC,[cycLeft]
+ Mov [cycLeft],EAX
+
+ .NoCycles:
+ Call SetEmuDSP,0,0,0 ;Create any remaining samples
+
+%else
+
+ ;If samples were passed, convert to clock cycles
+ Mov EAX,[%$cyc]
+ Test EAX,EAX
+ JNZ short .HaveCycles
+ Mov EAX,[%$smp]
+ Mul ECX ;cycles = (APU_CLK * len) / smpREmu
+ Div EBX
+ .HaveCycles:
+ Add [cycLeft],EAX
+ JLE short .HaveSamples
+
+ Cmp dword [%$smp],0
+ JNZ short .HaveSamples
+ Mov EAX,[cycLeft]
+ Mul EBX
+ Div ECX
+ Mov [%$smp],EAX
+ .HaveSamples:
+
+ ;Emulate APU -----------------------------
+ Mov [%$rate],EBX
+ XOr EBX,EBX ;Number of samples generated
+ Mov EDI,[%$pBuf]
+ .Next:
+ Mov EAX,[cycLeft]
+ Test EAX,EAX
+ JLE short .Done
+
+ ;SPC700 -------------------------------
+ Mov EDX,EAX
+ Call EmuSPC,EAX
+ Mov [cycLeft],EAX
+
+ ;DSP ----------------------------------
+ Sub EDX,EAX ;Calculate number of samples to create
+ Mov EAX,EDX ;EAX = number of cycles emulated
+ Mul dword [%$rate]
+ Add EAX,[smpDec]
+ AdC EDX,0
+ Div ECX ;samples = (((cycles - cycLeft) * smpREmu) + smpDec) / APU_CLK
+ Mov [smpDec],EDX
+
+ Add EBX,EAX ;size += samples
+ Cmp EBX,[%$smp] ;Sometimes sample count will go over by one
+ JBE short .LenOK
+ Add EAX,[%$smp]
+ Sub EAX,EBX
+ Mov EBX,[%$smp]
+ .LenOK:
+
+ Call EmuDSP,EDI,EAX ;pBuf = EmuDSP(pBuf,samples)
+ Mov EDI,EAX
+
+ Jmp short .Next
+
+ .Done:
+
+ ;Make sure enough samples were created to fill buffer
+ Sub EBX,[%$smp]
+ Retc Z,EDI
+
+ Neg EBX
+ Call EmuDSP,EDI,EBX
+%endif
+
+ FLdCW [2+%$fcw] ;Restore FPU precision to previous degree
+
+%if PROFILE
+ Call EndAPUProfile,Profile.apuTSC
+%endif
+
+ENDP
+
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Seek to Position
+
+PROC SeekAPU, time, fast
+USES ECX,EDX
+
+ XOr EDX,EDX
+ Mov EAX,[%$time] ;numSeconds = time / 64000
+ Test EAX,EAX
+ Retc Z
+ Mov ECX,64000
+ Div ECX
+ Mov ECX,EAX
+ IMul EDX,APU_CLK/64000 ;EDX = (time % 64000) * (APU_CLK / 64000)
+
+ Test byte [%$fast],-1 ;Fast mode completely bypasses the DSP emulation
+ JZ short .Slow
+
+ Add EDX,[cycLeft]
+ Mov EAX,EDX
+ .EmuSPC:
+
+ Add EAX,APU_CLK ;Emulate SPC for 1 second
+ .Next:
+ Call EmuSPC,EAX
+ Test EAX,EAX
+ JG short .Next
+
+ Dec ECX
+ JG short .EmuSPC
+ Mov [cycLeft],EAX
+
+ Jmp short .Done
+
+ .Slow:
+ Test EDX,EDX
+ JZ short .EmuAPU
+
+ Call EmuAPU,0,EDX,0
+ Test ECX,ECX
+ JZ short .Done
+
+ .EmuAPU:
+ Call EmuAPU,0,APU_CLK,0
+ Dec ECX
+ JNZ short .EmuAPU
+
+ .Done:
+
+ Call FixDSPSeek,[%$fast] ;Fixup DSP after seeking
+
+ENDP
+
+
+;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+;Shutdown Audio Processing Unit
+
+PROC ShutAPU
+
+ENDP \ No newline at end of file