Original Post

The last few days I’ve been fooling around with the debug modes in a few Virtual Boy games.

The biggest discovery was that Vertical Force’s debug menu is fully accessible in the retail game without hacking. I was also able to make a tiny bit of progress getting SD Gundam’s debug menu up, and lastly I made a small custom patch to change how the Virtual Bowling debug menu is launched. I want to give Parasyte huge credit for the Vertical Force discovery and my little Bowling mod, as both relied heavily on that original hacking work done some 20 years ago.

Vertical Force
Notably, Parasyte predicted in the readme for the original debug mode hack that, given its high-quality presentation, the menu might be accessible in-game. Well, it’s nice to know that hunch was right, all these years later! To access the debug menu, open the Config menu then press the following sequence of buttons:

  • Left D-Pad Left
  • Left D-Pad Left
  • Right D-Pad Right
  • Right D-Pad Right
  • Left D-Pad Up
  • Right D-Pad Down
  • Left D-Pad Up
  • Right D-Pad Down
  • L
  • R
  • Right D-Pad Right
  • Right D-Pad Right
  • Left D-Pad Left
  • Left D-Pad Left
  • Right D-Pad Up
  • Left D-Pad Down
  • Right D-Pad Up
  • Left D-Pad Down
  • R
  • L

If you don’t want to remember all that, there’s obviously Parasyte’s existing hack here on virtual-boy.com, which forces the debug menu to load on startup. Alternatively, there’s now a patch on The Cutting Room Floor’s Vertical Force page which replaces this button sequence with a single press of Select on the Config screen.

SD Gundam: Dimension War
It’s been known that SD Gundam has some sort of stage select for a while now, but as far as I know nobody has managed to trigger it in-game. I wasn’t able to get the menu working, but I did manage to get it to at least load and display on-screen.

The function at 41EE8 in the ROM is responsible for the debug menu. I wasn’t able to find if there’s anywhere in code which jumps to this function, but I’m just goofing around in an emulator. Somebody more capable (and with access to a disassembler?) may very well be able to take this further and get the debug menu fully working.

That said, you can force the game to jump to this function to at least see the menu, albeit without it actually functioning. Editing offset 7FD0 in the ROM from 01 AC E4 FE (jal fff27eb4) to 03 AC 18 9F (jal fff41ee8) will replace the main menu screen with the “SELECT GAME MODE” menu. From here, you can’t really do anything. A/Start will boot the game, but it’s not otherwise possible to navigate the menu or do anything useful. I’ve attached a screenshot of this menu, since looking at a screenshot is about as good as doing it for real with this half-baked modification.

I haven’t bothered making an IPS patch for this change because it’s basically useless, but I think it’s very likely somebody knowledgeable could get it into a completely working state. Who knows, it could even be like Vertical Force where the debug mode is accessible without hacking but nobody’s figured out how to open it yet.

EDIT: I finally managed to figure out Bob Vanderclay’s V810 Disassembler and got SD Gundam disassembled. I can confirm that there are no jumps to the debug menu function anywhere in the game (unless they’re obfuscated, but I’ll get into why I think that’s unlikely). What there is, however, is a dummy function at 7B8C which immediately jmp [lp]s, i.e. calling the function simply returns. There are also 28 calls (!) of this function scattered throughout the game’s program, including in conspicuous places like the start of the main menu function. Every single one of them is additionally stepped over with a jr, so the dummy function itself is never actually called.

My supposition is that the central portion of the game’s debug code lived in this function, which was compiled out for retail. This function would have handled jumping off to the various debug functions based on what functionality was called for at any given point in execution. This means it’s substantially more difficult for debug to be re-enabled in the retail build, because whatever this function used to do is completely opaque to us from the perspective of the final build. Depending on how thoroughly the rest of the debug code was scrubbed, it could be theoretically possible to restore the functionality by reproducing this function blind, but that would be a huge undertaking and require somebody with much greater ability than I have. Sorry for the downer result!

Virtual Bowling
This one is probably the least interesting, but I made a small hack to adjust how the debug menu is launched in Virtual Bowling. Parasyte’s patch here on virtual-boy.com simply forces the debug menu to open on start-up. This sort of means you need to keep two separate Virtual Bowling ROMs around depending on whether you want debug today or not. My modified patch instead checks whether you’re holding the Select button on start-up. If you are, the debug menu is triggered, otherwise the game boots normally. You can download this modified patch from The Cutting Room Floor’s Virtual Bowling page.

  • This topic was modified 3 months, 2 weeks ago by Vague Rant.
