Sonic and Sega Retro Message Board: Sonic 2 sound driver - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
Page 1 of 1
    Locked
    Locked Forum

Sonic 2 sound driver

#1 User is offline Erik JS 

Posted 19 January 2006 - 07:48 PM

  • Team Classic
  • Posts: 21
  • Joined: 24-August 04
  • Gender:Male
  • Location:São Bernardo do Campo - SP - BRASIL
In sometime between January 6th-7th I figured out the format of pointers to 68K banks. As you can realize from Tweaker's guide, banks are always multiple of $8000, and there's nothing in 68K to change them. That's because they are stored in Z80 RAM. I disassembled S2 sound driver and I can tell you, for instance, it's nothing like setting a variable to $1F that'll make Z80 acceess bank stored as 68K's $F8000 ($8000 x $1F). I got the Sega2f doc, and it only helped to find the actual Z80 address that does bank switching. The explanation there, though, wasn't in English for me. :P

First, let's put straight how music is accessed in S2. 68K code sets a RAM address ($FFFFFFE4) to have the value of the desired music. Somewhere else, one of those permanent functions checks that address to see if it has changed since last time. If so, it writes the music value to Z80 RAM ($A01B88). This last step involves more than a single move.b d0,$A01B88, because it's needed to stop Z80 processing before attempting to handle its data. After that, 68K makes Z80 resumes its operation. Z80 also has a constant function which checks to see if 1B88h is something but $80 (no music). Depending on that value, Z80 switches bank in order to play musics ($F8000), continue music (if $9C; F0000) or sound effects ($F8000). The bank is nothing but a space of $8000 bytes that is mirrored from a certain 68K memory space, so that's why music pointers in S2 are little-endian.

The bank switching, as said previously, isn't done by a single value assignment. On the other hand, it's done by a single memory address, which happens to be $A06000, or just 6000h for Z80. That's exactly what's written in Sega2f document:

Quote

2)  BANK
    From 8000H - FFFFH is window of 68K memory. Z-80 can access all of 68K memory by bank switching. bank select data create 68K address from A15 to A23. You must write these 9 bits one at a time into 6000H serially, byte units, using the LSB.


What such masterpiece of English language is saying is that bank is determined by a sequence of 9 values written one after other to 6000h. It sounds strange, but it works, believe me :P. Now, why is it a sequence of 9 values? As banks rely on multiples of $8000, it was not hard for me to fugure what they mean. Heh, they're indeed bits, and as you know (I hope), a bit can be one out of two values: 0/1, yes/no, true/false, etc. So they're nothing but a bunch of flags for the following bank values:
$8000
$10000
$20000
$40000
$80000
$100000
$200000
$400000
$800000

Sum everything and you'll have $FF8000 which is the hightest bank Z80 can access (and also the last $8000 bytes of Genesis memory). Yes, Z80 can access 68K RAM, but I don't see any practical use for it, as it would limit working space for 68K. I'm not sure about 68K SRAM, but it should be accessible too.

So how S2 sound driver does bank switch? It's actually something weirder than a "move.b #1, 6000H", but it follows such pattern. Let's see part of a Z80 disassembly from S2:
00000C79: AF  XOR A
00000C7A: 1E 01  LD E,01h
00000C7C: 21 00 60	LD HL,6000h
00000C7F: 73  LD (HL),E
00000C80: 73  LD (HL),E
00000C81: 73  LD (HL),E
00000C82: 73  LD (HL),E
00000C83: 73  LD (HL),E
00000C84: 77  LD (HL),A
00000C85: 77  LD (HL),A
00000C86: 77  LD (HL),A
00000C87: 77  LD (HL),A


This is always used for bank switching in S2. This part refers to the bank for musics but continue ($9C). LD (HL),E does the role of 1 and LD (HL),A does the same for 0. In byte terms, 73 is 1 and 77 is 0, for this case (and the rest of S2 sound driver). If you align that with the bank values you'll get $F8000, which is where music is stored in S2. During the Z80 halt in 68K code, before writing the value at 1B88h, you can put a check to see if certain condition is true, so you can alternate between one bank or other in order to play more musics than $1F - you still use the same values for music; the use of unused values like those after $70 in Sound Test is possible, but it requires Z80 reprogramming which I'm not able to do with my current knowledge, plus this method is enough for all S2 hacks that demands more musics.

