diff options
Diffstat (limited to 'lib/snesapu/SNES/SNESAPU/APU.Asm')
-rw-r--r-- | lib/snesapu/SNES/SNESAPU/APU.Asm | 423 |
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 |