mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-24 11:11:31 +11:00
647 lines
39 KiB
HTML
647 lines
39 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="sidebar-visible no-js">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title>Rust GBA Guide</title>
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
|
<meta name="description" content="">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="theme-color" content="#ffffff" />
|
|
|
|
<link rel="shortcut icon" href="favicon.png">
|
|
<link rel="stylesheet" href="css/variables.css">
|
|
<link rel="stylesheet" href="css/general.css">
|
|
<link rel="stylesheet" href="css/chrome.css">
|
|
<link rel="stylesheet" href="css/print.css" media="print">
|
|
|
|
<!-- Fonts -->
|
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
|
|
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
|
|
|
|
<!-- Highlight.js Stylesheets -->
|
|
<link rel="stylesheet" href="highlight.css">
|
|
<link rel="stylesheet" href="tomorrow-night.css">
|
|
<link rel="stylesheet" href="ayu-highlight.css">
|
|
|
|
<!-- Custom theme stylesheets -->
|
|
|
|
|
|
|
|
</head>
|
|
<body class="light">
|
|
<!-- Provide site root to javascript -->
|
|
<script type="text/javascript">var path_to_root = "";</script>
|
|
|
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
<script type="text/javascript">
|
|
try {
|
|
var theme = localStorage.getItem('mdbook-theme');
|
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
|
|
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
}
|
|
|
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
}
|
|
} catch (e) { }
|
|
</script>
|
|
|
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
<script type="text/javascript">
|
|
var theme;
|
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
if (theme === null || theme === undefined) { theme = 'light'; }
|
|
document.body.className = theme;
|
|
document.querySelector('html').className = theme + ' js';
|
|
</script>
|
|
|
|
<!-- Hide / unhide sidebar before it is displayed -->
|
|
<script type="text/javascript">
|
|
var html = document.querySelector('html');
|
|
var sidebar = 'hidden';
|
|
if (document.body.clientWidth >= 1080) {
|
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
sidebar = sidebar || 'visible';
|
|
}
|
|
html.classList.remove('sidebar-visible');
|
|
html.classList.add("sidebar-" + sidebar);
|
|
</script>
|
|
|
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
<ol class="chapter"><li><a href="00-introduction/00-index.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><ol class="section"><li><a href="00-introduction/01-requirements.html"><strong aria-hidden="true">1.1.</strong> Reader Requirements</a></li><li><a href="00-introduction/02-goals_and_style.html"><strong aria-hidden="true">1.2.</strong> Book Goals and Style</a></li><li><a href="00-introduction/03-development-setup.html"><strong aria-hidden="true">1.3.</strong> Development Setup</a></li><li><a href="00-introduction/04-hello-magic.html"><strong aria-hidden="true">1.4.</strong> Hello, Magic</a></li><li><a href="00-introduction/05-newtype.html"><strong aria-hidden="true">1.5.</strong> Newtype</a></li><li><a href="00-introduction/06-help_and_resources.html"><strong aria-hidden="true">1.6.</strong> Help and Resources</a></li></ol></li><li><a href="01-limitations/00-index.html"><strong aria-hidden="true">2.</strong> Limitations</a></li><li><ol class="section"><li><a href="01-limitations/01-no_floats.html"><strong aria-hidden="true">2.1.</strong> No Floats</a></li><li><a href="01-limitations/02-core_only.html"><strong aria-hidden="true">2.2.</strong> Core Only</a></li><li><a href="01-limitations/03-volatile_destination.html"><strong aria-hidden="true">2.3.</strong> Volatile Destination</a></li></ol></li><li><a href="02-concepts/00-index.html"><strong aria-hidden="true">3.</strong> Concepts</a></li><li><ol class="section"><li><a href="02-concepts/01-cpu.html"><strong aria-hidden="true">3.1.</strong> CPU</a></li><li><a href="02-concepts/02-bios.html"><strong aria-hidden="true">3.2.</strong> BIOS</a></li><li><a href="02-concepts/03-wram.html"><strong aria-hidden="true">3.3.</strong> Work RAM</a></li><li><a href="02-concepts/04-io-registers.html"><strong aria-hidden="true">3.4.</strong> IO Registers</a></li><li><a href="02-concepts/05-palram.html"><strong aria-hidden="true">3.5.</strong> Palette RAM</a></li><li><a href="02-concepts/06-vram.html"><strong aria-hidden="true">3.6.</strong> Video RAM</a></li><li><a href="02-concepts/07-oam.html"><strong aria-hidden="true">3.7.</strong> Object Attribute Memory</a></li><li><a href="02-concepts/08-rom.html"><strong aria-hidden="true">3.8.</strong> Game Pak ROM / Flash ROM</a></li><li><a href="02-concepts/09-sram.html"><strong aria-hidden="true">3.9.</strong> Save RAM</a></li></ol></li><li><a href="03-video/00-index.html"><strong aria-hidden="true">4.</strong> Video</a></li><li><ol class="section"><li><a href="03-video/01-rgb15.html"><strong aria-hidden="true">4.1.</strong> RBG15 Color</a></li><li><a href="03-video/TODO.html"><strong aria-hidden="true">4.2.</strong> TODO</a></li></ol></li><li><a href="04-non-video/00-index.html"><strong aria-hidden="true">5.</strong> Non-Video</a></li><li><ol class="section"><li><a href="04-non-video/01-buttons.html"><strong aria-hidden="true">5.1.</strong> Buttons</a></li><li><a href="04-non-video/02-timers.html"><strong aria-hidden="true">5.2.</strong> Timers</a></li><li><a href="04-non-video/03-dma.html"><strong aria-hidden="true">5.3.</strong> Direct Memory Access</a></li><li><a href="04-non-video/04-sound.html"><strong aria-hidden="true">5.4.</strong> Sound</a></li><li><a href="04-non-video/05-interrupts.html"><strong aria-hidden="true">5.5.</strong> Interrupts</a></li><li><a href="04-non-video/06-network.html"><strong aria-hidden="true">5.6.</strong> Network</a></li><li><a href="04-non-video/07-game_pak.html"><strong aria-hidden="true">5.7.</strong> Game Pak</a></li></ol></li><li><a href="05-examples/00-index.html"><strong aria-hidden="true">6.</strong> Examples</a></li><li><ol class="section"><li><a href="05-examples/01-hello_magic.html"><strong aria-hidden="true">6.1.</strong> hello_magic</a></li><li><a href="05-examples/02-hello_world.html"><strong aria-hidden="true">6.2.</strong> hello_world</a></li><li><a href="05-examples/03-light_cycle.html"><strong aria-hidden="true">6.3.</strong> light_cycle</a></li><li><a href="05-examples/04-bg_demo.html"><strong aria-hidden="true">6.4.</strong> bg_demo</a></li></ol></li></ol>
|
|
</nav>
|
|
|
|
<div id="page-wrapper" class="page-wrapper">
|
|
|
|
<div class="page">
|
|
|
|
<div id="menu-bar" class="menu-bar">
|
|
<div id="menu-bar-sticky-container">
|
|
<div class="left-buttons">
|
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
<i class="fa fa-bars"></i>
|
|
</button>
|
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
<i class="fa fa-paint-brush"></i>
|
|
</button>
|
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
<li role="none"><button role="menuitem" class="theme" id="light">Light <span class="default">(default)</span></button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
</ul>
|
|
|
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<h1 class="menu-title">Rust GBA Guide</h1>
|
|
|
|
<div class="right-buttons">
|
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
|
<i id="print-button" class="fa fa-print"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div id="search-wrapper" class="hidden">
|
|
<form id="searchbar-outer" class="searchbar-outer">
|
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
</form>
|
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
<div id="searchresults-header" class="searchresults-header"></div>
|
|
<ul id="searchresults">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
<script type="text/javascript">
|
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
});
|
|
</script>
|
|
|
|
<div id="content" class="content">
|
|
<main>
|
|
<a class="header" href="#introduction" id="introduction"><h1>Introduction</h1></a>
|
|
<p>This is the book for learning how to write GBA games in Rust.</p>
|
|
<p>I'm <strong>Lokathor</strong>, the main author of the book. There's also <strong>Ketsuban</strong> who
|
|
provides the technical advisement, reviews the PRs, and keeps my crazy in check.</p>
|
|
<p>The book is a work in progress, as you can see if you actually try to open many
|
|
of the pages listed in the Table Of Contents.</p>
|
|
<a class="header" href="#feedback" id="feedback"><h2>Feedback</h2></a>
|
|
<p>It's also often hard to tell when you've explained something properly to someone
|
|
who doesn't understand the concept yet. Please, if things don't make sense then
|
|
<a href="https://github.com/rust-console/gba/issues">file an issue</a> about it so I know
|
|
where things need to improve.</p>
|
|
<a class="header" href="#reader-requirements" id="reader-requirements"><h1>Reader Requirements</h1></a>
|
|
<p>This book naturally assumes that you've already read Rust's core book:</p>
|
|
<ul>
|
|
<li><a href="https://doc.rust-lang.org/book/">The Rust Programming Language</a></li>
|
|
</ul>
|
|
<p>Now, I <em>know</em> it sounds silly to say "if you wanna program Rust on this old
|
|
video game system you should already know how to program Rust", but the more
|
|
people I meet and chat with the more they tell me that they jumped into Rust
|
|
without reading any or all of the book. You know who you are.</p>
|
|
<p>Please, read the whole book!</p>
|
|
<p>In addition to the core book, there's also an expansion book that I will declare
|
|
to be required reading for this:</p>
|
|
<ul>
|
|
<li><a href="https://doc.rust-lang.org/nomicon/">The Rustonomicon</a></li>
|
|
</ul>
|
|
<p>The Rustonomicon is all about trying to demystify <code>unsafe</code>. We'll end up using a
|
|
fair bit of unsafe code as a natural consequence of doing direct hardware
|
|
manipulations. Using unsafe is like <a href="https://www.zeldadungeon.net/wp-content/uploads/2013/04/tumblr_mlkpzij6T81qizbpto1_1280.gif">swinging a
|
|
sword</a>,
|
|
you should start slowly, practice carefully, and always pay attention no matter
|
|
how experienced you think you've become.</p>
|
|
<p>That said, it's sometimes a <a href="https://www.youtube.com/watch?v=rTo2u13lVcQ">necessary
|
|
tool</a> to get the job done, so you
|
|
have to break out of the borderline pathological fear of using it that most rust
|
|
programmers tend to have.</p>
|
|
<a class="header" href="#book-goals-and-style" id="book-goals-and-style"><h1>Book Goals and Style</h1></a>
|
|
<p>So, what's this book actually gonna teach you?</p>
|
|
<p>I'm <em>not</em> gonna tell you how to use a crate that already exists.</p>
|
|
<p>Don't get me wrong, there <em>is</em> a <a href="https://crates.io/crates/gba">gba</a> crate, and
|
|
it's on crates.io and all that jazz.</p>
|
|
<p>However, unlike most crates that come with a tutorial book, I don't want to just
|
|
teach you how to use the crate. What I want is to teach you what you need to
|
|
know so that you could build the crate yourself, from scratch, if it didn't
|
|
already exist for you. Let's call it the <a href="https://handmadehero.org/">Handmade
|
|
Hero</a> school of design. Much more than you might find
|
|
in other Rust crate books, I'll be attempting to show a lot of the <em>why</em> in
|
|
addition to just the <em>how</em>. Once you know how to do it all on your own, you can
|
|
decide for yourself if the <code>gba</code> crate does it well, or if you think you can
|
|
come up with something that suits your needs better.</p>
|
|
<p>Overall the book is sorted for easy review once you're trying to program
|
|
something, and the GBA has a few interconnected concepts, so some parts of the
|
|
book end up having to refer you to portions that you haven't read yet. The
|
|
chapters and sections are sorted so that <em>minimal</em> future references are
|
|
required, but it's unavoidable.</p>
|
|
<p>The actual "tutorial order" of the book is the
|
|
<a href="../05-examples/00-index.html">Examples</a> chapter. Each section of that chapter
|
|
breaks down one of the provided examples in the <a href="https://github.com/rust-console/gba/tree/master/examples">examples
|
|
directory</a> of the
|
|
repository. We go over what sections of the book you'll need to have read for
|
|
the example code to make sense, and also how we apply the general concepts
|
|
described in the book to the specific example cases.</p>
|
|
<a class="header" href="#development-setup" id="development-setup"><h1>Development Setup</h1></a>
|
|
<p>Before you can build a GBA game you'll have to follow some special steps to
|
|
setup the development environment.</p>
|
|
<p>Once again, extra special thanks to <strong>Ketsuban</strong>, who first dove into how to
|
|
make this all work with rust and then shared it with the world.</p>
|
|
<a class="header" href="#per-system-setup" id="per-system-setup"><h2>Per System Setup</h2></a>
|
|
<p>Obviously you need your computer to have a <a href="https://rustup.rs/">working rust
|
|
installation</a>. However, you'll also need to ensure that
|
|
you're using a nightly toolchain (we will need it for inline assembly, among
|
|
other potential useful features). You can run <code>rustup default nightly</code> to set
|
|
nightly as the system wide default toolchain, or you can use a <a href="https://github.com/rust-lang-nursery/rustup.rs#the-toolchain-file">toolchain
|
|
file</a> to use
|
|
nightly just on a specific project, but either way we'll be assuming the use of
|
|
nightly from now on. You'll also need the <code>rust-src</code> component so that
|
|
<code>cargo-xbuild</code> will be able to compile the core crate for us in a bit, so run
|
|
<code>rustup component add rust-src</code>.</p>
|
|
<p>Next, you need <a href="https://devkitpro.org/wiki/Getting_Started">devkitpro</a>. They've
|
|
got a graphical installer for Windows that runs nicely, and I guess <code>pacman</code>
|
|
support on Linux (I'm on Windows so I haven't tried the Linux install myself).
|
|
We'll be using a few of their general binutils for the <code>arm-none-eabi</code> target,
|
|
and we'll also be using some of their tools that are specific to GBA
|
|
development, so <em>even if</em> you already have the right binutils for whatever
|
|
reason, you'll still want devkitpro for the <code>gbafix</code> utility.</p>
|
|
<ul>
|
|
<li>On Windows you'll want something like <code>C:\devkitpro\devkitARM\bin</code> and
|
|
<code>C:\devkitpro\tools\bin</code> to be <a href="https://stackoverflow.com/q/44272416/455232">added to your
|
|
PATH</a>, depending on where you
|
|
installed it to and such.</li>
|
|
<li>On Linux you can use pacman to get it, and the default install puts the stuff
|
|
in <code>/opt/devkitpro/devkitARM/bin</code> and <code>/opt/devkitpro/tools/bin</code>. If you need
|
|
help you can look in our repository's
|
|
<a href="https://github.com/rust-console/gba/blob/master/.travis.yml">.travis.yml</a>
|
|
file to see exactly what our CI does.</li>
|
|
</ul>
|
|
<p>Finally, you'll need <code>cargo-xbuild</code>. Just run <code>cargo install cargo-xbuild</code> and
|
|
cargo will figure it all out for you.</p>
|
|
<a class="header" href="#per-project-setup" id="per-project-setup"><h2>Per Project Setup</h2></a>
|
|
<p>Once the system wide tools are ready, you'll need some particular files each
|
|
time you want to start a new project. You can find them in the root of the
|
|
<a href="https://github.com/rust-console/gba">rust-console/gba repo</a>.</p>
|
|
<ul>
|
|
<li><code>thumbv4-none-agb.json</code> describes the overall GBA to cargo-xbuild (and LLVM)
|
|
so it knows what to do. Technically the GBA is <code>thumbv4-none-eabi</code>, but we
|
|
change the <code>eabi</code> to <code>agb</code> so that we can distinguish it from other <code>eabi</code>
|
|
devices when using <code>cfg</code> flags.</li>
|
|
<li><code>crt0.s</code> describes some ASM startup stuff. If you have more ASM to place here
|
|
later on this is where you can put it. You also need to build it into a
|
|
<code>crt0.o</code> file before it can actually be used, but we'll cover that below.</li>
|
|
<li><code>linker.ld</code> tells the linker all the critical info about the layout
|
|
expectations that the GBA has about our program, and that it should also
|
|
include the <code>crt0.o</code> file with our compiled rust code.</li>
|
|
</ul>
|
|
<a class="header" href="#compiling" id="compiling"><h2>Compiling</h2></a>
|
|
<p>Once all the tools are in place, there's particular steps that you need to
|
|
compile the project. For these to work you'll need some source code to compile.
|
|
Unlike with other things, an empty main file and/or an empty lib file will cause
|
|
a total build failure, because we'll need a
|
|
<a href="https://rust-embedded.github.io/book/intro/no-std.html">no_std</a> build, and rust
|
|
defaults to builds that use the standard library. The next section has a minimal
|
|
example file you can use (along with explanation), but we'll describe the build
|
|
steps here.</p>
|
|
<ul>
|
|
<li>
|
|
<p><code>arm-none-eabi-as crt0.s -o target/crt0.o</code></p>
|
|
<ul>
|
|
<li>This builds your text format <code>crt0.s</code> file into object format <code>crt0.o</code>
|
|
that's placed in the <code>target/</code> directory. Note that if the <code>target/</code>
|
|
directory doesn't exist yet it will fail, so you have to make the directory
|
|
if it's not there. You don't need to rebuild <code>crt0.s</code> every single time,
|
|
only when it changes, but you might as well throw a line to do it every time
|
|
into your build script so that you never forget because it's a practically
|
|
instant operation anyway.</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p><code>cargo xbuild --target thumbv4-none-agb.json</code></p>
|
|
<ul>
|
|
<li>This builds your Rust source. It accepts <em>most of</em> the normal options, such
|
|
as <code>--release</code>, and options, such as <code>--bin foo</code> or <code>--examples</code>, that you'd
|
|
expect <code>cargo</code> to accept.</li>
|
|
<li>You <strong>can not</strong> build and run tests this way, because they require <code>std</code>,
|
|
which the GBA doesn't have. If you want you can still run some of your
|
|
project's tests with <code>cargo test --lib</code> or similar, but that builds for your
|
|
local machine, so anything specific to the GBA (such as reading and writing
|
|
registers) won't be testable that way. If you want to isolate and try out
|
|
some piece code running on the GBA you'll unfortunately have to make a demo
|
|
for it in your <code>examples/</code> directory and then run the demo in an emulator
|
|
and see if it does what you expect.</li>
|
|
<li>The file extension is important! It will work if you forget it, but <code>cargo xbuild</code> takes the inclusion of the extension as a flag to also compile
|
|
dependencies with the same sysroot, so you can include other crates in your
|
|
build. Well, crates that work in the GBA's limited environment, but you get
|
|
the idea.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p>At this point you have an ELF binary that some emulators can execute directly
|
|
(more on that later). However, if you want a "real" ROM that works in all
|
|
emulators and that you could transfer to a flash cart to play on real hardware
|
|
there's a little more to do.</p>
|
|
<ul>
|
|
<li>
|
|
<p><code>arm-none-eabi-objcopy -O binary target/thumbv4-none-agb/MODE/BIN_NAME target/ROM_NAME.gba</code></p>
|
|
<ul>
|
|
<li>This will perform an <a href="https://linux.die.net/man/1/objcopy">objcopy</a> on our
|
|
program. Here I've named the program <code>arm-none-eabi-objcopy</code>, which is what
|
|
devkitpro calls their version of <code>objcopy</code> that's specific to the GBA in the
|
|
Windows install. If the program isn't found under that name, have a look in
|
|
your installation directory to see if it's under a slightly different name
|
|
or something.</li>
|
|
<li>As you can see from reading the man page, the <code>-O binary</code> option takes our
|
|
lovely ELF file with symbols and all that and strips it down to basically a
|
|
bare memory dump of the program.</li>
|
|
<li>The next argument is the input file. You might not be familiar with how
|
|
<code>cargo</code> arranges stuff in the <code>target/</code> directory, and between RLS and
|
|
<code>cargo doc</code> and stuff it gets kinda crowded, so it goes like this:
|
|
<ul>
|
|
<li>Since our program was built for a non-local target, first we've got a
|
|
directory named for that target, <code>thumbv4-none-agb/</code></li>
|
|
<li>Next, the "MODE" is either <code>debug/</code> or <code>release/</code>, depending on if we had
|
|
the <code>--release</code> flag included. You'll probably only be packing release
|
|
mode programs all the way into GBA roms, but it works with either mode.</li>
|
|
<li>Finally, the name of the program. If your program is something out of the
|
|
project's <code>src/bin/</code> then it'll be that file's name, or whatever name you
|
|
configured for the bin in the <code>Cargo.toml</code> file. If your program is
|
|
something out of the project's <code>examples/</code> directory there will be a
|
|
similar <code>examples/</code> sub-directory first, and then the example's name.</li>
|
|
</ul>
|
|
</li>
|
|
<li>The final argument is the output of the <code>objcopy</code>, which I suggest putting
|
|
at just the top level of the <code>target/</code> directory. Really it could go
|
|
anywhere, but if you're using git then it's likely that your <code>.gitignore</code>
|
|
file is already setup to exclude everything in <code>target/</code>, so this makes sure
|
|
that your intermediate game builds don't get checked into your git.</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p><code>gbafix target/ROM_NAME.gba</code></p>
|
|
<ul>
|
|
<li>The <code>gbafix</code> tool also comes from devkitpro. The GBA is very picky about a
|
|
ROM's format, and <code>gbafix</code> patches the ROM's header and such so that it'll
|
|
work right. Unlike <code>objcopy</code>, this tool is custom built for GBA development,
|
|
so it works just perfectly without any arguments beyond the file name. The
|
|
ROM is patched in place, so we don't even need to specify a new destination.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<p>And you're <em>finally</em> done!</p>
|
|
<p>Of course, you probably want to make a script for all that, but it's up to you.
|
|
On our own project we have it mostly set up within a <code>Makefile.toml</code> which runs
|
|
using the <a href="https://github.com/sagiegurari/cargo-make">cargo-make</a> plugin.</p>
|
|
<a class="header" href="#hello-magic" id="hello-magic"><h1>Hello, Magic</h1></a>
|
|
<p>So we know all the steps to build our source, we just need some source.</p>
|
|
<p>We're beginners, so we'll start small. With normal programming there's usually a
|
|
console available, so the minimal program prints "Hello, world" to the terminal.
|
|
On a GBA we don't have a terminal and standard out and all that, so the minimal
|
|
program draws a red, blue, and green dot to the screen.</p>
|
|
<p>At the lowest level of device programming, it's all <a href="https://en.wikipedia.org/wiki/Magic_number_(programming)">Magic
|
|
Numbers</a>. You write
|
|
special values to special places and then the hardware does something. A clear
|
|
API makes every magic number and magic location easy to understand. A clear <em>and
|
|
good</em> API also prevents you from using the wrong magic number in the wrong place
|
|
and causing problems for yourself.</p>
|
|
<p>This is the minimal example to just test that our build system is all set, so
|
|
just this once we'll go <em>full</em> magic number crazy town, for fun. Ready? Here
|
|
goes:</p>
|
|
<p><code>hello_magic.rs</code>:</p>
|
|
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
|
|
#![no_std]
|
|
|
|
#[panic_handler]
|
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
|
loop {}
|
|
}
|
|
|
|
#[start]
|
|
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
|
unsafe {
|
|
(0x400_0000 as *mut u16).write_volatile(0x0403);
|
|
(0x600_0000 as *mut u16).offset(120 + 80 * 240).write_volatile(0x001F);
|
|
(0x600_0000 as *mut u16).offset(136 + 80 * 240).write_volatile(0x03E0);
|
|
(0x600_0000 as *mut u16).offset(120 + 96 * 240).write_volatile(0x7C00);
|
|
loop {}
|
|
}
|
|
}
|
|
</code></pre></pre>
|
|
<p>Throw that into your project skeleton, build the program, and give it a run. You
|
|
should see a red, green, and blue dot close-ish to the middle of the screen. If
|
|
you don't, something <em>already</em> went wrong. Double check things, phone a friend,
|
|
write your senators, try asking <code>Lokathor</code> or <code>Ketsuban</code> on the <a href="https://discordapp.com/invite/aVESxV8">Rust Community
|
|
Discord</a>, until you're eventually able to
|
|
get your three dots going.</p>
|
|
<p>Of course, I'm sure you want to know why those numbers are the numbers to use.
|
|
Well that's what the whole rest of the book is about!</p>
|
|
<a class="header" href="#newtype" id="newtype"><h1>Newtype</h1></a>
|
|
<p>There's one thing I want to get out of the way near the start of the book and it
|
|
didn't really have a good fit anywhere else in the book so it goes right here.</p>
|
|
<p>We're talking about the "Newtype Pattern"!</p>
|
|
<p>Now, I told you to read the Rust Book before you read this book, and I'm sure
|
|
you're all good students who wouldn't sneak into this book without doing the
|
|
required reading, so I'm sure you all remember exactly what I'm talking about,
|
|
because they touch on the newtype concept in the book twice, in two <em>very</em> long
|
|
named sections:</p>
|
|
<ul>
|
|
<li><a href="https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types">Using the Newtype Pattern to Implement External Traits on External
|
|
Types</a></li>
|
|
<li><a href="https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction">Using the Newtype Pattern for Type Safety and
|
|
Abstraction</a></li>
|
|
</ul>
|
|
<p>...Yeah... The Rust Book doesn't know how to make a short sub-section name to
|
|
save its life. Shame.</p>
|
|
<a class="header" href="#newtype-basics" id="newtype-basics"><h2>Newtype Basics</h2></a>
|
|
<p>So, we have all these pieces of data, and we want to keep them separated, and we
|
|
don't wanna pay the cost for it at runtime. Well, we're in luck, we can pay the
|
|
cost at compile time.</p>
|
|
<pre><pre class="playpen"><code class="language-rust">
|
|
# #![allow(unused_variables)]
|
|
#fn main() {
|
|
pub struct PixelColor(u16);
|
|
#}</code></pre></pre>
|
|
<p>Ah, except that, as I'm sure you remember from <a href="https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent">The
|
|
Rustonomicon</a>
|
|
(and from <a href="https://github.com/rust-lang/rfcs/blob/master/text/1758-repr-transparent.md">the
|
|
RFC</a>
|
|
too, of course), if we have a single field struct that's sometimes different
|
|
from having just the bare value, so we should be using <code>#[repr(transparent)]</code>
|
|
with our newtypes.</p>
|
|
<pre><pre class="playpen"><code class="language-rust">
|
|
# #![allow(unused_variables)]
|
|
#fn main() {
|
|
#[repr(transparent)]
|
|
pub struct PixelColor(u16);
|
|
#}</code></pre></pre>
|
|
<p>Ah, and of course we'll need to make it so you can unwrap the value:</p>
|
|
<pre><pre class="playpen"><code class="language-rust">
|
|
# #![allow(unused_variables)]
|
|
#fn main() {
|
|
#[repr(transparent)]
|
|
pub struct PixelColor(u16);
|
|
|
|
impl From<PixelColor> for u16 {
|
|
fn from(color: PixelColor) -> u16 {
|
|
color.0
|
|
}
|
|
}
|
|
#}</code></pre></pre>
|
|
<p>And then we'll need to do that same thing for <em>every other newtype we want</em>.</p>
|
|
<p>Except there's only two tiny parts that actually differ between newtype
|
|
declarations: the new name and the base type. All the rest is just the same rote
|
|
code over and over. Generating piles and piles of boilerplate code? Sounds like
|
|
a job for a macro to me!</p>
|
|
<a class="header" href="#making-it-a-macro" id="making-it-a-macro"><h2>Making It A Macro</h2></a>
|
|
<p>The most basic version of the macro we want goes like this:</p>
|
|
<pre><pre class="playpen"><code class="language-rust">
|
|
# #![allow(unused_variables)]
|
|
#fn main() {
|
|
#[macro_export]
|
|
macro_rules! newtype {
|
|
($new_name:ident, $old_name:ident) => {
|
|
#[repr(transparent)]
|
|
pub struct $new_name($old_name);
|
|
};
|
|
}
|
|
#}</code></pre></pre>
|
|
<p>Except we also want to be able to add attributes (which includes doc comments),
|
|
so we upgrade our macro a bit:</p>
|
|
<pre><pre class="playpen"><code class="language-rust">
|
|
# #![allow(unused_variables)]
|
|
#fn main() {
|
|
#[macro_export]
|
|
macro_rules! newtype {
|
|
($(#[$attr:meta])* $new_name:ident, $old_name:ident) => {
|
|
$(#[$attr])*
|
|
#[repr(transparent)]
|
|
pub struct $new_name($old_name);
|
|
};
|
|
}
|
|
#}</code></pre></pre>
|
|
<p>And we want to automatically add the ability to turn the wrapper type back into
|
|
the wrapped type.</p>
|
|
<pre><pre class="playpen"><code class="language-rust">
|
|
# #![allow(unused_variables)]
|
|
#fn main() {
|
|
#[macro_export]
|
|
macro_rules! newtype {
|
|
($(#[$attr:meta])* $new_name:ident, $old_name:ident) => {
|
|
$(#[$attr])*
|
|
#[repr(transparent)]
|
|
pub struct $new_name($old_name);
|
|
|
|
impl From<$new_name> for $old_name {
|
|
fn from(x: $new_name) -> $old_name {
|
|
x.0
|
|
}
|
|
}
|
|
};
|
|
}
|
|
#}</code></pre></pre>
|
|
<p>That seems like enough for all of our examples, so we'll stop there. We could
|
|
add more things, such as making the <code>From</code> impl optional (because what if you
|
|
shouldn't unwrap it for some weird reason?), allowing for more precise
|
|
visibility controls (on both the newtype overall and the inner field), and maybe
|
|
even other things I can't think of right now. We won't really need those in our
|
|
example code for this book, so it's probably nicer to just keep the macro
|
|
simpler and quit while we're ahead.</p>
|
|
<p><strong>As a reminder:</strong> remember that macros have to appear <em>before</em> they're invoked in
|
|
your source, so the <code>newtype</code> macro will always have to be at the very top of
|
|
your file, or in a module that's declared before other modules and code.</p>
|
|
<a class="header" href="#help-and-resources" id="help-and-resources"><h1>Help and Resources</h1></a>
|
|
<a class="header" href="#help" id="help"><h2>Help</h2></a>
|
|
<p>So you're stuck on a problem and the book doesn't say what to do. Where can you
|
|
find out more?</p>
|
|
<p>The first place I would suggest is the <a href="https://discordapp.com/invite/aVESxV8">Rust Community
|
|
Discord</a>. If it's a general Rust question
|
|
then you can ask anyone in any channel you feel is appropriate. If it's GBA
|
|
specific then you can try asking me (<code>Lokathor</code>) or <code>Ketsuban</code> in the <code>#gamedev</code>
|
|
channel.</p>
|
|
<a class="header" href="#emulators" id="emulators"><h2>Emulators</h2></a>
|
|
<p>You certainly might want to eventually write a game that you can put on a flash
|
|
cart and play on real hardware, but for most of your development you'll probably
|
|
want to be using an emulator for testing, because you don't have to fiddle with
|
|
cables and all that.</p>
|
|
<p>In terms of emulators, you want to be using
|
|
<a href="https://github.com/mgba-emu/mgba">mGBA</a>, and you want to be using the <a href="https://github.com/mgba-emu/mgba/releases/tag/0.7-b1">0.7 Beta
|
|
1</a> or later. This update
|
|
lets you run raw ELF files, which means that you can have full debug symbols
|
|
available while you're debugging problems.</p>
|
|
<a class="header" href="#information-resources" id="information-resources"><h2>Information Resources</h2></a>
|
|
<p>Ketsuban and I didn't magically learn this all from nowhere, we read various
|
|
technical manuals and guides ourselves and then distilled the knowledge (usually
|
|
oriented towards C and C++) into this book for Rust.</p>
|
|
<p>We have personally used some or all of the following:</p>
|
|
<ul>
|
|
<li><a href="http://problemkaputt.de/gbatek.htm">GBATEK</a>: This is <em>the</em> resource. It
|
|
covers not only the GBA, but also the DS and DSi, and also a run down of ARM
|
|
assembly (32-bit and 16-bit opcodes). The link there is to the 2.9b version on
|
|
<code>problemkaputt.de</code> (the official home of the document), but if you just google
|
|
for gbatek the top result is for the 2.5 version on <code>akkit.org</code>, so make sure
|
|
you're looking at the newest version. Sometimes <code>problemkaputt.de</code> is a little
|
|
sluggish so I've also <a href="https://lokathor.com/gbatek.html">mirrored</a> the 2.9b
|
|
version on my own site as well. GBATEK is rather large, over 2mb of text, so
|
|
if you're on a phone or similar you might want to save an offline copy to go
|
|
easy on your data usage.</li>
|
|
<li><a href="https://www.coranac.com/tonc/text/">TONC</a>: While GBATEK is basically just a
|
|
huge tech specification, TONC is an actual <em>guide</em> on how to make sense of the
|
|
GBA's abilities and organize it into a game. It's written for C of course, but
|
|
as a Rust programmer you should always be practicing your ability to read C
|
|
code anyway. It's the programming equivalent of learning Latin because all the
|
|
old academic books are written in Latin.</li>
|
|
<li><a href="https://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm">CowBite</a>: This is
|
|
more like GBATEK, and it's less complete, but it mixes in a little more
|
|
friendly explanation of things in between the hardware spec parts.</li>
|
|
</ul>
|
|
<p>And I haven't had time to look at it myself, <a href="http://belogic.com/gba/">The Audio
|
|
Advance</a> seems to be very good. It explains in depth
|
|
how you can get audio working on the GBA. Note that the table of contents for
|
|
each page goes along the top instead of down the side.</p>
|
|
<a class="header" href="#non-rust-gba-community" id="non-rust-gba-community"><h2>Non-Rust GBA Community</h2></a>
|
|
<p>There's also the <a href="http://www.gbadev.org/">GBADev.org</a> site, which has a forum
|
|
and everything. They're coding in C and C++, but you can probably overcome that
|
|
difference with a little work on your part.</p>
|
|
<p>I also found a place called
|
|
<a href="https://gbatemp.net/categories/nintendo-gba-discussions.32/">GBATemp</a>, which
|
|
seems to have a more active forum but less of a focus on actual coding.</p>
|
|
<a class="header" href="#gba-limitations" id="gba-limitations"><h1>GBA Limitations</h1></a>
|
|
<a class="header" href="#no-floats" id="no-floats"><h1>No Floats</h1></a>
|
|
<a class="header" href="#core-only" id="core-only"><h1>Core Only</h1></a>
|
|
<a class="header" href="#volatile-destination" id="volatile-destination"><h1>Volatile Destination</h1></a>
|
|
<a class="header" href="#broad-concepts" id="broad-concepts"><h1>Broad Concepts</h1></a>
|
|
<a class="header" href="#cpu" id="cpu"><h1>CPU</h1></a>
|
|
<a class="header" href="#bios" id="bios"><h1>BIOS</h1></a>
|
|
<a class="header" href="#work-ram" id="work-ram"><h1>Work RAM</h1></a>
|
|
<a class="header" href="#io-registers" id="io-registers"><h1>IO Registers</h1></a>
|
|
<a class="header" href="#palette-ram" id="palette-ram"><h1>Palette RAM</h1></a>
|
|
<a class="header" href="#video-ram" id="video-ram"><h1>Video RAM</h1></a>
|
|
<a class="header" href="#object-attribute-memory" id="object-attribute-memory"><h1>Object Attribute Memory</h1></a>
|
|
<a class="header" href="#game-pak-rom--flash-rom" id="game-pak-rom--flash-rom"><h1>Game Pak ROM / Flash ROM</h1></a>
|
|
<a class="header" href="#save-ram" id="save-ram"><h1>Save RAM</h1></a>
|
|
<a class="header" href="#video" id="video"><h1>Video</h1></a>
|
|
<a class="header" href="#rbg15-color" id="rbg15-color"><h1>RBG15 Color</h1></a>
|
|
<a class="header" href="#todo" id="todo"><h1>TODO</h1></a>
|
|
<a class="header" href="#non-video" id="non-video"><h1>Non-Video</h1></a>
|
|
<a class="header" href="#buttons" id="buttons"><h1>Buttons</h1></a>
|
|
<a class="header" href="#timers" id="timers"><h1>Timers</h1></a>
|
|
<a class="header" href="#direct-memory-access" id="direct-memory-access"><h1>Direct Memory Access</h1></a>
|
|
<a class="header" href="#sound" id="sound"><h1>Sound</h1></a>
|
|
<a class="header" href="#interrupts" id="interrupts"><h1>Interrupts</h1></a>
|
|
<a class="header" href="#network" id="network"><h1>Network</h1></a>
|
|
<a class="header" href="#game-pak" id="game-pak"><h1>Game Pak</h1></a>
|
|
<a class="header" href="#examples" id="examples"><h1>Examples</h1></a>
|
|
<a class="header" href="#hello_magic" id="hello_magic"><h1>hello_magic</h1></a>
|
|
<a class="header" href="#hello_world" id="hello_world"><h1>hello_world</h1></a>
|
|
<a class="header" href="#light_cycle" id="light_cycle"><h1>light_cycle</h1></a>
|
|
<a class="header" href="#bg_demo" id="bg_demo"><h1>bg_demo</h1></a>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
|
|
|
|
|
|
|
|
<div style="clear: both"></div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
|
|
|
|
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
|
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
<!-- Custom JS scripts -->
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
window.addEventListener('load', function() {
|
|
window.setTimeout(window.print, 100);
|
|
});
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|