GBDK 2020 Docs
4.1.1
API Documentation for GBDK 2020
|
The standard Game Boy cartridge with no MBC has a fixed 32K bytes of ROM. In order to make cartridges with larger ROM sizes (to store more code and graphics) MBCs can be used. They allow switching between multiple ROM banks that use the same memory region. Only one of the banks can be selected as active at a given time, while all the other banks are inactive (and so, inaccessible).
Cartridges with no MBC controller are non-banked, they have 32K bytes of fixed ROM space and no switchable banks. For these cartridges the ROM space between 0000h and 7FFFh
can be treated as a single large bank of 32K bytes, or as two contiguous banks of 16K bytes in Bank 0
at 0000h - 3FFFh
and Bank 1
at 4000h to 7FFFh
.
Cartridges with MBCs allow the the Game Boy to work with ROMS up to 8MB in size and with RAM up to 128kB. Each bank is 16K Bytes. The following are usually true, with some exceptions:
0
of the ROM is located in the region at 0000h - 3FFFh
. It is fixed (non-banked) and cannot be switched out for another bank.1 .. N
can be switched into the upper region at 4000h - 7FFFh
. The upper limit for N
is determined by the MBC used and available cartridge space.0
for source files, that will happen by default if no bank is specified.See the Pandocs for more details about the individual MBCs and their capabilities.
For most projects we recommend MBC5.
When using MBCs and bank switching the space used in the lower fixed Bank 0
must be <= 16K bytes. Otherwise it's data will overflow into Bank 1
and may be overwriten or overwrite other data, and can get switched out when banks are changed.
See the FAQ entry about bank overflow errors.
When using MBCs, Bank 0
is the only bank which is always active and it's code can run regardless of what other banks are active. This means it is a limited resource and should be prioritized for data and functions which must be accessible regardless of which bank is currently active.
To assign code and constant data (such as graphics) to a ROM bank and use it:
The ROM and RAM bank for a source file can be set in a couple different ways. Multiple different banks cannot be assigned inside the same source file (unless the __addressmod
method is used), but multiple source files can share the same bank.
If no ROM and RAM bank are specified for a file then the default _CODE, _BSS and _DATA segments are used.
Ways to set the ROM bank for a Source file:
#pragma bank <N>
at the start of a source file. Example (ROM bank 2): #pragma bank 2
-Wf-bo<N>
. Example (ROM bank 2): -Wf-bo2
Note: You can use the NONBANKED
keyword to define a function as non-banked if it resides in a source file which has been assigned a bank.
-Wf-ba<N>
. Example (Cartridge SRAM bank 3): -Wf-ba3
At the link stage this is done with lcc using pass-through switches for makebin.
-Wm-yo<N>
where <N>
is the number of ROM banks. 2, 4, 8, 16, 32, 64, 128, 256, 512-Wm-yoA
may be used for automatic bank size.-Wm-ya<N>
where <N>
is the number of RAM banks. 2, 4, 8, 16, 32-Wm-yt<N>
where <N>
is the type of MBC cartridge (see chart below).Wm-yt0x1A
-Wm
part should be omitted.-yo A
) require a space when passed directly. See makebin-settings for details.The MBC settings below are available when using the makebin -Wl-yt<N>
switch.
Source: Pandocs. Additional details available at Pandocs
Hex Code | MBC Type | SRAM | Battery | RTC | Rumble | Extra | Max ROM Size (1) |
---|---|---|---|---|---|---|---|
0x00 | ROM ONLY | 32 K | |||||
0x01 | MBC-1 (2) | 2 MB | |||||
0x02 | MBC-1 (2) | SRAM | 2 MB | ||||
0x03 | MBC-1 (2) | SRAM | BATTERY | 2 MB | |||
0x05 | MBC-2 | 256 K | |||||
0x06 | MBC-2 | BATTERY | 256 K | ||||
0x08 | ROM (3) | SRAM | 32 K | ||||
0x09 | ROM (3) | SRAM | BATTERY | 32 K | |||
0x0B | MMM01 | 8 MB / N | |||||
0x0C | MMM01 | SRAM | 8 MB / N | ||||
0x0D | MMM01 | SRAM | BATTERY | 8 MB / N | |||
0x0F | MBC-3 | BATTERY | RTC | 2 MB | |||
0x10 | MBC-3 (4) | SRAM | BATTERY | RTC | 2 MB | ||
0x11 | MBC-3 | 2 MB | |||||
0x12 | MBC-3 (4) | SRAM | 2 MB | ||||
0x13 | MBC-3 (4) | SRAM | BATTERY | 2 MB | |||
0x19 | MBC-5 | 8 MB | |||||
0x1A | MBC-5 | SRAM | 8 MB | ||||
0x1B | MBC-5 | SRAM | BATTERY | 8 MB | |||
0x1C | MBC-5 | RUMBLE | 8 MB | ||||
0x1D | MBC-5 | SRAM | RUMBLE | 8 MB | |||
0x1E | MBC-5 | SRAM | BATTERY | RUMBLE | 8 MB | ||
0x20 | MBC-6 | ~2MB | |||||
0x22 | MBC-7 | SRAM | BATTERY | RUMBLE | SENSOR | 2MB | |
0xFC | POCKET CAMERA | To Do | |||||
0xFD | BANDAI TAMA5 | To Do | |||||
0xFE | HuC3 | RTC | To Do | ||||
0xFF | HuC1 | SRAM | BATTERY | IR | To Do |
1: Max possible size for MBC is shown. When used with generic SWITCH_ROM() the max size may be smaller. For example:
2: For MBC1 some banks in it's range are unavailable. See pandocs for more details https://gbdev.io/pandocs/MBC1
3: No licensed cartridge makes use of this option. Exact behaviour is unknown.
4: MBC3 with RAM size 64 KByte refers to MBC30, used only in Pocket Monsters Crystal Version for Japan.
The bank number for a banked function, variable or source file can be stored and retrieved using the following macros:
BANKED
(is a calling convention):NONBANKED
(is a storage attribute):_HOME
.<not-specified>
:near
instead of far
).Functions in banks can be called as follows:
BANKED
keyword. Example: void my_function() BANKED { do stuff }
in a source file which has had its bank set (see above).__addressmod
keyword (see the banks_new
example project and the SDCC manual for details).Non-banked functions (either in fixed Bank 0, or in an non-banked ROM with no MBC):
Banked functions (located in a switchable ROM bank)
BANKED
functions in any bank: YESLimitations:
Calling Convention:
Data declared as const
(read only) will be stored in ROM in the bank associated with it's source file (if none is specified it defaults to Bank 0). If that bank is a switchable bank then the data is only accesible while the given bank is active.
Far pointers include a segment (bank) selector so they are able to point to addresses (functions or data) outside of the current bank (unlike normal pointers which are not bank-aware). A set of macros is provided by GBDK 2020 for working with far pointers.
Warning: Do not call the far pointer function macros from inside interrupt routines (ISRs). The far pointer function macros use a global variable that would not get restored properly if a function called that way was interrupted by another one called the same way. However, they may be called recursively.
See FAR_CALL, TO_FAR_PTR and the banks_farptr
example project.
You can manually switch banks using the SWITCH_ROM(), SWITCH_RAM(), and other related macros. See banks.c
project for an example.
Note: You can only do a switch_rom_bank call from non-banked _CODE
since otherwise you would switch out the code that was executing. Global routines that will be called without an expectation of bank switching should fit within the limited 16k of non-banked _CODE
.
In order to load Data in one bank from code running in another bank a NONBANKED
wrapper function can be used. It can save the current bank, switch to another bank, operate on some data, restore the original bank and then return.
An example function which can :
The global variable _current_bank is updated automatically when calling SWITCH_ROM(), SWITCH_ROM_MBC1() and SWITCH_ROM_MBC5, or when a BANKED
function is called.
Normaly banked calls are used and the active bank does not need to be directly managed, but in the case that it does the following shows how to save and restore it.
A ROM bank auto-assignment feature was added in GBDK 2020 4.0.2.
Instead of having to manually specify which bank a source file will reside in, the banks can be assigned automatically to make the best use of space. The bank assignment operates on object files, after compiling/assembling and before linking.
To turn on auto-banking, use the -autobank
argument with lcc.
For a source example see the banks_autobank
project.
In the source files you want auto-banked, do the following:
#pragma bank 255
(this sets the temporary bank to 255
, which bankpack then updates when repacking).BANKREF(<some-bank-reference-name>)
.BANKREF()
may be created per file, but they should always have unique names.In the other source files you want to access the banked data from, do the following:
BANKREF_EXTERN(<some-bank-reference-name>)
.BANK(<some-bank-reference-name>)
.Example: level_1_map.c
Accessing that data: main.c
Features and Notes:
Making sure bankpack checks all files:
-ext=
flag and save the auto-banked output to a different extension (such as .rel
) and then pass the modified files to the linker. That way all object files will be processed each time the program is compiled. Recommended: .c and .s -> (compiler) .o -> (bankpack) -> .rel -> (linker) ... -> .gb
A bank overflow during compile/link time (in makebin) is when more code and data are allocated to a ROM bank than it has capacity for. The address for any overflowed data will be incorrect and the data is potentially unreachable since it now resides at the start of a different bank instead of the end of the expected bank.
See the FAQ entry about bank overflow errors.
The current toolchain can only detect and warn (using ihxcheck) when one bank overflows into another bank that has data at its start. It cannot warn if a bank overflows into an empty one. For more complete detection, you can use the third-party romusage tool.
In order to see how much space is used or remains available in a bank, you can use the third-party romusage tool.
There are several projects in the GBDK 2020 examples folder which demonstrate different ways to use banking.
Banks
: a basic banking exampleBanks_new
: examples of using new bank assignment and calling conventions available in GBDK 2020 and its updated SDCC version.Banks_farptr
: using far pointers which have the bank number built into the pointer.Banks_autobank
: shows how to use the bank auto-assignment feature in GBDK 2020 4.0.2 or later, instead of having to manually specify which bank a source file will reside it.