10

It's something I've always been wondering:

Almost all of the hardware registers on the Gameboy are placed between $ff00 and $ff7f (with plenty of gaps and empty space), the HRAM is located between $ff80 and $fffe, and just the Interrupt Enable register is at $ffff.

I would've expected the HRAM to span up to $ffff and the Interrupt Enable register to be somewhere in the regular hardware registers area, for example perhaps next to the Interrupt Flag register at $ff0f (and $ff0e is unused, even).

Thus, there's must've been some benefit or rationale for placing the Interrupt Enable register at $ffff, and I'm wondering what it is.

1
  • The standard guess would be that the registers are distributed between different chips — HRAM is also on the CPU — but it'd be really odd to separate the flag register and the enable register. Also the only schematic I can find (here: fms.komkon.org/GameBoy/Tech/GameBoy.gif ) seems to suggest that the thing was virtually a system-on-a-chip, with only a couple of SRAMs besides the LR35902 itself. So I'm not sure that theory is much of a starter here. – Tommy Oct 11 '19 at 18:45
7

You'll need to understand something about address decoding to understand what's likely going on in the Game Boy. The Wilson Mines address decoding page is well worth a read, but to summarize, you use logic gates to examine various parts of the address on the address bus and enable and disable different chips (RAM, ROM, I/O devices) based on the address that appears there. Generally you wouldn't do "full decoding" because examining all sixteen lines of the address bus takes more logic (more gates) than examining, say, just eight or twelve of them.¹

The Game Boy is a "system on a chip": with the exception of the RAM and (most of) the ROM, everything is placed on the same die as the CPU, including the video circuitry, sound generator, and so on. However, designs like this are not generally made de novo, but usually by combining existing discrete chips on to a single die. Thus, their interfaces will tend to remain consistent with the interfaces they had when they were in separate packages. So the decoding logic for I/O access between the CPU component and the other components will still be quite similar to what it was when these separate devices were on separate chips, even though they're now all put side-by-side on the same chip.

Thus, one still accesses the peripheral devices just as if they were on separate chips: access to the registers of the peripherals is done by decoding specific addreses to set enable signals that cause those peripherals to read the data (and sometimes a few low bits of the address) bus. If you look through Game Boy I/O map (the I/O Ports section of this page is probably the easiest overview to read, but less accurate than the pandocs), you'll notice it divides into fairly easily decodable pieces along these lines, with unused "holes" in places you'd expect them when doing binary address encoding:

$FF00 - $FF0F   Misc. I/O Buttons, serial interface, timers,
                interrupt source (hole from $FF08 to $FF0E)
$FF10 - $FF2F   Sound (hole from $FF27 to $FF2F)
$FF30 - $FF3F   Wave pattern RAM
$FF40 - $FF7F   Video (hole from $FF4C to $FF7F)

The interrupt logic is a bit special. 8080 CPUs require not only that the interrupt line be asserted by a peripheral, as is typical in microprocessor systems, but also that after this a specific value is put on the data bus to determine which interrupt routine to call. The GB's customized LR35902 CPU preserves the separate interrupt vectors (from $0040 through $0060, as documented here.

If you were doing a system with traditional separated chips for the GB hardware and a real 8080 CPU, you'd need some substantial additional external logic to handle determining the correct interrupt vector for a device and getting that on to the bus. My guess is that Nintendo, since they were tweaking the CPU core anyway, probably decided the easiest way to handle this was with further changes to the this part of the CPU core, controlled by a register written via a memory location. Since this would be accessed very differently from how "external" devices (not part of the CPU core) would accessed, it's not a great surprise to find this register in a completely different memory area from the external devices.

This is just speculation, of course; reverse-engineering the chip would actually show whether or not the circuitry is built along these lines.


¹My personal experience is that I/O layouts and access can be very mysterious and confusing until you truly understand decoding logic, down to the level of the individual AND, OR, etc. gates being used. If this answer doesn't make any sense at all to you, you probably need to better under address decoding. Unfortunately, this isn't entirely trivial and a proper explanation of which is beyond the scope of this answer. But this example may help.

2
  • 1
    Great answer, you might be on to something. However, note that $ff47..$ff4b are used by Video too (listed out of order by your IO page) and $ff30..$ff3f are used by wave ram (not listed by your IO page). I used bgb.bircd.org/pandocs.htm#videodisplay as a source. I originally wanted to reply that it seems addresses like $ffxf might be reserved for the CPU core (in the decoding logic) since I thought no other $ffxf address is mapped ($ff1f is another gap for example), but sadly $ff3f is mapped to wave ram... – secondperson Oct 13 '19 at 13:02
  • @secondperson Thanks for your comment! It did feel to me like something was missing from those mappings but I couldn't find a good, easily readable summary of the I/O area. I've tweaked it to add the sound area and the video part I missed. – cjs Oct 13 '19 at 14:22
1

It has been recently observed (in nesdev) that the Gameboy CPU appears equivalent to the SM83 CPU described in this PDF.

(Both CPUs appear to have the same instruction set and the same interrupt vector locations - but are connected to different hardware and interrupts)

Looking at the SM83-using hardware in the PDF (SM8311/SM8313/SM8314/SM8315) - it has:

  • All I/O registers between $ffd0 and $ffff
  • The IE register at $ffff (same place as in the Gameboy)
  • The IF register at $fffe

It should also be noticed that, as per the diagram in page 148 in that PDF, the interrupt logic (including IE and IF) is part of the CPU core.

Now, the rest is pure speculation, but perhaps something in the design of the SM83 CPU required the IE register to be in $ffff, so while the rest of the I/O registers (including IF) have been successfully relocated to $ff00 to $ff7f in the gameboy, IE just couldn't be moved the same way, and was kept in $ffff as a compromise?

(E.g. perhaps the CPU relies on IE being at an all-ones address)

Of course, that does raise the question of why the gameboy moved the I/O area to $ff00..$ff7f, instead of putting the HRAM there...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.