cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

05_banking_mbcs.md (13213B)


      1@page docs_rombanking_mbcs ROM/RAM Banking and MBCs
      2
      3
      4
      5# ROM/RAM Banking and MBCs (Memory Bank Controllers)
      6The 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).
      7
      8
      9## Non-banked cartridges
     10Cartridges 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`.
     11
     12
     13## MBC Banked cartridges (Memory Bank Controllers)
     14@anchor MBC
     15@anchor MBCS
     16Cartridges 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.
     17  - Bank 0 of the ROM is located in the region at `0000h - 3FFFh`. It is _usually_ fixed (non-banked) and cannot be switched out for another bank.
     18  - The higher region at `4000h to 7FFFh` is used for switching between different ROM banks.
     19
     20See the @ref Pandocs for more details about the individual MBCs and their capabilities.
     21
     22
     23# Working with Banks
     24To assign code and constant data (such as graphics) to a ROM bank and use it:
     25  - Place the code for your ROM bank in one or several source files.
     26  - Specify the ROM bank to use, either in the source file or at compile/link time.
     27  - Specify the number of banks and MBC type during link time.
     28  - When the program is running and wants to use data or call a function that is in a given bank, manually or automatically set the desired bank to active.
     29
     30
     31## Setting the ROM bank for a Source file
     32The 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.
     33
     34If no ROM and RAM bank are specified for a file then the default _CODE, _BSS and _DATA segments are used.
     35
     36Ways to set the ROM bank for a Source file:
     37  - `#pragma bank <N>` at the start of a source file. Example (ROM bank 2): `#pragma bank 2`
     38  - The lcc switch for ROM bank `-Wf-bo<N>`. Example (ROM bank 2): `-Wf-bo2`
     39  - Using @ref rom_autobanking
     40
     41Note: 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.
     42
     43
     44## Setting the RAM bank for a Source file
     45  - Using the lcc switch for RAM bank `-Wf-ba<N>`. Example (RAM bank 3): `-Wf-ba3`
     46
     47
     48@anchor setting_mbc_and_rom_ram_banks
     49## Setting the MBC and number of ROM & RAM banks available
     50
     51At the link stage this is done with @ref lcc using pass-through switches for @ref makebin.
     52  - `-Wl-yo<N>` where `<N>` is the number of ROM banks. 2, 4, 8, 16, 32, 64, 128, 256, 512
     53    - `-Wl-yoA` may be used for automatic bank size.
     54  - `-Wl-ya<N>` where `<N>` is the number of RAM banks. 2, 4, 8, 16, 32
     55  - `-Wl-yt<N>` where `<N>` is the type of MBC cartridge (see below).
     56    - Example: `Wl-yt0x1A`
     57
     58The MBC settings below are available when using the makebin MBC switch.
     59
     60Additional details available at [Pandocs](https://gbdev.io/pandocs/The_Cartridge_Header.html#0147---cartridge-type "Pandocs")
     61
     62```
     63# From Makebin source:
     64#
     65#-Wl-yt<NN> where <NN> is one of the numbers below
     66#
     67# 0147: Cartridge type:
     68# 0-ROM ONLY            12-ROM+MBC3+RAM
     69# 1-ROM+MBC1            13-ROM+MBC3+RAM+BATT
     70# 2-ROM+MBC1+RAM        19-ROM+MBC5
     71# 3-ROM+MBC1+RAM+BATT   1A-ROM+MBC5+RAM
     72# 5-ROM+MBC2            1B-ROM+MBC5+RAM+BATT
     73# 6-ROM+MBC2+BATTERY    1C-ROM+MBC5+RUMBLE
     74# 8-ROM+RAM             1D-ROM+MBC5+RUMBLE+SRAM
     75# 9-ROM+RAM+BATTERY     1E-ROM+MBC5+RUMBLE+SRAM+BATT
     76# B-ROM+MMM01           1F-Pocket Camera
     77# C-ROM+MMM01+SRAM      FD-Bandai TAMA5
     78# D-ROM+MMM01+SRAM+BATT FE - Hudson HuC-3
     79# F-ROM+MBC3+TIMER+BATT FF - Hudson HuC-1
     80# 10-ROM+MBC3+TIMER+RAM+BATT
     81# 11-ROM+MBC3
     82```
     83
     84
     85## Getting Bank Numbers
     86The bank number for a banked function, variable or source file can be stored and retrieved using the following macros:
     87  - @ref BANKREF(): create a reference for retrieving the bank number of a variable or function
     88  - @ref BANK(): retrieve a bank number using a reference created with @ref BANKREF()
     89  - @ref BANKREF_EXTERN(): Make a @ref BANKREF() reference residing in another source file accessible in the current file for use with @ref BANK().
     90
     91
     92## Banking and Functions
     93
     94@anchor banked_keywords
     95### BANKED/NONBANKED keywords
     96- `BANKED`:
     97  - The function will use banked sdcc calls.
     98  - Placed in the bank selected by its source file (or compiler switches).
     99- `NONBANKED`:
    100  - Placed in the non-banked lower 16K region (bank 0), regardless of the bank selected by its source file.
    101- `<not-specified>`:
    102  - The function does not use sdcc banked calls (`near` instead of `far`).
    103  - Placed in the bank selected by its source file (or compiler switches).
    104
    105@anchor banked_calls
    106### Banked Function Calls
    107Banked functions can be called as follows:
    108  - When defined with the `BANKED` keyword. Example: `void my_function() BANKED { do stuff }` in a source file which has had its bank set (see above).
    109  - Using @ref far_pointers
    110  - When defined with an area set up using the `__addressmod` keyword (see the `banks_new` example project and the SDCC manual for details).
    111  - Using @ref SWITCH_ROM() (and related functions for other MBCs) to manually switch in the required bank and then call the function.
    112
    113Non-banked functions (either in fixed Bank 0, or in an non-banked ROM with no MBC):
    114  - May call functions in any bank: __YES__
    115  - May use data in any bank: __YES__
    116
    117@todo Fill in this info for Banked Functions
    118Banked functions (located in a switchable ROM bank)
    119  - May call functions in any bank: ?
    120  - May use data in any bank: __NO__ (may only use data from currently active banks)
    121
    122Limitations:
    123  - SDCC banked calls and far_pointers in GBDK only save one byte for the ROM bank. So, for example, they are limited to __bank 31__ max for MBC1 and __bank 255__ max for MBC5. This is due to the bank switching for those MBCs requiring a second, additional write to select the upper bits for more banks (banks 32+ in MBC1 and banks 256+ in MBC5).
    124
    125
    126## Const Data (Variables in ROM)
    127@todo Const Data (Variables in ROM)
    128
    129
    130## Variables in RAM
    131@todo Variables in RAM
    132
    133
    134## Far Pointers
    135@anchor far_pointers
    136Far 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.
    137
    138__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.
    139
    140See @ref FAR_CALL, @ref TO_FAR_PTR and the `banks_farptr` example project.
    141
    142
    143## Bank switching
    144You can manually switch banks using the @ref SWITCH_ROM(), @ref SWITCH_RAM(), and other related macros. See `banks.c` project for an example.
    145
    146Note: 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`.
    147
    148
    149## Restoring the current bank (after calling functions which change it without restoring)
    150@anchor banking_current_bank
    151If a function call is made (for example inside an ISR) which changes the bank *without* restoring it, then the @ref _current_bank variable should be saved and then restored.
    152
    153For example, __instead__ of this code:
    154```
    155void vbl_music_isr(void)
    156{
    157    // A function which changes the bank and
    158    // *doesn't* restore it after changing.
    159    some_function();
    160}
    161```
    162It should be:
    163```
    164void vbl_music_isr(void)
    165{
    166    // Save the current bank
    167    uint8_t _saved_bank = _current_bank;
    168
    169    // A function which changes the bank and
    170    // *doesn't* restore it after changing.
    171    some_function();
    172
    173    // Now restore the current bank
    174    SWITCH_ROM(_saved_bank);
    175}
    176```
    177
    178## Currently active bank: _current_bank
    179The global variable @ref _current_bank is updated automatically when calling @ref SWITCH_ROM(), @ref SWITCH_ROM_MBC1() and @ref SWITCH_ROM_MBC5, or when a `BANKED` function is called.
    180
    181
    182
    183@anchor rom_autobanking
    184# Auto-Banking
    185A ROM bank auto-assignment feature was added in GBDK 2020 4.0.2.
    186
    187Instead 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.
    188
    189To turn on auto-banking, use the `-autobank` argument with lcc.
    190
    191For a source example see the `banks_autobank` project.
    192
    193In the source files you want auto-banked, do the following:
    194  - Set the source file to be autobanked `#pragma bank 255` (this sets the temporary bank to `255`, which @ref bankpack then updates when repacking).
    195  - Create a reference to store the bank number for that source file: `BANKREF(<some-bank-reference-name>)`.
    196    - More than one `BANKREF()` may be created per file, but they should always have unique names.
    197
    198In the other source files you want to access the banked data from, do the following:
    199  - Create an extern so the bank reference in another file is accessible: `BANKREF_EXTERN(<some-bank-reference-name>)`.
    200  - Obtain the bank number using  `BANK(<some-bank-reference-name>)`.
    201
    202Example: level_1_map.c
    203
    204        #pragma bank 255
    205        BANKREF(level_1_map)
    206        ...
    207        const uint8_t level_1_map[] = {... some map data here ...};
    208
    209Accessing that data: main.c
    210
    211      BANKREF_EXTERN(level_1_map)
    212      ...
    213      SWITCH_ROM( BANK(level_1_map) );
    214      // Do something with level_1_map[]
    215
    216Features and Notes:
    217  - Fixed banked source files can be used in the same project as auto-banked source files. The bankpack tool will attempt to pack the auto-banked source files as efficiently as possible around the fixed-bank ones.
    218
    219Making sure bankpack checks all files:
    220  - In order to correctly calculate the bank for all files every time, it is best to use the `-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.
    221
    222        Recommended: 
    223        .c and .s -> (compiler) .o -> (bankpack) -> .rel -> (linker) ... -> .gb
    224
    225  - It is important because when bankpack assigns a bank for an autobanked (bank=255) object file (.o) it rewrites the bank and will then no longer see the file as one that needs to be auto-banked. That file will then remain in its previously assigned bank until a source change causes the compiler to rebuild it to an object file again which resets its bank to 255.
    226
    227  - For example consider a fixed-bank source file growing too large to share a bank with an auto-banked source file that was previously assigned to it. To avoid a bank overflow it would be important to have the auto-banked file check every time whether it can share that bank or not.
    228
    229  - See @ref bankpack for more options and settings.
    230
    231
    232
    233# Errors related to banking (overflow, multiple writes to same location)
    234A _bank overflow_ during compile/link time (in @ref 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.
    235
    236See the @ref faq_bank_overflow_errors "FAQ entry about bank overflow errors".
    237
    238The current toolchain can only detect and warn (using @ref 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 @ref romusage tool.
    239
    240
    241
    242# Bank space usage
    243In order to see how much space is used or remains available in a bank, you can use the third-party @ref romusage tool.
    244
    245
    246## Other important notes
    247  - The @ref SWITCH_ROM_MBC5 macro is not interrupt-safe. If using less than 256 banks you may always use SWITCH_ROM - that is faster. Even if you use mbc5 hardware chip in the cart.
    248
    249
    250# Banking example projects
    251There are several projects in the GBDK 2020 examples folder which demonstrate different ways to use banking.
    252  - `Banks`: a basic banking example
    253  - `Banks_new`: examples of using new bank assignment and calling conventions available in GBDK 2020 and its updated SDCC version.
    254  - `Banks_farptr`: using far pointers which have the bank number built into the pointer.
    255  - `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.
    256