📄 spc700.asm
字号:
;Copyright (C) 1997-2001 ZSNES Team ( zsknight@zsnes.com / _demo_@zsnes.com )
;
;This program is free software; you can redistribute it and/or
;modify it under the terms of the GNU General Public License
;as published by the Free Software Foundation; either
;version 2 of the License, or (at your option) any later
;version.
;
;This program is distributed in the hope that it will be useful,
;but WITHOUT ANY WARRANTY; without even the implied warranty of
;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;GNU General Public License for more details.
;
;You should have received a copy of the GNU General Public License
;along with this program; if not, write to the Free Software
;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
%include "macros.mac"
EXTSYM DSPMem,spcWptr,debstop,disablespcclr,SPCSkipXtraROM,SPC700sh
EXTSYM cycpbl,spcRptr
EXTSYM spc700read
EXTSYM dspWptr
EXTSYM changeexecloop,curexecstate,SA1Enable,tableadb
NEWSYM Spc700AsmStart
%include "cpu/regsw.mac"
%include "cpu/spcdef.inc"
%include "cpu/spcaddr.inc"
; SPC 700 Emulation by _Demo_
; Version 2.0
; Little info on functions :
; Write byte : write al at [ebx]
; Read byte : read al from [ebx]
; update timer : update the timers, called every scanline
ALIGN32
;spcBuffer times 65536*4 db 0 ; The buffer of brr blocks... 4 bits -> 16 bits
;spcRamcmp times 65536 db 0 ; SPC Ram compare buffer
;spcPrevbf times 65536 db 0 ; SPC PrevX compare buffer
NEWSYM spcRam, times 65472 db 0FFh ; Pointer to the SPC's RAM
; copy #1
; THE SPC ROM :)
db 0CDh,0EFh,0BDh,0E8h,000h,0C6h,01Dh,0D0h,0FCh,08Fh,0AAh,0F4h,08Fh,0BBh,0F5h,078h
db 0CCh,0F4h,0D0h,0FBh,02Fh,019h,0EBh,0F4h,0D0h,0FCh,07Eh,0F4h,0D0h,00Bh,0E4h,0F5h
db 0CBh,0F4h,0D7h,000h,0FCh,0D0h,0F3h,0ABh,001h,010h,0EFh,07Eh,0F4h,010h,0EBh,0BAh
db 0F6h,0DAh,000h,0BAh,0F4h,0C4h,0F4h,0DDh,05Dh,0D0h,0DBh,01Fh,000h,000h,0C0h,0FFh
db 0AAh,0BBh,0CCh,0DDh,0EEh,0FFh,000h,011h,022h,033h,044h,055h,066h,077h,088h,099h
NEWSYM spcPCRam,
dd 0 ; Program Counter (with spcRam added)
NEWSYM spcA,
db 0 ; The A register (general purpose)
db 0
db 0
db 0
NEWSYM spcX,
db 0 ; The X register (general purpose)
db 0
db 0
db 0
NEWSYM spcY,
db 0 ; The Y register (general purpose)
db 0
db 0
db 0
NEWSYM spcP,
db 0 ; The processor status byte (Removed for each flags)
db 0 ; NZ are not always processed...
db 0
db 0
NEWSYM spcNZ,
db 0 ; The processor NZ flag (little speed up hack :) )
db 0
db 0
db 0
;spcNF db 0 ; The Negative Flag 128 or 127
;spcOF db 0 ; The Overflow Flag 64 or 191
;spcDPF db 0 ; Direct Page Flag 32 or 223
;spcUF db 0 ; The Unused Flag ? 16 or 239
;spcHCF db 0 ; The Half Carry Flag 8 or 247
;spcIF db 0 ; The interrupt flag 4 or 251
;spcZF db 0 ; The Zero Flag 2 or 253
;spcCF db 0 ; The Carry Flag 1 or 254
NEWSYM spcS, dd 1FFh ; The stack pointer (always from 100 to 1FF) (added Ram)
NEWSYM spcRamDP, dd 0 ; The direct page pointer
NEWSYM spcCycle, dd 0 ; The Cycle Counter
NEWSYM reg1read, db 0 ; read from 65816
NEWSYM reg2read, db 0 ; read from 65816
NEWSYM reg3read, db 0 ; read from 65816
NEWSYM reg4read, db 0 ; read from 65816
NEWSYM timeron, db 0 ; timer0 on
NEWSYM timincr0, db 0 ; # of ticks before incrementing
NEWSYM timincr1, db 0 ; # of ticks before incrementing
NEWSYM timincr2, db 0 ; # of ticks before incrementing
NEWSYM timinl0, db 0 ; ticks left before incrementing
NEWSYM timinl1, db 0 ; ticks left before incrementing
NEWSYM timinl2, db 0 ; ticks left before incrementing
NEWSYM timrcall, db 0 ; alternating bit 0 to correctly timer timer1 & 2 to 8000hz
NEWSYM spcextraram, times 64 db 0 ; extra ram, used for tcall
NEWSYM FutureExpandS, times 256-64 db 0
spcsave equ $-spcRam
; pharos equ hack *sigh*
NEWSYM PHspcsave, dd spcsave
; copy #2
NEWSYM SPCROM
db 0CDh,0EFh,0BDh,0E8h,000h,0C6h,01Dh,0D0h,0FCh,08Fh,0AAh,0F4h,08Fh,0BBh,0F5h,078h
db 0CCh,0F4h,0D0h,0FBh,02Fh,019h,0EBh,0F4h,0D0h,0FCh,07Eh,0F4h,0D0h,00Bh,0E4h,0F5h
db 0CBh,0F4h,0D7h,000h,0FCh,0D0h,0F3h,0ABh,001h,010h,0EFh,07Eh,0F4h,010h,0EBh,0BAh
db 0F6h,0DAh,000h,0BAh,0F4h,0C4h,0F4h,0DDh,05Dh,0D0h,0DBh,01Fh,000h,000h,0C0h,0FFh
%macro WriteByte 0
cmp ebx,0ffh+spcRam
ja .extramem
cmp ebx,0f0h+spcRam
jb .normalmem
sub ebx,spcRam
call dword near [spcWptr+ebx*4-0f0h*4]
jmp .finished
.extramem
cmp ebx,0ffc0h+spcRam
jb .normalmem
mov [spcextraram+ebx-0FFC0h-spcRam],al
test byte[spcRam+0F1h],80h
jnz .finished
; push ecx
; mov cl,[DSPMem+06Ch]
; test cl,20h
; pop ecx
; jz .finished
.normalmem
mov [ebx],al
.finished
%endmacro
%macro ReadByte 0
cmp ebx,0f0h+spcRam
jb .rnormalmem2
cmp ebx,0ffh+spcRam
ja .rnormalmem
sub ebx,spcRam
call dword near [spcRptr+ebx*4-0f0h*4]
jmp .rfinished
.rnormalmem
; cmp ebx,0ffc0h+spcRam
; jb .rnormalmem2
; test byte [DSPMem+6Ch],10h
; jz .rnormalmem2
; mov al,[spcextraram+ebx-0FFC0h-spcRam]
; jmp .rfinished
.rnormalmem2
mov al,[ebx]
.rfinished
%endmacro
%macro ReadByte2 0
cmp ebx,0f0h+spcRam
jb .rnormalmem2
cmp ebx,0ffh+spcRam
ja .rnormalmem
sub ebx,spcRam
call dword near [spcRptr+ebx*4-0f0h*4]
add ebx,spcRam
jmp .rfinished
.rnormalmem
; cmp ebx,0ffc0h+spcRam
; jb .rnormalmem2
; test byte [DSPMem+6Ch],10h
; jz .rnormalmem2
; mov al,[spcextraram+ebx-0FFC0h-spcRam]
; jmp .rfinished
.rnormalmem2
mov al,[ebx]
.rfinished
%endmacro
NEWSYM timer2upd, dd 0
; This function is called every scanline (262*60 times/sec)
; Make it call 0.9825 times (393/400) (skip when divisible by 64)
; 2 8khz, 1 64khz
NEWSYM updatetimer
; inc dword[timer2upd]
; cmp dword[timer2upd],400
; jne .nowrap
; mov dword[timer2upd],0
;.nowrap
;.again
; mov eax,dword[timer2upd]
; shr eax,6
; shl eax,6
; cmp eax,dword[timer2upd]
; je near .noin2d
.another
xor byte[timrcall],01h
test byte[timrcall],01h
jz near .notimer
test byte[timeron],1
jz .noin0
dec byte[timinl0]
jnz .noin0
inc byte[spcRam+0FDh]
mov al,[timincr0]
mov [timinl0],al
cmp byte[spcRam+0FDh],1
jne .noin0
reenablespc
mov dword[cycpbl],0
.noin0
test byte[timeron],2
jz .noin1
dec byte[timinl1]
jnz .noin1
inc byte[spcRam+0FEh]
mov al,[timincr1]
mov [timinl1],al
cmp byte[spcRam+0FEh],1
jne .noin1
reenablespc
mov dword[cycpbl],0
.noin1
.notimer
test byte[timeron],4
jz near .noin2d2
dec byte[timinl2]
jnz .noin2
inc byte[spcRam+0FFh]
mov al,[timincr2]
mov [timinl2],al
cmp byte[spcRam+0FFh],1
jne .noin2
reenablespc
mov dword[cycpbl],0
.noin2
dec byte[timinl2]
jnz .noin2b
inc byte[spcRam+0FFh]
mov al,[timincr2]
mov [timinl2],al
cmp byte[spcRam+0FFh],1
jne .noin2b
reenablespc
mov dword[cycpbl],0
.noin2b
dec byte[timinl2]
jnz .noin2c
inc byte[spcRam+0FFh]
mov al,[timincr2]
mov [timinl2],al
cmp byte[spcRam+0FFh],1
jne .noin2c
reenablespc
mov dword[cycpbl],0
.noin2c
dec byte[timinl2]
jnz .noin2d
inc byte[spcRam+0FFh]
mov al,[timincr2]
mov [timinl2],al
cmp byte[spcRam+0FFh],1
jne .noin2d
reenablespc
mov dword[cycpbl],0
.noin2d
.noin2d2
; inc dword[timer2upd]
; cmp dword[timer2upd],31
; jne .nowrap
; mov dword[timer2upd],0
; jmp .again
;.nowrap
inc dword[timer2upd]
cmp dword[timer2upd],60
jne .noanother
mov dword[timer2upd],0
jmp .another
.noanother
ret
; SPC Write Registers
; DO NOT MODIFY DX OR ECX!
NEWSYM SPCRegF0
mov [spcRam+0F0h],al
ret
NEWSYM SPCRegF1
cmp byte[disablespcclr],1
je .No23Clear
test al,10h
jz .No01Clear
mov byte [spcRam+0F4h],0
mov byte [spcRam+0F5h],0
.No01Clear
test al,20h
jz .No23Clear
mov byte [spcRam+0F6h],0
mov byte [spcRam+0F7h],0
.No23Clear
cmp byte[SPCSkipXtraROM],1
je near .AfterNoROM
test al,80h
jz .NoROM
push eax
push ebx
xor eax,eax
.loopa
mov bl,[SPCROM+eax]
mov [spcRam+0FFC0h+eax],bl
inc eax
cmp eax,040h
jne .loopa
pop ebx
pop eax
jmp .AfterNoROM
.NoROM
push eax
push ebx
xor eax,eax
.loopb
mov bl,[spcextraram+eax]
mov [spcRam+0FFC0h+eax],bl
inc eax
cmp eax,040h
jne .loopb
pop ebx
pop eax
.AfterNoROM
mov [spcRam+0F1h],al
and al,0Fh
mov [timeron],al
ret
NEWSYM SPCRegF2
mov [spcRam+0F2h],al
push eax
push ebx
xor eax,eax
mov al,[spcRam+0F2h]
mov bl,[DSPMem+eax]
mov [spcRam+0F3h],bl
pop ebx
pop eax
ret
NEWSYM SPCRegF3
push ebx
xor ebx,ebx
mov bl,[spcRam+0F2h]
and bl,07fh
call dword near [dspWptr+ebx*4]
pop ebx
mov [spcRam+ebx],al
ret
NEWSYM SPCRegF4
mov [reg1read],al
inc dword[spc700read]
ret
NEWSYM SPCRegF5
mov [reg2read],al
inc dword[spc700read]
ret
NEWSYM SPCRegF6
mov [reg3read],al
inc dword[spc700read]
ret
NEWSYM SPCRegF7
mov [reg4read],al
inc dword[spc700read]
ret
NEWSYM SPCRegF8
mov [spcRam+ebx],al
ret
NEWSYM SPCRegF9
mov [spcRam+ebx],al
ret
NEWSYM SPCRegFA
mov [timincr0],al
test byte[timinl0],0FFh
jne .nowrite
mov [timinl0],al
.nowrite
mov [spcRam+ebx],al
ret
NEWSYM SPCRegFB
mov [timincr1],al
test byte[timinl1],0FFh
jne .nowrite
mov [timinl1],al
.nowrite
mov [spcRam+ebx],al
ret
NEWSYM SPCRegFC
mov [timincr2],al
test byte[timinl2],0FFh
jne .nowrite
mov [timinl2],al
.nowrite
mov [spcRam+ebx],al
ret
NEWSYM SPCRegFD
ret
NEWSYM SPCRegFE
ret
NEWSYM SPCRegFF
ret
; SPC Read Registers
; DO NOT MODIFY ANY REG!
; return data true al
NEWSYM RSPCRegF0
mov al,[spcRam+0f0h]
ret
NEWSYM RSPCRegF1
mov al,[spcRam+0f1h]
ret
NEWSYM RSPCRegF2
mov al,[spcRam+0f2h]
ret
NEWSYM RSPCRegF3
mov al,[spcRam+0f3h]
ret
NEWSYM RSPCRegF4
mov al,[spcRam+0f4h]
ret
NEWSYM RSPCRegF5
mov al,[spcRam+0f5h]
ret
NEWSYM RSPCRegF6
mov al,[spcRam+0f6h]
ret
NEWSYM RSPCRegF7
mov al,[spcRam+0f7h]
ret
NEWSYM RSPCRegF8
mov al,0 ;[spcRam+0f8h]
ret
NEWSYM RSPCRegF9
mov al,0 ;[spcRam+0f9h]
ret
NEWSYM RSPCRegFA
mov al,[spcRam+0fah]
ret
NEWSYM RSPCRegFB
mov al,[spcRam+0fbh]
ret
NEWSYM RSPCRegFC
mov al,[spcRam+0fch]
ret
NEWSYM RSPCRegFD
mov al,[spcRam+0fdh]
and al,0Fh
cmp byte[spcRam+0fdh],0
je spcnextskip
mov byte [spcRam+0fdh],0
mov byte [spcnumread],0
ret
NEWSYM RSPCRegFE
mov al,[spcRam+0feh]
and al,0Fh
cmp byte[spcRam+0feh],0
je spcnextskip
mov byte [spcRam+0feh],0
mov byte [spcnumread],0
ret
NEWSYM RSPCRegFF
mov al,[spcRam+0ffh]
and al,0Fh
cmp byte[spcRam+0ffh],0
je spcnextskip
mov byte [spcRam+0ffh],0
mov byte [spcnumread],0
ret
NEWSYM spcnextskip
inc byte[spcnumread]
cmp byte[spcnumread],5
je near haltspc
ret
NEWSYM haltspc
cmp byte[SPC700sh],1
je .nochangestate
mov dword[cycpbl],0FFFFFFFFh
test byte[curexecstate],02h
jz .nochangestate
and byte[curexecstate],0FDh
push ebx
xor ebx,ebx
mov bl,dl
mov edi,[tableadb+ebx*4]
pop ebx
.nochangestate
mov byte[spcnumread],0
ret
NEWSYM spcnumread, db 0
%macro SPCSetFlagnzc 0
js .setsignflag
jz .setzeroflag
mov byte [spcNZ],1
jc .setcarryflag
and byte [spcP],0FEh
ret
.setsignflag
mov byte [spcNZ],80h
jc .setcarryflag
and byte [spcP],0FEh
ret
.setzeroflag
mov byte [spcNZ],0
jc .setcarryflag
and byte [spcP],0FEh
ret
.setcarryflag
or byte [spcP],1
ret
%endmacro
%macro SPCSetFlagnzcnoret 0
js .setsignflag
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -