make docs be hosted in a separate branch

This commit is contained in:
Lokathor 2019-01-02 20:27:15 -07:00
parent e0c76417b3
commit 70b752f82b
6 changed files with 4 additions and 1562 deletions

View file

@ -44,10 +44,10 @@ script:
deploy: deploy:
provider: pages provider: pages
local-dir: target/book-output
skip-cleanup: true skip-cleanup: true
github-token: $GITHUB_TOKEN github-token: $GITHUB_TOKEN
target-branch: master keep-history: false
keep-history: true
name: DocsBot name: DocsBot
verbose: true verbose: true
on: on:

View file

@ -9,7 +9,7 @@ keywords = ["gba"]
edition = "2018" edition = "2018"
license = "Apache-2.0" license = "Apache-2.0"
#publish = false publish = false
[dependencies] [dependencies]
typenum = "1.10" typenum = "1.10"

View file

@ -3,5 +3,5 @@ title = "Rust GBA Guide"
authors = ["Lokathor"] authors = ["Lokathor"]
[build] [build]
build-dir = "../docs" build-dir = "../target/book-output"
create-missing = true create-missing = true

View file

@ -1,339 +0,0 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>No Std - 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" class="active"><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="#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>If our code panics, we usually want to see that panic message. Unfortunately,
without a way to access something like <code>stdout</code> or <code>stderr</code> we've gotta do
something a little weirder.</p>
<p>If our program is running within the <code>mGBA</code> emulator, version 0.7 or later, we
can access a special set of addresses that allow us to send out <code>CString</code>
values, which then appear within a message log that you can check.</p>
<p>We can capture this behavior by making an <code>MGBADebug</code> type, and then implement
<code>core::fmt::Write</code> for that type. Once done, the <code>write!</code> macro will let us
target the mGBA debug output channel.</p>
<p>When used, it looks like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[panic_handler]
fn panic(info: &amp;core::panic::PanicInfo) -&gt; ! {
use core::fmt::Write;
use gba::mgba::{MGBADebug, MGBADebugLevel};
if let Some(mut mgba) = MGBADebug::new() {
let _ = write!(mgba, &quot;{}&quot;, info);
mgba.send(MGBADebugLevel::Fatal);
}
loop {}
}
#}</code></pre></pre>
<p>If you want to follow the particulars you can check the <code>MGBADebug</code> source in
the <code>gba</code> crate. Basically, there's one address you can use to try and activate
the debug output, and if it works you write your message into the &quot;array&quot; at
another address, and then finally write a send value to a third address. You'll
need to have read the <a href="03-volatile_destination.html">volatile</a> section for the
details to make sense.</p>
<a class="header" href="#llvm-intrinsics" id="llvm-intrinsics"><h2>LLVM Intrinsics</h2></a>
<p>The above code will make your program fail to build in debug mode, saying that
<code>__clzsi2</code> can't be found. This is a special builtin function that LLVM attempts
to use when there's no hardware version of an operation it wants to do (in this
case, counting the leading zeros). It's not <em>actually</em> necessary in this case,
which is why you only need it in debug mode. The higher optimization level of
release mode makes LLVM pre-compute more and fold more constants or whatever and
then it stops trying to call <code>__clzsi2</code>.</p>
<p>Unfortunately, sometimes a build will fail with a missing intrinsic even in
release mode.</p>
<p>If LLVM wants <em>core</em> to have that intrinsic then you're in
trouble, you'll have to send a PR to the
<a href="https://github.com/rust-lang-nursery/compiler-builtins">compiler-builtins</a>
repository and hope to get it into rust itself.</p>
<p>If LLVM wants <em>your code</em> to have the intrinsic then you're in less trouble. You
can look up the details and then implement it yourself. It can go anywhere in
your program, as long as it has the right ABI and name. In the case of
<code>__clzsi2</code> it takes a <code>usize</code> and returns a <code>usize</code>, so you'd write something
like:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[no_mangle]
pub extern &quot;C&quot; fn __clzsi2(mut x: usize) -&gt; usize {
//
}
#}</code></pre></pre>
<p>And so on for whatever other missing intrinsic.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../01-quirks/00-index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../01-quirks/02-fixed_only.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../01-quirks/00-index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a href="../01-quirks/02-fixed_only.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</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 -->
</body>
</html>

View file

@ -1,698 +0,0 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Fixed Only - 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" class="active"><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="#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>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../01-quirks/01-no_std.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../01-quirks/03-volatile_destination.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../01-quirks/01-no_std.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a href="../01-quirks/03-volatile_destination.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</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 -->
</body>
</html>

View file

@ -1,521 +0,0 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Volatile Destination - 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" class="active"><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="#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>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../01-quirks/02-fixed_only.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../01-quirks/04-newtype.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../01-quirks/02-fixed_only.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a href="../01-quirks/04-newtype.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</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 -->
</body>
</html>