Using the code shown above as "guinea pig", here's the code for a little music hack I did:
http://www.sonicforc...S/soundplay.txt - the code was compiled and inserted into unused space in ROM, and in $1084 I put a jmp code location.
http://www.sonicforc...JS/soundfix.txt - this is a fix for when musics are played through FFE2 due to SEGA's bad programming, because the funtion at $1376 is supposed to play SE. This will redirect sound requests lower than $A0 to 135E. Just compile and put a jmp code location in 1376. If this fix is not applied, sound $98 will fuck up at certain events when new music is playing. The previous code only sets bank when music is requested at FFE4. This isn't a bad fix, because you can't hear two musics at the same time anyway. :P
http://www.sonicforcecorp.talkhost.info/Er...s2musichack.rar - the ROM, with a new music for testing. First, play all songs from 01 to 1F in Options screen to make sure every original is still there. Then, enter DEZ by any way, or set level RAM address to 0E and play music 0A.

Now, here are the locations for all groups of 9 flags that serves to bank switching:
009Ah: SE
00D2h: DAC
062Ch: SE
06FAh: SEGA
097Bh: SE
0C6Fh: Continue
0C7Fh: Musics
0F3Fh: SE

If you want to make permanent changes in bank switching (in order to reallocate music), do the following:
- decompress sound driver with SDC;
- using a hex editor, go to a flag group location and change them;
- recompress the edited sound driver using SDC;
- put the new compressed sound driver back into the ROM, overwritting the old one in $EC0E8;
- fix the size of compressed sound driver at $EC050;

Side info:
- Z80 RAM's 0000-1FFF is 00474-02473 in GST savestates;
- You can use Korama's GSavestate for easy editing of Z80 RAM;

Special thanks to (no particular order):
drx - hosts Sega2f doc - http://www.hacking-cult.org
R. Solaris - helped me figuring out the meaning of bank switching in Sega2f doc
Tweaker - great music guide, plus sent me a music to test my sound driver experiments
M' (aka Kusanagi) - Portuguese friend. He gave me webspace at Sonic Force Corp.
MSN contacts who played my music hack and didn't leaked it (you know who you are) :thumbsup:

#2 User is offline Varion Icaria 

Posted 19 January 2006 - 07:55 PM

  • He's waiting....
  • Posts: 1004
  • Joined: 26-August 03
  • Gender:Male
  • Project:S4: Cybernetic Outbreak
  • Wiki edits:1
Great job, This greatly helps the community. :thumbsup:

#3 User is offline Tweaker 

Posted 19 January 2006 - 07:59 PM

  • Posts: 12389
  • Joined: 27-June 04
  • Gender:Male
I want your babies.

You need to teach me Z80 some time. SOMEONE, anyway. I'm like useless without. ;_;

#4 User is offline Heran Bago 

Posted 19 January 2006 - 08:00 PM

  • Ah! It's Puyo battle then.
  • Posts: 2949
  • Joined: 11-May 04
  • Gender:Male
  • Location:Foggy California
  • Project:勉強
  • Wiki edits:4
More songs in Sonic 2 = YAY. Kind of a pain to do, especially for those of us who aren't into Sonic Programming, but it's still the poop!

#5 User is offline Sonic Hachelle-Bee 

Posted 19 January 2006 - 08:14 PM

  • Lost in Wood zone
  • Posts: 716
  • Joined: 03-March 04
  • Gender:Male
  • Location:Paris, France
  • Project:Sonic 2 Long Version
This sounds REALLY interesting, really...!
*dream to include brand new musics in my hack, without erasing the others*

Great job.

#6 User is offline LocalH 

Posted 19 January 2006 - 08:36 PM

  • roxoring your soxors
  • Posts: 3147
  • Joined: 11-January 03
  • Gender:Male
  • Location:wouldn't you like to know
  • Project:MDEM - Genesis programming stufz
  • Wiki edits:3

Erik JS, on Jan 19 2006, 08:48 PM, said:

Yes, Z80 can access 68K RAM, but I don't see any practical use for it, as it would limit working space for 68K. I'm not sure about 68K SRAM, but it should be accessible too.

