-
Notifications
You must be signed in to change notification settings - Fork 33
Part 11 Memory Bank Controllers
Go Home
The entire available memory space the Gameboy can access is limited to a 2-byte address (0xFFFF or 65,535 addresses). When you divide this space up between all the devices, it leaves a pretty limited amount of space to be able to access the cartridge ROM.
0x0000 - 0x7FFF = 32,767 bytes = 32KB
So, what happens when the game is bigger than 32KB? Well, then the cartridge would have a specialized piece of hardware that manages pieces of this memory and allowed the game to swap out sections of this addressable memory space for different chunks. These is called switchable banks.
0x0000 - 0x3FFF: 16KB ROM Bank 00, this is non-switchable
0x4000 - 0x7FFF: 16KB ROM Bank 01..NN (in cartridge, switchable bank number)
0xA000 - 0xBFFF: 8KB External RAM (in cartridge, switchable bank, if any)
The problem with this magic? Because it was a piece of hardware in the cartridge, it was common for different games to have different types of MBCs. This makes it difficult for emulators because it means that we need to write multiple MBCs. Fortunately, most of them behaved very similar to each other and according to the documentation, there seem to be five core mappers on the Gameboy. By comparison, the NES had hundreds of mappers!
These MBCs are:
Small games that are smaller than 32KB ROM do not require a MBC chip for ROM banking. The ROM is directly mapped to memory at 0x0000-0x7FFF. Optionally up to 8KB of RAM could be connected at 0xA000-0xBFFF.
This is the first MBC chip for the Gameboy. Any newer MBC chips are similar, so that is relative easy to upgrade a program from one MBC chip to another, or even to make it compatible to several different types of MBCs. The game controls which banks are active by writing to the ROM address space (0x0000-0x7FFF). This doesn't store the value since it is read-only, but activates switched in the MBC.
This area contains any of the 16KB banks of the ROM. This allows to address up to 125 ROM banks (almost 2MB). As described below, bank numbers 0x20, 0x40, and 0x60 cannot be used, resulting in the odd amount of 125 banks.
This area is used to address external RAM in the cartridge. It can support up to 32KB, in form of four 8KB banks at 0xA000-0xBFFF.
Before external RAM can be read or written, it must be enabled by writing to this address space. It is recommended to disable external RAM after accessing it, in order to protect its contents from damage during power down of the Gameboy. Usually the following values are used:
0x00: Disable RAM (default)
0x0A: Enable RAM
However, any value with 0x0A in the lower 4 bits enables RAM, and any other value disables RAM.
Writing to this address space selects the lower 5 bits of the ROM Bank Number (in range 0x01-0x1F). When 0x00 is written, the MBC translates that to bank 0x01. That doesn't cause any issues so far, because ROM Bank 0x00 can be always directly accessed by reading from 0x0000-0x3FFF, but the same happens for banks 0x20, 0x40, and 0x60. Any attempt to address these ROM Banks will select banks 0x21, 0x41, and 0x61 instead.
This 2-bit register can be used to select a RAM bank in range from 0x00-0x03, or to specify the upper two bits (Bit 5-6) of the ROM bank number, depending on the current ROM/RAM Mode. (See below.)
This 1-bit register selects whether the two bits of the above register should be used as upper two bits of the ROM bank, or as RAM bank Number.
0x00: ROM Banking Mode (up to 8KByte RAM, 2MByte ROM) (default)
0x01: RAM Banking Mode (up to 32KByte RAM, 512KByte ROM)
The program may freely switch between both modes, the only limitation is that only RAM Bank 0x00 can be used during mode 0 (ROM Banking), and only ROM Banks 0x00-0x1F can be used during mode 1 (RAM Banking).
Same as for MBC1.
Same as for MBC1, but only a total of 16 ROM banks are supported.
The MBC2 doesn't support external RAM, instead it includes 512 4-bits of built-in RAM. As the data consists of 4-bit values, only the lower 4 bits of the bytes in this memory area are used.
The least significant bit of the upper address byte must be zero to enable/disable RAM. For example, the following addresses can be used to enable/disable cart RAM: 0x0000-0x00FF, 0x0200-0x02FF, ..., 0x1E00-0x1EFF. The suggested address range to use for MBC2 RAM enable/disable is 0x0000-0x00FF.
Writing a value (XXXXBBBB - X = Don't cares, B = bank select bits) into 0x2000-0x3FFF area will select an appropriate ROM bank at 0x4000-0x7FFF. The least significant bit of the upper address byte must be one to select a ROM bank. For example the following addresses can be used to select a ROM bank: 0x2100-0x21FF, 0x2300-0x23FF, ..., 0x3F00-0x3FFF. The suggested address range to use for MBC2 ROM bank selection is 0x2100-0x21FF.
Beside for the ability to access up to 2MB ROM (128 banks), and 32KB RAM (4 banks), the MBC3 also includes a built-in Real Time Clock (RTC). The RTC requires an external 32.768 kHz Quartz Oscillator, and an external battery (if it should continue to tick when the Gameboy is turned off). The emulator would need to simulate this by maintaining time elapsed.
Same as for MBC1.
Same as for MBC1, except that accessing banks 0x20, 0x40, and 0x60 is supported now.
Depending on the current Bank Number/RTC Register selection (see below), this memory space is used to access an 8KB external RAM Bank, or a single RTC Register.
Mostly the same as for MBC1, a value of 0x0A will enable reading and writing to external RAM and the RTC Registers. A value of 0x00 will disable both.
Same as for MBC1, except that the whole 7 bits of the RAM bank number are written directly to this address. As for the MBC1, writing a value of 0x00, will select Bank 0x01 instead. All other values 0x01-0x7F select the corresponding ROM Banks.
As with the MBC1s RAM Banking Mode, writing a value in range for 0x00-0x03 maps the corresponding external RAM Bank (if any) into memory at 0xA000-0xBFFF. When writing a value of 0x08-0x0C, this will map the corresponding RTC register into memory at 0xA000-0xBFFF. That register could then be read/written by accessing any address in that area, typically that is done by using address 0xA000.
0x6000-0x7FFF - Latch Clock Data (Write Only) When writing 0x00, and then 0x01 to this register, the current time becomes latched into the RTC registers. The latched data will not change until it becomes latched again, by repeating the write 0x00->0x01 procedure. This is supposed for reading from the RTC registers. It is proof to read the latched (frozen) time from the RTC registers, while the clock itself continues to tick in background.
The Clock Counter Registers: 0x08: RTC S Seconds 0-59 (0-3Bh) 0x09: RTC M Minutes 0-59 (0-3Bh) 0x0A: RTC H Hours 0-23 (0-17h) 0x0B: RTC DL Lower 8 bits of Day Counter (0-FFh) 0x0C: RTC DH Upper 1 bit of Day Counter, Carry Bit, Halt Flag Bit 0: Most significant bit of Day Counter (Bit 8) Bit 6: Halt (0=Active, 1=Stop Timer) Bit 7: Day Counter Carry Bit (1=Counter Overflow)
The Halt Flag is supposed to be set before writing to the RTC Registers.
The total 9 bits of the Day Counter allow to count days in range from 0-511 (0x0000-0x01FF). The Day Counter Carry Bit becomes set when this value overflows. In that case, the Carry Bit remains set until the program does reset it. Note that you can store an offset to the Day Counter in battery RAM. For example, every time you read a non-zero Day Counter, add this Counter to the offset in RAM, and reset the Counter to zero. This method allows to count any number of days, making your program Year-10000-Proof, provided that the cartridge gets used at least every 511 days.
When accessing the RTC Registers it is recommended to execute a 4ms delay (4 Cycles in Normal Speed Mode) between the separate accesses.
This controller (made by Hudson Soft) appears to be very similar to an MBC1 with the main difference being that it supports infrared LED input / output. I think we can ignore this one for our emulator.