gba/docs/ch01/hello2.html

320 lines
16 KiB
HTML
Raw Normal View History

2018-11-11 17:39:26 +11:00
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
2018-11-18 11:14:42 +11:00
<title>hello2 - Rust GBA Guide</title>
2018-11-11 17:39:26 +11:00
<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="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html" class="active"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
2018-11-11 17:39:26 +11:00
</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>
2018-11-18 11:14:42 +11:00
<h1 class="menu-title">Rust GBA Guide</h1>
2018-11-11 17:39:26 +11:00
<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="#hello2" id="hello2"><h1>hello2</h1></a>
<p>Okay so let's have a look again:</p>
<p><code>hello1</code></p>
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
#![no_std]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
}
#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
unsafe {
(0x04000000 as *mut u16).write_volatile(0x0403);
(0x06000000 as *mut u16).offset(120 + 80 * 240).write_volatile(0x001F);
(0x06000000 as *mut u16).offset(136 + 80 * 240).write_volatile(0x03E0);
(0x06000000 as *mut u16).offset(120 + 96 * 240).write_volatile(0x7C00);
loop {}
}
}
</code></pre></pre>
<p>Now let's clean this up so that it's clearer what's going on.</p>
2018-11-19 16:19:13 +11:00
<p>First we'll label that display control stuff, including using the <code>VolatilePtr</code>
type from the volatile explanation:</p>
2018-11-11 17:39:26 +11:00
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
2018-11-19 16:19:13 +11:00
pub const DISPCNT: VolatilePtr&lt;u16&gt; = VolatilePtr(0x04000000 as *mut u16);
2018-11-11 17:39:26 +11:00
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
#}</code></pre></pre>
<p>Next we make some const values for the actual pixel drawing</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub const VRAM: usize = 0x06000000;
pub const SCREEN_WIDTH: isize = 240;
#}</code></pre></pre>
2018-11-19 16:19:13 +11:00
<p>Note that VRAM has to be interpreted in different ways depending on mode, so we
just leave it as <code>usize</code> and we'll cast it into the right form closer to the
actual use.</p>
<p>Next we want a small helper function for putting together a color value.
Happily, this one can even be declared as a <code>const</code> function. At the time of
2018-11-11 17:39:26 +11:00
writing, we've got the &quot;minimal const fn&quot; support in nightly. It really is quite
limited, but I'm happy to let rustc and LLVM pre-compute as much as they can
when it comes to the GBA's tiny CPU.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub const fn rgb16(red: u16, green: u16, blue: u16) -&gt; u16 {
blue &lt;&lt; 10 | green &lt;&lt; 5 | red
}
#}</code></pre></pre>
<p>Finally, we'll make a function for drawing a pixel in Mode 3. Even though it's
just a one-liner, having the &quot;important parts&quot; be labeled as function arguments
usually helps you think about it a lot better.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
2018-11-19 16:19:13 +11:00
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
2018-11-11 17:39:26 +11:00
}
#}</code></pre></pre>
<p>So now we've got this:</p>
<p><code>hello2</code></p>
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
#![no_std]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
}
#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
unsafe {
2018-11-19 16:19:13 +11:00
DISPCNT.write(MODE3 | BG2);
2018-11-11 17:39:26 +11:00
mode3_pixel(120, 80, rgb16(31, 0, 0));
mode3_pixel(136, 80, rgb16(0, 31, 0));
mode3_pixel(120, 96, rgb16(0, 0, 31));
loop {}
}
}
2018-11-19 16:19:13 +11:00
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct VolatilePtr&lt;T&gt;(pub *mut T);
impl&lt;T&gt; VolatilePtr&lt;T&gt; {
pub unsafe fn read(&amp;self) -&gt; T {
core::ptr::read_volatile(self.0)
}
pub unsafe fn write(&amp;self, data: T) {
core::ptr::write_volatile(self.0, data);
}
pub unsafe fn offset(self, count: isize) -&gt; Self {
VolatilePtr(self.0.wrapping_offset(count))
}
}
pub const DISPCNT: VolatilePtr&lt;u16&gt; = VolatilePtr(0x04000000 as *mut u16);
2018-11-11 17:39:26 +11:00
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
pub const VRAM: usize = 0x06000000;
pub const SCREEN_WIDTH: isize = 240;
pub const fn rgb16(red: u16, green: u16, blue: u16) -&gt; u16 {
blue &lt;&lt; 10 | green &lt;&lt; 5 | red
}
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
2018-11-19 16:19:13 +11:00
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
2018-11-11 17:39:26 +11:00
}
</code></pre></pre>
2018-11-11 18:20:48 +11:00
<p>Exact same program that we started with, but much easier to read.</p>
<p>Of course, in the full <code>gba</code> crate that this book is a part of we have these and
other elements all labeled and sorted out for you (not identically, but
similarly). Still, for educational purposes it's often best to do it yourself at
least once.</p>
2018-11-11 17:39:26 +11:00
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch01/video_memory_intro.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
2018-11-11 17:39:26 +11:00
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../ch02/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
2018-11-12 08:56:11 +11:00
<i class="fa fa-angle-right"></i>
</a>
2018-11-11 17:39:26 +11:00
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch01/video_memory_intro.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
2018-11-11 17:39:26 +11:00
<i class="fa fa-angle-left"></i>
</a>
<a href="../ch02/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
2018-11-12 08:56:11 +11:00
<i class="fa fa-angle-right"></i>
</a>
2018-11-11 17:39:26 +11:00
</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>