mirror of
https://github.com/gbdk-2020/gbdk-2020.git
synced 2026-03-04 22:44:54 +01:00
824 lines
66 KiB
HTML
824 lines
66 KiB
HTML
<!-- HTML header for doxygen 1.8.14-->
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="cache-control" content="max-age=86400"/>
|
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
|
<meta name="generator" content="Doxygen 1.9.1"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<title>GBDK 2020 Docs: Supported Consoles & Cross Compiling</title>
|
|
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="jquery.js"></script>
|
|
<script type="text/javascript" src="dynsections.js"></script>
|
|
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="resize.js"></script>
|
|
<script type="text/javascript" src="navtreedata.js"></script>
|
|
<script type="text/javascript" src="navtree.js"></script>
|
|
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="search/searchdata.js"></script>
|
|
<script type="text/javascript" src="search/search.js"></script>
|
|
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
|
<link href="doxygen_extra.css" rel="stylesheet" type="text/css"/>
|
|
</head>
|
|
<body>
|
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
<div id="titlearea">
|
|
<table cellspacing="0" cellpadding="0">
|
|
<tbody>
|
|
<tr style="height: 56px;">
|
|
<td id="projectalign" style="padding-left: 0.5em;">
|
|
<div id="projectname">GBDK 2020 Docs
|
|
 <span id="projectnumber">4.3.0</span>
