diff options
| -rw-r--r-- | Constants.asm | 1 | ||||
| -rw-r--r-- | _inc/Nemesis Decompression.asm | 228 | ||||
| -rw-r--r-- | _inc/PauseGame.asm | 4 | ||||
| -rw-r--r-- | _incObj/41 Springs.asm | 8 | ||||
| -rw-r--r-- | _incObj/sub RandomNumber.asm | 4 | ||||
| -rw-r--r-- | build.bat | 1 | ||||
| -rw-r--r-- | chkbitperfect.rev00.bat | 12 | ||||
| -rw-r--r-- | chkbitperfect.rev01.bat | 13 | ||||
| -rw-r--r-- | s1built.bin | bin | 524288 -> 524288 bytes | |||
| -rw-r--r-- | s1rev00.bin | bin | 0 -> 524288 bytes | |||
| -rw-r--r-- | s1rev01.bin | bin | 0 -> 524288 bytes | |||
| -rw-r--r-- | sonic.asm | 220 |
12 files changed, 305 insertions, 186 deletions
diff --git a/Constants.asm b/Constants.asm index 41c60f4..89ebda1 100644 --- a/Constants.asm +++ b/Constants.asm @@ -4,6 +4,7 @@ Size_of_SegaPCM: equ $6978 Size_of_DAC_driver_guess: equ $1760 +System_Stack: equ $FFFE00 ; VDP addressses vdp_data_port: equ $C00000 diff --git a/_inc/Nemesis Decompression.asm b/_inc/Nemesis Decompression.asm index 3d8b430..b789af3 100644 --- a/_inc/Nemesis Decompression.asm +++ b/_inc/Nemesis Decompression.asm @@ -1,96 +1,110 @@ ; --------------------------------------------------------------------------- -; Nemesis decompression algorithm -; --------------------------------------------------------------------------- +; Nemesis decompression subroutine, decompresses art directly to VRAM +; Inputs: +; a0 = art address -; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| +; For format explanation see http://info.sonicretro.org/Nemesis_compression +; --------------------------------------------------------------------------- +; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| +; Nemesis decompression to VRAM NemDec: movem.l d0-a1/a3-a5,-(sp) - lea (loc_1502).l,a3 - lea (vdp_data_port).l,a4 - bra.s loc_145C -; =========================================================================== + lea (NemPCD_WriteRowToVDP).l,a3 ; write all data to the same location + lea (vdp_data_port).l,a4 ; specifically, to the VDP data port + bra.s NemDecMain + +; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| + +; Nemesis decompression subroutine, decompresses art to RAM +; Inputs: +; a0 = art address +; a4 = destination RAM address +NemDecToRAM: movem.l d0-a1/a3-a5,-(sp) - lea (loc_1518).l,a3 + lea (NemPCD_WriteRowToRAM).l,a3 ; advance to the next location after each write -loc_145C: +NemDecMain: lea (v_ngfx_buffer).w,a1 - move.w (a0)+,d2 + move.w (a0)+,d2 ; get number of patterns lsl.w #1,d2 - bcc.s loc_146A - adda.w #$A,a3 + bcc.s loc_146A ; branch if the sign bit isn't set + adda.w #NemPCD_WriteRowToVDP_XOR-NemPCD_WriteRowToVDP,a3 ; otherwise the file uses XOR mode loc_146A: - lsl.w #2,d2 - movea.w d2,a5 - moveq #8,d3 + lsl.w #2,d2 ; get number of 8-pixel rows in the uncompressed data + movea.w d2,a5 ; and store it in a5 because there aren't any spare data registers + moveq #8,d3 ; 8 pixels in a pattern row moveq #0,d2 moveq #0,d4 - bsr.w NemDec4 - move.b (a0)+,d5 - asl.w #8,d5 - move.b (a0)+,d5 - move.w #$10,d6 - bsr.s NemDec2 + bsr.w NemDec_BuildCodeTable + move.b (a0)+,d5 ; get first byte of compressed data + asl.w #8,d5 ; shift up by a byte + move.b (a0)+,d5 ; get second byte of compressed data + move.w #$10,d6 ; set initial shift value + bsr.s NemDec_ProcessCompressedData movem.l (sp)+,d0-a1/a3-a5 rts ; End of function NemDec +; --------------------------------------------------------------------------- +; Part of the Nemesis decompressor, processes the actual compressed data +; --------------------------------------------------------------------------- ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| -NemDec2: +NemDec_ProcessCompressedData: move.w d6,d7 - subq.w #8,d7 + subq.w #8,d7 ; get shift value move.w d5,d1 - lsr.w d7,d1 - cmpi.b #-4,d1 - bcc.s loc_14D6 + lsr.w d7,d1 ; shift so that high bit of the code is in bit position 7 + cmpi.b #%11111100,d1 ; are the high 6 bits set? + bcc.s NemPCD_InlineData ; if they are, it signifies inline data andi.w #$FF,d1 add.w d1,d1 - move.b (a1,d1.w),d0 + move.b (a1,d1.w),d0 ; get the length of the code in bits ext.w d0 - sub.w d0,d6 - cmpi.w #9,d6 - bcc.s loc_14B2 + sub.w d0,d6 ; subtract from shift value so that the next code is read next time around + cmpi.w #9,d6 ; does a new byte need to be read? + bcc.s loc_14B2 ; if not, branch addq.w #8,d6 asl.w #8,d5 - move.b (a0)+,d5 + move.b (a0)+,d5 ; read next byte loc_14B2: move.b 1(a1,d1.w),d1 move.w d1,d0 - andi.w #$F,d1 + andi.w #$F,d1 ; get palette index for pixel andi.w #$F0,d0 -loc_14C0: - lsr.w #4,d0 +NemPCD_ProcessCompressedData: + lsr.w #4,d0 ; get repeat count -loc_14C2: - lsl.l #4,d4 - or.b d1,d4 - subq.w #1,d3 - bne.s loc_14D0 - jmp (a3) -; End of function NemDec2 +NemPCD_WritePixel: + lsl.l #4,d4 ; shift up by a nybble + or.b d1,d4 ; write pixel + subq.w #1,d3 ; has an entire 8-pixel row been written? + bne.s NemPCD_WritePixel_Loop ; if not, loop + jmp (a3) ; otherwise, write the row to its destination, by doing a dynamic jump to NemPCD_WriteRowToVDP, NemDec_WriteAndAdvance, NemPCD_WriteRowToVDP_XOR, or NemDec_WriteAndAdvance_XOR +; End of function NemDec_ProcessCompressedData ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| -NemDec3: - moveq #0,d4 - moveq #8,d3 +NemPCD_NewRow: + moveq #0,d4 ; reset row + moveq #8,d3 ; reset nybble counter -loc_14D0: - dbf d0,loc_14C2 - bra.s NemDec2 +NemPCD_WritePixel_Loop: + dbf d0,NemPCD_WritePixel + bra.s NemDec_ProcessCompressedData ; =========================================================================== -loc_14D6: - subq.w #6,d6 +NemPCD_InlineData: + subq.w #6,d6 ; 6 bits needed to signal inline data cmpi.w #9,d6 bcc.s loc_14E4 addq.w #8,d6 @@ -98,98 +112,110 @@ loc_14D6: move.b (a0)+,d5 loc_14E4: - subq.w #7,d6 + subq.w #7,d6 ; and 7 bits needed for the inline data itself move.w d5,d1 - lsr.w d6,d1 + lsr.w d6,d1 ; shift so that low bit of the code is in bit position 0 move.w d1,d0 - andi.w #$F,d1 - andi.w #$70,d0 + andi.w #$F,d1 ; get palette index for pixel + andi.w #$70,d0 ; high nybble is repeat count for pixel cmpi.w #9,d6 - bcc.s loc_14C0 + bcc.s NemPCD_ProcessCompressedData addq.w #8,d6 asl.w #8,d5 move.b (a0)+,d5 - bra.s loc_14C0 -; End of function NemDec3 + bra.s NemPCD_ProcessCompressedData +; End of function NemPCD_NewRow ; =========================================================================== -loc_1502: - move.l d4,(a4) +NemPCD_WriteRowToVDP: + move.l d4,(a4) ; write 8-pixel row subq.w #1,a5 - move.w a5,d4 - bne.s NemDec3 - rts + move.w a5,d4 ; have all the 8-pixel rows been written? + bne.s NemPCD_NewRow ; if not, branch + rts ; otherwise the decompression is finished ; =========================================================================== - eor.l d4,d2 - move.l d2,(a4) +NemPCD_WriteRowToVDP_XOR: + eor.l d4,d2 ; XOR the previous row by the current row + move.l d2,(a4) ; and write the result subq.w #1,a5 move.w a5,d4 - bne.s NemDec3 + bne.s NemPCD_NewRow rts ; =========================================================================== -loc_1518: +NemPCD_WriteRowToRAM: move.l d4,(a4)+ subq.w #1,a5 move.w a5,d4 - bne.s NemDec3 + bne.s NemPCD_NewRow rts ; =========================================================================== +NemPCD_WriteRowToRAM_XOR: eor.l d4,d2 move.l d2,(a4)+ subq.w #1,a5 move.w a5,d4 - bne.s NemDec3 + bne.s NemPCD_NewRow rts ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| +; --------------------------------------------------------------------------- +; Part of the Nemesis decompressor, builds the code table (in RAM) +; --------------------------------------------------------------------------- -NemDec4: - move.b (a0)+,d0 +NemDec_BuildCodeTable: + move.b (a0)+,d0 ; read first byte -loc_1530: - cmpi.b #-1,d0 - bne.s loc_1538 - rts +NemBCT_ChkEnd: + cmpi.b #$FF,d0 ; has the end of the code table description been reached? + bne.s NemBCT_NewPALIndex ; if not, branch + rts ; otherwise, this subroutine's work is done ; =========================================================================== -loc_1538: +NemBCT_NewPALIndex: move.w d0,d7 -loc_153A: - move.b (a0)+,d0 - cmpi.b #$80,d0 - bcc.s loc_1530 +NemBCT_Loop: + move.b (a0)+,d0 ; read next byte + cmpi.b #$80,d0 ; sign bit being set signifies a new palette index + bcc.s NemBCT_ChkEnd ; a bmi could have been used instead of a compare and bcc + move.b d0,d1 - andi.w #$F,d7 - andi.w #$70,d1 - or.w d1,d7 - andi.w #$F,d0 + andi.w #$F,d7 ; get palette index + andi.w #$70,d1 ; get repeat count for palette index + or.w d1,d7 ; combine the two + andi.w #$F,d0 ; get the length of the code in bits move.b d0,d1 lsl.w #8,d1 - or.w d1,d7 + or.w d1,d7 ; combine with palette index and repeat count to form code table entry moveq #8,d1 - sub.w d0,d1 - bne.s loc_1568 - move.b (a0)+,d0 - add.w d0,d0 - move.w d7,(a1,d0.w) - bra.s loc_153A + sub.w d0,d1 ; is the code 8 bits long? + bne.s NemBCT_ShortCode ; if not, a bit of extra processing is needed + move.b (a0)+,d0 ; get code + add.w d0,d0 ; each code gets a word-sized entry in the table + move.w d7,(a1,d0.w) ; store the entry for the code + bra.s NemBCT_Loop ; repeat ; =========================================================================== -loc_1568: - move.b (a0)+,d0 - lsl.w d1,d0 - add.w d0,d0 +; the Nemesis decompressor uses prefix-free codes (no valid code is a prefix of a longer code) +; e.g. if 10 is a valid 2-bit code, 110 is a valid 3-bit code but 100 isn't +; also, when the actual compressed data is processed the high bit of each code is in bit position 7 +; so the code needs to be bit-shifted appropriately over here before being used as a code table index +; additionally, the code needs multiple entries in the table because no masking is done during compressed data processing +; so if 11000 is a valid code then all indices of the form 11000XXX need to have the same entry +NemBCT_ShortCode: + move.b (a0)+,d0 ; get code + add.w d0,d0 ; shift so that high bit is in bit position 7 + lsl.w d1,d0 ; get index into code table moveq #1,d5 lsl.w d1,d5 - subq.w #1,d5 - -loc_1574: - move.w d7,(a1,d0.w) - addq.w #2,d0 - dbf d5,loc_1574 - bra.s loc_153A -; End of function NemDec4 + subq.w #1,d5 ; d5 = 2^d1 - 1 + +NemBCT_ShortCode_Loop: + move.w d7,(a1,d0.w) ; store entry + addq.w #2,d0 ; increment index + dbf d5,NemBCT_ShortCode_Loop ; repeat for required number of entries + bra.s NemBCT_Loop +; End of function NemDec_BuildCodeTable diff --git a/_inc/PauseGame.asm b/_inc/PauseGame.asm index af53518..3460889 100644 --- a/_inc/PauseGame.asm +++ b/_inc/PauseGame.asm @@ -41,7 +41,7 @@ Pause_ChkStart: beq.s Pause_Loop ; if not, branch Pause_EndMusic: - move.b #$80,(v_snddriver_ram+f_pausemusic).w + move.b #$80,(v_snddriver_ram+f_pausemusic).w ; unpause the music Unpause: move.w #0,(f_pause).w ; unpause the game @@ -52,6 +52,6 @@ Pause_DoNothing: Pause_SlowMo: move.w #1,(f_pause).w - move.b #$80,(v_snddriver_ram+f_pausemusic).w + move.b #$80,(v_snddriver_ram+f_pausemusic).w ; Unpause the music rts ; End of function PauseGame diff --git a/_incObj/41 Springs.asm b/_incObj/41 Springs.asm index a9deec7..a724444 100644 --- a/_incObj/41 Springs.asm +++ b/_incObj/41 Springs.asm @@ -69,7 +69,7 @@ Spring_Up: ; Routine 2 move.w #$10,d3 move.w obX(a0),d4 bsr.w SolidObject - tst.b ob2ndRout(a0) ; is Sonic on top of the spring? + tst.b obSolid(a0) ; is Sonic on top of the spring? bne.s Spring_BounceUp ; if yes, branch rts ; =========================================================================== @@ -83,7 +83,7 @@ Spring_BounceUp: move.b #id_Spring,obAnim(a1) ; use "bouncing" animation move.b #2,obRoutine(a1) bclr #3,obStatus(a0) - clr.b ob2ndRout(a0) + clr.b obSolid(a0) sfx sfx_Spring,0,0,0 ; play spring sound Spring_AniUp: ; Routine 4 @@ -157,7 +157,7 @@ Spring_Dwn: ; Routine $E move.b #$E,obRoutine(a0) loc_DCA4: - tst.b ob2ndRout(a0) + tst.b obSolid(a0) bne.s locret_DCAE tst.w d4 bmi.s Spring_BounceDwn @@ -175,7 +175,7 @@ Spring_BounceDwn: bclr #3,obStatus(a1) move.b #2,obRoutine(a1) bclr #3,obStatus(a0) - clr.b ob2ndRout(a0) + clr.b obSolid(a0) sfx sfx_Spring,0,0,0 ; play spring sound Spring_AniDwn: ; Routine $10 diff --git a/_incObj/sub RandomNumber.asm b/_incObj/sub RandomNumber.asm index 4037722..c72d424 100644 --- a/_incObj/sub RandomNumber.asm +++ b/_incObj/sub RandomNumber.asm @@ -7,8 +7,8 @@ RandomNumber: move.l (v_random).w,d1 - bne.s .scramble ; if d0 is not 0, branch - move.l #$2A6D365A,d1 ; if do is 0, use seed number + bne.s .scramble ; if d1 is not 0, branch + move.l #$2A6D365A,d1 ; if d1 is 0, use seed number .scramble: move.l d1,d0 @@ -69,4 +69,3 @@ echo * * echo ************************************************************************* echo. pause - diff --git a/chkbitperfect.rev00.bat b/chkbitperfect.rev00.bat new file mode 100644 index 0000000..eb0d841 --- /dev/null +++ b/chkbitperfect.rev00.bat @@ -0,0 +1,12 @@ +@echo OFF + +REM // build the ROM +call build + +REM // run fc against a Sonic 1 Rev 00 ROM +echo ------------------------------------------------------------- +if exist s1built.bin ( fc /b s1built.bin s1rev00.bin +) else echo s1built.bin does not exist, probably due to an assembly error + +REM // if someone ran this from Windows Explorer, prevent the window from disappearing immediately +pause diff --git a/chkbitperfect.rev01.bat b/chkbitperfect.rev01.bat new file mode 100644 index 0000000..e0ec816 --- /dev/null +++ b/chkbitperfect.rev01.bat @@ -0,0 +1,13 @@ +@echo OFF + +REM // build the ROM +call build + +REM // run fc against a Sonic 1 Rev 01 ROM +echo ------------------------------------------------------------- +if exist s1built.bin ( fc /b s1built.bin s1rev01.bin +) else echo s1built.bin does not exist, probably due to an assembly error + +REM // if someone ran this from Windows Explorer, prevent the window from disappearing immediately +pause + diff --git a/s1built.bin b/s1built.bin Binary files differindex 08f7ca8..122112b 100644 --- a/s1built.bin +++ b/s1built.bin diff --git a/s1rev00.bin b/s1rev00.bin Binary files differnew file mode 100644 index 0000000..122112b --- /dev/null +++ b/s1rev00.bin diff --git a/s1rev01.bin b/s1rev01.bin Binary files differnew file mode 100644 index 0000000..aa36bf1 --- /dev/null +++ b/s1rev01.bin @@ -33,23 +33,71 @@ OptimiseSound = 0 ; change to 1 to optimise sound queuing ; =========================================================================== StartOfRom: -Vectors: dc.l $FFFE00, EntryPoint, BusError, AddressError - dc.l IllegalInstr, ZeroDivide, ChkInstr, TrapvInstr - dc.l PrivilegeViol, Trace, Line1010Emu, Line1111Emu - dc.l ErrorExcept, ErrorExcept, ErrorExcept, ErrorExcept - dc.l ErrorExcept, ErrorExcept, ErrorExcept, ErrorExcept - dc.l ErrorExcept, ErrorExcept, ErrorExcept, ErrorExcept - dc.l ErrorExcept, ErrorTrap, ErrorTrap, ErrorTrap - dc.l HBlank, ErrorTrap, VBlank, ErrorTrap - dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap - dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap - dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap - dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap - dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap - dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap +Vectors: dc.l System_Stack ; Initial stack pointer value + dc.l EntryPoint ; Start of program + dc.l BusError ; Bus error + dc.l AddressError ; Address error (4) + dc.l IllegalInstr ; Illegal instruction + dc.l ZeroDivide ; Division by zero + dc.l ChkInstr ; CHK exception + dc.l TrapvInstr ; TRAPV exception (8) + dc.l PrivilegeViol ; Privilege violation + dc.l Trace ; TRACE exception + dc.l Line1010Emu ; Line-A emulator + dc.l Line1111Emu ; Line-F emulator (12) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) (16) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) (20) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) + dc.l ErrorExcept ; Unused (reserved) (24) + dc.l ErrorExcept ; Spurious exception + dc.l ErrorTrap ; IRQ level 1 + dc.l ErrorTrap ; IRQ level 2 + dc.l ErrorTrap ; IRQ level 3 (28) + dc.l HBlank ; IRQ level 4 (horizontal retrace interrupt) + dc.l ErrorTrap ; IRQ level 5 + dc.l VBlank ; IRQ level 6 (vertical retrace interrupt) + dc.l ErrorTrap ; IRQ level 7 (32) + dc.l ErrorTrap ; TRAP #00 exception + dc.l ErrorTrap ; TRAP #01 exception + dc.l ErrorTrap ; TRAP #02 exception + dc.l ErrorTrap ; TRAP #03 exception (36) + dc.l ErrorTrap ; TRAP #04 exception + dc.l ErrorTrap ; TRAP #05 exception + dc.l ErrorTrap ; TRAP #06 exception + dc.l ErrorTrap ; TRAP #07 exception (40) + dc.l ErrorTrap ; TRAP #08 exception + dc.l ErrorTrap ; TRAP #09 exception + dc.l ErrorTrap ; TRAP #10 exception + dc.l ErrorTrap ; TRAP #11 exception (44) + dc.l ErrorTrap ; TRAP #12 exception + dc.l ErrorTrap ; TRAP #13 exception + dc.l ErrorTrap ; TRAP #14 exception + dc.l ErrorTrap ; TRAP #15 exception (48) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) if Revision<>2 - dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap - dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) + dc.l ErrorTrap ; Unused (reserved) else loc_E0: ; Relocated code from Spik_Hurt. REVXB was a nasty hex-edit. @@ -60,23 +108,25 @@ loc_E0: jmp (loc_D5A2).l dc.w ErrorTrap - dc.l ErrorTrap, ErrorTrap, ErrorTrap + dc.l ErrorTrap + dc.l ErrorTrap + dc.l ErrorTrap endif -Console: dc.b "SEGA MEGA DRIVE " ; Hardware system ID -_Date: dc.b "(C)SEGA 1991.APR" ; Release date +Console: dc.b "SEGA MEGA DRIVE " ; Hardware system ID (Console name) +_Date: dc.b "(C)SEGA 1991.APR" ; Copyright holder and release date (generally year) Title_Local: dc.b "SONIC THE HEDGEHOG " ; Domestic name Title_Int: dc.b "SONIC THE HEDGEHOG " ; International name Serial: if Revision=0 - dc.b "GM 00001009-00" ; Serial/version number + dc.b "GM 00001009-00" ; Serial/version number (Rev 0) else - dc.b "GM 00004049-01" + dc.b "GM 00004049-01" ; Serial/version number (Rev non-0) endif -Checksum: dc.w 0 +Checksum: dc.w $0 dc.b "J " ; I/O support -RomStartLoc: dc.l StartOfRom ; ROM start -RomEndLoc: dc.l EndOfRom-1 ; ROM end -RamStartLoc: dc.l $FF0000 ; RAM start -RamEndLoc: dc.l $FFFFFF ; RAM end +RomStartLoc: dc.l StartOfRom ; Start address of ROM +RomEndLoc: dc.l EndOfRom-1 ; End address of ROM +RamStartLoc: dc.l $FF0000 ; Start address of RAM +RamEndLoc: dc.l $FFFFFF ; End address of RAM SRAMSupport: if EnableSRAM=1 dc.b $52, $41, $A0+(BackupSRAM<<6)+(AddressSRAM<<3), $20 else @@ -84,10 +134,12 @@ SRAMSupport: if EnableSRAM=1 endif dc.l $20202020 ; SRAM start ($200001) dc.l $20202020 ; SRAM end ($20xxxx) -Notes: dc.b " " -Region: dc.b "JUE " ; Region +Notes: dc.b " " ; Notes (unused, anything can be put in this space, but it has to be 52 bytes.) +Region: dc.b "JUE " ; Region (Country code) +EndOfHeader: ; =========================================================================== +; Crash/Freeze the 68000. Unlike Sonic 2, Sonic 1 uses the 68000 for playing music, so it stops too ErrorTrap: nop @@ -99,22 +151,22 @@ EntryPoint: tst.l (z80_port_1_control).l ; test port A & B control registers bne.s PortA_Ok tst.w (z80_expansion_control).l ; test port C control register -PortA_Ok: - bne.s SkipSetup - lea SetupValues(pc),a5 +PortA_Ok: + bne.s SkipSetup ; Skip the VDP and Z80 setup code if port A, B or C is ok...? + lea SetupValues(pc),a5 ; Load setup values array address. movem.w (a5)+,d5-d7 movem.l (a5)+,a0-a4 move.b -$10FF(a1),d0 ; get hardware version (from $A10001) andi.b #$F,d0 - beq.s SkipSecurity + beq.s SkipSecurity ; If the console has no TMSS, skip the security stuff. move.l #'SEGA',$2F00(a1) ; move "SEGA" to TMSS register ($A14000) SkipSecurity: - move.w (a4),d0 - moveq #0,d0 - movea.l d0,a6 - move.l a6,usp ; set usp to 0 + move.w (a4),d0 ; clear write-pending flag in VDP to prevent issues if the 68k has been reset in the middle of writing a command long word to the VDP. + moveq #0,d0 ; clear d0 + movea.l d0,a6 ; clear a6 + move.l a6,usp ; set usp to $0 moveq #$17,d1 VDPInitLoop: @@ -122,6 +174,7 @@ VDPInitLoop: move.w d5,(a4) ; move value to VDP register add.w d7,d5 ; next register dbf d1,VDPInitLoop + move.l (a5)+,(a4) move.w d0,(a3) ; clear the VRAM move.w d7,(a1) ; stop the Z80 @@ -135,33 +188,34 @@ WaitForZ80: Z80InitLoop: move.b (a5)+,(a0)+ dbf d2,Z80InitLoop + move.w d0,(a2) move.w d0,(a1) ; start the Z80 move.w d7,(a2) ; reset the Z80 ClrRAMLoop: - move.l d0,-(a6) - dbf d6,ClrRAMLoop ; clear the entire RAM - move.l (a5)+,(a4) ; set VDP display mode and increment + move.l d0,-(a6) ; clear 4 bytes of RAM + dbf d6,ClrRAMLoop ; repeat until the entire RAM is clear + move.l (a5)+,(a4) ; set VDP display mode and increment mode move.l (a5)+,(a4) ; set VDP to CRAM write - moveq #$1F,d3 + moveq #$1F,d3 ; set repeat times ClrCRAMLoop: - move.l d0,(a3) - dbf d3,ClrCRAMLoop ; clear the CRAM - move.l (a5)+,(a4) + move.l d0,(a3) ; clear 2 palettes + dbf d3,ClrCRAMLoop ; repeat until the entire CRAM is clear + move.l (a5)+,(a4) ; set VDP to VSRAM write moveq #$13,d4 ClrVSRAMLoop: - move.l d0,(a3) - dbf d4,ClrVSRAMLoop ; clear the VSRAM + move.l d0,(a3) ; clear 4 bytes of VSRAM. + dbf d4,ClrVSRAMLoop ; repeat until the entire VSRAM is clear moveq #3,d5 PSGInitLoop: move.b (a5)+,$11(a3) ; reset the PSG - dbf d5,PSGInitLoop + dbf d5,PSGInitLoop ; repeat for other channels move.w d0,(a2) - movem.l (a6),d0-a6 ; clear all registers + movem.l (a6),d0-a6 ; clear all registers disable_ints SkipSetup: @@ -257,7 +311,7 @@ GameProgram: beq.w GameInit ; if yes, branch CheckSumCheck: - movea.l #ErrorTrap,a0 ; start checking bytes after the header ($200) + movea.l #EndOfHeader,a0 ; start checking bytes after the header ($200) movea.l #RomEndLoc,a1 ; stop at end of ROM move.l (a1),d0 moveq #0,d1 @@ -298,9 +352,9 @@ GameInit: MainGameLoop: move.b (v_gamemode).w,d0 ; load Game Mode - andi.w #$1C,d0 + andi.w #$1C,d0 ; limit Game Mode value to $1C max (change to a maximum of 7C to add more game modes) jsr GameModeArray(pc,d0.w) ; jump to apt location in ROM - bra.s MainGameLoop + bra.s MainGameLoop ; loop indefinitely ; =========================================================================== ; --------------------------------------------------------------------------- ; Main game mode array @@ -527,7 +581,7 @@ VBlank: move.w #$700,d0 .waitPAL: - dbf d0,.waitPAL + dbf d0,.waitPAL ; wait here in a loop doing nothing for a while... .notPAL: move.b (v_vbla_routine).w,d0 @@ -671,7 +725,7 @@ Demo_Time: bsr.w LoadTilesAsYouMove jsr (AnimateLevelGfx).l jsr (HUD_Update).l - bsr.w sub_165E + bsr.w ProcessDPLC2 tst.w (v_demolength).w ; is there time left on the demo? beq.w .end ; if not, branch subq.w #1,(v_demolength).w ; subtract 1 from time left @@ -698,9 +752,9 @@ VBla_0A: move.b #0,(f_sonframechg).w .nochg: - tst.w (v_demolength).w - beq.w .end - subq.w #1,(v_demolength).w + tst.w (v_demolength).w ; is there time left on the demo? + beq.w .end ; if not, return + subq.w #1,(v_demolength).w ; subtract 1 from time left in demo .end: rts @@ -876,7 +930,7 @@ JoypadInit: moveq #$40,d0 move.b d0,($A10009).l ; init port 1 (joypad 1) move.b d0,($A1000B).l ; init port 2 (joypad 2) - move.b d0,($A1000D).l ; init port 3 (expansion) + move.b d0,($A1000D).l ; init port 3 (expansion/extra) startZ80 rts ; End of function JoypadInit @@ -884,7 +938,6 @@ JoypadInit: ; --------------------------------------------------------------------------- ; Subroutine to read joypad input, and send it to the RAM ; --------------------------------------------------------------------------- - ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| @@ -932,7 +985,7 @@ VDPSetupGame: move.w (VDPSetupArray+2).l,d0 move.w d0,(v_vdp_buffer1).w - move.w #$8A00+223,(v_hbla_hreg).w + move.w #$8A00+223,(v_hbla_hreg).w ; H-INT every 224th scanline moveq #0,d0 move.l #$C0000000,(vdp_control_port).l ; set VDP to CRAM write move.w #$3F,d7 @@ -1072,35 +1125,37 @@ TilemapToVRAM: move.l #$800000,d4 Tilemap_Line: - move.l d0,4(a6) + move.l d0,4(a6) ; move d0 to VDP_control_port move.w d1,d3 Tilemap_Cell: move.w (a1)+,(a6) ; write value to namespace - dbf d3,Tilemap_Cell + dbf d3,Tilemap_Cell ; next tile add.l d4,d0 ; goto next line - dbf d2,Tilemap_Line + dbf d2,Tilemap_Line ; next line rts ; End of function TilemapToVRAM include "_inc/Nemesis Decompression.asm" + +; --------------------------------------------------------------------------- +; Subroutine to load pattern load cues (aka to queue pattern load requests) ; --------------------------------------------------------------------------- -; Subroutines to load pattern load cues -; input: -; d0 = pattern load cue number +; ARGUMENTS +; d0 = index of PLC list ; --------------------------------------------------------------------------- ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| - +; LoadPLC: AddPLC: movem.l a1-a2,-(sp) lea (ArtLoadCues).l,a1 add.w d0,d0 move.w (a1,d0.w),d0 - lea (a1,d0.w),a1 ; jump to relevant PLC + lea (a1,d0.w),a1 ; jump to relevant PLC lea (v_plc_buffer).w,a2 ; PLC buffer space .findspace: @@ -1120,14 +1175,24 @@ AddPLC: dbf d0,.loop ; repeat for length of PLC .skip: - movem.l (sp)+,a1-a2 + movem.l (sp)+,a1-a2 ; a1=object rts ; End of function AddPLC ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| +; Queue pattern load requests, but clear the PLQ first + +; ARGUMENTS +; d0 = index of PLC list (see ArtLoadCues) +; NOTICE: This subroutine does not check for buffer overruns. The programmer +; (or hacker) is responsible for making sure that no more than +; 16 load requests are copied into the buffer. +; _________DO NOT PUT MORE THAN 16 LOAD REQUESTS IN A LIST!__________ +; (or if you change the size of Plc_Buffer, the limit becomes (Plc_Buffer_Only_End-Plc_Buffer)/6) +; LoadPLC2: NewPLC: movem.l a1-a2,-(sp) lea (ArtLoadCues).l,a1 @@ -1137,28 +1202,30 @@ NewPLC: bsr.s ClearPLC ; erase any data in PLC buffer space lea (v_plc_buffer).w,a2 move.w (a1)+,d0 ; get length of PLC - bmi.s .skip + bmi.s .skip ; if it's negative, skip the next loop .loop: move.l (a1)+,(a2)+ move.w (a1)+,(a2)+ ; copy PLC to RAM - dbf d0,.loop ; repeat for length of PLC + dbf d0,.loop ; repeat for length of PLC .skip: movem.l (sp)+,a1-a2 rts ; End of function NewPLC +; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| + ; --------------------------------------------------------------------------- ; Subroutine to clear the pattern load cues ; --------------------------------------------------------------------------- -; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| +; Clear the pattern load queue ($FFF680 - $FFF700) ClearPLC: lea (v_plc_buffer).w,a2 ; PLC buffer space in RAM - moveq #$1F,d0 + moveq #$1F,d0 ; bytesToLcnt(v_plc_buffer_end-v_plc_buffer) .loop: clr.l (a2)+ @@ -1179,7 +1246,7 @@ RunPLC: tst.w (f_plc_execute).w bne.s Rplc_Exit movea.l (v_plc_buffer).w,a0 - lea (loc_1502).l,a3 + lea (NemPCD_WriteRowToVDP).l,a3 lea (v_ngfx_buffer).w,a1 move.w (a0)+,d2 bpl.s loc_160E @@ -1188,7 +1255,7 @@ RunPLC: loc_160E: andi.w #$7FFF,d2 move.w d2,(f_plc_execute).w - bsr.w NemDec4 + bsr.w NemDec_BuildCodeTable move.b (a0)+,d5 asl.w #8,d5 move.b (a0)+,d5 @@ -1224,7 +1291,8 @@ sub_1642: ; ||||||||||||||| S U B R O U T I N E ||||||||||||||||||||||||||||||||||||||| -sub_165E: +; sub_165E: +ProcessDPLC2: tst.w (f_plc_execute).w beq.s locret_16DA move.w #3,($FFFFF6FA).w @@ -1251,7 +1319,7 @@ loc_1676: loc_16AA: movea.w #8,a5 - bsr.w NemDec3 + bsr.w NemPCD_NewRow subq.w #1,(f_plc_execute).w beq.s loc_16DC subq.w #1,($FFFFF6FA).w @@ -1276,7 +1344,7 @@ loc_16E2: move.l 6(a0),(a0)+ dbf d0,loc_16E2 rts -; End of function sub_165E +; End of function ProcessDPLC2 ; --------------------------------------------------------------------------- ; Subroutine to execute the pattern load cue |
