summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Constants.asm1
-rw-r--r--_inc/Nemesis Decompression.asm228
-rw-r--r--_inc/PauseGame.asm4
-rw-r--r--_incObj/41 Springs.asm8
-rw-r--r--_incObj/sub RandomNumber.asm4
-rw-r--r--build.bat1
-rw-r--r--chkbitperfect.rev00.bat12
-rw-r--r--chkbitperfect.rev01.bat13
-rw-r--r--s1built.binbin524288 -> 524288 bytes
-rw-r--r--s1rev00.binbin0 -> 524288 bytes
-rw-r--r--s1rev01.binbin0 -> 524288 bytes
-rw-r--r--sonic.asm220
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
diff --git a/build.bat b/build.bat
index 03664a2..101129f 100644
--- a/build.bat
+++ b/build.bat
@@ -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
index 08f7ca8..122112b 100644
--- a/s1built.bin
+++ b/s1built.bin
Binary files differ
diff --git a/s1rev00.bin b/s1rev00.bin
new file mode 100644
index 0000000..122112b
--- /dev/null
+++ b/s1rev00.bin
Binary files differ
diff --git a/s1rev01.bin b/s1rev01.bin
new file mode 100644
index 0000000..aa36bf1
--- /dev/null
+++ b/s1rev01.bin
Binary files differ
diff --git a/sonic.asm b/sonic.asm
index 4c40c91..33b911c 100644
--- a/sonic.asm
+++ b/sonic.asm
@@ -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