51 |
52 | ## Make via Programmer's Notepad 2 {#sec-pn2}
53 |
54 | I never really knew about PN until it started coming with devkitARM, but it looks really good. I haven't used it that much myself, but only because I am still content with context. That said, PN is probably the better editor, and as it may come with the toolchain, chances are you'll have it already.
55 |
56 | For all its benefits, I should say this though: by default, it seems to ignore the desktop color scheme. This may not sound like a big deal, but because the background color defaulted to a hard white, I literally couldn't even look at the thing for more than a minute. When I first tried to fix this in the options, it seemed that you could only change this on a type-by-type basis instead of globally. Took me a while to figure out I'd been looking in the wrong place :P all along. Look under Tools-\>Options-\>Styles, not under Tools-\>Options-\>Schemes.
57 |
58 | To add commands for makefiles, go to Tools-\>Options-\>Tools (@fig:pn-make), and select the ‘Make’. Then add 2 commands for ‘make build’ and ‘make clean’
59 |
60 | F9 : make build
61 |
62 | - **Name:** `mk build`
63 | - **Command:** `E:\dev\devkitPro\msys\bin\make.exe`
64 | - **Folder:** `%d` (the makefile's directory)
65 | - **Parameters:** `-f %f build`
66 | - **Shortcut:** F9
67 |
68 | F10 : make clean
69 |
70 | - **Name:** `mk clean`
71 | - **Command:** `E:\dev\devkitPro\msys\bin\make.exe`
72 | - **Folder:** `%d` (the makefile's directory)
73 | - **Parameters:** `-f %f clean`
74 | - **Shortcut:** F10
75 |
76 | The name and shortcut can be different, of course; the rest should be as above. It is possible that you have to make sure the .mak extension is tied to the ‘Make’ scheme.
77 |
78 |
85 |
86 | By adding make commands to your editor, you should be able to run the makefile of every tonc demo. If you encounter problems, you probably forgot to set a path somewhere.
87 |
88 | ## Make via MS Visual C++ 6 {#sec-msvc6}
89 |
90 | I'm sure a lot of you will have gotten your hands on some version of Visual Studio one way or the other, officially, via school or … other methods. MSVC actually works with its own kind of makefiles and maketool called NMAKE, but we're going to ignore that one and use GNU's make instead. The instructions in this section work for versions 5 and 6, but I'm not sure about later versions. From what I hear, they changed a lot in those so if you have one of those you might have to do some digging of your own. I know that there are also add-ons that can create GBA projects via wizards, but again you'll have to find them yourself.
91 |
92 | ### VC and makefile projects {#ssec-msvc-make}
93 |
94 | #### Phase 1: setting the path
95 |
96 | The first thing you need to do, if you haven't done so already, is setting the path so that Visual C can find the tools. Open the \[Tools/Options\] dialog and go to the \[Directories\] tab, then select the \[Executable files\] list from the \[Show Directories for\] box (see @fig:msvc-dirs below). Now you need to add the bin directories of MSYS and dkARM. You can also set these directories to autoexec.bat as well. The devkitARM directory can also be set inside the makefiles themselves, but since I use 4 different computers to write Tonc, I prefer not to do this.
97 |
98 |
99 |
100 |
102 | *@fig:msvc-dirs: adding the the dkARM paths
103 | to the executable list.
104 |
105 |
106 | #### Phase 2: Creating a makefile project
107 |
108 | The second step is creating a project/workspace that uses custom makefiles. This is called, what else, a makefile project. Go to the \[Projects\] tab of the \[File/New\] dialog (shown in @fig:msvc-new below), select Makefile, give it a name and press OK. Mind you, this does *not* create the makefile, only the project! Also, the project's name I use here is ‘tonc’, change this to the name of your own project.
109 |
110 |
116 |
117 | #### Phase 3: Profit!\^H\^H\^H\^Hject settings!
118 |
119 | After you click OK, you will be asked to go to the Project Settings. Do so and you'll see the dialog from fig 6. The first thing you will find is the \[Build command line\] edit box. Right now, this reads something like
120 |
121 | ```sh
122 | NMAKE /f tonc.mak
123 | ```
124 |
125 | Change it to
126 |
127 | ```sh
128 | make -f tonc.mak build
129 | ```
130 |
131 | Why? Because we won't be using the standard VC make (NMAKE), but the GNU make (make). Why? Because it's free, platform-independent and usually comes with the devkit, making your project more portable, is more powerful and better documented as well. Why? Because ... just because, OK? This is the command that is executed when you press Rebuild (F7). The -f flag says which makefile to use. Inside a makefile you can have multiple sub-projects; in this case the one called build is the active one.
132 |
133 | The other settings aren't important for our purposes so leave them as they are. Yes, the output filename too; the makefile will take care of that. By the way, note that the workspace in @fig:msvc-make-cfg shows three projects: tonc and libtonc for actual tonc stuff, and a vault project. A standard practice of mine to have one vault project where I can store source-files I don't want compiled but do want to have available for reference (such as templates and examples). All my workspaces have one and I can highly recommend them.
134 |
135 |
142 |
143 | :::tip Converting GCC reports to MSVC reports
144 |
145 | When you build a normal MSVC project, it will report and errors and warnings and double-clicking on these will bring to to the line that spawned it. This does not work for devkitARM because GCC has a slightly different reporting format.
146 |
147 | ```
148 | # GCC error: {filename}:{line}: error: ...
149 | foo.c:42: error: 'bar' undeclared (first use in this function)
150 | # MSVC error: {dir}\{filename}(line): error ...
151 | dir\foo.c(42) : error C2065: 'bar' : undeclared identifier
152 | ```
153 |
154 | Because of the difference in line-number formatting, MSVC gets confused and can't find the line, or even the file. Fortunately, we can change this by piping the output of make through sed, the bash-shell string editor that comes with msys. To do this, change the build invocation to:
155 |
156 | ```sh
157 | make -f tonc.mak build 2>&1 | sed -e 's|\(\w\+\):\([0-9]\+\):|\1(\2):|'
158 | ```
159 |
160 | The `2>&1 | ` feeds the standard output of make to the standard input of the sed. The rest is a sed command that finds the parts before the first two colons, and converts them to the parenthesized format the MSVC expects. Note that tonc's build line is slightly more complicated because of its directory structure but the line above is what really matters.
161 |
162 | :::
163 |
164 | #### Phase 3b: Build configurations
165 |
166 | This one isn't strictly necessary, but may be useful. In Visual C++ you can have multiple build configurations, each with its own project settings. You're probably familiar with the Debug and Release Builds, but you can add your own as well with the \[Build/Configurations\] dialog (shown in @fig:msvc-bld-cfg). The tonc project has five configurations, which all drive different targets in tonc.mak. `Build` builds the current demo; `Clean` removes all intermediary and output files (.O, .ELF and.GBA). In order to build/clean a specific demo you'd have to change the project settings or, preferably, set the `DEMO` variable inside tonc.mak to the name of that demo. `Build All` and `Clean All` run `Build` and `Clean` for all demos, respectively. The ‘Utils’ configuration creates the tonc library required for some of the later examples.
167 |
168 |
175 |
176 | And that's about it as far as Visual C++ is concerned. You still have to actually create the referenced makefile (tonc.mak in this case). You know how to create a textfile, don't you? Another thing to remember about makefile projects is that all build commands are inside the makefile; the files mentioned in the File Viewer are just for show and are not compiled by themselves like ‘normal’ VC projects.
177 |
178 | :::note Easy switching between devkits in tonc.mak
179 |
180 | Tonc's makefiles are of such nature that each can stand on its own, but can also be called from a central makefile tonc.mak, with the `DEMO` variable. I've also put a `CROSS` (which houses the prefix) variable in there which overrides `CROSS` of the individual makefiles. Changing it in tonc.mak effectively changes it everywhere.
181 |
182 | :::
183 |
184 | :::tip Getting rid of MSVC 6.0's useless directories
185 |
186 | It appears that Visual Studio 6 (and higher too?) has a very annoying habit of creating all kinds of extra directories for each project added to a workspace and for each project configuration. Directories that you probably never intend to use, and *certainly* never asked for, and which clutter up your project. Removing them from disk doesn't solve the problem, because they'll just reappear merely by selecting the project/configuration.
187 |
188 | \*grumble\*
189 |
190 | Well, the good news is that for normal projects you can just remove them from the project settings, then remove them from disk and everything will be clean again. The bad news is that we're not using normal projects but makefile projects, which don't have the settings-tab in question. So what you have to do is go to the .DSP in a text editor, and remove everything resembling the following lines
191 |
192 | ```
193 | # PROP BASE Output_Dir [DIR]
194 | # PROP BASE Intermediate_Dir [DIR]
195 | # PROP Output_Dir [DIR]
196 | # PROP Intermediate_Dir [DIR]
197 | ```
198 |
199 | No, I don't exactly know what I'm doing, but yes when you remove the directories now they *stay* gone. In fact, I'm pretty sure a lot of lines can be removed from the DSP, but as there is no manual for the commands in a project file, I'm not taking any chances there.
200 |
201 | Now, if anyone does have a reference guide for DSP files, or can tell me whether this obnoxious behaviour is still present in later MSVC iterations, I'm all ears.
202 |
203 | :::
204 |
--------------------------------------------------------------------------------
/content/fonts/Font_LICENSE:
--------------------------------------------------------------------------------
1 | Source Sans: Copyright 2010-2022 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
2 |
3 | Fira Code: Copyright (c) 2014, The Fira Code Project Authors (https://github.com/tonsky/FiraCode)
4 |
5 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
6 | This license is copied below, and is also available with a FAQ at:
7 | http://scripts.sil.org/OFL
8 |
9 | -----------------------------------------------------------
10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11 | -----------------------------------------------------------
12 |
13 | PREAMBLE
14 | The goals of the Open Font License (OFL) are to stimulate worldwide
15 | development of collaborative font projects, to support the font creation
16 | efforts of academic and linguistic communities, and to provide a free and
17 | open framework in which fonts may be shared and improved in partnership
18 | with others.
19 |
20 | The OFL allows the licensed fonts to be used, studied, modified and
21 | redistributed freely as long as they are not sold by themselves. The
22 | fonts, including any derivative works, can be bundled, embedded,
23 | redistributed and/or sold with any software provided that any reserved
24 | names are not used by derivative works. The fonts and derivatives,
25 | however, cannot be released under any other type of license. The
26 | requirement for fonts to remain under this license does not apply
27 | to any document created using the fonts or their derivatives.
28 |
29 | DEFINITIONS
30 | "Font Software" refers to the set of files released by the Copyright
31 | Holder(s) under this license and clearly marked as such. This may
32 | include source files, build scripts and documentation.
33 |
34 | "Reserved Font Name" refers to any names specified as such after the
35 | copyright statement(s).
36 |
37 | "Original Version" refers to the collection of Font Software components as
38 | distributed by the Copyright Holder(s).
39 |
40 | "Modified Version" refers to any derivative made by adding to, deleting,
41 | or substituting -- in part or in whole -- any of the components of the
42 | Original Version, by changing formats or by porting the Font Software to a
43 | new environment.
44 |
45 | "Author" refers to any designer, engineer, programmer, technical
46 | writer or other person who contributed to the Font Software.
47 |
48 | PERMISSION & CONDITIONS
49 | Permission is hereby granted, free of charge, to any person obtaining
50 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
51 | redistribute, and sell modified and unmodified copies of the Font
52 | Software, subject to the following conditions:
53 |
54 | 1) Neither the Font Software nor any of its individual components,
55 | in Original or Modified Versions, may be sold by itself.
56 |
57 | 2) Original or Modified Versions of the Font Software may be bundled,
58 | redistributed and/or sold with any software, provided that each copy
59 | contains the above copyright notice and this license. These can be
60 | included either as stand-alone text files, human-readable headers or
61 | in the appropriate machine-readable metadata fields within text or
62 | binary files as long as those fields can be easily viewed by the user.
63 |
64 | 3) No Modified Version of the Font Software may use the Reserved Font
65 | Name(s) unless explicit written permission is granted by the corresponding
66 | Copyright Holder. This restriction only applies to the primary font name as
67 | presented to the users.
68 |
69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70 | Software shall not be used to promote, endorse or advertise any
71 | Modified Version, except to acknowledge the contribution(s) of the
72 | Copyright Holder(s) and the Author(s) or with their explicit written
73 | permission.
74 |
75 | 5) The Font Software, modified or unmodified, in part or in whole,
76 | must be distributed entirely under this license, and must not be
77 | distributed under any other license. The requirement for fonts to
78 | remain under this license does not apply to any document created
79 | using the Font Software.
80 |
81 | TERMINATION
82 | This license becomes null and void if any of the above conditions are
83 | not met.
84 |
85 | DISCLAIMER
86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94 | OTHER DEALINGS IN THE FONT SOFTWARE.
95 |
--------------------------------------------------------------------------------
/content/fonts/SourceSans3-It.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/SourceSans3-It.otf.woff
--------------------------------------------------------------------------------
/content/fonts/SourceSans3-Regular.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/SourceSans3-Regular.otf.woff
--------------------------------------------------------------------------------
/content/fonts/SourceSans3-Semibold.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/SourceSans3-Semibold.otf.woff
--------------------------------------------------------------------------------
/content/fonts/SourceSans3-SemiboldIt.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/SourceSans3-SemiboldIt.otf.woff
--------------------------------------------------------------------------------
/content/fonts/fira_code.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Fira Code';
3 | src: url('woff2/FiraCode-Light.woff2') format('woff2'),
4 | url("woff/FiraCode-Light.woff") format("woff");
5 | font-weight: 300;
6 | font-style: normal;
7 | }
8 |
9 | @font-face {
10 | font-family: 'Fira Code';
11 | src: url('woff2/FiraCode-Regular.woff2') format('woff2'),
12 | url("woff/FiraCode-Regular.woff") format("woff");
13 | font-weight: 400;
14 | font-style: normal;
15 | }
16 |
17 | @font-face {
18 | font-family: 'Fira Code';
19 | src: url('woff2/FiraCode-Medium.woff2') format('woff2'),
20 | url("woff/FiraCode-Medium.woff") format("woff");
21 | font-weight: 500;
22 | font-style: normal;
23 | }
24 |
25 | @font-face {
26 | font-family: 'Fira Code';
27 | src: url('woff2/FiraCode-SemiBold.woff2') format('woff2'),
28 | url("woff/FiraCode-SemiBold.woff") format("woff");
29 | font-weight: 600;
30 | font-style: normal;
31 | }
32 |
33 | @font-face {
34 | font-family: 'Fira Code';
35 | src: url('woff2/FiraCode-Bold.woff2') format('woff2'),
36 | url("woff/FiraCode-Bold.woff") format("woff");
37 | font-weight: 700;
38 | font-style: normal;
39 | }
40 |
41 | @font-face {
42 | font-family: 'Fira Code VF';
43 | src: url('woff2/FiraCode-VF.woff2') format('woff2-variations'),
44 | url('woff/FiraCode-VF.woff') format('woff-variations');
45 | /* font-weight requires a range: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide#Using_a_variable_font_font-face_changes */
46 | font-weight: 300 700;
47 | font-style: normal;
48 | }
--------------------------------------------------------------------------------
/content/fonts/woff/FiraCode-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff/FiraCode-Bold.woff
--------------------------------------------------------------------------------
/content/fonts/woff/FiraCode-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff/FiraCode-Light.woff
--------------------------------------------------------------------------------
/content/fonts/woff/FiraCode-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff/FiraCode-Medium.woff
--------------------------------------------------------------------------------
/content/fonts/woff/FiraCode-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff/FiraCode-Regular.woff
--------------------------------------------------------------------------------
/content/fonts/woff/FiraCode-SemiBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff/FiraCode-SemiBold.woff
--------------------------------------------------------------------------------
/content/fonts/woff/FiraCode-VF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff/FiraCode-VF.woff
--------------------------------------------------------------------------------
/content/fonts/woff2/FiraCode-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff2/FiraCode-Bold.woff2
--------------------------------------------------------------------------------
/content/fonts/woff2/FiraCode-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff2/FiraCode-Light.woff2
--------------------------------------------------------------------------------
/content/fonts/woff2/FiraCode-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff2/FiraCode-Medium.woff2
--------------------------------------------------------------------------------
/content/fonts/woff2/FiraCode-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff2/FiraCode-Regular.woff2
--------------------------------------------------------------------------------
/content/fonts/woff2/FiraCode-SemiBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff2/FiraCode-SemiBold.woff2
--------------------------------------------------------------------------------
/content/fonts/woff2/FiraCode-VF.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/tonc/bfcab3c294d4ba74ee8d092926845760c55ae31a/content/fonts/woff2/FiraCode-VF.woff2
--------------------------------------------------------------------------------
/content/foreword.md:
--------------------------------------------------------------------------------
1 | # Foreword
2 |
3 | Welcome to Tonc, a guide to Game Boy Advance programming originally published in 2004.
4 |
5 | You are reading a new, revamped version of it, powered by mdbook and now maintained by the community.
6 |
7 | :::warning Work In Progress notice
8 |
9 | We recently finished the porting of this book. Improvements ongoing, if you spot any problems please feel free to ask for help or get involved!
10 |
11 | :::
12 |
13 | ## Contributing
14 |
15 | This book is open source, released under the [CC-BY-NC-SA](https://raw.githubusercontent.com/gbadev-org/tonc/master/LICENSE) license. Everyone is welcome to help, provide feedback and propose additions or improvements. The git repository is hosted at [github.com/gbadev-org/tonc](https://github.com/gbadev-org/tonc), where you can learn more about how you can help, find detailed contribution guidelines and procedures, file Issues and send Pull Requests.
16 |
17 | More resources about GBA development can be found at [gbadev.net](https://gbadev.net). There is also a [Discord chat](https://discord.gg/DDYbusKVyJ) dedicated to the gbadev community.
18 |
19 | ## Authors
20 |
21 | Jasper "cearn" Vijn is the original author, creating and maintaining Tonc till 2013.
22 |
23 | exelotl, avivace, PinoBatch, copyrat90, LunarLambda, gwilymk, mtthgn, and djedditt ported the contents to markdown and migrated the underlying rendering technology to mdbook.
24 |
25 | ## Using this document
26 |
27 | In the top navigation bar, you will find a series of icons.
28 |
29 | By clicking on the icon you will toggle an interactive table of contents to navigate the document. You can also use → and ← keys on your keyboard to go to the following and previous page.
30 |
31 | The lets you choose among 6 different themes and color schemes to please your reading experience, including the classic Tonc theme.
32 |
33 | You can search anywhere by pressing s on your keyboard or clicking the icon.
34 |
35 | The icon allows you to suggest an edit on the current page by directly opening the source file in the git repository.
36 |
37 |
--------------------------------------------------------------------------------
/content/hardware.md:
--------------------------------------------------------------------------------
1 | # 1. GBA Hardware
2 |
3 |
4 |
5 | ## Meet the GBA {#sec-intro}
6 |
7 | The Nintendo Game Boy Advance (GBA) is a portable games console. As if you didn't know already. The CPU is a 32-bit ARM7tdmi chip running at 16.78 MHz. It has a number of distinct memory areas (like work RAM, IO and video memory) which we will look into shortly. The games are stored on Game Paks, consisting of ROM for code and data, and fairly often some RAM for saving game info. The GBA has a 240x160 LCD screen capable of displaying 32768 colors (15 bits).
8 |
9 | Unfortunately, the screen is not back-lit, which made a lot of people very angry and has generally been regarded as a bad move. So, in 2003 Nintendo launched the GBA SP, a sort of GBA 2.0, which features a fold-up screen reminiscent of the old Game & Watch games (remember those? You do? Boy, you are *old*! (For the record, I still have mine too :) )). Then came the final GBA version, the Game Boy Micro, a very, very small GBA which easily fits in everyone's pockets. The differences the GBA, GBA-SP and Micro are mainly cosmetic, though, they're the same thing from a programming point of view.
10 |
11 | The original Game Boy took the world by storm in 1989. Not bad for a monochrome handheld console, eh? Later the Game Boy Color was released which finally put some color on the aging machine, but it was still very much a simple Game Boy. The true successor was the GBA, released in 2001. The GBA is backward compatible with the Game Boy, so you can play all the old GB games as well.
12 |
13 | In terms of capabilities the GBA is a lot like the Super NES (SNES): 15-bit color, multiple background layers and hardware rotation and scaling. And shoulder buttons, of course. A cynic might look at the enormous amount of SNES ports and say that the GBA *is* a SNES, only portable. This is true, but you can hardly call that a bad thing.
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {*@fig:gba}: original GBA.
24 |
25 |
26 |
27 |
28 |
29 |
30 | {*@fig:gba-sp}: GBA-SP.
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | ## GBA specs and capabilities {#sec-specs}
39 |
40 | Below is a list of the specifications and capabilities of the GBA. This is not a full list, but these are the most important things you need to know.
41 |
42 | - Video
43 | - 240x160 pixel, 15-bit color LCD screen. The original GBA screen was not backlit, but the SP's and Micro's are.
44 | - 3 [bitmap modes](bitmaps.html) and 3 [tilemap modes](regbg.html) and [sprites](regobj.html).
45 | - 4 individual tilemap layers (backgrounds) and 128 sprites (objects).
46 | - [Affine transformations](affine.html) (rotate/scale/shear) on 2 backgrounds and 32 objects.
47 | - [Special graphic effects](gfx.html): mosaic, additive blend, fade to white/black.
48 | - Sound
49 | - 6 channels total
50 | - 4 tone generators from the original Game Boy: 2 square wave, 1 general wave and one noise generator.
51 | - 2 'DirectSound' channels for playing samples and music.
52 | - Miscellaneous
53 | - 10 buttons (or [keys](keys.html)): 4-way directional pad, Select/Start, fire buttons A/B, shoulder buttons L/R.
54 | - 14 hardware interrupts.
55 | - 4-player multiplayer mode via a multiboot cable.
56 | - Optional infrared, solar and gyroscopic interfaces. Other interfaces have also been made by some.
57 | - Main programming platforms: C/C++ and assembly, though there are tools for Pascal, Forth, Lua and others as well. Easy to start with, yet hard to truly master.
58 |
59 | From a programming point of view, the GBA (or any other console for that matter) is totally different from a PC. There is no operating system, no messing with drivers and hardware incompatibilities; it's bits as far as the eye can see. Well, PCs are also just bits, but that's several layers down; on consoles it's just you, the CPU and memory. Basically, it's the [Real Programmer](http://www.catb.org/~esr/jargon/html/R/Real-Programmer.html)'s dream.
60 |
61 | To get anything done, you use memory-mapped IO. Specific areas of memory are mapped directly to hardware functions. In the first demo, for example, we will write the number `0x0403` to memory address `0400:0000h`. This tells the GBA to enable background 2 and set the graphics mode to 3. What this actually *means* is, of course, what this tutorial is for :).
62 |
63 | ### CPU {#ssec-cpu}
64 |
65 | As said, the GBA runs on a ARM7tdmi RISC chip at 16.78 MHz (224 cycles/second). It is a 32-bit chip that can run on two different instruction sets. First, there's is ARM code, which is a set of 32-bit instructions. Then there's Thumb, which uses 16-bit instructions. Thumb instructions are a subset of the ARM instruction set; since the instructions are shorter, the code can be smaller, but their power is also reduced. It is recommended that normal code be Thumb code in ROM, and for time-critical code to be ARM code and put in IWRAM. Since all tonc-demos are still rather simple, most (but not all) code is Thumb code.
66 |
67 | For more information on the CPU, go to [www.arm.com](http://www.arm.com) or to the [assembly chapter](asm.html)
68 |
69 | ## Memory Sections {#sec-memory}
70 |
71 | This section lists the various memory areas. It's basically a summary of the [GBATEK](https://problemkaputt.de/gbatek.htm) section on memory.
72 |
73 |
74 |
75 |
76 |
77 |
78 |
area
79 |
start
80 |
end
81 |
length
82 |
port-size
83 |
description
84 |
85 |
86 |
87 |
88 |
System ROM
89 |
0000:0000
90 |
0000:03FF
91 |
16 KB
92 |
32 bit
93 |
Bios memory. You can execute it, but not read it (i.o.w, touch, don't look)
94 |
95 |
96 |
EWRAM
97 |
0200:0000h
98 |
0203:FFFFh
99 |
256 KB
100 |
16 bit
101 |
External work RAM. Is available for your code and data. If you're using a multiboot cable, this is where the downloaded code goes and execution starts (normally execution starts at ROM). Due to the 16-bit port, you want this section's code to be Thumb code.
102 |
103 |
104 |
IWRAM
105 |
0300:0000h
106 |
0300:7FFFh
107 |
32 KB
108 |
32 bit
109 |
This is also available for code and data. The 32-bit bus and the fact it's embedded in the CPU make this the fastest memory section. The 32-bit bus means that ARM instructions can be loded at once, so put your ARM code here.
110 |
111 |
112 |
IO RAM
113 |
0400:0000h
114 |
0400:03FFh
115 |
1 KB
116 |
32 bit
117 |
Memory-mapped IO registers. These have nothing to do with the CPU registers you use in assembly so the name can be a bit confusing. Don't blame me for that. This section is where you control graphics, sound, buttons and other features.
118 |
119 |
120 |
PAL RAM
121 |
0500:0000h
122 |
0500:03FFh
123 |
1 KB
124 |
16 bit
125 |
Memory for two palettes contaning 256 entries of 15-bit colors each. The first is for backgrounds, the second for sprites.
126 |
127 |
128 |
VRAM
129 |
0600:0000h
130 |
0601:7FFFh
131 |
96 KB
132 |
16 bit
133 |
Video RAM. This is where the data used for backgrounds and sprites are stored. The interpretation of this data depends on a number of things, including video mode and background and sprite settings.
134 |
135 |
136 |
OAM
137 |
0700:0000h
138 |
0700:03FFh
139 |
1 KB
140 |
32 bit
141 |
Object Attribute Memory. This is where you control the sprites.
142 |
143 |
144 |
PAK ROM
145 |
0800:0000h
146 |
var
147 |
var
148 |
16 bit
149 |
Game Pak ROM. This is where the game is located and execution starts, except when you're running from a multiboot cable. This size is variable, but the limit is 32 MB. It's a 16-bit bus, so Thumb code is preferable over ARM code here.
150 |
151 |
152 |
Cart RAM
153 |
0E00:0000h
154 |
var
155 |
var
156 |
8 bit
157 |
This is where saved data is stored. Cart RAM can be in the form of SRAM, Flash ROM or EEPROM. Programatically they all do the same thing: store data. The total size is variable, but 64 KB is a good indication.
Hello and welcome to Tonc, a guide to GBA programming. In these
61 | pages you'll find information on various aspects of GBA programming,
62 | such as the GBA video system (including a detailed, mathematically
63 | correct look into how the GBA does those rotational sprites and
64 | backgrounds), button handling and DMA, but also trickier subjects
65 | like interrupts, BIOS calls, and graphical tricks like blending,
66 | windowing and Mode 7. All subjects have at least one non-trivial
67 | demo for them.
68 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/content/refs.md:
--------------------------------------------------------------------------------
1 | # F. References and links
2 |
3 |
4 |
5 | ## General sites {#sec-gen}
6 |
7 | ### Essentials {#ssec-essential}
8 |
9 | - [www.devkitpro.org](https://devkitpro.org/). Home of **devkitARM**, the toolchain of choice for GBA development. And NDS and more. Updated regularly and you can find a **libgba** and sample code here too.
10 | - [www.gbadev.org](http://www.gbadev.org). GBA development hub. Tools, documents, tutorials can all be found here. A visit to the [forum](http://forum.gbadev.org) is highly recommended if you're just starting, whether you have problems or not. If you do have a problem, chances are you're not the first and that it has been solved before here. Just remember the [rules of posting](http://www.albinoblacksheep.com/flash/posting.php) before you start a topic.
11 | - [Nocash](http://nocash.emubase.de/). Martin Korth's site. You can find the immensely complete (though Spartan) [GBATEK](https://problemkaputt.de/gbatek.htm) reference document and the [No\$gba](http://nocash.emubase.de/gba.htm) emulator, both of which are insanely great.
12 | - [vba.ngemu.com](http://vba.ngemu.com), The **VisualBoy Advance** emulator. Not as accurate as no\$gba when it comes to timings, but still very, very good, and has a more friendly interface and all kinds of cool viewers for tiles, maps, IO registers and the like.
13 |
14 | ### Alternative dev environments {#ssec-altdev}
15 |
16 | - [www.ngine.de](http://www.ngine.de), Host of **HAM**. HAM is a full C developer environment for the GBA, complete with IDE, palette and map editor and, of course, compiler. There is also an extension library called [HEL](http://www.console-dev.de/project/hel-library-for-gba/) with extra (and optimized) code. Taking a look at that would be a good idea.
17 | - **DragonBasic**. If you don't like all the intricacies of C/asm, you might try this BASIC-like environment. The project is a little, uhm, asleep right now, though.
18 | - [Catapult](https://web.archive.org/web/20071106103247/http://www.nocturnal-central.com/catapult.php). Don't know too much about Catapult, but from what I've seen, it seems to work a little bit like Gamemaker: you create images/sound and scripts that Catapult ties together into a ROM image. Catapult comes complete with graphic, map and sound editors, tutorials, samples, emulator and probably more.
19 |
20 | ### Personal sites {#ssec-personal}
21 |
22 | A few sites of (high-ranked) forum-dwellers. These guys have been around for a while and you can learn a lot from playing their demos and browsing through their source code.
23 |
24 | - [darkfader.net](https://www.darkfader.net/main/). Darkfader's site, with information, tools, demos, code not only for GBA development, but many other systems as well.
25 | - [deku.rydia.net](https://web.archive.org/web/20160203205842/http://deku.rydia.net/). DekuTree64's site has more than just the sound mixer; there's also some demos (with source) and tools like **quither**, a quantizer / ditherer for 16 color tiles.
26 | - Headspin had put together [this overview](https://web.archive.org/web/20220512153726/https://members.iinet.net.au/~freeaxs/gbacomp/) of various items, incluning the different compression routines and music players available.
27 | - [www.thingker.com](https://web.archive.org/web/20050205230410/http://www.thingker.com:80/gba/). Scott Lininger's site with a number of demos, including **multiplayer** code, which seems very hard to come by.
28 | - [www.console-dev.de](http://www.console-dev.de). Peter Schaut's site, with VisualHam, the HAMlib IDE; HEL, the HAM addon library; katie, a data-management tool and more.
29 | - [www.pineight.com](http://www.pineight.com/). Site of gbadev faq maintainer, tepples. There are a number of interesting things here. Special mentions for **Tetanus on Drugs**, a zonked-out version of tetris (can't call it a clone as it is so much more), and **GBFS**, a file system for the GBA.
30 |
31 | ## Documents {#sec-doc}
32 |
33 | ### Tutorials {#ssec-tut}
34 |
35 | - [www.belogic.com](http://www.belogic.com). Pretty much _the_ site on GBA sound programming. Has info on all the registers, and a set of _very_ complete demos.
36 | - If you're looking for **C/C++ tutorials**, there seems to be some good stuff [here](http://www.cprogramming.com/tutorial.html)
37 | - DekuTree's [sound mixing tutorial](https://stuij.github.io/deku-sound-tutorial/). Whereas Belogic shows the basics of sound programming, this sight guides you through the steps of making a sound/music mixer.
38 | - [www.drunkencoders.com](http://www.drunkencoders.com). This is the new home of **the PERN project**, the original series of tutorials for gba development. PERN was set for a complete renewal, but that seems to have been deprioritised in favor of the DS, which you will also find a lot about there.
39 | - jake2431 has been gathering **NDS / C / GBA tutorial links** on the gbadev [forum:8353](https://gbadev.net/forum-archive/thread/18/8353.html)
40 |
41 | ### Reference documents {#ssec-ref}
42 |
43 | - The [**comp.lang.c FAQ**](http://c-faq.com/). Pretty long, but very useful if you're learning C as well as GBA programming.
44 | - A document on [**C coding standards**](https://web.archive.org/web/20110624025547/http://www.jetcafe.org/~jim/c-style.html), one of many floating around. If you've based your code on any of the non-tonc tutorials out there you **_need_** to read this. The standard doesn't have to be followed religiously, but adopting most of them would be a good idea and would solve a lot of the bad habits the other sites teach.
45 | - Mr Lee has a few things to say about [optimization](https://web.archive.org/web/20170907095140/http://leto.net/docs/C-optimization.php). These are simple optimization that cost nothing or little in readability.
46 | - The [**gbadev forum FAQ**](https://gbadev.net/forum-archive/thread/14/418.html). Essential reading, whether you're new or not. Bookmark it, make a local copy, print it out; I don't care, but get FAQed.
47 | - The [**GBATEK**](https://problemkaputt.de/gbatek.htm). reference document. This is basically the GBA-coders' bible (only this one _is_ a worthwhile read). The information density is very high and maybe a little perplexing if you're just starting, but when you get the hang of it, it's pretty much all you'll require. Is also part of HAMLib's documentation.
48 | - The [CowBite Spec](http://www.cs.rit.edu/~tjh8300/CowBite/CowBiteSpec.htm), a another reference document. At least partially based on GBATEK. Not as rich, but probably more understandable.
49 | - [www.gnu.org](http://www.gnu.org/manual/manual.html#Development). **GCC documentation** in various formats. These sites have manuals on the GCC toolchains and other things. Get the files for the assembler (**AS**), compiler (**GCC**), linker (**LD**) and preferably the maketool (**make**) as well. The preprocessor manual (**cpp**) may be useful as well.
50 |
51 | ### ARM docs {#ssec-arm}
52 |
53 | Naturally, the ARM site itself also has useful documents. Note that most of these are pdfs.
54 |
55 | - [miscPDF 8031](https://github.com/ARM-software/abi-aa/releases/download/2023Q3/aapcs32.pdf). The **Arm Architecture Procedure Call Standard** (AAPCS). Explains how parameters are passed between functions. Required reading if you want to do assembly.
56 | - [PDF DAI0034A](http://netwinder.osuosl.org/pub/netwinder/docs/arm/DAI0034vA.pdf). **Writing efficient C for ARM**. Although it's written with ARM's own compiler in mind, some tips will work for other toolchains as well.
57 | - [PDF DDI0210B](https://documentation-service.arm.com/static/5f4786a179ff4c392c0ff819?token=) The big one: the complete **technical reference manual** for the ARM7TDMI.
58 | - **Instruction set reference sheets**. [ARM + Thumb](https://documentation-service.arm.com/static/5ed66080ca06a95ce53f932d?token=) combined.
59 | - Support faqs on **alignment issues**: [faqdev 1228](https://web.archive.org/web/20080331064522/http://www.arm.com/support/faqdev/1228.html), [faqdev 1469](https://web.archive.org/web/20070202123419/http://www.arm.com/support/faqdev/1469.html), and [faqip 3661](https://web.archive.org/web/20090117030418/http://www.arm.com/support/faqip/3661.html).
60 |
61 | ## Tools {#sec-tools}
62 |
63 | ### Source code tools {#ssec-tools-text}
64 |
65 | If you're still using Notepad to write your GBA code, don't. Do yourself a favor and just … don't, OK? Though I personally use Visual C for writing code, there are some other very nice tools for the job, both in terms of general text editors as IDEs.
66 |
67 | - **[ConTEXT](https://archive.org/details/tucows_349269_ConTEXT)**. A while back there was a thread where someone asked for a replacement editor for Notepad since, and I quote, “Notepad SUCKS!”. The name ConTEXT popped up a couple of times, and I find it very nice indeed, and not just for coding purposes. It allows for custom highlighters, integrated shell commands (to run makefiles for example) and attachable help files
68 | - [**Programmer's Notepad**](http://www.pnotepad.org/) (PN). Good and versatile text editor. Comes with the devkitPro installation.
69 | - **[Eclipse IDE](http://www.eclipse.org)**. While I haven't had time to work with it firsthand, a good number of gbadev forum-dwellers swear by it. You can read how to set it up for GBA development in [forum:5271](https://gbadev.net/forum-archive/thread/14/5271.html).
70 | - **[Dev-C++](http://www.bloodshed.net/)**. Dev-C++ is another IDE that comes up often and maybe worth a look. [forum:1736](https://gbadev.net/forum-archive/thread/7/1736.html) has info on how to set it up, but it's an old thread so you may have to do a little extra work.
71 |
72 | ### Graphics tools {#ssec-tools-gfx}
73 |
74 | Just as Notepad sucks for coding (and anything apart from the simplest text editing), MS-Paint is hell on Earth when it comes to the kind of graphics you need in GBA games. What you need is a tool that allows full control over the bitmap's palette, and MS-Paint fails spectacularly in that respect. So, I might add, does Visual C's native bitmap editor. And even big and bulky photo-editing tools like PhotoShop and Paint Shop Pro have difficulty here, or so I'm told. So here are some tools that do allow the kind of control that you need. Whatever tool you plan on using: **make sure it doesn't screw up the palette**! Some editors are known to throw entries around.
75 |
76 | - **[gfx2gba](http://www.ohnehirn.de/tools/)**. Command-line converter of graphics with interesting features such as tile-stripping, palette merging and supports all bitdepths and BIOS compression routines. Note that there are two converters named gfx2gba; you'll want the one my Markus. The HAM distribution includes this tool.
77 | - **[The GIMP](http://www.gimp.com)**. Very complete GNU-based bitmap/photo editor.
78 | - **[Graphics Gale](https://graphicsgale.com/us/)** is a very complete graphics editor. It has all the tools you would expect a bitmap editor to have, a proper palette editor and an animation tool.
79 | - **[Usenti](http://www.coranac.com/projects/#usenti)**. This is my own bitmap editor. It may not be as advanced as Graphics Gale, but that does make the interface a lot easier. Aside from that it has some very interesting palette tweaking options like a palette swapper and sorter, and can export to GBA formats in binary, ASM and C code.
80 |
81 | ### Map Editors {#ssec-tools-map}
82 |
83 | While the maps that I've used in Tonc were created on the fly, for any serious work you need a map editor. Here are a few.
84 |
85 | - **[MapEd](http://nessie.gbadev.org)**, by Nessie. Allows multiple layers, collision tiles and custom exporters. Yum.
86 | - **[Mappy](http://www.tilemap.co.uk/mappy.php)**. This is a general purpose map editor which can be used for a lot of different types of maps
87 | - **[Mirach](http://www.coranac.com/projects/#mirach)**. This is my own map editor, but lack of time means that I haven't been able to get all the tools that I wanted in yet `:(`.
88 |
89 | ### Misc tools {#ssec-tools-misc}
90 |
91 | - **[excellut](http://www.coranac.com/projects/#excellut)**. One thing you do not want in GBA programming is to call mathematical functions. You want [look-up tables](luts.html) to get the proper values. Excellut sets up MS Excel to enable you to create any kind of LUT you can think of within seconds (well, OK, minutes). If you haven't created a LUT builder of your own (and maybe even if you have)it's definitely worth a look.
92 |
93 | ## Books {#sec-books}
94 |
95 | - Douglas Adams, “_The Hitchhiker's Guide to the Galaxy_”. OK, so this isn't exactly a reference, but recommended nonetheless. If only to know the significance of the number 42 and the origin of the Babel Fish.
96 | - Edward Angel, “_Interactive Computer Graphics with Open GL_”. Though this is a book on 3D, Lots of the linear algebra can be applied to 2D as well. Relevant chapters are 4 (matrix transformations) and 5 (perspective (Mode 7 anyone?)). Make sure you have the 3rd edition, there are too many embarassing errors in the second.
97 | - George B. Arfken & Hans J. Weber, “_Mathematical Methods for Physicists_” If physics were an RPG, this would be the Monster's Manual. Chapters 1-3 deal with vectors and matrices in great detail.
98 | - André LaMothe, “_Black Art of 3D Game Programming_”. For the DOS-era, so may be hard to find. Deals with 3D programming under heavy hardware constraints (just like the GBA). Very nice.
99 | - André LaMothe “_Tricks of the Windows Game Programming Gurus_”. Another 1000+ page tome by Mr LaMothe; one of many), an excellent guide to game programming in general, and to DirectX in particular.
100 | - David C. Lay, “_Linear Algebra and its Applications_”. Nearly everything on my [matrix](matrix.html) page comes out of this book.
101 | - O'Reilly pocket references for “_CSS_” and “_HTML_” by Eric Meyer and Jennifer Niederst, respectively. Absolute lifesavers for something like this site.
102 | - Steve Oualline, “_How Not to Program in C++_”. The cover features a computer sticking its tongue out at you; the first sentence of the introduction is “Pain is a wonderful learning tool”. You just know this is gonna be good. This book gives you 111 broken code problems to solve, ranging from obvious to crafted by the Dark Lord himself. If you can't recognize yourself in at least half of these problems, you haven't been coding in C for very long.
103 |
--------------------------------------------------------------------------------
/content/setup.md:
--------------------------------------------------------------------------------
1 | # 2. Setting up a development environment
2 |
3 |
4 |
5 | ## Introduction {#sec-intro}
6 |
7 | Unless you want to punch in the instructions in binary in a hex editor, you'll need a development environment to turn human readable code into machine code. This chapter will show you how to set up the necessary components and use them to compile Tonc's examples.
8 |
9 | By the end you should have:
10 |
11 | * A text editor
12 | * A GBA emulator _(mGBA)_
13 | * A cross-compiler toolchain _(devkitARM)_
14 | * Libraries used for GBA programming _(libtonc in particular)_
15 | * The examples which accompany this tutorial
16 |
17 |
18 | :::warning Some command-line skills required
19 |
20 | To compile a GBA game, you'll need a basic undestanding of the command-line. If this is unfamiliar to you, the following [Unix command-line tutorial](https://command-line-tutorial.readthedocs.io/) may be helpful.
21 |
22 | If you're on Windows, you should use the **MSYS2** terminal which comes with devkitARM. On other OS's, the built-in terminal should be perfectly adequate.
23 |
24 | :::
25 |
26 |
27 | ## Choosing a text editor {#sec-editor}
28 |
29 | A decent text editor is essential for programming. At the bare minimum you'll want something that supports syntax highlighting and gives you control over indentation and line endings. That means _notepad.exe_ sadly won't cut it.
30 |
31 | There are many options, and you may already have a favourite. But in case you don't, here are some suggestions:
32 |
33 | - [Visual Studio Code](https://code.visualstudio.com/) - a popular and featureful editor that works on Linux, Windows & Mac
34 |
35 | - [Kate](https://kate-editor.org/) - another powerful editor, a bit lighter and fully open-source
36 |
37 | - [Geany](https://www.geany.org/) - runs well on low-end machines and is still very extensible via plugins
38 |
39 | - [Notepad++](https://notepad-plus-plus.org/) - a lightweight and widely-loved choice on Windows
40 |
41 | Once you've chosen an editor and gotten comfortable with it, you can move onto the next section.
42 |
43 |
44 |
45 | {*@fig:text-editor}: Editing a file in VS Code.
46 |
47 |
48 | In many editors it's possible to set a hotkey (usually F5 or Ctrl+Enter) to compile and run your code. This can be an effective workflow, but for the purposes of this tutorial we'll use the command-line, because it's essential to know what's going on under the hood.
49 |
50 | Likewise, code-completion and error highlighting are also valuable features which you may want to spend time setting up, but are outside the scope of this chapter.
51 |
52 |
53 | ## Installing a GBA emulator {#sec-emu}
54 |
55 | Needless to say, you'll need a way to actually run your GBA programs. Testing on real hardware from time to time is highly recommended (and part of the fun), but for everyday development you'll want something more convenient. That's where emulators come in.
56 |
57 | At the time of writing, the most suitable emulator for GBA development is [mGBA](https://mgba.io/). It's highly accurate and has features for developers such as memory viewers, debug logging, and a GDB server for step debugging, all of which will make your life a lot easier when things go wrong (and they will)!
58 |
59 |
60 |
61 | {*@fig:mgba-game}: A GBA ROM running inside mGBA
62 |
63 |
64 | Other emulators which you might want to use are: [NanoBoyAdvance](https://github.com/nba-emu/NanoBoyAdvance) and [SkyEmu](https://github.com/skylersaleh/SkyEmu), which are both _cycle accurate_ and effectively the closest you can get to playing on real hardware without actually doing so.
65 |
66 | Finally [no$gba](https://problemkaputt.github.io/gba.htm) (debug version) is a somewhat older and less accurate Windows-only GBA emulator, but has some unique debugging features you won't find elsewhere. Namely a visual debugger, performance profiler, CPU usage meters, and memory access checking which can catch buffer overflows and such. If you can get it working, it's an invaluable tool!
67 |
68 |
69 | ## Installing devkitARM {#sec-dkp}
70 |
71 | devkitARM has been the standard toolchain for GBA homebrew for many years. It is provided by a team called devkitPro (dkP), though informally the tools are often referred to as devkitPro too (much to the maintainers' lament).
72 |
73 | To install devkitARM, visit the [devkitPro Getting Started](https://devkitpro.org/wiki/Getting_Started) page and follow the instructions for your OS.
74 |
75 | :::danger Do not use spaces in paths
76 |
77 | devkitARM uses [`make`](https://en.wikipedia.org/wiki/Make_(software)) for building projects, which doesn't cope well with spaces in paths (such as `My Documents`). The reason for this is that `make` uses spaces as a separator between command-line options, but unlike e.g. shell scripts, it doesn't provide an adequate form of quoting/escaping, especially not when working with lists of filenames.
78 |
79 | :::
80 |
81 | ### Windows tips {#ssec-dkp-win}
82 |
83 | If you are on Windows, there is a GUI installer which downloads and installs the components automatically. Be sure to select "GBA Development" during installation, as shown in @fig:devkitpro.
84 |
85 |
86 |
87 | {*@fig:devkitpro}: Installing devkitARM with the GBA packages on Windows.
88 |
89 |
90 |
91 | ### Linux & Mac tips {#ssec-dkp-unix}
92 |
93 | If you are using Linux or Mac, after following the instructions on dkP's Getting Started page, you should install the `gba-dev` package group via `dkp-pacman` in your terminal _(or just `pacman` if you use Arch Linux)_. To do this, run the following command:
94 |
95 | ```sh
96 | sudo dkp-pacman -S gba-dev
97 | ```
98 |
99 | When asked which packages to install _("Enter a selection (default=all):")_ you should simply hit Enter to install everything in the entire `gba-dev` group.
100 |
101 |
102 | ## Obtaining Tonc's example code {#sec-examples}
103 |
104 | This tutorial comes with a [full set of examples](https://github.com/gbadev-org/libtonc-examples) to demonstrate the concepts taught in each chapter.
105 |
106 | Additionally, libtonc is the GBA programming library that accompanies Tonc, and is necessary to compile the examples. In the past, libtonc had to be downloaded separately and placed where your projects could find it. But nowadays it comes included as part of devkitARM. As long as you selected the `gba-dev` packages during installation, _you already have libtonc_.
107 |
108 | The bad news is devkitARM doesn't include the Tonc examples, so you still have to download those yourself. You can get them via _"Code -> Download Zip"_ on the repository page, or by using [git](https://git-scm.com/) in your terminal:
109 |
110 | ```sh
111 | git clone https://github.com/gbadev-org/libtonc-examples
112 | ```
113 |
114 |
115 |
116 | :::tip toolbox.h vs libtonc
117 |
118 | In the early chapters, we'll be building our own library called `toolbox.h` which replicates parts of libtonc for educational purposes. But for real-world usage, sticking to a more featureful, tried-and-tested library (such as libtonc itself) should be preferred.
119 |
120 | :::
121 |
122 |
123 | ## Compiling the examples {#sec-compile}
124 |
125 | To test your installation, let's try building one of the examples.
126 |
127 | In the terminal, navigate to the directory where one of the examples is located (let's say, the *hello* example) and run `make`:
128 |
129 | ```sh
130 | cd libtonc-examples/basic/hello
131 | make
132 | ```
133 |
134 | When invoked, `make` will build the project by following the rules in the file called _'Makefile'_ in the current working directory. Assuming this was successful, a `.gba` file will be produced, which you can run in your emulator of choice:
135 |
136 |
137 |
138 | {*@fig:mgba-hello}: One of the Tonc examples running in mGBA.
139 |
140 |
141 | If you've gotten this far, congratulations! You are now ready to start writing your own GBA programs.
142 |
143 | You can move onto the next chapter, or keep reading for more details.
144 |
145 |
146 | :::tip Setting environment variables
147 |
148 | If you get an error such as `Please set DEVKITPRO in your environment`, it means your environment variables aren't set properly. The solution to this differs between machines, but usually you want to edit a file called `.bashrc` in your home directory, and add the following lines to it:
149 |
150 | ```sh
151 | export DEVKITPRO=/opt/devkitpro
152 | export DEVKITARM=/opt/devkitpro/devkitARM
153 | export DEVKITPPC=/opt/devkitpro/devkitPPC
154 |
155 | export PATH=$DEVKITARM/bin:$DEVKITPRO/tools/bin:$PATH # optional
156 | ```
157 |
158 | The last line adds the compiler and related tools to your `PATH` environment variable, allowing you to use them directly in your terminal.
159 |
160 | This is optional, because the example makefiles also set `PATH` during the build process. But having the tools on hand is useful, and *required* if you want to follow along in the next section.
161 |
162 | After editing `.bashrc`, you will have to close and reopen your terminal to apply the changes. Or you can run `source ~/.bashrc` to persist these changes in the current shell.
163 |
164 | :::
165 |
166 |
167 | ## Manual steps to build a GBA ROM {#sec-build-steps}
168 |
169 | We've just seen how to compile a GBA program via `make`. Copying the makefile and using it for your own projects is absolutely encouraged! That said, it's valuable to know what's happening under the hood.
170 |
171 | Converting your C/C++/asm sources into a valid GBA ROM involves 4 steps, which can be seen in the output from running `make`:
172 |
173 | ```sh
174 | $ make
175 | hello.c # <--- invoke the compiler
176 | linking cartridge # <--- invoke the linker
177 | built ... hello.gba # <--- elf stripped
178 | ROM fixed! # <--- header fixed
179 | ```
180 |
181 | The steps are as follows:
182 |
183 | 1. **Compile/assemble the sources**. We turn the human readable C or C++ files (`.c`/`.cpp`) or assembly files (`.s`/`.asm`) to a binary format known as [object files](https://en.wikipedia.org/wiki/Object_code) (`.o`). There is one object file for each source file.
184 |
185 | The tool for this is called `arm-none-eabi-gcc`. Actually, this is just a front-end for the real compiler, but that's just details. The `arm-none-eabi-` here is a prefix which means this version of GCC produces machine code for bare-metal ARM platforms; other target platforms have different prefixes. Note that C++ uses `g++` instead of `gcc`.
186 |
187 | 2. **Link the object files**. After that, the separate object files are linked into a single executable [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) file. Any precompiled code libraries (`.a`) you may have specified are linked at this stage too.
188 |
189 | You can actually compile and link at the same time, but it is good practice to keep them separate: serious projects usually contain multiple source files and you don't want to have to wait for the whole world to recompile when you only changed one. This becomes even more important when you start adding data (graphics, music, etc).
190 |
191 | Again, `arm-none-eabi-gcc` is used for invoking the linker, although the actual linker is called `arm-none-eabi-ld`.
192 |
193 | 3. **Strip to raw binary**. The ELF file still contains debug data and can't actually be read by the GBA (though many emulators will accept it). `arm-none-eabi-objcopy` removes the debug data and makes sure the GBA will accept it. Well, almost.
194 |
195 | 4. **Fix the header**. Each GBA game has a header with a checksum to make sure it's a valid GBA ROM. The linking step makes room for one, but leaves it blank, so we have to use a tool like DarkFader's `gbafix` to fix the header. This tool comes with devkitARM, so you don't have to download it separately.
196 |
197 |
198 | You can of course run all these commands in the terminal yourself without a makefile, provided the dkP tools are in your `PATH`.
199 |
200 | Let's try it with the example named *first* - this is the easiest one to compile because it doesn't depend on any libraries.
201 |
202 |
203 | ```sh
204 | cd libtonc-examples/basic/first/source
205 |
206 | # Compile first.c to first.o
207 | arm-none-eabi-gcc -mthumb -c first.c
208 |
209 | # Link first.o (and standard libs) to first.elf
210 | arm-none-eabi-gcc -specs=gba.specs -mthumb first.o -o first.elf
211 |
212 | # Strip to binary-only
213 | arm-none-eabi-objcopy -O binary first.elf first.gba
214 |
215 | # Fix header
216 | gbafix first.gba
217 | ```
218 |
219 | There you have it - a GBA program compiled from scratch! Well... we can always go deeper but this is probably a good place to stop for now. x)
220 |
221 | There are various options passed to the tools here that may not be immediately obvious. These are explained in the [makefile appendix](makefile.html#sec-flags) if you're interested.
222 |
223 |
224 | :::tip Avoid batch files for compiling
225 |
226 | You may be tempted to stick all these commands into a batch file or shell script, and use that to compile your project. This is simple, but not recommended.
227 |
228 | The reason becomes apparent as soon as your project has more than one source file: if you make an edit to a single file, you shouldn't have to recompile _all_ of the sources, only the one that changed. A build system such as `make` is smart enough to realise this, whereas simple shell scripts are not.
229 |
230 | When you get to the point where your project has dozens of source files, this makes a big difference!
231 |
232 | :::
233 |
234 | ## Alternative toolchains {#sec-alt}
235 |
236 | The advantage of devkitARM is that it provides a consistent environment for compiling GBA homebrew on Windows, Mac and Linux. However, if you're feeling adventurous there are other good options available nowadays:
237 |
238 | * [gba-toolchain](https://github.com/felixjones/gba-toolchain) - uses the CMake build system instead of Makefiles
239 | * [meson-gba](https://github.com/LunarLambda/meson-gba) - uses the Meson build system instead of Makefiles
240 | * [gba-bootstrap](https://github.com/AntonioND/gba-bootstrap) - the bare minimum needed to compile a GBA program. In other words, _roll your own toolchain_, with the hard bits done for you.
241 |
242 | Why would you want to use these? They might be easier to install (many Linux distros offer their own builds of `arm-none-eabi-gcc` and related packages, which is essentially the same thing devkitARM provides), or you could be using a machine for which devkitARM is not available (such as a Raspberry Pi). Or perhaps you just want a better build system than makefiles.
243 |
244 | Tonc assumes you're using devkitARM, but most of the information is relevant no matter which toolchain you're using.
245 |
246 |
247 | :::danger Avoid 'devkitAdvance'
248 |
249 | You may encounter a toolchain called _devkitAdvance_. This is an ancient toolchain which hasn't been updated since 2003. By using it, you will be missing out on _two decades worth_ of compiler improvements and optimisations. If somebody recommends this to you, run away!
250 |
251 | :::
252 |
--------------------------------------------------------------------------------
/content/timers.md:
--------------------------------------------------------------------------------
1 | # 15. Timers
2 |
3 |
4 |
5 | ## Timing is everything {#sec-intro}
6 |
7 | Think of every time you've heard a joke ruined because the punch line came too late or too early; think of all the failed jumps in Super Mario Bros (or any other platform game); all the occasions that you skidded at the start of a Mario Kart race for revving too soon; that your invincibility wore off just *before* you got a red shell up your a\[censored\]s; that you didn't quite dodge that hail of bullets in old-skool shooters because of a sudden slow-down. Think of all this and situations like them and you'll agree that in games, as in life, Timing Is Everything.
8 |
9 | Ironically, tim*ers* are of less importance. Throughout video-game history programmers have built their games around one timing mechanism: the vertical refresh rate of the screen. In other words, the VBlank. This is a machine-oriented timer (you count frames) rather than a human-oriented one (where you'd count seconds). For consoles, this works very well as the hardware is always the same. (Except, of course, that some countries use NTSC televisions (@ 60 Hz) and others use PAL TVs (@ 50 Hz). Everyone living in the latter category and has access to both kinds knows the difference and curses the fact that it's the NTSC countries that most games stem from.) While the VBlank timer is pervasive, it is not the only one. The GBA has four clock timers at your disposal. This section covers these timers.
10 |
11 | ## GBA Timers {#sec-tmr}
12 |
13 | All conceivable timers work in pretty much the same way. You have something that oscillates with a certain fixed frequency (like a CPU clock or the swing of a pendulum). After every full period, a counter is incremented and you have yourself a timer. Easy, innit?
14 |
15 | The basic frequency of the GBA timers is the CPU frequency, which is 224 ≈ 16.78 Mhz. In other words, one clock cycle of the CPU takes 2−24 ≈ 59.6 ns. Since this is a very lousy timescale for us humans, the GBA allows for 4 different frequencies (or, rather periods): 1, 64, 256 and 1024 cycles. Some details of these frequencies are shown in {@tbl:tmr-freq}. By clever use of the timer registers, you can actually create timers of any frequency, but more on that later. It should be noted that the screen refreshes every 280,896 cycles, exactly.
16 |
17 |
18 |
19 |
20 | {*@tbl:tmr-freq}: Timer frequencies
21 |
22 |
23 |
#cycles
frequency
period
24 |
1
16.78 MHz
59.59 ns
25 |
64
262.21 kHz
3.815 μs
26 |
256
65.536 kHz
15.26 μs
27 |
1024
16.384 kHz
61.04 μs
28 |
29 |
30 |
31 | ### Timer registers {#ssec-tmr-regs}
32 |
33 | The GBA has four timers, timers 0 to 3. Each of these has two registers: a data register (`REG_TMxD`) and a control register (`REG_TMxCNT`). The addresses can be found in {@tbl:tmr-reg}.
34 |
35 |
Timer frequency. 0-3 for 1, 64, 256, or 1024 cycles,
76 | respectively. y in the define is the number of
77 | cycles.
78 |
79 |
2
CM
80 |
TM_CASCADE
81 |
Cascade mode. When the counter of the preceding
82 | (x−1) timer overflows (REG_TM(x-1)D=
83 | 0xffff), this one will be incremented too. A timer that
84 | has this bit set does not count on its own, though you
85 | still have to enable it. Obviously, this won't work for timer 0.
86 | If you plan on using it make sure you understand exactly what I
87 | just said; this place is a death-trap for the unwary.
88 |
89 |
6
I
90 |
TM_IRQ
91 |
Raise an interrupt on overflow.
92 |
93 |
7
En
94 |
TM_ENABLE
95 |
Enable the timer.
96 |
97 |
98 |
99 |
100 | ### REG_TMxD {#ssec-reg-tmxd}
101 |
102 | The data register `REG_TMxD` is a 16-bit number that works a little bit differently than you might expect at first, but in the end it makes sense. The number that you **read** from the register is the **current** timer-count. So far, so good. However, the number that you **write** to `REG_TMxD` is the **initial value** that the counter begins at when the timer is either enabled (via `TM_ENABLE`) or overflows. This has number of ‘interesting’ consequences. To make things a little easier, define variables *n* of the initial value (the write-number) and *c* for the current count (the read number).
103 |
104 | First of all, when you set an *n* (of, say, `c000h`) like this:
105 |
106 | ```c
107 | REG_TM2D= 0xc000;
108 | ```
109 |
110 | you will *not* have set the current timer-count *c* to *n* (=`c000h`). In fact, if the timer is disabled, then *c*= 0. However, as soon as you do enable the counter, then *c = n* and proceeds from there. And when the timer overflows, it will reset to this value as well. By the way, because *n* is only the starting value it is important to set *n* first, and enable the timer afterwards.
111 |
112 | Secondly, ask yourself this: what happens when you disable the timer again? Well, the counter retains its current value. However, when you *enable* it afterwards, *c* will reset to *n* again. This is a bit of a drag if you want to disable the timer for a while (during a game-pause for instance) and then pick up where it left of. Well, yeah, but there is a way to make it happen. How? By turning it into a cascade timer via `TM_CASCADE`! Having that bit set in the `REG_TMxCNT` will cause the timer to be increased only when the preceding one overflows. If you prevent that from ever happening (if it's disabled for instance) then you will have effectively disabled your timer.
113 |
114 | Lastly, given a certain *n*, then the timer will overflow after *T*= `10000h`−*n* increments. Or, thanks to the wonders of two's complement, just *T*= −*n*. Combined with a cascade timer (or interrupts) you can build timers of any frequency, which is what you want from a timer.
115 |
116 | :::warning Writing to REG_TMxD is weird
117 |
118 | Writing into REG_TMxD may not do what you think it does. It does *not* set the timer value. Rather, it sets the *initial* value for the next timer run.
119 |
120 | :::
121 |
122 | ## Timer demo : like clockwork {#sec-demo}
123 |
124 | In today's demo, I'm going to show how to make a simple digital clock with the timers. To do this, we'll need a 1 Hz timer. As that's not available directly, I'm going to set up a cascading timer system with timers 2 and 3. Timer 3 will be set to cascade mode, which is updated when timer 2 overflows. It is possible to set the overflow to happen at a frequency of exactly one Hertz. The clock frequency is 224, or 1024\*0x4000. By setting timer 2 to `TM_FREQ_1024` and to start at −0x4000, the cascading timer 3 will effectively be a 1 Hz counter.
125 |
126 |
131 |
132 | Whenever timer 3 is updated, the demo turns the number of seconds into hours, minutes and seconds and prints that on screen (see {@fig:tmr-demo}). Yes, I am using divisions and moduli here because it is the simplest procedure and I can spare the cycles in this particular demo.
133 |
134 | The demo can be (un)paused with Select and Start. Start disables timer 2, and thus timer 3 too. Select turns timer 2 into a cascade timer as well, and since timer 1 is disabled, doing this also stops timer 2 (and 3). The difference is what happens when you unpause. By disabling a timer, it will start again at the initial value; but stopping it with a cascade actually keeps the timer active and it will simply resume counting once the cascade is removed. The difference is a subtle one, but the latter is more appropriate.
135 |
136 | ```c
137 | // Using a the "Berk" font from headspins font collection.
138 |
139 | #include
140 | #include
141 | #include "berk.h"
142 |
143 | void tmr_test()
144 | {
145 | // Overflow every ~1 second:
146 | // 0x4000 ticks @ FREQ_1024
147 |
148 | REG_TM2D= -0x4000; // 0x4000 ticks till overflow
149 | REG_TM2CNT= TM_FREQ_1024; // we're using the 1024 cycle timer
150 |
151 | // cascade into tm3
152 | REG_TM3CNT= TM_ENABLE | TM_CASCADE;
153 |
154 | u32 sec= -1;
155 |
156 | while(1)
157 | {
158 | vid_vsync();
159 | key_poll();
160 |
161 | if(REG_TM3D != sec)
162 | {
163 | sec= REG_TM3D;
164 | tte_printf("#{es;P:24,60}%02d:%02d:%02d",
165 | sec/3600, (sec%3600)/60, sec%60);
166 | }
167 |
168 | if(key_hit(KEY_START)) // pause by disabling timer
169 | REG_TM2CNT ^= TM_ENABLE;
170 |
171 | if(key_hit(KEY_SELECT)) // pause by enabling cascade
172 | REG_TM2CNT ^= TM_CASCADE;
173 | }
174 | }
175 |
176 | int main()
177 | {
178 | // set-up berk font
179 | tte_init_se(0, BG_CBB(0)|BG_SBB(31), 1, 0, 0, &berkFont, se_drawg);
180 | tte_init_con();
181 | memcpy16(pal_bg_mem, berkPal, berkPalLen/4);
182 |
183 | REG_DISPCNT= DCNT_MODE0 | DCNT_BG0;
184 |
185 | tmr_test();
186 |
187 | return 0;
188 | }
189 | ```
190 |
191 | This was a rather simple use of timers. Of course, I could have just as easily used the VBlank to keep track of the seconds, which is how it's usually done anyway. The hardware timers are usually reserved for timed DMA's, which are used in [sound mixers](https://stuij.github.io/deku-sound-tutorial/g), not for game timers. There is one other use that comes to mind, though, namely profiling: examining how fast your functions are. One of the [text system demos](text.html#ssec-demo-se2) uses that to check the speeds of a few copying routines.
192 |
--------------------------------------------------------------------------------
/content/toc.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Contents
11 |
12 |
13 |
14 |
249 | Tonc v1.4 is final. Yeah, I said that about v1.0 as well, but this
250 | time I mean it. Really. Honest. Cross my heart and hope to die, etc,
251 | etc.
252 | Well … barring minor errata, this will be
253 | final. Honest, cross my heart, yadda yadda yadda.
254 |
255 |
256 |
257 |
258 |
259 |
--------------------------------------------------------------------------------
/maintainer/PORTING_TO_MARKDOWN.md:
--------------------------------------------------------------------------------
1 |
2 | ## Converting pages to markdown
3 |
4 | Conversion can be done one page at a time.
5 |
6 | You can use `pandoc` to get you started:
7 |
8 | ### 1. Initial conversion
9 |
10 | ```sh
11 | cd content
12 |
13 | # rename to avoid conflicts in page generation
14 | mv intro.htm intro-old.htm
15 |
16 | # run through pandoc (minus some extensions to get sane output)
17 | pandoc --from=html --to=markdown-fenced_divs-bracketed_spans-escaped_line_breaks-smart --wrap=none -o intro.md intro-old.htm
18 | ```
19 |
20 | Then replace the table of contents with a `` marker:
21 |
22 | ```md
23 | # ii. Introduction to Tonc
24 |
25 |
26 | ```
27 |
28 | Add a link from `SUMMARY.md` to the new markdown file to add it to the table of contents.
29 |
30 | ### 2. Cleanup
31 |
32 | Next, go through the page and fix anything that's broken.
33 |
34 | For example:
35 |
36 | * Change `` back to `` (for some reason pandoc messes this up). Same goes for `` and some other tags.
37 |
38 | ```
39 | sed -i '' -E 's,([^<]+),\1,g' pagename.md
40 | ```
41 |
42 | * Remove section numbers from headings (but the number in the page title should stay, e.g. `# 3. My first GBA demo`)
43 |
44 | ```
45 | sed -i '' -E 's,^(##+) [0-9]+\.[0-9.]+,\1,g' pagename.md
46 | # For appendices, do this instead:
47 | sed -i '' -E 's,^(##+) [A-G]\.[0-9.]+,\1,g' pagename.md
48 | ```
49 |
50 | * Replace Tables and Figures with the raw HTML from the `-old.htm` file.
51 |
52 | * Equations are coded in MathML, which displays in all browsers since 2023 according to [Can I use](https://caniuse.com/mathml).
53 | It's recommended to write equations in LaTeX first, using a live preview tool such as [Online LaTeX Equation Editor](https://latexeditor.lagrida.com/).
54 | Right-click the preview and choose Copy to Clipboard > MathML Code.
55 |
56 | * Set the correct language on each code block (`c`, `asm`, `sh`, `makefile`)
57 |
58 | * Use backticks (`` ` ``) around code keywords and italics (`*`) around file names in the text.
59 |
60 | * Container tags need empty lines after them, otherwise the Markdown within won't be rendered properly. For example:
61 |
62 | ```html
63 |
64 |
65 | ...
66 |
67 |
68 |
69 |
70 | ...
71 |
72 | ```
73 |
74 | * The `target` attribute should be removed from links:
75 |
76 | ```
77 | sed -i 's/{target="_blank"}//g' pagename.md
78 | ```
79 |
80 | * Image links with a `{#id}` attribute need to be converted to `` tags:
81 |
82 | (vim substitute command)
83 | ```
84 | %s$!\[\(.\{-}\)\](\(.\{-}\)){\s*#\(.\{-}\)\s*}\s*$$g
85 | ```
86 |
87 | Once it's in good shape, you can delete the original .htm file.
88 |
89 | ### 3. Figures, tables, equations
90 |
91 | For autonumbering and cross-referencing of figures, tables and equations, we use a syntax based on [pandoc-xnos](https://github.com/tomduck/pandoc-xnos).
92 |
93 |
94 | * The `id` attribute is used to define a figure, e.g. `id="fig:foobar"` or `{#fig:foobar}`.
95 |
96 | * Possible ID kinds are `fig:`, `tbl:` and `eq:` to define figures, tables, and equations respectively.
97 |
98 | * Use `@fig:foobar` to refer to a figure.
99 |
100 | * Use `*@fig:foobar` when the first letter should be capitalised.
101 |
102 | * Use `!@fig:foobar` to print only the number (without the word 'fig').
103 |
104 | * Use `{@fig:foobar}` to avoid clashing with surrounding syntax.
105 |
106 | * The figure/table/equation prefix is defined by the page title.
107 |
108 |
109 | For example, on the page *'ii. Introduction to Tonc'*, the following Markdown:
110 |
111 | ```html
112 |
113 | **{*@fig:toncdirs}**: directories.
114 | ```
115 |
116 | Will be rendered as:
117 |
118 |
119 |
120 |
121 |
122 |
123 | Fig ii.1: directories.
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/mdbook-xnos/mdbook-xnos.py:
--------------------------------------------------------------------------------
1 | import json
2 | import re
3 | import sys
4 |
5 | r_prefix = re.compile(r'^# (\w+\.)', flags=re.MULTILINE)
6 | # XXX: mdBook doesn't support attributes on arbitrary elements
7 | # r_def1 = re.compile(r'#(fig|tbl|eq|sec):([\w-]+)') # Matches #fig:foo
8 | r_def2 = re.compile(r'id="(fig|tbl|eq|sec):([\w-]+)"') # Matches id="fig:foo"
9 | r_ref1 = re.compile(r'\\?([!+*]?)@(fig|tbl|eq|sec):([\w-]+)') # Matches @fig:foo
10 | # XXX: mdBook seems to escape bare *
11 | r_ref2 = re.compile(r'{\\?([!+*]?)@(fig|tbl|eq|sec):([\w-]+)}') # Matches {@fig:foo}
12 |
13 | def run(section):
14 | # Other book item (part title or separator)
15 | if 'Chapter' not in section:
16 | return
17 |
18 | content = section['Chapter']['content']
19 |
20 | prefix = ''
21 |
22 | if section['Chapter']['number'] == None:
23 | m = r_prefix.search(content)
24 | if m != None:
25 | prefix = m.group(1)
26 | else:
27 | prefix = str(section['Chapter']['number'][0]) + '.'
28 |
29 | counts = { 'fig': 0, 'tbl': 0, 'eq': 0, 'sec': 0 }
30 |
31 | id_to_num = {}
32 |
33 | def add_id(match):
34 | kind = match.group(1)
35 | id = (kind + ':' + match.group(2))
36 | counts[kind] += 1
37 | id_to_num[id] = prefix + str(counts[kind])
38 |
39 | # for match in r_def1.finditer(content): add_id(match)
40 | for match in r_def2.finditer(content): add_id(match)
41 |
42 | plus_names = { 'fig': 'fig', 'tbl': 'table', 'eq': 'eq', 'sec': 'section' }
43 | star_names = { 'fig': 'Fig', 'tbl': 'Table', 'eq': 'Eq', 'sec': 'Section' }
44 |
45 | clever_refs = True
46 | clever_names = plus_names
47 |
48 | def replacefigs(match):
49 | op = match.group(1)
50 | kind = match.group(2)
51 | id = (kind + ':' + match.group(3))
52 | if id in id_to_num:
53 | num = id_to_num[id]
54 | if clever_refs:
55 | if op == '!': return num
56 | elif op == '+': return plus_names[kind] + ' ' + num
57 | elif op == '*': return star_names[kind] + ' ' + num
58 | else: return clever_names[kind] + ' ' + num
59 | else:
60 | if op == '+': return plus_names[kind] + ' ' + num
61 | elif op == '*': return star_names[kind] + ' ' + num
62 | else: return num
63 | else:
64 | return match.group(0) # fallback, don't do any replacement
65 |
66 | # XXX: dead code in original xnos.py?
67 | # return id_to_num.get(id, fallback)
68 |
69 | content = r_ref2.sub(replacefigs, content)
70 | content = r_ref1.sub(replacefigs, content)
71 |
72 | section['Chapter']['content'] = content
73 |
74 | if __name__ == '__main__':
75 | if len(sys.argv) > 1: # we check if we received any argument
76 | if sys.argv[1] == "supports":
77 | # then we are good to return an exit status code of 0, since the other argument will just be the renderer's name
78 | sys.exit(0)
79 |
80 | # load both the context and the book representations from stdin
81 | context, book = json.load(sys.stdin)
82 |
83 | for chapter in book['sections']:
84 | run(chapter)
85 |
86 | print(json.dumps(book))
87 |
--------------------------------------------------------------------------------
/preproc/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "pandocs-preproc"
3 | version = "0.1.0"
4 | authors = ["ISSOtm "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | anyhow = "1.0.42"
11 | clap = "2.33.3"
12 | lazy_static = "1.4.0"
13 | # mdbook here is only used as a lib, so no need for the extra features
14 | mdbook = { version = "0.4.8", default-features = false }
15 | pulldown-cmark = "0.8.0"
16 | pulldown-cmark-to-cmark = "6.0.1"
17 | regex = "1.5.4"
18 | serde_json = "1.0.59"
19 | termcolor = "1.1.2"
20 |
--------------------------------------------------------------------------------
/preproc/src/admonitions.rs:
--------------------------------------------------------------------------------
1 | /*
2 | * Adapted from gbdev's Pan Docs preprocessor
3 | * https://github.com/gbdev/pandocs/blob/master/preproc/src/admonitions.rs
4 | *
5 | * This Source Code Form is subject to the
6 | * terms of the Mozilla Public License, v.
7 | * 2.0. If a copy of the MPL was not
8 | * distributed with this file, You can
9 | * obtain one at
10 | * http://mozilla.org/MPL/2.0/.
11 | */
12 |
13 | use std::{iter::Peekable, matches};
14 |
15 | use anyhow::Error;
16 | use mdbook::book::Chapter;
17 | use pulldown_cmark::{Event, Options, Parser, Tag};
18 |
19 | use crate::Pandocs;
20 |
21 | impl Pandocs {
22 | pub fn process_admonitions(&self, chapter: &mut Chapter) -> Result<(), Error> {
23 | let mut buf = String::with_capacity(chapter.content.len());
24 | let extensions =
25 | Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH;
26 |
27 | let events = AdmonitionsGenerator::new(Parser::new_ext(&chapter.content, extensions));
28 |
29 | pulldown_cmark_to_cmark::cmark(events, &mut buf, None)
30 | .map_err(|err| Error::from(err).context("Markdown serialization failed"))?;
31 | chapter.content = buf;
32 |
33 | Ok(())
34 | }
35 | }
36 |
37 | struct AdmonitionsGenerator<'a, Iter: Iterator>> {
38 | iter: Peekable,
39 | nesting_level: usize,
40 | at_paragraph_start: bool,
41 | }
42 |
43 | impl<'a, Iter: Iterator>> AdmonitionsGenerator<'a, Iter> {
44 | const KINDS: [&'static str; 4] = ["note", "tip", "warning", "danger"];
45 |
46 | fn new(iter: Iter) -> Self {
47 | Self {
48 | iter: iter.peekable(),
49 | nesting_level: 0,
50 | at_paragraph_start: false,
51 | }
52 | }
53 | }
54 |
55 | impl<'a, Iter: Iterator>> Iterator for AdmonitionsGenerator<'a, Iter> {
56 | type Item = Event<'a>;
57 |
58 | fn next(&mut self) -> Option {
59 | let mut evt = self.iter.next()?;
60 |
61 | match evt {
62 | Event::Text(ref text) if self.at_paragraph_start => {
63 | if let Some(params) = text.strip_prefix(":::") {
64 | // Check that there is no more text in the paragraph; if there isn't, we'll consume the entire paragraph.
65 | // Note that this intentionally rejects any formatting within the paragraph—serialisation would be too complex.
66 | if matches!(self.iter.peek(), Some(Event::End(Tag::Paragraph))) {
67 | if params.is_empty() {
68 | if self.nesting_level != 0 {
69 | // Ending an admonition.
70 | self.nesting_level -= 1;
71 |
72 | evt = Event::Html("".into());
73 | }
74 | } else {
75 | let (kind, title) =
76 | match params.split_once(|c: char| c.is_ascii_whitespace()) {
77 | Some((kind, title)) => (kind, title.trim()),
78 | None => (params, ""),
79 | };
80 | if Self::KINDS.contains(&kind) {
81 | // Beginning an admonition.
82 | self.nesting_level += 1;
83 |
84 | evt = Event::Html(
85 | if title.is_empty() {
86 | format!("