mirror of
https://github.com/italicsjenga/gba.git
synced 2025-01-26 01:16:33 +11:00
293 lines
16 KiB
HTML
293 lines
16 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="sidebar-visible no-js">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title>GBA Assembly - 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="development-setup.html"><strong aria-hidden="true">1.</strong> Development Setup</a></li><li><a href="gba-asm.html" class="active"><strong aria-hidden="true">2.</strong> GBA Assembly</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="#gba-assembly" id="gba-assembly"><h1>GBA Assembly</h1></a>
|
|
<p>On the GBA sometimes you just end up using assembly. Not a whole lot, but
|
|
sometimes. Accordingly, you should know how assembly works on the GBA.</p>
|
|
<ul>
|
|
<li>
|
|
<p>The <a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0210c/index.html">ARM Infocenter:
|
|
ARM7TDMI</a>
|
|
is the basic authority for reference information. The GBA has a CPU with the
|
|
<code>ARMv4</code> ISA, the <code>ARMv4T</code> variant, and specifically the <code>ARM7TDMI</code>
|
|
microarchitecture. Someone at ARM decided that having both <code>ARM#</code> and <code>ARMv#</code>
|
|
was a good way to <a href="https://en.wikichip.org/wiki/arm/versions">version things</a>,
|
|
even when the numbers don't match, and the rest of us have been sad ever
|
|
since. The link there will take you to the correct book within the big pile of
|
|
ARM books available within the ARM Infocenter. Note that there is also a <a href="http://infocenter.arm.com/help/topic/com.arm.doc.ddi0210c/DDI0210B.pdf">PDF
|
|
Version</a>
|
|
of the documentation available, if you'd like that.</p>
|
|
</li>
|
|
<li>
|
|
<p>The <a href="https://problemkaputt.de/gbatek.htm#armcpuoverview">GBATek: ARM CPU
|
|
Overview</a> also has quite a
|
|
bit of info. Most of it is somewhat a duplication of what you'd find in the
|
|
ARM Infocenter reference manual, but it's also somewhat specialized towards
|
|
the GBA's specifics. It's in the usual, uh, "sparse" style that GBATEK is
|
|
written in, so I wouldn't suggest that read it first.</p>
|
|
</li>
|
|
<li>
|
|
<p>The <a href="https://rust.godbolt.org/z/ndCnk3">Compiler Explorer</a> can be used to
|
|
quickly look at assembly output of your Rust code. That link there will load
|
|
up an essentially blank <code>no_std</code> file with <code>opt-level=3</code> set and targeting
|
|
<code>thumbv6m-none-eabi</code>. That's <em>not</em> the same as the GBA (it's two ISA revisions
|
|
later, ARMv6 instead of ARMv4), but it's the closest CPU target that ships
|
|
with rustc, so it's the closest you can get with the compiler explorer
|
|
website. If you're very dedicated I suppose you could setup a <a href="https://github.com/mattgodbolt/compiler-explorer#running-a-local-instance">local
|
|
instance</a>
|
|
of compiler explorer and then add the extra target definition and so on, but
|
|
that's <em>probably</em> overkill.</p>
|
|
</li>
|
|
</ul>
|
|
<a class="header" href="#arm-and-thumb" id="arm-and-thumb"><h2>ARM and THUMB</h2></a>
|
|
<p>The "T" part in <code>ARMv4T</code> and <code>ARM7TDMI</code> means "Thumb". An ARM chip that supports
|
|
Thumb mode has two different instruction sets instead of just one. The chip can
|
|
run in ARM mode with 32-bit instructions, or it can run in THUMB mode with
|
|
16-bit instructions. Apparently these modes are sometimes called <code>a32</code> and <code>t32</code>
|
|
in a more modern context, but I will stick with ARM and THUMB because that's
|
|
what other GBA references use (particularly GBATEK), and it's probably best to
|
|
be more in agreement with them than with stuff for Raspberry Pi programming or
|
|
whatever other modern ARM thing.</p>
|
|
<p>On the GBA, the memory bus that physically transfers data from the game pak into
|
|
the device is a 16-bit memory bus. This means that if you need to transfer more
|
|
than 16 bits at a time you have to do more than one transfer. Since we'd like
|
|
our instructions to get to the CPU as fast as possible, we compile the majority
|
|
of our program with the THUMB instruction set. The ARM reference says that with
|
|
THUMB instructions on a 16-bit memory bus system you get about 160% performance
|
|
compared to using ARM instructions. That's absolutely something we want to take
|
|
advantage of. Also, your THUMB compiled code is about 65% of the same code
|
|
compiled with ARM. Since a game ROM can only be 32MB total, and we're trying to
|
|
fit in images and sound too, we want to get space savings where we can.</p>
|
|
<p>You may wonder, why is the THUMB code 65% as large if the instructions
|
|
themselves are 50% as large, and why have ARM mode at all if there's such a
|
|
benefit to be had with THUMB? Well, THUMB mode doesn't support as many different
|
|
instructions as ARM mode does. Some lines of source code that can compile to a
|
|
single ARM instruction might need to compile into more than one THUMB
|
|
instruction. THUMB still has most of the really good instructions available, so
|
|
it all averages out to about 65%.</p>
|
|
<p>That said, some parts of a GBA program <em>must</em> be written in ARM mode. Also, ARM
|
|
mode does allow that increased instruction flexibility. So we <em>need</em> to use ARM
|
|
some of the time, and we might just <em>want</em> to use ARM even when we don't need
|
|
to. It is possible to switch modes on the fly, there's extremely minimal
|
|
overhead, even less than doing some function calls. The only problem is the
|
|
16-bit memory bus of the game pak giving us a needless speed penalty with our
|
|
ARM code. The CPU <em>executes</em> the ARM instructions at full speed, but then it has
|
|
to wait while more instructions get sent in. What do we do? Well, code is
|
|
ultimately just a different kind of data. We can copy parts of our code off the
|
|
game pak ROM and place it into a part of the RAM that has a 32-bit memory bus.
|
|
Then the CPU can execute the code from there, going at full speed. Of course,
|
|
there's only a very small amount of RAM compared to the size of a game pak, so
|
|
we'll only do this with a few select functions. Exactly which functions will
|
|
probably depend on your game.</p>
|
|
<p>One problem with this process is that Rust doesn't currently offer a way to mark
|
|
individual functions for being ARM or THUMB. The whole program is compiled in a
|
|
single mode. That's not an automatic killer, since we can use the <code>asm!</code> macro
|
|
to write some inline assembly, then within our inline assembly we switch from
|
|
THUMB to ARM, do some ARM stuff, and switch back to THUMB mode before the inline
|
|
assembly is over. Rust is none the wiser to what happened. Yeah, it's clunky,
|
|
that's why <a href="https://github.com/rust-embedded/wg/issues/256#issuecomment-439677804">it's on the 2019
|
|
wishlist</a>
|
|
to fix it (then LLVM can manage it automatically for you).</p>
|
|
<p>The bigger problem is that when we do that all of our functions still start off
|
|
in THUMB mode, even if they temporarily use ARM mode. For the few bits of code
|
|
that must start <em>already in</em> ARM mode, we're stuck. Those parts have to be
|
|
written in external assembly files and then included with the linker. We were
|
|
already going to write some assembly, and we already use more than one file in
|
|
our project all the time, those parts aren't a big problem. The big problem is
|
|
that using custom linker scripts isn't transitive between crates.</p>
|
|
<p>What I mean is that once we have a file full of custom assembly that we're
|
|
linking in by hand, that's not "part of" the crate any more. At least not as
|
|
<code>cargo</code> see it. So we can't just upload it to <code>crates.io</code> and then depend on it
|
|
in other projects and have <code>cargo</code> download the right version and and include it
|
|
all automatically. We're back to fully manually copying files from the old
|
|
project into the new one, adding more lines to the linker script each time we
|
|
split up a new assembly file, all that stuff. Like the stone age. Sometimes ya
|
|
gotta suffer for your art.</p>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
|
|
<a rel="prev" href="development-setup.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
|
|
|
|
|
|
<div style="clear: both"></div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
|
|
<a href="development-setup.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></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>
|