SCHG How-to:Port Flamewing's Sonic 3 & Knuckles Sound Driver
From Sonic Retro
(Original guide by KZG4)
Many people have been using the older Sonic 3 and Knuckles sound driver port made by Kram1024 many years ago. I decided to try and port over Flamewing's improved Sonic 3 and Knuckles sound driver so people that intend to port over a Z80 based sound driver will be able to use a newer one.
Contents
Note
This guide is meant for a fresh install. I have not made this in order for the user to copy this over a disasm with Port Sonic 3 Sound Driver Part 1 applied onto it. I have not tested it so I have no idea if adding this guide over it will work.
Step 1: Resources
First you need the following:
- An ASM68K version of Hivebrain's disasm of Sonic 1. You can use the original version: Sonic 1 (Split and Text by Hivebrain) (ASM68K) (info) (1,016 kB) or you can use a modified version, such as Project Sonic 1: Two-Eight by MarkeyJester
- Flamewing's Sonic 3 and Knuckles sound driver: You can get this right here.
- Flamewing's smps2asm Music and SFX Pack: You can get this right here
- A utitily to extract .7z files. I'd Recommend 7Zip.
Step 2: Setup
Make a new .asm files called 'Macos.asm' and include it in your disasm's /_inc/ folder. Put this code in the file:
SonicControl equ $FFFFF602
Joypad equ $FFFFF604
Held equ 0
Press equ 1
iStart equ 7
iA equ 6
iC equ 5
iB equ 4
iRight equ 3
iLeft equ 2
iDown equ 1
iUp equ 0
MaskStart equ 1<<7
MaskA equ 1<<6
MaskC equ 1<<5
MaskB equ 1<<4
MaskRight equ 1<<3
MaskLeft equ 1<<2
MaskDown equ 1<<1
MaskUp equ 1
; =============================================================
; Macro to check button presses
; Arguments: 1 - buttons to check
; 2 - bitfield to check
; -------------------------------------------------------------
tpress macro
move.b (\2+1),d0
andi.b #\1,d0
endm
; =============================================================
; Macro to check if buttons are held
; Arguments: 1 - buttons to check
; 2 - bitfield to check
; -------------------------------------------------------------
theld macro
move.b \2,d0
andi.b #\1,d0
endm
; ---------------------------------------------------------------------------
; Align and pad
; input: length to align to, value to use as padding (default is 0)
; ---------------------------------------------------------------------------
align: macro
if (narg=1)
dcb.b \1-(*%\1),0
else
dcb.b \1-(*%\1),\2
endc
endm
; ---------------------------------------------------------------------------
; Set a VRAM address via the VDP control port.
; input: 16-bit VRAM address, control port (default is ($C00004).l)
; ---------------------------------------------------------------------------
locVRAM: macro loc,controlport
if (narg=1)
move.l #($40000000+((loc&$3FFF)<<16)+((loc&$C000)>>14)),($C00004).l
else
move.l #($40000000+((loc&$3FFF)<<16)+((loc&$C000)>>14)),controlport
endc
endm
; ---------------------------------------------------------------------------
; DMA copy data from 68K (ROM/RAM) to the VRAM
; input: source, length, destination
; ---------------------------------------------------------------------------
writeVRAM: macro
lea (vdp_control_port).l,a5
move.l #$94000000+(((\2>>1)&$FF00)<<8)+$9300+((\2>>1)&$FF),(a5)
move.l #$96000000+(((\1>>1)&$FF00)<<8)+$9500+((\1>>1)&$FF),(a5)
move.w #$9700+((((\1>>1)&$FF0000)>>16)&$7F),(a5)
move.w #$4000+(\3&$3FFF),(a5)
move.w #$80+((\3&$C000)>>14),(v_vdp_buffer2).w
move.w (v_vdp_buffer2).w,(a5)
endm
; ---------------------------------------------------------------------------
; DMA copy data from 68K (ROM/RAM) to the CRAM
; input: source, length, destination
; ---------------------------------------------------------------------------
writeCRAM: macro
lea (vdp_control_port).l,a5
move.l #$94000000+(((\2>>1)&$FF00)<<8)+$9300+((\2>>1)&$FF),(a5)
move.l #$96000000+(((\1>>1)&$FF00)<<8)+$9500+((\1>>1)&$FF),(a5)
move.w #$9700+((((\1>>1)&$FF0000)>>16)&$7F),(a5)
move.w #$C000+(\3&$3FFF),(a5)
move.w #$80+((\3&$C000)>>14),(v_vdp_buffer2).w
move.w (v_vdp_buffer2).w,(a5)
endm
; ---------------------------------------------------------------------------
; stop the Z80
; ---------------------------------------------------------------------------
stopZ80: macro
move.w #$100,($A11100).l
@wait: btst #0,($A11100).l
bne.s @wait
endm
; ---------------------------------------------------------------------------
; wait for Z80 to stop
; ---------------------------------------------------------------------------
waitZ80: macro
@wait: btst #0,($A11100).l
bne.s @wait
endm
stopZ80a: macro
move.w #$100,($A11100).l
endm
; ---------------------------------------------------------------------------
; reset the Z80
; ---------------------------------------------------------------------------
resetZ80: macro
move.w #$100,($A11200).l
endm
resetZ80a: macro
move.w #0,($A11200).l
endm
; ---------------------------------------------------------------------------
; start the Z80
; ---------------------------------------------------------------------------
startZ80: macro
move.w #0,($A11100).l
endm
; ---------------------------------------------------------------------------
; disable interrupts
; ---------------------------------------------------------------------------
disable_ints: macro
move #$2700,sr
endm
; ---------------------------------------------------------------------------
; enable interrupts
; ---------------------------------------------------------------------------
enable_ints: macro
move #$2300,sr
endm
; ---------------------------------------------------------------------------
; play a sound effect or music
; input: track, terminate routine (leave blank to not terminate)
; ---------------------------------------------------------------------------
music: macro track,terminate
move.w #track,d0
if (narg=1)
jsr (PlaySound).l
else
jmp (PlaySound).l
endc
endm
sfx: macro track,terminate
move.w #track,d0
if (narg=1)
jsr (PlaySound_Special).l
else
jmp (PlaySound_Special).l
endc
endm
This code adds some macros that the S3K driver uses, along with controller macros that you may find helpful.
Step 3: Removing the Sonic 1 Sound Driver
First, We need to locate
Step 4: Inserting the Sonic 3K Sound Driver
After you have removed the Sonic 1 Sound Driver, Locate the SoundDriverLoad Routine. The routine will look like this:
SoundDriverLoad: ; XREF: GameClrRAM; TitleScreen
nop
move.w #$100,($A11100).l ; stop the Z80
move.w #$100,($A11200).l ; reset the Z80
lea (Kos_Z80).l,a0 ; load sound driver
lea ($A00000).l,a1
bsr.w KosDec ; decompress
move.w #0,($A11200).l
nop
nop
nop
nop
move.w #$100,($A11200).l ; reset the Z80
move.w #0,($A11100).l ; start the Z80
rts
; End of function SoundDriverLoad
Now, replace this routine with this:
SoundDriverLoad: ; XREF: GameClrRAM; TitleScreen
LoadZ80drv:
nop
stopZ80a
resetZ80
lea (RomEndLoc).l,a0
move.l (a0),d0
addq.l #1,d0
movea.l d0,a0
lea ($A00000).l,a1
jsr KosDec
; lea (DriverResetData).l,a0
; lea ($A01C8A).l,a1 ; z80 ram start of variables (A01C00 in older version)
; move.w #DriverResetDataEnd-DriverResetData,d0
;DriverResetDataLoadLoop:
; move.b (a0)+,(a1)+
; dbf d0,DriverResetDataLoadLoop
btst #0,($C00005).l ; check video mode
sne ($A01C02).l ; set PAL mode flag
resetZ80a
nop
nop
nop
nop
resetZ80
startZ80
rts
; End of function SoundDriverLoad
DriverResetData:
dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DriverResetDataEnd:
Step 5: Modifying Build.bat
Step 6: Changing SFX
Step 7: Fixing Music
Known Issues
Some of the Known Issues with this guide are:
- Pushing SFX is broken
- Point SFX is broken
- Pausing during gameplay does not stop music
Conclusion
Congrats! Now you have ported the Flamewing S3K driver to your Sonic 1 hack!
Credits
- Kurk (me): Main Guide, Code.
- Flamewing: Making his S3K driver and smps2asm.
- Crash: Porting the Flamewing S3K driver to S1 with a similar method, which helped me while writing this
- Alriightyman: Made a guide to do this but for Sonic 2, which helped me while writing this
- Clownancy: Fixed S1 SFX from Clone Driver v2
- Valley Bell: Isolating the Sonic 1 sound driver, which helped me locate what parts of the S1 sound driver to remove
- Kram1024: Making the original Sonic 3 sound driver in Sonic 1 guide.