Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the recommendation to rely on C==$14 to detect SGB #442

Open
nitro2k01 opened this issue Oct 18, 2022 · 6 comments
Open

Remove the recommendation to rely on C==$14 to detect SGB #442

nitro2k01 opened this issue Oct 18, 2022 · 6 comments
Assignees
Labels
content Improvements or additions to documentation

Comments

@nitro2k01
Copy link
Member

nitro2k01 commented Oct 18, 2022

Ok, time to be "that guy".

While it can be a neat trick to know that the SGB boot ROM leaves C==$14, it can lead to both false positives and false negatives in plausible real world scenarios. Therefore I would suggest restoring the recommendation to use MLT_REQ as the recommended way of detecting SGB functionality. Below are the ways in which it could lead to false detection, as well as addressing some of the things mentioned in that text.

False positives

The impact of a false positive is that any attempt to transfer data using _TRN commands will be seen as garbage on the screen.

  • One of the Gameboy clone boot ROMs will leave C==$14. By my naming conventions it is called fortune_boot.bin but it may exist in variously named clone consoles.
  • The game may run on a real SGB, through the boot ROM, without access to SGB commands. In particular one common way that this could happen is using the EZFlash Jr cartridge. This cartridge has trouble running on a SGB because of reset line issues. A common workaround to this issue is to hit the reset button at a point which allows the boot ROM to run and the menu to show. However, since the stock firmware of the EZFJ runs first and doesn't have SGB support enabled in its header, communication with the SNES BIOS is locked out after that point, including in the case that the SGB CPU is reset because a game was loaded.

False negatives

The impact of a false negative is that SGB functionality such as borders and screen colorization are disabled, when they don't need to be.

  • Some cartridge menus on older flash cartridges don't reset the game, but instead store a small trampoline in WRAM which they use to jump to $100 after setting up the cartridge's multi ROM functionality to show the ROM in question. One such example is the EMS 64M USB cartridge if using multi ROM functionality. Such a menu will almost certainly not leave C==$14 or care to leave different register values for SGB compared to DMG.
  • Older emulators typically don't produce correct initial register values for SGB, instead typically giving values similar to those found on a DMG. On such emulators, SGB functionality will be disabled, even though the game would otherwise run fine in the emulator in question.
  • There's one scenario where even newer more accurate emulators can fail to produce C==$14, namely in a "SGB+GBC" mode if such a mode exists. Both BGB and mGBA have such a mode and both (not surprisingly) start with the exact initial registers of a GBC. In this mode, SGB functionality is locked out, and the game is shown with an empty, useless border around it instead.

The conclusion is that relying solely on C==$14 for SGB detection is likely to cause real world irritation for a small but significant group of users of the software you create and should not be recommended as the main SGB detection mechanism.

Claims made in the current text

but this method is more complicated

True, but not by much. If you consider that the purpose of detecting SGB mode is typically to send over a border and/or colorize the screen, which in itself takes some setting up, the added effort in programming the detection algorithm is minor. A better solution to this point would be to create a library/example code that a developer can use as is.

and slower than checking the value of the A and C registers after startup.

So, it is true that SGB commands take some time to execute, due to a recommended delay after each command. Nintendo recommends a 70000 M cycle, or ~4 frame delay. Do that twice during detection (once to activate multiple controller mode, and then to deactivate it) and you're looking at an 8 frame delay, or ~133 ms. However, consider that on real hardware, it was directly preceded by a forced delay of anything from a 3.11 s (GBC) to 5.59 s (DMG). Also combine this with the fact that most games are expected to show a copyright, title or similar static screen as the first thing, which can be loaded before this delay and thus essentially absorbs it. Given this context, a one-time 133 ms delay before user input is accepted should barely be perceptible to a human, much less an annoyance.

@ISSOtm
Copy link
Member

ISSOtm commented Oct 18, 2022

MLT_REQ detection also has some false negatives, such as if a previously-ran firmware ran a MLT_REQ detection itself, but did not reset it to singleplayer. If the environment cannot be trusted, there's not much that can be done.

Additionally, MLT_REQ detection is known to be very finicky: timings must be obeyed, registers must be polled in the right order, interrupts must be disabled... there's a lot of moving parts, and a lot that can go wrong. (Pokémon Yellow being a famous example of SGB detection gone right for the wrong reasons.)
This complexity is what the current article lumps under "but this method is more complicated".

Also, what are the forced delays you noted calculated from? I don't know of any reasons why such would be needed on DMG or CGB, much less why they are shorter on the latter.

Note also that games may not show a static screen at that point. For example, Aevilia plays an animation (clouds scrolling by) during boot-up, Libbet fades the Nintendo logo out, etc.


Ultimately it's a question of how much effort you're willing to put into supporting broken setups: using boot-up c is much simpler and still correct for a large majority of users, while MLT_REQ is much more error-prone, slower, and still not bulletproof.

SGB+CGB specifically is ill-defined, as it does not emulate any actual hardware configuration (there is not enough bandwidth to transfer 15bpp tiles, and not enough for a hypothetical 8bpp "hack" instead), so every implementation is bound to diverge somehow, at least unless emulators agree on and publish a spec.

@CasualPokePlayer
Copy link
Contributor

Also, what are the forced delays you noted calculated from? I don't know of any reasons why such would be needed on DMG or CGB, much less why they are shorter on the latter.