Actually, it's my understanding that reading 68k RAM with the Z80 is unreliable. From Charles MacDonald's docs:
In my own tests, I've been unable to do the following:

 - Read banked 68000 RAM. (returns FFh)
 - Find result of partial writes to the bank address register.
 - Have the Z80 read A00000-A0FFFF through the banked memory area.
   (locks up the machine)

 Steve Snake informed me that reading 68000 RAM is possible, but is not
 a recommended practice by Sega. Perhaps only some models of the Genesis
 allow for it.

I haven't tested it myself, however.

Anyway, awesome job. I knew it was along those lines, and I understood perfectly the manner in which that 8K is banked, but I never could wrap my head around the code that actually made the bank switch. My goal was to put the S3-only music back into S3&K. Perhaps with this information I'll try it again.
This post has been edited by LocalH: 19 January 2006 - 08:39 PM

#7 User is offline Tweaker 

Posted 19 January 2006 - 09:01 PM

  • Posts: 12389
  • Joined: 27-June 04
  • Gender:Male

LocalH, on Jan 19 2006, 08:36 PM, said:

Erik JS, on Jan 19 2006, 08:48 PM, said:

Yes, Z80 can access 68K RAM, but I don't see any practical use for it, as it would limit working space for 68K. I'm not sure about 68K SRAM, but it should be accessible too.

Actually, it's my understanding that reading 68k RAM with the Z80 is unreliable. From Charles MacDonald's docs:
In my own tests, I've been unable to do the following:

 - Read banked 68000 RAM. (returns FFh)
 - Find result of partial writes to the bank address register.
 - Have the Z80 read A00000-A0FFFF through the banked memory area.
   (locks up the machine)

 Steve Snake informed me that reading 68000 RAM is possible, but is not
 a recommended practice by Sega. Perhaps only some models of the Genesis
 allow for it.

I haven't tested it myself, however.

Anyway, awesome job. I knew it was along those lines, and I understood perfectly the manner in which that 8K is banked, but I never could wrap my head around the code that actually made the bank switch. My goal was to put the S3-only music back into S3&K. Perhaps with this information I'll try it again.

It should be quite simple, actually. All you've gotta do is change the loaded banks by the method above. I can locate the pointer index pointer, so the bank stuff should be around there as well.

Then again, Erik would know more, as he disassembled that driver as well.

#8 User is offline jman2050 

Posted 19 January 2006 - 09:02 PM

  • Teh Sonik Haker
  • Posts: 615
  • Joined: 10-December 05
  • Wiki edits:4
Dude, this owns. Knowing how the driver bank switches and crap will help me greatly.
This post has been edited by jman2050: 19 January 2006 - 09:03 PM

#9 User is offline Stealth 

Posted 19 January 2006 - 09:25 PM

  • Posts: 546
  • Joined: 31-July 05
  • Gender:Male
  • Project:HCGE, Project HC, Sonic Megamix, SonED2, [...]
  • Wiki edits:19
Sonic 2 & Knuckles uses the same basic idea (patching over the original program) to play the music and sounds from their offset position. It even runs the original code from the new Sonic 2 ROM space to extract it
00301006 S2K_Sound_Init:
00301006                 nop     
00301008                 jsr     $2EC000
0030100E                 move.w  #$100,($A11100).l
00301016                 move.w  #$100,($A11200).l
0030101E                 lea     ($A00000).l,a1
00301024                 moveq   #$73,d0
00301026                 move.b  d0,$A0(a1)
0030102A                 move.b  d0,$D8(a1)
0030102E                 move.b  d0,$632(a1)
00301032                 move.b  d0,$700(a1)
00301036                 move.b  d0,$981(a1)
0030103A                 move.b  d0,$C75(a1)
0030103E                 move.b  d0,$C85(a1)
00301042                 move.b  d0,$F45(a1)
00301046                 move.w  #0,($A11200).l
0030104E                 nop     
00301050                 nop     
00301052                 nop     
00301054                 nop     
00301056                 move.w  #$100,($A11200).l
0030105E                 move.w  #0,($A11100).l
00301066                 rts     
00301066; End of function S2K_Sound_Init

