When the Game Boy was released back in 1989, using multiple megabytes of memory was inefficient from a design point-of-view because the cost of using so much memory was highly impractical for most companies to make back the initial production costs. However, as the years went by — and given Moore’s Law — the costs came down and, when it was discontinued in 2003, eight megabyte or larger cartridges were common.
However, by its original design, the Game Boy can only access 16 KB of ROM memory at a time. To get around this limitation, ROM sections of 16 KB code can be accessed through a technique called ‘banking’: one section of 16 KB code swapped for another.
By default, a Game Boy game, with no additional code or cartridge changes, is 32 KB with two 16 KB sections for all of its code, including any maps or large arrays.
Part of the way GBDK was designed was such that it doesn’t understand banking directly. Instead, it has the SWITCH_ROM_MBC1() function that can swap out existing ROM banks. However, to use additional banks requires additional compiling code instructions.
For each additional bank, the instructions “-Wf-boX -Wf-baX” need to be added where X is the bank a file represents.
To combine all the resulting files, use “-Wl-ytX -Wl-yoY -Wl-yaY” where X is the type of cartridge and Y is the number of total banks to the next power of two.
Note: If you are defining banks explicitly starting with at least one, use four total banks.
Switching, extern, and calling functions
Once a bank has been switched, its functions cannot normally be accessed. Anything that happens in that 16 KB is limited to that bank. However, using the keyword “extern,” a reference can be maintained into a separate bank when declaring a function. To use another bank’s functions, it is as easy as using something, like in the above example: extern void update().
Using this technique opens up the ability to build on the first concept from Part 4, as well: Make your code as module as possible.
Because of the much larger amount of memory now available through banking, the storage of more maps, arrays, and other larger data structures can be separated into other banks, initially loaded through SWITCH_ROM_MBC1() calls and then referencing them through use of extern. In fact, this is a common and even recommended practice to logically break up sections of dialogue, when using tile-based displaying, or to have many in-game area maps in different sections and as part of different ROM banks.