Staacks / gbinterceptor

Capture or stream Game Boy gameplay footage via USB without modifying the Game Boy.
478 stars 24 forks source link

Is this necessary? #12

Closed DaKnig closed 1 year ago

DaKnig commented 1 year ago

I am interested in this project; while browsing the code I found this line: https://github.com/Staacks/gbinterceptor/blob/a20ea0fc2684e79c001283a8b832f442333bf8b2/firmware/cpubus.c#L148 a real gb, depending on model, does not reset the memory and starts with whatever random garbage it had there. why would you reset this completely?

Staacks commented 1 year ago

I added this when I introduced the game detection mechanism for the upcoming version 1.1.0 and in order to explain this reset I need to explain a few things about the detection mechanism first:

In order to detect which game is running the Interceptor cannot just read some data from the cartridge but needs to work with what is requested by the actual Game Boy. At the same time, there is not enough headroom left on the core that handles the bus data to calculate a hash of each instruction on the bus and to check each hash against a database.

So, instead I hash the data that is written to our emulated memory, because we get at least one Game Boy CPU cycle that does not require much attention whenever the Game Boy writes to memory. In that time we can update the hash and I do this on VRAM data because that usually receives distinct data (for example the game logo or assets for an intro animation) right after the game has been turned on and (in most cases) without relying on tricky things like the div register.

Now, checking the hash against a database of 1400 hashes also takes a moment, especially when they do not fit into RAM but need to be read from significantly slower (although cached) flash memory, so this cannot be done on the core that looks after the bus. It is instead done on the core that emulates the PPU during vblank.

Since the check is done only during vblank on a different core, the hash needs to be stable once the data in VRAM has been loaded. It is not synchronized, so we might just miss the moment when the hash ahs the value that can be found in the database, so the hash should ideally be stable at some point for a few frames to make sure that this one is checked against the database.

For most games this is the case because they load their assets and then rarely manipulate the data until you load a different level or cutscene. But I found some games that periodically write the same data to VRAM over and over again in every single frame. While the content of VRAM does not change here, simply hashing the data that is written to VRAM would not be enough anymore. So, instead I only hash data that is written to VRAM and that is actually different from the data that is already there. This way the hash only changes while assets are loaded but remains constant after that.

And that is where the memory reset comes in: In order to do know which data is new I need to compare the written data to the old data in VRAM and if old data persisted in VRAM across a reboot I would get a different hash each time because different data would match the old data and would be ignored for the hash.

I am closing this as it is not really an issue, but feel free to ask further.