I asked drx if I could post this publically and he seemed fine with that. Also, this is nothing particularly special and is mainly sound related. Member "IWasAPerson" mentioned on an IRC channel that when he was using the Sonic 32x disassembly for his hack, he had noticed certain bugs related to the sound driver and it's PWM channels. These bugs ranged from co-ordination flags crashing the processor, to not restoring PWM channels after the "1-up" track has been played. I have taken the time to fix these bugs and add/change one or two addition things to it with the help of andlabs' document findings, which some of you who may have been working on the Sonic 32x disassembly, might find interesting and useful. http://mrjester.hapisan.com/01_Public/Sonic32x%20(Plus).rar Bugs, fixes and changes: Flags such as "F2" would increase the stack by 8 and then "return" causing the rest of the sound driver to be skipped and return to the end of the vertical interrupt routine, where there it would load data it stored back out of the stack before returning from the exception routine. The error though was caused because the data in the registers was moved into the stack "before" the PWM routine was ran, and then reloaded out of it "after" the routine was finished, of course, if the flag happened to be F2 or E4, etc, then it would never reload that register data out of the stack. This has now been fixed by removing the stack store/reload instructions (they weren't required luckily). Because of the way the PWM channels were mapped (having PWM1 in DAC slot and the other 3 PWM channels in a dedicated ram space), PWM1 ran through the SMPS engine more or less fine, however the other three did not, certain flags like the life collecting (music save and restore) routines would not store/reload the other PWM channels correctly, but of course, this was unnoticeable in the original Sonic 32x as the only song that really used the extra PWM channels, was 86 (Scrap Brain Zone). The PWM channels have been re-arranged where PWM 1 to 4 have been moved (in order) to $00FFC600, with another 4 slots at $00FFC6C0 for storing the channel data when the extra life track plays, all known bugs have been fixed with all channels. The header format for this version has been changed, see "Readme.txt" for details about the old header format, the new format is as followed: VVVV C1C2 T1T2 PWM1 PPVV PWM2 PPVV PWM3 PPVV PWM4 PPVV FM01 PPVV FM02 PPVV FM03 PPVV FM04 PPVV FM05 PPVV FM06 PPVV PSG1 PPVV TTTT PSG2 PPVV TTTT PSG3 PPVV TTTT The keys are: <!--g1--><div class='geshitop'>Syntax Highlighted Code: ASM</div><div class='geshimain'><!--eg1--><pre class="asm" style="font-family:monospace;"><span style="color: #adadad; font-style: italic;">; VVVV = Voice pointer - Same as Sonic 1's</span> <span style="color: #adadad; font-style: italic;">;</span> <span style="color: #adadad; font-style: italic;">; C1 = FM and PWM counter - Similar to Sonic 1's, this is the counter for</span> <span style="color: #adadad; font-style: italic;">; how many FM and PWM channels in the song, the</span> <span style="color: #adadad; font-style: italic;">; maximum value is "0A" (4 PWM & 6 FM channels)</span> <span style="color: #adadad; font-style: italic;">; if the value is reduced, the 4 PWM channels</span> <span style="color: #adadad; font-style: italic;">; are taken into account first, so having the</span> <span style="color: #adadad; font-style: italic;">; value "08" mean 2 PWM & 6 FM channels, what</span> <span style="color: #adadad; font-style: italic;">; this means is that in order to use the PWMs,</span> <span style="color: #adadad; font-style: italic;">; you need to use all 6 FM channels (or at least</span> <span style="color: #adadad; font-style: italic;">; have a pointer for them in the header, if you</span> <span style="color: #adadad; font-style: italic;">; wish not to use certain FM channels, just point</span> <span style="color: #adadad; font-style: italic;">; them to an F2 flag to stop them.</span> <span style="color: #adadad; font-style: italic;">;</span> <span style="color: #adadad; font-style: italic;">; C2 = PSG counter - Same as Sonic 1's</span> <span style="color: #adadad; font-style: italic;">;</span> <span style="color: #adadad; font-style: italic;">; T1T2 = Tempo/Tempo divider - Same as Sonic 1's</span> <span style="color: #adadad; font-style: italic;">;</span> <span style="color: #adadad; font-style: italic;">; PWM1(-4) = PWM channel pointer - Same as Sonic 1's FM/DAC/PSG pointers, but for</span> <span style="color: #adadad; font-style: italic;">; PWM channels</span> <span style="color: #adadad; font-style: italic;">;</span> <span style="color: #adadad; font-style: italic;">; PPVV (after PWM1(-4) = PWM Setting - Same as Sonic 1's PP (Pitch) and VV (Volume),</span> <span style="color: #adadad; font-style: italic;">; but for the PWM channels</span> <span style="color: #adadad; font-style: italic;">;</span> <span style="color: #adadad; font-style: italic;">; FM01 (and after) = Rest of SMPS - Same as Sonic 1's</span></pre><!--gc2--><!--OyBWVlZWID0gVm9pY2UgcG9pbnRlciAtCQlTYW1lIGFzIFNvbmljIDEmIzM5O3MKOwo7IEMxID0gRk0g YW5kIFBXTSBjb3VudGVyIC0JCVNpbWlsYXIgdG8gU29uaWMgMSYjMzk7cywgdGhpcyBpcyB0aGUgY291b nRlciBmb3IKOwkJCQkJaG93IG1hbnkgRk0gYW5kIFBXTSBjaGFubmVscyBpbiB0aGUgc29uZywgdGhlCj sJCQkJCW1heGltdW0gdmFsdWUgaXMgJnF1b3Q7MEEmcXVvdDsgKDQgUFdNICZhbXA7IDYgRk0gY2hhbm5 lbHMpCjsJCQkJCWlmIHRoZSB2YWx1ZSBpcyByZWR1Y2VkLCB0aGUgNCBQV00gY2hhbm5lbHMKOwkJCQkJ YXJlIHRha2VuIGludG8gYWNjb3VudCBmaXJzdCwgc28gaGF2aW5nIHRoZQo7CQkJCQl2YWx1ZSAmcXVvd DswOCZxdW90OyBtZWFuIDIgUFdNICZhbXA7IDYgRk0gY2hhbm5lbHMsIHdoYXQKOwkJCQkJdGhpcyBtZW FucyBpcyB0aGF0IGluIG9yZGVyIHRvIHVzZSB0aGUgUFdNcywKOwkJCQkJeW91IG5lZWQgdG8gdXNlIGF sbCA2IEZNIGNoYW5uZWxzIChvciBhdCBsZWFzdAo7CQkJCQloYXZlIGEgcG9pbnRlciBmb3IgdGhlbSBp biB0aGUgaGVhZGVyLCBpZiB5b3UKOwkJCQkJd2lzaCBub3QgdG8gdXNlIGNlcnRhaW4gRk0gY2hhbm5lb HMsIGp1c3QgcG9pbnQKOwkJCQkJdGhlbSB0byBhbiBGMiBmbGFnIHRvIHN0b3AgdGhlbS4KOwo7IEMyID 0gUFNHIGNvdW50ZXIgLQkJCVNhbWUgYXMgU29uaWMgMSYjMzk7cwo7CjsgVDFUMiA9IFRlbXBvL1RlbXB vIGRpdmlkZXIgLQkJU2FtZSBhcyBTb25pYyAxJiMzOTtzCjsKOyBQV00xKC00KSA9IFBXTSBjaGFubmVs IHBvaW50ZXIgLQlTYW1lIGFzIFNvbmljIDEmIzM5O3MgRk0vREFDL1BTRyBwb2ludGVycywgYnV0IGZvc go7CQkJCQlQV00gY2hhbm5lbHMKOwo7IFBQVlYgKGFmdGVyIFBXTTEoLTQpID0gUFdNIFNldHRpbmcgLQ lTYW1lIGFzIFNvbmljIDEmIzM5O3MgUFAgKFBpdGNoKSBhbmQgVlYgKFZvbHVtZSksCjsJCQkJCWJ1dCB mb3IgdGhlIFBXTSBjaGFubmVscwo7CjsgRk0wMSAoYW5kIGFmdGVyKSA9IFJlc3Qgb2YgU01QUyAtCVNh bWUgYXMgU29uaWMgMSYjMzk7cw==--><!--egc2--><!--g2--></div><!--eg2--> Pitch modification could only be done by the sample table held at "PWMSamples", which meant if you wanted a sample to play at a different pitch, you'd have to use another slot. This has changed, there is now only 1 slot per sample used (talking about the timpani sample mainly), as the pitch of the samples can be alter to any pitch at start, or even during the music by using the "E9" flag, the "E9" flag has a byte following it to help change the pitch for FM and PSG channels, this now works for PWM channels within reason. The byte following it is a signed value, from 00 to 7F will raise the pitch while FF to 80 will lower it. The signed value is multiplied by 40 and is then added to the sample's main pitch stored in the sample table. So if the value was 03, it would add 00C0 to the sample's pitch in the table for playing. Also by changing the main pitch in the sample table, you can alter the pitches for every pitch setting in the music at once. Technical things to note: The pitch modification was only possible by using a small space in the 32x's frame buffer, the SH2 sources remain unchanged, however the 68k SMPS driver will ensure that the Slave driver will ALWAYS set PWM1 to play sample 00 in the table, PWM2 to play sample 01 in the table, PWM3 to play sample 02 in the table, and PWM4 to play sample 03 in the table. The 68k will load the correct sample table data into the correct PWM table slot for it to read (Basically, table swapping), the reason for this is that the frame buffer space is re-writable and hence allows the pitch to be changed in real time, also it seems the SH2 cannot access 68k ram, which is why that was not used instead. The address for each sample table slot is: Code (Text): PWM1 = $0001FFC0 -> $0001FFCF PWM2 = $0001FFD0 -> $0001FFDF PWM3 = $0001FFE0 -> $0001FFEF PWM4 = $0001FFF0 -> $0001FFFF Remember, to access the addresses via 68k, add $840000 to the address, to access the addresses via SH2, add $24000000 to the address instead. A reminder of the PWM "SMPS" channel addresses are: Code (Text): PWM1 main = $00FFC600 -> $00FFC62F PWM2 main = $00FFC630 -> $00FFC65F PWM3 main = $00FFC660 -> $00FFC68F PWM4 main = $00FFC690 -> $00FFC6BF PWM1 storage = $00FFC6C0 -> $00FFC6EF PWM2 storage = $00FFC6F0 -> $00FFC71F PWM3 storage = $00FFC720 -> $00FFC74F PWM4 storage = $00FFC750 -> $00FFC77F These are stored at the end of the block ram address, so although Sonic 1's levels don't surpass that address, if you make a level design with a lot of blocks, be careful not to surpass that address. The SEGA pcm sample is set to play by the 68k method, I chose to do this because I felt it sounded better than the PWM method =P Finally, the rom built from this will not work on the Gens family of emulators (Including Gens GS), and will only (for now) work on KEGA Fusion, you can find most of the "32x Plus" software changes by searching "Jester Coding" in the main source. I've read in 32x documents that the VDP is less complexe and a bit more simpler than the Mega Drive's VDP, so I may have a look at that and see about improving 32x Plus with more graphical stuff. I credit drx, puto, Upthorn and Hivebrain (those noted in the original disassembly) for their original hardwork in providing a public Sonic 32x disassembly in the first place.
Because the 32X as a whole is more complex and not as well documented... Chilly Willy's SDK should change that soon though? :/
The 32X VDP pretty much outputs a framebuffer, yeah. The problem is that in order to use the 32X, you need to learn how to use the Mega Drive side first...
<!--quoteo(post=575570:date=Apr 6 2011, 09:58 AM:name=Sik)--><div class='quotetop'>QUOTE (Sik @ Apr 6 2011, 09:58 AM) <a href="index.php?act=findpost&pid=575570"></a></div><div class='quotemain'><!--quotec-->The 32X VDP pretty much outputs a framebuffer, yeah. The problem is that in order to use the 32X, you need to learn how to use the Mega Drive side first...<!--QuoteEnd--></div><!--QuoteEEnd--> Well, my toolchain and examples eliminates much of the need to learn about the MD side unless you wish to do more with it. This probably has a problem with Gens GS for the same reason I pointed out the GerbilSoft - look at line 431 in the slave sh2 code: Code (Text): mov.l #_pwmcycle, r0 mov.w #719, r1;727 mov.w r1, @r0 ; set cycle register to 719 ; for 1047 final PWM cycle becomes: 23,01MHz/1047 = 21,977kHz ; for 719 final PWM cycle becomes: 23,01MHz/719 = 32,003kHz The cycle count must never exceed 719 or you'll get noise. But if you look at the code, it still does this: Code (Text): .playsample: mov.b @r1+, r2 mov.l r0, @(PWM_SampleCounter,r14) mov.l r1, @(PWM_SampleAddress,r14) mov #$FFFFFF80, r0 xor r0, r2 mov.l @(PWM_LChVolume,r14), r1 muls r1, r2 mov.l @(PWM_LChLastSample,r14), r1 sts macl, r0 shar r0 shar r0 shar r0 shar r0 mov.l r0, @(PWM_LChLastSample,r14) -ditto for right which is then processed like this Code (Text): mov.w #$400, r1 xor r1, r4 xor r1, r5 xor r1, r6 xor r1, r7 mov.w #$7ff, r1 and r1, r4 and r1, r5 and r1, r6 and r1, r7 mov.w #$200, r1 sub r1, r4 sub r1, r5 sub r1, r6 sub r1, r7 The xor coverts from signed to unsigned samples. The and clamps from 0 to $7FF, and then the sub is a fudge to make it work on Fusion. :specialed: It only works by accident on Fusion... one that may be corrected at any time. I suggest tossing most/all the sound code and rewriting it from scratch to work PROPERLY.
Wouldn't it be easier/better to port the Sonic 1 sounds to the Chaotix sound engine? I don't know if it's better than the Sonic 1/2/3 sound engine, but it must be more compatible with the 32x hardware for obvious reasons.
The Chaotix sound engine is just SMPS with added support for the 32X sound hardware by mixing four channels of samples. It's possible to bring everything over; you just have to know how to make the necessary modifications. See my diassembly and on the subversion and my thread on the Chaotix sample rips (look in my thread list). Tempo's driver is Chaotix's driver + YM2612 DAC. Make of that as you will...
Forgive me if this is a stupid question, but Sonic32x disassembly? What? I've never even heard of Sonic32x.
<!--quoteo(post=581682:date=Apr 25 2011, 03:47 PM:name=Mad Echidna)--><div class='quotetop'>QUOTE (Mad Echidna @ Apr 25 2011, 03:47 PM) <a href="index.php?act=findpost&pid=581682"></a></div><div class='quotemain'><!--quotec-->Forgive me if this is a stupid question, but Sonic32x disassembly? What? I've never even heard of Sonic32x.<!--QuoteEnd--></div><!--QuoteEEnd--> One day in drx land, drx ported S1 to the 32X. The End.
<!--quoteo(post=581700:date=Apr 25 2011, 10:32 PM:name=Polygon Jim)--><div class='quotetop'>QUOTE (Polygon Jim @ Apr 25 2011, 10:32 PM) <a href="index.php?act=findpost&pid=581700"></a></div><div class='quotemain'><!--quotec--><!--quoteo(post=581682:date=Apr 25 2011, 03:47 PM:name=Mad Echidna)--><div class='quotetop'>QUOTE (Mad Echidna @ Apr 25 2011, 03:47 PM) <a href="index.php?act=findpost&pid=581682"></a></div><div class='quotemain'><!--quotec-->Forgive me if this is a stupid question, but Sonic32x disassembly? What? I've never even heard of Sonic32x.<!--QuoteEnd--></div><!--QuoteEEnd--> One day in drx land, drx ported S1 to the 32X. The End. <!--QuoteEnd--></div><!--QuoteEEnd--> And then <a href="http://forums.sonicretro.org/index.php?showtopic=11876" target="_blank">drx posted it on Retro</a> and <a href="http://info.sonicretro.org/Sonic_the_Hedgehog_32X" target="_blank">someone else put it on the Wiki</a>. The real End.
I share the same viewpoint, I'd love to be less limited by pallets too, I could have a go at making some pretty awesome versions of existing art. =P
So shouldn't this updated hack be added to <a href="http://info.sonicretro.org/Sonic_the_Hedgehog_32X" target="_blank">the wiki page</a>? Also, why don't we just open up <a href="http://forums.sonicretro.org/index.php?showtopic=11876" target="_blank">the old topic</a> and throw this topic in there?
<!--quoteo(post=581700:date=Apr 25 2011, 02:32 PM:name=Polygon Jim)--><div class='quotetop'>QUOTE (Polygon Jim @ Apr 25 2011, 02:32 PM) <a href="index.php?act=findpost&pid=581700"></a></div><div class='quotemain'><!--quotec--><!--quoteo(post=581682:date=Apr 25 2011, 03:47 PM:name=Mad Echidna)--><div class='quotetop'>QUOTE (Mad Echidna @ Apr 25 2011, 03:47 PM) <a href="index.php?act=findpost&pid=581682"></a></div><div class='quotemain'><!--quotec-->Forgive me if this is a stupid question, but Sonic32x disassembly? What? I've never even heard of Sonic32x.<!--QuoteEnd--></div><!--QuoteEEnd--> One day in drx land, drx ported S1 to the 32X. The End. <!--QuoteEnd--></div><!--QuoteEEnd--> Not much of a "port" - the only thing the 32X does is play some PCM instead of using the YM2612 DAC... and it doesn't even do that properly.
I've been doing some reading, and apparently rather than using sprites, the 32X VDP just stores the entire screen like an image. For some reason there's only enough memory for 204 lines if you're using high-colour graphics (the remaining 20 have to be duplicates or blank). The 256-colour palette mode would seem to be a better choice, and is the one they used for Chaotix.
That'd take a fair bit less programming I suppose, at least when it comes to changing the art format. Decompressed, it could simply be a byte assigned to a pallet entry per pixel. The hard part would be figuring out how to enable 256 colour mode I suppose, and the pallet format. =P
The only thing I'm not clear on is the exact code for setting registers and transfering data. Everything else is very straightforward.
It's probably going to be weird to bump this dead thread, but the code to play PWM samples does not work on real hardware (or emulators such as Gens/GS), all it does is freeze the game. Using the debugger, it seems to freeze at these sets of instructions. Code (Text): @PWM_ACK1 move.w ($A15128).l,d0 and.w #$8000,d0 beq.s @PWM_ACK1 ;and.w #$1F00,d1 ; Clear PWM command moveq #0,d1 move.b (sp)+,d1 move.b d2,d4 btst #6,d3 bne.s @RightPan clr.b d4 @RightPan move.w d4,($A1512A).l ; Set volume to... this lsl.w #8,d1 ; Multiply channel ID by $100 or.w #$1004,d1 ; Set left volume move.w d1,($A15128).l ; Send command to PWM
I assume it will be the stack access. In that very subroutine there are three bytes moved to (and restored from) the stack, one byte at a time: Code (Text): move.b d0,-(sp) move.b d1,-(sp) move.b d1,-(sp) Code (Text): move.b (sp)+,d1 Code (Text): move.b (sp)+,d1 Code (Text): move.b (sp)+,d0 I don't have the hardware setup to test, but changing these to word (.w) will eliminate one issue at least. The subroutine is a mess though, there appears to be one extra stack write/read for some unknown reason.