|
|
</div>
|
|
<div id="projectbrief">API Documentation for GBDK 2020</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<!-- end header part -->
|
|
<!-- Generated by Doxygen 1.9.1 -->
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
|
var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
|
|
/* @license-end */
|
|
</script>
|
|
<script type="text/javascript" src="menudata.js"></script>
|
|
<script type="text/javascript" src="menu.js"></script>
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
|
$(function() {
|
|
initMenu('',true,false,'search.php','Search');
|
|
$(document).ready(function() { init_search(); });
|
|
});
|
|
/* @license-end */</script>
|
|
<div id="main-nav"></div>
|
|
</div><!-- top -->
|
|
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
|
<div id="nav-tree">
|
|
<div id="nav-tree-contents">
|
|
<div id="nav-sync" class="sync"></div>
|
|
</div>
|
|
</div>
|
|
<div id="splitbar" style="-moz-user-select:none;"
|
|
class="ui-resizable-handle">
|
|
</div>
|
|
</div>
|
|
<script type="text/javascript">
|
|
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
|
$(document).ready(function(){initNavTree('docs_supported_consoles.html',''); initResizable(); });
|
|
/* @license-end */
|
|
</script>
|
|
<div id="doc-content">
|
|
<!-- window showing the filter options -->
|
|
<div id="MSearchSelectWindow"
|
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
|
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
|
</div>
|
|
|
|
<!-- iframe showing the search results (closed by default) -->
|
|
<div id="MSearchResultsWindow">
|
|
<iframe src="javascript:void(0)" frameborder="0"
|
|
name="MSearchResults" id="MSearchResults">
|
|
</iframe>
|
|
</div>
|
|
|
|
<div class="PageDoc"><div class="header">
|
|
<div class="headertitle">
|
|
<div class="title">Supported Consoles & Cross Compiling </div> </div>
|
|
</div><!--header-->
|
|
<div class="contents">
|
|
<div class="textblock"><p><a class="anchor" id="docs_consoles_supported_list"></a></p>
|
|
<h1><a class="anchor" id="autotoc_md142"></a>
|
|
Consoles Supported by GBDK</h1>
|
|
<p>As of version <code>4.2.0</code> GBDK includes support for other consoles in addition to the Game Boy.</p>
|
|
<ul>
|
|
<li>Game Boy and related clones<ul>
|
|
<li>Nintendo Game Boy / Game Boy Color (GB/GBC)</li>
|
|
<li>Analogue Pocket (AP)</li>
|
|
<li>Mega Duck / Cougar Boy (DUCK)</li>
|
|
</ul>
|
|
</li>
|
|
<li>Sega Consoles<ul>
|
|
<li>Sega Master System (SMS)</li>
|
|
<li>Sega Game Gear (GG)</li>
|
|
</ul>
|
|
</li>
|
|
<li>NES/Famicom (NES)</li>
|
|
<li>MSX DOS (MSXDOS) (partial support)</li>
|
|
</ul>
|
|
<p>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.</p>
|
|
<p><a class="anchor" id="docs_consoles_compiling"></a></p>
|
|
<h1><a class="anchor" id="autotoc_md143"></a>
|
|
Cross Compiling for Different Consoles</h1>
|
|
<h2><a class="anchor" id="autotoc_md144"></a>
|
|
lcc</h2>
|
|
<p>When compiling and building through <a class="el" href="docs_toolchain.html#lcc">lcc</a> use the <code>-m<port>:<plat></code> flag to select the desired console via its port and platform combination. See below for available settings.</p>
|
|
<h2><a class="anchor" id="autotoc_md145"></a>
|
|
sdcc</h2>
|
|
<p>When building directly with the sdcc toolchain, the following must be specified manually (when using <a class="el" href="docs_toolchain.html#lcc">lcc</a> it will populate these automatically based on <code>-m<port>:<plat></code>).</p>
|
|
<p>When compiling with <a class="el" href="docs_toolchain_settings.html#sdcc-settings">sdcc</a>:</p><ul>
|
|
<li><code>-m<port></code>, <code>-D__PORT_<port></code> and <code>-D__TARGET_<plat></code></li>
|
|
</ul>
|
|
<p>When assembling select the appropriate include path: <code>-I<gbdk-path>lib/<plat></code>.</p>
|
|
<p>The assemblers used are:</p><ul>
|
|
<li><a class="el" href="docs_toolchain_settings.html#sdasgb-settings">sdasgb</a> (for GB/AP)</li>
|
|
<li><a class="el" href="docs_toolchain_settings.html#sdasz80-settings">sdasz80</a> (for SMS/GG)</li>
|
|
<li><a class="el" href="docs_toolchain_settings.html#sdas6500-settings">sdas6500</a> (for NES)</li>
|
|
</ul>
|
|
<p>When linking:</p><ul>
|
|
<li>Select the appropriate include paths: <code>-k <gbdk-path>lib/<port></code>, <code>-k <gbdk-path>lib/<plat></code></li>
|
|
<li>Include the appropriate library files <code>-l <port>.lib</code>, <code>-l <plat>.lib</code></li>
|
|
<li>The crt will be under <code><gbdk-path>lib/<plat>/crt0.o</code></li>
|
|
</ul>
|
|
<p>The linkers used are:</p><ul>
|
|
<li><a class="el" href="docs_toolchain_settings.html#sdldgb-settings">sdldgb</a> (for GB/AP)</li>
|
|
<li><a class="el" href="docs_toolchain_settings.html#sdldz80-settings">sdldz80</a> (for SMS/GG or MSXDOS)</li>
|
|
<li><a class="el" href="docs_toolchain_settings.html#sdld6808-settings">sdld6808</a> (for NES)</li>
|
|
</ul>
|
|
<p>MSXDOS requires an additional build step with <a class="el" href="docs_toolchain.html#utility_makecom">makecom</a> after <a class="el" href="docs_toolchain.html#makebin">makebin</a> to create the final binary:</p><ul>
|
|
<li><code>makecom <image.bin> [<image.noi>] <output.com></code></li>
|
|
</ul>
|
|
<p><a class="anchor" id="console_port_plat_settings"></a></p>
|
|
<h2><a class="anchor" id="autotoc_md146"></a>
|
|
Console Port and Platform Settings</h2>
|
|
<p>Note: Starting with GBDK-2020 4.1.0 and SDCC 4.2, the Game Boy and related clones use <code>sm83</code> for the port instead of <code>gbz80</code></p>
|
|
<ul>
|
|
<li>Nintendo Game Boy / Game Boy Color <br />
|
|
<ul>
|
|
<li><a class="el" href="docs_toolchain.html#lcc">lcc</a> : <code>-msm83:gb</code></li>
|
|
<li>port:<code>sm83</code>, plat:<code>gb</code></li>
|
|
</ul>
|
|
</li>
|
|
<li>Analogue Pocket<ul>
|
|
<li><a class="el" href="docs_toolchain.html#lcc">lcc</a> : <code>-msm83:ap</code></li>
|
|
<li>port:<code>sm83</code>, plat:<code>ap</code></li>
|
|
</ul>
|
|
</li>
|
|
<li>Mega Duck / Cougar Boy<ul>
|
|
<li><a class="el" href="docs_toolchain.html#lcc">lcc</a> : <code>-msm83:duck</code></li>
|
|
<li>port:<code>sm83</code>, plat:<code>duck</code></li>
|
|
</ul>
|
|
</li>
|
|
<li>Sega Master System<ul>
|
|
<li><a class="el" href="docs_toolchain.html#lcc">lcc</a> : <code>-mz80:sms</code></li>
|
|
<li>port:<code>z80</code>, plat:<code>sms</code></li>
|
|
</ul>
|
|
</li>
|
|
<li>Sega Game Gear<ul>
|
|
<li><a class="el" href="docs_toolchain.html#lcc">lcc</a> : <code>-mz80:gg</code></li>
|
|
<li>port:<code>z80</code>, plat:<code>gg</code></li>
|
|
</ul>
|
|
</li>
|
|
<li>NES<ul>
|
|
<li><a class="el" href="docs_toolchain.html#lcc">lcc</a> : <code>-mmos6502:nes</code></li>
|
|
<li>port:<code>mos6502</code>, plat:<code>nes</code></li>
|
|
</ul>
|
|
</li>
|
|
<li>MSX DOS<ul>
|
|
<li><a class="el" href="docs_toolchain.html#lcc">lcc</a> : <code>-mz80:msxdos</code></li>
|
|
<li>port:<code>z80</code>, plat:<code>msxdos</code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h1><a class="anchor" id="autotoc_md147"></a>
|
|
Cross-Platform Constants</h1>
|
|
<p>There are several constant #defines that can be used to help select console specific code during compile time (with <code>#ifdef</code>, <code>#ifndef</code>) .</p>
|
|
<h2><a class="anchor" id="autotoc_md148"></a>
|
|
Console Identifiers</h2>
|
|
<ul>
|
|
<li>When <code><gb/gb.h></code> is included (either directly or through <code><gbdk/platform.h></code>)<ul>
|
|
<li>When building for Game Boy:<ul>
|
|
<li><code>NINTENDO</code> will be #defined</li>
|
|
<li><code>GAMEBOY</code> will be #defined</li>
|
|
</ul>
|
|
</li>
|
|
<li>When building for Analogue Pocket<ul>
|
|
<li><code>NINTENDO</code> will be #defined</li>
|
|
<li><code>ANALOGUEPOCKET</code> will be #defined</li>
|
|
</ul>
|
|
</li>
|
|
<li>When building for Mega Duck / Cougar Boy<ul>
|
|
<li><code>NINTENDO</code> will be #defined</li>
|
|
<li><code>MEGADUCK</code> will be #defined</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>When <code><sms/sms.h></code> is included (either directly or through <code><gbdk/platform.h></code>)<ul>
|
|
<li>When building for Master System<ul>
|
|
<li><code>SEGA</code> will be #defined</li>
|
|
<li><code>MASTERSYSTEM</code> will be #defined</li>
|
|
</ul>
|
|
</li>
|
|
<li>When building for Game Gear<ul>
|
|
<li><code>SEGA</code> will be #defined</li>
|
|
<li><code>GAMEGEAR</code> will be #defined</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>When <code><nes/nes.h></code> is included (either directly or through <code><gbdk/platform.h></code>)<ul>
|
|
<li><code>NINTENDO_NES</code> will be #defined</li>
|
|
</ul>
|
|
</li>
|
|
<li>When <code><msx/msx.h></code> is included (either directly or through <code><gbdk/platform.h></code>)<ul>
|
|
<li><code>MSXDOS</code> will be #defined</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="anchor" id="autotoc_md149"></a>
|
|
Console Hardware Properties</h2>
|
|
<p>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.</p>
|
|
<ul>
|
|
<li><a class="el" href="nes_2hardware_8h.html#a519e327cac96f68a8ca9b77e0343672f">DEVICE_SCREEN_X_OFFSET</a>, <a class="el" href="nes_2hardware_8h.html#af334c0e7dd6e434b3dbebd45bcdeb75a">DEVICE_SCREEN_Y_OFFSET</a></li>
|
|
<li><a class="el" href="nes_2hardware_8h.html#add7f32ba868ef6517798f5fce337e4b2">DEVICE_SCREEN_WIDTH</a>, <a class="el" href="nes_2hardware_8h.html#ad252264fdcf900e5fbf611f7a45962ed">DEVICE_SCREEN_HEIGHT</a></li>
|
|
<li><a class="el" href="nes_2hardware_8h.html#a491dc081eae8c81e7ca88075ab806291">DEVICE_SCREEN_BUFFER_WIDTH</a>, <a class="el" href="nes_2hardware_8h.html#a81fb56b6778772f829dab4c534e7749e">DEVICE_SCREEN_BUFFER_HEIGHT</a></li>
|
|
<li><a class="el" href="nes_2hardware_8h.html#a4d682ed7a6158c5ba10afec739b17a8a">DEVICE_SCREEN_MAP_ENTRY_SIZE</a></li>
|
|
<li><a class="el" href="nes_2hardware_8h.html#af531e7ac0c0a58517fa3061631745c31">DEVICE_SPRITE_PX_OFFSET_X</a>, <a class="el" href="nes_2hardware_8h.html#a7f6c8420831388300bbec13ea4cb57a0">DEVICE_SPRITE_PX_OFFSET_Y</a></li>
|
|
<li><a class="el" href="sms_2hardware_8h.html#ad14c51cdfb347c34c364f54e67dc978d">DEVICE_SCREEN_PX_WIDTH</a>, <a class="el" href="sms_2hardware_8h.html#a7bd450aa268b881257089cf8cd6697ec">DEVICE_SCREEN_PX_HEIGHT</a></li>
|
|
<li><a class="el" href="sms_8h.html#a8b77608c87a9aef65a03531482b2163b">MAX_HARDWARE_SPRITES</a></li>
|
|
<li><a class="el" href="sms_8h.html#afc296eacbda6a42f2a71aacab376ceb7">HARDWARE_SPRITE_CAN_FLIP_X</a>, <a class="el" href="sms_8h.html#a9119d69d971f6bee9e55d0df8f0ac983">HARDWARE_SPRITE_CAN_FLIP_Y</a></li>
|
|
</ul>
|
|
<h1><a class="anchor" id="autotoc_md150"></a>
|
|
Using <gbdk/...> headers</h1>
|
|
<p>Some include files under <code><gbdk/..></code> are cross platform and others allow the build process to auto-select the correct include file for the current target port and platform (console).</p>
|
|
<p>For example, the following can be used </p><pre class="fragment">#include <gbdk/platform.h>
|
|
#include <gbdk/metasprites.h>
|
|
</pre><p> Instead of </p><pre class="fragment">#include <gb/gb.h>
|
|
#include <gb/metasprites.h>
|
|
</pre><p> and </p><pre class="fragment">#include <sms/sms.h>
|
|
#include <sms/metasprites.h>
|
|
</pre><p><a class="anchor" id="docs_consoles_cross_platform_examples"></a></p>
|
|
<h1><a class="anchor" id="autotoc_md151"></a>
|
|
Cross Platform Example Projects</h1>
|
|
<p>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.</p>
|
|
<p>They also show how to build for multiple target consoles with a single build command and <code>Makefile</code>. The <code>Makefile.targets</code> allows selecting different <code>port</code> and <code>plat</code> settings when calling the build stages.</p>
|
|
<h2><a class="anchor" id="autotoc_md152"></a>
|
|
Cross Platform Asset Example</h2>
|
|
<p>The cross-platform <code>Logo</code> example project shows how assets can be managed for multiple different console targets together.</p>
|
|
<p>In the example <a class="el" href="docs_toolchain.html#utility_png2asset">utility_png2asset</a> 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 <a class="el" href="gb_8h.html#acb5c235def5988696724051c5f838e74">set_bkg_native_data()</a> to load the assets tiles in native format to the tile memory used for background tiles on that platform.</p>
|
|
<h1><a class="anchor" id="autotoc_md153"></a>
|
|
Hardware Summaries</h1>
|
|
<p>The specs below reflect the typical configuration of hardware when used with GBDK and is not meant as a complete list of their capabilities.</p>
|
|
<p>GB/AP/DUCK</p><ul>
|
|
<li>Sprites:<ul>
|
|
<li>256 tiles (upper 128 are shared with background) (amount is doubled in CGB mode)</li>
|
|
<li>tile flipping/mirroring: yes</li>
|
|
<li>40 total, max 10 per line</li>
|
|
<li>2 x 4 color palette (color 0 transparent). 8 x 4 color palettes in CGB mode</li>
|
|
</ul>
|
|
</li>
|
|
<li>Background: 256 tiles (typical setup: upper 128 are shared with sprites) (amount is doubled in CGB mode)<ul>
|
|
<li>tile grid size: 8x8</li>
|
|
<li>tile attribute grid size: 8x8 (CGB mode only)</li>
|
|
<li>tile flipping/mirroring: no (yes in CGB mode)</li>
|
|
<li>1 x 4 color palette. 8 x 4 color palettes in CGB mode</li>
|
|
</ul>
|
|
</li>
|
|
<li>Window "layer": available</li>
|
|
<li>Screen: 160 x 144</li>
|
|
<li>Hardware Map: 256 x 256</li>
|
|
</ul>
|
|
<p>SMS/GG</p><ul>
|
|
<li>Sprites:<ul>
|
|
<li>256 tiles (a bit less in the default setup)</li>
|
|
<li>tile flipping/mirroring: no</li>
|
|
<li>64 total, max 8 per line</li>
|
|
<li>1 x 16 color palette (color 0 transparent)</li>
|
|
</ul>
|
|
</li>
|
|
<li>Background: 512 tiles (upper 256 are shared with sprites)<ul>
|
|
<li>tile grid size: 8x8</li>
|
|
<li>tile attribute grid size: 8x8</li>
|
|
<li>tile flipping/mirroring: yes</li>
|
|
<li>2 x 16 color palettes</li>
|
|
</ul>
|
|
</li>
|
|
<li>Window "layer": not available</li>
|
|
<li>SMS<ul>
|
|
<li>Screen: 256 x 192</li>
|
|
<li>Hardware Map: 256 x 224</li>
|
|
</ul>
|
|
</li>
|
|
<li>GG<ul>
|
|
<li>Screen: 160 x 144</li>
|
|
<li>Hardware Map: 256 x 224</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p>NES/Famicom</p><ul>
|
|
<li>Sprites:<ul>
|
|
<li>8x8 or 8x16</li>
|
|
<li>256 tiles</li>
|
|
<li>tile flipping/mirroring: yes</li>
|
|
<li>64 total, max 8 per line</li>
|
|
<li>4 x 4 color palette (color 0 transparent)</li>
|
|
</ul>
|
|
</li>
|
|
<li>Background: 256 tiles<ul>
|
|
<li>tile grid size: 8x8</li>
|
|
<li>tile attribute grid size: 16x16 (bit packed into 32x32)</li>
|
|
<li>tile flipping/mirroring: no</li>
|
|
<li>4 x 4 color palette (color 0 same for all sub-palettes)</li>
|
|
</ul>
|
|
</li>
|
|
<li>Window "layer": not available</li>
|
|
<li>Screen: 256 x 240</li>
|
|
<li>Hardware Map: Depends on mirroring mode<ul>
|
|
<li>256 x 240 (single-screen mirroring)</li>
|
|
<li>512 x 240 (vertical mirroring / horizontal scrolling)</li>
|
|
<li>256 x 480 (horizontal mirroring / vertical scrolling)</li>
|
|
<li>512 x 480 (4-screen layout. Requires additional RAM on cartridge)</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p><a class="anchor" id="docs_consoles_safe_display_controller_access"></a></p>
|
|
<h2><a class="anchor" id="autotoc_md154"></a>
|
|
Safe VRAM / Display Controller Access</h2>
|
|
<p>GB/AP</p><ul>
|
|
<li>VRAM / Display Controller (PPU)<ul>
|
|
<li>VRAM and some other display data / registers should only be written to when the <a class="el" href="gb_2hardware_8h.html#a3b0bf7449b517b3cda2a89428db6deb9">STATF_B_BUSY</a> bit of <a class="el" href="gb_2hardware_8h.html#ad40ebf3b29add46cdd310a7e0802bc6b">STAT_REG</a> is off. Most GBDK API calls manage this automatically.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p>SMS/GG</p><ul>
|
|
<li>Display Controller (VDP)<ul>
|
|
<li>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).</li>
|
|
<li>Recommended approach: Avoid writing to the VDP (tiles, map, scrolling, colors, etc) during an interrupt routine (ISR).</li>
|
|
<li>Alternative (requires careful implementation): Make sure writes to the VDP during an ISR are only performed when the <a class="el" href="sms_8h.html#a388d1dff2698172ba8574e43f5c77c93">_shadow_OAM_OFF</a> flag indicates it is safe to do so.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p>NES/Famicom</p><ul>
|
|
<li>See <a class="el" href="docs_supported_consoles.html#nes_technical_details">NES technical details</a></li>
|
|
</ul>
|
|
<p><a class="anchor" id="using_cgb_features"></a></p>
|
|
<h1><a class="anchor" id="autotoc_md155"></a>
|
|
Using Game Boy Color (GBC/CGB) Features</h1>
|
|
<h2><a class="anchor" id="autotoc_md156"></a>
|
|
Differences Versus the Regular Game Boy (DMG/GBP/SGB)</h2>
|
|
<p>These are some of the main hardware differences between the Regular Game Boy and the Game Boy Color.</p>
|
|
<ul>
|
|
<li>CPU: Optional 2x Speed mode</li>
|
|
<li>Serial Link: Additional Speeds 2KB/s, 32KB/s, 64KB/s</li>
|
|
<li>IR Port</li>
|
|
<li>Sprites:<ul>
|
|
<li>2 banks x 256 tile patterns (2x as many) (typically upper 128 of each bank shared with background)</li>
|
|
<li>8 x 4 color palettes in CGB mode (BGR-555 per color, 32768 color choices)</li>
|
|
</ul>
|
|
</li>
|
|
<li>Background:<ul>
|
|
<li>2 banks x 256 tile patterns (2x as many) (typically upper 128 of each bank shared with sprites)</li>
|
|
<li>Second map bank for tile attributes (color, flipping/mirroring, priority, bank)</li>
|
|
<li>8 x 4 color palettes in CGB mode (BGR-555 per color, 32,768 color choices))</li>
|
|
<li>BG and Window master priority</li>
|
|
</ul>
|
|
</li>
|
|
<li>WRAM: 8 x 4K WRAM banks in the 0xD000 - 0xDFFF region</li>
|
|
<li>LCD VRAM DMA</li>
|
|
</ul>
|
|
<h2><a class="anchor" id="autotoc_md157"></a>
|
|
Game Boy Color features in GBDK</h2>
|
|
<p>These are some of the main GBDK API features for the CGB. Many of the items listed below link to additional information.</p>
|
|
<ul>
|
|
<li>ROM header settings:<ul>
|
|
<li>See the FAQ entry <a class="el" href="docs_faq.html#faq_gb_type_header_setting">How do I set SGB, Color only and Color compatibility in the ROM header?</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>Tile and Pattern data:<ul>
|
|
<li>Select VRAM Banks: <a class="el" href="gb_2hardware_8h.html#a5ccae0d556500e1055a0ec8de20c535a">VBK_REG</a> (used with <code>set_bkg/win/sprite_*()</code>)</li>
|
|
<li><a class="el" href="gb_8h.html#a0bcf384938628c4ab52e63b2df8f78f8">set_bkg_attributes()</a>, <a class="el" href="gb_8h.html#a1cefe143b3861632897e0c989401bce7">set_bkg_submap_attributes()</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>Color:<ul>
|
|
<li><a class="el" href="msx_8h.html#a9f879bd31899f7989f887b6238de24e3">set_bkg_palette()</a>, <a class="el" href="msx_8h.html#a2215732f2ba2ec6406b65d3cca56a200">set_bkg_palette_entry()</a></li>
|
|
<li><a class="el" href="msx_8h.html#a7d5ed1aed79d8fd2894893d7f6f9b835">set_sprite_palette()</a>, <a class="el" href="msx_8h.html#a8b5c17235a3f65af70492e109a25f237">set_sprite_palette_entry()</a></li>
|
|
<li><a class="el" href="cgb_8h.html#a2a89f4110072dbe76805e7b07299788d">set_default_palette()</a></li>
|
|
<li><a class="el" href="cgb_8h.html#a4a118ad3ee36468a3fa616977a64864e">RGB()</a>, <a class="el" href="cgb_8h.html#a7d2ed0f10b2b74123a544327bbfd7564">RGB8()</a>, <a class="el" href="cgb_8h.html#ab5a6e450fcf10402278fe585a421dbbd">RGBHTML()</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>Detect and change CPU speed: if (<a class="el" href="gb_8h.html#a874b9bd95b0a05d6a6072feabc879e45">_cpu</a> == <a class="el" href="gb_8h.html#aee435a3a0dde3dbd7b6112dbb456cde8">CGB_TYPE</a>), <a class="el" href="cgb_8h.html#a871b5b1aba74ab8764f72b73bc090adb">cpu_fast()</a></li>
|
|
<li>More details in <a class="el" href="cgb_8h.html">cgb.h</a> (<code>#include <gb/cgb.h></code>)</li>
|
|
</ul>
|
|
<h2><a class="anchor" id="autotoc_md158"></a>
|
|
CGB Examples</h2>
|
|
<p>Several examples in GBDK show how to use CGB features, including the following:</p><ul>
|
|
<li><code>gb/colorbar</code>, <code>gb/dscan</code>, <code>cross-platform/large_map</code>, <code>cross-platform/logo</code>, <code>cross-platform/metasprites</code></li>
|
|
</ul>
|
|
<h1><a class="anchor" id="autotoc_md159"></a>
|
|
Porting Between Supported Consoles</h1>
|
|
<h2><a class="anchor" id="autotoc_md160"></a>
|
|
From Game Boy to Analogue Pocket</h2>
|
|
<p>The Analogue Pocket operating in <code>.pocket</code> 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.</p>
|
|
<h3><a class="anchor" id="autotoc_md161"></a>
|
|
Official differences:</h3>
|
|
<ul>
|
|
<li>Altered register flag and address definitions<ul>
|
|
<li><a class="el" href="gb_2hardware_8h.html#ad40ebf3b29add46cdd310a7e0802bc6b">STAT</a> & <a class="el" href="gb_2hardware_8h.html#a6515fdfaa50eeb7e63faeea54f77cd6b">LCDC</a>: Order of register bits is reversed<ul>
|
|
<li>Example: <a class="el" href="gb_2hardware_8h.html#ac112618942cb4719def91693616baaff">LCD on/off</a> is LCDC.0 instead of .7</li>
|
|
<li>Example: <a class="el" href="gb_2hardware_8h.html#ac1e4b66204a5bff207be36fdfedd63d5">LYC Interrupt enable</a> is STAT.1 instead of .6</li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="el" href="gb_2hardware_8h.html#a6515fdfaa50eeb7e63faeea54f77cd6b">LCDC</a> address is <code>0xFF4E</code> instead of <code>0xFF40</code></li>
|
|
</ul>
|
|
</li>
|
|
<li>Different logo data in the header at address <code>0x0104</code>:<ul>
|
|
<li><code>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</code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3><a class="anchor" id="autotoc_md162"></a>
|
|
Observed differences:</h3>
|
|
<ul>
|
|
<li>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).</li>
|
|
<li>The Serial Link port does not work</li>
|
|
<li>The IR port in CGB mode does not work as reliably as the Game Boy Color</li>
|
|
</ul>
|
|
<p>In order for software to be easily ported to the Analogue Pocket, or to run on both, use the following practices.</p>
|
|
<h3><a class="anchor" id="autotoc_md163"></a>
|
|
Registers and Flags</h3>
|
|
<p>Use API defined registers and register flags instead of hardwired ones.</p><ul>
|
|
<li>LCDC register: <a class="el" href="gb_2hardware_8h.html#a6515fdfaa50eeb7e63faeea54f77cd6b">LCDC_REG</a> or <a class="el" href="gb_2hardware_8h.html#a8b576a1fe1473ac4aff8afecb28035cb">rLCDC</a></li>
|
|
<li>STAT register: <a class="el" href="gb_2hardware_8h.html#ad40ebf3b29add46cdd310a7e0802bc6b">STAT_REG</a> or <a class="el" href="gb_2hardware_8h.html#a338ec378453b4457efdb3008978c0f28">rSTAT</a></li>
|
|
<li>LCDC flags: -> LCDCF_... (example: <a class="el" href="gb_2hardware_8h.html#a1491fc03ed7f02e7309cc7b0c48b6c8a">LCDCF_ON</a>)</li>
|
|
<li>STAT flags: -> STATF_... (example: <a class="el" href="gb_2hardware_8h.html#a3b53105cc5be896b48794ba82d2aeb4c">STATF_LYC</a>)</li>
|
|
</ul>
|
|
<h3><a class="anchor" id="autotoc_md164"></a>
|
|
Boot logo</h3>
|
|
<p>As long as the target console is <a class="el" href="docs_supported_consoles.html#docs_consoles_compiling">set during build time</a> then the correct boot logo will be automatically selected.</p>
|
|
<h2><a class="anchor" id="autotoc_md165"></a>
|
|
From Game Boy to SMS/GG</h2>
|
|
<h3><a class="anchor" id="autotoc_md166"></a>
|
|
RAM Banks</h3>
|
|
<ul>
|
|
<li>The SMS/GG ROM file size must be at least 64K to enable mapper support for RAM banks in emulators.<ul>
|
|
<li>If the generated ROM is too small then <code>-yo 4</code> for makebin (or <code>-Wm-yo4</code> for LCC) can be used to set the size to 64K.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3><a class="anchor" id="autotoc_md167"></a>
|
|
Tile Data and Tile Map loading</h3>
|
|
<h4><a class="anchor" id="autotoc_md168"></a>
|
|
Tile and Map Data in 2bpp Game Boy Format</h4>
|
|
<ul>
|
|
<li><a class="el" href="gb_8h.html#a1f5101f2b7bb0123c26a3e257f843626">set_bkg_data()</a> and <a class="el" href="gb_8h.html#ae45b1c639698951b47e44fa8e89556f2">set_sprite_data()</a> will load 2bpp tile data in "Game Boy" format on both GB and SMS/GG.</li>
|
|
<li>On the SMS/GG <a class="el" href="gb_8h.html#aa224c9bac27c7fd268e62bdf33338a84">set_2bpp_palette()</a> sets 4 colors that will be used when loading 2bpp assets with <a class="el" href="gb_8h.html#a1f5101f2b7bb0123c26a3e257f843626">set_bkg_data()</a>. This allows GB assets to be easily colorized without changing the asset format. There is some performance penalty for using the conversion.</li>
|
|
<li><a class="el" href="msx_8h.html#a9a732aec1b7aec7d10a9d76ca4da2064">set_bkg_tiles()</a> loads 1-byte-per-tile tilemaps both for the GB and SMS/GG.</li>
|
|
</ul>
|
|
<h4><a class="anchor" id="autotoc_md169"></a>
|
|
Tile and Map Data in Native Format</h4>
|
|
<p>Use the following api calls when assets are avaialble in the native format for each platform.</p>
|
|
<p><a class="el" href="gb_8h.html#a68651e50243349b48164a8ad983dca4e">set_native_tile_data()</a></p><ul>
|
|
<li>GB/AP: loads 2bpp tiles data</li>
|
|
<li>SMS/GG: loads 4bpp tile data</li>
|
|
</ul>
|
|
<p><a class="el" href="gb_8h.html#a55f82ff980398dd97036fd936ebd727e">set_tile_map()</a></p><ul>
|
|
<li>GB/AP: loads 1-byte-per-tile tilemaps</li>
|
|
<li>SMS/GG: loads 2-byte-per-tile tilemaps</li>
|
|
</ul>
|
|
<p>There are also bit-depth specific API calls:</p><ul>
|
|
<li>1bpp: <a class="el" href="sms_8h.html#adcb394299a1033616fc7d2faec8bd6ad">set_1bpp_colors</a>, <a class="el" href="sms_8h.html#a4d5f74eed0489ebfdc2410ee3f9f7f04">set_bkg_1bpp_data</a>, <a class="el" href="sms_8h.html#a2cc121fbeb5570248531b85a8f0b5b97">set_sprite_1bpp_data</a></li>
|
|
<li>2bpp: <a class="el" href="sms_8h.html#aa224c9bac27c7fd268e62bdf33338a84">set_2bpp_palette</a>, <a class="el" href="sms_8h.html#aa7ba76e4d44dbf19da351fd1ea8e3023">set_bkg_2bpp_data</a>, <a class="el" href="sms_8h.html#a10ee2919fcab7a5c482816ed718d1c4a">set_sprite_2bpp_data</a>, <a class="el" href="sms_8h.html#ab752b1bb0f58da2a6d52e9747c4b3dd8">set_tile_2bpp_data</a> (sms/gg only)</li>
|
|
<li>2bpp: <a class="el" href="sms_8h.html#a551fa0b4eb3f30b067a6367a60472095">set_bkg_4bpp_data</a> (sms/gg only), <a class="el" href="sms_8h.html#ad9f5644f83d1b513d83c14bf83a18ce6">set_sprite_4bpp_data</a> (sms/gg only)</li>
|
|
</ul>
|
|
<h3><a class="anchor" id="autotoc_md170"></a>
|
|
Colors and Palettes</h3>
|
|
<p>The SMS/GG have 2 x 16 color palettes:</p><ul>
|
|
<li>The first (0) is just for the background</li>
|
|
<li>The second (1) is shared between sprites and the background (and for sprites a single color 0 of that palette is transparent)</li>
|
|
</ul>
|
|
<p>On the Game Gear</p><ul>
|
|
<li>Each Palette is 32 bytes in size: 16 colors x 2 bytes per palette color entry.</li>
|
|
<li>Each color (16 per palette) is packed as BGR-444 format (x:4:4:4, MSBits [15..12] are unused).</li>
|
|
<li>Each component (R, G, B) may have values from 0 - 15 (4 bits), 15 is brightest.</li>
|
|
</ul>
|
|
<p>On the SMS</p><ul>
|
|
<li>On SMS each Palette is 16 bytes in size: 16 colors x 1 byte per palette color entry.</li>
|
|
<li>Each color (16 per palette) is packed as BGR-222 format (x:2:2:2, MSBits [7..6] are unused).</li>
|
|
<li>Each component (R, G, B) may have values from 0 - 3 (2 bits), 3 is brightest.</li>
|
|
</ul>
|
|
<p>For setting palette data:</p><ul>
|
|
<li><a class="el" href="msx_8h.html#a2c9aabf4519e01257b0d0e04e8108164">set_palette_entry()</a>: Will set a single color in a palette</li>
|
|
<li><a class="el" href="msx_8h.html#af288f3b302839006d33d38755d922de0">set_palette()</a>: Can set all the colors for one or both palettes</li>
|
|
<li><a class="el" href="msx_8h.html#a9f879bd31899f7989f887b6238de24e3">set_bkg_palette()</a>: Is just an alias for <a class="el" href="msx_8h.html#af288f3b302839006d33d38755d922de0">set_palette()</a>. The full 16 colors can be set using this call.</li>
|
|
<li><a class="el" href="msx_8h.html#a7d5ed1aed79d8fd2894893d7f6f9b835">set_sprite_palette()</a>: Is also an alias for <a class="el" href="msx_8h.html#af288f3b302839006d33d38755d922de0">set_palette()</a>, but it offsets to write to the second 16 color palette.</li>
|
|
<li>Also see: <a class="el" href="cgb_8h.html#a4a118ad3ee36468a3fa616977a64864e">RGB()</a>, <a class="el" href="cgb_8h.html#a7d2ed0f10b2b74123a544327bbfd7564">RGB8()</a>, <a class="el" href="cgb_8h.html#ab5a6e450fcf10402278fe585a421dbbd">RGBHTML()</a></li>
|
|
</ul>
|
|
<h4><a class="anchor" id="autotoc_md171"></a>
|
|
Emulated Game Boy Color map attributes on the SMS/Game Gear</h4>
|
|
<p>On the Game Boy Color, <a class="el" href="gb_2hardware_8h.html#a5ccae0d556500e1055a0ec8de20c535a">VBK_REG</a> is used to select between the regular background tile map and the background attribute tile map (for setting tile color palette and other properties).</p>
|
|
<p>This behavior is emulated for the SMS/GG when using <a class="el" href="msx_8h.html#a9a732aec1b7aec7d10a9d76ca4da2064">set_bkg_tiles()</a> and <a class="el" href="gb_2hardware_8h.html#a5ccae0d556500e1055a0ec8de20c535a">VBK_REG</a>. It allows writing a 1-byte tile map separately from a 1-byte attributes map.</p>
|
|
<dl class="section note"><dt>Note</dt><dd>Tile map attributes on SMS/Game Gear use different control bits than the Game Boy Color, so a modified attribute map must be used.</dd></dl>
|
|
<p><a class="anchor" id="nes_technical_details"></a></p>
|
|
<h2><a class="anchor" id="autotoc_md172"></a>
|
|
From Game Boy to NES</h2>
|
|
<p>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.</p>
|
|
<p>Most notably:</p><ul>
|
|
<li>PPU memory can only be written in a serial fashion using a data port at 0x2007 (PPUDATA)</li>
|
|
<li>PPU memory can only be written to during vblank, or when manually disabling rendering via PPUMASK. Hblank writes to PPU memory are not possible</li>
|
|
<li>PPU memory write address is re-purposed for scrolling coordinates when rendering is enabled which means PPU memory updates / scrolling must cooperate</li>
|
|
<li>PPU internal palette memory is also mapped to external VRAM area making palette updates during rendering very expensive and error-prone</li>
|
|
<li>The base NES system has no support for any scanline interrupts. And cartridge mappers that add scanline interrupts do so using wildly varying solutions</li>
|
|
<li>There's no easy way to determine the current scanline or CPU-to-PPU alignment meaning timed code is often required on the NES</li>
|
|
<li>The PAL variant of the NES has very different CPU / PPU timings, as do the Dendy clone and other clone systems</li>
|
|
<li>The stock 2 kB CPU RAM is just 1/4th the 8kB CPU RAM on a Game Boy<ul>
|
|
<li>Free RAM after accounting for ZP, stack, OAM page and system variables further cuts this in half</li>
|
|
<li>This means a lot of GB code will need to be carefully optimized for RAM usage when ported to the NES</li>
|
|
<li>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</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<h3><a class="anchor" id="autotoc_md173"></a>
|
|
Mapper</h3>
|
|
<p>Currently the NES support in GBDK uses UNROM-512 (Mapper30) with single-screen mirroring.</p>
|
|
<h3><a class="anchor" id="autotoc_md174"></a>
|
|
Buffered mode vs direct mode</h3>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<p>To deal with this limitation, all functions in gbdk-nes that write to PPU memory can run in either <em>Buffered</em> or <em>Direct</em> mode.</p>
|
|
<p>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.</p>
|
|
<ul>
|
|
<li>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</li>
|
|
<li>DISPLAY_OFF will switch the system into direct mode, allowing much larger/faster transfers while the screen is blanked</li>
|
|
</ul>
|
|
<p>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.</p>
|
|
<h4><a class="anchor" id="autotoc_md175"></a>
|
|
Buffered mode implementation details</h4>
|
|
<p>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. </p><pre class="fragment">PLA
|
|
STA PPUDATA
|
|
...
|
|
PLA
|
|
STA PPUDATA
|
|
RTS
|
|
</pre><p> 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.</p>
|
|
<p>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)</p>
|
|
<p>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".</p>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<p>Buffered mode is typically used for scrolling updates or dynamically animated tiles, where only a small amount of bytes need updating per frame.</p>
|
|
<h4><a class="anchor" id="autotoc_md176"></a>
|
|
Direct mode implementation details</h4>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<h4><a class="anchor" id="autotoc_md177"></a>
|
|
Caveat: Make sure the transfer buffer is emptied before switching to direct mode</h4>
|
|
<p>Because the switch to direct mode is instant and doesn't wait for the next invocation of the vblank, it is possible to create situations where there is still remaining data in the transfer buffer that would only get written once the system is switched back to buffered mode.</p>
|
|
<p>To avoid this situation, make sure to always "drain" the buffer by doing a call to vsync when you expect your code to finish.</p>
|
|
<h4><a class="anchor" id="autotoc_md178"></a>
|
|
Caveat: Only update the PPU palette during buffered mode</h4>
|
|
<p>The oddity that PPU palette values are accessed through the same mechanism as other PPU memory bytes comes with the side effect that the vblank NMI handler will only write the palette values in buffered mode.</p>
|
|
<p>The reason for this design choice is two-fold:</p><ul>
|
|
<li>Having the NMI handler keep doing the palette updates when in direct mode would result in a race condition when the NMI handler interrupts the direct mode code and messes with the PPUADDR state that the direct mode code expects to remain unchanged</li>
|
|
<li>Having the palette updates also switch to direct mode would run into another quirk of the system: Pointing PPUADDR at palette registers when display is turned off will make the display output that palette color instead of the common background color. The result would be glitchy artifacts on screen when updating the palette, leading to a slightly-glitchy looking game whenever the palette is updated with the screen off</li>
|
|
</ul>
|
|
<p>To work around this, you are advised to never fully turn the display off during a palette fade. If you don't follow this advice all your palette updates will get delayed until the screen is turned back on.</p>
|
|
<h3><a class="anchor" id="autotoc_md179"></a>
|
|
Shadow PPU registers</h3>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<h3><a class="anchor" id="autotoc_md180"></a>
|
|
Implementation of (fake) vbl / lcd handlers</h3>
|
|
<p>GBDK provides an API for installing Interrupt Service Routines that execute on start of vblank (VBL handler), or on a specific scanline (LCD handler).</p>
|
|
<p>But the base NES system has no suitable scanline interrupts that can provide such functionality. So instead, gbdk-nes API allows <em>fake</em> handlers to be installed in the goal of keeping code compatible with other platforms.</p>
|
|
<ul>
|
|
<li>An installed VBL handler will be called immediately when calling vsync. This handler should only update PPU shadow registers.</li>
|
|
<li>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.</li>
|
|
<li>After the vblank NMI handler has finished palette updates, OAM DMA, VRAM updates and scroll updates 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.</li>
|
|
</ul>
|
|
<p>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. 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.</p>
|
|
<dl class="section note"><dt>Note</dt><dd>The support for VBL and LCD handlers is currently under consideration and subject to change in newer versions of gbdk-nes.</dd></dl>
|
|
<h3><a class="anchor" id="autotoc_md181"></a>
|
|
Caveat: Make sure to call vsync on every frame</h3>
|
|
<p>On the GB, the call to vsync is an optional call that serves two purposes:</p>
|
|
<ol type="1">
|
|
<li>It provides a consistent frame timing for your game</li>
|
|
<li>It allows future register writes to be synchronized to the screen</li>
|
|
</ol>
|
|
<p>On gbdk-nes the second point is no longer true, because writes need to be made to the shadow registers <em>before</em> vsync is called.</p>
|
|
<p>But the vsync call serves three other very important purposes:</p>
|
|
<p>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) 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. C. It calls flush_shadow_attributes so that updates to background attributes actually get written to PPU memory</p>
|
|
<p>For these reasons you should always include a call to vsync if you expect to see any graphical updates on the screen.</p>
|
|
<h3><a class="anchor" id="autotoc_md182"></a>
|
|
Caveat: Do all status bar scroll movement in LCD handlers to mitigate glitches</h3>
|
|
<p>The fake LCD ISR system is not bullet-proof. In particular, it has a problem where lag frames can cause the shadow register updates in LCD handlers not to be ready in time for when the timed code in the NMI handler would be called. This will effectively cause all those updates to be missing for one frame, and result in glitched scroll updates.</p>
|
|
<p>There is currently no complete work-around for this problem other than avoiding lag frames altogether. But the glitch can be made less distracting by making sure only the status bar glitches rather than the main background.</p>
|
|
<p>If you are using LCD handlers to achieve a top-screen stationary status bar, it is recommended that you follow the following guidelines to make sure the background itself has consistent scrolling:</p><ul>
|
|
<li>Use move_bkg either in your main loop or in the VBL handler, to set the level scrolling</li>
|
|
<li>Use move_bkg in the first invocation of the LCD handler, to set the (stationary) status bar scroll position</li>
|
|
<li>Use move_bkg in the second invocation of the LCD handler, to reset the background scrolling</li>
|
|
</ul>
|
|
<p>In short: Ensuring that the last called LCD handler sets the scroll back to the original value means the PPU rendering keeps rendering the background from the same scrolling position even when the NMI handling was missed.</p>
|
|
<h3><a class="anchor" id="autotoc_md183"></a>
|
|
Tile Data and Tile Map loading</h3>
|
|
<h4><a class="anchor" id="autotoc_md184"></a>
|
|
Tile and Map Data in 2bpp Game Boy Format</h4>
|
|
<ul>
|
|
<li><a class="el" href="gb_8h.html#a1f5101f2b7bb0123c26a3e257f843626">set_bkg_data()</a> and <a class="el" href="gb_8h.html#ae45b1c639698951b47e44fa8e89556f2">set_sprite_data()</a> will load 2bpp tile data in "Game Boy" format on both GB and NES.</li>
|
|
<li><a class="el" href="msx_8h.html#a9a732aec1b7aec7d10a9d76ca4da2064">set_bkg_tiles()</a> loads 1-byte-per-tile tilemaps both for the GB and NES.</li>
|
|
</ul>
|
|
<h4><a class="anchor" id="autotoc_md185"></a>
|
|
Tile and Map Data in Native Format</h4>
|
|
<p>Use the following api calls when assets are available in the native format for each platform.</p>
|
|
<p><a class="el" href="gb_8h.html#a68651e50243349b48164a8ad983dca4e">set_native_tile_data()</a></p><ul>
|
|
<li>GB/AP: loads 2bpp tiles data</li>
|
|
<li>NES: loads 2bpp tiles data</li>
|
|
</ul>
|
|
<p><a class="el" href="gb_8h.html#a55f82ff980398dd97036fd936ebd727e">set_tile_map()</a></p><ul>
|
|
<li>GB/AP: loads 1-byte-per-tile tilemaps</li>
|
|
<li>NES: loads 1-byte-per-tile tilemaps</li>
|
|
</ul>
|
|
<p>Bit-depth specific API calls:</p><ul>
|
|
<li>1bpp: <a class="el" href="sms_8h.html#adcb394299a1033616fc7d2faec8bd6ad">set_1bpp_colors</a>, <a class="el" href="sms_8h.html#a4d5f74eed0489ebfdc2410ee3f9f7f04">set_bkg_1bpp_data</a>, <a class="el" href="sms_8h.html#a2cc121fbeb5570248531b85a8f0b5b97">set_sprite_1bpp_data</a></li>
|
|
<li>2bpp: <a class="el" href="sms_8h.html#aa224c9bac27c7fd268e62bdf33338a84">set_2bpp_palette</a>, <a class="el" href="sms_8h.html#aa7ba76e4d44dbf19da351fd1ea8e3023">set_bkg_2bpp_data</a>, <a class="el" href="sms_8h.html#a10ee2919fcab7a5c482816ed718d1c4a">set_sprite_2bpp_data</a></li>
|
|
</ul>
|
|
<p>Platform specific API calls:</p><ul>
|
|
<li><a class="el" href="nes_8h.html#a0254d6e23d4202cb070b1fe54c6a7210">set_bkg_attributes_nes16x16()</a>, <a class="el" href="nes_8h.html#aadba8b700b97ec97dc9c488496619fd9">set_bkg_submap_attributes_nes16x16()</a>, <a class="el" href="nes_8h.html#a7b7c27e672467f08097f744f3530bbc7">set_bkg_attribute_xy_nes16x16()</a></li>
|
|
</ul>
|
|
<h4><a class="anchor" id="autotoc_md186"></a>
|
|
Game Boy Color map attributes on the NES</h4>
|
|
<p>On the Game Boy Color, <a class="el" href="gb_2hardware_8h.html#a5ccae0d556500e1055a0ec8de20c535a">VBK_REG</a> is used to select between the regular background tile map and the background attribute tile map (for setting tile color palette and other properties).</p>
|
|
<p>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.</p>
|
|
<p>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:</p><ul>
|
|
<li><a class="el" href="gb_8h.html#a0bcf384938628c4ab52e63b2df8f78f8">set_bkg_attributes()</a></li>
|
|
<li><a class="el" href="gb_8h.html#a1cefe143b3861632897e0c989401bce7">set_bkg_submap_attributes()</a></li>
|
|
<li><a class="el" href="sms_8h.html#a4d5a69c2f61a3b7e8656548132a872d7">set_bkg_attribute_xy()</a></li>
|
|
</ul>
|
|
<p>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.</p>
|
|
<p>There is one more platform specific difference to note: While the <a class="el" href="sms_8h.html#a4d5a69c2f61a3b7e8656548132a872d7">set_bkg_attribute_xy()</a> function takes coordinates on a 8x8 grid, the <a class="el" href="gb_8h.html#a0bcf384938628c4ab52e63b2df8f78f8">set_bkg_attributes()</a> and <a class="el" href="gb_8h.html#a1cefe143b3861632897e0c989401bce7">set_bkg_submap_attributes()</a> 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.</p>
|
|
<p>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 <em>NOT</em> portable between NES/other platforms, and is not recommended.</p>
|
|
<dl class="section note"><dt>Note</dt><dd>Tile map attributes on NES are on a 16x16 grid and use different control bits than the Game Boy Color.<ul>
|
|
<li>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:<ul>
|
|
<li>D1-D0: Top-left 16x16 pixels</li>
|
|
<li>D3-D2: Top-right 16x16 pixels</li>
|
|
<li>D5-D4: Bottom-left 16x16 pixels</li>
|
|
<li>D7-D6: Bottom-right 16x16 pixels</li>
|
|
<li><a href="https://www.nesdev.org/wiki/PPU_attribute_tables">https://www.nesdev.org/wiki/PPU_attribute_tables</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</dd></dl>
|
|
<h2><a class="anchor" id="autotoc_md187"></a>
|
|
From Game Boy to Mega Duck / Cougar Boy</h2>
|
|
<p>The Mega Duck is (for practical purposes) functionally identical to the Original Game Boy though it has a couple changes listed below.</p>
|
|
<h3><a class="anchor" id="autotoc_md188"></a>
|
|
Summary of Hardware changes:</h3>
|
|
<ul>
|
|
<li>Cartridge Boot Logo: not present on Mega Duck</li>
|
|
<li>Cartridge Header data: not present on Mega Duck</li>
|
|
<li>Program Entry Point: <code>0x0000</code> (on Game Boy: <code>0x0100</code> )</li>
|
|
<li>Display registers and flag definitions: Some changed</li>
|
|
<li>Audio registers and flag definitions: Some changed</li>
|
|
<li>MBC ROM bank switching register address: <code>0x0001</code> (many Game Boy MBCs use <code>0x2000 - 0x3FFF</code>)</li>
|
|
</ul>
|
|
<h3><a class="anchor" id="autotoc_md189"></a>
|
|
Best Practices</h3>
|
|
<p>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 <em>most</em> of the differences (for the exceptions see <a class="el" href="docs_supported_consoles.html#megaduck_sound_register_value_changes">Sound Register Value Changes</a>).</p><ul>
|
|
<li><a class="el" href="docs_supported_consoles.html#docs_consoles_compiling">Set the target console during build time</a></li>
|
|
<li>Use the GBDK definitions and macros for:<ul>
|
|
<li>Video Registers and Flags (examples: <a class="el" href="gb_2hardware_8h.html#a6515fdfaa50eeb7e63faeea54f77cd6b">LCDC_REG</a>, <a class="el" href="gb_2hardware_8h.html#a731588b96fb8cdbeb7e68c089373e6f8">LCDCF_BG8000</a>, etc)</li>
|
|
<li>Audio Registers and Flags (examples: <a class="el" href="gb_2hardware_8h.html#a7accf5feabd95a2d84c72f5915fff837">NR12_REG</a>, <a class="el" href="gb_2hardware_8h.html#a52593a64863d51fbf5860b0d31448972">NR43_REG</a>, etc)</li>
|
|
<li>Use the default <a class="el" href="msx_8h.html#ac996706e2a5e73f010841437f26d4d4f">SWITCH_ROM</a> macro for changing ROM banks</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p><a class="anchor" id="megaduck_sound_register_value_changes"></a></p>
|
|
<h3><a class="anchor" id="autotoc_md190"></a>
|
|
Sound Register Value Changes</h3>
|
|
<p>There are two hardware changes which will not be handled automatically when following the practices mentioned above.</p>
|
|
<p>These changes may be required when using existing Sound Effects and Music Drivers written for the Game Boy.</p>
|
|
<ol type="1">
|
|
<li>Registers <a class="el" href="gb_2hardware_8h.html#a7accf5feabd95a2d84c72f5915fff837">NR12_REG</a>, <a class="el" href="gb_2hardware_8h.html#af1301c73bf93350045ba3a4887723ae8">NR22_REG</a>, <a class="el" href="gb_2hardware_8h.html#aba3d9fb63552bc02ec879696b581adac">NR42_REG</a>, and <a class="el" href="gb_2hardware_8h.html#a52593a64863d51fbf5860b0d31448972">NR43_REG</a> have their contents nybble swapped.<ul>
|
|
<li>To maintain compatibility the value to write (or the value read) can be converted this way: <code>((uint8_t)(value << 4) | (uint8_t)(value >> 4))</code></li>
|
|
</ul>
|
|
</li>
|
|
<li>Register <a class="el" href="gb_2hardware_8h.html#a244ee6d8f6144be9b0f94602eddb6239">NR32_REG</a> has the volume bit values changed.<ul>
|
|
<li><code>Game Boy: Bits:6..5 : 00 = mute, 01 = 100%, 10 = 50%, 11 = 25%</code></li>
|
|
<li><code>Mega Duck: Bits:6..5 : 00 = mute, 01 = 25%, 10 = 50%, 11 = 100%</code></li>
|
|
<li>To maintain compatibility the value to write (or the value read) can be converted this way: <code>(((~(uint8_t)value) + (uint8_t)0x20u) & (uint8_t)0x60u)</code></li>
|
|
</ul>
|
|
</li>
|
|
</ol>
|
|
<h3><a class="anchor" id="autotoc_md191"></a>
|
|
Graphics Register Bit Changes</h3>
|
|
<p>These changes are handled automatically when their GBDK definitions are used.</p>
|
|
<table class="markdownTable">
|
|
<tr class="markdownTableHead">
|
|
<th class="markdownTableHeadNone"><a class="el" href="gb_2hardware_8h.html#a6515fdfaa50eeb7e63faeea54f77cd6b">LCDC_REG</a> Flag </th><th class="markdownTableHeadNone">Game Boy </th><th class="markdownTableHeadNone">Mega Duck </th><th class="markdownTableHeadNone"></th><th class="markdownTableHeadNone">Purpose </th></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ac112618942cb4719def91693616baaff">LCDCF_B_ON</a> </td><td class="markdownTableBodyNone">.7 </td><td class="markdownTableBodyNone">.7 </td><td class="markdownTableBodyNone">(same) </td><td class="markdownTableBodyNone">Bit for LCD On/Off Select </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ac826fdb70a043ebb8f1b317b00db6ff3">LCDCF_B_WIN9C00</a> </td><td class="markdownTableBodyNone">.6 </td><td class="markdownTableBodyNone">.3 </td><td class="markdownTableBodyNone"></td><td class="markdownTableBodyNone">Bit for Window Tile Map Region Select </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ae1de721c95ddc8f29ba9b9deaee8d68c">LCDCF_B_WINON</a> </td><td class="markdownTableBodyNone">.5 </td><td class="markdownTableBodyNone">.5 </td><td class="markdownTableBodyNone">(same) </td><td class="markdownTableBodyNone">Bit for Window Display On/Off Control </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#aa336ca1c8bd29763222fc011a6272bdf">LCDCF_B_BG8000</a> </td><td class="markdownTableBodyNone">.4 </td><td class="markdownTableBodyNone">.4 </td><td class="markdownTableBodyNone">(same) </td><td class="markdownTableBodyNone">Bit for BG & Window Tile Data Region Select </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a4889bb882e956665069212c4c8aa623b">LCDCF_B_BG9C00</a> </td><td class="markdownTableBodyNone">.3 </td><td class="markdownTableBodyNone">.2 </td><td class="markdownTableBodyNone"></td><td class="markdownTableBodyNone">Bit for BG Tile Map Region Select </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#aa8f5bcd5073aae5948a9647dcb76f779">LCDCF_B_OBJ16</a> </td><td class="markdownTableBodyNone">.2 </td><td class="markdownTableBodyNone">.1 </td><td class="markdownTableBodyNone"></td><td class="markdownTableBodyNone">Bit for Sprites Size Select </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a6f6852d0f1d295b03e1230d5d97cb3e9">LCDCF_B_OBJON</a> </td><td class="markdownTableBodyNone">.1 </td><td class="markdownTableBodyNone">.0 </td><td class="markdownTableBodyNone"></td><td class="markdownTableBodyNone">Bit for Sprites Display Visible/Hidden Select </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#aa1f66868f63af2af6544e84122de3cc3">LCDCF_B_BGON</a> </td><td class="markdownTableBodyNone">.0 </td><td class="markdownTableBodyNone">.6 </td><td class="markdownTableBodyNone"></td><td class="markdownTableBodyNone">Bit for Background Display Visible Hidden Select </td></tr>
|
|
</table>
|
|
<h3><a class="anchor" id="autotoc_md192"></a>
|
|
Detailed Register Address Changes</h3>
|
|
<p>These changes are handled automatically when their GBDK definitions are used.</p>
|
|
<table class="markdownTable">
|
|
<tr class="markdownTableHead">
|
|
<th class="markdownTableHeadNone">Register </th><th class="markdownTableHeadNone">Game Boy </th><th class="markdownTableHeadNone">Mega Duck </th></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a6515fdfaa50eeb7e63faeea54f77cd6b">LCDC_REG</a> </td><td class="markdownTableBodyNone">0xFF40 </td><td class="markdownTableBodyNone">0xFF10 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ad40ebf3b29add46cdd310a7e0802bc6b">STAT_REG</a> </td><td class="markdownTableBodyNone">0xFF41 </td><td class="markdownTableBodyNone">0xFF11 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a244b162cf13bbcb4fe842d7e298b39c2">SCY_REG</a> </td><td class="markdownTableBodyNone">0xFF42 </td><td class="markdownTableBodyNone">0xFF12 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a86cc170585319565195f2c163250be1f">SCX_REG</a> </td><td class="markdownTableBodyNone">0xFF43 </td><td class="markdownTableBodyNone">0xFF13 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#aeb643bd4eac2e6e410cae2fae677c0a7">LY_REG</a> </td><td class="markdownTableBodyNone">0xFF44 </td><td class="markdownTableBodyNone">0xFF18 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a591084a506c33266b7d6cc3b4b8936ae">LYC_REG</a> </td><td class="markdownTableBodyNone">0xFF45 </td><td class="markdownTableBodyNone">0xFF19 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ae13ce414d3fe7c98c1434918186dfc81">DMA_REG</a> </td><td class="markdownTableBodyNone">0xFF46 </td><td class="markdownTableBodyNone">0xFF1A </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#af577ba87ec3d13d7415e4c4a53cdf997">BGP_REG</a> </td><td class="markdownTableBodyNone">0xFF47 </td><td class="markdownTableBodyNone">0xFF1B </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a13f3e89f7b92258d825292e5058815c7">OBP0_REG</a> </td><td class="markdownTableBodyNone">0xFF48 </td><td class="markdownTableBodyNone">0xFF14 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a9da545164e049ef773128f869daece13">OBP1_REG</a> </td><td class="markdownTableBodyNone">0xFF49 </td><td class="markdownTableBodyNone">0xFF15 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a1c8d52607616ef37da335447e4cbe850">WY_REG</a> </td><td class="markdownTableBodyNone">0xFF4A </td><td class="markdownTableBodyNone">0xFF16 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a310aa43fbee2fd6b6b419df48acce1e0">WX_REG</a> </td><td class="markdownTableBodyNone">0xFF4B </td><td class="markdownTableBodyNone">0xFF17 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ad859dc62b1df1584ade0cbb822a3e46f">NR10_REG</a> </td><td class="markdownTableBodyNone">0xFF10 </td><td class="markdownTableBodyNone">0xFF20 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ad53dc7f22b99fce195210a95f2749a72">NR11_REG</a> </td><td class="markdownTableBodyNone">0xFF11 </td><td class="markdownTableBodyNone">0xFF22 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a7accf5feabd95a2d84c72f5915fff837">NR12_REG</a> </td><td class="markdownTableBodyNone">0xFF12 </td><td class="markdownTableBodyNone">0xFF21 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a3d30d4797321b403cd713d727fa3db6c">NR13_REG</a> </td><td class="markdownTableBodyNone">0xFF13 </td><td class="markdownTableBodyNone">0xFF23 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a04c340d91842e8ee2b93922c2bcf39a4">NR14_REG</a> </td><td class="markdownTableBodyNone">0xFF14 </td><td class="markdownTableBodyNone">0xFF24 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a6dd3af1c8e3c66409aa0bc889d98e171">NR21_REG</a> </td><td class="markdownTableBodyNone">0xFF16 </td><td class="markdownTableBodyNone">0xFF25 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#af1301c73bf93350045ba3a4887723ae8">NR22_REG</a> </td><td class="markdownTableBodyNone">0xFF17 </td><td class="markdownTableBodyNone">0xFF27 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a7bb32ac86e3fbf5f869410ba42620616">NR23_REG</a> </td><td class="markdownTableBodyNone">0xFF18 </td><td class="markdownTableBodyNone">0xFF28 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a6676e579a5e421adfb3d3e2d470d9ab6">NR24_REG</a> </td><td class="markdownTableBodyNone">0xFF19 </td><td class="markdownTableBodyNone">0xFF29 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a85d8e680d4d40a918b4195d2a4fada2a">NR30_REG</a> </td><td class="markdownTableBodyNone">0xFF1A </td><td class="markdownTableBodyNone">0xFF2A </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#aea78f857e34370d7e1177a8bafe08148">NR31_REG</a> </td><td class="markdownTableBodyNone">0xFF1B </td><td class="markdownTableBodyNone">0xFF2B </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a244ee6d8f6144be9b0f94602eddb6239">NR32_REG</a> </td><td class="markdownTableBodyNone">0xFF1C </td><td class="markdownTableBodyNone">0xFF2C </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a01c768b60853c8eecdefc2cedfc8d672">NR33_REG</a> </td><td class="markdownTableBodyNone">0xFF1D </td><td class="markdownTableBodyNone">0xFF2E </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ab6da3e2cdbac1331bef3f6de9c808ab1">NR34_REG</a> </td><td class="markdownTableBodyNone">0xFF1E </td><td class="markdownTableBodyNone">0xFF2D </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a557833cc1671aa0bd71f33766b4e0f24">NR41_REG</a> </td><td class="markdownTableBodyNone">0xFF20 </td><td class="markdownTableBodyNone">0xFF40 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#aba3d9fb63552bc02ec879696b581adac">NR42_REG</a> </td><td class="markdownTableBodyNone">0xFF21 </td><td class="markdownTableBodyNone">0xFF42 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a52593a64863d51fbf5860b0d31448972">NR43_REG</a> </td><td class="markdownTableBodyNone">0xFF22 </td><td class="markdownTableBodyNone">0xFF41 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a849d2cff8df2655f86b294466bec40d6">NR44_REG</a> </td><td class="markdownTableBodyNone">0xFF23 </td><td class="markdownTableBodyNone">0xFF43 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#a924fdf48f6ad020423f6309055314928">NR50_REG</a> </td><td class="markdownTableBodyNone">0xFF24 </td><td class="markdownTableBodyNone">0xFF44 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ab28f97eabd5f32d48ea27d97bd5dc64f">NR51_REG</a> </td><td class="markdownTableBodyNone">0xFF25 </td><td class="markdownTableBodyNone">0xFF46 </td></tr>
|
|
<tr class="markdownTableRowEven">
|
|
<td class="markdownTableBodyNone"><a class="el" href="gb_2hardware_8h.html#ac429365dce851ca57d8fe4f7c54a1caa">NR52_REG</a> </td><td class="markdownTableBodyNone">0xFF26 </td><td class="markdownTableBodyNone">0xFF45 </td></tr>
|
|
<tr class="markdownTableRowOdd">
|
|
<td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">- </td></tr>
|
|
</table>
|
|
</div></div><!-- contents -->
|
|
</div><!-- PageDoc -->
|
|
</div><!-- doc-content -->
|
|
<!-- HTML footer for doxygen 1.8.14-->
|
|
<!-- start footer part -->
|
|
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
|
</div>
|
|
</body>
|
|
</html>
|