81 Replies

Thanks for the vast explanation.
I will try to test some of them on Thursday.
I will also upload one or two fresh save states.

I have also postponed my reprocard-order for games with save feature (seeing the constant updates it is too risky at the moment in my opinion).

Thanks, much appreciated.

And yep, that seems very wise. For one, I’ve never done any Virtual Boy hacking before or really any assembly hacking on this scale. I’m basically learning as I go doing these patches. Plus I have barely any familiarity with the games themselves. I had fooled around in Mednafen back in the day, but really only played the games properly since the release of Floogle’s Red Viper for 3DS. Add to that that as far as I know, only you (with a HyperBoy) and speedyink (with a HyperFlash32) have tested any of these on real hardware and it’s a recipe for disaster. 😀

I tried to delete my save in Mario Clash (with the 1.3. patch file applied) but the combo L+R+ L-dpad down+R-dpad down doesn´t do anything in the game.

EDIT: save patch 1.5 for Jack Bros seems to work, the one for Red Alarm (version 1.4) not, at least I have no hi-score in the title screen after restarting the system. The level (= difficulty) and display options are also not saved anymore.
I attached a clean save for this version, at least there the combo restarted the game, so I assume that it worked here.

EDIT2: somehow my post didn´t show up.

EDIT3: space squash still does not work. Now neither the progress nor the high score is saved. I have attached a clean save.

EDIT4: V-Tetris save patch seems to work.

  • This reply was modified 2 months, 3 weeks ago by abarth.
  • This reply was modified 2 months, 3 weeks ago by abarth.
  • This reply was modified 2 months, 3 weeks ago by abarth.

Well, for whatever it’s worth, save initialization is working correctly now, but I don’t understand why it broke everything else in some titles. Regrettably, I don’t really see a path forward from here. I have absolutely no grasp of how those changes could have broken saving entirely in titles like Red Alarm and Space Squash. This represents the entirety of the changes made to Space Squash:

diff --git a/sposh-save.asm b/sposh-save.asm
index 99a89bc..3b44b05 100644
--- a/sposh-save.asm
+++ b/sposh-save.asm
@@ -335,10 +335,11 @@ CLEAR_SRAM:
?mov CHECKWORD, r9
ld.w 0x0000[r9], r9
movhi 0x600, r0, r6
- movea 0x4000, r0, r7
+ mov 1, r7
+ shl 15, r7
- st.w r0, 0x0000[r6]
- add 4, r6
+ st.b r0, 0x0000[r6]
+ add 2, r6
add -1, r7
?mov CHECKWORD, r9
@@ -537,7 +538,7 @@ ERASE_CHECK: ; r10 is free
cmp r6, r7
movhi 0x600, r0, r10
- st.w r0, 0x0000[r10]
+ st.b r0, 0x0000[r10]
?pop r7

Without really needing to be able to read code, what this means is that I changed one instruction that loaded the value 4000 into two instructions that load 8000, changed two previously non-functional store words (st.w) into store bytes (st.b) and in line with that change am cycling through SRAM 2 bytes at a time instead of 4. These are extremely minor changes in the code which clears out SRAM on first boot, with no relation to any of the actual saving or loading behavior.

I simply have no idea what could be going wrong here and not even any theories I can explore. I don’t really have any other option but to hope that somebody else can understand why these issues are occurring. At least all of the work up to this point has been open source, so if a capable VB hacker wishes to look into them they may be able to fix these problems.

That is really unfortunate.
Do you think your previous working versions (like for Red Alarm) will somehow stop working when you continue using them on real hardware because the SRAM clearance is somehow different to the “normal” procedure? To put it in other words: what is wrong with using the 1.3 safe patch for Red Alarm?

Without any understanding of why changing a failed st.w to a successful st.b completely breaks all saving across the board, I can’t really advise whether the old versions which fail save initialization are truly functioning correctly. The 4000 failed writes which occur on boot in the old versions might accidentally be fixing something but also accidentally breaking something else. With zero knowledge of what the problem is, unfortunately I also have zero knowledge of the solution.

EDIT: Probably a long shot, but the Sacred Tech Scroll claims that 8 dummy reads of WorkRAM are required before WorkRAM will begin functioning correctly. This is apparently an error Nintendo themselves believed (their software, e.g. Mario Clash, also performs these dummy reads) but according to pizzarollsroyce, it’s instead the VIP’s DRAM which requires these dummy reads, and either way the hardware handles performing them anyway.

