Tuesday, 30 December 2014

MBC address wraparound on the GameBoy

I discovered many games were doing out-of-bound accesses on MBC's by accessing banks that weren't in the file. Nintendo's docs simply say a "memory image" is created in unused ROM space, which is somewhat obtuse, and really not easy to understand.

After tearing my hair out for a few hours, wondering if there was a bug in our core or in the games, I realised that this really means the ROM's contents are mirrored again; that is, banks are "repeated."

The simple procedure is to modulo the bank number with the number of banks, easily derived by dividing the ROM size by the ROM bank numbers. I don't know if adjustment is needed for specific MBC's such as MBC1 which cannot address banks whose lower bits are 0 (e.g. it can't address 0x0, 0x20, 0x40, 0x60, etc.), but it all seems to work properly now.

Now if I could just figure out why Link's Awakening has bizarre scroll bugs... it's not banking related, and it only happens in specific corner cases (when SCX is > 0 and Y scroll changes is one instance)...

Sunday, 28 December 2014

Implementing MBC3 timers in supergameherm

I've mentioned supergameherm in my initial post and how I would be talking about it. As promised, here is some discussion on the topic.

As anyone who develops for the GameBoy knows, all but the most simple games require an MBC (Memory Bank Controller), due to address space constraints. Tetris, notably, did not need an MBC (being one of the simplest games ever made for the GameBoy); however, most did.

If you're ever wondering how games such as Pokémon Gold and Silver kept what day of the week and what time it was (within semi-reasonable accuracy), it used a timer inside the cartridge, which was powered by a battery. Its ticking was controlled by a quartz oscillator. Pretty simple stuff; it might even remind you of a watch.

The RTC has 5 registers: seconds, minutes, hours, the lower 8 bits of a day counter, and another register containing the following values:
  • Bit 0: Extra bit for day (day counter was unsigned 9 bits, allowing values from 0-512)
  • Bits 1-5: Unused, values unknown (I don't have real hardware anymore to test with)
  • Bit 6: Clock halt (timer stops when this bit is set - to avoid race conditions, only write to the RTC registers when this is set)
  • Bit 7: Day counter overflow flag (when day > 512, and is NOT reset by the cartridge when it overflows again - only the game resets it)
In addition, there are another 5 "shadow" registers that you don't normally see - they are the latch registers. When a bit is set in the cart, the present time is latched into these shadow registers, and this is what is presented as the current time. The time only appears frozen; it really isn't. You can modify the registers all day long, and the real time will keep on ticking and pretend nothing happened. Unlatch the time, and you get the real time back - but the old value is retained in the latched registers until you relatch the RTC (inaccessible of course, in theory).

All this is in the pandocs for the most part, but the relevant bits are in Denglisch, which can be hard to read at times.

The easiest way to emulate the counter ticking is to intercept all reads to the RTC registers, and then compute a time delta. You could of course implement a simple counter, but that requires checking for overflow of seconds/minutes/hours/days/setting day carry - things you have to do if you are computing a delta anyway! Besides all that, you need a function to compute a delta if you have any hope of loading a save file and keeping accurate time (assuming the ROM is opened every 512 days of course, to ensure the day overflow bit is checked :p). It's best to only adjust the clock as-needed, because modulus and division are very slow operations on x86.

When saving, just keep track of the Unix time stamp (see the time() function in C). In the save format used by VBA and modern BGB, the clock data is appended to the end of the save file, including the Unix time stamp. Using this information, a delta can be computed, and the time brought up to speed in the game. As far as the game is concerned, nothing even happened.

If you're curious about the code to compute time deltas, it's all on GitHub. If you want to make your own MBC3 implementation, feel free to use that code - it's BSD licensed. I wanted WTFPL, but Anna wanted BSD, and I wasn't going to argue the point.

There seems to be a dearth of emulators which do RTC emulation. It's a real pity, because the code isn't that difficult. The only tricky part is to remember to compute the delta before latching.

Optimisations I want to make to the code are to replace my MBC3 time structure with a structure containing pointers. We use memory-mapped I/O for save files to emulate .sav files accurately without obliterating performance. Writing to disk for every RAM operation would have been costly, and isn't feasible for games that actually use the RAM for purposes besides save files (a common thing seems to be holding sprites). This avoids an unnecessary function call to write back all the values periodically to the memory region.

Why I'm using Blogger

So it appears some of my friends (I'm looking at you, Anna, who is quoted below) think my choice of Blogger is shit.

Of all platforms in all the world, you picked the shittiest one?
Like, WordPress is less shitty.
Au contraire, WordPress is always the shittiest.
 Like, LiveJournal is less shitty.
Hi yes, I'm a big girl now. I haven't been 18 in... 5 years? Besides, is there even anyone left on LJ these days
Rails' example is less shitty
I take that back. Rails is always the shittiest. Ugh. Maybe one day I will write a rant about Ruby when I feel like dealing with a bunch of code "artisans" or ninjas, but today is not that day.
 I would have hosted any solution for you and even done the admin part
But this way nobody has to do the admin part except some underpaid slave at Google! Managing a blog is only free if your time has no value; I wouldn't subject anyone I cared about to that kind of masochistic torture, especially the torture of maintaining WordPress, aka "certified pre-0wned."
You mean besides the fact they make money off you by putting in ads and pay you none of it?
My rants aren't a profit-making enterprise, ffs. Let them profit off it in exchange for me nor anyone else I care about not having to maintain a blog platform.
Besides the fact it forces your readers to sign in with Google to comment, not allowing OpenID or Disqus any other federated login?
Disqus is ugh, and Google is an OpenID provider. EDIT: it has come to my attention that Google are no longer an OpenID provider, but Blogger is an OpenID consumer.
Besides the fact none of their templates work correctly on mobile and you have to write your own HTML and CSS if you want those visits which are 60% of web traffic these days?
Looks fine on my phone, dunno what you're on about.
Besides the fact it isn't HTML compliant and fails egregiously on any validator.
Adorable, you think WordPress pages are any better. *patpat* EDIT: I was asked to take back the patpat.
Besides the fact they slipstream analytics even when you don't want them and disable them?
You got me there, but I'm too lazy to care.
I mean, TypePad, Tumblr, jesus fuck anything is better than Blogger
Never heard of TypePad. I don't want to be associated with tumblr or its poisonous, self-defeating culture of SJW's.

I guess it boils down to one thing:

I just don't give a fuck.

Oh god I've made a blog

I don't know why I've done such a terrible thing but apparently I've been told "you should write more." On the other hand, I don't really like things like the 150 character format, and I am not much for social media. I guess a blog is more of an outlet for what I have to say. Call me a traditionalist, I guess.

If you don't know who I am, I'm Elizabeth Myers. I do stuff. There's not a lot to talk about. I'm pretty boring, in my own opinion.

So yeah, expect mostly rants and information here, including:
  • Rants about the GameBoy series of consoles (I am making an emulator with Anna Wilcox)
  • Information on said console that may be of use (I've found documentation on the GameBoy sucks balls)
  • Rants about stupidity
  • HowTo's and various guides
  • Poop - because you can never have enough toilet humour
Beware, there is adult language on this blog, and possibly adult content. Viewer discretion is advised, if you're a fucking prude.

Also, fuck you if you get offended. Eat a bucket of shit if anything I say offends you. Seriously.