gbdev / pandocs

The single, most comprehensive Game Boy technical reference.
https://gbdev.io/pandocs/
Creative Commons Zero v1.0 Universal
618 stars 93 forks source link

Undocumented SGB Hardware quirk: Command packet bytes are buffered #509

Open binarycounter opened 1 year ago

binarycounter commented 1 year ago

Hey, as discussed on discord, here's the issue:

The command packet buffer (at $7000 on the SNES side) is not written to immediately as bits come in (as I would expect). There is an internal 1 byte buffer that incoming transfers are written to. And only once 8 bits are transferred and that buffer is full, it gets written to $7000+. That means that if you transfer less than a byte, that data will never reach the buffer at $7000.

This quirk never comes up in official (or existing homebrew) software because the BIOS only reads the packet once the full 16 bytes are transferred and the "packet available" flag is set.

I am working on a SGB demo that jumps out of the BIOS and runs custom SNES code. Part of the demo has synchronised music playback between GB and SPC, with the GB being the part that dictates the speed. To save CPU time I was looking for the smallest possible amount of data i could transfer to indicate a new engine tick and tried just transferring the reset pulse and a single bit. This worked on Mesen2 and Higan, but not on hardware (PAL SNES 2/1/3, SGB1, EZFlash Jr cart). It only started working when I transfered a full byte.

To test this, I have created two test ROMs, one of which behaves differently on hardware, than it does on Higan and Mesen2 (both compiled from latest source).

The ROMs transfer a small program to SNES WRAM that continously reads $7000, left shifts it twice and writes it to the screen register. The GB side then every few scanlines transfers a single bit, toggling between 1/0. On the 8bit version, this bit is then padded with 7 additional 0 bits. If the transfer is successful, the SNES should start rapidly strobing the screen on and off every few scanlines. This only works on hardware, if the value is padded to 8 bits.