mgba-emu / mgba

mGBA Game Boy Advance Emulator
https://mgba.io/
Mozilla Public License 2.0
5.72k stars 790 forks source link

Key IRQ always happens at the same LY #1232

Open pinobatch opened 5 years ago

pinobatch commented 5 years ago

388 implemented key IRQ. But a program can tell that it's running on mGBA because the key IRQ always happens right at vblank.

To reproduce:

  1. Build mGBA Qt 0.8-5388-f92059be on Xubuntu 18.04
  2. Start the attached test ROM "Telling LYs?": tellinglys-0.01.zip
  3. Press all 8 buttons in any order
  4. Watch the arrow sprite at the right side

Expect: Arrow moves after each press, followed by "Pass", as on DMG, CGB, DOL-017, and BGB emulator

Actual: Arrow stays half off the bottom of the screen, followed by three words in Impact font that clearly aren't "Pass"

zeromus commented 5 years ago

It isnt philosophically clear what an emulator core should do. nor even what a frontend should do.

Should a core wait arbitrarily before obeying instructions on what input to assert?

Should a frontend wait arbitrarily before forwarding the user's input to the core, to be obeyed immediately? This has implications on how useful emulators are for practical purposes (sub-frame input is difficult to time if the frontend or core are deferring them arbitrarily; input at frame level is even difficult if it's applied chaotically)

I would think this has to be implemented as a user-selected hack. Since it's a hypothetical consideration, I wouldnt suggest it default to on.

I wonder what the organization here should be. Are there a class of emulation tweaks which you could call "human input fuzzing" which could be enabled or disabled as a group?

I hope you don't mind if I invite @nattthebear @adelikat @adelikat @vadosnaprimer who might be interested in this

endrift commented 5 years ago

image Works fine in the SDL version.

nattthebear commented 5 years ago

The test rom records the LY value for each of eight keypresses, and then computes entropy as follows:

Entropy = PopCnt((LY1 & LY2 & ... & LY8) ^ (LY1 | LY2 | ... | LY8))

The test succeeds if Entropy >= 5.

That means that roughly speaking, you'll need key timing jitter on the order of 500ns or quicker in order to pass the test.

On a modern computer with about 50 million levels of abstraction between the emulator and the physical switch on the keyboard/gamepad, you won't get meaningful data within an order of magnitude of that, so any emulator that passes the test is either artificially adding jitter itself or relying on implementation details of the input subsystems it hooks into.

Do any real games rely on this behavior? Is this behavior observable in the GBA as well?

Bizhawk probably won't implement this, not that it matters here.

pinobatch commented 5 years ago

My AGB-001 gives "Pass!", behaving the same in this respect as my CGB-001. By "real games", do you mean licensed games?

My concern was more with bringing mGBA to where it can be used to test homebrew games during development. If a joypad interrupt interrupts something that the program doesn't expect it to interrupt, then the game may crash or otherwise misbehave. During the development of the test ROM, I discovered using bgb's debugger that there's about an 0.9% chance that it'll interrupt OAM DMA, for instance, and to avoid the CPU trying to read RAM that's not accessible during DMA, programs have to di and ei around the wait loop.

I asked beware what bgb does to generate its entropy. He confirmed that it's an RNG, emulating both random timing and switch bounce to mimic hardware.

zeromus commented 5 years ago

Whether this would improve or disimprove an emulator for homebrew testing purposes is not a matter of opinion but definitely one way or the other as a matter of perspective depending on what kind of eccentricity you're worried about. This isn't about accuracy, this is about compromises and tradeoffs (although it could in theory be an option, like I said). "Real games" means anything not specifically designed to illustrate this problem. If no real game in the universe is bugged by this, then it may not be worth the trouble even discussing once the existence of the problem is noted (although in retrospect, the existence of this problem should be obvious as a matter of emu-science).

I hope the bgb author made it pseudorandom based on the emulation clock or entropy set at bootup so it's deterministic...

pinobatch commented 5 years ago

I asked beware, and bgb disables randomization when either of these is true:

As for real games: He mentioned a homebrew game called Super Ninja, which appears to rely on emulator-like input timing. Switch bounce will cause it to enter and immediately exit pause mode. On the other hand, I was thinking of using the joypad interrupt once at the title screen to seed the game's RNG with more entropy than frame counting alone can offer. I'm told an unlicensed NES game relies on sub-frame input timing as well, so if you're building a front end that can handle both NES and GB, you might need the functionality.

zeromus commented 5 years ago

It would be simpler just to not care so much about getting so much entropy. If it's so important to the game, make the game make a game out of it by instruction the user to mash buttons until sufficient entropy is generated. Knowing what you do now, do you really think it's smart to rely on a method which is likely to break emulators and could quite conceivably break hardware clones and retro-gaming appliances (those could be using emulators or even not using emulators but implementing their input differently)

nattthebear commented 5 years ago

My AGB-001 gives "Pass!", behaving the same in this respect as my CGB-001

Sorry, I meant GBA in GBA mode. Presumably it's affected by the same issue?

zeromus commented 5 years ago

This seems logically equivalent to a user sending a pure sine waveform into the microphone through an emulator and having a game detect that it's a physically impossibly pure waveform. So.... send it fuzzier inputs? I guess you want a tool that sends fuzzy button inputs. I still favor introducing the concept of hardware fuzzing enable/disable which someone could use to control whether all known problems are minimized, or pristine digital signals are used.

I said hardware fuzzing instead of input fuzzing like I previously might have because I thought of another example. Let's say we have a game that uses two clocks on separate crystals to check whether theyre running at a fixed ratio. A definitely fixed ratio should only be possible on an emulator.

Heck, the game could even more simply just check to see if there's noise on the mic line at all times. What emulator is going to think to do that?

What about devices with gyros in them? Even if the player isn't using the gyro at a given moment, so he doesn't think he's giving any particular input, the game could be checking it for noise.

Admittedly your scenario of handling button bounce or unlucky IRQ timings IS the most legitimate of all these. I could see some gyro algorithms falling apart with all zero input though.