;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. ; SPC7110 emulation. Information fully reverse engineered ; by Dark Force and John Weidman, ZSNES code by zsKnight ; SA-1 emulation. Information provided by Ivar of Snes9x. ; coded by zsKnight ; SDD-1 emulation. SDD-1 MMC reverse engineered by zsKnight, ; SDD-1 decompress Dark Force and John Weidman, ; - Add MMC support ; - Add end of DMA IRQ support ; - Add Char Conversion #1 ; - Add Char Conversion #2 ; - Add Memory Disables (Guess this isn't needed) ; IRQs - IRQ Clear (also clear 2300), IRQ Disable, and IRQ Enable ; Mario RPG Level-up not working - it was using one of the IRQ functions ; that no other place in the game is using, which I suppose is the cause ; of the problem, but it's been so long since I worked on SA-1, that ; I forgot which part. %include "macros.mac" EXTSYM regptr,regptw,romdata,SA1Status,debstop4,SDD1BankA,curromsize EXTSYM debuggeron EXTSYM Get_Time,Get_TimeDate EXTSYM spc7110romptr,SPC7110Entries EXTSYM SPC7110IndexSize,SPC7110nfname EXTSYM Open_File,Close_File,Read_File,File_Seek ; EXTSYM Msgptr,MessageOn EXTSYM irqv2,irqv,nmiv2,nmiv EXTSYM snesmmap,snesmap2 EXTSYM curypos,CurrentExecSA1 EXTSYM debstop3 EXTSYM memaccessbankr8sdd1,memtabler8,AddrNoIncr NEWSYM Sa1RegsAsmStart %include "cpu/regs.mac" %include "cpu/regsw.mac" ALIGN32 NEWSYM SPCMultA, dd 0 NEWSYM SPCMultB, dd 0 NEWSYM SPCDivEnd, dd 0 NEWSYM SPCMulRes, dd 0 NEWSYM SPCDivRes, dd 0 NEWSYM SPC7110BankA, dd 020100h NEWSYM SPC7110RTCStat, dd 0 NEWSYM SPC7110RTC, db 00,00,00,00,00,00,01,00,01,00,00,00,00,00,0Fh,00 NEWSYM SPC7110RTCB, db 00,00,00,00,00,00,01,00,01,00,00,00,00,01,0Fh,06 NEWSYM SPCROMPtr, dd 0 NEWSYM SPCROMtoI, dd SPCROMPtr NEWSYM SPCROMAdj, dd 0 NEWSYM SPCROMInc, dd 0 NEWSYM SPCROMCom, dd 0 NEWSYM SPCCompPtr, dd 0 NEWSYM SPCDecmPtr, dd 0 NEWSYM SPCCompCounter, dd 0 NEWSYM SPCCompCommand, dd 0 NEWSYM SPCCheckFix, dd 0 NEWSYM SPCSignedVal, dd 0 num2writespc7110reg equ $-SPCMultA NEWSYM PHnum2writespc7110reg, dd num2writespc7110reg NEWSYM RTCData, db 0Fh,0,0,0,0,0,0,0,0,0,0,0,0,0,0Fh,0 NEWSYM RTCPtr, dd 0 NEWSYM RTCPtr2, dd 0 NEWSYM RTCRest, dd 0 NEWSYM SPC7110TempPosition, dd 0 NEWSYM SPC7110TempLength, dd 0 NEWSYM SPCPrevCompPtr, dd 0 RTC2800: push ebx cmp dword[RTCRest],100 ; je .go ; inc dword[RTCRest] ; jmp .notfirst .go cmp dword[RTCPtr],0 jne near .notfirst cmp byte[debuggeron],1 je near .notfirst ; fill time/date push ebx push eax call Get_Time mov bl,al and bl,0Fh mov [RTCData+1],bl ; seconds shr eax,4 mov bl,al and bl,0Fh mov [RTCData+2],bl ; jmp .done shr eax,4 cmp word[RTCData+1],0 ; jne .notminch mov bl,al and bl,0Fh mov [RTCData+3],bl ; minutes shr eax,4 mov bl,al and bl,0Fh mov [RTCData+4],bl .notminch ; jmp .done shr eax,4 mov bl,al and bl,0Fh mov [RTCData+5],bl ; hours shr eax,4 mov bl,al and bl,0Fh mov [RTCData+6],bl call Get_TimeDate mov bl,al and bl,0Fh mov [RTCData+7],bl ; day shr eax,4 mov bl,al and bl,0Fh mov bl,al and bl,0Fh mov [RTCData+8],bl shr eax,4 mov bl,al and bl,0Fh mov [RTCData+9],bl ; month shr eax,8 mov bl,al and bl,0Fh mov [RTCData+10],bl ; year shr eax,4 mov bl,al and bl,01Fh xor bh,bh .notokay cmp bl,9 jbe .okay inc bh sub bl,10 jmp .notokay .okay mov [RTCData+11],bl add bh,9 mov [RTCData+12],bh shr eax,8 and al,0Fh mov [RTCData+13],al ; day of week .done pop eax pop ebx .notfirst mov ebx,[RTCPtr] mov al,[RTCData+ebx] inc dword[RTCPtr] cmp dword[RTCPtr],0Fh jne .notclear mov dword[RTCPtr],0 .notclear pop ebx ret RTC2801w: mov byte[debstop3],1 mov dword[RTCRest],0 mov dword[RTCPtr],0 cmp al,0Eh jne .notreset mov dword[RTCPtr2],0 ret .notreset cmp al,0Dh jne .notstop mov dword[RTCPtr2],0 ret .notstop push ebx mov ebx,dword[RTCPtr2] cmp ebx,0 je .next cmp ebx,13 ja .nomore mov [RTCData+ebx],al .next inc dword[RTCPtr2] .nomore pop ebx ret NEWSYM RTCinit mov dword[RTCPtr],0 ret NEWSYM RTCReset setreg 2800h*4,RTC2800 ret NEWSYM RTCReset2 setregw 2801h*4,RTC2801w ret SPC4850: mov al,[SPC7110RTC] ret SPC4851: mov al,[SPC7110RTC+01h] ret SPC4852: mov al,[SPC7110RTC+02h] ret SPC4853: mov al,[SPC7110RTC+03h] ret SPC4854: mov al,[SPC7110RTC+04h] ret SPC4855: mov al,[SPC7110RTC+05h] ret SPC4856: mov al,[SPC7110RTC+06h] ret SPC4857: mov al,[SPC7110RTC+07h] ret SPC4858: mov al,[SPC7110RTC+08h] ret SPC4859: mov al,[SPC7110RTC+09h] ret SPC485A: mov al,[SPC7110RTC+0Ah] ret SPC485B: mov al,[SPC7110RTC+0Bh] ret SPC485C: mov al,[SPC7110RTC+0Ch] ret SPC485D: mov al,[SPC7110RTC+0Dh] ret SPC485E: mov al,[SPC7110RTC+0Eh] ret SPC485F: mov al,[SPC7110RTC+0Fh] ret NEWSYM SPCDecompFin, dd 0 NEWSYM SPC7110init mov dword[SPCMultA],0 mov dword[SPCMultB],0 mov dword[SPCDivEnd],0 mov dword[SPCMulRes],0 mov dword[SPCDivRes],0 mov dword[SPC7110BankA],020100h mov dword[SPC7110RTCStat],0 mov dword[SPC7110RTCStat],0 mov dword[SPCROMPtr],0 mov dword[SPCROMtoI],SPCROMPtr mov dword[SPCROMAdj],0 mov dword[SPCROMInc],0 mov dword[SPCROMCom],0 mov dword[SPCDecompFin],0 mov dword[SPCCompPtr],0 mov dword[SPCDecmPtr],0 mov dword[SPCCompCounter],0 mov dword[SPCCompCommand],0 mov dword[SPCCheckFix],0 mov dword[SPCPrevCompPtr],0 ret NEWSYM SPC7110Reset setregw 4801h*4,SPC4801w setregw 4802h*4,SPC4802w setregw 4803h*4,SPC4803w setregw 4804h*4,SPC4804w setregw 4805h*4,SPC4805w setregw 4806h*4,SPC4806w setregw 4807h*4,SPC4807w setregw 4808h*4,SPC4808w setregw 4809h*4,SPC4809w setregw 480Ah*4,SPC480Aw setregw 480Bh*4,SPC480Bw setregw 4811h*4,SPC4811w setregw 4812h*4,SPC4812w setregw 4813h*4,SPC4813w setregw 4814h*4,SPC4814w setregw 4815h*4,SPC4815w setregw 4816h*4,SPC4816w setregw 4817h*4,SPC4817w setregw 4818h*4,SPC4818w setregw 4820h*4,SPC4820w setregw 4821h*4,SPC4821w setregw 4822h*4,SPC4822w setregw 4823h*4,SPC4823w setregw 4824h*4,SPC4824w setregw 4825h*4,SPC4825w setregw 4826h*4,SPC4826w setregw 4827h*4,SPC4827w setregw 482Eh*4,SPC482Ew setregw 4831h*4,SPC4831w setregw 4832h*4,SPC4832w setregw 4833h*4,SPC4833w setregw 4840h*4,SPC4840w setregw 4841h*4,SPC4841w setregw 4842h*4,SPC4842w ret NEWSYM initSPC7110regs setreg 4800h*4,SPC4800 setreg 4801h*4,SPC4801 setreg 4802h*4,SPC4802 setreg 4803h*4,SPC4803 setreg 4804h*4,SPC4804 setreg 4805h*4,SPC4805 setreg 4806h*4,SPC4806 setreg 4807h*4,SPC4807 setreg 4808h*4,SPC4808 setreg 4809h*4,SPC4809 setreg 480Ah*4,SPC480A setreg 480Bh*4,SPC480B setreg 480Ch*4,SPC480C setreg 4810h*4,SPC4810 setreg 4811h*4,SPC4811 setreg 4812h*4,SPC4812 setreg 4813h*4,SPC4813 setreg 4814h*4,SPC4814 setreg 4815h*4,SPC4815 setreg 4816h*4,SPC4816 setreg 4817h*4,SPC4817 setreg 4818h*4,SPC4818 setreg 481Ah*4,SPC481A setreg 4820h*4,SPC4820 setreg 4821h*4,SPC4821 setreg 4822h*4,SPC4822 setreg 4823h*4,SPC4823 setreg 4824h*4,SPC4824 setreg 4825h*4,SPC4825 setreg 4826h*4,SPC4826 setreg 4827h*4,SPC4827 setreg 4828h*4,SPC4828 setreg 4829h*4,SPC4829 setreg 482Ah*4,SPC482A setreg 482Bh*4,SPC482B setreg 482Ch*4,SPC482C setreg 482Dh*4,SPC482D setreg 482Eh*4,SPC482E setreg 482Fh*4,SPC482F setreg 4831h*4,SPC4831 setreg 4832h*4,SPC4832 setreg 4833h*4,SPC4833 setreg 4834h*4,SPC4834 setreg 4840h*4,SPC4840 setreg 4841h*4,SPC4841 setreg 4842h*4,SPC4842 setreg 4850h*4,SPC4850 setreg 4851h*4,SPC4851 setreg 4852h*4,SPC4852 setreg 4853h*4,SPC4853 setreg 4854h*4,SPC4854 setreg 4855h*4,SPC4855 setreg 4856h*4,SPC4856 setreg 4857h*4,SPC4857 setreg 4858h*4,SPC4858 setreg 4859h*4,SPC4859 setreg 485Ah*4,SPC485A setreg 485Bh*4,SPC485B setreg 485Ch*4,SPC485C setreg 485Dh*4,SPC485D setreg 485Eh*4,SPC485E setreg 485Fh*4,SPC485F ret %macro BankSwitchSPC7110 2 push ecx push edx push eax mov [SPC7110BankA+%1],al inc al cmp byte[curromsize],13 jne .mbit24 .mbit40 cmp al,5 jb .okaymbit sub al,4 jmp .mbit40 .mbit24 cmp al,3 jb .okaymbit sub al,2 jmp .mbit24 .okaymbit and eax,07h shl eax,20 add eax,[romdata] mov ecx,10h mov ebx,snesmap2+%2*4 mov edx,snesmmap+%2*4 .mmaploop2 mov [ebx],eax mov [edx],eax add eax,10000h add ebx,4 add edx,4 loop .mmaploop2 pop eax pop edx pop ecx ret %endmacro NEWSYM LastLog pushad cmp byte[CurValUsed],0 je near .novalue xor ebx,ebx mov edx,DecompArray mov eax,[CurPtrVal] cmp dword[DecompAPtr],0 je .noptr .loop mov ecx,[edx] cmp ecx,eax je .match add edx,8 inc ebx cmp ebx,[DecompAPtr] jne .loop .noptr cmp dword[DecompAPtr],8192 je .novalue mov [edx],eax xor eax,eax mov ax,[CurDecompSize] mov [edx+4],ax mov ax,[CurPtrLen] mov [edx+6],ax mov al,[CurPtrLen+2] mov [edx+3],al inc dword[DecompAPtr] jmp .novalue .match add edx,4 mov bx,[CurDecompSize] xor ebx,ebx cmp [edx],bx jae .novalue mov [edx],bx .novalue mov [lastentry],edx mov byte[CurValUsed],1 mov eax,[SPCCompPtr] and eax,0FFFFFFh mov [CurPtrVal],eax popad ret SPC4800: ; mov byte[debstop3],1 ; cmp word[SPCCompCounter],0FFFFh ; jne .notzero ; xor al,al ; ret ;.notzero cmp byte[SPCCompCommand],0 je .manual xor al,al dec word[SPCCompCounter] push ebx xor ebx,ebx ; mov ebx,[SPCCompPtr] ; and ebx,0FFFFFFh ; add ebx,[romdata] ; add ebx,100000h mov bx,[SPCDecmPtr] add ebx,[romdata] add ebx,510000h mov al,[ebx] pop ebx ; xor al,al inc dword[SPCCompPtr] push eax inc word[SPCDecmPtr] mov ax,[SPCDecmPtr] mov [CurDecompPtr],ax sub ax,[PrevDecompPtr] mov [CurDecompSize],ax pop eax ; cmp word[SPCCompCounter],0FFFFh ; jne .exit ; mov byte[SPCDecompFin],80h ;.exit ret .manual xor al,al push ebx xor ebx,ebx mov bx,[SPCDecmPtr] add ebx,[romdata] add ebx,510000h mov al,[ebx] pop ebx dec word[SPCCompCounter] inc dword[SPCCompPtr] inc word[SPCDecmPtr] inc word[CurDecompSize] ; cmp word[SPCCompCounter],0FFFFh ; jne .exit2 ; mov byte[SPCDecompFin],80h ;.exit2 ret SPC4801: mov al,[SPCCompPtr] ret SPC4802: mov al,[SPCCompPtr+1] ret SPC4803: mov al,[SPCCompPtr+2] ret SPC4804: mov al,[SPCCompPtr+3] ret SPC4805: mov al,[SPCDecmPtr] ret SPC4806: mov al,[SPCDecmPtr+1] ret SPC4807: xor al,al ret SPC4808: xor al,al ret SPC4809: mov al,[SPCCompCounter] ret SPC480A: mov al,[SPCCompCounter+1] ret SPC480B: mov al,[SPCCompCommand] mov dword[SPCDecmPtr],0 ret SPC480C: ; decompression finished status mov al,[SPCDecompFin] mov byte[SPCDecompFin],0 ret NEWSYM CurPtrVal, dd 0 NEWSYM CurCompCounter2, dd 0 NEWSYM CurPtrLen, dd 0 NEWSYM CurValUsed, db 0 NEWSYM PrevDecompPtr, dw 0 NEWSYM CurDecompPtr, dw 0 NEWSYM CurDecompSize, dw 0 NEWSYM DecompArray, times 65536 db 0 NEWSYM DecompAPtr, dd 0 lastentry dd 0 NEWSYM UpdateRTC test byte[SPC7110RTC+0Dh],02h jnz .notimer .notimer ret SPC4801w: mov [SPCCompPtr],al ret SPC4802w: mov [SPCCompPtr+1],al ret SPC4803w: mov [SPCCompPtr+2],al ret SPC4804w: mov [SPCCompPtr+3],al ret SPC4805w: mov [SPCDecmPtr],al ret SPC4806w: mov [SPCDecmPtr+1],al cmp dword[SPCCompPtr],0124AD48h jne .nodata mov byte[debstop3],1 .nodata pushad cmp byte[CurValUsed],0 je near .novalue xor ebx,ebx mov edx,DecompArray mov eax,[CurPtrVal] ; and eax,0FFFFFFh cmp dword[DecompAPtr],0 je .noptr .loop mov ecx,[edx] ; and ecx,0FFFFFFh cmp ecx,eax je .match add edx,8 inc ebx cmp ebx,[DecompAPtr] jne .loop .noptr cmp dword[DecompAPtr],8192 je .novalue mov [edx],eax xor eax,eax mov ax,[CurDecompSize] mov [edx+4],ax mov ax,[CurPtrLen] mov [edx+6],ax mov al,[CurPtrLen+2] mov [edx+3],al inc dword[DecompAPtr] jmp .novalue .match add edx,4 xor ebx,ebx mov bx,[CurDecompSize] cmp [edx],bx jae .novalue mov [edx],bx .novalue mov [lastentry],edx mov byte[CurValUsed],1 mov eax,[SPCCompPtr] and eax,0FFFFFFh mov [CurPtrVal],eax popad mov word[CurDecompSize],0 push eax mov al,[SPCCompPtr+3] mov [CurPtrLen+2],al mov ax,[SPCDecmPtr] ;CurCompCounter2] mov [CurPtrLen],ax mov eax,[SPCCompPtr] mov [CurPtrVal],eax mov ax,[SPCDecmPtr] mov [PrevDecompPtr],ax mov [CurDecompPtr],ax mov word[CurDecompSize],0 pop eax mov byte[SPCDecompFin],0h ; Start Decompression pushad mov eax,[SPCCompPtr] cmp [SPCPrevCompPtr],eax je near .previousequal mov [SPCPrevCompPtr],eax mov ecx,[SPC7110Entries] mov ebx,[SPCCompPtr] and ebx,0FFFFFFh mov eax,[spc7110romptr] or ecx,ecx jz .noentries .loopc mov edx,[eax] cmp dl,[SPCCompPtr+3] jne .notfound shr edx,8 cmp ebx,edx je .found .notfound add eax,12 loop .loopc jmp .noentries .found xor word[CurPtrLen],0FFFFh mov ecx,[eax+8] mov ebx,[eax+4] xor edx,edx mov dx,[SPCDecmPtr] add edx,[romdata] add edx,510000h push eax .loopb mov al,[ebx] mov [edx],al inc ebx inc edx loop .loopb pop eax mov ebx,[eax+4] mov edx,[lastentry] ; mov [edx+4],ebx mov ebx,[eax] ; mov [edx],ebx jmp .foundentry .noentries mov ecx,[SPC7110IndexSize] ; Address/index, pointer, length, SPC7110nfname mov edx,[romdata] add edx,580000h .sploop mov eax,[SPCCompPtr] shl eax,8 mov al,[SPCCompPtr+3] cmp [edx],eax je .foundsp add edx,12 sub ecx,12 jc .overflow jnz .sploop .overflow jmp .notfoundentry .foundsp mov eax,[edx+4] mov [SPC7110TempPosition],eax mov eax,[edx+8] mov [SPC7110TempLength],eax mov edx,SPC7110nfname add edx,9 mov eax,[SPCCompPtr] and eax,0FFFFFFh mov ecx,6 .sploop2 mov ebx,eax shr ebx,20 and ebx,0Fh cmp bl,9 jbe .below9 add bl,55-48 .below9 add bl,48 mov [edx],bl inc edx shl eax,4 loop .sploop2 mov edx,SPC7110nfname call Open_File jc .error mov bx,ax mov dx,[SPC7110TempPosition] mov cx,[SPC7110TempPosition+2] call File_Seek xor edx,edx mov dx,[SPCDecmPtr] add edx,[romdata] add edx,510000h mov ecx,[SPC7110TempLength] call Read_File call Close_File jmp .foundentry .error ; mov dword[Msgptr],SPC7110nfname ; mov dword[MessageOn],60*6 .notfoundentry .foundentry .previousequal popad .fin .blah ; Finished ; mov word[SPCCompCounter],0FFFFh mov byte[SPCDecompFin],80h ret SPC4807w: ret SPC4808w: ret SPC4809w: mov [SPCCompCounter],al mov [CurCompCounter2],al ret SPC480Aw: mov [SPCCompCounter+1],al mov [CurCompCounter2+1],al ret SPC480Bw: mov [SPCCompCommand],al ret ;NEWSYM SPCROMPtr, dd 0 ;NEWSYM SPCROMAdj, dd 0 ;NEWSYM SPCROMInc, dd 0 ;NEWSYM SPCROMCom, dd 0 ; 01, ;$4810 DATA ROM CONTINUOUS READ PORT: returns a byte from data rom at data ; rom pointer location, defval:00 ;$4811 DATA ROM POINTER: ($0000FF) r/w low offset, defval:00 ;$4812 DATA ROM POINTER: ($00FF00) r/w high offset, defval:00 ;$4813 DATA ROM POINTER: ($FF0000) r/w bank offset, defval:00 ; bank offset is zero based from start of data rom: banks $00-$3f ; data rom -> $10-$4f full rom ;$4814 DATA ROM POINTER ADJUST: ($00FF) low byte, defval:00 ;$4815 DATA ROM POINTER ADJUST: ($FF00) high byte, defval:00 ;$4816 DATA ROM POINTER INCREMENT: ($00FF) low byte, defval:00 ;$4817 DATA ROM POINTER INCREMENT: ($FF00) high byte, defval:00 ;$4818 DATA ROM COMMAND MODE: bit field control of data rom pointer (see ; data rom command mode byte), defval:00 ; write: set command mode, ; read: performs action instead of returning value, unknown purpose, ; command mode is loaded to $4818 but only set after writing to both ; $4814 and $4815 in any order ;$481A DATA ROM READ AFTER ADJUST PORT: returns a byte from data rom at ; data rom pointer location + adjust value ($4814/5), defval:00 SPC4810: cmp dword[SPCCheckFix],0 jne .okay xor al,al ret .okay push ebx push ecx mov ebx,[SPCROMPtr] add ebx,[romdata] add ebx,100000h mov al,[ebx] cmp byte[SPCROMCom+1],0 jne .noincr1 mov ebx,[SPCROMtoI] inc dword[ebx] .noincr1 cmp byte[SPCROMCom+1],1 ; add 4816 after 4810 read jne .noincr1b mov ebx,[SPCROMtoI] mov ecx,[SPCROMInc] add dword[ebx],ecx .noincr1b pop ecx pop ebx ret SPC4811: mov al,[SPCROMPtr] ret SPC4812: mov al,[SPCROMPtr+1] ret SPC4813: mov al,[SPCROMPtr+2] ret SPC4814: mov al,[SPCROMAdj] ret SPC4815: mov al,[SPCROMAdj+1] ret SPC4816: mov al,[SPCROMInc] ret SPC4817: mov al,[SPCROMInc+1] ret SPC4818: mov al,[SPCROMCom] ret SPC481A: cmp dword[SPCCheckFix],0 jne .okay xor al,al ret .okay push ebx push ecx xor ebx,ebx xor ecx,ecx mov bx,[SPCROMAdj] add ebx,[SPCROMPtr] add ebx,[romdata] add ebx,100000h mov al,[ebx] cmp byte[SPCROMCom+1],4 ; 16bit 4814 jne .notincr mov ecx,[SPCROMtoI] mov ebx,[SPCROMAdj] add [ecx],ebx .notincr pop ecx pop ebx ret SPC4811w: mov [SPCROMPtr],al mov byte[SPCCheckFix],1 ret SPC4812w: mov [SPCROMPtr+1],al ret SPC4813w: mov [SPCROMPtr+2],al ret SPC4814w: mov [SPCROMAdj],al cmp byte[SPCROMCom+1],2 ; 8 bit 4814 jne .notincr mov ebx,[SPCROMtoI] xor ecx,ecx mov cl,[SPCROMAdj] test byte[SPCROMCom],08h jz .noneg movsx ecx,byte[SPCROMAdj] .noneg add dword[ebx],ecx .notincr ret SPC4815w: mov [SPCROMAdj+1],al mov word[SPCROMAdj+2],0 test byte[SPCROMCom],08h jz .noneg test byte[SPCROMAdj+1],80h jz .noneg mov word[SPCROMAdj+2],0FFFFh .noneg cmp byte[SPCROMCom+1],3 ; 16bit 4814 jne .notincr push ebx push ecx mov ecx,[SPCROMtoI] mov ebx,[SPCROMAdj] add [ecx],ebx pop ecx pop ebx .notincr ret SPC4816w: mov [SPCROMInc],al ret SPC4817w: mov [SPCROMInc+1],al mov word[SPCROMInc+2],0 test byte[SPCROMCom],04h jz .noneg test byte[SPCROMInc+1],40h jz .noneg mov word[SPCROMInc+2],0FFFFh .noneg ret SPC4818w: mov [SPCROMCom],al mov word[SPCROMAdj+2],0 test byte[SPCROMCom],08h jz .noneg test byte[SPCROMAdj+1],80h jz .noneg mov word[SPCROMAdj+2],0FFFFh .noneg mov word[SPCROMInc+2],0 test byte[SPCROMCom],04h jz .noneg2 test byte[SPCROMInc+1],40h jz .noneg2 mov word[SPCROMInc+2],0FFFFh .noneg2 mov dword[SPCROMtoI],SPCROMPtr test byte[SPCROMCom],10h jz .nouseadjust mov dword[SPCROMtoI],SPCROMAdj .nouseadjust test al,02h jz .no4814 test al,40h jz .no16b test al,20h jz .not481A mov byte[SPCROMCom+1],4 ; 16bit 4814 after 481A jmp .fin .not481A mov byte[SPCROMCom+1],3 ; 16bit 4814 jmp .fin .no16b test al,20h jz .nooffsetadd mov byte[SPCROMCom+1],2 ; 8 bit 4814 jmp .fin .nooffsetadd mov byte[SPCROMCom+1],0FFh jmp .fin .no4814 test al,01h jz .incrval0 mov byte[SPCROMCom+1],1 ; add 4816 after 4810 read jmp .fin .incrval0 mov byte[SPCROMCom+1],0 ; add 1 after 4810 read .fin ret ;Data Rom Command Mode Byte: ;X6543210 ;|||||||| ;|||||| \__ : 00 - use 1 as the offset increment value, add immediately after reading $4810 ;|||||| : 01 - use $4816 as offset increment, add immediately after reading $4810 ;|||||| : 10 - use $4814 as offset increment, see below for when to add ;|||||| : 11 - unused ;||||||____ : 0 - unsigned calculation for $4816 ;||||| 1 - signed calculation for $4816 ;|||||_____ : 0 - unsigned calculation for $4814 ;|||| 1 - signed calculation for $4814 ;||||______ : 0 - offset increment gets added to $4811/2/3 ;||| 1 - offset increment gets added to $4814/5 ;| \_______ : 00 - disable offset addition ;| : 01 - 8 bit offset addition using $4814, immediately after writing to $4814/5 ;| : 10 - 16 bit offset addition using $4814/5, immediately after writing to $4814/5 ;| : 11 - 16 bit offset addition using $4814/5, only after reading $481A ;|_________ : unused SPC4820: mov al,[SPCMultA] ; mov byte[debstop3],1 ret SPC4821: mov al,[SPCMultA+1] ret SPC4822: mov al,[SPCMultA+2] ret SPC4823: mov al,[SPCMultA+3] ret SPC4824: mov al,[SPCMultB] ret SPC4825: mov al,[SPCMultB+1] ret SPC4826: mov al,[SPCDivEnd] ret SPC4827: mov al,[SPCDivEnd+1] ret SPC4820w: mov [SPCMultA],al ret SPC4821w: mov [SPCMultA+1],al ret SPC4822w: mov [SPCMultA+2],al ret SPC4823w: mov [SPCMultA+3],al ret SPC4824w: mov [SPCMultB],al ret SPC4825w: mov [SPCMultB+1],al ; Calculate SPCMultA*SPCMultB -> SPCMulRes test byte[SPCSignedVal],1 jnz .signed push edx push eax push ebx xor eax,eax xor ebx,ebx mov ax,[SPCMultA] mov bx,[SPCMultB] mul ebx mov [SPCMulRes],eax pop ebx pop eax pop edx ret .signed push edx push eax push ebx movsx eax,word[SPCMultA] movsx ebx,word[SPCMultB] imul ebx mov [SPCMulRes],eax pop ebx pop eax pop edx ret SPC4826w: mov [SPCDivEnd],al ret SPC4827w: mov [SPCDivEnd+1],al ; Calculte SPCMultA/SPCDivEnd -> SPCMulRes, rem SPCDivRes cmp word[SPCDivEnd],0 je near .nodivide test byte[SPCSignedVal],1 jnz .signed push edx push eax push ebx xor edx,edx xor ebx,ebx mov eax,[SPCMultA] mov bx,[SPCDivEnd] div ebx mov [SPCMulRes],eax mov [SPCDivRes],dx pop ebx pop eax pop edx ret .signed push edx push eax push ebx xor edx,edx mov eax,[SPCMultA] test eax,80000000h jz .nd mov edx,0FFFFFFFFh .nd movsx ebx,word[SPCDivEnd] idiv ebx mov [SPCMulRes],eax mov [SPCDivRes],dx pop ebx pop eax pop edx ret .nodivide mov dword[SPCMulRes],0FFFFFFFFh mov dword[SPCDivRes],0FFFFh ret SPC4828: mov al,[SPCMulRes] ret SPC4829: mov al,[SPCMulRes+1] ret SPC482A: mov al,[SPCMulRes+2] ret SPC482B: mov al,[SPCMulRes+3] ret SPC482C: mov al,[SPCDivRes] ret SPC482D: mov al,[SPCDivRes+1] ret SPC482E: xor al,al ret SPC482Ew: mov byte[SPCSignedVal],al mov dword[SPCMultA],0 mov dword[SPCMultB],0 mov dword[SPCDivEnd],0 mov dword[SPCMulRes],0 mov dword[SPCDivRes],0 ret SPC482F: xor al,al ret SPC4831w: BankSwitchSPC7110 0,0D0h ret SPC4832w: BankSwitchSPC7110 1,0E0h ret SPC4833w: ; mov byte[debstop3],1 BankSwitchSPC7110 2,0F0h ret SPC4831: mov al,[SPC7110BankA] ret SPC4832: mov al,[SPC7110BankA+1] ret SPC4833: mov al,[SPC7110BankA+2] ret SPC4834: xor al,al ret ;NEWSYM SPC7110RTCStat, dd 0 ;NEWSYM SPC7110RTC, db 00,00,00,00,00,00,01,00,01,00,00,00,00,01,0F,06 ;$4840 RTC CHIP ENABLE/DISABLE: bit 0: on = enable, off = disable, defval:00 ;$4841 RTC INDEX/DATA PORT: ; first write after rtc enable: rtc command mode byte (see rtc command modes) ; subsequent writes: index of rtc register to read/write (00-0f) ; read: returns value of indexed rtc register ; auto-increment of register index occurs after each subsequent read/write ;$4842 RTC READY STATUS: bit 7: on = ready, off = still processing, tested before reading rtc data ; high bit cleared after successful read SPC4840w: test al,1 jz .notreset mov byte[SPC7110RTCStat],al mov byte[SPC7110RTCStat+1],0FEh .notreset ret SPC4841w: cmp byte[SPC7110RTCStat+1],0FEh je .commandbyte cmp byte[SPC7110RTCStat+1],0FFh je .commandindex push ebx xor ebx,ebx mov bl,[SPC7110RTCStat+1] mov [SPC7110RTC+ebx],al cmp ebx,0Fh jne .notlast test al,01h jz .notlast mov dword[SPC7110RTC],0 mov dword[SPC7110RTC+4],010000h mov dword[SPC7110RTC+8],01h mov byte[SPC7110RTC+12],0 .notlast pop ebx inc byte[SPC7110RTCStat+1] and byte[SPC7110RTCStat+1],0Fh ret .commandbyte inc byte[SPC7110RTCStat+1] mov byte[SPC7110RTCStat+2],al ret .commandindex push eax and al,0Fh mov byte[SPC7110RTCStat+1],al pop eax ret SPC4842w: ret SPC4840: mov al,[SPC7110RTCStat] ret SPC4841: cmp byte[SPC7110RTCStat+1],0FEh je near .commandbyte cmp byte[SPC7110RTCStat+1],0FFh je near .commandbyte push ebx xor ebx,ebx mov bl,[SPC7110RTCStat+1] or ebx,ebx jnz near .dontupdate test byte[SPC7110RTC+0Fh],03h jnz near .dontupdate test byte[SPC7110RTC+0Dh],01h jnz near .dontupdate ;00 - seconds 1's digit 00 ;01 - seconds 10's digit 00 ;02 - minutes 1's digit 00 ;03 - minutes 10's digit 00 ;04 - hours 1's digit 00 ;05 - hours 10's digit 00 ;06 - day of month 1's digit 01 ;07 - day of month 10's digit 00 ;08 - month 1's digit 01 ;09 - month 10's digit 00 ;0a - year 1's digit 00 ;0b - year 10's digit 00 ;0c - day of week 00 cmp byte[debuggeron],1 je near .dontupdate ; fill time/date push ebx push eax call Get_Time mov bl,al and bl,0Fh mov [SPC7110RTC],bl ; seconds shr eax,4 mov bl,al and bl,0Fh mov [SPC7110RTC+1],bl shr eax,4 mov bl,al and bl,0Fh mov [SPC7110RTC+2],bl ; minutes shr eax,4 mov bl,al and bl,0Fh mov [SPC7110RTC+3],bl test byte[SPC7110RTC+0Fh],4 ; jz .not24hrs ; jmp .not24hrs shr eax,4 mov bl,al and bl,0Fh mov [SPC7110RTC+4],bl ; hours shr eax,4 mov bl,al and bl,0Fh mov [SPC7110RTC+5],bl jmp .24hrs .not24hrs shr eax,4 xor ebx,ebx mov bl,al mov al,[SPCTimerVal+ebx] mov bl,al and bl,0Fh mov [SPC7110RTC+4],bl ; hours shr eax,4 mov bl,al and bl,0Fh mov [SPC7110RTC+5],bl .24hrs call Get_TimeDate mov bl,al and bl,0Fh mov [SPC7110RTC+6],bl ; day shr eax,4 mov bl,al and bl,0Fh mov [SPC7110RTC+7],bl shr eax,4 mov bl,al and bl,0Fh xor bh,bh cmp bl,9 jbe .less sub bl,10 mov bh,1 .less mov [SPC7110RTC+8],bl ; month mov [SPC7110RTC+9],bh ; month shr eax,8 mov bl,al and bl,0Fh mov [SPC7110RTC+10],bl ; year shr eax,4 mov bl,al and bl,01Fh xor bh,bh .notokay cmp bl,9 jbe .okay inc bh sub bl,10 jmp .notokay .okay mov [SPC7110RTC+11],bl shr eax,8 and al,0Fh mov [SPC7110RTC+12],al ; day of week .done pop eax pop ebx .dontupdate ; test byte[SPC7110RTC+0Fh],1 ; jz .realtime ; cmp ebx,0Dh ; jae .realtime ; mov al,[SPC7110RTCB+ebx] ; jmp .next ;.realtime mov al,[SPC7110RTC+ebx] ;.next pop ebx inc byte[SPC7110RTCStat+1] and byte[SPC7110RTCStat+1],0Fh ret .commandbyte inc byte[SPC7110RTCStat+1] mov al,byte[SPC7110RTCStat+2] ret SPCTimerVal db 12h,01h,02h,03h,04h,05h,06h,07h,08h,09h,0,0,0,0,0,0 db 10h,11h,32h,21h,22h,23h,24h,25h,26h,27h,0,0,0,0,0,0 db 28h,29h SPC4842: mov al,80h ret ;$4820 16 BIT MULTIPLICAND: ($00FF) low byte, defval:00 ; 32 BIT DIVI: ($000000FF) low byte of low word, defval:00 ;$4821 16 BIT MULTIPLICAND: ($FF00) high byte, defval:00 ; 32 BIT DIVI: ($0000FF00) high byte of low word, defval:00 ;$4822 32 BIT DIVI: ($00FF0000) low byte of high word, defval:00 ;$4823 32 BIT DIVI: ($FF000000) high byte of high word, defval:00 ;$4824 16 BIT MULTIPLIER: ($00FF) low byte, defval:00 ;$4825 16 BIT MULTIPLIER: ($FF00) high byte, defval:00 ;$4826 16 BIT DIVISOR: ($00FF), defval:00 ;$4827 16 BIT DIVISOR: ($FF00), defval:00 ;$4828 32 BIT PRODUCT: ($000000FF) low byte of low word, defval:00 ; 32 BIT QUOTIENT:($000000FF) low byte of low word, defval:00 ;$4829 32 BIT PRODUCT: ($0000FF00) high byte of low word, defval:00 ; 32 BIT QUOTIENT:($0000FF00) high byte of low word, defval:00 ;$482A 32 BIT PRODUCT: ($00FF0000) low byte of high word, defval:00 ; 32 BIT QUOTIENT:($00FF0000) low byte of high word, defval:00 ;$482B 32 BIT PRODUCT: ($FF000000) high byte of high word, defval:00 ; 32 BIT QUOTIENT:($FF000000) high byte of high word, defval:00 ;$482C 16 BIT REMAINDER: ($00FF) low byte, defval:00 ;$482D 16 BIT REMAINDER: ($FF00) high byte, defval:00 ;$482E MUL/DIV RESET, write = reset $4820 to $482D, defval:00 ;$482F MUL/DIV FINISHED STATUS: bit 7: on = processing, off = finished, ; high bit is set after a write to multiplier or divisor regs $4825/$4827, defval:00 ALIGN32 ; IRQ Stuff NEWSYM SA1Mode, dd 0 ; 0 = SNES CPU, 1 = SA1 CPU NEWSYM SA1Control, dd 0 ; don't execute if b5 or 6 are set NEWSYM SA1BankPtr, dd 0 NEWSYM SA1ResetV, dd 0 NEWSYM SA1NMIV, dd 0 NEWSYM SA1IRQV, dd 0 NEWSYM SA1RV, dd 0 NEWSYM CurBWPtr, dd 0 NEWSYM SA1TempVar, dd 0 NEWSYM SA1IRQEn, dd 0 NEWSYM SA1Message, dd 0 NEWSYM SA1IRQExec, dd 0 NEWSYM SA1IRQEnable, dd 0 NEWSYM SA1DoIRQ, dd 0 ; Arithmetic Stuff NEWSYM SA1ARC, dd 0 NEWSYM SA1AR1, dd 0 NEWSYM SA1AR2, dd 0 NEWSYM SA1ARR1, dd 0 NEWSYM SA1ARR2,dd 0 NEWSYM SA1Stat, dd 0 NEWSYM SNSNMIV, dd 0 NEWSYM SNSIRQV, dd 0 NEWSYM SA1DMACount, dd 0 NEWSYM SA1DMAInfo, dd 0 NEWSYM SA1DMAChar, dd 0 NEWSYM SA1DMASource, dd 0 NEWSYM SA1DMADest, dd 0 NEWSYM SA1IRQTemp, dd 0 NEWSYM SA1BankSw, dd 1 NEWSYM SA1BankVal, db 0,1,2,3 SA1Reserved times 472 db 0 ; SA1 Swap Stuff NEWSYM SA1xa, dd 0 NEWSYM SA1xx, dd 0 NEWSYM SA1xy, dd 0 NEWSYM SA1xd, dd 0 NEWSYM SA1xdb, dd 0 NEWSYM SA1xpb, dd 0 NEWSYM SA1xs, dd 0 NEWSYM SA1RegP, dd 0 NEWSYM SA1RegE, dd 0 NEWSYM SA1RegPCS,dd 0 NEWSYM SA1BWPtr,dd 0 NEWSYM SA1Ptr, dd 0 ; Current PC, SA-1 NEWSYM SA1Overflow, dd 0 NEWSYM VarLenAddr, dd 0 NEWSYM VarLenAddrB, dd 0 NEWSYM VarLenBarrel, dd 0 NEWSYM SA1TimerVal, dd 0 NEWSYM SA1TimerSet, dd 0 NEWSYM SA1TimerCount, dd 0 NEWSYM SA1IRQData, dd 0 ; SNES Swap Stuff NEWSYM SNSRegP, dd 0 NEWSYM SNSRegE, dd 0 NEWSYM SNSRegPCS,dd 0 NEWSYM SNSBWPtr,dd 0 NEWSYM SNSPtr, dd 0 ; Current PC, SNES NEWSYM IRAM, times 2049 db 0 ;2 kbytes of iram num2writesa1reg equ $-SA1Mode NEWSYM PHnum2writesa1reg, dd num2writesa1reg NEWSYM SA1RAMArea, dd 0 NEWSYM SA1Temp, dd 0 NEWSYM Sdd1Mode, dd 0 NEWSYM Sdd1Bank, dd 0 NEWSYM Sdd1Addr, dd 0 NEWSYM Sdd1NewAddr, dd 0 %macro SA1QuickF 2 NEWSYM %1 mov [%2],al ret %endmacro NEWSYM RestoreSA1 mov eax,[romdata] add [SA1RegPCS],eax add [CurBWPtr],eax add [SA1BWPtr],eax add [SNSBWPtr],eax cmp byte[SA1Stat],1 jne .notsa1stat mov dword[SA1RegPCS],IRAM .notsa1stat cmp byte[SA1Stat],2 jne .notsa1stat2 mov dword[SA1RegPCS],IRAM-3000h .notsa1stat2 mov eax,[SA1RegPCS] add [SA1Ptr],eax mov eax,[romdata] add eax,4096*1024 mov [SA1RAMArea],eax pushad call UpdateBanks popad ret NEWSYM SaveSA1 mov byte[SA1Stat],0 mov eax,[SA1RegPCS] sub [SA1Ptr],eax cmp dword[SA1RegPCS],IRAM jne .notiram mov byte[SA1Stat],1 .notiram cmp dword[SA1RegPCS],IRAM-3000h jne .notiram2 mov byte[SA1Stat],2 .notiram2 mov eax,[romdata] sub [SA1RegPCS],eax sub [CurBWPtr],eax sub [SA1BWPtr],eax sub [SNSBWPtr],eax ret NEWSYM SA1Reset mov byte[SA1IRQData+1],0 mov byte[SA1Mode],0 mov byte[SA1Status],0 mov byte[SA1Control],20h mov dword[SA1DoIRQ],0 mov ax,[irqv2] mov [irqv],ax mov ax,[nmiv2] mov [nmiv],ax mov eax,[romdata] sub eax,8000h mov [SA1RegPCS],eax mov eax,[romdata] add eax,4096*1024 mov [SA1RAMArea],eax mov eax,[romdata] add eax,4096*1024-6000h mov dword[CurBWPtr],eax mov dword[SA1BWPtr],eax mov dword[SNSBWPtr],eax mov dword[SA1xa],0 mov dword[SA1xx],0 mov dword[SA1xy],0 mov dword[SA1xd],0 mov dword[SA1xdb],0 mov dword[SA1xpb],0 mov dword[SA1xs],1FFh mov dword[SA1RegP],0 mov dword[SA1RegE],0 mov dword[SA1IRQExec],0 mov dword[SA1IRQEnable],0 mov dword[SA1Message],0 mov byte[SA1Overflow],0 ret NEWSYM UpdateBanks cmp byte[SA1BankSw],1 jne .noswap mov al,[SA1BankVal] call sa12220w mov al,[SA1BankVal+1] call sa12221w mov al,[SA1BankVal+2] call sa12222w mov al,[SA1BankVal+3] call sa12223w .noswap ret NEWSYM UpdateBanksSDD1 pushad cmp dword[SDD1BankA],0 je .nobank mov al,[SDD1BankA] call sdd14804w mov al,[SDD1BankA+1] call sdd14805w mov al,[SDD1BankA+2] call sdd14806w mov al,[SDD1BankA+3] call sdd14807w .nobank popad ret %macro BankSwitch 4 push ecx push edx push eax mov [SA1BankVal+%1],al mov ebx,snesmmap+%2*4 test al,80h jz .noupper and eax,07h shl eax,20 push eax jmp .yesupper .noupper and eax,07h shl eax,20 push eax mov eax,%4 .yesupper mov ecx,20h add eax,[romdata] sub eax,8000h .mmaploop mov [ebx],eax add eax,8000h add ebx,4 loop .mmaploop pop eax add eax,[romdata] mov ecx,10h mov ebx,snesmap2+%3*4 mov edx,snesmmap+%3*4 .mmaploop2 mov [ebx],eax mov [edx],eax add eax,10000h add ebx,4 add edx,4 loop .mmaploop2 pop eax pop edx pop ecx ret %endmacro NEWSYM sa12220w BankSwitch 0,0,0C0h,0 NEWSYM sa12221w BankSwitch 1,20h,0D0h,100000h NEWSYM sa12222w BankSwitch 2,80h,0E0h,200000h NEWSYM sa12223w BankSwitch 3,0A0h,0F0h,300000h %macro BankSwitchSDD1 2 push ecx push edx push eax mov [SDD1BankA+%1],al and eax,07h shl eax,20 add eax,[romdata] mov ecx,10h mov ebx,snesmap2+%2*4 mov edx,snesmmap+%2*4 .mmaploop2 mov [ebx],eax mov [edx],eax add eax,10000h add ebx,4 add edx,4 loop .mmaploop2 pop eax pop edx pop ecx ret %endmacro sdd14804: mov al,[SDD1BankA] ret sdd14805: mov al,[SDD1BankA+1] ret sdd14806: mov al,[SDD1BankA+2] ret sdd14807: mov al,[SDD1BankA+3] ret NEWSYM sdd14804w BankSwitchSDD1 0,0C0h NEWSYM sdd14805w BankSwitchSDD1 1,0D0h NEWSYM sdd14806w BankSwitchSDD1 2,0E0h NEWSYM sdd14807w BankSwitchSDD1 3,0F0h NEWSYM sa12200w mov bl,al and bl,0Fh mov byte[SA1Message],bl test al,80h jz .noirq or byte[SA1DoIRQ],1 .noirq test al,10h jz .nonmi or byte[SA1DoIRQ],2 .nonmi test byte[SA1Control],20h jz .noreset test al,20h jnz .noreset mov [SA1Control],al mov ebx,[romdata] mov [SA1BankPtr],ebx xor ebx,ebx mov bx,[SA1ResetV] add ebx,[romdata] sub ebx,8000h mov [SA1Ptr],ebx mov byte[SA1xpb],0 mov word[SA1xs],1FFh mov ebx,[romdata] sub ebx,8000h mov [SA1RegPCS],ebx xor ebx,ebx ret .noreset mov [SA1Control],al ret NEWSYM sa12201w ; IRQ Enable mov byte[SA1IRQEnable],al ret NEWSYM sa12202w ; IRQ Clear test al,80h jz .noirqclear and byte[SA1IRQExec],0FEh and byte[SA1DoIRQ],0FBh .noirqclear test al,20h jz .nocdmairqclear and byte[SA1IRQExec],0FDh and byte[SA1DoIRQ],0F7h .nocdmairqclear ret SA1QuickF sa12203w, SA1ResetV SA1QuickF sa12204w, SA1ResetV+1 SA1QuickF sa12205w, SA1NMIV SA1QuickF sa12206w, SA1NMIV+1 SA1QuickF sa12207w, SA1IRQV SA1QuickF sa12208w, SA1IRQV+1 NEWSYM sa12209w ; IRQ Stuff mov [SA1IRQData+1],al test al,80h jz .noirq ; execute IRQ on the SNES or byte[SA1DoIRQ],4 .noirq mov bl,al and bl,0Fh mov byte[SA1Message+1],bl mov bx,[irqv2] test al,40h jz .noirqchange mov bx,[SNSIRQV] .noirqchange mov [irqv],bx mov bx,[nmiv2] test al,10h jz .nonmichange mov bx,[SNSNMIV] .nonmichange mov [nmiv],bx ret SA1QuickF sa1220Aw, SA1IRQEn NEWSYM sa1220Bw ; SA-1 IRQ Clear test al,80h jz .noirqclear mov byte[SA1IRQExec+1],0 and byte[SA1DoIRQ],0FEh .noirqclear test al,20h jz .nocdmairqclear .nocdmairqclear test al,10h jz .nonmiclear mov byte[SA1IRQExec+2],0 and byte[SA1DoIRQ],0FDh .nonmiclear ret SA1QuickF sa1220Cw, SNSNMIV SA1QuickF sa1220Dw, SNSNMIV+1 SA1QuickF sa1220Ew, SNSIRQV SA1QuickF sa1220Fw, SNSIRQV+1 NEWSYM sa12224w ; BWRAM mov bl,al and ebx,1Fh shl ebx,13 add ebx,[romdata] add ebx,1024*4096-6000h mov dword[SNSBWPtr],ebx cmp byte[SA1Status],0 jne .nosnes mov dword[CurBWPtr],ebx .nosnes ret NEWSYM sa12225w ; BWRAM mov bl,al and ebx,1Fh shl ebx,13 add ebx,[romdata] add ebx,1024*4096-6000h mov dword[SA1BWPtr],ebx cmp byte[SA1Status],0 je .nosa1 mov dword[CurBWPtr],ebx .nosa1 ret NEWSYM sa12250w mov byte[SA1ARC],al mov byte[SA1ARC+1],1 test al,2 jz .notcumul mov word[SA1ARR1],0 mov word[SA1ARR1+2],0 mov word[SA1ARR1+4],0 .notcumul ret NEWSYM sa12251w mov byte[SA1AR1],al mov byte[SA1ARC+1],1 ret NEWSYM sa12252w mov byte[SA1AR1+1],al mov byte[SA1ARC+1],1 ret NEWSYM sa12253w mov byte[SA1AR2],al mov byte[SA1ARC+1],1 ret NEWSYM sa12254w mov byte[SA1AR2+1],al mov byte[SA1ARC+1],1 test byte[SA1ARC],2 jnz .cumul call UpdateArithStuff ret ; set overflow bit if exceeds 40bits .cumul pushad xor edx,edx mov ax,[SA1AR1] mov bx,[SA1AR2] imul bx shl edx,16 mov dx,ax mov byte[SA1Overflow],0 add [SA1ARR1],edx adc byte[SA1ARR2],0 jnc .notoverflow mov byte[SA1Overflow],80h .notoverflow popad ret UpdateArithStuff: cmp byte[SA1ARC+1],1 jne .noarith pushad mov byte[SA1ARC+1],0 test byte[SA1ARC],3 jz .multiply test byte[SA1ARC],2 jnz near .cumulativesum test byte[SA1ARC],1 jnz .division .multiply xor edx,edx mov ax,[SA1AR1] mov bx,[SA1AR2] imul bx mov [SA1ARR1],ax mov [SA1ARR1+2],dx popad .noarith ret .division movsx eax,word[SA1AR1] xor edx,edx test eax,80000000h jz .notneg mov edx,0FFFFFFFFh .notneg xor ebx,ebx mov bx,[SA1AR2] or ebx,ebx jz .invalid idiv ebx mov [SA1ARR1],ax mov [SA1ARR1+2],dx ; mov word[SA1AR1],0 ; mov word[SA1AR2],0 popad ret .invalid mov word[SA1ARR1],0 mov word[SA1ARR1+2],0 popad ret .cumulativesum popad ret sa12300r: mov al,[SA1Message+1] test byte[SA1IRQExec],1 jz .notexecuted or al,80h .notexecuted test byte[SA1IRQExec],2 jz .notexecutedi or al,20h .notexecutedi mov bl,[SA1IRQData+1] and bl,50h or al,bl ret sa12301r: mov al,[SA1Message] test byte[SA1IRQExec+1],1 jz .notexecuted or al,80h .notexecuted ret sa12306r: ; call UpdateArithStuff mov al,[SA1ARR1] ret sa12307r: ; call UpdateArithStuff mov al,[SA1ARR1+1] ret sa12308r: ; call UpdateArithStuff mov al,[SA1ARR1+2] ret sa12309r: ; call UpdateArithStuff mov al,[SA1ARR1+3] ret sa1230Ar: ; call UpdateArithStuff mov al,[SA1ARR2] ret sa1230Br: mov al,[SA1Overflow] ret NEWSYM IRamRead mov al,[IRAM+ecx-3000h] ret NEWSYM IRamWrite mov [IRAM+ecx-3000h],al ret NEWSYM IRamWrite2 mov [IRAM+ecx-3000h],al xor dh,dh ret NEWSYM sa1223Fw mov [SA1Overflow+1],al ret ; Variable Length Data NEWSYM sa12258w mov [VarLenBarrel+2],al mov bl,al and bl,0Fh cmp bl,0 jne .not0 mov bl,16 .not0 mov [VarLenBarrel+3],bl test al,80h jz .notchange mov [VarLenBarrel],bl mov [VarLenBarrel+1],bl .notchange ret NEWSYM sa12259w mov [VarLenAddr],al mov [VarLenAddrB],al mov byte[VarLenBarrel],0 mov byte[VarLenBarrel+1],0 ret NEWSYM sa1225Aw mov [VarLenAddr+1],al mov [VarLenAddrB+1],al mov byte[VarLenBarrel],0 mov byte[VarLenBarrel+1],0 ret NEWSYM sa1225Bw mov [VarLenAddr+2],al mov [VarLenAddrB+2],al mov byte[VarLenBarrel],0 mov byte[VarLenBarrel+1],0 ret ; Variable Length Read NEWSYM sa1230Cr push ecx xor ebx,ebx xor ecx,ecx mov bl,[VarLenAddr+2] mov cx,[VarLenAddr] test ecx,8000h jz .loweraddr add ecx,[snesmmap+ebx*4] jmp .upperaddr .loweraddr add ecx,[snesmap2+ebx*4] .upperaddr mov ebx,[ecx] mov cl,[VarLenBarrel+1] shr ebx,cl mov al,bl pop ecx test byte[VarLenBarrel+2],80h jnz .autoinc ret .autoinc mov bl,[VarLenBarrel+3] add [VarLenBarrel],bl mov bl,[VarLenBarrel] cmp bl,16 jbe .notover sub byte[VarLenBarrel],16 add dword[VarLenAddr],2 mov byte[VarLenAddr+3],0 .notover ret NEWSYM sa1230Dr push ecx xor ebx,ebx xor ecx,ecx mov bl,[VarLenAddrB+2] mov cx,[VarLenAddrB] test ecx,8000h jz .loweraddr add ecx,[snesmmap+ebx*4] jmp .upperaddr .loweraddr add ecx,[snesmap2+ebx*4] .upperaddr mov ebx,[ecx] mov cl,[VarLenBarrel+1] shr ebx,cl mov al,bh pop ecx test byte[VarLenBarrel+2],80h jnz .autoinc ret .autoinc mov bl,[VarLenBarrel+3] add [VarLenBarrel+1],bl mov bl,[VarLenBarrel+1] cmp bl,16 jbe .notover sub byte[VarLenBarrel+1],16 add dword[VarLenAddrB],2 mov byte[VarLenAddrB+3],0 .notover ret NEWSYM sa1230Er mov al,10h ret ; Approximate H loc NEWSYM sa12302r test byte[SA1TimerSet],80h jnz .timeron mov al,byte[CurrentExecSA1] shl al,2 add al,dh ret .timeron mov al,[SA1TimerCount] ret NEWSYM sa12303r test byte[SA1TimerSet],80h jnz .timeron mov al,byte[CurrentExecSA1] shr al,3 ret .timeron mov al,[SA1TimerCount+1] and al,1 ret NEWSYM sa12304r test byte[SA1TimerSet],80h jnz .timeron mov al,[curypos] ret .timeron mov bx,[SA1TimerCount+1] shr bx,1 mov al,bl ret NEWSYM sa12305r test byte[SA1TimerSet],80h jnz .timeron mov al,[curypos+1] ret .timeron mov bx,[SA1TimerCount+2] shr bx,1 mov al,bl and al,1 ret NEWSYM sa12210w ; Timer Settings mov [SA1TimerSet],al ret NEWSYM sa12211w ; Timer Clear mov dword[SA1TimerVal],0 ret NEWSYM sa12212w mov [SA1TimerCount],al ret NEWSYM sa12213w mov [SA1TimerCount+1],al ret NEWSYM sa12214w mov [SA1TimerCount+2],al ret NEWSYM sa12215w mov [SA1TimerCount+3],al ret NEWSYM sa12230w mov [SA1DMAInfo],al ret NEWSYM sa12231w mov [SA1DMAChar],al ; if b7=1, then end of chdma process ret SA1QuickF sa12232w, SA1DMASource SA1QuickF sa12233w, SA1DMASource+1 SA1QuickF sa12234w, SA1DMASource+2 SA1QuickF sa12235w, SA1DMADest NEWSYM sa12236w mov [SA1DMADest+1],al test byte[SA1DMAInfo],10h jnz near sa1chconv test byte[SA1DMAInfo],4 jnz .noiram jmp sa1dmairam .noiram ret NEWSYM sa12237w mov [SA1DMADest+2],al test byte[SA1DMAInfo],10h jnz .nobwram test byte[SA1DMAInfo],4 jz .nobwram jmp sa1dmabwram .nobwram ret NEWSYM sa12238w mov [SA1DMACount],al ret NEWSYM sa12239w mov [SA1DMACount+1],al ret NEWSYM sa1dmaptr, dd 0 NEWSYM sa1dmaptrs, dd 0 NEWSYM sa1dmairam mov ebx,[SA1DMADest] and ebx,7FFh add ebx,IRAM mov [sa1dmaptr],ebx jmp executesa1dma NEWSYM sa1dmabwram mov ebx,[SA1DMADest] and ebx,3FFFFh add ebx,[SA1RAMArea] mov [sa1dmaptr],ebx executesa1dma: test byte[SA1DMAInfo],1 jz .nobwram mov ebx,[SA1DMASource] and ebx,3FFFFh add ebx,[SA1RAMArea] mov [sa1dmaptrs],ebx jmp .doneram .nobwram test byte[SA1DMAInfo],2 jz .noiram mov ebx,[SA1DMASource] and ebx,7FFh add ebx,IRAM mov [sa1dmaptrs],ebx jmp .doneram .noiram xor ebx,ebx mov bl,[SA1DMASource+2] mov ebx,[snesmmap+ebx*4] push ecx xor ecx,ecx mov cx,[SA1DMASource] add ebx,ecx mov [sa1dmaptrs],ebx pop ecx .doneram push edx push eax push ecx mov ecx,[SA1DMACount] or ecx,ecx jz .notransfer mov ebx,[sa1dmaptrs] mov edx,[sa1dmaptr] .loop mov al,[ebx] mov [edx],al inc ebx inc edx loop .loop .notransfer pop ecx pop eax pop edx ret ; Character Conversion DMA sa1chconv: ; or byte[SA1DoIRQ],4 or byte[SA1DoIRQ],8 ret mov ebx,[SA1DMADest] mov byte[debstop4],1 ; and ebx,7FFh and ebx,3FFFFh add ebx,[SA1RAMArea] mov [sa1dmaptr],ebx mov ebx,[SA1DMASource] and ebx,3FFFFh add ebx,[SA1RAMArea] mov [sa1dmaptrs],ebx ; 4 colors = 32 bytes, 16 colors = 64 bytes, 256 colors = 128 bytes ; SA1DMAChar,bit 2-4 = # of 8x8 tiles/horizontal row (0=1,1=2,2=3,..,5=32) ; SA1DMAChar,bit 0-1 = Color Mode (0=8b,1=4b,2=2b,3=?) test byte[SA1DMAChar],1 jnz .4bit test byte[SA1DMAChar],2 jnz .2bit mov ebx,[sa1dmaptr] push ecx pop ecx ret .4bit mov ebx,[sa1dmaptr] push ecx pop ecx ret .2bit push ecx mov ecx,8 mov ebx,[sa1dmaptr] push edx mov edx,[sa1dmaptrs] ; sub ebx,1000h jmp .skipall mov ecx,1000h .loops and edx,07FFh mov al,[ebx] mov [IRAM+edx],al inc ebx inc edx loop .loops pop edx pop ecx ret .skipall jmp .conv ; repeat for 320 tiles mov ecx,320 .chl2 mov al,[ebx] mov dword[.numrows],16 .chl mov [edx],al inc edx dec dword[.numrows] jne .chl inc ebx dec ecx jnz .chl2 pop edx pop ecx ret ; Convert 10 rows into bitplane from ebx to edx .conv mov dword[.numrows],10 .cloop3 mov ch,32 .cloop mov cl,8 .cloop2 mov ax,[ebx] add ax,ax rcl byte[edx+8],1 add ax,ax rcl byte[edx],1 add ax,ax rcl byte[edx+8],1 add ax,ax rcl byte[edx],1 add ax,ax rcl byte[edx+8],1 add ax,ax rcl byte[edx],1 add ax,ax rcl byte[edx+8],1 add ax,ax rcl byte[edx],1 add ax,ax rcl byte[edx+8],1 add ax,ax rcl byte[edx],1 add ax,ax rcl byte[edx+8],1 add ax,ax rcl byte[edx],1 add ax,ax rcl byte[edx+8],1 add ax,ax rcl byte[edx],1 add ax,ax rcl byte[edx+8],1 add ax,ax rcl byte[edx],1 add ebx,64 inc edx dec cl jnz near .cloop2 add edx,8 sub ebx,64*8-2 dec ch jnz near .cloop sub ebx,2*32 add ebx,8*64 dec dword[.numrows] jnz near .cloop3 pop edx pop ecx mov ebx,[sa1dmaptr] push ecx mov ecx,32 .loop ; mov dword[IRAM+ebx],0FFFFFFFFh add ebx,4 loop .loop pop ecx ret .numrows dd 0 NEWSYM initSA1regs setreg 2300h*4,sa12300r setreg 2301h*4,sa12301r setreg 2302h*4,sa12302r setreg 2303h*4,sa12303r setreg 2304h*4,sa12304r setreg 2305h*4,sa12305r setreg 2306h*4,sa12306r setreg 2307h*4,sa12307r setreg 2308h*4,sa12308r setreg 2309h*4,sa12309r setreg 230Ah*4,sa1230Ar setreg 230Bh*4,sa1230Br setreg 230Ch*4,sa1230Cr setreg 230Dh*4,sa1230Dr setreg 230Eh*4,sa1230Er ; Set IRam, memory address 3000-37FF mov edi,3000h*4 add edi,[regptr] mov eax,IRamRead mov ecx,800h .loopr mov [edi],eax add edi,4 loop .loopr ret NEWSYM initSA1regsw setregw 2200h*4,sa12200w setregw 2201h*4,sa12201w setregw 2202h*4,sa12202w setregw 2203h*4,sa12203w setregw 2204h*4,sa12204w setregw 2205h*4,sa12205w setregw 2206h*4,sa12206w setregw 2207h*4,sa12207w setregw 2208h*4,sa12208w setregw 2209h*4,sa12209w setregw 220Ah*4,sa1220Aw setregw 220Bh*4,sa1220Bw setregw 220Ch*4,sa1220Cw setregw 220Dh*4,sa1220Dw setregw 220Eh*4,sa1220Ew setregw 220Fh*4,sa1220Fw setregw 2210h*4,sa12210w setregw 2211h*4,sa12211w setregw 2212h*4,sa12212w setregw 2213h*4,sa12213w setregw 2214h*4,sa12214w setregw 2215h*4,sa12215w setregw 2220h*4,sa12220w setregw 2221h*4,sa12221w setregw 2222h*4,sa12222w setregw 2223h*4,sa12223w setregw 2224h*4,sa12224w setregw 2225h*4,sa12225w setregw 2230h*4,sa12230w setregw 2231h*4,sa12231w setregw 2232h*4,sa12232w setregw 2233h*4,sa12233w setregw 2234h*4,sa12234w setregw 2235h*4,sa12235w setregw 2236h*4,sa12236w setregw 2237h*4,sa12237w setregw 2238h*4,sa12238w setregw 2239h*4,sa12239w setregw 223Fh*4,sa1223Fw setregw 2250h*4,sa12250w setregw 2251h*4,sa12251w setregw 2252h*4,sa12252w setregw 2253h*4,sa12253w setregw 2254h*4,sa12254w setregw 2259h*4,sa12259w setregw 225Ah*4,sa1225Aw setregw 225Bh*4,sa1225Bw mov edi,3000h*4 add edi,[regptw] mov eax,IRamWrite mov ecx,800h .loopw mov [edi],eax add edi,4 loop .loopw setregw 3000h*4,IRamWrite2 ret NEWSYM SDD1Reset setregw 4801h*4,sdd14801w setregw 4802h*4,dbstop setregw 4803h*4,dbstop setregw 4804h*4,sdd14804w setregw 4805h*4,sdd14805w setregw 4806h*4,sdd14806w setregw 4807h*4,sdd14807w setregw 4808h*4,dbstop setregw 4809h*4,dbstop setregw 480Ah*4,dbstop setregw 480Bh*4,dbstop setregw 480Ch*4,dbstop setregw 480Dh*4,dbstop setregw 480Eh*4,dbstop setregw 480Fh*4,dbstop ret NEWSYM initSDD1regs setreg 4804h*4,sdd14804 setreg 4805h*4,sdd14805 setreg 4806h*4,sdd14806 setreg 4807h*4,sdd14807 ret dbstop: mov byte[debstop3],1 ret NEWSYM sdd14801w cmp al,0 jne .notzero ret .notzero mov byte[AddrNoIncr],0 ; set banks C0h-FFh to decompressing routine push eax push ebx mov eax,memtabler8+0C0h*4 mov ebx,40h .loop mov dword[eax],memaccessbankr8sdd1 add eax,4 dec ebx jnz .loop mov dword[Sdd1Mode],1 pop ebx pop eax ret NEWSYM Sa1RegsAsmEnd