So recently I have just been playing around a bit more with my previous gameboy things, see my previous few blog posts for how I run code using my pokemon cart, just wanted to write a bit about some of those.
First up, I did end up implementing gameboy cart save dumping into my gameboy audio dumper:
It is a quite simple addition overall, the only strange thing is this first rather big code block:
That really just has to compare each value in the games header to determine how big the save is, they made it rather strange so it cant just be easily scaled up, oh well:
I dont have too many carts around that even have saving but interestingly enough I ended up running across one cart that seems to always corrupt the save when inserting that cart into a running gameboy color, and that is tetris dx.
For some odd reason, the first byte of the cart always gets set to 0 as I was able to see in a hex editor:
You see how it reads _ETRIS now? Well yeah as you can guess that should read TETRIS instead, and the game actually checks for that on boot, and if it is not present it completely wipes the save! Meaning that at any time if I would've booted this cart up in all my dump tests, I would've lost my original save from way back in the day!
I do believe that this may have something to do with the chip inside the cart which is a MBC1, the "1" indicating it being the first controller chip version, so I assume this particular bug is related to that, I do have a cart that has MBC2 and another with MBC5 chips in them, and on those there is no such save corruption at all. Also this does not seem to be related to some random cpu command but rather just the chip being powered up in a weird way, because a gameboy by default cannot read/write onto cart RAM until you unlock it by writing a magic value (0xA) into a specific cart register. And I did also dump the cart without writing into that register first and as you would expect, the save reads as 0xFF (no data).
Just because I really wanted to get into weird behavior I also booted the cart normal in another gameboy, then quickly ripped out the cart and plug it into my gameboy color, and guess what, now it just writes some random byte into a random address in the save instead!
That probably comes from some residual value still in the chip, how strange indeed.
Also as I mentioned, I have a cart with a MBC2 chip, now this chip save is a very strange one that does not use full 1 byte (8 bit) values per address, but it is 4 bit instead, so only half of a byte is actually usable as save. In my gameboy emulator:
I have this implemented by setting the upper part of the byte to 0xF because I figured that it probably would read as that on a real gameboy, because all other inaccessible registers on it always have bits set like that as well. And I am happy to see that indeed, a real MBC2 save looks exactly like that, so thats cool!
Looking into different audio pulses
My audio dumper does work by just turning the gameboy audio wave channel on and off, and I did already push the pulses as short as possible, zoomed in looking like this:
and as I wrote in a previous blog post, it could not get much closer together as that would lead to problems seeing how big a pulse is. Now I did also previously have the idea of maybe just making this pulse more like a smooth curve instead of just turning it on/off which should be easy enough as I specifically use the wave audio channel that can have custom samples, this may make it easier to see the pulse size, and on gameboy color, such a custom curve results in a pretty good result:Warning: Spoilers inside!
This was captured at a higher samplerate than the previous image to really see the detail on it compared to the previous image. However, I did not end up using this method in my released build originally because I did read about a sample corruption on the original gameboy on this page:Warning: Spoilers inside!
Now I did never see this corruption for myself before but now with this particular test version I have made, I was indeed able to see it for myself now:
If you compare that to the previous image you can clearly see after the first 4 pulses, it suddenly has every other pulse cut in half! So I suppose I will keep the method unchanged for now, it does work well enough for now.Warning: Spoilers inside!
In my receiver that converts these pulses into bytes I may try some other methods in the future to see the exact pulse size, at the moment I just use 6 points of reference around the pulse and 2 in the middle of it to and measure the value in between those to get its exact size, but I want to look into maybe doing something like taking something called RMS value instead, this basically takes all points I give it, in this case probably about 10 or more sample points in a row instead of just some on the side and in the middle, and gives me a single absolute volume value out, which may make this more accurate which would be nice. Also I probably should support more than the 44100hz sample rate, because as you can see from the previous image, at 96000hz the pulse gets much clearer and should measure much more accurately too. I just made it 44100 for now as I figured that is the easiest overall to capture, if anyone else is crazy enough to ever even test my dumper.
Some chinese multicart
Under the few carts I do have is actually this particular multicart called "Super 101 in 1" which has actually 16 games on it, the cart looks like this:
and when I wanted to dump it in my dumper, it always just did 32kb, this is because the first game on it is in fact only 32kb big, but when booted in an emu, you can clearly see that this is not actually just a game:
They basically just hacked the first game a bit to put this selection menu in, there is quite a bit of space after all in this game so it was probably the ideal target.
Now for me to properly dump this cart I had to figure out how it actually sets different games to boot, now this is where all the pirate mappers I implemented into my nes emu help:
This immediately gave me the idea that I should just set write breakpoints for normal cart chip registers and see if anything strange is written to them, and indeed for register 6000, there is:
This particular register on a real cart is not all that often used, on MBC1 chips, it just selects if the amount of banks RAM and ROM can have, and on MBC3 chips, it can be used to get the current time, on all the others like MBC2 and MBC5 it does not do anything.
This write happens right when you boot the cart, and then when selecting a game, it does more writes depending on the game, I did list those here:
From this, I was able to figure out exactly the logic behind this register by basically modifying my cart dumper and before dumping just writing in other values into it and seeing what happens, its quite technical:
That little bit took me quite a while to figure out, but now I know exactly how this cart works, how big it is (2MB) and also which games are exactly on it in which versions:
Overall, I made a good 15 dumps, all 1MB each, with all sorts of unusual values that the cart never actually writes into it itself just to make sure I exactly know what logic is going on, and also of course to build a proper 2MB dump of the cart itself instead of the initial 32kb dump. Was quite fun figuring out this odd cart I had laying around now for ages.
Also, I did end up implementing it for testing in my emulator and it works great, though I yet have to commit any changes to the emulator itself because there are various other things I still want to do to it before, in particular regarding the audio to make it more accurate. I did test my audio dumper on my own emulator and found out I dont actually handle the audio channel output how a real gameboy does exaclty, it is actually shifted up in a way it should not be, so I want to fix that up first.
I hope those different things were at least a bit interesting, thanks for reading.
You need to be logged in to comment