Forced "delay" is from the bootroms.

@nitro2k01
Copy link
Member Author

nitro2k01 commented Oct 18, 2022

MLT_REQ detection also has some false negatives, such as if a previously-ran firmware ran a MLT_REQ detection itself, but did not reset it to singleplayer. If the environment cannot be trusted, there's not much that can be done.

That's a tenuous argument of something that may exist, vs things that I listed that exist for a fact. Even so, doesn't our MLT_REQ set things right in this case?

I could look into what those menu ROMs are doing, although that's not the most important argument since those cartridges are mostly out of commission. I mostly mentioned it to point out in a wider sense that MLT_REQ is generally the most accurate method of SGB detection.

Additionally, MLT_REQ detection is known to be very finicky: timings must be obeyed, registers must be polled in the right order, interrupts must be disabled... there's a lot of moving parts, and a lot that can go wrong. (Pokémon Yellow being a famous example of SGB detection gone right for the wrong reasons.)

Timings must be obeyed, but this can be easily achieved with copy-paste example code that does things right. Interrupts must be disabled (if you're referring to not probing the joypad during a transfer) but a typical structure of a game is that initialization is/can be done with interrupts disabled before the main game code is executed.

Also, what are the forced delays you noted calculated from? I don't know of any reasons why such would be needed on DMG or CGB, much less why they are shorter on the latter.

I'm referring to the boot ROM logo animation, which cannot be skipped. Ie, I'm putting the 133 ms delay from SGB detection into the context in which it is perceived by the player.

Note also that games may not show a static screen at that point. For example, Aevilia plays an animation (clouds scrolling by) during boot-up, Libbet fades the Nintendo logo out, etc.

Ok, but if you're putting that extra effort into the intro screen, you can probably either figure out how to make the transfer work anyway, or accept a blank screen for 133 ms at startup, or decide on your own that using C for detection is right for you, depending on your needs. (Note that you only need to suppress reading user input during the detection. The game is still allowed to output graphics during this time.) More "fancy" games are not necessarily relevant for the mainstream use of documentation which should work for a wide range of users.

Ultimately it's a question of how much effort you're willing to put into supporting broken setups: using boot-up c is much simpler and still correct for a large majority of users, while MLT_REQ is much more error-prone, slower, and still not bulletproof.

It's simpler, but MLT_REQ has higher accuracy over all. I don't agree that MLT_REQ is much more error prone. If it does cause errors, those are the type of errors that are likely to be caught in development anyway, since they would stop the game from working as desired even under normal circumstances

SGB+CGB specifically is ill-defined, as it does not emulate any actual hardware configuration (there is not enough bandwidth to transfer 15bpp tiles, and not enough for a hypothetical 8bpp "hack" instead), so every implementation is bound to diverge somehow, at least unless emulators agree on and publish a spec.

It's a hack, that may or may not work depending on circumstances. You can try it right now, and some commercially released games will work as expected in this mode, while others won't. Using C for detection, however, guarantees that this hack works 0% of the time.

@nitro2k01
Copy link
Member Author

SGB+CGB specifically is ill-defined, as it does not emulate any actual hardware configuration (there is not enough bandwidth to transfer 15bpp tiles, and not enough for a hypothetical 8bpp "hack" instead), so every implementation is bound to diverge somehow, at least unless emulators agree on and publish a spec.

And to be clear on this point, it does not invent a new mode with 15 bpp or 8 bpp transfers. It simply behaves as if the hardware was a good old 2 bpp SGB, when SGB transfers are being requested. So if the game happens to not lock out the SGB code paths when GBC is detected, it will (with some probability) "just work".

@nitro2k01
Copy link
Member Author

Note also that games may not show a static screen at that point. For example, Aevilia plays an animation (clouds scrolling by) during boot-up, Libbet fades the Nintendo logo out, etc.

Oh, and another point about this. If you're planning to use a SGB border (which you likely are if you're detecting SGB) you need to display a static screen for a short while anyway for the data transfer of the border graphics. So this is something you need to plan your creative decisions around at any rate.

Aevilia is a GBC only game, so not really applicable. Libbet appears to simply detect SGB the traditional way (meaning the Nintendo logo stays static during detection, even on a DMG) and accept the extra delay that comes with that.

@avivace avivace changed the title Please remove the recommendation to rely on C==$14 as the main way of SGB detection Remove the recommendation to rely on C==$14 to detect SGB Oct 31, 2022
@avivace avivace added the content Improvements or additions to documentation label Oct 31, 2022
@pinobatch
Copy link
Member

Libbet fades the logo out

Libbet appears to simply detect SGB the traditional way (meaning the Nintendo logo stays static during detection, even on a DMG)

Correct. Libbet detects SGB using MLT_REQ while the logo is still up in order to decide whether to knock away the ®.

  • GBC (also A+B+Select+Start): Clear tilemap first, no ® deflection
  • DMG/SGB: Wait 30 frames, detect via MLT_REQ, and schedule ® deflection only if DMG

Perhaps ISSOtm was thinking of 144p Test Suite, which detects SGB while fading out the logo.

  1. Dark gray: Wait 8 frames while (presumably) various things in the SGB front end continue to initialize
  2. Light gray: Detect SGB using MLT_REQ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
content Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

5 participants