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)
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.