git.y1.nz

gbdk-2020

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

docs/pages/06b_supported_consoles.md

      1 @page docs_supported_consoles Supported Consoles & Cross Compiling
      2   
      3 @anchor docs_consoles_supported_list
      4 # Consoles Supported by GBDK
      5 As of version `4.2.0` GBDK includes support for other consoles in addition to the Game Boy.
      6 
      7   - Game Boy and related clones
      8     - Nintendo Game Boy / Game Boy Color (GB/GBC)
      9     - Analogue Pocket (AP)
     10     - Mega Duck / Cougar Boy (DUCK)
     11 
     12   - Sega Consoles
     13     - Sega Master System (SMS)
     14     - Sega Game Gear (GG)
     15 
     16   - NES/Famicom (NES)
     17 
     18   - MSX DOS (MSXDOS) (partial support)
     19 
     20 While the GBDK API has many convenience functions that work the same or similar across different consoles, it's important to keep their different capabilities in mind when writing code intended to run on more than one. Some (but not all) of the differences are screen sizes, color capabilities, memory layouts, processor type (z80 vs gbz80/sm83) and speed.
     21 
     22  
     23 @anchor docs_consoles_compiling
     24 # Cross Compiling for Different Consoles
     25 
     26 ## lcc
     27 When compiling and building through @ref lcc use the `-m<port>:<plat>` flag to select the desired console via its port and platform combination. See below for available settings.
     28 
     29 
     30 ## sdcc
     31 When building directly with the sdcc toolchain, the following must be specified manually
     32 (when using @ref lcc it will populate these automatically based on `-m<port>:<plat>`).
     33 
     34 When compiling with @ref sdcc-settings "sdcc":
     35   - `-m<port>`, `-D__PORT_<port>` and `-D__TARGET_<plat> `
     36 
     37 When assembling select the appropriate include path: `-I<gbdk-path>lib/<plat>`.
     38 
     39 The assemblers used are:
     40   - @ref sdasgb-settings "sdasgb" (for GB/AP)
     41   - @ref sdasz80-settings "sdasz80" (for SMS/GG)
     42   - @ref sdas6500-settings "sdas6500" (for NES)
     43 
     44 When linking:
     45   - Select the appropriate include paths: `-k <gbdk-path>lib/<port>`, `-k <gbdk-path>lib/<plat>`
     46   - Include the appropriate library files `-l <port>.lib`, `-l <plat>.lib`
     47   - The crt will be under `  <gbdk-path>lib/<plat>/crt0.o`
     48 
     49 The linkers used are:
     50    - @ref sdldgb-settings "sdldgb" (for GB/AP)
     51    - @ref sdldz80-settings "sdldz80" (for SMS/GG or MSXDOS)
     52    - @ref sdld6808-settings "sdld6808" (for NES)
     53 
     54 MSXDOS requires an additional build step with @ref utility_makecom "makecom" after @ref makebin to create the final binary:
     55   - `makecom <image.bin> [<image.noi>] <output.com>`
     56 
     57 
     58 @anchor console_port_plat_settings
     59 ## Console Port and Platform Settings
     60 Note: Starting with GBDK-2020 4.1.0 and SDCC 4.2, the Game Boy and related clones use `sm83` for the port instead of `gbz80`
     61 
     62   - Nintendo Game Boy / Game Boy Color    
     63     - @ref lcc : `-msm83:gb`
     64     - port:`sm83`, plat:`gb`
     65   - Analogue Pocket
     66     - @ref lcc : `-msm83:ap`
     67     - port:`sm83`, plat:`ap`
     68   - Mega Duck / Cougar Boy
     69     - @ref lcc : `-msm83:duck`
     70     - port:`sm83`, plat:`duck`
     71 
     72   - Sega Master System
     73     - @ref lcc : `-mz80:sms`
     74     - port:`z80`, plat:`sms`
     75   - Sega Game Gear
     76     - @ref lcc : `-mz80:gg`
     77     - port:`z80`, plat:`gg`
     78 
     79   - NES
     80     - @ref lcc : `-mmos6502:nes`
     81     - port:`mos6502`, plat:`nes`
     82 
     83   - MSX DOS
     84     - @ref lcc : `-mz80:msxdos`
     85     - port:`z80`, plat:`msxdos`
     86 
     87 
     88 # Cross-Platform Constants
     89 There are several constant \#defines that can be used to help select console specific code during compile time (with `#ifdef`, `#ifndef`) .
     90 
     91 ## Console Identifiers
     92   - When `<gb/gb.h>` is included (either directly or through `<gbdk/platform.h>`)
     93     - When building for Game Boy:
     94       - `NINTENDO` will be \#defined
     95       - `GAMEBOY` will be \#defined
     96     - When building for Analogue Pocket
     97       - `NINTENDO` will be \#defined
     98       - `ANALOGUEPOCKET` will be \#defined
     99     - When building for Mega Duck / Cougar Boy
    100       - `NINTENDO` will be \#defined
    101       - `MEGADUCK` will be \#defined
    102 
    103   - When `<sms/sms.h>` is included (either directly or through `<gbdk/platform.h>`)
    104     - When building for Master System
    105       - `SEGA` will be \#defined
    106       - `MASTERSYSTEM` will be \#defined
    107     - When building for Game Gear
    108       - `SEGA` will be \#defined
    109       - `GAMEGEAR` will be \#defined
    110 
    111   - When `<nes/nes.h>` is included (either directly or through `<gbdk/platform.h>`)
    112     - `NINTENDO_NES` will be \#defined
    113 
    114   - When `<msx/msx.h>` is included (either directly or through `<gbdk/platform.h>`)
    115     - `MSXDOS` will be \#defined
    116 
    117 ## Console Hardware Properties
    118 Constants that describe properties of the console hardware are listed below. Their values will change to reflect the current console target that is being built.
    119 
    120   - @ref DEVICE_SCREEN_X_OFFSET, @ref DEVICE_SCREEN_Y_OFFSET
    121   - @ref DEVICE_SCREEN_WIDTH, @ref DEVICE_SCREEN_HEIGHT
    122   - @ref DEVICE_SCREEN_BUFFER_WIDTH, @ref DEVICE_SCREEN_BUFFER_HEIGHT
    123   - @ref DEVICE_SCREEN_MAP_ENTRY_SIZE
    124   - @ref DEVICE_SPRITE_PX_OFFSET_X, @ref DEVICE_SPRITE_PX_OFFSET_Y
    125   - @ref DEVICE_SCREEN_PX_WIDTH, @ref DEVICE_SCREEN_PX_HEIGHT
    126   - @ref MAX_HARDWARE_SPRITES
    127   - @ref HARDWARE_SPRITE_CAN_FLIP_X, @ref HARDWARE_SPRITE_CAN_FLIP_Y
    128 
    129 
    130 # Using <gbdk/...> headers
    131 Some include files under `<gbdk/..>` are cross platform and others allow the build process to auto-select the correct include file for the current target port and platform (console).
    132 
    133 For example, the following can be used
    134     
    135     #include <gbdk/platform.h>
    136     #include <gbdk/metasprites.h>
    137 
    138 Instead of
    139 
    140     #include <gb/gb.h>
    141     #include <gb/metasprites.h>
    142 
    143 and
    144 
    145     #include <sms/sms.h>
    146     #include <sms/metasprites.h>
    147 
    148 
    149 @anchor docs_consoles_cross_platform_examples
    150 # Cross Platform Example Projects
    151 GBDK includes an number of cross platform example projects. These projects show how to write code that can be compiled and run on multiple different consoles (for example Game Boy and Game Gear) with, in some cases, minimal differences. 
    152 
    153 They also show how to build for multiple target consoles with a single build command and `Makefile`. The `Makefile.targets` allows selecting different `port` and `plat` settings when calling the build stages.
    154 
    155 ## Cross Platform Asset Example
    156 The cross-platform `Logo` example project shows how assets can be managed for multiple different console targets together.
    157 
    158 In the example @ref utility_png2asset is used to generate assets in the native format for each console at compile-time from separate source PNG images. The Makefile is set to use the source PNG folder which matches the current console being compiled, and the source code uses @ref set_bkg_native_data() to load the assets tiles in native format to the tile memory used for background tiles on that platform.
    159 
    160 
    161 # Hardware Summaries
    162 The specs below reflect the typical configuration of hardware when used with GBDK and is not meant as a complete list of their capabilities.
    163 
    164 GB/AP/DUCK
    165 - Sprites:
    166   - 256 tiles (upper 128 are shared with background) (amount is doubled in CGB mode)
    167   - tile flipping/mirroring: yes
    168   - 40 total, max 10 per line
    169   - 2 x 4 color palette (color 0 transparent). 8 x 4 color palettes in CGB mode
    170 - Background: 256 tiles (typical setup: upper 128 are shared with sprites) (amount is doubled in CGB mode)
    171   - tile grid size: 8x8
    172   - tile attribute grid size: 8x8 (CGB mode only)
    173   - tile flipping/mirroring: no (yes in CGB mode)
    174   - 1 x 4 color palette. 8 x 4 color palettes in CGB mode
    175 - Window "layer": available
    176 - Screen: 160 x 144
    177 - Hardware Map: 256 x 256
    178 
    179 
    180 SMS/GG
    181 - Sprites:
    182   - 256 tiles (a bit less in the default setup)
    183   - tile flipping/mirroring: no
    184   - 64 total, max 8 per line
    185   - 1 x 16 color palette (color 0 transparent)
    186 - Background: 512 tiles (upper 256 are shared with sprites)
    187   - tile grid size: 8x8
    188   - tile attribute grid size: 8x8
    189   - tile flipping/mirroring: yes
    190   - 2 x 16 color palettes
    191 - Window "layer": not available
    192 - SMS
    193   - Screen: 256 x 192
    194   - Hardware Map: 256 x 224
    195 - GG
    196   - Screen: 160 x 144
    197   - Hardware Map: 256 x 224
    198 
    199 NES/Famicom
    200 - Sprites:
    201   - 8x8 or 8x16
    202   - 256 tiles
    203   - tile flipping/mirroring: yes
    204   - 64 total, max 8 per line
    205   - 4 x 4 color palette (color 0 transparent)
    206 - Background: 256 tiles
    207   - tile grid size: 8x8
    208   - tile attribute grid size: 16x16 (bit packed into 32x32)
    209   - tile flipping/mirroring: no
    210   - 4 x 4 color palette (color 0 same for all sub-palettes)
    211 - Window "layer": not available
    212 - Screen: 256 x 240
    213 - Hardware Map: Depends on mirroring mode
    214   - 256 x 240 (single-screen mirroring)
    215   - 512 x 240 (vertical mirroring / horizontal scrolling)
    216   - 256 x 480 (horizontal mirroring / vertical scrolling)
    217   - 512 x 480 (4-screen layout. Requires additional RAM on cartridge)
    218 
    219 @anchor docs_consoles_safe_display_controller_access
    220 ## Safe VRAM / Display Controller Access
    221 
    222 GB/AP
    223 - VRAM / Display Controller (PPU)
    224   - VRAM and some other display data / registers should only be written to when the @ref STATF_B_BUSY bit of @ref STAT_REG is off. Most GBDK API calls manage this automatically.
    225 
    226 SMS/GG
    227 - Display Controller (VDP)
    228   - Writing to the VDP should not be interrupted while an operation is already in progress (since that will interfere with the internal data pointer causing data to be written to the wrong location).
    229   - Recommended approach: Avoid writing to the VDP (tiles, map, scrolling, colors, etc) during an interrupt routine (ISR).
    230   - Alternative (requires careful implementation): Make sure writes to the VDP during an ISR are only performed when the @ref _shadow_OAM_OFF flag indicates it is safe to do so.
    231 
    232 
    233 NES/Famicom
    234 - See @ref nes_technical_details "NES technical details"
    235 
    236 @anchor using_cgb_features
    237 # Using Game Boy Color (GBC/CGB) Features
    238 
    239 ## Differences Versus the Regular Game Boy (DMG/GBP/SGB)
    240 These are some of the main hardware differences between the Regular Game Boy and the Game Boy Color.
    241 
    242   - CPU: Optional 2x Speed mode
    243   - Serial Link: Additional Speeds 2KB/s, 32KB/s, 64KB/s
    244   - IR Port
    245   - Sprites:
    246     - 2 banks x 256 tile patterns (2x as many) (typically upper 128 of each bank shared with background)
    247     - 8 x 4 color palettes in CGB mode (BGR-555 per color, 32768 color choices)
    248   - Background:
    249     - 2 banks x 256 tile patterns (2x as many) (typically upper 128 of each bank shared with sprites)
    250     - Second map bank for tile attributes (color, flipping/mirroring, priority, bank)
    251     - 8 x 4 color palettes in CGB mode (BGR-555 per color, 32,768 color choices))
    252     - BG and Window master priority
    253   - WRAM: 8 x 4K WRAM banks in the 0xD000 - 0xDFFF region
    254   - LCD VRAM DMA
    255 
    256 ## Game Boy Color features in GBDK
    257 These are some of the main GBDK API features for the CGB. 
    258 Many of the items listed below link to additional information.
    259 
    260   - ROM header settings:
    261     - See the FAQ entry @ref faq_gb_type_header_setting "How do I set SGB, Color only and Color compatibility in the ROM header?"
    262   - Tile and Pattern data:
    263     - Select VRAM Banks: @ref VBK_REG (used with `set_bkg/win/sprite_*()`)
    264     - set_bkg_attributes(), set_bkg_submap_attributes()
    265   - Color:
    266     - set_bkg_palette(), set_bkg_palette_entry() 
    267     - set_sprite_palette(), set_sprite_palette_entry() 
    268     - set_default_palette()
    269     - RGB(), RGB8(), RGBHTML()
    270   - Detect and change CPU speed: if (@ref _cpu == @ref CGB_TYPE), cpu_fast()
    271   - More details in @ref cgb.h (`#include <gb/cgb.h>`)
    272 
    273 ## CGB Examples
    274 Several examples in GBDK show how to use CGB features, including the following:
    275   - `gb/colorbar`, `gb/dscan`, `cross-platform/large_map`, `cross-platform/logo`, `cross-platform/metasprites`
    276 
    277 
    278 # Porting Between Supported Consoles
    279 
    280 ## From Game Boy to Analogue Pocket
    281 The Analogue Pocket operating in `.pocket` mode is (for practical purposes) functionally identical to the Game Boy / Color though it has a couple changes listed below. These are handled automatically in GBDK as long as the practices outlined below are followed.
    282 
    283 ### Official differences:
    284    - Altered register flag and address definitions
    285      - @ref STAT_REG "STAT" & @ref LCDC_REG "LCDC": Order of register bits is reversed
    286        - Example: @ref LCDCF_B_ON "LCD on/off" is LCDC.0 instead of .7
    287        - Example: @ref STATF_B_LYC "LYC Interrupt enable" is STAT.1 instead of .6
    288      - @ref LCDC_REG "LCDC" address is `0xFF4E` instead of `0xFF40`
    289    - Different logo data in the header at address `0x0104`:
    290      - `0x01, 0x10, 0xCE, 0xEF, 0x00, 0x00, 0x44, 0xAA, 0x00, 0x74, 0x00, 0x18, 0x11, 0x95, 0x00, 0x34, 0x00, 0x1A, 0x00, 0xD5, 0x00, 0x22, 0x00, 0x69, 0x6F, 0xF6, 0xF7, 0x73, 0x09, 0x90, 0xE1, 0x10, 0x44, 0x40, 0x9A, 0x90, 0xD5, 0xD0, 0x44, 0x30, 0xA9, 0x21, 0x5D, 0x48, 0x22, 0xE0, 0xF8, 0x60`
    291                 
    292 ### Observed differences:
    293   - MBC1 and MBC5 are supported, MBC3 won't save and RTC doesn't progress when game is not running, the HuC3 isn't supported at all (via JoseJX and sg).
    294   - The Serial Link port does not work
    295   - The IR port in CGB mode does not work as reliably as the Game Boy Color
    296 
    297  In order for software to be easily ported to the Analogue Pocket, or to run on both, use the following practices.
    298 
    299 ### Registers and Flags
    300 Use API defined registers and register flags instead of hardwired ones.
    301    - LCDC register: @ref LCDC_REG or @ref rLCDC
    302    - STAT register: @ref STAT_REG or @ref rSTAT
    303    - LCDC flags: -> LCDCF_... (example: @ref LCDCF_ON)
    304    - STAT flags: -> STATF_... (example: @ref STATF_LYC)
    305 
    306 ### Boot logo
    307 As long as the target console is @ref docs_consoles_compiling "set during build time" then the correct boot logo will be automatically selected.
    308 
    309 
    310 ## From Game Boy to SMS/GG
    311 
    312 ### RAM Banks
    313 - The SMS/GG ROM file size must be at least 64K to enable mapper support for RAM banks in emulators.
    314   - If the generated ROM is too small then `-yo 4` for makebin (or `-Wm-yo4` for LCC) can be used to set the size to 64K.
    315 
    316 ### Tile Data and Tile Map loading
    317 
    318 #### Tile and Map Data in 2bpp Game Boy Format
    319 - @ref set_bkg_data() and @ref set_sprite_data() will load 2bpp tile data in "Game Boy" format on both GB and SMS/GG.
    320 - On the SMS/GG @ref set_2bpp_palette() sets 4 colors that will be used when loading 2bpp assets with set_bkg_data(). This allows GB assets to be easily colorized without changing the asset format. There is some performance penalty for using the conversion.
    321 - @ref set_bkg_tiles() loads 1-byte-per-tile tilemaps both for the GB and SMS/GG.
    322 
    323 #### Tile and Map Data in Native Format
    324 Use the following api calls when assets are avaialble in the native format for each platform.
    325 
    326 @ref set_native_tile_data()
    327   - GB/AP: loads 2bpp tiles data
    328   - SMS/GG: loads 4bpp tile data
    329 
    330 @ref set_tile_map()
    331   - GB/AP: loads 1-byte-per-tile tilemaps
    332   - SMS/GG: loads 2-byte-per-tile tilemaps
    333 
    334 There are also bit-depth specific API calls:
    335 - 1bpp: @ref set_1bpp_colors, @ref set_bkg_1bpp_data, @ref set_sprite_1bpp_data
    336 - 2bpp: @ref set_2bpp_palette, @ref set_bkg_2bpp_data, @ref set_sprite_2bpp_data, @ref set_tile_2bpp_data (sms/gg only)
    337 - 2bpp: @ref set_bkg_4bpp_data (sms/gg only), @ref set_sprite_4bpp_data (sms/gg only)
    338 
    339 
    340 ### Colors and Palettes
    341 The SMS/GG have 2 x 16 color palettes:
    342 - The first (0) is just for the background
    343 - The second (1) is shared between sprites and the background (and for sprites a single color 0 of that palette is transparent)
    344 
    345 On the Game Gear
    346 - Each Palette is 32 bytes in size: 16 colors x 2 bytes per palette color entry.
    347 - Each color (16 per palette) is packed as BGR-444 format (x:4:4:4, MSBits [15..12] are unused).
    348 - Each component (R, G, B) may have values from 0 - 15 (4 bits), 15 is brightest.
    349 
    350 On the SMS
    351 - On SMS each Palette is 16 bytes in size: 16 colors x 1 byte per palette color entry.
    352 - Each color (16 per palette) is packed as BGR-222 format (x:2:2:2, MSBits [7..6] are unused).
    353 - Each component (R, G, B) may have values from 0 - 3 (2 bits), 3 is brightest.
    354 
    355 For setting palette data:
    356 - @ref set_palette_entry(): Will set a single color in a palette
    357 - @ref set_palette(): Can set all the colors for one or both palettes
    358 - @ref set_bkg_palette(): Is just an alias for @ref set_palette(). The full 16 colors can be set using this call.
    359 - @ref set_sprite_palette(): Is also an alias for @ref set_palette(), but it offsets to write to the second 16 color palette.
    360 - Also see: @ref RGB(), RGB8(), @ref RGBHTML()
    361 
    362 
    363 #### Emulated Game Boy Color map attributes on the SMS/Game Gear
    364 On the Game Boy Color, @ref VBK_REG is used to select between the regular background tile map and the background attribute tile map (for setting tile color palette and other properties).
    365 
    366 This behavior is emulated for the SMS/GG when using @ref set_bkg_tiles() and @ref VBK_REG. It allows writing a 1-byte tile map separately from a 1-byte attributes map.
    367 
    368 @note Tile map attributes on SMS/Game Gear use different control bits than the Game Boy Color, so a modified attribute map must be used.
    369 
    370 
    371 @anchor nes_technical_details
    372 ## From Game Boy to NES
    373 
    374 The NES graphics architecture is similar to the GB's. However, there are a number of design choices in the NES hardware that make the NES a particularly cumbersome platform to develop for, and that will require special attention.
    375 
    376 Most notably:
    377 * PPU memory can only be written in a serial fashion using a data port at 0x2007 (PPUDATA)
    378 * PPU memory can only be written to during vblank, or when manually disabling rendering via PPUMASK. Hblank writes to PPU memory are not possible
    379 * PPU memory write address is re-purposed for scrolling coordinates when rendering is enabled which means PPU memory updates / scrolling must cooperate
    380 * PPU internal palette memory is also mapped to external VRAM area making palette updates during rendering very expensive and error-prone
    381 * The base NES system has no support for any scanline interrupts. And cartridge mappers that add scanline interrupts do so using wildly varying solutions
    382 * There's no easy way to determine the current scanline or CPU-to-PPU alignment meaning timed code is often required on the NES
    383 * The PAL variant of the NES has very different CPU / PPU timings, as do the Dendy clone and other clone systems
    384 * The stock 2 kB CPU RAM is just 1/4th the 8kB CPU RAM on a Game Boy
    385   - Free RAM after accounting for ZP, stack, OAM page and system variables further cuts this in half
    386   - This means a lot of GB code will need to be carefully optimized for RAM usage when ported to the NES
    387   - In particular, make sure to use the "const" modifier for arrays that are read-only, to make sure they don't end up in RAM
    388   
    389 To provide an easier experience, gbdk-nes attempts to hide most of these quirks so that in theory the programming experience for gbdk-nes should be as close as possible to that of the GB/GBC. However, to avoid surprises it is recommended to familiarize yourself with the NES-specific quirks and implementation choices mentioned here.
    390 
    391 This entire section is written as a guide on porting GB projects to NES. If you are new to GBDK, you may wish to familiarize yourself with using GBDK for GB development first as the topics covered will make a lot more sense after gaining experience with GB development.
    392 
    393 ### Mapper
    394 
    395 Currently the NES support in GBDK uses UNROM-512 (Mapper30) with single-screen mirroring.
    396 
    397 ### Buffered mode vs direct mode
    398 
    399 On the GB, the vblank period serves as an optimal time to write data to PPU memory, and PPU memory can also be written efficiently with VRAM DMA.
    400 
    401 On the NES, writing PPU memory during the vblank period is not optional. Whenever rendering is turned on the PPU is in a state where accessing PPU memory results in undefined behavior outside the short vblank period. The NES also has no VRAM DMA hardware to help with data writes. This makes the vblank period not only more precious, but important to never exceed to avoid glitched games.
    402 
    403 To deal with this limitation, all functions in gbdk-nes that write to PPU memory can run in either *Buffered* or *Direct* mode.
    404 
    405 The good news is that switching between buffered and direct mode in gbdk-nes is usually done behind-the-scenes and normally shouldn't affect your code too much, as long as you use the portable GBDK functions and macros to do this.
    406 
    407 * DISPLAY_ON / SHOW_BG / SHOW_SPR will all switch the system into buffered mode, allowing limited amounts of transfers during vblank, without affecting the display of graphics
    408 * DISPLAY_OFF will switch the system into direct mode, allowing much larger/faster transfers while the screen is blanked
    409 
    410 The following sections describe how the buffered / direct modes work in more detail. As buffered / direct mode is mostly hidden by the API calls, feel free to skip these sections if you wish.
    411 
    412 #### Buffered mode implementation details
    413 
    414 To take maximum advantage of the short vblank period, gbdk-nes implements a popular optimization: An unrolled loop that pulls prepared data bytes from the stack.
    415 
    416     PLA
    417     STA PPUDATA
    418     ...
    419     PLA
    420     STA PPUDATA
    421     RTS
    422 
    423 The data structure to facilitate this is usually called a vram transfer buffer, often affectionately called a "popslide" buffer after Damian Yerrick's implementation. This buffer essentially forms a list of commands where each command sets up a new PPU address and then writes a sequence of bytes with an auto-increment of either +1 or +32. Each such command is often called a "stripe" in the nesdev community.
    424 
    425 The transfer buffer starts at 0x100 and takes around half of the hardware stack page. You can think of the transfer buffer as a software-implemented DMA that allows writing bytes at the optimal rate of 8 cycles / byte. (ignoring the PPU address setup cost)
    426 
    427 The buffer supports writing up to 32 continuous bytes at a time. This allows updating a full screen row / column, or two 8x8 tiles worth of tile data in one command / "stripe".
    428 
    429 By doing writes to this buffer during game logic, your game will effectively keep writing data transfer commands for the vblank NMI handler to process in the next vblank period, without having to wait until the vblank.
    430 
    431 Given that the transfer buffer only has space for around 100 data bytes, it is important to not overfill the buffer, as this will bring code execution to a screeching halt, until the NMI handler empties the old contents of the buffer to free up space and allow new commands to be written.
    432 
    433 Buffered mode is typically used for scrolling updates or dynamically animated tiles, where only a small amount of bytes need updating per frame.
    434 
    435 #### Direct mode implementation details
    436 
    437 During direct mode, all graphics routines will write directly to the PPUADDR / PPUDATA ports and the transfer buffer limit is never a concern because the transfer buffer is effectively bypassed.
    438 
    439 Direct mode is typically used for initializing large amounts of tile data at boot and/or level loading time. Unless you plan to have an animated loading screen and decompress a lot of data, it makes more sense to just fade the screen to black and allow direct mode to write data as fast as possible.
    440 
    441 Direct mode also affects how (fake) interrupt handlers are processed. As long as vsync() is called on each frame, the VBL and LCD handlers will still be executed in direct mode - but no graphics registers will be written.
    442 
    443 The TIM handler will still be executed as normal.
    444 
    445 #### Caveat: Write appropriate global backdrop before turning display off
    446 
    447 On the GB, when the display is turned off the LCD will display a whiter-than-white color.
    448 
    449 On the NES, calling DISPLAY_OFF will turn sprites and BG off and allow VRAM writes in direct mode. But the color displayed will be last global backdrop color (i.e. palette entry 0) that was written before DISPLAY_OFF was called.
    450 
    451 Because all palette writes will be postponed in direct mode, the same also applies to other palette entries: Their values will be maintained in RAM, but never actually reach the PPU's hardware palette registers until buffered mode is re-entered by calling DISPLAY_ON.
    452 
    453 You should not try to do any palette fades after calling DISPLAY_OFF, as they will be delayed in direct mode until the display is turned on again with DISPLAY_ON. Once DISPLAY_ON is called, the NMI handler will start updating the hardware palette registers with the RAM registers as normal.
    454 
    455 ### Shadow PPU registers
    456 
    457 Like the SMS, the NES hardware is designed to only allow loading the full X/Y scroll on the very first scanline. i.e., under normal operation you are only allowed to change the Y-scroll once.
    458 
    459 In contrast to the SMS, this limitation can be circumvented with a specific set of out-of-order writes to the PPUSCROLL/PPUADDR registers, taking advantage of the quirk that the PPUADDR and PPUSCROLL share register bits. But this write sequence is very timing-sensitive as the writes need to fall into (a smaller portion of) the hblank period in order to avoid race conditions when the CPU and PPU both try to update the same register during scanline rendering.
    460 
    461 To simplify the programming interface, gbdk-nes functions like move_bkg / scroll_bkg only ever update shadow registers in RAM. The vblank NMI handler will later pick these values up and write them to the actual PPU registers registers.
    462 
    463 ### Implementation of (fake) vbl / lcd handlers
    464 
    465 GBDK provides an API for installing Interrupt Service Routines that execute on start of vblank (VBL handler), or on a specific scanline (LCD handler).
    466 
    467 But the base NES system has no suitable scanline interrupts that can provide the exact equivalent functionality. So instead, gbdk-nes API allows *fake* handlers to be installed in the goal of keeping code compatible with other platforms.
    468 
    469 * An installed VBL handler will be called immediately when calling vsync. This handler should only update PPU shadow registers. After each invocation, shadow registers are stored into a buffer.
    470 * An installed LCD handler for a specific scanline will then be called repeatedly until the value of _lcd_scanline is either set to an earlier scanline or >= 240. After each invocation, shadow registers are stored into a buffer.
    471 * After the built-in vblank NMI handler has finished palette updates, OAM DMA, VRAM updates it will then use the buffered VBL shadow registers to write the real registers. If LCD handlers are enabled it will then manually run a delay loop to reach the particular scanlines that the installed LCD handler was pre-called for, and use the contents of the buffer to update registers.
    472 
    473 Because the LCD "ISR" is actually implemented with a delay loop, it will burn a lot of CPU cycles in the frame - the further down the requested scanline is the larger the CPU cycle loss.
    474 In practice this makes this faked-LCD-ISR functionality mostly suitable for status bars at the top of the screen screen. Or for simple parallax cutscenes where the CPU has little else to do.
    475 
    476 To make porting between user VBL / LCD handlers written in C easier, gbdk-nes also provides aliases for the shadow registers that correspond to the GB hardware registers.
    477 
    478 * @ref SCX_REG is an alias for @ref bkg_scroll_x shadow register
    479 * @ref SCY_REG is an alias for @ref bkg_scroll_y shadow register
    480 * @ref LYC_REG is an alias for @ref _lcd_scanline shadow register
    481 
    482 Because these are shadow registers that are interpreted by the GBDK library to mimick GB behaviour, they won't behave exactly how the GB hardware registers do under all conditions. However, for most practical purposes they allow writing portable VBL / LCD handlers in C.
    483 
    484 @note
    485 The bkg_scroll_y shadow register functions the same as @ref SCY_REG GB, with its value added to @ref _lcd_scanline to determine the final Y scrolling coordinate. However, its range is different due to tilemaps being 32x30 instead 32x32. 
    486 
    487 Negative coordinates won't work correctly due to the wrapping from 239 to 0. Instead, they need to be corrected with this wrapping in mind. i.e. a negative coordinate of -1 needs to be converted to 239 before being written to bkg_scroll_y.
    488 
    489 A portable way to do this is to check for a negative offset, and use the screen height define:
    490 
    491   SCY_REG = offset < 0 ? (uint8_t)(DEVICE_SCREEN_BUFFER_HEIGHT*8 + offset) : offset;
    492 
    493 ### Caveat: Make sure to call vsync on every frame
    494 
    495 On the GB, the call to vsync is an optional call that serves two purposes:
    496 
    497 1. It provides a consistent frame timing for your game 
    498 2. It allows future register writes to be synchronized to the screen
    499 
    500 On gbdk-nes the second point is no longer true, because writes need to be made to the shadow registers either *before* vsync is called, or in a user VBL isr handler.
    501 
    502 But the vsync call serves three other very important purposes:
    503 
    504 A. It calls the optional VBL handler, where shadow registers can be written (and will later be picked up by the actual vblank NMI handler)
    505 B. It repeatedly calls the optional LCD handler up to MAX_LCD_ISR_CALLS times. After each call, PPU shadow registers are stored into a buffer that will later be used by timed code in the NMI to handle mid-frame changes for screen splits / sprite hiding / etc.
    506 C. It calls flush_shadow_attributes so that updates to background attributes actually get written to PPU memory
    507 
    508 For these reasons you should always include a call to vsync if you expect to see any graphical updates on the screen.
    509 
    510 ### Implementation of timer handler
    511 
    512 The nature of the deferred handling for fake VBL and LCD handlers in gbdk-nes means that lag frames will cause these handlers to be called at delayed irregular times.
    513 
    514 For graphics updates this is the behaviour you usually want. But for non-graphics tasks like music playback it will cause distracting stutter.
    515 
    516 The timer overflow handler (TIM) provides an alternative method that is guaranteed to be stutter-free. The TIM handler is always called if timer overflow occurs at the end of the NMI handler in both buffered and direct mode. 
    517 
    518 The TMA_REG and TAC_REG hardware registers are emulated via RAM variable with the same names. The timer emulation matches the values of these registers for a GBC running in double-speed mode. But there will be a small variation in exact frequency compared to real GBC hardware, and the nature of the timer emulation via vblank means the execution is not as evenly paced as on GBC hardware.
    519 
    520 The TIMA_REG should not be written or read in gbdk-nes, as the emulation does not handle its contents exactly as on GB.
    521 
    522 At reset, TAC_REG is set to clock rate 00 and timer enabled, and TMA_REG is set to either of two values, depending on the detected system:
    523 
    524 * TIMER_VBLANK_PARITY_MODE_SYSTEM_60HZ for a Famicom / US NES
    525 * TIMER_VBLANK_PARITY_MODE_SYSTEM_50Hz for a PAL NES / PAL Famiclone
    526 
    527 These default values ensure that the TIM emulation will always call the TIM handler exactly once for every vblank, resulting in 60Hz vs 50Hz depending on the system.
    528 
    529 Changing TMA_REG allows setting a slower or faster frequency for this emulated timer overflow interrupt if your GB game uses the timer overflow hardware for regular events like music that are slower or faster than 60Hz (50Hz for PAL).
    530 
    531 If you are porting a GB game to gbdk-nes where the music handler is called in the VBL or LCD handler then it is advisable to move this call to the timer handler, in order to achieve reliable music playback at 60Hz (50Hz for PAL).
    532 
    533 Keep in mind that you should NOT write any graphics registers in the TIM handler. This will likely not do what you want, and it may result in bad graphical glitches.
    534 
    535 Tweaking the playback rate by setting TMA_REG / TAC_REG is a decent way to achieve the same average playback rate as on a GB game that uses a different rate than the vblank tick rate and allow similar music speed for different regions. 
    536 
    537 However, it is recommended to use the default vblank parity mode whenever remaking the music specifically for 60Hz / 50Hz is an option, as keeping the music tick rate steady will give more pleasant sound playback for rates that are already close to native vblank rate of 60Hz / 50Hz.
    538 
    539 @anchor docs_nes_tim_overlay
    540 @note
    541 Because the TIM handler will be called from the vblank NMI, this function and all functions it calls need to use the `#pragma nooverlay` command. This makes memory for local variables and function parameters unique to this function instead of being shared with other functions' allocations in the reusable overlay segment.
    542 
    543     #pragma save
    544     #pragma nooverlay
    545     void tim_isr(void)
    546     {
    547         // Do TIM isr things
    548     }
    549     #pragma restore
    550 
    551 Without this pragma the calls in your TIM handler could end up overwriting local variables or function parameters that the main program was using when it was interrupted.
    552 You should also avoid calls to the standard library, and even multiplications and division / modulo operations in your TIM handlers. These more expensive math operations in SDCC are currently implemented with functions that use the overlay segment and would cause similar conflicts.
    553 For more details on overlay segment and interrupts, please see section 3.7 in the SDCC manual.
    554 
    555 ### Tile Data and Tile Map loading
    556 
    557 #### Tile and Map Data in 2bpp Game Boy Format
    558 - @ref set_bkg_data() and @ref set_sprite_data() will load 2bpp tile data in "Game Boy" format on both GB and NES.
    559 <!--- On the NES @ref set_2bpp_palette() ... not support.  -->
    560 - @ref set_bkg_tiles() loads 1-byte-per-tile tilemaps both for the GB and NES.
    561 
    562 #### Tile and Map Data in Native Format
    563 Use the following api calls when assets are available in the native format for each platform.
    564 
    565 @ref set_native_tile_data()
    566   - GB/AP: loads 2bpp tiles data
    567   - NES: loads 2bpp tiles data
    568 
    569 @ref set_tile_map()
    570   - GB/AP: loads 1-byte-per-tile tilemaps
    571   - NES: loads 1-byte-per-tile tilemaps
    572 
    573 Bit-depth specific API calls:
    574 - 1bpp: @ref set_1bpp_colors, @ref set_bkg_1bpp_data, @ref set_sprite_1bpp_data
    575 - 2bpp: @ref set_2bpp_palette, @ref set_bkg_2bpp_data, @ref set_sprite_2bpp_data
    576 
    577 Platform specific API calls:
    578 - set_bkg_attributes_nes16x16(), set_bkg_submap_attributes_nes16x16(), set_bkg_attribute_xy_nes16x16()
    579 
    580 
    581 #### Game Boy Color map attributes on the NES
    582 On the Game Boy Color, @ref VBK_REG is used to select between the regular background tile map and the background attribute tile map (for setting tile color palette and other properties).
    583 
    584 This behavior of setting VBK_REG to specify tile indices/attributes is not supported on the NES platform. Instead the dedicated functions for attribute setting should be used. These will work on other platforms as well and are the preferred way to set attributes.
    585 
    586 To maintain API compatibility with other platforms that have attributes on an 8x8 grid specified with a whole byte per attribute, the NES platform supports the dedicated calls for setting attributes on an 8x8 grid:
    587 - set_bkg_attributes()
    588 - set_bkg_submap_attributes()
    589 - set_bkg_attribute_xy()
    590 
    591 This allows code to for attribute setting to remain unchanged between platforms. The effect of using these calls is that some attribute setting will be redundant due to the coarser attribute grid. i.e., setting the attribute at coordinates (4, 4), (4,5), (5, 4) and (5, 5) will all set the same attribute.
    592 
    593 There is one more platform specific difference to note: While the set_bkg_attribute_xy() function takes coordinates on a 8x8 grid, the set_bkg_attributes() and set_bkg_submap_attributes() functions take a pointer to data in NES packed attribute format, where each byte contains data for 4 16x16 attribute. i.e. a 32x32 region. 
    594 
    595 While this implementation detail of how the attribute map is encoded is usually hidden by the API functions it does mean that code which manually tries to read the attribute data is *NOT* portable between NES/other platforms, and is not recommended.
    596 
    597 @note Tile map attributes on NES are on a 16x16 grid and use different control bits than the Game Boy Color.
    598 - NES 16x16 Tile Attributes are bit packed into 4 attributes per byte with each 16x16 area of a 32x32 pixel block using the bits as follows:
    599   - D1-D0: Top-left 16x16 pixels
    600   - D3-D2: Top-right 16x16 pixels
    601   - D5-D4: Bottom-left 16x16 pixels
    602   - D7-D6: Bottom-right 16x16 pixels
    603   - https://www.nesdev.org/wiki/PPU_attribute_tables
    604 
    605 
    606 ## From Game Boy to Mega Duck / Cougar Boy
    607 The Mega Duck is (for practical purposes) functionally identical to the Original Game Boy though it has a couple changes listed below.
    608 
    609 ### Summary of Hardware changes:
    610   - Cartridge Boot Logo: not present on Mega Duck
    611   - Cartridge Header data: not present on Mega Duck
    612   - Program Entry Point: `0x0000` (on Game Boy: `0x0100` )
    613   - Display registers and flag definitions: Some changed
    614   - Audio registers and flag definitions: Some changed
    615   - MBC ROM bank switching register address: `0x0001` (many Game Boy MBCs use `0x2000 - 0x3FFF`)
    616   - Also see @ref links_megaduck_docs "links for megaduck development"
    617 
    618 ### Best Practices
    619 In order for software to be easily ported to the Mega Duck, or to run on both, use these practices. That will allow GBDK to automatically handle _most_ of the differences (for the exceptions see @ref megaduck_sound_register_value_changes "Sound Register Value Changes").
    620   - @ref docs_consoles_compiling "Set the target console during build time"
    621   - Use the GBDK definitions and macros for:
    622     - Video Registers and Flags (examples: @ref LCDC_REG, @ref LCDCF_BG8000, etc)
    623     - Audio Registers and Flags (examples: @ref NR12_REG, @ref NR43_REG, etc)
    624     - Use the default @ref SWITCH_ROM macro for changing ROM banks
    625 
    626 @anchor megaduck_sound_register_value_changes
    627 ### Sound Register Value Changes
    628 There are two hardware changes which will not be handled automatically when following the practices mentioned above.
    629 
    630 These changes may be required when using existing Sound Effects and Music Drivers written for the Game Boy.
    631 
    632 1. Registers @ref NR12_REG, @ref NR22_REG, @ref NR42_REG, and @ref NR43_REG have their contents nybble swapped.
    633     - To maintain compatibility the value to write (or the value read) can be converted this way: `((uint8_t)(value << 4) | (uint8_t)(value >> 4))`
    634 2. Register @ref NR32_REG has the volume bit values changed.
    635     - `Game Boy:  Bits:6..5 : 00 = mute, 01 = 100%, 10 = 50%, 11 = 25%`
    636     - `Mega Duck: Bits:6..5 : 00 = mute, 01 = 25%,  10 = 50%, 11 = 100%`
    637     - To maintain compatibility the value to write (or the value read) can be converted this way: `(((~(uint8_t)value) + (uint8_t)0x20u) & (uint8_t)0x60u)`
    638 
    639 ### Graphics Register Bit Changes
    640 These changes are handled automatically when their GBDK definitions are used.
    641 
    642 | @ref LCDC_REG Flag   | Game Boy | Mega Duck |        | Purpose                                          |
    643 | -------------------- | -------- | --------- | ------ | ------------------------------------------------ |
    644 | @ref LCDCF_B_ON      | .7       | .7        | (same) | Bit for LCD On/Off Select                        |
    645 | @ref LCDCF_B_WIN9C00 | .6       | .3        |        | Bit for Window Tile Map Region Select            |
    646 | @ref LCDCF_B_WINON   | .5       | .5        | (same) | Bit for Window Display On/Off Control            |
    647 | @ref LCDCF_B_BG8000  | .4       | .4        | (same) | Bit for BG & Window Tile Data Region Select      |
    648 | @ref LCDCF_B_BG9C00  | .3       | .2        |        | Bit for BG Tile Map Region Select                |
    649 | @ref LCDCF_B_OBJ16   | .2       | .1        |        | Bit for Sprites Size Select                      |
    650 | @ref LCDCF_B_OBJON   | .1       | .0        |        | Bit for Sprites Display Visible/Hidden Select    |
    651 | @ref LCDCF_B_BGON    | .0       | .6        |        | Bit for Background Display Visible Hidden Select |
    652 
    653 
    654 ### Detailed Register Address Changes
    655 These changes are handled automatically when their GBDK definitions are used.
    656 
    657 | Register      | Game Boy | Mega Duck |
    658 | ------------- | -------- | --------- |
    659 | @ref LCDC_REG | 0xFF40   | 0xFF10    |
    660 | @ref STAT_REG | 0xFF41   | 0xFF11    |
    661 | @ref SCY_REG  | 0xFF42   | 0xFF12    |
    662 | @ref SCX_REG  | 0xFF43   | 0xFF13    |
    663 | @ref LY_REG   | 0xFF44   | 0xFF18    |
    664 | @ref LYC_REG  | 0xFF45   | 0xFF19    |
    665 | @ref DMA_REG  | 0xFF46   | 0xFF1A    |
    666 | @ref BGP_REG  | 0xFF47   | 0xFF1B    |
    667 | @ref OBP0_REG | 0xFF48   | 0xFF14    |
    668 | @ref OBP1_REG | 0xFF49   | 0xFF15    |
    669 | @ref WY_REG   | 0xFF4A   | 0xFF16    |
    670 | @ref WX_REG   | 0xFF4B   | 0xFF17    |
    671 | -             | -        | -         |
    672 | @ref NR10_REG | 0xFF10   | 0xFF20    |
    673 | @ref NR11_REG | 0xFF11   | 0xFF22    |
    674 | @ref NR12_REG | 0xFF12   | 0xFF21    |
    675 | @ref NR13_REG | 0xFF13   | 0xFF23    |
    676 | @ref NR14_REG | 0xFF14   | 0xFF24    |
    677 | -             | -        | -         |
    678 | @ref NR21_REG | 0xFF16   | 0xFF25    |
    679 | @ref NR22_REG | 0xFF17   | 0xFF27    |
    680 | @ref NR23_REG | 0xFF18   | 0xFF28    |
    681 | @ref NR24_REG | 0xFF19   | 0xFF29    |
    682 | -             | -        | -         |
    683 | @ref NR30_REG | 0xFF1A   | 0xFF2A    |
    684 | @ref NR31_REG | 0xFF1B   | 0xFF2B    |
    685 | @ref NR32_REG | 0xFF1C   | 0xFF2C    |
    686 | @ref NR33_REG | 0xFF1D   | 0xFF2E    |
    687 | @ref NR34_REG | 0xFF1E   | 0xFF2D    |
    688 | -             | -        | -         |
    689 | @ref NR41_REG | 0xFF20   | 0xFF40    |
    690 | @ref NR42_REG | 0xFF21   | 0xFF42    |
    691 | @ref NR43_REG | 0xFF22   | 0xFF41    |
    692 | @ref NR44_REG | 0xFF23   | 0xFF43    |
    693 | -             | -        | -         |
    694 | @ref NR50_REG | 0xFF24   | 0xFF44    |
    695 | @ref NR51_REG | 0xFF25   | 0xFF46    |
    696 | @ref NR52_REG | 0xFF26   | 0xFF45    |
    697 | -             | -        | -         |

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