All that said, KR155E directed me to VUEngine’s SRAM handler, which similarly performs 8 dummy reads of SRAM before it starts accessing it for actual use. There’s no reference to such a requirement in the Tech Scroll or anywhere else I’ve been able to read, but it can’t hurt. I’m attaching a new build of Red Alarm, since it’s probably the easiest one to confirm whether or not saving works (easy to get a high score of 100 points or adjust the depth/brightness, etc.). This version performs 8 dummy reads of SRAM on startup, similar to VUEngine software. This is a bit of a hail Mary; I have a low degree of confidence in this making a difference, but it was easy to implement, so if it makes a difference then that’d be nice.

EDIT2: Actually, I may see an issue in the Red Alarm patch. Attachment removed for now, I wish to investigate this a bit more before I ask you to test.

EDIT3: For now I’m attaching two alternate versions of the Space Squash patch which I’d appreciate if you could test. One implements the 8 dummy reads and one implements a 200μs delay before it starts reading SRAM, the two requirements Nintendo lists for accessing WRAM. If either of them makes a difference to your ability to save on real hardware, that would be great news, but it’s hard to say how likely it is they’ll do anything.

EDIT4: I have at least half of a theory of what’s going on but not the whole of one. The first thing I do on startup is check that there is a valid save for the current game in SRAM. If there is, execution continues normally. If there is not, we jump out, erase the entire SRAM and start over. In old builds, this erasure step was not functional on HyperBoy and similar carts due to use of store word instructions. This meant that whether or not my hack detected a valid save, the save would never be erased either way. Since I fixed the save-clearing function by using store byte instructions only, the save-erasing step now works as expected.

However, it seems that the initial check of SRAM has actually been failing this entire time on HyperBoy hardware. That wasn’t clear because instead of the save being erased, the hack would try to erase the save, fail and continue on to the initialization step (e.g. in Space Squash, copying over the default high scores, hence why yours vanished). This would leave your save in a partially initialized state, with your high scores replaced but your game progress intact because of the failed SRAM clear. Now that the SRAM clear is working correctly, it has become clear that SRAM is getting cleared on every boot for at least some games, hence why you cannot save at all any more in Red Alarm or Space Squash. The question now is why the SRAM check fails every time. Hopefully, it’s just some arbitrary requirement to access SRAM like the 8 dummy reads or the 200μs delay. If not that, then we’re back to square one with no idea why the check fails.

Nice seeing you not giving up!
I have tested both 1.1 patches for Space Squash.
Sadly they do not work correctly. The progress is saved (so you can continue the game from the last beaten area), but the highscore is not being saved.
I have attached the save file of the dummy test if this can further help you.

What’s most interesting in the new save is that it’s still not entirely cleared out as I thought it would be with the fixed initialization. The first 0x243 bytes have not been cleared out as they should be, but everything after that has. The switch from word- to byte-based clearing has helped–about half as much of the save is still uninitialized compared to the original save you shared. The byte-based method is slower, which I suspect might be related here. If we assume that SRAM only starts responding correctly after some specific unknown period of time, that would explain the different result: the first 0x243 (about 600) st.bs are failing, then the SRAM finally wakes up and the other … 0x7DBD (about 32,000) writes work correctly. If that’s the case, the solution might just be to keep increasing the delay before we start accessing SRAM until it works. The “delay” patch from yesterday was 200 microseconds, but if time is the deciding factor, then that wasn’t a long enough wait before we started accessing SRAM.

These are all pretty small periods of time we’re talking about; 200 microseconds is 0.0002 of one second, so we can probably afford to push it pretty high before it becomes noticeable. Doing the math, with my current approach it should take about 174 microseconds to write out those 0x243 bytes. Before that is the SRAM check, so we need to factor that into the delay as well. The very first read from SRAM is checking the validity of the very first byte which is another ~36 cycles before we start writing. Adding that too, we’re still only at about 176 microseconds, so in theory the 200μs delay should have been enough, unless it’s a situation where you have to wait 200μs after the first access?

OK, I guess that’s enough theories for another test. I’ve been a broken record with this, but thanks so much for your patience with me, you’re doing the whole VB scene a huge favor by helping to resolve these issues.

I’m going to attach two new patches.

One of them has the dummy reads followed by a 200μs delay, in case the setup process is “wake SRAM up, wait 200μs, then start reading/writing”.

