Daiku no Gen-san - Robot Teikoku no Yabou (Japan)
I found an interesting case in this game today. It behaves slightly differently on GBHawk and Gambatte, and neither produces an input file that works on GBI.
The first immediate difference between GBHawk and Gambatte is in a timer interrupt, which is pretty strange since timer emulation needs to be practically perfect for pokemon games to work, so there must be a weird edge case happening somewhere.
The input files produced are slightly different, varying in timing in 6 places throughout the movie, but they both desync in the same way on console, and the inputs work out the same in terms of emulated frames.
I also don't see any uninitialized RAM used, at least not in an obvious way that my checker picks up on.
I'll be looking deeper into this, might be something interesting here.
EDIT:
Alright, so two things came up in this case.
First, the primary desync was caused by an edge case of enabling the timer on the same cycle that a state change would occur. In this case, the timer was enabled by writing 5, which tells the timer to check bit 3 of the divider register. At this time, the divider register is 59591, which is 7 (mod 8), so this would trigger a state change since the divider register would increment at the same cycle. What should happen, on GBP at least, is that an extra timer increment should occur.
Now, the details of this are not fleshed out that well. There is a test ROM for it called tac_set_disabled.gbc, and GBHawk and Gambatte both fail it in different ways, with neither getting really close. Also, the results are different depending on GBA variant. It's a race condition, so some cases could even be console dependent I suppose. It would probably be a good idea to run this test ROM on various GBP's and see what the results are.
Anyway, if I implement the simplest possible case of going from off to on on the same cycle as an increment, then GBHawk desyncs in the same way as GBP.
Gambatte on the other hand was already doing this. It desynced for a different more familiar reason, mode 3 timing:
083A: CB 4E BIT 1,(HL) A:66 F:20 B:00 C:0C D:D8 E:85 H:FF L:41 SP:D9F8 Cy:461806951 LY:47 znHcie
083C: 28 03 JR Z,0841h A:66 F:20 B:00 C:0C D:D8 E:85 H:FF L:41 SP:D9F8 Cy:461806963 LY:47 znHcie
083E: FB EI A:66 F:20 B:00 C:0C D:D8 E:85 H:FF L:41 SP:D9F8 Cy:461806971 LY:47 znHcie
083A: CB 4E BIT 1,(HL) A:66 B:00 C:0c D:d8 E:85 F:20 H:ff L:41 LY:2f SP:d9f8 Cy:461806948
083C: 28 03 JR Z,0841h A:66 B:00 C:0c D:d8 E:85 F:a0 H:ff L:41 LY:2f SP:d9f8 Cy:461806960
0841: E1 POP HL A:66 B:00 C:0c D:d8 E:85 F:a0 H:ff L:41 LY:2f SP:d9f8 Cy:461806972
Top is GBHawk, bottom is Gambatte. This is at a part of the game where there is a lot of sprites + scrolling. Gambatte fails the test ROMs associated with this case.
It's pretty crazy that one movie that I just recorded in a casual way by hand ran into 2 desync cases. I've attached the files for reference. I'm not sure exactly how I want to implement the timer fix in GBHawk yet, it might wait until after 2.5.
http://tasvideos.org/userfiles/info/65391155339899622
http://tasvideos.org/userfiles/info/65391163693719305
EDIT: Actually the timer thing is adifferent case from what is tested in tac_set_disabled.gbc. The behaviour here depends on the initial state of the DIV register. I tried running a bunch of Gambatte's timer tests. It looks like the expected timer DIV initial state for GB is zero, and for GBC is 0xFFFF. Almost all of the tests work in GBC mode if I set timer to 0xFFFF. However if I do this then the Gensan 2 run syncs again because it doesn't get an additional timer increment. I need to determine what the initial state is for GBA to narrow down what is going on here.
EDIT2: regardless of the initial value of DIV, an extra increment needs to occur in order for this run to sync. I'm currently not sure where it comes from, but it works perfectly on a much longer run , up to 25000 frames, if there is an extra increment when enabling. Note that the starting value of DIV being 0 or 0xFFFF is invisible to the pokemon TASes because they only read DIV and don't use the timer the same way, and invisible to pokemon TCG because DIV is reset by speed switch.