2018-11-18 11:14:42 +11:00
<!DOCTYPE HTML>
< html lang = "en" class = "sidebar-visible no-js" >
< head >
<!-- Book generated using mdBook -->
< meta charset = "UTF-8" >
< title > Volatile - 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" >
2018-11-22 17:00:59 +11:00
< 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" class = "active" > < 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" > < 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-18 11:14:42 +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 >
< 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" id = "volatile" > < h1 > Volatile< / h1 > < / a >
< p > Before we focus on what the numbers mean, first let's ask ourselves: Why are we
doing < em > volatile< / em > writes? You've probably never used that keywords before at all.
What < em > is< / em > volatile anyway?< / p >
< p > Well, the optimizer is pretty aggressive, and so it'll skip reads and writes
when it thinks can. Like if you write to a pointer once, and then again a moment
later, and it didn't see any other reads in between, it'll think that it can
just skip doing that first write since it'll get overwritten anyway. Sometimes
that's correct, but sometimes it's not.< / p >
< p > Marking a read or write as < em > volatile< / em > tells the compiler that it really must do
that action, and in the exact order that we wrote it out. It says that there
might even be special hardware side effects going on that the compiler isn't
aware of. In this case, the write to the display control register sets a video
mode, and the writes to the Video RAM set pixels that will show up on the
screen.< / p >
< p > Similar to " atomic" operations you might have heard about, all volatile
operations are enforced to happen in the exact order that you specify them, but
only relative to other volatile operations. So something like< / p >
< pre > < pre class = "playpen" > < code class = "language-rust" >
# #![allow(unused_variables)]
#fn main() {
2018-11-19 16:19:13 +11:00
c.write_volatile(5);
2018-11-18 11:14:42 +11:00
a += b;
2018-11-19 16:19:13 +11:00
d.write_volatile(7);
2018-11-18 11:14:42 +11:00
#}< / code > < / pre > < / pre >
< p > might end up changing < code > a< / code > either before or after the change to < code > c< / code > (since the
value of < code > a< / code > doesn't affect the write to < code > c< / code > ), but the write to < code > d< / code > will
< em > always< / em > happen after the write to < code > c< / code > , even though the compiler doesn't see any
direct data dependency there.< / p >
< p > If you ever go on to use volatile stuff on other platforms it's important to
note that volatile doesn't make things thread-safe, you still need atomic for
that. However, the GBA doesn't have threads, so we don't have to worry about
those sorts of thread safety concerns (there's interrupts, but that's another
matter).< / p >
2018-11-19 16:19:13 +11:00
< a class = "header" href = "#volatile-by-default" id = "volatile-by-default" > < h2 > Volatile by default< / h2 > < / a >
< p > Of course, writing out < code > volatile_write< / code > every time is more than we wanna do.
There's clarity and then there's excessive. This is a chance to write our first
< a href = "https://doc.rust-lang.org/1.0.0/style/features/types/newtype.html" > newtype< / a > .
Basically a type that's got the exact same binary representation as some other
type, but new methods and trait implementations.< / p >
< p > We want a < code > *mut T< / code > that's volatile by default, and also when we offset it...
well the verdict is slightly unclear on how < code > offset< / code > vs < code > wrapping_offset< / code > work
when you're using pointers that you made up out of nowhere. I've asked the
experts and they genuinely weren't sure, so we'll make an < code > offset< / code > method that
does a < code > wrapping_offset< / code > just to be careful.< / p >
< pre > < pre class = "playpen" > < code class = "language-rust" >
# #![allow(unused_variables)]
#fn main() {
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct VolatilePtr< T> (pub *mut T);
impl< T> VolatilePtr< T> {
pub unsafe fn read(& self) -> T {
core::ptr::read_volatile(self.0)
}
pub unsafe fn write(& self, data: T) {
core::ptr::write_volatile(self.0, data);
}
pub unsafe fn offset(self, count: isize) -> Self {
VolatilePtr(self.0.wrapping_offset(count))
}
}
#}< / code > < / pre > < / pre >
2018-11-18 11:14:42 +11:00
< / main >
< nav class = "nav-wrapper" aria-label = "Page navigation" >
<!-- Mobile navigation buttons -->
< a rel = "prev" href = "../ch01/hello1.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 = "../ch01/io_registers.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 = "../ch01/hello1.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 = "../ch01/io_registers.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 >