The second one just has a 1500μs delay with no dummy reads, in case this is purely a timing thing and the dummy reads are irrelevant.

I don’t think you should need to test progress again (and I know it’s a hassle to test that in Space Squash since it takes a pretty long time to clear an Area). It should be enough to test the Config Menu: turn off BGM, set the difficulty to Hard, change the Match points, etc. and see if that gets retained across boots. Similar to high scores, the config gets reset back to the defaults when the save is initialized, so if you can retain that, it should mean that high scores are also working.

Sharing your saves is definitely very helpful, so regardless of whether either of these patches help, it’d be good to see the SRAM files for them. Thanks again for all your help.

Glad I can help! I have only recently discovered the VB 5 months ago and this little console already conquered my heart.

So the test results are the following:
– 1500 delay: config changed was saved after restart. highscore (with your cheat patch applied) is saved, continue works also!
– 200 delay and dummy: config is not saved after restart. no further tests conducted.

So 1500 delay looks promising!

I have attached both save files.

Fantastic, now we’re getting somewhere!

The only thing really remaining to discover is exactly how long a delay is needed. I chose 1500 as a random “long” delay (if you consider 0.0015 seconds a long time). The real delay is presumably somewhere in-between 200 and 1500 microseconds.

I’m attaching a little homebrew app which simply writes out 255 bytes in a row, waiting 100 microseconds between each byte, so its total runtime is roughly 0.03 seconds–essentially instant. It doesn’t display anything or make any sounds, just writes out those first 255 bytes in a fraction of a second. If you could run this app, dump your save, then do it again a couple more times just to catch any minor variations (so 3 different saves), we should be able to get a solid idea of how long the Virtual Boy needs to wait before it starts writing to SRAM after powering up. We’ll probably be the first people outside of official developers to know this information, since it’s not documented anywhere. 😀


attached you´ll find the saves. hopefully it worked. I created 5 files.

Great work, thanks very much! It did indeed work perfectly. Better than I expected, even. I can see that there is some slight variation in how long it takes for SRAM to be accessible. After a 100-microsecond wait, only 2/5 saves wrote out correctly. After 200 microseconds, they actually all wrote out correctly. We already confirmed 200 wasn’t quite reliable though, since in multiple tests that was not a long enough wait for Space Squash to save correctly. That probably means 200 is right on the borderline. This could mean 300μs would be safe across the board, since we’ve seen no evidence so far of SRAM failing after 300μs. Throw in a bit of buffer for “in case of emergency” and maybe we can settle on about a 500μs wait just to be safe. It’s late here but tomorrow I’ll start on implementing the delay into the existing patches. It’s easy enough to adjust the delay later if it turns out we need more/less. Thanks again and excellent work!

Cool! Looking forward to your updated patches.
BTW, I have ordered a Golf reprocard with SRAM feature enabled since this patch should have worked from the beginning.

OK, I’ve got some of the patches onto the new 500us-delay setup. The most important ones for now are Red Alarm and Space Squash, since we were having problems with those previously. Especially for Space Squash, it would be a huge help if you could upload a fresh save just so I can make sure it’s still clearing out SRAM correctly after reducing the delay from 1500us to 500us.

I tried to delete my save in Mario Clash (with the 1.3. patch file applied) but the combo L+R+ L-dpad down+R-dpad down doesn´t do anything in the game.

I’ve also just tried to fix this by using a different method to soft reset Mario Clash when you press the SRAM clear combo on the title screen, so I’m attaching that as well. The button combo is still the same and it’s still on the title screen (with the PUSH START BUTTON text, etc.). Mario Clash now also has the 500us delay like the others, but that’s purely for cautionary reasons since the game never had any trouble saving anyway, other than from bugs in the high score saving that were fixed a while back.

BTW, I have ordered a Golf reprocard with SRAM feature enabled since this patch should have worked from the beginning.

Nice! Should make a really unique addition to your collection!

Test results:
space squash 500 µs with cheats applied: config change is not being saved. test aborted.
red alarm (japanese version) with patch 1.4 applied: config settings (like level and depth) are saved, highscore also.
mario clash with 1.3 patch: progress and highscore is saved, sram erase function works.

i have attached the save files, mario clahs as clean save after sram clerance.

EDIT: would you mind looking into a possible save patch for Bound High?
EDIT2: and perhaps for Nester´s Funky Bowling if you have time and are motivated 😉 ?

  • This reply was modified 2 months, 2 weeks ago by abarth.
  • This reply was modified 2 months, 2 weeks ago by abarth.

