Fixing the Sidmania demo

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Fixing the Sidmania demo
by on (#182610)
After a lot of work and general examination (bsnes-plus's trace logger was a godsend), I've managed to figure out why the initial text and Censor logo appear corrupted on some emulators (ex. SNES9x) and on SD2SNES. I spent a lot of time comparing VRAM dumps between SNES9x and bsnes-plus (the differences were huge, but then some parts matched up). This was confusing at first -- and I put about 12 hours into the task of RE'ing it -- before going to bed and having a minor epiphany while falling asleep: "were VRAM updates being done inside VBlank? I don't remember seeing them wait for VBlank. Check that tomorrow".

Sure enough, the initial VRAM population were being done regardless of VBlank. This includes all BG1 and BG2 CHR data (BG1 = Censor logo, BG2 = ASCII text overlay), as well as BG1/BG2 screen/layout data. Purely because of timing/luck a bunch of the VRAM update routines were being done "partially" inside VBlank, and partially outside. Forced blanking would fix this problem, especially so early on -- and the demo does set $2100 gradually (from $00 to $0F, for a fade-in) on its own. But setting $2100 = $8F is required per official Nintendo documentation, surely they didn't omit this?

This is a mode 20 demo. The reset vector is $8000. The code at $008000 is nothing more than jml $168000. The code at $168000 contains what looks *almost* like the per-official-documentation initialisation code. Here it is:

Code:
008000 jml $168000   [168000] A:0000 X:0000 Y:0000 S:01ff D:0000 DB:00 nv1BdIzc V:  0 H: 46 F: 0
168000 clc                    A:0000 X:0000 Y:0000 S:01ff D:0000 DB:00 nv1BdIzc V:  0 H: 54 F: 0
168001 xce                    A:0000 X:0000 Y:0000 S:01ff D:0000 DB:00 nv1BdIzc V:  0 H: 58 F: 0
168002 sei                    A:0000 X:0000 Y:0000 S:01ff D:0000 DB:00 nvMXdIzC V:  0 H: 61 F: 0
168003 phk                    A:0000 X:0000 Y:0000 S:01ff D:0000 DB:00 nvMXdIzC V:  0 H: 65 F: 0
168004 plb                    A:0000 X:0000 Y:0000 S:01fe D:0000 DB:00 nvMXdIzC V:  0 H: 70 F: 0
168005 rep #$20               A:0000 X:0000 Y:0000 S:01ff D:0000 DB:16 nvMXdIzC V:  0 H: 77 F: 0
168007 lda #$01fd             A:0000 X:0000 Y:0000 S:01ff D:0000 DB:16 nvmXdIzC V:  0 H: 83 F: 0
16800a tcs                    A:01fd X:0000 Y:0000 S:01ff D:0000 DB:16 nvmXdIzC V:  0 H: 89 F: 0
16800b lda #$0000             A:01fd X:0000 Y:0000 S:01fd D:0000 DB:16 nvmXdIzC V:  0 H: 92 F: 0
16800e tcd                    A:0000 X:0000 Y:0000 S:01fd D:0000 DB:16 nvmXdIZC V:  0 H: 98 F: 0
16800f sep #$30               A:0000 X:0000 Y:0000 S:01fd D:0000 DB:16 nvmXdIZC V:  0 H:102 F: 0
168011 stz $2101     [162101] A:0000 X:0000 Y:0000 S:01fd D:0000 DB:16 nvMXdIZC V:  0 H:107 F: 0
168014 stz $2102     [162102] A:0000 X:0000 Y:0000 S:01fd D:0000 DB:16 nvMXdIZC V:  0 H:115 F: 0
168017 stz $2103     [162103] A:0000 X:0000 Y:0000 S:01fd D:0000 DB:16 nvMXdIZC V:  0 H:122 F: 0
16801a stz $2104     [162104] A:0000 X:0000 Y:0000 S:01fd D:0000 DB:16 nvMXdIZC V:  0 H:130 F: 0
16801d stz $2104     [162104] A:0000 X:0000 Y:0000 S:01fd D:0000 DB:16 nvMXdIZC V:  0 H:147 F: 0
168020 stz $2105     [162105] A:0000 X:0000 Y:0000 S:01fd D:0000 DB:16 nvMXdIZC V:  0 H:155 F: 0
...

$2100 isn't being set until later on. If I set a write breakpoint on $2100, this is the result:
Code:
Loaded Sidmania.
Breakpoint 0 hit (1).
16825d sta $2100     [162100] A:3c01 X:0000 Y:0000 S:01fc D:0000 DB:16 nvMXdIzC V:231 H:310 F:15

That's smack dab in the middle of the fade-in and fade-out routine (which also has some support for setting $2100 = $80, but I haven't sat down to fully understand the "logic flow" of the routine).

Patching the game to use a reset vector of $FC00, then adding some code there (file offset $7C00; .sfc file, not .smc) was easy: clc / xce / sei / sep #$30 / lda #$8f / sta $2100 / jml $168000. The results in SNES9x debugger are attached.

I believe the reason it has worked on older copiers (SWC DX32, etc.) is because those probably pre-init $2100 (and certainly other registers) to $8F (or maybe just $80) prior to actually mapping the ROM address-line-wise + jumping to reset vector. SD2SNES and emulators showing garbage is 100% legitimate -- the core issue is that forced blanking wasn't set, or another way of looking at it is that VRAM update routines weren't waiting for VBlank (using forced blanking is a lot easier to solve this problem).

There's a lot more work to do on this, including figuring out why the starfield graphics during the actual Sidmania part are all garbled/messed up (I'm thinking similar issues, re: doing VRAM updates outside of VBlank, or memory that is being pre-used/pre-initted by the previous phase of the demo, or some mode 7 registers not being initialised correctly/inconsistently), but hey, one thing at a time.
Re: Fixing the Sidmania demo
by on (#182611)
tl;dr: The homebrew demo Sidmania for Super NES fails to disable rendering before uploading data to VRAM.
Re: Fixing the Sidmania demo
by on (#182613)
Strangely, my copy of the demo appears to work totally fine on my sd2snes, Snes9x 1.54, and bsnes-plus (and the latest revisions of the latter randomize the PPU state, VRAM, etc. at boot time using the same method as higan, specifically to flush out issues like this).

I haven't done any actual stepping through to see if it's doing anything more correctly than your copy was, but just in case, here's the one I was running:
https://dl.dropboxusercontent.com/u/431 ... DMANIA.sfc

(An unrelated "fix" just for fun: the PAR code 00AF303E with this copy will make the DSP use a much better-sounding noise frequency setting.)
Re: Fixing the Sidmania demo
by on (#182614)
The version of Sidmania you have is substantially different than the one I have: there are 24639 differences (fc /b yours mine | find /c ": "). So, it looks like there are multiple versions of this demo floating around. I have what is most likely the very first release (which came in SMC format, so to make the SFC I just nuked the first 512 bytes). Here's mine, for what it's worth:

https://www.dropbox.com/s/b13wdv9spzgqc ... a.sfc?dl=0

And the MD5s of all those, including the original SMC version:

Code:
a2b37676eeb8e58e47b307242954d02c *SIDMANIA.sfc -- Revenant
293970ccf6117df3b1348b91307b888d *SIDMANIA.sfc -- koitsu
c12d3cc70daafbc693634768cfba26f8 *SIDMANIA.smc -- koitsu (original SMC version)


Edit: more details:

* In SNES9x debug (Geiger), yours has the same problem as mine (corrupted graphics in the Censor/text intro)
* In SNES9x 1.53 (64-bit builds here -- I got this link from here), yours has the same problem as mine (corrupted graphics in the Censor/text intro)
* On SD2SNES, yours has the same problem as mine (corrupted graphics in the Censor/text intro -- the corruption changes between power cycles)

Thus, I think the differences are therefore most likely in the actual "Sidmania" part, rather than the Censor logo + text intro portion. A very quick "review" of the fc /b differences (file offsets) shows that to be true.

Testing yours during the actual Sidmania part -- the graphical corruption and slowdown depicted here is fixed.

So, this thread still stands valid -- bugs in the Censor/text intro phase prior to the Sidmania portion of the demo. :)
Re: Fixing the Sidmania demo
by on (#182615)
I checked some more, and yours is the same as the version that was always available on Censor's old site, with the original NFO and all that. Mine is the one currently linked to on Pouet, but doesn't include anything but the ROM itself. No idea where this one may have originally come from.
Re: Fixing the Sidmania demo
by on (#182616)
One thing to keep in mind on these sorts of fixes, bsnes/accuracy or higan initializes all registers and memory as randomly as possible. This is really overly aggressive but the goal is to catch these sorts of potential bugs and ensure the system is initialized fully for new homebrew being developed. But it plays poorly with older homebrew.

When you run something like the sd2snes, Super UFO, SWC DX2, etc ... those are running SNES code that is setting up certain register/memory states. So you can't trust them either. The initialization patterns of real hardware registers, unassisted by flashcarts/copiers, isn't fully mapped out. So it's best to err on the side of caution here.

Also worth noting, bsnes/balanced and bsnes/performance don't do this heavy-handed register randomization. You shouldn't use those for this kind of testing if possible.
Re: Fixing the Sidmania demo
by on (#182619)
byuu wrote:
One thing to keep in mind on these sorts of fixes, bsnes/accuracy or higan initializes all registers and memory as randomly as possible. This is really overly aggressive but the goal is to catch these sorts of potential bugs and ensure the system is initialized fully for new homebrew being developed. But it plays poorly with older homebrew.

Yes, I'm aware of this behaviour, which is fine -- we agree that the power-on states of WRAM etc. are variable based on physical characteristics that are beyond an emulator's control, and are mostly unpredictable (or bare minimum, cannot be relied upon). Again: I'm fine with it.

However, what made my life a living hell was the fact that because of that, I couldn't do something like, oh, compare WRAM dumps between SNES9x and bsnes-plus when both emulators had the same breakpoint set. In other words: the fact that I can't toggle this behaviour makes troubleshooting things like this painful. (That said, I get the impression SNES9x does some kind of pre-initting as well -- and I would tell them the exact same thing :-) )

I have other gripes/bitches about bsnes-plus v073+2 -- which isn't your problem because it's a fork -- but the list keeps growing. The 3 that drove me batshit were how, in the Properties dialog:

1. BG VRAM addresses (ex. $2107 to $210a bits 7-2) were shown in bytes not words (ex. $7000 instead of $3800) -- I kept wondering why all the values were 2x larger than what I expected. It's a matter of preference which is "accurate"; IMO, I'd show both, but with notation of words vs. bytes for both,
2. BG sizes (ex. $2107 to $210a bits 1-0) depicted are backwards or wrong: they should be WxH, yet %10 is shown as 64x32 when in fact it's 32x64 (%10 = "long vertical screen", i.e. horizontal mirroring; %01 = "wide horizontal screen", i.e. vertical mirroring),
3. There was a CPU or PPU MMIO register which wasn't being tracked. Now I'm annoyed because I didn't write down which register it was! :(

It's still substantially better than what you get in SNES9x debugger (Geiger), for the most part.

byuu wrote:
When you run something like the sd2snes, Super UFO, SWC DX2, etc ... those are running SNES code that is setting up certain register/memory states. So you can't trust them either. The initialization patterns of real hardware registers, unassisted by flashcarts/copiers, isn't fully mapped out. So it's best to err on the side of caution here.

Correct. My point is that this demo was developed during the time where the SMC, SWC DX, SWC DX32, MGH, and Super UFO were in existence (SWC DX2 (64mbit) hadn't come out yet -- that wasn't until maybe late 1996). The bug I found was never noticed (presumably until now) because for whatever reason those copiers likely "pre-init" SNES registers to some values prior to (in layman's terms) "switching control over to the ROM". It could also be an effect of all of them having menuing systems (vs. a raw EPROM/EEPROM cartridge). In other words: I am in full agreement with you.

I myself didn't write flawless homebrew code in the 90s either, so I'm not chastising Geggin/Alfatech in the least. We wrote all this stuff with the tools and devices/hardware we had available at the time (read: no emulators, no hardware ICE, and dev usually consisted of copying files onto floppy disks + seeing results + rinse lather repeat a thousand times, all alongside makeshift documentation + REing efforts. The floppy disk aspect, BTW, is why we often didn't pad ROM sizes -- it would add literally minutes to each trial/test run due to floppy speed, and it wasted hard disk space (many of us back then only had 20-40MB hard disks, if at all!)). I often have to remind people of this fact, as many people involved in "SNES stuff" in the past ~15 years were not around back in 1994. Bugs are bugs though.

byuu wrote:
Also worth noting, bsnes/balanced and bsnes/performance don't do this heavy-handed register randomization. You shouldn't use those for this kind of testing if possible.

Again, not your problem, but: bsnes-plus gives you two binaries: bsnes.exe and bsnes-accuracy.exe. The former works (but what it's built with/what profile it's using I don't know, but it does randomise WRAM and registers), and bsnes-accuracy.exe crashes on startup. I don't run "official" bsnes/higan because of the debugger need and the file format/manifest ordeal (refuse to get into that again).
Re: Fixing the Sidmania demo
by on (#182623)
I didn't want to turn this thread into emulator chat, so I responded to some of koitsu's post in the actual bsnes-plus thread.

Anyway, it's interesting that my version of the ROM still has problems on the opening screen when you run it. I tried it in higan, Geiger's (1.51.ep10r2) and on the sd2snes (including resetting the console about a dozen times) and it still looked totally fine every time.
Re: Fixing the Sidmania demo
by on (#182630)
> However, what made my life a living hell was the fact that because of that, I couldn't do something like, oh, compare WRAM dumps between SNES9x and bsnes-plus when both emulators had the same breakpoint set.

I have a toggle setting that disables the randomization for the purposes of TAS, netplay, and debugging these sorts of issues (well, as long as toggling it doesn't mask the issue.)

I don't know if it's exposed in an emulator that forked off from my branch five years ago, though.

> I get the impression SNES9x does some kind of pre-initting as well

It sets all the memory to 0x55. The registers are mostly zero-initialized with a few key exceptions. But for the most part, Snes9X chooses defaults to maximize compatibility with commercial games that are also notoriously bad about initializing the full system state upon reset.

> It's still substantially better than what you get in SNES9x debugger (Geiger), for the most part.

Definitely. Very happy that we were finally able to push his selfishly closed source fork out of relevance.

> My point is that this demo was developed during the time where the SMC, SWC DX, SWC DX32, MGH, and Super UFO were in existence

We had this discussion around one of your early demos.

I agree with you. There's no sense blaming demo authors for things they didn't know about and couldn't have controlled. I've made the very same mistakes myself with my fan translations from '98 - '03.

As long as you aren't demanding I support these games now, then I have no objections. I like your idea of going back and fixing these things. Even if a lot of these are just demos, they're pretty cool and it'd be a shame to lose the early history of SNES homebrew to time. My main concern is getting all of these fixes organized somewhere. RHDN won't even allow hex_usr's patch that fixes critical bugs in the Dragon Quest 1&2 fan translation. The author is regrettably deceased so we can't ask him to put out a new build. So we are in need of a less stubborn site to host things like this so that they aren't lost.

... of course, a really simple idea would be to emulate the SWC DX2 BIOS. That could be pretty fun. Homebrewers being silly with copier I/O registers could create the SFDS :P (joking of course)

> It could also be an effect of all of them having menuing systems (vs. a raw EPROM/EEPROM cartridge)

That is the reason why, yes. You can actually just write #$0f to $2100 on the Super UFO 8.3j and see the "Now Loading ..." UFO screen appear again. It would have been an amusing copy protection if a game dev tried to check dirty WRAM/VRAM for evidence of a specific copier type ;)

> and the file format/manifest ordeal (refuse to get into that again).

That's a shame, because you've been able to load ZIPped images with the SMC/SWC extension inside and copier headers present without any manifest whatsoever for quite a while now in higan.

I agree completely on the debugger. I'm unable to come up with a debugger that I can tolerate maintaining (especially as I now emulate 6+ separate systems and they all need debuggers), but it's an essential thing for devs to have.
Re: Fixing the Sidmania demo
by on (#182641)
byuu wrote:
I have a toggle setting that disables the randomization for the purposes of TAS, netplay, and debugging these sorts of issues (well, as long as toggling it doesn't mask the issue.)

I don't know if it's exposed in an emulator that forked off from my branch five years ago, though.

I provide the setting as well, though currently it's only available in the .cfg file and not the GUI.