gba/docs/print.html
2018-12-24 20:24:29 +00:00

2257 lines
122 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-help_and_resources.html"><strong aria-hidden="true">1.5.</strong> Help and Resources</a></li></ol></li><li><a href="01-quirks/00-index.html"><strong aria-hidden="true">2.</strong> Quirks</a></li><li><ol class="section"><li><a href="01-quirks/01-no_std.html"><strong aria-hidden="true">2.1.</strong> No Std</a></li><li><a href="01-quirks/02-fixed_only.html"><strong aria-hidden="true">2.2.</strong> Fixed Only</a></li><li><a href="01-quirks/03-volatile_destination.html"><strong aria-hidden="true">2.3.</strong> Volatile Destination</a></li><li><a href="01-quirks/04-newtype.html"><strong aria-hidden="true">2.4.</strong> Newtype</a></li><li><a href="01-quirks/05-const_asserts.html"><strong aria-hidden="true">2.5.</strong> Const Asserts</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-link_cable.html"><strong aria-hidden="true">5.6.</strong> Link Cable</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></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 GameBoy Advance (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 very often hard to tell when you've explained something properly. In the
same way that your brain will read over small misspellings and correct things
into the right word, if an explanation for something you already understand
accidentally skips over some small detail then your brain can fill in the gaps
without you realizing it.</p>
<p><strong>Please</strong>, 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 &quot;if you wanna program Rust on this old
video game system you should already know how to program Rust&quot;, 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>My goal is certainly not just showing off the crate. Programming for the GBA is
weird enough that I'm trying to teach you all the rest of the stuff you need to
know along the way. If I do my job right then you'd be able to write your own
crate for GBA stuff just how you think it should all go by the end.</p>
<p>Overall the book is sorted more for easy review once you're trying to program
something. The GBA has a few things that can stand on their own and many other
things are a mass of 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 that it'll happen sometimes.</p>
<p>The actual &quot;tutorial order&quot; 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 &quot;real&quot; 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 &quot;MODE&quot; 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 &quot;Hello, world&quot; 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">#![no_std]
#![feature(start)]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
}
#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; 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="#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>First, if I fail to describe something related to Rust, you can always try
checking in <a href="https://doc.rust-lang.org/nightly/reference/introduction.html">The Rust
Reference</a> to see
if they cover it. You can mostly ignore that big scary red banner at the top,
things are a lot better documented than they make it sound.</p>
<p>If you need help trying to fiddle your math down as hard as you can, there are
resources such as the <a href="https://graphics.stanford.edu/%7Eseander/bithacks.html">Bit Twiddling
Hacks</a> page.</p>
<p>As to GBA related lore, Ketsuban and I didn't magically learn this all from
nowhere, we read various technical manuals and guides ourselves and then
distilled those works oriented around C and C++ into a 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="#quirks" id="quirks"><h1>Quirks</h1></a>
<p>The GBA supports a lot of totally normal Rust code exactly like you'd think.</p>
<p>However, it also is missing a lot of what you might expect, and sometimes we
have to do things in slightly weird ways.</p>
<p>We start the book by covering the quirks our code will have, just to avoid too
many surprises later.</p>
<a class="header" href="#no-std" id="no-std"><h1>No Std</h1></a>
<p>First up, as you already saw in the <code>hello_magic</code> code, we have to use the
<code>#![no_std]</code> outer attribute on our program when we target the GBA. You can find
some info about <code>no_std</code> in two official sources:</p>
<ul>
<li><a href="https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib">unstable
book section</a></li>
<li><a href="https://rust-embedded.github.io/book/intro/no-std.html?highlight=no_std#a--no_std--rust-environment">embedded
book section</a></li>
</ul>
<p>The unstable book is borderline useless here because it's describing too many
things in too many words. The embedded book is much better, but still fairly
terse.</p>
<a class="header" href="#bare-metal" id="bare-metal"><h2>Bare Metal</h2></a>
<p>The GBA falls under what the Embedded Book calls &quot;Bare Metal Environments&quot;.
Basically, the machine powers on and immediately begins executing some ASM code.
Our ASM startup was provided by <code>Ketsuban</code> (check the <code>crt0.s</code> file). We'll go
over <em>how</em> it works much later on, for now it's enough to know that it does
work, and eventually control passes into Rust code.</p>
<p>On the rust code side of things, we determine our starting point with the
<code>#[start]</code> attribute on our <code>main</code> function. The <code>main</code> function also has a
specific type signature that's different from the usual <code>main</code> that you'd see in
Rust. I'd tell you to read the unstable-book entry on <code>#[start]</code> but they
<a href="https://doc.rust-lang.org/unstable-book/language-features/start.html">literally</a>
just tell you to look at the <a href="https://github.com/rust-lang/rust/issues/29633">tracking issue for
it</a> instead, and that's not very
helpful either. Basically it just <em>has</em> to be declared the way it is, even
though there's nothing passing in the arguments and there's no place that the
return value will go. The compiler won't accept it any other way.</p>
<a class="header" href="#no-standard-library" id="no-standard-library"><h2>No Standard Library</h2></a>
<p>The Embedded Book tells us that we can't use the standard library, but we get
access to something called &quot;libcore&quot;, which sounds kinda funny. What they're
talking about is just <a href="https://doc.rust-lang.org/core/index.html">the core
crate</a>, which is called <code>libcore</code>
within the rust repository for historical reasons.</p>
<p>The <code>core</code> crate is actually still a really big portion of Rust. The standard
library doesn't actually hold too much code (relatively speaking), instead it
just takes code form other crates and then re-exports it in an organized way. So
with just <code>core</code> instead of <code>std</code>, what are we missing?</p>
<p>In no particular order:</p>
<ul>
<li>Allocation</li>
<li>Clock</li>
<li>Network</li>
<li>File System</li>
</ul>
<p>The allocation system and all the types that you can use if you have a global
allocator are neatly packaged up in the
<a href="https://doc.rust-lang.org/alloc/index.html">alloc</a> crate. The rest isn't as
nicely organized.</p>
<p>It's <em>possible</em> to implement a fair portion of the entire standard library
within a GBA context and make the rest just panic if you try to use it. However,
do you really need all that? Eh... probably not?</p>
<ul>
<li>We don't need a file system, because all of our data is just sitting there in
the ROM for us to use. When programming we can organize our <code>const</code> data into
modules and such to keep it organized, but once the game is compiled it's just
one huge flat address space. TODO: Parasyte says that a FS can be handy even
if it's all just ReadOnly, so we'll eventually talk about how you might set up
such a thing I guess, since we'll already be talking about replacements for
three of the other four things we &quot;lost&quot;. Maybe we'll make Parasyte write that
section.</li>
<li>Networking, well, the GBA has a Link Cable you can use to communicate with
another GBA, but it's not really like a unix socket with TCP, so the standard
Rust networking isn't a very good match.</li>
<li>Clock is actually two different things at once. One is the ability to store
the time long term, which is a bit of hardware that some gamepaks have in them
(eg: pokemon ruby/sapphire/emerald). The GBA itself can't keep time while
power is off. However, the second part is just tracking time moment to moment,
which the GBA can totally do. We'll see how to access the timers soon enough.</li>
</ul>
<p>Which just leaves us with allocation. Do we need an allocator? Depends on your
game. For demos and small games you probably don't need one. For bigger games
you'll maybe want to get an allocator going eventually. It's in some sense a
crutch, but it's a very useful one.</p>
<p>So I promise that at some point we'll cover how to get an allocator going.
Either a Rust Global Allocator (if practical), which would allow for a lot of
the standard library types to be used &quot;for free&quot; once it was set up, or just a
custom allocator that's GBA specific if Rust's global allocator style isn't a
good fit for the GBA (I honestly haven't looked into it).</p>
<a class="header" href="#bare-metal-panic" id="bare-metal-panic"><h2>Bare Metal Panic</h2></a>
<p>TODO: expand this</p>
<ul>
<li>Write <code>0xC0DE</code> to <code>0x4fff780</code> (<code>u16</code>) to enable mGBA logging. Write any other
value to disable it.</li>
<li>Read <code>0x4fff780</code> (<code>u16</code>) to check mGBA logging status.
<ul>
<li>You get <code>0x1DEA</code> if debugging is active.</li>
<li>Otherwise you get standard open bus nonsense values.</li>
</ul>
</li>
<li>Write your message into the virtual <code>[u8; 255]</code> array starting at <code>0x4fff600</code>.
mGBA will interpret these bytes as a CString value.</li>
<li>Write <code>0x100</code> PLUS the message level to <code>0x4fff700</code> (<code>u16</code>) when you're ready
to send a message line:
<ul>
<li>0: Fatal (halts execution with a popup)</li>
<li>1: Error</li>
<li>2: Warning</li>
<li>3: Info</li>
<li>4: Debug</li>
</ul>
</li>
<li>Sending the message also automatically zeroes the output buffer.</li>
<li>View the output within the &quot;Tools&quot; menu, &quot;View Logs...&quot;. Note that the Fatal
message, if any doesn't get logged.</li>
</ul>
<p>TODO: this will probably fail without a <code>__clzsi2</code> implementation, which is a
good seg for the next section</p>
<a class="header" href="#llvm-intrinsics" id="llvm-intrinsics"><h2>LLVM Intrinsics</h2></a>
<p>TODO: explain that we'll occasionally have to provide some intrinsics.</p>
<a class="header" href="#fixed-only" id="fixed-only"><h1>Fixed Only</h1></a>
<p>In addition to not having much of the standard library available, we don't even
have a floating point unit available! We can't do floating point math in
hardware! We <em>could</em> still do floating point math as pure software computations
if we wanted, but that's a slow, slow thing to do.</p>
<p>Are there faster ways? It's the same answer as always: &quot;Yes, but not without a
tradeoff.&quot;</p>
<p>The faster way is to represent fractional values using a system called a <a href="https://en.wikipedia.org/wiki/Fixed-point_arithmetic">Fixed
Point Representation</a>.
What do we trade away? Numeric range.</p>
<ul>
<li>Floating point math stores bits for base value and for exponent all according
to a single <a href="https://en.wikipedia.org/wiki/IEEE_754">well defined</a> standard
for how such a complicated thing works.</li>
<li>Fixed point math takes a normal integer (either signed or unsigned) and then
just &quot;mentally associates&quot; it (so to speak) with a fractional value for its
&quot;units&quot;. If you have 3 and it's in units of 1/2, then you have 3/2, or 1.5
using decimal notation. If your number is 256 and it's in units of 1/256th
then the value is 1.0 in decimal notation.</li>
</ul>
<p>Floating point math requires dedicated hardware to perform quickly, but it can
&quot;trade&quot; precision when it needs to represent extremely large or small values.</p>
<p>Fixed point math is just integral math, which our GBA is reasonably good at, but
because your number is associated with a fixed fraction your results can get out
of range very easily.</p>
<a class="header" href="#representing-a-fixed-point-value" id="representing-a-fixed-point-value"><h2>Representing A Fixed Point Value</h2></a>
<p>So we want to associate our numbers with a mental note of what units they're in:</p>
<ul>
<li><a href="https://doc.rust-lang.org/core/marker/struct.PhantomData.html">PhantomData</a>
is a type that tells the compiler &quot;please remember this extra type info&quot; when
you add it as a field to a struct. It goes away at compile time, so it's
perfect for us to use as space for a note to ourselves without causing runtime
overhead.</li>
<li>The <a href="https://crates.io/crates/typenum">typenum</a> crate is the best way to
represent a number within a type in Rust. Since our values on the GBA are
always specified as a number of fractional bits to count the number as, we can
put <code>typenum</code> types such as <code>U8</code> or <code>U14</code> into our <code>PhantomData</code> to keep track
of what's going on.</li>
</ul>
<p>Now, those of you who know me, or perhaps just know my reputation, will of
course <em>immediately</em> question what happened to the real Lokathor. I do not care
for most crates, and I particularly don't care for using a crate in teaching
situations. However, <code>typenum</code> has a number of factors on its side that let me
suggest it in this situation:</p>
<ul>
<li>It's version 1.10 with a total of 21 versions and nearly 700k downloads, so we
can expect that the major troubles have been shaken out and that it will remain
fairly stable for quite some time to come.</li>
<li>It has no further dependencies that it's going to drag into the compilation.</li>
<li>It happens all at compile time, so it's not clogging up our actual game with
any nonsense.</li>
<li>The (interesting) subject of &quot;how do you do math inside Rust's trait system?&quot; is
totally separate from the concern that we're trying to focus on here.</li>
</ul>
<p>Therefore, we will consider it acceptable to use this crate.</p>
<p>Now the <code>typenum</code> crate defines a whole lot, but we'll focus down to just a
single type at the moment:
<a href="https://docs.rs/typenum/1.10.0/typenum/uint/struct.UInt.html">UInt</a> is a
type-level unsigned value. It's like <code>u8</code> or <code>u16</code>, but while they're types that
then have values, each <code>UInt</code> construction statically equates to a specific
value. Like how the <code>()</code> type only has one value, which is also called <code>()</code>. In
this case, you wrap up <code>UInt</code> around smaller <code>UInt</code> values and a <code>B1</code> or <code>B0</code>
value to build up the binary number that you want at the type level.</p>
<p>In other words, instead of writing</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
let six = 0b110;
#}</code></pre></pre>
<p>We write</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
type U6 = UInt&lt;UInt&lt;UInt&lt;UTerm, B1&gt;, B1&gt;, B0&gt;;
#}</code></pre></pre>
<p>Wild, I know. If you look into the <code>typenum</code> crate you can do math and stuff
with these type level numbers, and we will a little bit below, but to start off
we <em>just</em> need to store one in some <code>PhantomData</code>.</p>
<a class="header" href="#a-struct-for-fixed-point" id="a-struct-for-fixed-point"><h3>A struct For Fixed Point</h3></a>
<p>Our actual type for a fixed point value looks like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
use core::marker::PhantomData;
use typenum::marker_traits::Unsigned;
/// Fixed point `T` value with `F` fractional bits.
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Fx&lt;T, F: Unsigned&gt; {
bits: T,
_phantom: PhantomData&lt;F&gt;,
}
#}</code></pre></pre>
<p>This says that <code>Fx&lt;T,F&gt;</code> is a generic type that holds some base number type <code>T</code>
and a <code>F</code> type that's marking off how many fractional bits we're using. We only
want people giving unsigned type-level values for the <code>PhantomData</code> type, so we
use the trait bound <code>F: Unsigned</code>.</p>
<p>We use
<a href="https://github.com/rust-lang/rfcs/blob/master/text/1758-repr-transparent.md">repr(transparent)</a>
here to ensure that <code>Fx</code> will always be treated just like the base type in the
final program (in terms of bit pattern and ABI).</p>
<p>If you go and check, this is <em>basically</em> how the existing general purpose crates
for fixed point math represent their numbers. They're a little fancier about it
because they have to cover every case, and we only have to cover our GBA case.</p>
<p>That's quite a bit to type though. We probably want to make a few type aliases
for things to be easier to look at. Unfortunately there's <a href="https://en.wikipedia.org/wiki/Fixed-point_arithmetic#Notation">no standard
notation</a> for how
you write a fixed point type. We also have to limit ourselves to what's valid
for use in a Rust type too. I like the <code>fx</code> thing, so we'll use that for signed
and then <code>fxu</code> if we need an unsigned value.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
/// Alias for an `i16` fixed point value with 8 fractional bits.
pub type fx8_8 = Fx&lt;i16,U8&gt;;
#}</code></pre></pre>
<p>Rust will complain about having <code>non_camel_case_types</code>, and you can shut that
warning up by putting an <code>#[allow(non_camel_case_types)]</code> attribute on the type
alias directly, or you can use <code>#![allow(non_camel_case_types)]</code> at the very top
of the module to shut up that warning for the whole module (which is what I
did).</p>
<a class="header" href="#constructing-a-fixed-point-value" id="constructing-a-fixed-point-value"><h2>Constructing A Fixed Point Value</h2></a>
<p>So how do we actually <em>make</em> one of these values? Well, we can always just wrap or unwrap any value in our <code>Fx</code> type:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
impl&lt;T, F: Unsigned&gt; Fx&lt;T, F&gt; {
/// Uses the provided value directly.
pub fn from_raw(r: T) -&gt; Self {
Fx {
num: r,
phantom: PhantomData,
}
}
/// Unwraps the inner value.
pub fn into_raw(self) -&gt; T {
self.num
}
}
#}</code></pre></pre>
<p>I'd like to use the <code>From</code> trait of course, but it was giving me some trouble, i
think because of the orphan rule. Oh well.</p>
<p>If we want to be particular to the fact that these are supposed to be
<em>numbers</em>... that gets tricky. Rust is actually quite bad at being generic about
number types. You can use the <a href="https://crates.io/crates/num">num</a> crate, or you
can just use a macro and invoke it once per type. Guess what we're gonna do.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
macro_rules! fixed_point_methods {
($t:ident) =&gt; {
impl&lt;F: Unsigned&gt; Fx&lt;$t, F&gt; {
/// Gives the smallest positive non-zero value.
pub fn precision() -&gt; Self {
Fx {
num: 1,
phantom: PhantomData,
}
}
/// Makes a value with the integer part shifted into place.
pub fn from_int_part(i: $t) -&gt; Self {
Fx {
num: i &lt;&lt; F::U8,
phantom: PhantomData,
}
}
}
};
}
fixed_point_methods! {u8}
fixed_point_methods! {i8}
fixed_point_methods! {i16}
fixed_point_methods! {u16}
fixed_point_methods! {i32}
fixed_point_methods! {u32}
#}</code></pre></pre>
<p>Now <em>you'd think</em> that those can be <code>const</code>, but at the moment you can't have a
<code>const</code> function with a bound on any trait other than <code>Sized</code>, so they have to
be normal functions.</p>
<p>Also, we're doing something a little interesting there with <code>from_int_part</code>. We
can take our <code>F</code> type and get its constant value. There's other associated
constants if we want it in other types, and also non-const methods if you wanted
that for some reason (maybe passing it as a closure function? dunno).</p>
<a class="header" href="#casting-base-values" id="casting-base-values"><h2>Casting Base Values</h2></a>
<p>Next, once we have a value in one base type we will need to be able to move it
into another base type. Unfortunately this means we gotta use the <code>as</code> operator,
which requires a concrete source type and a concrete destination type. There's
no easy way for us to make it generic here.</p>
<p>We could let the user use <code>into_raw</code>, cast, and then do <code>from_raw</code>, but that's
error prone because they might change the fractional bit count accidentally.
This means that we have to write a function that does the casting while
perfectly preserving the fractional bit quantity. If we wrote one function for
each conversion it'd be like 30 different possible casts (6 base types that we
support, and then 5 possible target types). Instead, we'll write it just once in
a way that takes a closure, and let the user pass a closure that does the cast.
The compiler should merge it all together quite nicely for us once optimizations
kick in.</p>
<p>This code goes outside the macro. I want to avoid too much code in the macro if
we can, it's a little easier to cope with I think.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
/// Casts the base type, keeping the fractional bit quantity the same.
pub fn cast_inner&lt;Z, C: Fn(T) -&gt; Z&gt;(self, op: C) -&gt; Fx&lt;Z, F&gt; {
Fx {
num: op(self.num),
phantom: PhantomData,
}
}
#}</code></pre></pre>
<p>It's horrible and ugly, but Rust is just bad at numbers sometimes.</p>
<a class="header" href="#adjusting-fractional-part" id="adjusting-fractional-part"><h2>Adjusting Fractional Part</h2></a>
<p>In addition to the base value we might want to change our fractional bit
quantity. This is actually easier that it sounds, but it also requires us to be
tricky with the generics. We can actually use some typenum type level operators
here.</p>
<p>This code goes inside the macro: we need to be able to use the left shift and
right shift, which is easiest when we just use the macro's <code>$t</code> as our type. We
could alternately put a similar function outside the macro and be generic on <code>T</code>
having the left and right shift operators by using a <code>where</code> clause. As much as
I'd like to avoid too much code being generated by macro, I'd <em>even more</em> like
to avoid generic code with huge and complicated trait bounds. It comes down to
style, and you gotta decide for yourself.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
/// Changes the fractional bit quantity, keeping the base type the same.
pub fn adjust_fractional_bits&lt;Y: Unsigned + IsEqual&lt;F, Output = False&gt;&gt;(self) -&gt; Fx&lt;$t, Y&gt; {
let leftward_movement: i32 = Y::to_i32() - F::to_i32();
Fx {
num: if leftward_movement &gt; 0 {
self.num &lt;&lt; leftward_movement
} else {
self.num &gt;&gt; (-leftward_movement)
},
phantom: PhantomData,
}
}
#}</code></pre></pre>
<p>There's a few things at work. First, we introduce <code>Y</code> as the target number of
fractional bits, and we <em>also</em> limit it that the target bits quantity can't be
the same as we already have using a type-level operator. If it's the same as we
started with, why are you doing the cast at all?</p>
<p>Now, once we're sure that the current bits and target bits aren't the same, we
compute <code>target - start</code>, and call this our &quot;leftward movement&quot;. Example: if
we're targeting 8 bits and we're at 4 bits, we do 8-4 and get +4 as our leftward
movement. If the leftward_movement is positive we naturally shift our current
value to the left. If it's not positive then it <em>must</em> be negative because we
eliminated 0 as a possibility using the type-level operator, so we shift to the
right by the negative value.</p>
<a class="header" href="#addition-subtraction-shifting-negative-comparisons" id="addition-subtraction-shifting-negative-comparisons"><h2>Addition, Subtraction, Shifting, Negative, Comparisons</h2></a>
<p>From here on we're getting help from <a href="https://spin.atomicobject.com/2012/03/15/simple-fixed-point-math/">this blog
post</a> by <a href="https://spin.atomicobject.com/author/vranish/">Job
Vranish</a>, so thank them if you
learn something.</p>
<p>I might have given away the game a bit with those <code>derive</code> traits on our fixed
point type. For a fair number of operations you can use the normal form of the
op on the inner bits as long as the fractional parts have the same quantity.
This includes equality and ordering (which we derived) as well as addition,
subtraction, and bit shifting (which we need to do ourselves).</p>
<p>This code can go outside the macro, with sufficient trait bounds.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
impl&lt;T: Add&lt;Output = T&gt;, F: Unsigned&gt; Add for Fx&lt;T, F&gt; {
type Output = Self;
fn add(self, rhs: Fx&lt;T, F&gt;) -&gt; Self::Output {
Fx {
num: self.num + rhs.num,
phantom: PhantomData,
}
}
}
#}</code></pre></pre>
<p>The bound on <code>T</code> makes it so that <code>Fx&lt;T, F&gt;</code> can be added any time that <code>T</code> can
be added to its own type with itself as the output. We can use the exact same
pattern for <code>Sub</code>, <code>Shl</code>, <code>Shr</code>, and <code>Neg</code>. With enough trait bounds, we can do
anything!</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
impl&lt;T: Sub&lt;Output = T&gt;, F: Unsigned&gt; Sub for Fx&lt;T, F&gt; {
type Output = Self;
fn sub(self, rhs: Fx&lt;T, F&gt;) -&gt; Self::Output {
Fx {
num: self.num - rhs.num,
phantom: PhantomData,
}
}
}
impl&lt;T: Shl&lt;u32, Output = T&gt;, F: Unsigned&gt; Shl&lt;u32&gt; for Fx&lt;T, F&gt; {
type Output = Self;
fn shl(self, rhs: u32) -&gt; Self::Output {
Fx {
num: self.num &lt;&lt; rhs,
phantom: PhantomData,
}
}
}
impl&lt;T: Shr&lt;u32, Output = T&gt;, F: Unsigned&gt; Shr&lt;u32&gt; for Fx&lt;T, F&gt; {
type Output = Self;
fn shr(self, rhs: u32) -&gt; Self::Output {
Fx {
num: self.num &gt;&gt; rhs,
phantom: PhantomData,
}
}
}
impl&lt;T: Neg&lt;Output = T&gt;, F: Unsigned&gt; Neg for Fx&lt;T, F&gt; {
type Output = Self;
fn neg(self) -&gt; Self::Output {
Fx {
num: -self.num,
phantom: PhantomData,
}
}
}
#}</code></pre></pre>
<p>Unfortunately, for <code>Shl</code> and <code>Shr</code> to have as much coverage on our type as it
does on the base type (allowing just about any right hand side) we'd have to do
another macro, but I think just <code>u32</code> is fine. We can always add more later if
we need.</p>
<p>We could also implement <code>BitAnd</code>, <code>BitOr</code>, <code>BitXor</code>, and <code>Not</code>, but they don't
seem relevent to our fixed point math use, and this section is getting long
already. Just use the same general patterns if you want to add it in your own
programs. Shockingly, <code>Rem</code> also works directly if you want it, though I don't
forsee us needing floating point remainder. Also, the GBA can't do hardware
division or remainder, and we'll have to work around that below when we
implement <code>Div</code> (which maybe we don't need, but it's complex enough I should
show it instead of letting people guess).</p>
<p><strong>Note:</strong> In addition to the various <code>Op</code> traits, there's also <code>OpAssign</code>
variants. Each <code>OpAssign</code> is the same as <code>Op</code>, but takes <code>&amp;mut self</code> instead of
<code>self</code> and then modifies in place instead of producing a fresh value. In other
words, if you want both <code>+</code> and <code>+=</code> you'll need to do the <code>AddAssign</code> trait
too. It's not the worst thing to just write <code>a = a+b</code>, so I won't bother with
showing all that here. It's pretty easy to figure out for yourself if you want.</p>
<a class="header" href="#multiplication" id="multiplication"><h2>Multiplication</h2></a>
<p>This is where things get more interesting. When we have two numbers <code>A</code> and <code>B</code>
they really stand for <code>(a*f)</code> and <code>(b*f)</code>. If we write <code>A*B</code> then we're really
writing <code>(a*f)*(b*f)</code>, which can be rewritten as <code>(a*b)*2f</code>, and now it's
obvious that we have one more <code>f</code> than we wanted to have. We have to do the
multiply of the inner value and then divide out the <code>f</code>. We divide by <code>1 &lt;&lt; bit_count</code>, so if we have 8 fractional bits we'll divide by 256.</p>
<p>The catch is that, when we do the multiply we're <em>extremely</em> likely to overflow
our base type with that multiplication step. Then we do that divide, and now our
result is basically nonsense. We can avoid this to some extent by casting up to
a higher bit type, doing the multiplication and division at higher precision,
and then casting back down. We want as much precision as possible without being
too inefficient, so we'll always cast up to 32-bit (on a 64-bit machine you'd
cast up to 64-bit instead).</p>
<p>Naturally, any signed value has to be cast up to <code>i32</code> and any unsigned value
has to be cast up to <code>u32</code>, so we'll have to handle those separately.</p>
<p>Also, instead of doing an <em>actual</em> divide we can right-shift by the correct
number of bits to achieve the same effect. <em>Except</em> when we have a signed value
that's negative, because actual division truncates towards zero and
right-shifting truncates towards negative infinity. We can get around <em>this</em> by
flipping the sign, doing the shift, and flipping the sign again (which sounds
silly but it's so much faster than doing an actual division).</p>
<p>Also, again signed values can be annoying, because if the value <em>just happens</em>
to be <code>i32::MIN</code> then when you negate it you'll have... <em>still</em> a negative
value. I'm not 100% on this, but I think the correct thing to do at that point
is to give <code>$t::MIN</code> as the output num value.</p>
<p>Did you get all that? Good, because this involves casting, so we will need to
implement it three times, which calls for another macro.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
macro_rules! fixed_point_signed_multiply {
($t:ident) =&gt; {
impl&lt;F: Unsigned&gt; Mul for Fx&lt;$t, F&gt; {
type Output = Self;
fn mul(self, rhs: Fx&lt;$t, F&gt;) -&gt; Self::Output {
let pre_shift = (self.num as i32).wrapping_mul(rhs.num as i32);
if pre_shift &lt; 0 {
if pre_shift == core::i32::MIN {
Fx {
num: core::$t::MIN,
phantom: PhantomData,
}
} else {
Fx {
num: (-((-pre_shift) &gt;&gt; F::U8)) as $t,
phantom: PhantomData,
}
}
} else {
Fx {
num: (pre_shift &gt;&gt; F::U8) as $t,
phantom: PhantomData,
}
}
}
}
};
}
fixed_point_signed_multiply! {i8}
fixed_point_signed_multiply! {i16}
fixed_point_signed_multiply! {i32}
macro_rules! fixed_point_unsigned_multiply {
($t:ident) =&gt; {
impl&lt;F: Unsigned&gt; Mul for Fx&lt;$t, F&gt; {
type Output = Self;
fn mul(self, rhs: Fx&lt;$t, F&gt;) -&gt; Self::Output {
Fx {
num: ((self.num as u32).wrapping_mul(rhs.num as u32) &gt;&gt; F::U8) as $t,
phantom: PhantomData,
}
}
}
};
}
fixed_point_unsigned_multiply! {u8}
fixed_point_unsigned_multiply! {u16}
fixed_point_unsigned_multiply! {u32}
#}</code></pre></pre>
<a class="header" href="#division" id="division"><h2>Division</h2></a>
<p>Division is similar to multiplication, but reversed. Which makes sense. This
time <code>A/B</code> gives <code>(a*f)/(b*f)</code> which is <code>a/b</code>, one <em>less</em> <code>f</code> than we were
after.</p>
<p>As with the multiplication version of things, we have to up-cast our inner value
as much a we can before doing the math, to allow for the most precision
possible.</p>
<p>The snag here is that the GBA has no division or remainder. Instead, the GBA has
a BIOS function you can call to do <code>i32/i32</code> division.</p>
<p>This is a potential problem for us though. If we have some unsigned value, we
need it to fit within the positive space of an <code>i32</code> <em>after the multiply</em> so
that we can cast it to <code>i32</code>, call the BIOS function that only works on <code>i32</code>
values, and cast it back to its actual type.</p>
<ul>
<li>If you have a u8 you're always okay, even with 8 floating bits.</li>
<li>If you have a u16 you're okay even with a maximum value up to 15 floating
bits, but having a maximum value and 16 floating bits makes it break.</li>
<li>If you have a u32 you're probably going to be in trouble all the time.</li>
</ul>
<p>So... ugh, there's not much we can do about this. For now we'll just have to
suffer some.</p>
<p>// TODO: find a numerics book that tells us how to do <code>u32/u32</code> divisions.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
macro_rules! fixed_point_signed_division {
($t:ident) =&gt; {
impl&lt;F: Unsigned&gt; Div for Fx&lt;$t, F&gt; {
type Output = Self;
fn div(self, rhs: Fx&lt;$t, F&gt;) -&gt; Self::Output {
let mul_output: i32 = (self.num as i32).wrapping_mul(1 &lt;&lt; F::U8);
let divide_result: i32 = crate::bios::div(mul_output, rhs.num as i32);
Fx {
num: divide_result as $t,
phantom: PhantomData,
}
}
}
};
}
fixed_point_signed_division! {i8}
fixed_point_signed_division! {i16}
fixed_point_signed_division! {i32}
macro_rules! fixed_point_unsigned_division {
($t:ident) =&gt; {
impl&lt;F: Unsigned&gt; Div for Fx&lt;$t, F&gt; {
type Output = Self;
fn div(self, rhs: Fx&lt;$t, F&gt;) -&gt; Self::Output {
let mul_output: i32 = (self.num as i32).wrapping_mul(1 &lt;&lt; F::U8);
let divide_result: i32 = crate::bios::div(mul_output, rhs.num as i32);
Fx {
num: divide_result as $t,
phantom: PhantomData,
}
}
}
};
}
fixed_point_unsigned_division! {u8}
fixed_point_unsigned_division! {u16}
fixed_point_unsigned_division! {u32}
#}</code></pre></pre>
<a class="header" href="#trigonometry" id="trigonometry"><h2>Trigonometry</h2></a>
<p>TODO: look up tables! arcbits!</p>
<a class="header" href="#just-using-a-crate" id="just-using-a-crate"><h2>Just Using A Crate</h2></a>
<p>If, after seeing all that, and seeing that I still didn't even cover every
possible trait impl that you might want for all the possible types... if after
all that you feel too intimidated, then I'll cave a bit on your behalf and
suggest to you that the <a href="https://crates.io/crates/fixed">fixed</a> crate seems to
be the best crate available for fixed point math.</p>
<p><em>I have not tested its use on the GBA myself</em>.</p>
<p>It's just my recommendation from looking at the docs of the various options
available, if you really wanted to just have a crate for it.</p>
<a class="header" href="#volatile-destination" id="volatile-destination"><h1>Volatile Destination</h1></a>
<p>TODO: update this when we can make more stuff <code>const</code></p>
<a class="header" href="#volatile-memory" id="volatile-memory"><h2>Volatile Memory</h2></a>
<p>The compiler is an eager friend, so when it sees a read or a write that won't
have an effect, it eliminates that read or write. For example, if we write</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
let mut x = 5;
x = 7;
#}</code></pre></pre>
<p>The compiler won't actually ever put 5 into <code>x</code>. It'll skip straight to putting
7 in <code>x</code>, because we never read from <code>x</code> when it's 5, so that's a safe change to
make. Normally, values are stored in RAM, which has no side effects when you
read and write from it. RAM is purely for keeping notes about values you'll need
later on.</p>
<p>However, what if we had a bit of hardware where we wanted to do a write and that
did something <em>other than</em> keeping the value for us to look at later? As you saw
in the <code>hello_magic</code> example, we have to use a <code>write_volatile</code> operation.
Volatile means &quot;just do it anyway&quot;. The compiler thinks that it's pointless, but
we know better, so we can force it to really do exactly what we say by using
<code>write_volatile</code> instead of <code>write</code>.</p>
<p>This is kinda error prone though, right? Because it's just a raw pointer, so we
might forget to use <code>write_volatile</code> at some point.</p>
<p>Instead, we want a type that's always going to use volatile reads and writes.
Also, we want a pointer type that lets our reads and writes to be as safe as
possible once we've unsafely constructed the initial value.</p>
<a class="header" href="#constructing-the-voladdress-type" id="constructing-the-voladdress-type"><h3>Constructing The VolAddress Type</h3></a>
<p>First, we want a type that stores a location within the address space. This can
be a pointer, or a <code>usize</code>, and we'll use a <code>usize</code> because that's easier to
work with in a <code>const</code> context (and we want to have <code>const</code> when we can get it).
We'll also have our type use <code>NonZeroUsize</code> instead of just <code>usize</code> so that
<code>Option&lt;VolAddress&lt;T&gt;&gt;</code> stays as a single machine word. This helps quite a bit
when we want to iterate over the addresses of a block of memory (such as
locations within the palette memory). Hardware is never at the null address
anyway. Also, if we had <em>just</em> an address number then we wouldn't be able to
track what type the address is for. We need some
<a href="https://doc.rust-lang.org/core/marker/struct.PhantomData.html">PhantomData</a>,
and specifically we need the phantom data to be for <code>*mut T</code>:</p>
<ul>
<li>If we used <code>*const T</code> that'd have the wrong
<a href="https://doc.rust-lang.org/nomicon/subtyping.html">variance</a>.</li>
<li>If we used <code>&amp;mut T</code> then that's fusing in the ideas of <em>lifetime</em> and
<em>exclusive access</em> to our type. That's potentially important, but that's also
an abstraction we'll build <em>on top of</em> this <code>VolAddress</code> type if we need it.</li>
</ul>
<p>One abstraction layer at a time, so we start with just a phantom pointer. This gives us a type that looks like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[derive(Debug)]
#[repr(transparent)]
pub struct VolAddress&lt;T&gt; {
address: NonZeroUsize,
marker: PhantomData&lt;*mut T&gt;,
}
#}</code></pre></pre>
<p>Now, because of how <code>derive</code> is specified, it derives traits <em>if the generic
parameter</em> supports those traits. Since our type is like a pointer, the traits
it supports are distinct from whatever traits the target type supports. So we'll
provide those implementations manually.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
impl&lt;T&gt; Clone for VolAddress&lt;T&gt; {
fn clone(&amp;self) -&gt; Self {
*self
}
}
impl&lt;T&gt; Copy for VolAddress&lt;T&gt; {}
impl&lt;T&gt; PartialEq for VolAddress&lt;T&gt; {
fn eq(&amp;self, other: &amp;Self) -&gt; bool {
self.address == other.address
}
}
impl&lt;T&gt; Eq for VolAddress&lt;T&gt; {}
impl&lt;T&gt; PartialOrd for VolAddress&lt;T&gt; {
fn partial_cmp(&amp;self, other: &amp;Self) -&gt; Option&lt;Ordering&gt; {
Some(self.address.cmp(&amp;other.address))
}
}
impl&lt;T&gt; Ord for VolAddress&lt;T&gt; {
fn cmp(&amp;self, other: &amp;Self) -&gt; Ordering {
self.address.cmp(&amp;other.address)
}
}
#}</code></pre></pre>
<p>Boilerplate junk, not interesting. There's a reason that you derive those traits
99% of the time in Rust.</p>
<a class="header" href="#constructing-a-voladdress-value" id="constructing-a-voladdress-value"><h3>Constructing A VolAddress Value</h3></a>
<p>Okay so here's the next core concept: If we unsafely <em>construct</em> a
<code>VolAddress&lt;T&gt;</code>, then we can safely <em>use</em> the value once it's been properly
created.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
// you'll need these features enabled and a recent nightly
#![feature(const_int_wrapping)]
#![feature(min_const_unsafe_fn)]
impl&lt;T&gt; VolAddress&lt;T&gt; {
pub const unsafe fn new_unchecked(address: usize) -&gt; Self {
VolAddress {
address: NonZeroUsize::new_unchecked(address),
marker: PhantomData,
}
}
pub const unsafe fn cast&lt;Z&gt;(self) -&gt; VolAddress&lt;Z&gt; {
VolAddress {
address: self.address,
marker: PhantomData,
}
}
pub unsafe fn offset(self, offset: isize) -&gt; Self {
VolAddress {
address: NonZeroUsize::new_unchecked(self.address.get().wrapping_add(offset as usize * core::mem::size_of::&lt;T&gt;())),
marker: PhantomData,
}
}
}
#}</code></pre></pre>
<p>So what are the unsafety rules here?</p>
<ul>
<li>Non-null, obviously.</li>
<li>Must be aligned for <code>T</code></li>
<li>Must always produce valid bit patterns for <code>T</code></li>
<li>Must not be part of the address space that Rust's stack or allocator will ever
uses.</li>
</ul>
<p>So, again using the <code>hello_magic</code> example, we had</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
(0x400_0000 as *mut u16).write_volatile(0x0403);
#}</code></pre></pre>
<p>And instead we could declare</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
const MAGIC_LOCATION: VolAddress&lt;u16&gt; = unsafe { VolAddress::new_unchecked(0x400_0000) };
#}</code></pre></pre>
<a class="header" href="#using-a-voladdress-value" id="using-a-voladdress-value"><h3>Using A VolAddress Value</h3></a>
<p>Now that we've named the magic location, we want to write to it.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
impl&lt;T&gt; VolAddress&lt;T&gt; {
pub fn read(self) -&gt; T
where
T: Copy,
{
unsafe { (self.address.get() as *mut T).read_volatile() }
}
pub unsafe fn read_non_copy(self) -&gt; T {
(self.address.get() as *mut T).read_volatile()
}
pub fn write(self, val: T) {
unsafe { (self.address.get() as *mut T).write_volatile(val) }
}
}
#}</code></pre></pre>
<p>So if the type is <code>Copy</code> we can <code>read</code> it as much as we want. If, somehow, the
type isn't <code>Copy</code>, then it might be <code>Drop</code>, and that means if we read out a
value over and over we could cause the <code>drop</code> method to trigger UB. Since the
end user might really know what they're doing, we provide an unsafe backup
<code>read_non_copy</code>.</p>
<p>On the other hand, we can <code>write</code> to the location as much as we want. Even if
the type isn't <code>Copy</code>, <em>not running <code>Drop</code> is safe</em>, so a <code>write</code> is always
safe.</p>
<p>Now we can write to our magical location.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
MAGIC_LOCATION.write(0x0403);
#}</code></pre></pre>
<a class="header" href="#voladdress-iteration" id="voladdress-iteration"><h3>VolAddress Iteration</h3></a>
<p>We've already seen that sometimes we want to have a base address of some sort
and then offset from that location to another. What if we wanted to iterate over
<em>all the locations</em>. That's not particularly hard.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
impl&lt;T&gt; VolAddress&lt;T&gt; {
pub const unsafe fn iter_slots(self, slots: usize) -&gt; VolAddressIter&lt;T&gt; {
VolAddressIter { vol_address: self, slots }
}
}
#[derive(Debug)]
pub struct VolAddressIter&lt;T&gt; {
vol_address: VolAddress&lt;T&gt;,
slots: usize,
}
impl&lt;T&gt; Clone for VolAddressIter&lt;T&gt; {
fn clone(&amp;self) -&gt; Self {
VolAddressIter {
vol_address: self.vol_address,
slots: self.slots,
}
}
}
impl&lt;T&gt; PartialEq for VolAddressIter&lt;T&gt; {
fn eq(&amp;self, other: &amp;Self) -&gt; bool {
self.vol_address == other.vol_address &amp;&amp; self.slots == other.slots
}
}
impl&lt;T&gt; Eq for VolAddressIter&lt;T&gt; {}
impl&lt;T&gt; Iterator for VolAddressIter&lt;T&gt; {
type Item = VolAddress&lt;T&gt;;
fn next(&amp;mut self) -&gt; Option&lt;Self::Item&gt; {
if self.slots &gt; 0 {
let out = self.vol_address;
unsafe {
self.slots -= 1;
self.vol_address = self.vol_address.offset(1);
}
Some(out)
} else {
None
}
}
}
impl&lt;T&gt; FusedIterator for VolAddressIter&lt;T&gt; {}
#}</code></pre></pre>
<a class="header" href="#voladdressblock" id="voladdressblock"><h3>VolAddressBlock</h3></a>
<p>Obviously, having a base address and a length exist separately is error prone.
There's a good reason for slices to keep their pointer and their length
together. We want something like that, which we'll call a &quot;block&quot; because
&quot;array&quot; and &quot;slice&quot; are already things in Rust.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[derive(Debug)]
pub struct VolAddressBlock&lt;T&gt; {
vol_address: VolAddress&lt;T&gt;,
slots: usize,
}
impl&lt;T&gt; Clone for VolAddressBlock&lt;T&gt; {
fn clone(&amp;self) -&gt; Self {
VolAddressBlock {
vol_address: self.vol_address,
slots: self.slots,
}
}
}
impl&lt;T&gt; PartialEq for VolAddressBlock&lt;T&gt; {
fn eq(&amp;self, other: &amp;Self) -&gt; bool {
self.vol_address == other.vol_address &amp;&amp; self.slots == other.slots
}
}
impl&lt;T&gt; Eq for VolAddressBlock&lt;T&gt; {}
impl&lt;T&gt; VolAddressBlock&lt;T&gt; {
pub const unsafe fn new_unchecked(vol_address: VolAddress&lt;T&gt;, slots: usize) -&gt; Self {
VolAddressBlock { vol_address, slots }
}
pub const fn iter(self) -&gt; VolAddressIter&lt;T&gt; {
VolAddressIter {
vol_address: self.vol_address,
slots: self.slots,
}
}
pub unsafe fn index_unchecked(self, slot: usize) -&gt; VolAddress&lt;T&gt; {
self.vol_address.offset(slot as isize)
}
pub fn index(self, slot: usize) -&gt; VolAddress&lt;T&gt; {
if slot &lt; self.slots {
unsafe { self.vol_address.offset(slot as isize) }
} else {
panic!(&quot;Index Requested: {} &gt;= Bound: {}&quot;, slot, self.slots)
}
}
pub fn get(self, slot: usize) -&gt; Option&lt;VolAddress&lt;T&gt;&gt; {
if slot &lt; self.slots {
unsafe { Some(self.vol_address.offset(slot as isize)) }
} else {
None
}
}
}
#}</code></pre></pre>
<p>Now we can have something like:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
const OTHER_MAGIC: VolAddressBlock&lt;u16&gt; = unsafe {
VolAddressBlock::new_unchecked(
VolAddress::new_unchecked(0x600_0000),
240 * 160
)
};
OTHER_MAGIC.index(120 + 80 * 240).write_volatile(0x001F);
OTHER_MAGIC.index(136 + 80 * 240).write_volatile(0x03E0);
OTHER_MAGIC.index(120 + 96 * 240).write_volatile(0x7C00);
#}</code></pre></pre>
<a class="header" href="#docs" id="docs"><h3>Docs?</h3></a>
<p>If you wanna see these types and methods with a full docs write up you should
check the GBA crate's source.</p>
<a class="header" href="#volatile-asm" id="volatile-asm"><h2>Volatile ASM</h2></a>
<p>In addition to some memory locations being volatile, it's also possible for
inline assembly to be declared volatile. This is basically the same idea, &quot;hey
just do what I'm telling you, don't get smart about it&quot;.</p>
<p>Normally when you have some <code>asm!</code> it's basically treated like a function,
there's inputs and outputs and the compiler will try to optimize it so that if
you don't actually use the outputs it won't bother with doing those
instructions. However, <code>asm!</code> is basically a pure black box, so the compiler
doesn't know what's happening inside at all, and it can't see if there's any
important side effects going on.</p>
<p>An example of an important side effect that doesn't have output values would be
putting the CPU into a low power state while we want for the next VBlank. This
lets us save quite a bit of battery power. It requires some setup to be done
safely (otherwise the GBA won't ever actually wake back up from the low power
state), but the <code>asm!</code> you use once you're ready is just a single instruction
with no return value. The compiler can't tell what's going on, so you just have
to say &quot;do it anyway&quot;.</p>
<p>Note that if you use a linker script to include any ASM with your Rust program
(eg: the <code>crt0.s</code> file that we setup in the &quot;Development Setup&quot; section), all of
that ASM is &quot;volatile&quot; for these purposes. Volatile isn't actually a <em>hardware</em>
concept, it's just an LLVM concept, and the linker script runs after LLVM has
done its work.</p>
<a class="header" href="#newtype" id="newtype"><h1>Newtype</h1></a>
<p>TODO: we've already used newtype twice by now (fixed point values and volatile
addresses), so we need to adjust how we start this section.</p>
<p>There's a great Zero Cost abstraction that we'll be using a lot that you might
not already be familiar with: we're talking about the &quot;Newtype Pattern&quot;!</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>TODO: we've already talked about repr(transparent) by now</p>
<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 the RFC 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>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>If you're going to do much with macros you should definitely read through <a href="https://danielkeep.github.io/tlborm/book/index.html">The
Little Book of Rust
Macros</a>, but we won't be
doing too much so you can just follow along here a bit if you like.</p>
<p>The most basic version of a newtype macro starts 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) =&gt; {
#[repr(transparent)]
pub struct $new_name($old_name);
};
}
#}</code></pre></pre>
<p>The <code>#[macro_export]</code> makes it exported by the current module (like <code>pub</code>
kinda), and then we have one expansion option that takes an identifier, a <code>,</code>,
and then a second identifier. The new name is the outer type we'll be using, and
the old name is the inner type that's being wrapped. You'd use our new macro
something like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
newtype! {PixelColorCurly, u16}
newtype!(PixelColorParens, u16);
newtype![PixelColorBrackets, u16];
#}</code></pre></pre>
<p>Note that you can invoke the macro with the outermost grouping as any of <code>()</code>,
<code>[]</code>, or <code>{}</code>. It makes no particular difference to the macro. Also, that space
in the first version is kinda to show off that you can put white space in
between the macro name and the grouping if you want. The difference is mostly
style, but there are some rules and considerations here:</p>
<ul>
<li>If you use curly braces then you <em>must not</em> put a <code>;</code> after the invocation.</li>
<li>If you use parentheses or brackets then you <em>must</em> put the <code>;</code> at the end.</li>
<li>Rustfmt cares which you use and formats accordingly:
<ul>
<li>Curly brace macro use mostly gets treated like a code block.</li>
<li>Parentheses macro use mostly gets treated like a function call.</li>
<li>Bracket macro use mostly gets treated like an array declaration.</li>
</ul>
</li>
</ul>
<a class="header" href="#upgrade-that-macro" id="upgrade-that-macro"><h2>Upgrade That Macro!</h2></a>
<p>We also want to be able to add <code>derive</code> stuff and doc comments to our newtype.
Within the context of <code>macro_rules!</code> definitions these are called &quot;meta&quot;. Since
we can have any number of them we wrap it all up in a &quot;zero or more&quot; matcher.
Then our macro looks like this:</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) =&gt; {
$(#[$attr])*
#[repr(transparent)]
pub struct $new_name($old_name);
};
}
#}</code></pre></pre>
<p>So now we can write</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
newtype! {
/// Color on the GBA gives 5 bits for each channel, the highest bit is ignored.
#[derive(Debug, Clone, Copy)]
PixelColor, u16
}
#}</code></pre></pre>
<p>And that's about all we'll need for the examples.</p>
<p><strong>As a reminder:</strong> remember that <code>macro_rules</code> 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 if you put it in a module within your project
you'll need to declare the module before anything that uses it.</p>
<a class="header" href="#potential-homework" id="potential-homework"><h2>Potential Homework</h2></a>
<p>If you wanted to keep going and get really fancy with it, you could potentially
add a lot more:</p>
<ul>
<li>Make a <code>pub const fn new() -&gt; Self</code> method that outputs the base value in a
const way. Combine this with builder style &quot;setter&quot; methods that are also
const and you can get the compiler to do quite a bit of the value building
work at compile time.</li>
<li>Making the macro optionally emit a <code>From</code> impl to unwrap it back into the base
type.</li>
<li>Allow for visibility modifiers to be applied to the inner field and the newly
generated type.</li>
<li>Allowing for generic newtypes. You already saw the need for this once in the
volatile section. Unfortunately, this particular part gets really tricky if
you're using <code>macro_rules!</code>, so you might need to move up to a full
<code>proc_macro</code>. Having a <code>proc_macro</code> isn't bad except that they have to be
defined in a crate of their own and they're compiled before use. You can't
ever use them in the crate that defines them, so we won't be using them in any
of our single file examples.</li>
<li>Allowing for optional <code>Deref</code> and <code>DerefMut</code> of the inner value. This takes
away most all the safety aspect of doing the newtype, but there may be times
for it. As an example, you could make a newtype with a different form of
Display impl that you want to otherwise treat as the base type in all places.</li>
</ul>
<a class="header" href="#constant-assertions" id="constant-assertions"><h1>Constant Assertions</h1></a>
<p>Have you ever wanted to assert things <em>even before runtime</em>? We all have, of
course. Particularly when the runtime machine is a poor little GBA, we'd like to
have the machine doing the compile handle as much checking as possible.</p>
<p>Enter the <a href="https://docs.rs/static_assertions/">static assertions</a> crate, which
provides a way to let you assert on a <code>const</code> expression.</p>
<p>This is an amazing crate that you should definitely use when you can.</p>
<p>It's written by <a href="https://github.com/nvzqz">Nikolai Vazquez</a>, and they kindly
wrote up a <a href="https://nikolaivazquez.com/posts/programming/rust-static-assertions/">blog
post</a> that
explains the thinking behind it.</p>
<p>However, I promised that each example would be single file, and I also promised
to explain what's going on as we go, so we'll briefly touch upon giving an
explanation here.</p>
<a class="header" href="#how-we-const-assert" id="how-we-const-assert"><h2>How We Const Assert</h2></a>
<p>Alright, as it stands (2018-12-15), we can't use <code>if</code> in a <code>const</code> context.</p>
<p>Since we can't use <code>if</code>, we can't use a normal <code>assert!</code>. Some day it will be
possible, and a failed assert at compile time will be a compile error and a
failed assert at run time will be a panic and we'll have a nice unified
programming experience. We can add runtime-only assertions by being a little
tricky with the compiler.</p>
<p>If we write</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
const ASSERT: usize = 0 - 1;
#}</code></pre></pre>
<p>that gives a warning, since the math would underflow. We can upgrade that
warning to a hard error:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[deny(const_err)]
const ASSERT: usize = 0 - 1;
#}</code></pre></pre>
<p>And to make our construction reusable we can enable the
<a href="https://github.com/rust-lang/rust/issues/54912">underscore_const_names</a> feature
in our program (or library) and then give each such const an underscore for a
name.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#![feature(underscore_const_names)]
#fn main() {
#[deny(const_err)]
const _: usize = 0 - 1;
#}</code></pre></pre>
<p>Now we wrap this in a macro where we give a <code>bool</code> expression as input. We
negate the bool then cast it to a <code>usize</code>, meaning that <code>true</code> negates into
<code>false</code>, which becomes <code>0usize</code>, and then there's no underflow error. Or if the
input was <code>false</code>, it negates into <code>true</code>, then becomes <code>1usize</code>, and then the
underflow error fires.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
macro_rules! const_assert {
($condition:expr) =&gt; {
#[deny(const_err)]
#[allow(dead_code)]
const ASSERT: usize = 0 - !$condition as usize;
}
}
#}</code></pre></pre>
<p>Technically, written like this, the expression can be anything with a
<code>core::ops::Not</code> implementation that can also be <code>as</code> cast into <code>usize</code>. That's
<code>bool</code>, but also basically all the other number types. Since we want to ensure
that we get proper looking type errors when things go wrong, we can use
<code>($condition &amp;&amp; true)</code> to enforce that we get a <code>bool</code> (thanks to <code>Talchas</code> for
that particular suggestion).</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
macro_rules! const_assert {
($condition:expr) =&gt; {
#[deny(const_err)]
#[allow(dead_code)]
const _: usize = 0 - !($condition &amp;&amp; true) as usize;
}
}
#}</code></pre></pre>
<a class="header" href="#asserting-something" id="asserting-something"><h2>Asserting Something</h2></a>
<p>As an example of how we might use a <code>const_assert</code>, we'll do a demo with colors.
There's a red, blue, and green channel. We store colors in a <code>u16</code> with 5 bits
for each channel.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
newtype! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Color, u16
}
#}</code></pre></pre>
<p>And when we're building a color, we're passing in <code>u16</code> values, but they could
be using more than just 5 bits of space. We want to make sure that each channel
is 31 or less, so we can make a color builder that does a <code>const_assert!</code> on the
value of each channel.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
macro_rules! rgb {
($r:expr, $g:expr, $b:expr) =&gt; {
{
const_assert!($r &lt;= 31);
const_assert!($g &lt;= 31);
const_assert!($b &lt;= 31);
Color($b &lt;&lt; 10 | $g &lt;&lt; 5 | $r)
}
}
}
#}</code></pre></pre>
<p>And then we can declare some colors</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
const RED: Color = rgb!(31, 0, 0);
const BLUE: Color = rgb!(31, 500, 0);
#}</code></pre></pre>
<p>The second one is clearly out of bounds and it fires an error just like we
wanted.</p>
<a class="header" href="#broad-concepts" id="broad-concepts"><h1>Broad Concepts</h1></a>
<p>The GameBoy Advance sits in a middle place between the chthonic game consoles of
the ancient past and the &quot;small PC in a funny case&quot; consoles of the modern age.</p>
<p>On the one hand, yeah, you're gonna find a few strange conventions as you learn
all the ropes.</p>
<p>On the other, at least we're writing in Rust at all, and not having to do all
the assembly by hand.</p>
<p>This chapter for &quot;concepts&quot; has a section for each part of the GBA's hardware
memory map, going by increasing order of base address value. The sections try to
explain as much as possible while sticking to just the concerns you might have
regarding that part of the memory map.</p>
<p>For an assessment of how to wrangle all three parts of the video system (PALRAM,
VRAM, and OAM), along with the correct IO registers, into something that shows a
picture, you'll want the Video chapter.</p>
<p>Similarly, the &quot;IO Registers&quot; part of the GBA actually controls how you interact
with every single bit of hardware connected to the GBA. A full description of
everything is obviously too much for just one section of the book. Instead you
get an overview of general IO register rules and advice. Each particular
register is described in the appropriate sections of either the Video or
Non-Video chapters.</p>
<a class="header" href="#bus-size" id="bus-size"><h2>Bus Size</h2></a>
<p>TODO: describe this</p>
<a class="header" href="#minimum-write-size" id="minimum-write-size"><h2>Minimum Write Size</h2></a>
<p>TODO: talk about parts where you can't write one byte at a time</p>
<a class="header" href="#volatile-or-not" id="volatile-or-not"><h2>Volatile or Not?</h2></a>
<p>TODO: discuss what memory should be used volatile style and what can be used normal style.</p>
<a class="header" href="#cpu" id="cpu"><h1>CPU</h1></a>
<a class="header" href="#bios" id="bios"><h1>BIOS</h1></a>
<ul>
<li><strong>Address Span:</strong> <code>0x0</code> to <code>0x3FFF</code> (16k)</li>
</ul>
<p>The <a href="https://en.wikipedia.org/wiki/BIOS">BIOS</a> of the GBA is a small read-only
portion of memory at the very base of the address space. However, it is also
hardware protected against reading, so if you try to read from BIOS memory when
the program counter isn't pointed into the BIOS (eg: any time code <em>you</em> write
is executing) then you get <a href="https://problemkaputt.de/gbatek.htm#gbaunpredictablethings">basically garbage
data</a> back.</p>
<p>So we're not going to spend time here talking about what bits to read or write
within BIOS memory like we do with the other sections. Instead we're going to
spend time talking about <a href="https://doc.rust-lang.org/unstable-book/language-features/asm.html">inline
assembly</a>
(<a href="https://github.com/rust-lang/rust/issues/29722">tracking issue</a>) and then use
it to call the <a href="https://problemkaputt.de/gbatek.htm#biosfunctions">GBA BIOS
Functions</a>.</p>
<p>Note that BIOS calls have <em>more overhead than normal function calls</em>, so don't
go using them all over the place if you don't have to. They're also usually
written more to be compact in terms of code than for raw speed, so you actually
can out speed them in some cases. Between the increased overhead and not being
as speed optimized, you can sometimes do a faster job without calling the BIOS
at all. (TODO: investigate more about what parts of the BIOS we could
potentially offer faster alternatives for.)</p>
<p>I'd like to take a moment to thank <a href="https://github.com/mbr">Marc Brinkmann</a>
(with contributions from <a href="https://github.com/oli-obk">Oliver Schneider</a> and
<a href="https://github.com/phil-opp">Philipp Oppermann</a>) for writing <a href="http://embed.rs/articles/2016/arm-inline-assembly-rust/">this blog
post</a>. It's at least
ten times the tutorial quality as the <code>asm</code> entry in the Unstable Book has. In
fairness to the Unstable Book, the actual spec of how inline ASM works in rust
is &quot;basically what clang does&quot;, and that's specified as &quot;basically what GCC
does&quot;, and that's basically/shockingly not specified much at all despite GCC
being like 30 years old.</p>
<p>So let's be slow and pedantic about this process.</p>
<a class="header" href="#inline-asm" id="inline-asm"><h2>Inline ASM</h2></a>
<p><strong>Fair Warning:</strong> Inline asm is one of the least stable parts of Rust overall,
and if you write bad things you can trigger internal compiler errors and panics
and crashes and make LLVM choke and die without explanation. If you write some
inline asm and then suddenly your program suddenly stops compiling without
explanation, try commenting out that whole inline asm use and see if it's
causing the problem. Double check that you've written every single part of the
asm call absolutely correctly, etc, etc.</p>
<p><strong>Bonus Warning:</strong> The general information that follows regarding the asm macro
is consistent from system to system, but specific information about register
names, register quantities, asm instruction argument ordering, and so on is
specific to ARM on the GBA. If you're programming for any other device you'll
need to carefully investigate that before you begin.</p>
<p>Now then, with those out of the way, the inline asm docs describe an asm call as
looking like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
asm!(assembly template
: output operands
: input operands
: clobbers
: options
);
#}</code></pre></pre>
<p>And once you stick a lot of stuff in there it can <em>absolutely</em> be hard to
remember the ordering of the elements. So we'll start with a code block that
has some comments thrown in on each line:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
asm!(/* ASM */ TODO
:/* OUT */ TODO
:/* INP */ TODO
:/* CLO */ TODO
:/* OPT */
);
#}</code></pre></pre>
<p>Now we have to decide what we're gonna write. Obviously we're going to do some
instructions, but those instructions use registers, and how are we gonna talk
about them? We've got two choices.</p>
<ol>
<li>
<p>We can pick each and every register used by specifying exact register names.
In THUMB mode we have 8 registers available, named <code>r0</code> through <code>r7</code>. If you
switch into 32-bit mode there's additional registers that are also available.</p>
</li>
<li>
<p>We can specify slots for registers we need and let LLVM decide. In this style
you name your slots <code>$0</code>, <code>$1</code> and so on. Slot numbers are assigned first to
all specified outputs, then to all specified inputs, in the order that you
list them.</p>
</li>
</ol>
<p>In the case of the GBA BIOS, each BIOS function has pre-designated input and
output registers, so we will use the first style. If you use inline ASM in other
parts of your code you're free to use the second style.</p>
<a class="header" href="#assembly" id="assembly"><h3>Assembly</h3></a>
<p>This is just one big string literal. You write out one instruction per line, and
excess whitespace is ignored. You can also do comments within your assembly
using <code>;</code> to start a comment that goes until the end of the line.</p>
<p>Assembly convention doesn't consider it unreasonable to comment potentially as
much as <em>every single line</em> of asm that you write when you're getting used to
things. Or even if you are used to things. This is cryptic stuff, there's a
reason we avoid writing in it as much as possible.</p>
<p>Remember that our Rust code is in 16-bit mode. You <em>can</em> switch to 32-bit mode
within your asm as long as you switch back by the time the block ends. Otherwise
you'll have a bad time.</p>
<a class="header" href="#outputs" id="outputs"><h3>Outputs</h3></a>
<p>A comma separated list. Each entry looks like</p>
<ul>
<li><code>&quot;constraint&quot; (binding)</code></li>
</ul>
<p>An output constraint starts with a symbol:</p>
<ul>
<li><code>=</code> for write only</li>
<li><code>+</code> for reads and writes</li>
<li><code>&amp;</code> for for &quot;early clobber&quot;, meaning that you'll write to this at some point
before all input values have been read. It prevents this register from being
assigned to an input register.</li>
</ul>
<p>Followed by <em>either</em> the letter <code>r</code> (if you want LLVM to pick the register to
use) or curly braces around a specific register (if you want to pick).</p>
<ul>
<li>The binding can be any single 32-bit or smaller value.</li>
<li>If your binding has bit pattern requirements (&quot;must be non-zero&quot;, etc) you are
responsible for upholding that.</li>
<li>If your binding type will try to <code>Drop</code> later then you are responsible for it
being in a fit state to do that.</li>
<li>The binding must be either a mutable binding or a binding that was
pre-declared but not yet assigned.</li>
</ul>
<p>Anything else is UB.</p>
<a class="header" href="#inputs" id="inputs"><h3>Inputs</h3></a>
<p>This is a similar comma separated list.</p>
<ul>
<li><code>&quot;constraint&quot; (binding)</code></li>
</ul>
<p>An input constraint doesn't have the symbol prefix, you just pick either <code>r</code> or
a named register with curly braces around it.</p>
<ul>
<li>An input binding must be a single 32-bit or smaller value.</li>
<li>An input binding <em>should</em> be a type that is <code>Copy</code> but this is not an absolute
requirement. Having the input be read is semantically similar to using
<code>core::ptr::read(&amp;binding)</code> and forgetting the value when you're done.</li>
</ul>
<a class="header" href="#clobbers" id="clobbers"><h3>Clobbers</h3></a>
<p>Sometimes your asm will touch registers other than the ones declared for input
and output.</p>
<p>Clobbers are declared as a comma separated list of string literals naming
specific registers. You don't use curly braces with clobbers.</p>
<p>LLVM <em>needs</em> to know this information. It can move things around to keep your
data safe, but only if you tell it what's about to happen.</p>
<p>Failure to define all of your clobbers can cause UB.</p>
<a class="header" href="#options" id="options"><h3>Options</h3></a>
<p>There's only one option we'd care to specify. That option is &quot;volatile&quot;.</p>
<p>Just like with a function call, LLVM will skip a block of asm if it doesn't see
that any outputs from the asm were used later on. Nearly every single BIOS call
(other than the math operations) will need to be marked as &quot;volatile&quot;.</p>
<a class="header" href="#bios-asm" id="bios-asm"><h3>BIOS ASM</h3></a>
<ul>
<li>Inputs are always <code>r0</code>, <code>r1</code>, <code>r2</code>, and/or <code>r3</code>, depending on function.</li>
<li>Outputs are always zero or more of <code>r0</code>, <code>r1</code>, and <code>r3</code>.</li>
<li>Any of the output registers that aren't actually used should be marked as
clobbered.</li>
<li>All other registers are unaffected.</li>
</ul>
<p>All of the GBA BIOS calls are performed using the
<a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0068b/BABFCEEG.html">swi</a>
instruction, combined with a value depending on what BIOS function you're trying
to invoke. If you're in 16-bit code you use the value directly, and if you're in
32-bit mode you shift the value up by 16 bits first.</p>
<a class="header" href="#example-bios-function-division" id="example-bios-function-division"><h3>Example BIOS Function: Division</h3></a>
<p>For our example we'll use the division function, because GBATEK gives very clear
instructions on how each register is used with that one:</p>
<pre><code class="language-txt">Signed Division, r0/r1.
r0 signed 32bit Number
r1 signed 32bit Denom
Return:
r0 Number DIV Denom ;signed
r1 Number MOD Denom ;signed
r3 ABS (Number DIV Denom) ;unsigned
For example, incoming -1234, 10 should return -123, -4, +123.
The function usually gets caught in an endless loop upon division by zero.
</code></pre>
<p>The math folks tell me that the <code>r1</code> value should be properly called the
&quot;remainder&quot; not the &quot;modulus&quot;. We'll go with that for our function, doesn't hurt
to use the correct names. Our Rust function has an assert against dividing by
<code>0</code>, then we name some bindings <em>without</em> giving them a value, we make the asm
call, and then return what we got.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub fn div_rem(numerator: i32, denominator: i32) -&gt; (i32, i32) {
assert!(denominator != 0);
let div_out: i32;
let rem_out: i32;
unsafe {
asm!(/* ASM */ &quot;swi 0x06&quot;
:/* OUT */ &quot;={r0}&quot;(div_out), &quot;={r1}&quot;(rem_out)
:/* INP */ &quot;{r0}&quot;(numerator), &quot;{r1}&quot;(denominator)
:/* CLO */ &quot;r3&quot;
:/* OPT */
);
}
(div_out, rem_out)
}
#}</code></pre></pre>
<p>I <em>hope</em> this all makes sense by now.</p>
<a class="header" href="#specific-bios-functions" id="specific-bios-functions"><h2>Specific BIOS Functions</h2></a>
<p>For a full list of all the specific BIOS functions and their use you should
check the <code>gba::bios</code> module within the <code>gba</code> crate. There's just so many of
them that enumerating them all here wouldn't serve much purpose.</p>
<p>Which is not to say that we'll never cover any BIOS functions in this book!
Instead, we'll simply mention them when whenever they're relevent to the task at
hand (such as controlling sound or waiting for vblank).</p>
<p>//TODO: list/name all BIOS functions as well as what they relate to elsewhere.</p>
<a class="header" href="#work-ram" id="work-ram"><h1>Work RAM</h1></a>
<a class="header" href="#external-work-ram-ewram" id="external-work-ram-ewram"><h2>External Work RAM (EWRAM)</h2></a>
<ul>
<li><strong>Address Span:</strong> <code>0x2000000</code> to <code>0x203FFFF</code> (256k)</li>
</ul>
<p>This is a big pile of space, the use of which is up to each game. However, the
external work ram has only a 16-bit bus (if you read/write a 32-bit value it
silently breaks it up into two 16-bit operations) and also 2 wait cycles (extra
CPU cycles that you have to expend <em>per 16-bit bus use</em>).</p>
<p>It's most helpful to think of EWRAM as slower, distant memory, similar to the
&quot;heap&quot; in a normal application. You can take the time to go store something
within EWRAM, or to load it out of EWRAM, but if you've got several operations
to do in a row and you're worried about time you should pull that value into
local memory, work on your local copy, and then push it back out to EWRAM.</p>
<a class="header" href="#internal-work-ram-iwram" id="internal-work-ram-iwram"><h2>Internal Work RAM (IWRAM)</h2></a>
<ul>
<li><strong>Address Span:</strong> <code>0x3000000</code> to <code>0x3007FFF</code> (32k)</li>
</ul>
<p>This is a smaller pile of space, but it has a 32-bit bus and no wait.</p>
<p>By default, <code>0x3007F00</code> to <code>0x3007FFF</code> is reserved for interrupt and BIOS use.
The rest of it is mostly up to you. The user's stack space starts at <code>0x3007F00</code>
and proceeds <em>down</em> from there. For best results you should probably start at
<code>0x3000000</code> and then go upwards. Under normal use it's unlikely that the two
memory regions will crash into each other.</p>
<a class="header" href="#io-registers" id="io-registers"><h1>IO Registers</h1></a>
<ul>
<li><strong>Address Span:</strong> <code>0x400_0000</code> to <code>0x400_03FE</code></li>
</ul>
<a class="header" href="#palette-ram-palram" id="palette-ram-palram"><h1>Palette RAM (PALRAM)</h1></a>
<ul>
<li><strong>Address Span:</strong> <code>0x500_0000</code> to <code>0x500_03FF</code> (1k)</li>
</ul>
<p>Palette RAM has a 16-bit bus, which isn't really a problem because it
conceptually just holds <code>u16</code> values. There's no automatic wait state, but if
you try to access the same location that the display controller is accessing you
get bumped by 1 cycle. Since the display controller can use the palette ram any
number of times per scanline it's basically impossible to predict if you'll have
to do a wait or not during VDraw. During VBlank you won't have any wait of
course.</p>
<p>PALRAM is among the memory where there's weirdness if you try to write just one
byte: if you try to write just 1 byte, it writes that byte into <em>both</em> parts of
the larger 16-bit location. This doesn't really affect us much with PALRAM,
because palette values are all supposed to be <code>u16</code> anyway.</p>
<p>The palette memory actually contains not one, but <em>two</em> sets of palettes. First
there's 256 entries for the background palette data (starting at <code>0x5000000</code>),
and then there's 256 entries for object palette data (starting at <code>0x5000200</code>).</p>
<p>The GBA also has two modes for palette access: 8-bits-per-pixel (8bpp) and
4-bits-per-pixel (4bpp).</p>
<ul>
<li>In 8bpp mode an 8-bit palette index value within a background or sprite
simply indexes directly into the 256 slots for that type of thing.</li>
<li>In 4bpp mode a 4-bit palette index value within a background or sprite
specifies an index within a particular &quot;palbank&quot; (16 palette entries each),
and then a <em>separate</em> setting outside of the graphical data determines which
palbank is to be used for that background or object (the screen entry data for
backgrounds, and the object attributes for objects).</li>
</ul>
<a class="header" href="#transparency" id="transparency"><h3>Transparency</h3></a>
<p>When a pixel within a background or object specifies index 0 as its palette
entry it is treated as a transparent pixel. This means that in 8bpp mode there's
only 255 actual color options (0 being transparent), and in 4bpp mode there's
only 15 actual color options available within each palbank (the 0th entry of
<em>each</em> palbank is transparent).</p>
<p>Individual backgrounds, and individual objects, each determine if they're 4bpp
or 8bpp separately, so a given overall palette slot might map to a used color in
8bpp and an unused/transparent color in 4bpp. If you're a palette wizard.</p>
<p>Palette slot 0 of the overall background palette is used to determine the
&quot;backdrop&quot; color. That's the color you see if no background or object ends up
being rendered within a given pixel.</p>
<p>Since display mode 3 and display mode 5 don't use the palette, they cannot
benefit from transparency.</p>
<a class="header" href="#video-ram-vram" id="video-ram-vram"><h1>Video RAM (VRAM)</h1></a>
<ul>
<li><strong>Address Span:</strong> <code>0x600_0000</code> to <code>0x601_7FFF</code> (96k)</li>
</ul>
<p>We've used this before! VRAM has a 16-bit bus and no wait. However, the same as
with PALRAM, the &quot;you might have to wait if the display controller is looking at
it&quot; rule applies here.</p>
<p>Unfortunately there's not much more exact detail that can be given about VRAM.
The use of the memory depends on the video mode that you're using.</p>
<p>One general detail of note is that you can't write individual bytes to any part
of VRAM. Depending on mode and location, you'll either get your bytes doubled
into both the upper and lower parts of the 16-bit location targeted, or you
won't even affect the memory. This usually isn't a big deal, except in two
situations:</p>
<ul>
<li>In Mode 4, if you want to change just 1 pixel, you'll have to be very careful
to read the old <code>u16</code>, overwrite just the byte you wanted to change, and then
write that back.</li>
<li>In any display mode, avoid using <code>memcopy</code> to place things into VRAM.
It's written to be byte oriented, and only does 32-bit transfers under select
conditions. The rest of the time it'll copy one byte at a time and you'll get
either garbage or nothing at all.</li>
</ul>
<a class="header" href="#object-attribute-memory-oam" id="object-attribute-memory-oam"><h1>Object Attribute Memory (OAM)</h1></a>
<ul>
<li><strong>Address Span:</strong> <code>0x700_0000</code> to <code>0x700_03FF</code> (1k)</li>
</ul>
<p>The Object Attribute Memory has a 32-bit bus and no default wait, but suffers
from the &quot;you might have to wait if the display controller is looking at it&quot;
rule. You cannot write individual bytes to OAM at all, but that's not really a
problem because all the fields of the data types within OAM are either <code>i16</code> or
<code>u16</code> anyway.</p>
<p>Object attribute memory is the wildest yet: it conceptually contains two types
of things, but they're <em>interlaced</em> with each other all the way through.</p>
<p>Now, <a href="http://problemkaputt.de/gbatek.htm#lcdobjoamattributes">GBATEK</a> and
<a href="https://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm#OAM%20(sprites)">CowByte</a>
doesn't quite give names to the two data types here.
<a href="https://www.coranac.com/tonc/text/regobj.htm#sec-oam">TONC</a> calls them
<code>OBJ_ATTR</code> and <code>OBJ_AFFINE</code>, but we'll be giving them names fitting with the
Rust naming convention. Just know that if you try to talk about it with others
they might not be using the same names. In Rust terms their layout would look
like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[repr(C)]
pub struct ObjectAttributes {
attr0: u16,
attr1: u16,
attr2: u16,
filler: i16,
}
#[repr(C)]
pub struct AffineMatrix {
filler0: [u16; 3],
pa: i16,
filler1: [u16; 3],
pb: i16,
filler2: [u16; 3],
pc: i16,
filler3: [u16; 3],
pd: i16,
}
#}</code></pre></pre>
<p>(Note: the <code>#[repr(C)]</code> part just means that Rust must lay out the data exactly
in the order we specify, which otherwise it is not required to do).</p>
<p>So, we've got 1024 bytes in OAM and each <code>ObjectAttributes</code> value is 8 bytes, so
naturally we can support up to 128 objects.</p>
<p><em>At the same time</em>, we've got 1024 bytes in OAM and each <code>AffineMatrix</code> is 32
bytes, so we can have 32 of them.</p>
<p>But, as I said, these things are all <em>interlaced</em> with each other. See how
there's &quot;filler&quot; fields in each struct? If we imagine the OAM as being just an
array of one type or the other, indexes 0/1/2/3 of the <code>ObjectAttributes</code> array
would line up with index 0 of the <code>AffineMatrix</code> array. It's kinda weird, but
that's just how it works. When we setup functions to read and write these values
we'll have to be careful with how we do it. We probably <em>won't</em> want to use
those representations above, at least not with the <code>AffineMatrix</code> type, because
they're quite wasteful if you want to store just object attributes or just
affine matrices.</p>
<a class="header" href="#game-pak-rom--flash-rom-rom" id="game-pak-rom--flash-rom-rom"><h1>Game Pak ROM / Flash ROM (ROM)</h1></a>
<ul>
<li><strong>Address Span (Wait State 0):</strong> <code>0x800_0000</code> to <code>0x9FF_FFFF</code></li>
<li><strong>Address Span (Wait State 1):</strong> <code>0xA00_0000</code> to <code>0xBFF_FFFF</code></li>
<li><strong>Address Span (Wait State 2):</strong> <code>0xC00_0000</code> to <code>0xDFF_FFFF</code></li>
</ul>
<p>The game's ROM data is a single set of data that's up to 32 megabytes in size.
However, that data is mirrored to three different locations in the address
space. Depending on which part of the address space you use, it can affect the
memory timings involved.</p>
<p>TODO: describe <code>WAITCNT</code> here, we won't get a better chance at it.</p>
<p>TODO: discuss THUMB vs ARM code and why THUMB is so much faster (because ROM is a 16-bit bus)</p>
<a class="header" href="#save-ram-sram" id="save-ram-sram"><h1>Save RAM (SRAM)</h1></a>
<ul>
<li><strong>Address Span:</strong> <code>0xE00_0000</code> to <code>0xE00FFFF</code> (64k)</li>
</ul>
<p>The actual amount of SRAM available depends on your game pak, and the 64k figure
is simply the maximum possible. A particular game pak might have less, and an
emulator will likely let you have all 64k if you want.</p>
<p>As with other portions of the address space, SRAM has some number of wait cycles
per use. As with ROM, you can change the wait cycle settings via the <code>WAITCNT</code>
register if the defaults don't work well for your game pak. See the ROM section
for full details of how the <code>WAITCNT</code> register works.</p>
<p>The game pak SRAM also has only an 8-bit bus, so have fun with that.</p>
<p>The GBA Direct Memory Access (DMA) unit cannot access SRAM.</p>
<p>Also, you <a href="https://problemkaputt.de/gbatek.htm#gbacartbackupsramfram">should not write to SRAM with code executing from
ROM</a>. Instead, you
should move the code to WRAM and execute the save code from there. We'll cover
how to handle that eventually.</p>
<a class="header" href="#video" id="video"><h1>Video</h1></a>
<p>GBA Video starts with an IO register called the &quot;Display Control Register&quot;, and
then spirals out from there. You generally have to use Palette RAM (PALRAM),
Video RAM (VRAM), Object Attribute Memory (OAM), as well as any number of other
IO registers.</p>
<p>They all have to work together just right, and there's a lot going on when you
first try doing it, so try to take it very slowly as you're learning each step.</p>
<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>
<p>Besides video effects the GBA still has an okay amount of stuff going on.</p>
<p>Obviously you'll want to know how to read the user's button inputs. That can
almost go without saying, except that I said it.</p>
<p>Each other part can be handled in about any order you like.</p>
<p>Using interrupts is perhaps one of the hardest things for us as Rust programmers
due to quirks in our compilation process. Our code all gets compiled to 16-bit
THUMB instructions, and we don't have a way to mark a function to be compiled
using 32-bit ASM instructions instead. However, an interrupt handler <em>must</em> be
written in 32-bit ASM instructions for it to work. That means that we have to
write our interrupt handler in 32-bit ASM by hand. We'll do it, but I don't
think we'll be too happy about it.</p>
<p>The Link Cable related stuff is also probably a little harder to test than
anything else. Just because link cable emulation isn't always the best, and or
you need two GBAs with two flash carts and the cable for hardware testing.
Still, we'll try to go over it eventually.</p>
<a class="header" href="#buttons" id="buttons"><h1>Buttons</h1></a>
<p>It's all well and good to just show a picture, even to show an animation, but if
we want a game we have to let the user interact with something.</p>
<a class="header" href="#key-input-register" id="key-input-register"><h2>Key Input Register</h2></a>
<ul>
<li>KEYINPUT, <code>0x400_0130</code>, <code>u16</code>, read only</li>
</ul>
<p>This little <code>u16</code> stores the status of <em>all</em> the buttons on the GBA, all at
once. There's only 10 of them, and we have 16 bits to work with, so that sounds
easy. However, there's a bit of a catch. The register follows a &quot;low-active&quot;
convention, where pressing a button <em>clears</em> that bit until it's released.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
const NO_BUTTONS_PRESSED: u16 = 0b0000_0011_1111_1111;
#}</code></pre></pre>
<p>The buttons are, going up in order from the 0th bit:</p>
<ul>
<li>A</li>
<li>B</li>
<li>Select</li>
<li>Start</li>
<li>Right</li>
<li>Left</li>
<li>Up</li>
<li>Down</li>
<li>R</li>
<li>L</li>
</ul>
<p>Bits above that are not used. However, since the left and right directions, as
well as the up and down directions, can never be pressed at the same time, the
<code>KEYINPUT</code> register should never read as zero. Of course, the register <em>might</em>
read as zero if someone is using an emulator that allows for such inputs, so I
wouldn't go so far as to make it be <code>NonZeroU16</code> or anything like that.</p>
<p>When programming, we usually are thinking of what buttons we want to have <em>be
pressed</em> instead of buttons we want to have <em>not be pressed</em>. This means that we
need an inversion to happen somewhere along the line. The easiest moment of
inversion is immediately as you read in from the register and wrap the value up
in a newtype.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub fn read_key_input() -&gt; KeyInput {
KeyInput(KEYINPUT.read() ^ 0b0000_0011_1111_1111)
}
#}</code></pre></pre>
<p>Now the KeyInput you get can be checked for what buttons are pressed by checking
for a set bit like you'd do anywhere else.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
impl KeyInput {
pub fn a_pressed(self) -&gt; bool {
(self.0 &amp; A_BIT) &gt; 0
}
}
#}</code></pre></pre>
<p>Note that the current <code>KEYINPUT</code> value changes in real time as the user presses
or releases the buttons. To account for this, it's best to read the value just
once per game frame and then use that single value as if it was the input across
the whole frame. If you've worked with polling input before that should sound
totally normal. If not, just remember to call <code>read_key_input</code> once per frame
and then use that <code>KeyInput</code> value across the whole frame.</p>
<a class="header" href="#detecting-new-presses" id="detecting-new-presses"><h3>Detecting New Presses</h3></a>
<p>The keypad only tells you what's <em>currently</em> pressed, but if you want to check
what's <em>newly</em> pressed it's not too much harder.</p>
<p>All that you do is store the last frame's keys and compare them to the current
keys with an <code>XOR</code>. In the <code>gba</code> crate it's called <code>KeyInput::difference</code>. Once
you've got the difference between last frame and this frame, you know what
changes happened.</p>
<ul>
<li>If something is in the difference and <em>not pressed</em> in the last frame, that
means it was newly pressed.</li>
<li>If something is in the difference and <em>pressed</em> in the last frame that means
it was newly released.</li>
<li>If something is not in the difference then there's no change between last
frame and this frame.</li>
</ul>
<a class="header" href="#key-interrupt-control" id="key-interrupt-control"><h2>Key Interrupt Control</h2></a>
<ul>
<li>KEYCNT, <code>0x400_0132</code>, <code>u16</code>, read/write</li>
</ul>
<p>This lets you control what keys will trigger a keypad interrupt. Of course, for
the actual interrupt to fire you also need to set the <code>IME</code> and <code>IE</code> registers
properly. See the <a href="05-interrupts.html">Interrupts</a> section for details there.</p>
<p>The main thing to know about this register is that the keys are in <em>the exact
same order</em> as the key input order. However, with this register they use a
high-active convention instead (eg: the bit is active when the button should be
pressed as part of the interrupt).</p>
<p>In addition to simply having the bits for the buttons, bit 14 is a flag for
enabling keypad interrupts (in addition to the flag in the <code>IE</code> register), and
bit 15 decides how having more than one button works. If bit 15 is disabled,
it's an OR combination (eg: &quot;press any key to continue&quot;). If bit 15 is enabled
it's an AND combination (eg: &quot;press A+B+Start+Select to reset&quot;).</p>
<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="#link-cable" id="link-cable"><h1>Link Cable</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>
</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>