git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

commit bf08c55636ed0aa4537f4df0542420dd596c21c2
parent 9c420b4e62e8eaab06cdd719d7e5d3358efe4ec7
Author: bbbbbr <bbbbbr@users.noreply.github.com>
Date:   Thu,  9 Jun 2022 22:00:45 -0700

Merge pull request #369 from bbbbbr/docs_4_1_0

Docs: Misc Banking, Coding, FAQ, etc updates
Diffstat:
Mdocs/pages/02_links_and_tools.md25+++++++++++++++++--------
Mdocs/pages/03_using_gbdk.md12+++++++++++-
Mdocs/pages/04_coding_guidelines.md77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mdocs/pages/05_banking_mbcs.md113+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mdocs/pages/06_toolchain.md2+-
Mdocs/pages/06b_supported_consoles.md13++++++++++++-
Mdocs/pages/08_faq.md10+++++++---
7 files changed, 175 insertions(+), 77 deletions(-)

diff --git a/docs/pages/02_links_and_tools.md b/docs/pages/02_links_and_tools.md @@ -88,14 +88,7 @@ This is a brief list of useful tools and information. It is not meant to be comp @anchor tools_music -# Music drivers and tools - - @anchor gbt-player - __GBT Player__ - A .mod converter and music driver that works with GBDK and RGBDS. - https://github.com/AntonioND/gbt-player - Docs from GBStudio that should mostly apply: https://www.gbstudio.dev/docs/music/ - - +# Music And Sound Effects - @anchor hUGEdriver __hUGEtracker__ and __hUGEdriver__ A tracker and music driver that work with GBDK and RGBDS. @@ -104,6 +97,22 @@ This is a brief list of useful tools and information. It is not meant to be comp https://github.com/SuperDisk/hUGEDriver https://github.com/SuperDisk/hUGETracker + - @anchor CBT-FX + __CBT-FX__ + A sound effects driver which can play effects created in FX Hammer. + https://github.com/datguywitha3ds/CBT-FX + + - @anchor VGM2GBSFX + __VGM2GBSFX__ + A sound effects converter and driver for DMG VGM files, FX Hammer and PCM WAV files. + https://github.com/untoxa/VGM2GBSFX + + - @anchor gbt-player + __GBT Player__ + A .mod converter and music driver that works with GBDK and RGBDS. + https://github.com/AntonioND/gbt-player + Docs from GBStudio that should mostly apply: https://www.gbstudio.dev/docs/music/ + @anchor tools_emulators # Emulators diff --git a/docs/pages/03_using_gbdk.md b/docs/pages/03_using_gbdk.md @@ -56,10 +56,11 @@ If you want to use your own Interrupt Dispatcher instead of the GBDK chained dis Then, @ref ISR_VECTOR() or @ref ISR_NESTED_VECTOR() can be used to install a custom ISR handler. +@anchor isr_nowait_info ## Returning from Interrupts and STAT mode By default when an Interrupt handler completes and is ready to exit it will check STAT_REG and only return at the BEGINNING of either LCD Mode 0 or Mode 1. This helps prevent graphical glitches caused when an ISR interrupts a graphics operation in one mode but returns in a different mode for which that graphics operation is not allowed. -You can change this behavior using nowait_int_handler() which does not check @ref STAT_REG before returning. Also see @ref wait_int_handler(). +You can change this behavior using @ref nowait_int_handler() which does not check @ref STAT_REG before returning. Also see @ref wait_int_handler(). # What GBDK does automatically and behind the scenes @@ -73,6 +74,15 @@ Including @ref stdio.h and using functions such as @ref printf() will use a larg ## Default Interrupt Service Handlers (ISRs) - V-Blank: A default V-Blank ISR is installed on startup which copies the Shadow OAM to the hardware OAM and increments the global @ref sys_time variable once per frame. - Serial Link I/O: If any of the GBDK serial link functions are used such as @ref send_byte() and @ref receive_byte(), the default SIO serial link handler will be installed automatically at compile-time. + - APA Graphics Mode: When this mode is used (via @ref drawing.h) custom VBL and LCD ISRs handlers will be installed (`drawing_vbl` and `drawing_lcd`). Changing the mode to (`mode(M_TEXT_OUT);`) will cause them to be de-installed. These handlers are used to change the tile data source at start-of-frame and mid-frame so that 384 background tiles can be used instead of the typical 256. + + +## Ensuring Safe Access to Graphics Memory +There are certain times during each video frame when memory and registers relating to graphics are "busy" and should not be read or written to (otherwise there may be corrupt or dropped data). GBDK handles this automatically for most graphics related API calls. It also ensures that ISR handlers return in such a way that if they interrupted a graphics access then it will only resume when access is allowed. + +The ISR return behavior @ref isr_nowait_info "can be turned off" using the @ref nowait_int_handler. + +For more details see the related Pandocs section: https://gbdev.io/pandocs/Accessing_VRAM_and_OAM.html # Copying Functions to RAM and HIRAM diff --git a/docs/pages/04_coding_guidelines.md b/docs/pages/04_coding_guidelines.md @@ -154,8 +154,36 @@ If you wish to use the original tools, you must add the `const` keyword every ti - Learn some ASM and inspect the compiler output to understand what the compiler is doing and how your code gets translated. This can help with writing better C code and with debugging. +@anchor docs_constant_signedness +## Constants, Signed-ness and Overflows +There are a some scenarios where the compiler will warn about overflows with constants. They often have to do with mixed signedness between constants and variables. To avoid problems use care about whether or not constants are explicitly defined as unsigned and what type of variables they are used with. + +`WARNING: overflow in implicit constant conversion` + +- A constant can be used where the the value is too high (or low) for the storage medium causing an value overflow. + - For example this constant value is too high since the max value for a signed 8 bit char is `127`. + + #define TOO_LARGE_CONST 255 + int8_t signed_var = TOO_LARGE_CONST; + +- This can also happen when constants are not explicitly declared as unsigned (and so may get treated by the compiler as signed) and then added such that the resulting value exceeds the signed maximum. + - For example, this results in an warning even though the sum total is `254` which is less than the `255`, the max value for a unsigned 8 bit char variable. + + #define CONST_UNSIGNED 127u + #define CONST_SIGNED 127 + uint8_t unsigned_var = (CONST_SIGNED + CONST_UNSIGNED); + + - It can be avoided by always using the unsigned `u` when the constant is intended for unsigned operations. + + #define CONST_UNSIGNED 127u + #define CONST_ALSO_UNSIGNED 127u // <-- Added "u", now no warning + uint8_t unsigned_var = (CONST_UNSIGNED + CONST_ALSO_UNSIGNED); + + + + @anchor docs_chars_varargs -## chars and vararg functions +## Chars and vararg functions In standard C when `chars` are passed to a function with variadic arguments (varargs, those declared with `...` as a parameter), such as @ref printf(), those `chars` get automatically promoted to `ints`. For an 8 bit CPU such as the Game Boy's, this is not as efficient or desirable in most cases. So the default SDCC behavior, which GBDK-2020 expects, is that chars will remain chars and _not_ get promoted to ints when **explicitly cast as chars while calling a varargs function**. @@ -195,33 +223,42 @@ For many applications C is fast enough but in intensive functions are sometimes ## Calling convention -sdcc in common with almost all C compilers prepends a '_' to any function names. For example the function printf(...) begins at the label _printf::. Note that all functions are declared global. - -The parameters to a function are pushed in right to left order with no aligning - so a byte takes up a byte on the stack instead of the more natural word. So for example the function int store_byte( uint16_t addr, uint8_t byte) would push 'byte' onto the stack first then addr using a total of three bytes. As the return address is also pushed, the stack would contain: - - At SP+0 - the return address - At SP+2 - addr +SDCC in common with almost all C compilers prepends a `_` to any function names. For example the function `printf(...)` begins at the label `_printf::.` Note that all functions are declared global. - At SP+4 - byte +Functions can be marked with `OLDCALL` which will cause them to use the `__sdcccall(0)` calling convention instead of the new default `__sdcccall(1)` which replaced it. -Note that the arguments that are pushed first are highest in the stack due to how the Game Boy's stack grows downwards. - -The function returns in DE. +For details about the calling convetions, see sections `SM83 calling conventions` and `Z80, Z180 and Z80N calling conventions` in the SDCC manual. + - http://sdcc.sourceforge.net/doc/sdccman.pdf ## Variables and registers -C normally expects registers to be preserved across a function call. However in the case above as DE is used as the return value and HL is used for anything, only BC needs to be preserved. +<!-- C normally expects registers to be preserved across a function call. However in the case above as DE is used as the return value and HL is used for anything, only BC needs to be preserved. --> Getting at C variables is slightly tricky due to how local variables are allocated on the stack. However you shouldn't be using the local variables of a calling function in any case. Global variables can be accessed by name by adding an underscore. -## Segments -The use of segments for code, data and variables is more noticeable in assembler. GBDK and SDCC define a number of default segments - `_CODE`, `_DATA` and `_BSS`. Two extra segments `_HEADER` and `_HEAP` exist for the Game Boy header and malloc heap respectively. - -The order these segments are linked together is determined by crt0.s and is currently `_CODE` in ROM, then `_DATA`, `_BSS`, `_HEAP` in WRAM, with `STACK` at the top of WRAM. `_HEAP` is placed after `_BSS` so that all spare memory is available for the malloc routines. To place code in other than the first two banks, use the segments `_CODE_x` where x is the 16kB bank number. - -As the `_BSS` segment occurs outside the ROM area you can only use .ds to reserve space in it. - -While you don't have to use the `_CODE` and `_DATA` distinctions in assembler you may wish to do so to maintain consistency. +## Segments / Areas +The use of segments/areas for code, data and variables is more noticeable in assembler. GBDK and SDCC define a number of default ones. The order they are linked is determined by crt0.s and is currently as follows for the Game Boy and related clones. + + - ROM (in this order) + - `_HEADER`: For the Game Boy header + - `_CODE`: CODE is specified as after BASE, but is placed before it due to how the linker works. + - `_HOME` + - `_BASE` + - `_CODE_0` + - `_INITIALIZER`: Constant data used to init RAM data + - `_LIT` + - `_GSINIT`: Code used to init RAM data + - `_GSFINAL` + + - Banked ROM + - `_CODE_x` Places code in ROM other than Bank `0`, where x is the 16kB bank number. + + - WRAM (in this order) + - `_DATA`: Uninitialized RAM data + - `_BSS` + - `_INITIALIZED`: Initialized RAM data + - `_HEAP`: placed after `_INITIALIZED` so that all spare memory is available for the malloc routines. + - `STACK`: at the end of WRAM diff --git a/docs/pages/05_banking_mbcs.md b/docs/pages/05_banking_mbcs.md @@ -7,19 +7,30 @@ The standard Game Boy cartridge with no MBC has a fixed 32K bytes of ROM. In ord ## Non-banked cartridges -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 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`. ## MBC Banked cartridges (Memory Bank Controllers) @anchor MBC @anchor MBCS -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. - - 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. - - The higher region at `4000h to 7FFFh` is used for switching between different ROM banks. - +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: + - Bank `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. + - Banks `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. + - It is not necessary to manually assign Bank `0` for source files, that will happen by default if no bank is specified. + See the @ref Pandocs for more details about the individual MBCs and their capabilities. +### Bank 0 Size Limit and Overlows When Using MBCs +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 @ref faq_bank_overflow_errors "FAQ entry about bank overflow errors". + + +### Conserving Bank 0 for Important Functions and Data +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. + + # Working with Banks To assign code and constant data (such as graphics) to a ROM bank and use it: - Place the code for your ROM bank in one or several source files. @@ -92,12 +103,14 @@ The bank number for a banked function, variable or source file can be stored and ## Banking and Functions @anchor banked_keywords -### BANKED/NONBANKED keywords -- `BANKED`: +### BANKED/NONBANKED Keywords for Functions +- `BANKED` (is a calling convention): - The function will use banked sdcc calls. - Placed in the bank selected by its source file (or compiler switches). -- `NONBANKED`: + - This keyword only specifies the __calling convention__ for the function, it does not set a bank itself. +- `NONBANKED` (is a storage attribute): - Placed in the non-banked lower 16K region (bank 0), regardless of the bank selected by its source file. + - Forces the .area to `_HOME`. - `<not-specified>`: - The function does not use sdcc banked calls (`near` instead of `far`). - Placed in the bank selected by its source file (or compiler switches). @@ -114,17 +127,20 @@ Non-banked functions (either in fixed Bank 0, or in an non-banked ROM with no MB - May call functions in any bank: __YES__ - May use data in any bank: __YES__ -@todo Fill in this info for Banked Functions Banked functions (located in a switchable ROM bank) - - May call functions in any bank: ? - - May use data in any bank: __NO__ (may only use data from currently active banks) + - May call functions in fixed Bank 0: __YES__ + - May call `BANKED` functions in any bank: __YES__ + - The compiler and library will manage the bank switching automatically using the bank switching trampoline. + - May use data in any bank: __NO__ + - May only use data from Bank 0 and the currently active bank. + - A @ref wrapped_function_for_banked_data "NONBANKED wrapper function" may be used to access data in other banks. Limitations: - 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). ## Const Data (Variables in ROM) -@todo Const Data (Variables in ROM) +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. ## Variables in RAM @@ -146,38 +162,45 @@ You can manually switch banks using the @ref SWITCH_ROM(), @ref SWITCH_RAM(), an 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`. -## Restoring the current bank (after calling functions which change it without restoring) -@anchor banking_current_bank -If 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. +@anchor wrapped_function_for_banked_data +## Wrapper Function for Accessing Banked Data +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. -For example, __instead__ of this code: -``` -void vbl_music_isr(void) +An example function which can : +- Load background data from any bank +- And which can be called from code residing in any bank + +```{.c} +// This function is NONBANKED so it resides in fixed Bank 0 +void set_banked_bkg_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data, uint8_t bank) NONBANKED { - // A function which changes the bank and - // *doesn't* restore it after changing. - some_function(); + uint8_t save = _current_bank; + SWITCH_ROM(bank); + set_bkg_data(first_tile, nb_tiles, data); + SWITCH_ROM(save); } -``` -It should be: -``` -void vbl_music_isr(void) -{ - // Save the current bank - uint8_t _saved_bank = _current_bank; - - // A function which changes the bank and - // *doesn't* restore it after changing. - some_function(); - // Now restore the current bank - SWITCH_ROM(_saved_bank); -} +// And then it can be called from any bank: +set_banked_bkg_data(<first tile>, <num tiles>, tile_data, BANK(tile_data)); ``` + +@anchor banking_current_bank ## Currently active bank: _current_bank The 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. +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. + +```{.c} +// The current bank can be saved +uint8_t _saved_bank = _current_bank; + +// Call some function which changes the bank but does not restore it +// ... + +// And then restored if needed +SWITCH_ROM(_saved_bank); +``` @anchor rom_autobanking @@ -201,17 +224,21 @@ In the other source files you want to access the banked data from, do the follow Example: level_1_map.c - #pragma bank 255 - BANKREF(level_1_map) - ... - const uint8_t level_1_map[] = {... some map data here ...}; +```{.c} +#pragma bank 255 +BANKREF(level_1_map) +... +const uint8_t level_1_map[] = {... some map data here ...}; +``` Accessing that data: main.c - BANKREF_EXTERN(level_1_map) - ... - SWITCH_ROM( BANK(level_1_map) ); - // Do something with level_1_map[] +```{.c} +BANKREF_EXTERN(level_1_map) +... +SWITCH_ROM( BANK(level_1_map) ); +// Do something with level_1_map[] +``` Features and Notes: - 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. diff --git a/docs/pages/06_toolchain.md b/docs/pages/06_toolchain.md @@ -16,7 +16,7 @@ To see individual arguments and options for a tool, run that tool from the comma # Data Types -For data types and special C keywords, see @ref file_asm_gbz80_types_h "asm/gbz80/types.h" and @ref file_asm_types_h "asm/types.h". +For data types and special C keywords, see @ref file_asm_sm83_types_h "asm/sm83/types.h" and @ref file_asm_types_h "asm/types.h". Also see the SDCC manual (scroll down a little on the linked page): http://sdcc.sourceforge.net/doc/sdccman.pdf#section.1.1 diff --git a/docs/pages/06b_supported_consoles.md b/docs/pages/06b_supported_consoles.md @@ -137,7 +137,18 @@ In the example @ref utility_png2asset is used to generate assets in the native f # Porting From Game Boy to Analogue Pocket -The Analogue Pocket is (for practical purposes) functionally identical to the Game Boy / Color, but has a couple altered register flag and address definitions and a different boot logo. In order for software to be easily ported to the Analogue Pocket, or to run on both, use the following practices. +The Analogue Pocket operating in `.pocket` mode is (for practical purposes) functionally identical to the Game Boy / Color though it has a couple changes: + +Official differences: + - Altered register flag and address definitions + - Different boot logo + +Observed differences: + - MBC1 and MBC5 are supported, MBC3 won't save, the HuC3 isn't supported at all (via JoseJX) + - The Serial Link port does not work + - The IR port in CGB mode does not work as reliably as the Game Boy Color + + In order for software to be easily ported to the Analogue Pocket, or to run on both, use the following practices. ## Registers and Flags Use API defined registers and register flags instead of hardwired ones. diff --git a/docs/pages/08_faq.md b/docs/pages/08_faq.md @@ -57,7 +57,7 @@ - This may happen if you have large initialized arrays declared without the `const` keyword. It's important to use the const keyword for read-only data. See @ref const_gbtd_gbmb and @ref const_array_data <!-- --> - What flags should be enabled for debugging? - - You can use the @ref lcc_debug "lcc debug flag" <!-- --> + - You can use the @ref lcc_debug "lcc debug flag" `-debug`to turn on debug output. It covers most uses and removes the need to specify multiple flags such as `-Wa-l -Wl-m -Wl-j`. <!-- --> - Is it possible to generate a debug symbol file (`.sym`) compatible with the @ref bgb emulator? - Yes, turn on `.noi` output (LCC argument: `-Wl-j` or `-debug` and then use `-Wm-yS` with LCC (or `-yS` with makebin directly). <!-- --> @@ -66,8 +66,12 @@ - The default locations are: `_shadow_OAM=0xC000` and 240 bytes after it `_DATA=0xC0A0` - So, for example, if you wanted to move them both to start 256(0x100) bytes later, use these command line arguments for LCC: - To change the Shadow OAM address: `-Wl-g_shadow_OAM=0xC100` - - To change the DATA address (again, 240 bytes after the Shadow OAM): `-Wl-b_DATA=0xc1a0` - <!-- --> + - To change the DATA address (again, 240 bytes after the Shadow OAM): `-Wl-b_DATA=0xc1a0` <!-- --> + + - What does this warning mean? + `WARNING: overflow in implicit constant conversion` + - See @ref docs_constant_signedness "Constants, Signed-ness and Overflows" + <!-- --> # API / Utilities

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.