Oh wow, surprising result for Space Squash, I really thought 500 microseconds would cut it but it’s not even close. Especially surprising after the SRAM tester homebrew, since that gave the impression 200 microseconds was already pretty close. There must be other factors at play, maybe even physical ones (ambient temperature?). Comparing the previous 200 microsecond delay to the new 500, we only got about a 25% improvement. We need another ~800-900 microseconds (~1250 total) to make sure the save gets initialized correctly. I guess 1500 was pretty close after all. Ultimately, I think I will just stick to 1500, since it’s already known to be working and still only a fraction of a single frame.

The reason we’re having such a bad time with Space Squash specifically is that it starts reading in the config settings extremely early on boot. We’re talking less than one microsecond. The original game is reading all of these values from ROM, and ROM is accessible instantly. Our hack falls over when it starts trying to read these values from SRAM as if it were as fast as ROM, but hey, that’s what the delay is for.

Super glad we got Mario Clash worked out. I do have one more thing I’d be interested to look at for that game. DogP’s controller fix hack is fantastic, but the one thing that’s not so great is that it breaks the attract mode that plays if you leave the game sitting on the title screen for a while. The CPU player is pressing all the wrong buttons, so it never even manages to jump off the chain at the start. I think this should be fixable and would go a long way to make Mario Clash with saving/button swap feel like a real commercial game instead of a ROM hack.

EDIT: would you mind looking into a possible save patch for Bound High?
EDIT2: and perhaps for Nester´s Funky Bowling if you have time and are motivated 😉 ?

Yeah, when I started out I was specifically looking at the commercially-released games, but Bound High is obviously … pretty close! Honestly I haven’t really played much of the game yet myself, so I’m not sure how progression/saving would work. The game page says it has Password saving already though, so that’s always a good place to start if I look at getting it saving internally. It’s on the list!

Nester’s Funky Bowling is probably the most likely one I’ll look at from the remaining games. I haven’t looked at the code at all yet (hopefully, it’s not another Space Invaders) but just from how the high score table works it could be one of the easier ones to work on–like V-Tetris, that one was pretty friendly to work on, too. And I could use something simple after Space Squash, that was certainly one of the more challenging games.

Nester’s Funky Bowling is probably the most likely one I’ll look at from the remaining games. I haven’t looked at the code at all yet (hopefully, it’s not another Space Invaders) but just from how the high score table works it could be one of the easier ones to work on–like V-Tetris, that one was pretty friendly to work on, too. And I could use something simple after Space Squash, that was certainly one of the more challenging games.

Definitely a pretty simple one for a change.

I have it saving the player 1 and 2 names, character selection (Nester/Hester), preferred ball weights and the League Leaders (high scores). Same SRAM erase setup as usual, L + R + Left D-Pad Down + Right D-Pad Down on the title screen.

I think this is complete as long as no issues come up.

Yes, I would also tend to 1500 ms delay for Space Squash, but this is only my amateurish opinion 😉

Mario Clash:
Yes, you are right, I haven´t looked at the demo play since your remark, but now knowing it I have seen it too. The button swap really crashes those plays.

Bound High: yes, password saving is already working, I have the game as reprocard and completed it. “Normal” SRAM saving would be great, but no rush!

Nice!! Thanks for this! I will test it this evening or tomorrow at the latest.

Nester seems to work. Player´s name is saved as well as high score and SRAM delete.
I have attached a normal save with my highscore (159) and a clean save after SRAM deletion.


Excellent, everything looks good in both saves, same results as in emulation. 👍 I’ll go ahead and put the new patch up on GitHub tomorrow–no changes from the version you have now, so you won’t need to re-patch.

I also have a tiny patch for Hyper Fighting. It doesn’t need any testing, it’s just a quick bug fix I whipped up and posted on the Discord. Eventually it’ll go up on GitHub as well I suppose, but I don’t know when, so I’ll put it here so it’s not just buried in a Discord attachment.

Hyper Fighting has a tiny bug with the Brightness setting in the Options screen. If you set the brightness to maximum (32), the next time you start up the game it will be reset back down to 16. On startup, the game checks if the brightness is >31 and resets it. This is most likely just a typo in the game’s code: the anonymous dev probably meant to have it reset if the brightness somehow got set to >32 (more than the maximum), but instead they made it reset if the brightness is equal to the maximum. This 1-byte patch fixes that bug.


Write a reply

You must be logged in to reply to this topic.