It's also similar to what I did for Sonic for MegaCD, which, even on the actual hardware, you can at least hear at the title screen and options menus. It'd be working in level mode too if the Z80 actually had proper access to any of the RAM I could store it in (LocalH just partially explained one aspect above; Genesis RAM seems to be one of the hardest places to avoid bus conflicts between the Z80 and 68000), so there's no question that this method works. There's one other aspect that might be important to consider, though, and that is the offsets. Obviously, even if you have the bank address, the program still needs to know where the data you want exists within the bank. It'd probably be just fine if you had a new music listing starting RIGHT at the beginning of a bank (as with the original music set, which you'd be swapping out in this case), but if there were anything before it within the bank, or if you wanted to add a new DAC sample bank or something, you'd need to modify the starting offsets too:

 	 lea	($A007C1).l,a0
 	 move.l	#MusicPoint2,d0;Set offset address of music pointer listing
 	 bsr  SetDataOffset

  lea	($A00985).l,a0
  move.l	#SoundPoint,d0;Set offset address of sound pointer listing
  bsr  SetDataOffset

  lea	($A01233).l,a0
  move.l	#SndDAC_Sample1,d0;Set offset address of the DAC sample
  bsr  SetDataOffset

  lea	($A01237).l,a0
  move.l	#SndDAC_Sample2,d0;Set offset address of the DAC sample
  bsr  SetDataOffset

  lea	($A0123B).l,a0
  move.l	#SndDAC_Sample3,d0;Set offset address of the DAC sample
  bsr  SetDataOffset

  lea	($A0123F).l,a0
  move.l	#SndDAC_Sample4,d0;Set offset address of the DAC sample
  bsr  SetDataOffset

  lea	($A01243).l,a0
  move.l	#SndDAC_Sample5,d0;Set offset address of the DAC sample
  bsr  SetDataOffset

  lea	($A01247).l,a0
  move.l	#SndDAC_Sample6,d0;Set offset address of the DAC sample
  bsr  SetDataOffset

  lea	($A0124B).l,a0
  move.l	#SndDAC_Sample7,d0;Set offset address of the DAC sample
  bsr  SetDataOffset
  rts

SetDataOffset:
  and.l	#$7FFF,d0;Address is an offset from 8000 (Z80's 68K bank access RAM)
  move.b	d0,(a0)+
  lsr.l	#8,d0
  add.l	#$80,d0
  move.b	d0,(a0)+
  rts


An example pulled directly from Sonic for MegaCD. (This should also be done while the Z80 is haulted, obviously). This code takes the location of each of the listed data and generates it's offset within it's bank, and sends it to the appropriate part of the Z80 program. One last important thing to remember is that while compressed songs are loaded to a specific area of Z80 RAM and don't need any pointer changes, sound effects and uncompressed songs are played through the bank area and are not moved, so if they're moved around in the bank, their pointers also have to be updated, not just the offset pointers above. This means that although there's a line included to update the sound effect listing offset, it's rather pointless unless every sound effect has had it's pointers updated

Using this concept to increase the ammount of music you can play back in Sonic 2 could prove to be interesting

#10 User is offline Aurochs 

Posted 21 January 2006 - 12:12 PM

  • Единый, могучий Советский Союз!
  • Posts: 2343
  • Joined: 09-January 05
  • Gender:Male
  • Project:Whatever catches my fancy
  • Wiki edits:325

Tweaker, on Jan 19 2006, 08:59 PM, said:

You need to teach me Z80 some time. SOMEONE, anyway. I'm like useless without. ;_;

I learned it from guides I found on ticalc.org and SMS Power. I recommend either this or this, depending on the format you prefer - the first one is HTML, the second is CHM. You should also get this opcode reference and the official Zilog documentation.

Quote

Yes, Z80 can access 68K RAM, but I don't see any practical use for it, as it would limit working space for 68K. I'm not sure about 68K SRAM, but it should be accessible too.

The SRAM is contained in the address space for the cartridge ROM rather than some esoteric cartridge-switched area, so you can access it from the Z80 side. Be careful though - there's no operating system to throw addressing error exceptions if you try to write to addresses in the cartridge ROM space, so if you actually try to write to a read-only byte, the real hardware will crash while it waits for write confirmation that will never come.

Actually, you can access ANY location in the 68000 address space through the bank - including areas that are already in the Z80 address space. You could even set the bank register to access the Z80 bank. I have no clue what will happen if you do that, but it can't be good.
This post has been edited by Aurochs: 21 January 2006 - 12:29 PM

Page 1 of 1
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users