summaryrefslogtreecommitdiffstats
path: root/gbdk/docs/api/docs_using_gbdk.html
blob: 2216054c542b6f9b7d612fbe8279be4a651d5851 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
<!-- 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.8.20"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>GBDK 2020 Docs: Using GBDK</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
   &#160;<span id="projectnumber">4.0.6</span>
   </div>
   <div id="projectbrief">API Documentation for GBDK 2020</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.20 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @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&amp;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&amp;dn=gpl-2.0.txt GPL-v2 */
$(document).ready(function(){initNavTree('docs_using_gbdk.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">Using GBDK </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h1><a class="anchor" id="autotoc_md40"></a>
Interrupts</h1>
<p>Interrupts allow execution to jump to a different part of your code as soon as an external event occurs - for example the LCD entering the vertical blank period, serial data arriving or the timer reaching its end count. For an example see the irq.c sample project.</p>
<p>Interrupts in GBDK are handled using the functions <a class="el" href="gb_8h.html#ad77796783b3a601b6f3781dfc3983499">disable_interrupts()</a>, <a class="el" href="gb_8h.html#ae0b13f17609b26c86fc33944aeb6e867">enable_interrupts()</a>, <a class="el" href="sms_8h.html#aefda0091b2934571a11e07b512735f50">set_interrupts(uint8_t ier)</a> and the interrupt service routine (ISR) linkers <a class="el" href="gb_8h.html#a0d29659d08708143dd8bc720278e06b5">add_VBL()</a>, <a class="el" href="sms_8h.html#a6c66a583a8f0744e3985c89725e3dc10">add_TIM</a>, <a class="el" href="sms_8h.html#a51add93356a25c71e8c37a73c9065c9d">add_LCD</a>, <a class="el" href="sms_8h.html#a3372d61a07e0466bdb909a27f3aaaca9">add_SIO</a> and <a class="el" href="sms_8h.html#a48163816121cd669526817d3e6266fd9">add_JOY</a> which add interrupt handlers for the vertical blank, timer, LCD, serial link and joypad interrupts respectively.</p>
<p>Since an interrupt can occur at any time an Interrupt Service Request (ISR) cannot take any arguments or return anything. Its only way of communicating with the greater program is through the global variables. When interacting with those shared ISR global variables from main code outside the interrupt, it is a good idea to wrap them in a <code>critical {}</code> section in case the interrupt occurs and modifies the variable while it is being used.</p>
<p>Interrupts should be disabled before adding ISRs. To use multiple interrupts, <em>logical OR</em> the relevant IFLAGs together.</p>
<p>ISRs should be kept as small and short as possible, do not write an ISR so long that the Game Boy hardware spends all of its time servicing interrupts and has no time spare for the main code.</p>
<p>For more detail on the Game Boy interrupts consider reading about them in the <a class="el" href="docs_links_and_tools.html#Pandocs">Pandocs</a>.</p>
<h2><a class="anchor" id="autotoc_md41"></a>
Available Interrupts</h2>
<p>The GameBoy hardware can generate 5 types of interrupts. Custom Interrupt Service Routines (ISRs) can be added in addition to the built-in ones available in GBDK.</p>
<ul>
<li>VBL : LCD Vertical Blanking period start<ul>
<li>The default VBL ISR is installed automatically.<ul>
<li>See <a class="el" href="gb_8h.html#a0d29659d08708143dd8bc720278e06b5">add_VBL()</a> and <a class="el" href="gb_8h.html#ad43fdfdb1e157b141f3fc48b78bf4386">remove_VBL()</a></li>
</ul>
</li>
</ul>
</li>
<li>LCD : LCDC status (such as the start of a horizontal line)<ul>
<li>See <a class="el" href="gb_8h.html#a9f9f77105099a34556247d5bb03368d1">add_LCD()</a> and <a class="el" href="gb_8h.html#a32683767caa2a263a1f494b3605786e7">remove_LCD()</a></li>
<li>Example project: <code>lcd_isr_wobble</code></li>
</ul>
</li>
<li>TIM : Timer overflow<ul>
<li>See <a class="el" href="gb_8h.html#a028d1a2e820951bb4f103d6469975ffb">add_TIM()</a> and <a class="el" href="gb_8h.html#a142f6c7755fce8b1148faf658d8ec147">remove_TIM()</a></li>
<li>Example project: <code>tim</code></li>
</ul>
</li>
<li>SIO : Serial Link I/O transfer end<ul>
<li>The default SIO ISR gets installed automatically if any of the standard SIO calls are used. These calls include <a class="el" href="gb_8h.html#aa82422752016328ed0765879e286019f">add_SIO()</a>, <a class="el" href="gb_8h.html#a5b821b31215361265d8b7894a9ae7118">remove_SIO()</a>, <a class="el" href="gb_8h.html#ae339d7d8d7e0ebd6691b42608c416964">send_byte()</a>, <a class="el" href="gb_8h.html#a9a7fd7be44bb12bc85a144b732ce02f7">receive_byte()</a>.</li>
<li>The default SIO ISR cannot be removed once installed. Only secondary chained SIO ISRs (added with <a class="el" href="gb_8h.html#aa82422752016328ed0765879e286019f">add_SIO()</a> ) can be removed.</li>
<li>See <a class="el" href="gb_8h.html#aa82422752016328ed0765879e286019f">add_SIO()</a> and <a class="el" href="gb_8h.html#a5b821b31215361265d8b7894a9ae7118">remove_SIO()</a></li>
<li>Example project: <code>comm</code></li>
</ul>
</li>
<li>JOY : Transition from high to low of a joypad button<ul>
<li>See <a class="el" href="gb_8h.html#aa2f0235e78da2d1d94d3628d7a1afc30">add_JOY()</a> and <a class="el" href="gb_8h.html#a4a3e87e0917d5efb6bc7c94e9754fcd0">remove_JOY()</a></li>
</ul>
</li>
</ul>
<h2><a class="anchor" id="autotoc_md42"></a>
Adding your own interrupt handler</h2>
<p>It is possible to install your own interrupt handlers (in C or in assembly) for any of these interrupts. Up to 4 chained handlers may be added, with the last added being called last. If the <a class="el" href="gb_8h.html#ad43fdfdb1e157b141f3fc48b78bf4386">remove_VBL()</a> function is to be called, only three may be added for VBL.</p>
<p>Interrupt handlers are called in sequence. To install a new interrupt handler, do the following:</p>
<ol type="1">
<li>Write a function (say foo()) that takes no parameters, and that returns nothing. Remember that the code executed in an interrupt handler must be short.</li>
<li>Inside a <code>__critical { ... }</code> section, install your interrupt handling routines using the add_XXX() function, where XXX is the interrupt that you want to handle.</li>
<li>Enable interrupts for the IRQ you want to handle, using the <a class="el" href="gb_8h.html#a9312e7ec34162d6b6ed0875631fa6fe3">set_interrupts()</a> function. Note that the VBL interrupt is already enabled before the main() function is called. If you want to set the interrupts before main() is called, you must install an initialization routine.</li>
</ol>
<p>See the <code>irq</code> example project for additional details for a complete example.</p>
<h2><a class="anchor" id="autotoc_md43"></a>
Using your own Interrupt Dispatcher</h2>
<p>If you want to use your own Interrupt Dispatcher instead of the GBDK chained dispatcher (for improved performance), then don't call the <code>add_...()</code> function for the respective interrupt and it's dispatcher won't be installed.</p><ul>
<li>Exception: the VBL dispatcher will always be linked in at compile time.</li>
<li>For the SIO interrupt, also do not make any standard SIO calls to avoid having it's dispatcher installed.</li>
</ul>
<p>Then, <a class="el" href="isr_8h.html#a73769fed9338af86fdb7df35d7b82620">ISR_VECTOR()</a> or <a class="el" href="isr_8h.html#a78f9ef588aaf221023e48899898d566b">ISR_NESTED_VECTOR()</a> can be used to install a custom ISR handler.</p>
<h2><a class="anchor" id="autotoc_md44"></a>
Returning from Interrupts and STAT mode</h2>
<p>By default when an Interrupt handler completes and is ready to exit it will check STAT_REG and only return at the BEGINNING of either LCD Mode 0 or Mode 1. This helps prevent graphical glitches caused when an ISR interrupts a graphics operation in one mode but returns in a different mode for which that graphics operation is not allowed.</p>
<p>You can change this behavior using <a class="el" href="gb_8h.html#a695c6d0e8fd7cf11dae0d4c67bc058f9">nowait_int_handler()</a> which does not check <a class="el" href="gb_2hardware_8h.html#ad40ebf3b29add46cdd310a7e0802bc6b">STAT_REG</a> before returning. Also see <a class="el" href="gb_8h.html#acc9afd0cb72e763a1213d256b942a68f">wait_int_handler()</a>.</p>
<h1><a class="anchor" id="autotoc_md45"></a>
What GBDK does automatically and behind the scenes</h1>
<h2><a class="anchor" id="autotoc_md46"></a>
OAM (VRAM Sprite Attribute Table)</h2>
<p>GBDK sets up a Shadow OAM which gets copied automatically to the hardware OAM by the default V-Blank ISR. The Shadow OAM allows updating sprites without worrying about whether it is safe to write to them or not based on the hardware LCD mode.</p>
<h2><a class="anchor" id="autotoc_md47"></a>
Font tiles when using stdio.h</h2>
<p>Including <a class="el" href="stdio_8h.html">stdio.h</a> and using functions such as <a class="el" href="stdio_8h.html#ab403fa700816f08631ba75bc536f74d4">printf()</a> will use a large number of the background tiles for font characters. If stdio.h is not included then that space will be available for use with other tiles instead.</p>
<h2><a class="anchor" id="autotoc_md48"></a>
Default Interrupt Service Handlers (ISRs)</h2>
<ul>
<li>V-Blank: A default V-Blank ISR is installed on startup which copies the Shadow OAM to the hardware OAM and increments the global <a class="el" href="sms_8h.html#a78d2fd18666afec116f176d46debb4e7">sys_time</a> variable once per frame.</li>
<li>Serial Link I/O: If any of the GBDK serial link functions are used such as <a class="el" href="gb_8h.html#ae339d7d8d7e0ebd6691b42608c416964">send_byte()</a> and <a class="el" href="gb_8h.html#a9a7fd7be44bb12bc85a144b732ce02f7">receive_byte()</a>, the default SIO serial link handler will be installed automatically at compile-time.</li>
</ul>
<h1><a class="anchor" id="autotoc_md49"></a>
Copying Functions to RAM and HIRAM</h1>
<p>See the <code>ram_function</code> example project included with GBDK demonstrates copying functions to RAM and HIRAM.</p>
<p><code>Warning!</code> Copying of functions is generally not safe since they may contain jumps to absolute addresses that will not be converted to match the new location.</p>
<p>It is possible to copy functions to RAM and HIRAM (using the <a class="el" href="asm_2gbz80_2string_8h.html#a6a1a6cbe7fb6102819098340a4986574">memcpy()</a> and <a class="el" href="gb_8h.html#a97b9f2fc6ac7cae97656aca940d65d44">hiramcpy()</a> functions), and execute them from C. Ensure you have enough free space in RAM or HIRAM for copying a function.</p>
<p>There are basically two ways for calling a function located in RAM, HIRAM, or ROM:</p>
<ul>
<li>Declare a pointer-to-function variable, and set it to the address of the function to call.</li>
<li>Declare the function as extern, and set its address at link time using the -Wl-gXXX=# flag (where XXX is the name of the function, and # is its address).</li>
</ul>
<p>The second approach is slightly more efficient. Both approaches are demonstrated in the <code>ram_function.c</code> example.</p>
<h1><a class="anchor" id="autotoc_md50"></a>
Mixing C and Assembly</h1>
<p>You can mix C and assembly (ASM) in two ways as described below. For additional detail see the <a class="el" href="docs_links_and_tools.html#links_sdcc_docs">links_sdcc_docs</a>.</p>
<h2><a class="anchor" id="autotoc_md51"></a>
Inline ASM within C source files</h2>
<p>Example: <br  />
 </p><pre class="fragment">   __asm__("nop");
</pre><p>Another Example: <br  />
 </p><pre class="fragment">  void some_c_function() 
  {
    // Optionally do something
    __asm
        (ASM code goes here)
    __endasm;
  }
</pre><h2><a class="anchor" id="autotoc_md52"></a>
In Separate ASM files</h2>
<dl class="todo"><dt><b><a class="el" href="todo.html#_todo000002">Todo:</a></b></dt><dd>This is from GBDK 2.x docs, verify it with GBDK-2020 and modern SDCC</dd></dl>
<p>It is possible to assemble and link files written in ASM alongside files written in C.</p>
<ul>
<li>A C identifier <code>i</code> will be called <code>_i</code> in assembly.</li>
<li>Results are always returned into the <code>DE</code> register.</li>
<li>Parameters are passed on the stack (starting at <code>SP+2</code> because the return address is also saved on the stack).</li>
<li>Assembly identifier are exported using the <code>.globl</code> directive.</li>
<li>You can access GameBoy hardware registers using <code>_reg_0xXX</code> where <code>XX</code> is the register number (see <code>sound.c</code> for an example).</li>
<li>Registers must be preserved across function calls (you must store them at function begin, and restore them at the end), except <code>HL</code> (and <code>DE</code> when the function returns a result).</li>
</ul>
<p>Here is an example of how to mix assembly with C:</p>
<p><code>main.c</code> </p><pre class="fragment">main()
{
  int16_t i;
  int16_t add(int16_t, int16_t);

  i = add(1, 3);
}
</pre><p><code>add.s</code> </p><pre class="fragment">.globl _add
_add:         ; int16_t add(int16_t a, int16_t b)
              ; There is no register to save:
              ;  BC is not used
              ;  DE is the return register
              ;  HL needs never to be saved
LDA  HL,2(SP)
LD   E,(HL)   ; Get a in DE
INC  HL
LD   D,(HL)
INC  HL
LD   A,(HL)   ; Get b in HL
INC  HL
LD   H,(HL)
LD   L,A
ADD  HL,DE    ; Add DE to HL
LD   D,H
LD   E,L
              ; There is no register to restore
RET           ; Return result in DE
</pre><h1><a class="anchor" id="autotoc_md53"></a>
Including binary files in C source with incbin</h1>
<p>Data from binary files can be included in C source files as a const array using the <a class="el" href="incbin_8h.html#af34047ed60abd6453f819c2a5230cd2b">INCBIN()</a> macro.</p>
<p>See the <code>incbin</code> example project for a demo of how to use it.</p>
<h1><a class="anchor" id="autotoc_md54"></a>
Known Issues and Limitations</h1>
<h2><a class="anchor" id="autotoc_md55"></a>
SDCC</h2>
<ul>
<li>Const arrays declared with <code>somevar[n] = {x}</code> will <b>NOT</b> get initialized with value <code>x</code>. This may change when the SDCC RLE initializer is fixed. Use memset for now if you need it.</li>
<li>SDCC banked calls and <a class="el" href="docs_rombanking_mbcs.html#far_pointers">far_pointers</a> in GBDK only save one byte for the ROM bank, so for example they are limtied to <b>bank 15</b> max for MBC1 and <b>bank 255</b> max for MBC5. See <a class="el" href="docs_rombanking_mbcs.html#banked_calls">banked_calls</a> for more details. </li>
</ul>
</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>