gba/docs/02-concepts/02-bios.html
2018-12-21 00:30:01 +00:00

411 lines
25 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>BIOS - Rust GBA Guide</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body class="light">
<!-- Provide site root to javascript -->
<script type="text/javascript">var path_to_root = "../";</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = 'light'; }
document.body.className = theme;
document.querySelector('html').className = theme + ' js';
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<ol class="chapter"><li><a href="../00-introduction/00-index.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><ol class="section"><li><a href="../00-introduction/01-requirements.html"><strong aria-hidden="true">1.1.</strong> Reader Requirements</a></li><li><a href="../00-introduction/02-goals_and_style.html"><strong aria-hidden="true">1.2.</strong> Book Goals and Style</a></li><li><a href="../00-introduction/03-development-setup.html"><strong aria-hidden="true">1.3.</strong> Development Setup</a></li><li><a href="../00-introduction/04-hello-magic.html"><strong aria-hidden="true">1.4.</strong> Hello, Magic</a></li><li><a href="../00-introduction/05-help_and_resources.html"><strong aria-hidden="true">1.5.</strong> Help and Resources</a></li></ol></li><li><a href="../01-quirks/00-index.html"><strong aria-hidden="true">2.</strong> Quirks</a></li><li><ol class="section"><li><a href="../01-quirks/01-no_std.html"><strong aria-hidden="true">2.1.</strong> No Std</a></li><li><a href="../01-quirks/02-fixed_only.html"><strong aria-hidden="true">2.2.</strong> Fixed Only</a></li><li><a href="../01-quirks/03-volatile_destination.html"><strong aria-hidden="true">2.3.</strong> Volatile Destination</a></li><li><a href="../01-quirks/04-newtype.html"><strong aria-hidden="true">2.4.</strong> Newtype</a></li><li><a href="../01-quirks/05-const_asserts.html"><strong aria-hidden="true">2.5.</strong> Const Asserts</a></li></ol></li><li><a href="../02-concepts/00-index.html"><strong aria-hidden="true">3.</strong> Concepts</a></li><li><ol class="section"><li><a href="../02-concepts/01-cpu.html"><strong aria-hidden="true">3.1.</strong> CPU</a></li><li><a href="../02-concepts/02-bios.html" class="active"><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><li><ol class="section"><li><a href="../05-examples/01-hello_magic.html"><strong aria-hidden="true">6.1.</strong> hello_magic</a></li><li><a href="../05-examples/02-hello_world.html"><strong aria-hidden="true">6.2.</strong> hello_world</a></li><li><a href="../05-examples/03-light_cycle.html"><strong aria-hidden="true">6.3.</strong> light_cycle</a></li><li><a href="../05-examples/04-bg_demo.html"><strong aria-hidden="true">6.4.</strong> bg_demo</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar" class="menu-bar">
<div id="menu-bar-sticky-container">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light <span class="default">(default)</span></button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust GBA Guide</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<a class="header" href="#bios" id="bios"><h1>BIOS</h1></a>
<ul>
<li><strong>Address Span:</strong> <code>0x0</code> to <code>0x3FFF</code> (16k)</li>
</ul>
<p>The <a href="https://en.wikipedia.org/wiki/BIOS">BIOS</a> of the GBA is a small read-only
portion of memory at the very base of the address space. However, it is also
hardware protected against reading, so if you try to read from BIOS memory when
the program counter isn't pointed into the BIOS (eg: any time code <em>you</em> write
is executing) then you get <a href="https://problemkaputt.de/gbatek.htm#gbaunpredictablethings">basically garbage
data</a> back.</p>
<p>So we're not going to spend time here talking about what bits to read or write
within BIOS memory like we do with the other sections. Instead we're going to
spend time talking about <a href="https://doc.rust-lang.org/unstable-book/language-features/asm.html">inline
assembly</a>
(<a href="https://github.com/rust-lang/rust/issues/29722">tracking issue</a>) and then use
it to call the <a href="https://problemkaputt.de/gbatek.htm#biosfunctions">GBA BIOS
Functions</a>.</p>
<p>Note that BIOS calls have <em>more overhead than normal function calls</em>, so don't
go using them all over the place if you don't have to. They're also usually
written more to be compact in terms of code than for raw speed, so you actually
can out speed them in some cases. Between the increased overhead and not being
as speed optimized, you can sometimes do a faster job without calling the BIOS
at all. (TODO: investigate more about what parts of the BIOS we could
potentially offer faster alternatives for.)</p>
<p>I'd like to take a moment to thank <a href="https://github.com/mbr">Marc Brinkmann</a>
(with contributions from <a href="https://github.com/oli-obk">Oliver Schneider</a> and
<a href="https://github.com/phil-opp">Philipp Oppermann</a>) for writing <a href="http://embed.rs/articles/2016/arm-inline-assembly-rust/">this blog
post</a>. It's at least
ten times the tutorial quality as the <code>asm</code> entry in the Unstable Book has. In
fairness to the Unstable Book, the actual spec of how inline ASM works in rust
is &quot;basically what clang does&quot;, and that's specified as &quot;basically what GCC
does&quot;, and that's basically/shockingly not specified much at all despite GCC
being like 30 years old.</p>
<p>So let's be slow and pedantic about this process.</p>
<a class="header" href="#inline-asm" id="inline-asm"><h2>Inline ASM</h2></a>
<p><strong>Fair Warning:</strong> Inline asm is one of the least stable parts of Rust overall,
and if you write bad things you can trigger internal compiler errors and panics
and crashes and make LLVM choke and die without explanation. If you write some
inline asm and then suddenly your program suddenly stops compiling without
explanation, try commenting out that whole inline asm use and see if it's
causing the problem. Double check that you've written every single part of the
asm call absolutely correctly, etc, etc.</p>
<p><strong>Bonus Warning:</strong> The general information that follows regarding the asm macro
is consistent from system to system, but specific information about register
names, register quantities, asm instruction argument ordering, and so on is
specific to ARM on the GBA. If you're programming for any other device you'll
need to carefully investigate that before you begin.</p>
<p>Now then, with those out of the way, the inline asm docs describe an asm call as
looking like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
asm!(assembly template
: output operands
: input operands
: clobbers
: options
);
#}</code></pre></pre>
<p>And once you stick a lot of stuff in there it can <em>absolutely</em> be hard to
remember the ordering of the elements. So we'll start with a code block that
has some comments thrown in on each line:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
asm!(/* ASM */ TODO
:/* OUT */ TODO
:/* INP */ TODO
:/* CLO */ TODO
:/* OPT */
);
#}</code></pre></pre>
<p>Now we have to decide what we're gonna write. Obviously we're going to do some
instructions, but those instructions use registers, and how are we gonna talk
about them? We've got two choices.</p>
<ol>
<li>
<p>We can pick each and every register used by specifying exact register names.
In THUMB mode we have 8 registers available, named <code>r0</code> through <code>r7</code>. If you
switch into 32-bit mode there's additional registers that are also available.</p>
</li>
<li>
<p>We can specify slots for registers we need and let LLVM decide. In this style
you name your slots <code>$0</code>, <code>$1</code> and so on. Slot numbers are assigned first to
all specified outputs, then to all specified inputs, in the order that you
list them.</p>
</li>
</ol>
<p>In the case of the GBA BIOS, each BIOS function has pre-designated input and
output registers, so we will use the first style. If you use inline ASM in other
parts of your code you're free to use the second style.</p>
<a class="header" href="#assembly" id="assembly"><h3>Assembly</h3></a>
<p>This is just one big string literal. You write out one instruction per line, and
excess whitespace is ignored. You can also do comments within your assembly
using <code>;</code> to start a comment that goes until the end of the line.</p>
<p>Assembly convention doesn't consider it unreasonable to comment potentially as
much as <em>every single line</em> of asm that you write when you're getting used to
things. Or even if you are used to things. This is cryptic stuff, there's a
reason we avoid writing in it as much as possible.</p>
<p>Remember that our Rust code is in 16-bit mode. You <em>can</em> switch to 32-bit mode
within your asm as long as you switch back by the time the block ends. Otherwise
you'll have a bad time.</p>
<a class="header" href="#outputs" id="outputs"><h3>Outputs</h3></a>
<p>A comma separated list. Each entry looks like</p>
<ul>
<li><code>&quot;constraint&quot; (binding)</code></li>
</ul>
<p>An output constraint starts with a symbol:</p>
<ul>
<li><code>=</code> for write only</li>
<li><code>+</code> for reads and writes</li>
<li><code>&amp;</code> for for &quot;early clobber&quot;, meaning that you'll write to this at some point
before all input values have been read. It prevents this register from being
assigned to an input register.</li>
</ul>
<p>Followed by <em>either</em> the letter <code>r</code> (if you want LLVM to pick the register to
use) or curly braces around a specific register (if you want to pick).</p>
<ul>
<li>The binding can be any single 32-bit or smaller value.</li>
<li>If your binding has bit pattern requirements (&quot;must be non-zero&quot;, etc) you are
responsible for upholding that.</li>
<li>If your binding type will try to <code>Drop</code> later then you are responsible for it
being in a fit state to do that.</li>
<li>The binding must be either a mutable binding or a binding that was
pre-declared but not yet assigned.</li>
</ul>
<p>Anything else is UB.</p>
<a class="header" href="#inputs" id="inputs"><h3>Inputs</h3></a>
<p>This is a similar comma separated list.</p>
<ul>
<li><code>&quot;constraint&quot; (binding)</code></li>
</ul>
<p>An input constraint doesn't have the symbol prefix, you just pick either <code>r</code> or
a named register with curly braces around it.</p>
<ul>
<li>An input binding must be a single 32-bit or smaller value.</li>
<li>An input binding <em>should</em> be a type that is <code>Copy</code> but this is not an absolute
requirement. Having the input be read is semantically similar to using
<code>core::ptr::read(&amp;binding)</code> and forgetting the value when you're done.</li>
</ul>
<a class="header" href="#clobbers" id="clobbers"><h3>Clobbers</h3></a>
<p>Sometimes your asm will touch registers other than the ones declared for input
and output.</p>
<p>Clobbers are declared as a comma separated list of string literals naming
specific registers. You don't use curly braces with clobbers.</p>
<p>LLVM <em>needs</em> to know this information. It can move things around to keep your
data safe, but only if you tell it what's about to happen.</p>
<p>Failure to define all of your clobbers can cause UB.</p>
<a class="header" href="#options" id="options"><h3>Options</h3></a>
<p>There's only one option we'd care to specify. That option is &quot;volatile&quot;.</p>
<p>Just like with a function call, LLVM will skip a block of asm if it doesn't see
that any outputs from the asm were used later on. Nearly every single BIOS call
(other than the math operations) will need to be marked as &quot;volatile&quot;.</p>
<a class="header" href="#bios-asm" id="bios-asm"><h3>BIOS ASM</h3></a>
<ul>
<li>Inputs are always <code>r0</code>, <code>r1</code>, <code>r2</code>, and/or <code>r3</code>, depending on function.</li>
<li>Outputs are always zero or more of <code>r0</code>, <code>r1</code>, and <code>r3</code>.</li>
<li>Any of the output registers that aren't actually used should be marked as
clobbered.</li>
<li>All other registers are unaffected.</li>
</ul>
<p>All of the GBA BIOS calls are performed using the
<a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0068b/BABFCEEG.html">swi</a>
instruction, combined with a value depending on what BIOS function you're trying
to invoke. If you're in 16-bit code you use the value directly, and if you're in
32-bit mode you shift the value up by 16 bits first.</p>
<a class="header" href="#example-bios-function-division" id="example-bios-function-division"><h3>Example BIOS Function: Division</h3></a>
<p>For our example we'll use the division function, because GBATEK gives very clear
instructions on how each register is used with that one:</p>
<pre><code class="language-txt">Signed Division, r0/r1.
r0 signed 32bit Number
r1 signed 32bit Denom
Return:
r0 Number DIV Denom ;signed
r1 Number MOD Denom ;signed
r3 ABS (Number DIV Denom) ;unsigned
For example, incoming -1234, 10 should return -123, -4, +123.
The function usually gets caught in an endless loop upon division by zero.
</code></pre>
<p>The math folks tell me that the <code>r1</code> value should be properly called the
&quot;remainder&quot; not the &quot;modulus&quot;. We'll go with that for our function, doesn't hurt
to use the correct names. Our Rust function has an assert against dividing by
<code>0</code>, then we name some bindings <em>without</em> giving them a value, we make the asm
call, and then return what we got.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub fn div_rem(numerator: i32, denominator: i32) -&gt; (i32, i32) {
assert!(denominator != 0);
let div_out: i32;
let rem_out: i32;
unsafe {
asm!(/* ASM */ &quot;swi 0x06&quot;
:/* OUT */ &quot;={r0}&quot;(div_out), &quot;={r1}&quot;(rem_out)
:/* INP */ &quot;{r0}&quot;(numerator), &quot;{r1}&quot;(denominator)
:/* CLO */ &quot;r3&quot;
:/* OPT */
);
}
(div_out, rem_out)
}
#}</code></pre></pre>
<p>I <em>hope</em> this all makes sense by now.</p>
<a class="header" href="#specific-bios-functions" id="specific-bios-functions"><h2>Specific BIOS Functions</h2></a>
<p>For a full list of all the specific BIOS functions and their use you should
check the <code>gba::bios</code> module within the <code>gba</code> crate. There's just so many of
them that enumerating them all here wouldn't serve much purpose.</p>
<p>Which is not to say that we'll never cover any BIOS functions in this book!
Instead, we'll simply mention them when whenever they're relevent to the task at
hand (such as controlling sound or waiting for vblank).</p>
<p>//TODO: list/name all BIOS functions as well as what they relate to elsewhere.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../02-concepts/01-cpu.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="../02-concepts/03-wram.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="../02-concepts/01-cpu.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="../02-concepts/03-wram.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>