Merge pull request #11 from rust-console/lokathor

Part of chapter 3
This commit is contained in:
Lokathor 2018-11-19 02:23:02 -07:00 committed by GitHub
commit 5b327dce6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 3447 additions and 549 deletions

View file

@ -14,7 +14,8 @@ before_script:
script:
- cargo check && cargo check --release
# at the moment we DO NOT run "cargo test" because of lang-item issues
# Only run a test build for the library itself
- cargo test --lib && cargo test --lib --release
- cd book && mdbook build
deploy:

View file

@ -1,7 +1,7 @@
[package]
name = "gba"
description = "A crate (and book) for making GBA games with Rust."
version = "0.2.0"
version = "0.3.0"
authors = ["Lokathor <zefria@gmail.com>", "Ketsuban"]
repository = "https://github.com/rust-console/gba"
readme = "README.md"
@ -9,8 +9,10 @@ keywords = ["gba"]
edition = "2018"
license = "Apache-2.0"
publish = false
[dependencies]
gba-proc-macro = "0.1.1"
gba-proc-macro = "0.2.1"
[profile.release]
lto = true

63
Makefile.toml Normal file
View file

@ -0,0 +1,63 @@
[config]
skip_core_tasks = true
[tasks.create-target-dir]
script_runner = "@rust"
script = [
'''
fn main() {
std::fs::DirBuilder::new().recursive(true).create("./target/").unwrap();
}
'''
]
[tasks.assemble]
dependencies = ["create-target-dir"]
command = "arm-none-eabi-as"
args = ["crt0.s", "-o", "target/crt0.o"]
[tasks.build-examples-debug]
dependencies = ["assemble"]
command = "cargo"
args = ["xbuild", "--examples", "--target", "thumbv4-none-agb.json"]
[tasks.build-examples-release]
dependencies = ["assemble"]
command = "cargo"
args = ["xbuild", "--examples", "--target", "thumbv4-none-agb.json", "--release"]
[tasks.pack-roms]
script_runner = "@rust"
script = [
'''
fn main() -> std::io::Result<()> {
for entry in std::fs::read_dir("examples/")? {
let entry = entry?;
let mut path = entry.path();
if path.is_dir() {
continue;
} else {
path.set_extension("");
let name = path.file_name().unwrap().to_str().unwrap();
println!("{:?}", name);
std::process::Command::new("arm-none-eabi-objcopy").args(
&["-O", "binary",
&format!("target/thumbv4-none-agb/release/examples/{}",name),
&format!("target/example-{}.gba",name)])
.output().expect("failed to objcopy!");
std::process::Command::new("gbafix").args(
&[&format!("target/example-{}.gba",name)])
.output().expect("failed to gbafix!");
}
}
Ok(())
}
'''
]
[tasks.build]
dependencies = ["build-examples-debug", "build-examples-release", "pack-roms"]
[tasks.test]
command = "cargo"
args = ["test", "--lib"]

View file

@ -1,4 +1,9 @@
[![License:Apache2](https://img.shields.io/badge/License-Apache2-green.svg)](https://www.apache.org/licenses/LICENSE-2.0)
[![travis.ci](https://travis-ci.org/rust-console/gba.svg?branch=master)](https://travis-ci.org/rust-console/gba)
[![crates.io](https://img.shields.io/crates/v/gba.svg)](https://crates.io/crates/gba)
[![docs.rs](https://docs.rs/gba/badge.svg)](https://docs.rs/gba/latest/gba/)
* [![Built with cargo-make](https://sagiegurari.github.io/cargo-make/assets/badges/cargo-make.svg)](https://sagiegurari.github.io/cargo-make)
# gba

View file

@ -1,7 +1,6 @@
[book]
title = "Rust GBA Tutorials"
title = "Rust GBA Guide"
authors = ["Lokathor"]
#description = "Rust GBA Tutorials."
[build]
build-dir = "../docs"

View file

@ -2,14 +2,21 @@
# Rust GBA Tutorials
* [Introduction](introduction.md)
* [Ch 0: Development Setup](ch0/index.md)
* [Ch 1: Hello GBA](ch1/index.md)
* [hello1](ch1/hello1.md)
* [IO Registers](ch1/io_registers.md)
* [The Display Control Register](ch1/the_display_control_register.md)
* [Video Memory Intro](ch1/video_memory_intro.md)
* [hello2](ch1/hello2.md)
* [Ch 2: User Input](ch2/index.md)
* [The Key Input Register](ch2/the_key_input_register.md)
* [The VCount Register](ch2/the_vcount_register.md)
* [light_cycle](ch2/light_cycle.md)
* [Ch 0: Development Setup](ch00/index.md)
* [Ch 1: Hello GBA](ch01/index.md)
* [hello1](ch01/hello1.md)
* [Volatile](ch01/volatile.md)
* [IO Registers](ch01/io_registers.md)
* [The Display Control Register](ch01/the_display_control_register.md)
* [Video Memory Intro](ch01/video_memory_intro.md)
* [hello2](ch01/hello2.md)
* [Ch 2: User Input](ch02/index.md)
* [The Key Input Register](ch02/the_key_input_register.md)
* [The VCount Register](ch02/the_vcount_register.md)
* [light_cycle](ch02/light_cycle.md)
* [Ch 3: Memory and Objects](ch03/index.md)
* [GBA Memory](ch03/gba_memory.md)
* [Tiled Backgrounds](ch03/tiled_backgrounds.md)
* [Object Basics](ch03/object_basics.md)
* [GBA RNG](ch03/gba_rng.md)
* [memory_game](ch03/memory_game.md)

View file

@ -4,54 +4,58 @@ Before you can build a GBA game you'll have to follow some special steps to
setup the development environment. Perhaps unfortunately, there's enough detail
here to warrant a mini-chapter all on its own.
Before we begin I'd like to give a special thanks to **Ketsuban**, who is the
wizard that arranged for all of this to be able to happen and laid out the
details of the plan to the rest of the world.
Once again, extra special thanks to **Ketsuban**, who first dove into how to
make this all work with rust and then shared it with the world.
## Per System Setup
Obviously you need your computer to have a working rust installation. However,
you'll also need to ensure that you're using a nightly toolchain. You can run
`rustup default nightly` to set nightly as the system wide default toolchain, or
you can use a [toolchain
Obviously you need your computer to have a [working rust
installation](https://rustup.rs/). However, you'll also need to ensure that
you're using a nightly toolchain (we will need it for inline assembly, among
other potential useful features). You can run `rustup default nightly` to set
nightly as the system wide default toolchain, or you can use a [toolchain
file](https://github.com/rust-lang-nursery/rustup.rs#the-toolchain-file) to use
nightly just on a specific project, but either way we'll be assuming nightly
from now on.
nightly just on a specific project, but either way we'll be assuming the use of
nightly from now on. You'll also need the `rust-src` component so that
`cargo-xbuild` will be able to compile the core crate for us in a bit, so run
`rustup component add rust-src`.
Next you need [devkitpro](https://devkitpro.org/wiki/Getting_Started). They've
got a graphical installer for Windows, and `pacman` support on Linux. We'll be
using a few of their binutils for the `arm-none-eabi` target, and we'll also be
using some of their tools that are specific to GBA development, so _even if_ you
already have the right binutils for whatever reason, you'll still want devkitpro
for the `gbafix` utility.
Next, you need [devkitpro](https://devkitpro.org/wiki/Getting_Started). They've
got a graphical installer for Windows that runs nicely, and I guess `pacman`
support on Linux (I'm on Windows so I haven't tried the Linux install myself).
We'll be using a few of their general binutils for the `arm-none-eabi` target,
and we'll also be using some of their tools that are specific to GBA
development, so _even if_ you already have the right binutils for whatever
reason, you'll still want devkitpro for the `gbafix` utility.
* On Windows you'll want something like `C:\devkitpro\devkitARM\bin` and
`C:\devkitpro\tools\bin` to be [added to your
PATH](https://stackoverflow.com/q/44272416/455232), depending on where you
installed it to and such.
* On Linux you'll also want it to be added to your path, but if you're using
Linux I'll just assume you know how to do all that.
Linux I'll just assume you know how to do all that. I'm told that the default
installation path is `/opt/devkitpro/devkitARM/bin`, so look there first if
you didn't select some other place.
Finally, you'll need `cargo-xbuild`. Just run `cargo install cargo-xbuild` and
cargo will figure it all out for you.
## Per Project Setup
Now you'll need some particular files each time you want to start a new project.
You can find them in the root of the [rust-console/gba
repo](https://github.com/rust-console/gba).
Once the system wide tools are ready, you'll need some particular files each
time you want to start a new project. You can find them in the root of the
[rust-console/gba repo](https://github.com/rust-console/gba).
* `thumbv4-none-agb.json` describes the overall GBA to cargo-xbuild so it knows
what to do. This is actually a somewhat made up target name since there's no
official target name. The GBA is essentially the same as a normal
`thumbv4-none-eabi` device, but we give it the "agb" signifier so that later
on we'll be able to use rust's `cfg` ability to allow our code to know if it's
specifically targeting a GBA or some other similar device (like an NDS).
* `thumbv4-none-agb.json` describes the overall GBA to cargo-xbuild (and LLVM)
so it knows what to do. Technically the GBA is `thumbv4-none-eabi`, but we
change the `eabi` to `agb` so that we can distinguish it from other `eabi`
devices when using `cfg` flags.
* `crt0.s` describes some ASM startup stuff. If you have more ASM to place here
later on this is where you can put it. You also need to build it into a
`crt0.o` file before it can actually be used, but we'll cover that below.
* `linker.ld` tells the linker more critical info about the layout expectations
that the GBA has about our program.
* `linker.ld` tells the linker all the critical info about the layout
expectations that the GBA has about our program, and that it should also
include the `crt0.o` file with our compiled rust code.
## Compiling
@ -72,13 +76,13 @@ Once you've got something to build, you perform the following steps:
as `--release`, and options, such as `--bin foo` or `--examples`, that you'd
expect `cargo` to accept.
* You **can not** build and run tests this way, because they require `std`,
which the GBA doesn't have. You can still run some of your project's tests
with `cargo test`, but that builds for your local machine, so anything
specific to the GBA (such as reading and writing registers) won't be
testable that way. If you want to isolate and try out some piece code
running on the GBA you'll unfortunately have to make a demo for it in your
`examples/` directory and then run the demo in an emulator and see if it
does what you expect.
which the GBA doesn't have. If you want you can still run some of your
project's tests with `cargo test --lib` or similar, but that builds for your
local machine, so anything specific to the GBA (such as reading and writing
registers) won't be testable that way. If you want to isolate and try out
some piece code running on the GBA you'll unfortunately have to make a demo
for it in your `examples/` directory and then run the demo in an emulator
and see if it does what you expect.
* The file extension is important. `cargo xbuild` takes it as a flag to
compile dependencies with the same sysroot, so you can include crates
normally. Well, creates that work in the GBA's limited environment, but you
@ -132,3 +136,6 @@ transfer to a flash cart there's a little more to do.
And you're finally done!
Of course, you probably want to make a script for all that, but it's up to you.
On our own project we have it mostly set up within a `Makefile.toml` which runs
using the [cargo-make](https://github.com/sagiegurari/cargo-make) plugin. It's
not really the best plugin, but it's what's available.

View file

@ -1,5 +1,6 @@
# hello1
Our first example will be a totally minimal, full magic number crazy town.
Ready? Here goes:
`hello1.rs`
@ -8,7 +9,6 @@ Ready? Here goes:
#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
@ -26,17 +26,18 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
}
```
Throw that into your project, build the program (as described back in Chapter
0), and give it a run. You should see a red, green, and blue dot close-ish to
the middle of the screen. If you don't, something already went wrong. Double
check things, phone a friend, write your senators, try asking Ketsuban on the
[Rust Community Discord](https://discordapp.com/invite/aVESxV8), until you're
able to get your three dots going.
Throw that into your project skeleton, build the program (as described back in
Chapter 0), and give it a run in your emulator. You should see a red, green, and
blue dot close-ish to the middle of the screen. If you don't, something already
went wrong. Double check things, phone a friend, write your senators, try asking
Ketsuban on the [Rust Community Discord](https://discordapp.com/invite/aVESxV8),
until you're able to get your three dots going.
## Explaining hello1
## A basic hello1 explanation
So, what just happened? Even if you're used to Rust that might look pretty
strange. We'll go over each part extra carefully.
strange. We'll go over most of the little parts right here, and then bigger
parts will get their own sections.
```rust
#![feature(start)]
@ -60,7 +61,6 @@ There's no standard library available on the GBA, so we'll have to live a core
only life.
```rust
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
@ -74,10 +74,6 @@ However, right now we don't know how to get any sort of message out to the user
so... we do nothing at all. We _can't even return_ from here, so we just sit in
an infinite loop. The player will have to reset the universe from the outside.
The `#[cfg(not(test))]` part makes this item only exist in the program when
we're _not_ in a test build. This is so that `cargo test` and such work right as
much as possible.
```rust
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
@ -148,46 +144,5 @@ magic numbers mean or do.
* `0x06000000` is the start of Video RAM.
So we write some magic to the display control register once, then we write some
other magic to three locations of magic to the Video RAM. We get three dots,
each in their own location... so that second part makes sense at least.
We'll get into the magic number details in the other sections of this chapter.
## Sidebar: Volatile
We'll get into what all that is in a moment, but first let's ask ourselves: Why
are we doing _volatile_ writes? You've probably never used it before at all.
What is volatile anyway?
Well, the optimizer is pretty aggressive some of the time, 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 right, but sometimes it's wrong.
Marking a read or write as _volatile_ 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.
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
```rust
c.volatile_write(5);
a += b;
d.volatile_write(7);
```
might end up changing `a` either before or after the change to `c` (since the
value of `a` doesn't affect the write to `c`), but the write to `d` will
_always_ happen after the write to `c` even though the compiler doesn't see any
direct data dependency there.
If you ever 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 thread
safety concerns.
other magic to three magic locations in the Video RAM. Somehow that shows three
dots. Gotta read on to find out why!

View file

@ -8,7 +8,6 @@ Okay so let's have a look again:
#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
@ -28,10 +27,11 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
Now let's clean this up so that it's clearer what's going on.
First we'll label that display control stuff:
First we'll label that display control stuff, including using the `VolatilePtr`
type from the volatile explanation:
```rust
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
pub const DISPCNT: VolatilePtr<u16> = VolatilePtr(0x04000000 as *mut u16);
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
```
@ -43,9 +43,12 @@ pub const VRAM: usize = 0x06000000;
pub const SCREEN_WIDTH: isize = 240;
```
And then we want a small helper function for putting together a color value.
Note that VRAM has to be interpreted in different ways depending on mode, so we
just leave it as `usize` and we'll cast it into the right form closer to the
actual use.
Happily, this one can even be declared as a const function. At the time of
Next we want a small helper function for putting together a color value.
Happily, this one can even be declared as a `const` function. At the time of
writing, we've got the "minimal const fn" 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.
@ -62,7 +65,7 @@ usually helps you think about it a lot better.
```rust
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
```
@ -74,7 +77,6 @@ So now we've got this:
#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
@ -83,7 +85,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
unsafe {
DISPCNT.write_volatile(MODE3 | BG2);
DISPCNT.write(MODE3 | BG2);
mode3_pixel(120, 80, rgb16(31, 0, 0));
mode3_pixel(136, 80, rgb16(0, 31, 0));
mode3_pixel(120, 96, rgb16(0, 0, 31));
@ -91,7 +93,22 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
}
}
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
#[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))
}
}
pub const DISPCNT: VolatilePtr<u16> = VolatilePtr(0x04000000 as *mut u16);
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
@ -103,12 +120,13 @@ pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
}
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
```
Exact same program that we started with, but much easier to read.
Of course, in the full `gba` crate that this book is a part of we have these and
other elements all labeled and sorted out for you. Still, for educational
purposes it's often best to do it yourself at least once.
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.

View file

@ -107,6 +107,3 @@ First let's [convert that to
binary](https://www.wolframalpha.com/input/?i=0x0403), and we get
`0b100_0000_0011`. So, that's setting Mode 3 with background 2 enabled and
nothing else special.
However, I think we can do better than that. This is a prime target for more
newtyping as we attempt a `hello2` program.

View file

@ -106,8 +106,8 @@ So at pixels `(120,80)`, `(136,80)`, and `(120,96)` we write three values. Once
again we probably need to [convert them](https://www.wolframalpha.com/) into
binary to make sense of it.
* 0x001F: 0b11111
* 0x03E0: 0b11111_00000
* 0x7C00: 0b11111_00000_00000
* 0x001F: 0b0_00000_00000_11111
* 0x03E0: 0b0_00000_11111_00000
* 0x7C00: 0b0_11111_00000_00000
Ah, of course, a red pixel, a green pixel, and a blue pixel.

70
book/src/ch01/volatile.md Normal file
View file

@ -0,0 +1,70 @@
# Volatile
Before we focus on what the numbers mean, first let's ask ourselves: Why are we
doing _volatile_ writes? You've probably never used that keywords before at all.
What _is_ volatile anyway?
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.
Marking a read or write as _volatile_ 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.
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
```rust
c.write_volatile(5);
a += b;
d.write_volatile(7);
```
might end up changing `a` either before or after the change to `c` (since the
value of `a` doesn't affect the write to `c`), but the write to `d` will
_always_ happen after the write to `c`, even though the compiler doesn't see any
direct data dependency there.
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).
## Volatile by default
Of course, writing out `volatile_write` every time is more than we wanna do.
There's clarity and then there's excessive. This is a chance to write our first
[newtype](https://doc.rust-lang.org/1.0.0/style/features/types/newtype.html).
Basically a type that's got the exact same binary representation as some other
type, but new methods and trait implementations.
We want a `*mut T` that's volatile by default, and also when we offset it...
well the verdict is slightly unclear on how `offset` vs `wrapping_offset` 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 `offset` method that
does a `wrapping_offset` just to be careful.
```rust
#[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))
}
}
```

View file

@ -16,21 +16,21 @@ We need some better drawing operations this time around.
pub unsafe fn mode3_clear_screen(color: u16) {
let color = color as u32;
let bulk_color = color << 16 | color;
let mut ptr = VRAM as *mut u32;
let mut ptr = VolatilePtr(VRAM as *mut u32);
for _ in 0..SCREEN_HEIGHT {
for _ in 0..(SCREEN_WIDTH / 2) {
ptr.write_volatile(bulk_color);
ptr.write(bulk_color);
ptr = ptr.offset(1);
}
}
}
pub unsafe fn mode3_draw_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
pub unsafe fn mode3_read_pixel(col: isize, row: isize) -> u16 {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read_volatile()
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read()
}
```
@ -46,7 +46,7 @@ Now we just have to fill in the main function:
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
unsafe {
DISPCNT.write_volatile(MODE3 | BG2);
DISPCNT.write(MODE3 | BG2);
}
let mut px = SCREEN_WIDTH / 2;
@ -55,7 +55,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
loop {
// read the input for this frame
let this_frame_keys = read_key_input();
let this_frame_keys = key_input();
// adjust game state and wait for vblank
px += 2 * this_frame_keys.column_direction() as isize;
@ -113,7 +113,23 @@ it's not black that means we've been here before and the player has crashed into
their own line. In this case, we reset the game without moving them to a new
location.
Finally, if the player is in bounds and they haven't crashed, we write their color into memory at this position.
Finally, if the player is in bounds and they haven't crashed, we write their
color into memory at this position.
Regardless of how it worked out, we hold here until vdraw starts before going to
the next loop.
the next loop. That's all there is to it.
## The gba crate doesn't quite work like this
Once again, as with the `hello1` and `hello2` examples, the `gba` crate covers
much of this same ground as our example here, but in slightly different ways.
Better organization and abstractions are usually only realized once you've used
more of the whole thing you're trying to work with. If we want to have a crate
where the whole thing is well integrated with itself, then the examples would
also end up having to explain about things we haven't really touched on much
yet. It becomes a lot harder to teach.
So, going forward, we will continue to teach concepts and build examples that
don't directly depend on the `gba` crate. This allows the crate to freely grow
without all the past examples becoming a great inertia upon it.

View file

@ -56,15 +56,15 @@ a `u16` and then wrap that in our newtype which will implement methods for
reading and writing the key bits.
```rust
pub const KEYINPUT: *mut u16 = 0x400_0130 as *mut u16;
pub const KEYINPUT: VolatilePtr<u16> = VolatilePtr(0x400_0130 as *mut u16);
/// A newtype over the key input state of the GBA.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct KeyInputSetting(u16);
pub fn read_key_input() -> KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile()) }
pub fn key_input() -> KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read()) }
}
```
@ -93,11 +93,13 @@ folded and refolded by the compiler, but we can just check.
It turns out that the `!=0` test is 4 instructions and the `==0` test is 6
instructions. Since we want to get savings where we can, and we'll probably
check the keys of an input often enough, we'll just always use a `!=0` test and
then adjust how we initially read the register to compensate.
then adjust how we initially read the register to compensate. By using xor with
a mask for only the 10 used bits we can flip the "low when pressed" values so
that the entire result has active bits in all positions where a key is pressed.
```rust
pub fn read_key_input() -> KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b1111_1111_1111_1111) }
pub fn key_input() -> KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b0000_0011_1111_1111) }
}
```

View file

@ -46,10 +46,10 @@ quickly during the blank period.
So first we want a way to check the vcount value at all:
```rust
pub const VCOUNT: *mut u16 = 0x0400_0006 as *mut u16;
pub const VCOUNT: VolatilePtr<u16> = VolatilePtr(0x0400_0006 as *mut u16);
pub fn read_vcount() -> u16 {
unsafe { VCOUNT.read_volatile() }
pub fn vcount() -> u16 {
unsafe { VCOUNT.read() }
}
```
@ -59,11 +59,11 @@ Then we want two little helper functions to wait until VBlank and vdraw.
pub const SCREEN_HEIGHT: isize = 160;
pub fn wait_until_vblank() {
while read_vcount() < SCREEN_HEIGHT as u16 {}
while vcount() < SCREEN_HEIGHT as u16 {}
}
pub fn wait_until_vdraw() {
while read_vcount() >= SCREEN_HEIGHT as u16 {}
while vcount() >= SCREEN_HEIGHT as u16 {}
}
```

237
book/src/ch03/gba_memory.md Normal file
View file

@ -0,0 +1,237 @@
# GBA Memory
The [GBA Memory Map](http://problemkaputt.de/gbatek.htm#gbamemorymap) has
several memory portions to it, each with their own little differences. Most of
the memory has pre-determined use according to the hardware, but there is also
space for games to use as a scratch pad in whatever way the game sees fit.
The memory ranges listed here are _inclusive_, so they end with a lot of `F`s
and `E`s.
We've talked about volatile memory before, but just as a reminder I'll say that
all of the memory we'll talk about here should be accessed with volatile with
two exceptions:
1) Work RAM (both internal and external) can be used normally, and if the
compiler is able to totally elide any reads and writes that's okay.
2) However, if you set aside any space in Work RAM where an interrupt will
communicate with the main program then that specific location will have to
keep using volatile access, since the compiler never knows when an interrupt
will actually happen.
## BIOS / System ROM
* `0x0` to `0x3FFF` (16k)
This is special memory for the BIOS. It is "read-only", but even then it's only
accessible when the program counter is pointing into the BIOS region. At all
other times you get a [garbage
value](http://problemkaputt.de/gbatek.htm#gbaunpredictablethings) back when you
try to read out of the BIOS.
## External Work RAM / EWRAM
* `0x2000000` to `0x203FFFF` (256k)
This is a big pile of space, the use of which is up to each game. However, the
external work ram has only a 16-bit bus (if you read/write a 32-bit value it
silently breaks it up into two 16-bit operations) and also 2 wait cycles (extra
CPU cycles that you have to expend _per 16-bit bus use_).
In other words, we should think of EWRAM as if it was "heap space" in a normal
application. You can take the time to go store something within EWRAM, or to
load it out of EWRAM, but you should always avoid doing a critical computation
on values in EWRAM. It's a bit of a pain, but if you wanna be speedy and you
have more than just one manipulation that you want to do, you should pull the
value into a local variable, do all of your manipulations, and then push it back
out at the end.
## Internal Work RAM / IWRAM
* `0x3000000` to `0x3007FFF` (32k)
This is a smaller pile of space, but it has a 32-bit bus and no wait.
By default, `0x3007F00` to `0x3007FFF` is reserved for interrupt and BIOS use.
The rest of it is totally up to you. The user's stack space starts at
`0x3007F00` and proceeds _down_ from there. In other words, if you start your
own customized IWRAM use at `0x3000000` and go up, eventually you might hit your
stack. However, most reasonable uses won't actually cause a memory collision.
It's just something you should know about if you're using a ton of stack or
IWRAM and then get problems.
## IO Registers
* `0x4000000` to `0x40003FE`
We've touched upon a few of these so far, and we'll get to more later. At the
moment it is enough to say that, as you might have guessed, all of them live in
this region. Each individual register is a `u16` or `u32` and they control all
sorts of things. We'll actually be talking about some more of them in this very
chapter, because that's how we'll control some of the background and object
stuff.
## Palette RAM / PALRAM
* `0x5000000` to `0x50003FF` (1k)
Palette RAM has a 16-bit bus, which isn't really a problem because it
conceptually just holds `u16` values. There's no automatic wait state, but if
you try to access the same location that the display controller is accessing you
get bumped by 1 cycle. Since the display controller can use the palette ram any
number of times per scanline it's basically impossible to predict if you'll have
to do a wait or not during VDraw. During VBlank you won't have any wait of
course.
PALRAM is among the memory where there's weirdness if you try to write just one
byte: if you try to write just 1 byte, it writes that byte into _both_ parts of
the larger 16-bit location. This doesn't really affect us much with PALRAM,
because palette values are all supposed to be `u16` anyway.
The palette memory actually contains not one, but _two_ sets of palettes. First
there's 256 entries for the background palette data (starting at `0x5000000`),
and then there's 256 entries for object palette data (starting at `0x5000200`).
The GBA also has two modes for palette access: 8-bits-per-pixel (8bpp) and
4-bits-per-pixel (4bpp).
* In 8bpp mode an (8-bit) palette index value within a background or sprite
simply indexes directly into the 256 slots for that type of thing.
* In 4bpp mode a (4-bit) palette index value within a background or sprite
specifies an index within a particular "palbank" (16 palette entries each),
and then a _separate_ setting outside of the graphical data determines which
palbank is to be used for that background or object (the screen entry data for
backgrounds, and the object attributes for objects).
## Video RAM / VRAM
* `0x6000000` to `0x6017FFF` (96k)
We've used this before! VRAM has a 16-bit bus and no wait. However, the same as
with PALRAM, the "you might have to wait if the display controller is looking at
it" rule applies here.
Unfortunately there's not much more exact detail that can be given about VRAM.
The use of the memory depends on the video mode that you're using.
One general detail of note is that you can't write individual bytes to any part
of VRAM. Depending on mode and location, you'll either get your bytes doubled
into both the upper and lower parts of the 16-bit location targeted, or you
won't even affect the memory. This usually isn't a big deal, except in two
situations:
* In Mode 4, if you want to change just 1 pixel, you'll have to be very careful
to read the old `u16`, overwrite just the byte you wanted to change, and then
write that back.
* In any display mode, avoid using `memcopy` to place things into VRAM.
It's written to be byte oriented, and only does 32-bit transfers under select
conditions. The rest of the time it'll copy one byte at a time and you'll get
either garbage or nothing at all.
## Object Attribute Memory / OAM
* `0x7000000` to `0x70003FF` (1k)
The Object Attribute Memory has a 32-bit bus and no default wait, but suffers
from the "you might have to wait if the display controller is looking at it"
rule. You cannot write individual bytes to OAM at all, but that's not really a
problem because all the fields of the data types within OAM are either `i16` or
`u16` anyway.
Object attribute memory is the wildest yet: it conceptually contains two types
of things, but they're _interlaced_ with each other all the way through.
Now, [GBATEK](http://problemkaputt.de/gbatek.htm#lcdobjoamattributes) and
[CowByte](https://www.cs.rit.edu/~tjh8300/CowBite/CowBiteSpec.htm#OAM%20(sprites))
doesn't quite give names to the two data types, though
[TONC](https://www.coranac.com/tonc/text/regobj.htm#sec-oam) calls them
`OBJ_ATTR` and `OBJ_AFFINE`. We'll give them Rust names of course. In Rust terms
their layout would look like this:
```rust
#[repr(C)]
pub struct ObjectAttribute {
attr0: u16,
attr1: u16,
attr2: u16,
filler: i16,
}
#[repr(C)]
pub struct AffineMatrix {
filler0: [u16; 3],
pa: i16,
filler1: [u16; 3],
pb: i16,
filler2: [u16; 3],
pc: i16,
filler3: [u16; 3],
pd: i16,
}
```
(Note: the `#[repr(C)]` part just means that Rust must lay out the data exactly
in the order we specify, which otherwise it is not required to do).
So, we've got 1024 bytes in OAM and each `ObjectAttribute` value is 8 bytes, so
naturally we can support up to 128 objects.
_At the same time_, we've got 1024 bytes in OAM and each `AffineMatrix` is 32
bytes, so we can have 32 of them.
But, as I said, these things are all _interlaced_ with each other. See how
there's "filler" fields in each struct? If we imagine the OAM as being just an
array of one type or the other, indexes 0/1/2/3 of the `ObjectAttribute` array
would line up with index 0 of the `AffineMatrix` array. It's kinda weird, but
that's just how it works. When we setup functions to read and write these values
we'll have to be careful with how we do it. We probably _won't_ want to use
those representations above, at least not with the `AffineMatrix` type, because
they're quite wasteful if you want to store just object attributes or just
affine matrices.
## Game Pak ROM / Flash ROM
* `0x8000000` to `0x9FFFFFF` (wait 0)
* `0xA000000` to `0xBFFFFFF` (wait 1)
* `0xC000000` to `0xDFFFFFF` (wait 2)
* Max of 32Mb
These portions of the memory are less fixed, because they depend on the precise
details of the game pak you've inserted into the GBA. In general, they connect
to the game pak ROM and/or Flash memory, using a 16-bit bus. The ROM is
read-only, but the Flash memory (if any) allows writes.
The game pak ROM is listed as being in three sections, but it's actually the
same memory being effectively mirrored into three different locations. The
mirror that you choose to access the game pak through affects which wait state
setting it uses (configured via IO register of course). Unfortunately, the
details come down more to the game pak hardware that you load your game onto
than anything else, so there's not much I can say right here. We'll eventually
talk about it more later,
One thing of note is the way that the 16-bit bus affects us: the instructions to
execute are coming through the same bus as the rest of the game data, so we want
them to be as compact as possible. The ARM chip in the GBA supports two
different instruction sets, "thumb" and "non-thumb". The thumb mode instructions
are 16-bit, so they can each be loaded one at a time, and the non-thumb
instructions are 32-bit, so we're at a penalty if we execute them directly out
of the game pak. However, some things will demand that we use non-thumb code, so
we'll have to deal with that eventually. It's possible to switch between modes,
but it's a pain to keep track of what mode you're in because there's not
currently support for it in Rust itself (perhaps some day). So we'll stick with
thumb code as much as we possibly can, that's why our target profile for our
builds starts with `thumbv4`.
## Game Pak SRAM
* `0xE000000` to `0xE00FFFF` (64k)
The game pak SRAM has an 8-bit bus. Why did Pokémon always take so long to save?
This is why. It also has some amount of wait, but as with the ROM, the details
depend on your game pak hardware (and also as with ROM, you can adjust the
settings with an IO register, should you need to).
One thing to note about the SRAM is that the GBA has a Direct Memory Access
(DMA) feature that can be used for bulk memory movements in some cases, but the
DMA _cannot_ access the SRAM region. You really are stuck reading and writing
one byte at a time when you're using the SRAM.

2
book/src/ch03/gba_rng.md Normal file
View file

@ -0,0 +1,2 @@
# GBA RNG
TODO

34
book/src/ch03/index.md Normal file
View file

@ -0,0 +1,34 @@
# Ch 3: Memory and Objects
Alright so we can do some basic "movement", but we left a big trail in the video
memory of everywhere we went. Most of the time that's not what we want at all.
If we want more hardware support we're going to have to use a new video mode. So
far we've only used Mode 3, but modes 4 and 5 are basically the same. Instead,
we'll switch focus to using a tiled graphical mode.
First we will go over the complete GBA memory mapping. Part of this is the
memory for tiled graphics, but also things like all those IO registers, where
our RAM is for scratch space, all that stuff. Even if we can't put all of them
to use at once, it's helpful to have an idea of what will be available in the
long run.
Tiled modes bring us two big new concepts that each have their own complexity:
backgrounds and objects. They share some concepts, but fundamentally the
background is for creating a very large static space that you can scroll around
the view within, and the objects are about having a few moving bits that appear
over the background. Careful use of backgrounds and objects is key to having the
best looking GBA game, so we won't even be able to cover it all in a single
chapter.
And, of course, since most games are pretty boring if they're totally static
we'll touch on the kinds of RNG implementations you might want to have on a GBA.
Most general purpose RNGs that you find are rather big compared to the amount of
memory we want to give them, and they often use a lot of `u64` operations, so
they end up much slower on a 32-bit machine like the GBA (you can lower 64-bit
ops to combinations of 32-bit ops, but that's quite a bit more work). We'll
cover a few RNG options that size down the RNG to a good size and a good speed
without trading away too much in terms of quality.
To top it all off, we'll make a simple "memory game" sort of thing. There's some
face down cards in a grid, you pick one to check, then you pick the other to
check, and then if they match the pair disappears.

View file

@ -0,0 +1,2 @@
# memory_game
TODO

View file

@ -0,0 +1,2 @@
# Object Basics
TODO

View file

@ -0,0 +1,2 @@
# Tiled Backgrounds
TODO

View file

@ -1,8 +1,38 @@
# Introduction
Here's a book that'll help you program in Rust on the GBA.
Here's a book that'll help you program in Rust on the Game Boy Advance (GBA).
It's very "work in progress". At the moment there's only one demo program.
It's a work in progress of course, but so is most of everything in Rust.
## Style and Purpose
I'm out to teach you how to program in Rust on the GBA, obviously. However,
while there _is_ a [gba](https://github.com/rust-console/gba) crate, and while I
genuinely believe it to be a good and useful crate for GBA programming, we _will
not_ be using the `gba` crate within this book. In fact we won't be using any
crates at all. We can call it the [Handmade Hero](https://handmadehero.org/)
approach, if you like.
I don't want to just teach you how to use the `gba` crate, I want to teach you
what you'd need to know to write the crate from scratch if it wasn't there.
Each chapter of the book will focus on a few things you'll need to know about
GBA programming and then present a fully self-contained example that puts those
ideas into action. Just one file per example, no dependencies, no external
assets, no fuss. The examples will be in the text of the book within code
blocks, but also you can find them in the [examples
directory](https://github.com/rust-console/gba/tree/master/examples) of the repo
if you want to get them that way.
## Expected Knowledge
I will try not to ask too much of the reader ahead of time, but you are expected
to have already read [The Rust Book](https://doc.rust-lang.org/book/).
It's very difficult to know when you've said something that someone else won't
already know about, or if you're presenting ideas out of order. If things aren't
clear please [file an issue](https://github.com/rust-console/gba/issues) and
we'll try to address it.
## Getting Help
@ -14,11 +44,12 @@ channel.
* `Lokathor` is the fool who decided to write a crate and book for it.
If it's _not_ a GBA specific question then you can probably ask any of the other
folks in the server as well.
folks in the server as well (there's a few hundred folks).
## Other Works
## Further Reading
If you want to read more about developing on the GBA there are some other good resources as well:
If you want to read more about developing on the GBA there are some other good
resources as well:
* [Tonc](https://www.coranac.com/tonc/text/toc.htm), a tutorial series written
for C, but it's what I based the ordering of this book's sections on.

View file

@ -1,6 +1,7 @@
@rem Build the crt0 file before we begin
arm-none-eabi-as crt0.s -o crt0.o
@if not exist ".\target" mkdir target
arm-none-eabi-as crt0.s -o target/crt0.o
@rem Build all examples, both debug and release
cargo xbuild --examples --target thumbv4-none-agb.json

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Ch 0: Development Setup - Rust GBA Tutorials</title>
<title>Ch 0: Development Setup - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html" class="active"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html" class="active"><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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -140,49 +140,53 @@
<p>Before you can build a GBA game you'll have to follow some special steps to
setup the development environment. Perhaps unfortunately, there's enough detail
here to warrant a mini-chapter all on its own.</p>
<p>Before we begin I'd like to give a special thanks to <strong>Ketsuban</strong>, who is the
wizard that arranged for all of this to be able to happen and laid out the
details of the plan to the rest of the world.</p>
<p>Once again, extra special thanks to <strong>Ketsuban</strong>, who first dove into how to
make this all work with rust and then shared it with the world.</p>
<a class="header" href="#per-system-setup" id="per-system-setup"><h2>Per System Setup</h2></a>
<p>Obviously you need your computer to have a working rust installation. However,
you'll also need to ensure that you're using a nightly toolchain. You can run
<code>rustup default nightly</code> to set nightly as the system wide default toolchain, or
you can use a <a href="https://github.com/rust-lang-nursery/rustup.rs#the-toolchain-file">toolchain
<p>Obviously you need your computer to have a <a href="https://rustup.rs/">working rust
installation</a>. However, you'll also need to ensure that
you're using a nightly toolchain (we will need it for inline assembly, among
other potential useful features). You can run <code>rustup default nightly</code> to set
nightly as the system wide default toolchain, or you can use a <a href="https://github.com/rust-lang-nursery/rustup.rs#the-toolchain-file">toolchain
file</a> to use
nightly just on a specific project, but either way we'll be assuming nightly
from now on.</p>
<p>Next you need <a href="https://devkitpro.org/wiki/Getting_Started">devkitpro</a>. They've
got a graphical installer for Windows, and <code>pacman</code> support on Linux. We'll be
using a few of their binutils for the <code>arm-none-eabi</code> target, and we'll also be
using some of their tools that are specific to GBA development, so <em>even if</em> you
already have the right binutils for whatever reason, you'll still want devkitpro
for the <code>gbafix</code> utility.</p>
nightly just on a specific project, but either way we'll be assuming the use of
nightly from now on. You'll also need the <code>rust-src</code> component so that
<code>cargo-xbuild</code> will be able to compile the core crate for us in a bit, so run
<code>rustup component add rust-src</code>.</p>
<p>Next, you need <a href="https://devkitpro.org/wiki/Getting_Started">devkitpro</a>. They've
got a graphical installer for Windows that runs nicely, and I guess <code>pacman</code>
support on Linux (I'm on Windows so I haven't tried the Linux install myself).
We'll be using a few of their general binutils for the <code>arm-none-eabi</code> target,
and we'll also be using some of their tools that are specific to GBA
development, so <em>even if</em> you already have the right binutils for whatever
reason, you'll still want devkitpro for the <code>gbafix</code> utility.</p>
<ul>
<li>On Windows you'll want something like <code>C:\devkitpro\devkitARM\bin</code> and
<code>C:\devkitpro\tools\bin</code> to be <a href="https://stackoverflow.com/q/44272416/455232">added to your
PATH</a>, depending on where you
installed it to and such.</li>
<li>On Linux you'll also want it to be added to your path, but if you're using
Linux I'll just assume you know how to do all that.</li>
Linux I'll just assume you know how to do all that. I'm told that the default
installation path is <code>/opt/devkitpro/devkitARM/bin</code>, so look there first if
you didn't select some other place.</li>
</ul>
<p>Finally, you'll need <code>cargo-xbuild</code>. Just run <code>cargo install cargo-xbuild</code> and
cargo will figure it all out for you.</p>
<a class="header" href="#per-project-setup" id="per-project-setup"><h2>Per Project Setup</h2></a>
<p>Now you'll need some particular files each time you want to start a new project.
You can find them in the root of the <a href="https://github.com/rust-console/gba">rust-console/gba
repo</a>.</p>
<p>Once the system wide tools are ready, you'll need some particular files each
time you want to start a new project. You can find them in the root of the
<a href="https://github.com/rust-console/gba">rust-console/gba repo</a>.</p>
<ul>
<li><code>thumbv4-none-agb.json</code> describes the overall GBA to cargo-xbuild so it knows
what to do. This is actually a somewhat made up target name since there's no
official target name. The GBA is essentially the same as a normal
<code>thumbv4-none-eabi</code> device, but we give it the &quot;agb&quot; signifier so that later
on we'll be able to use rust's <code>cfg</code> ability to allow our code to know if it's
specifically targeting a GBA or some other similar device (like an NDS).</li>
<li><code>thumbv4-none-agb.json</code> describes the overall GBA to cargo-xbuild (and LLVM)
so it knows what to do. Technically the GBA is <code>thumbv4-none-eabi</code>, but we
change the <code>eabi</code> to <code>agb</code> so that we can distinguish it from other <code>eabi</code>
devices when using <code>cfg</code> flags.</li>
<li><code>crt0.s</code> describes some ASM startup stuff. If you have more ASM to place here
later on this is where you can put it. You also need to build it into a
<code>crt0.o</code> file before it can actually be used, but we'll cover that below.</li>
<li><code>linker.ld</code> tells the linker more critical info about the layout expectations
that the GBA has about our program.</li>
<li><code>linker.ld</code> tells the linker all the critical info about the layout
expectations that the GBA has about our program, and that it should also
include the <code>crt0.o</code> file with our compiled rust code.</li>
</ul>
<a class="header" href="#compiling" id="compiling"><h2>Compiling</h2></a>
<p>The next steps only work once you've got some source code to build. If you need
@ -206,13 +210,13 @@ practically instant operation.</li>
as <code>--release</code>, and options, such as <code>--bin foo</code> or <code>--examples</code>, that you'd
expect <code>cargo</code> to accept.</li>
<li>You <strong>can not</strong> build and run tests this way, because they require <code>std</code>,
which the GBA doesn't have. You can still run some of your project's tests
with <code>cargo test</code>, but that builds for your local machine, so anything
specific to the GBA (such as reading and writing registers) won't be
testable that way. If you want to isolate and try out some piece code
running on the GBA you'll unfortunately have to make a demo for it in your
<code>examples/</code> directory and then run the demo in an emulator and see if it
does what you expect.</li>
which the GBA doesn't have. If you want you can still run some of your
project's tests with <code>cargo test --lib</code> or similar, but that builds for your
local machine, so anything specific to the GBA (such as reading and writing
registers) won't be testable that way. If you want to isolate and try out
some piece code running on the GBA you'll unfortunately have to make a demo
for it in your <code>examples/</code> directory and then run the demo in an emulator
and see if it does what you expect.</li>
<li>The file extension is important. <code>cargo xbuild</code> takes it as a flag to
compile dependencies with the same sysroot, so you can include crates
normally. Well, creates that work in the GBA's limited environment, but you
@ -275,7 +279,10 @@ ROM is patched in place, so we don't even need to specify a new destination.</li
</li>
</ul>
<p>And you're finally done!</p>
<p>Of course, you probably want to make a script for all that, but it's up to you.</p>
<p>Of course, you probably want to make a script for all that, but it's up to you.
On our own project we have it mostly set up within a <code>Makefile.toml</code> which runs
using the <a href="https://github.com/sagiegurari/cargo-make">cargo-make</a> plugin. It's
not really the best plugin, but it's what's available.</p>
</main>
@ -288,7 +295,7 @@ ROM is patched in place, so we don't even need to specify a new destination.</li
<a rel="next" href="../ch1/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch01/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -306,7 +313,7 @@ ROM is patched in place, so we don't even need to specify a new destination.</li
<a href="../ch1/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch01/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>hello1 - Rust GBA Tutorials</title>
<title>hello1 - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html" class="active"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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" class="active"><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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -137,12 +137,12 @@
<div id="content" class="content">
<main>
<a class="header" href="#hello1" id="hello1"><h1>hello1</h1></a>
<p>Ready? Here goes:</p>
<p>Our first example will be a totally minimal, full magic number crazy town.
Ready? Here goes:</p>
<p><code>hello1.rs</code></p>
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
@ -159,15 +159,16 @@ fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
}
}
</code></pre></pre>
<p>Throw that into your project, build the program (as described back in Chapter
0), and give it a run. You should see a red, green, and blue dot close-ish to
the middle of the screen. If you don't, something already went wrong. Double
check things, phone a friend, write your senators, try asking Ketsuban on the
<a href="https://discordapp.com/invite/aVESxV8">Rust Community Discord</a>, until you're
able to get your three dots going.</p>
<a class="header" href="#explaining-hello1" id="explaining-hello1"><h2>Explaining hello1</h2></a>
<p>Throw that into your project skeleton, build the program (as described back in
Chapter 0), and give it a run in your emulator. You should see a red, green, and
blue dot close-ish to the middle of the screen. If you don't, something already
went wrong. Double check things, phone a friend, write your senators, try asking
Ketsuban on the <a href="https://discordapp.com/invite/aVESxV8">Rust Community Discord</a>,
until you're able to get your three dots going.</p>
<a class="header" href="#a-basic-hello1-explanation" id="a-basic-hello1-explanation"><h2>A basic hello1 explanation</h2></a>
<p>So, what just happened? Even if you're used to Rust that might look pretty
strange. We'll go over each part extra carefully.</p>
strange. We'll go over most of the little parts right here, and then bigger
parts will get their own sections.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#![feature(start)]
@ -191,7 +192,6 @@ only life.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
@ -203,9 +203,6 @@ Basically, if we somehow trigger a panic, this is where the program goes.
However, right now we don't know how to get any sort of message out to the user
so... we do nothing at all. We <em>can't even return</em> from here, so we just sit in
an infinite loop. The player will have to reset the universe from the outside.</p>
<p>The <code>#[cfg(not(test))]</code> part makes this item only exist in the program when
we're <em>not</em> in a test build. This is so that <code>cargo test</code> and such work right as
much as possible.</p>
<pre><pre class="playpen"><code class="language-rust">#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
</code></pre></pre>
@ -269,55 +266,21 @@ magic numbers mean or do.</p>
<li><code>0x06000000</code> is the start of Video RAM.</li>
</ul>
<p>So we write some magic to the display control register once, then we write some
other magic to three locations of magic to the Video RAM. We get three dots,
each in their own location... so that second part makes sense at least.</p>
<p>We'll get into the magic number details in the other sections of this chapter.</p>
<a class="header" href="#sidebar-volatile" id="sidebar-volatile"><h2>Sidebar: Volatile</h2></a>
<p>We'll get into what all that is in a moment, but first let's ask ourselves: Why
are we doing <em>volatile</em> writes? You've probably never used it before at all.
What is volatile anyway?</p>
<p>Well, the optimizer is pretty aggressive some of the time, 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 right, but sometimes it's wrong.</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 &quot;atomic&quot; 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() {
c.volatile_write(5);
a += b;
d.volatile_write(7);
#}</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 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 thread
safety concerns.</p>
other magic to three magic locations in the Video RAM. Somehow that shows three
dots. Gotta read on to find out why!</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch1/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch01/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="../ch1/io_registers.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch01/volatile.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -329,13 +292,13 @@ safety concerns.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch1/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch01/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="../ch1/io_registers.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch01/volatile.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>hello2 - Rust GBA Tutorials</title>
<title>hello2 - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html" class="active"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -142,7 +142,6 @@
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
@ -160,11 +159,12 @@ fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
}
</code></pre></pre>
<p>Now let's clean this up so that it's clearer what's going on.</p>
<p>First we'll label that display control stuff:</p>
<p>First we'll label that display control stuff, including using the <code>VolatilePtr</code>
type from the volatile explanation:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
pub const DISPCNT: VolatilePtr&lt;u16&gt; = VolatilePtr(0x04000000 as *mut u16);
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
#}</code></pre></pre>
@ -175,8 +175,11 @@ pub const BG2: u16 = 0b100_0000_0000;
pub const VRAM: usize = 0x06000000;
pub const SCREEN_WIDTH: isize = 240;
#}</code></pre></pre>
<p>And then we want a small helper function for putting together a color value.</p>
<p>Happily, this one can even be declared as a const function. At the time of
<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
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>
@ -194,7 +197,7 @@ usually helps you think about it a lot better.</p>
# #![allow(unused_variables)]
#fn main() {
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
#}</code></pre></pre>
<p>So now we've got this:</p>
@ -202,7 +205,6 @@ pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
@ -211,7 +213,7 @@ fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
unsafe {
DISPCNT.write_volatile(MODE3 | BG2);
DISPCNT.write(MODE3 | BG2);
mode3_pixel(120, 80, rgb16(31, 0, 0));
mode3_pixel(136, 80, rgb16(0, 31, 0));
mode3_pixel(120, 96, rgb16(0, 0, 31));
@ -219,7 +221,22 @@ fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
}
}
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
#[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);
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
@ -231,26 +248,27 @@ pub const fn rgb16(red: u16, green: u16, blue: u16) -&gt; u16 {
}
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
</code></pre></pre>
<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. Still, for educational
purposes it's often best to do it yourself at least once.</p>
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>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch1/video_memory_intro.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch01/video_memory_intro.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="../ch2/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch02/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -262,13 +280,13 @@ purposes it's often best to do it yourself at least once.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch1/video_memory_intro.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch01/video_memory_intro.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="../ch2/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch02/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Ch 1: Hello GBA - Rust GBA Tutorials</title>
<title>Ch 1: Hello GBA - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html" class="active"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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" class="active"><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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -150,13 +150,13 @@ three dots to the screen.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch0/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch00/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="../ch1/hello1.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch01/hello1.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -168,13 +168,13 @@ three dots to the screen.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch0/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch00/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="../ch1/hello1.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch01/hello1.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>IO Registers - Rust GBA Tutorials</title>
<title>IO Registers - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html" class="active"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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" class="active"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -176,13 +176,13 @@ array index is.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch1/hello1.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch01/volatile.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="../ch1/the_display_control_register.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch01/the_display_control_register.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -194,13 +194,13 @@ array index is.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch1/hello1.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch01/volatile.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="../ch1/the_display_control_register.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch01/the_display_control_register.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>The Display Control Register - Rust GBA Tutorials</title>
<title>The Display Control Register - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html" class="active"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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" class="active"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -221,21 +221,19 @@ some nifty graphical effects.</p>
binary</a>, and we get
<code>0b100_0000_0011</code>. So, that's setting Mode 3 with background 2 enabled and
nothing else special.</p>
<p>However, I think we can do better than that. This is a prime target for more
newtyping as we attempt a <code>hello2</code> program.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch1/io_registers.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch01/io_registers.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="../ch1/video_memory_intro.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch01/video_memory_intro.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -247,13 +245,13 @@ newtyping as we attempt a <code>hello2</code> program.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch1/io_registers.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch01/io_registers.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="../ch1/video_memory_intro.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch01/video_memory_intro.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Video Memory Intro - Rust GBA Tutorials</title>
<title>Video Memory Intro - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html" class="active"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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" class="active"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -228,9 +228,9 @@ data to fit in two pages, we compress the resolution.</p>
again we probably need to <a href="https://www.wolframalpha.com/">convert them</a> into
binary to make sense of it.</p>
<ul>
<li>0x001F: 0b11111</li>
<li>0x03E0: 0b11111_00000</li>
<li>0x7C00: 0b11111_00000_00000</li>
<li>0x001F: 0b0_00000_00000_11111</li>
<li>0x03E0: 0b0_00000_11111_00000</li>
<li>0x7C00: 0b0_11111_00000_00000</li>
</ul>
<p>Ah, of course, a red pixel, a green pixel, and a blue pixel.</p>
@ -239,13 +239,13 @@ binary to make sense of it.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch1/the_display_control_register.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch01/the_display_control_register.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="../ch1/hello2.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch01/hello2.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -257,13 +257,13 @@ binary to make sense of it.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch1/the_display_control_register.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch01/the_display_control_register.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="../ch1/hello2.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch01/hello2.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

262
docs/ch01/volatile.html Normal file
View file

@ -0,0 +1,262 @@
<!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">
<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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</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="#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 &quot;atomic&quot; 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() {
c.write_volatile(5);
a += b;
d.write_volatile(7);
#}</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>
<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&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))
}
}
#}</code></pre></pre>
</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>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Ch 2: User Input - Rust GBA Tutorials</title>
<title>Ch 2: User Input - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html" class="active"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html" class="active"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -160,13 +160,13 @@ organized&quot; for the long term.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch1/hello2.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch01/hello2.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="../ch2/the_key_input_register.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch02/the_key_input_register.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -178,13 +178,13 @@ organized&quot; for the long term.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch1/hello2.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch01/hello2.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="../ch2/the_key_input_register.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch02/the_key_input_register.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>light_cycle - Rust GBA Tutorials</title>
<title>light_cycle - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html" class="active"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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"><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" class="active"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -150,21 +150,21 @@ go off the screen or if they touch their own trail.</p>
pub unsafe fn mode3_clear_screen(color: u16) {
let color = color as u32;
let bulk_color = color &lt;&lt; 16 | color;
let mut ptr = VRAM as *mut u32;
let mut ptr = VolatilePtr(VRAM as *mut u32);
for _ in 0..SCREEN_HEIGHT {
for _ in 0..(SCREEN_WIDTH / 2) {
ptr.write_volatile(bulk_color);
ptr.write(bulk_color);
ptr = ptr.offset(1);
}
}
}
pub unsafe fn mode3_draw_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
pub unsafe fn mode3_read_pixel(col: isize, row: isize) -&gt; u16 {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read_volatile()
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read()
}
#}</code></pre></pre>
<p>The draw pixel and read pixel are both pretty obvious. What's new is the clear
@ -176,7 +176,7 @@ screen clear is twice as fast.</p>
<pre><pre class="playpen"><code class="language-rust">#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
unsafe {
DISPCNT.write_volatile(MODE3 | BG2);
DISPCNT.write(MODE3 | BG2);
}
let mut px = SCREEN_WIDTH / 2;
@ -185,7 +185,7 @@ fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
loop {
// read the input for this frame
let this_frame_keys = read_key_input();
let this_frame_keys = key_input();
// adjust game state and wait for vblank
px += 2 * this_frame_keys.column_direction() as isize;
@ -236,21 +236,37 @@ different colors.</p>
it's not black that means we've been here before and the player has crashed into
their own line. In this case, we reset the game without moving them to a new
location.</p>
<p>Finally, if the player is in bounds and they haven't crashed, we write their color into memory at this position.</p>
<p>Finally, if the player is in bounds and they haven't crashed, we write their
color into memory at this position.</p>
<p>Regardless of how it worked out, we hold here until vdraw starts before going to
the next loop.</p>
the next loop. That's all there is to it.</p>
<a class="header" href="#the-gba-crate-doesnt-quite-work-like-this" id="the-gba-crate-doesnt-quite-work-like-this"><h2>The gba crate doesn't quite work like this</h2></a>
<p>Once again, as with the <code>hello1</code> and <code>hello2</code> examples, the <code>gba</code> crate covers
much of this same ground as our example here, but in slightly different ways.</p>
<p>Better organization and abstractions are usually only realized once you've used
more of the whole thing you're trying to work with. If we want to have a crate
where the whole thing is well integrated with itself, then the examples would
also end up having to explain about things we haven't really touched on much
yet. It becomes a lot harder to teach.</p>
<p>So, going forward, we will continue to teach concepts and build examples that
don't directly depend on the <code>gba</code> crate. This allows the crate to freely grow
without all the past examples becoming a great inertia upon it.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch2/the_vcount_register.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch02/the_vcount_register.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="../ch03/index.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>
@ -259,12 +275,16 @@ the next loop.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch2/the_vcount_register.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch02/the_vcount_register.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="../ch03/index.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>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>The Key Input Register - Rust GBA Tutorials</title>
<title>The Key Input Register - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html" class="active"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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"><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" class="active"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -185,15 +185,15 @@ reading and writing the key bits.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub const KEYINPUT: *mut u16 = 0x400_0130 as *mut u16;
pub const KEYINPUT: VolatilePtr&lt;u16&gt; = VolatilePtr(0x400_0130 as *mut u16);
/// A newtype over the key input state of the GBA.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct KeyInputSetting(u16);
pub fn read_key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile()) }
pub fn key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read()) }
}
#}</code></pre></pre>
<p>Now we want a way to check if a key is <em>being pressed</em>, since that's normally
@ -218,12 +218,14 @@ folded and refolded by the compiler, but we can just check.</p>
<p>It turns out that the <code>!=0</code> test is 4 instructions and the <code>==0</code> test is 6
instructions. Since we want to get savings where we can, and we'll probably
check the keys of an input often enough, we'll just always use a <code>!=0</code> test and
then adjust how we initially read the register to compensate.</p>
then adjust how we initially read the register to compensate. By using xor with
a mask for only the 10 used bits we can flip the &quot;low when pressed&quot; values so
that the entire result has active bits in all positions where a key is pressed.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub fn read_key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b1111_1111_1111_1111) }
pub fn key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b0000_0011_1111_1111) }
}
#}</code></pre></pre>
<p>Now we add a method for seeing if a key is pressed. In the full library there's
@ -339,13 +341,13 @@ stuff, but we'll cover that later on because it's not necessary right now.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch2/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch02/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="../ch2/the_vcount_register.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch02/the_vcount_register.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -357,13 +359,13 @@ stuff, but we'll cover that later on because it's not necessary right now.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch2/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch02/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="../ch2/the_vcount_register.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch02/the_vcount_register.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>The VCount Register - Rust GBA Tutorials</title>
<title>The VCount Register - 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">
@ -72,7 +72,7 @@
</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="../ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="../ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="../ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="../ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="../ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch2/the_vcount_register.html" class="active"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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"><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" class="active"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -183,10 +183,10 @@ quickly during the blank period.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub const VCOUNT: *mut u16 = 0x0400_0006 as *mut u16;
pub const VCOUNT: VolatilePtr&lt;u16&gt; = VolatilePtr(0x0400_0006 as *mut u16);
pub fn read_vcount() -&gt; u16 {
unsafe { VCOUNT.read_volatile() }
pub fn vcount() -&gt; u16 {
unsafe { VCOUNT.read() }
}
#}</code></pre></pre>
<p>Then we want two little helper functions to wait until VBlank and vdraw.</p>
@ -196,11 +196,11 @@ pub fn read_vcount() -&gt; u16 {
pub const SCREEN_HEIGHT: isize = 160;
pub fn wait_until_vblank() {
while read_vcount() &lt; SCREEN_HEIGHT as u16 {}
while vcount() &lt; SCREEN_HEIGHT as u16 {}
}
pub fn wait_until_vdraw() {
while read_vcount() &gt;= SCREEN_HEIGHT as u16 {}
while vcount() &gt;= SCREEN_HEIGHT as u16 {}
}
#}</code></pre></pre>
<p>And... that's it. No special types to be made this time around, it's just a
@ -211,13 +211,13 @@ number we read out of memory.</p>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch2/the_key_input_register.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../ch02/the_key_input_register.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="../ch2/light_cycle.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="../ch02/light_cycle.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -229,13 +229,13 @@ number we read out of memory.</p>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="../ch2/the_key_input_register.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="../ch02/the_key_input_register.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="../ch2/light_cycle.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="../ch02/light_cycle.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

412
docs/ch03/gba_memory.html Normal file
View file

@ -0,0 +1,412 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>GBA Memory - 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="../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"><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.html" class="active"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</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="#gba-memory" id="gba-memory"><h1>GBA Memory</h1></a>
<p>The <a href="http://problemkaputt.de/gbatek.htm#gbamemorymap">GBA Memory Map</a> has
several memory portions to it, each with their own little differences. Most of
the memory has pre-determined use according to the hardware, but there is also
space for games to use as a scratch pad in whatever way the game sees fit.</p>
<p>The memory ranges listed here are <em>inclusive</em>, so they end with a lot of <code>F</code>s
and <code>E</code>s.</p>
<p>We've talked about volatile memory before, but just as a reminder I'll say that
all of the memory we'll talk about here should be accessed with volatile with
two exceptions:</p>
<ol>
<li>Work RAM (both internal and external) can be used normally, and if the
compiler is able to totally elide any reads and writes that's okay.</li>
<li>However, if you set aside any space in Work RAM where an interrupt will
communicate with the main program then that specific location will have to
keep using volatile access, since the compiler never knows when an interrupt
will actually happen.</li>
</ol>
<a class="header" href="#bios--system-rom" id="bios--system-rom"><h2>BIOS / System ROM</h2></a>
<ul>
<li><code>0x0</code> to <code>0x3FFF</code> (16k)</li>
</ul>
<p>This is special memory for the BIOS. It is &quot;read-only&quot;, but even then it's only
accessible when the program counter is pointing into the BIOS region. At all
other times you get a <a href="http://problemkaputt.de/gbatek.htm#gbaunpredictablethings">garbage
value</a> back when you
try to read out of the BIOS.</p>
<a class="header" href="#external-work-ram--ewram" id="external-work-ram--ewram"><h2>External Work RAM / EWRAM</h2></a>
<ul>
<li><code>0x2000000</code> to <code>0x203FFFF</code> (256k)</li>
</ul>
<p>This is a big pile of space, the use of which is up to each game. However, the
external work ram has only a 16-bit bus (if you read/write a 32-bit value it
silently breaks it up into two 16-bit operations) and also 2 wait cycles (extra
CPU cycles that you have to expend <em>per 16-bit bus use</em>).</p>
<p>In other words, we should think of EWRAM as if it was &quot;heap space&quot; in a normal
application. You can take the time to go store something within EWRAM, or to
load it out of EWRAM, but you should always avoid doing a critical computation
on values in EWRAM. It's a bit of a pain, but if you wanna be speedy and you
have more than just one manipulation that you want to do, you should pull the
value into a local variable, do all of your manipulations, and then push it back
out at the end.</p>
<a class="header" href="#internal-work-ram--iwram" id="internal-work-ram--iwram"><h2>Internal Work RAM / IWRAM</h2></a>
<ul>
<li><code>0x3000000</code> to <code>0x3007FFF</code> (32k)</li>
</ul>
<p>This is a smaller pile of space, but it has a 32-bit bus and no wait.</p>
<p>By default, <code>0x3007F00</code> to <code>0x3007FFF</code> is reserved for interrupt and BIOS use.
The rest of it is totally up to you. The user's stack space starts at
<code>0x3007F00</code> and proceeds <em>down</em> from there. In other words, if you start your
own customized IWRAM use at <code>0x3000000</code> and go up, eventually you might hit your
stack. However, most reasonable uses won't actually cause a memory collision.
It's just something you should know about if you're using a ton of stack or
IWRAM and then get problems.</p>
<a class="header" href="#io-registers" id="io-registers"><h2>IO Registers</h2></a>
<ul>
<li><code>0x4000000</code> to <code>0x40003FE</code></li>
</ul>
<p>We've touched upon a few of these so far, and we'll get to more later. At the
moment it is enough to say that, as you might have guessed, all of them live in
this region. Each individual register is a <code>u16</code> or <code>u32</code> and they control all
sorts of things. We'll actually be talking about some more of them in this very
chapter, because that's how we'll control some of the background and object
stuff.</p>
<a class="header" href="#palette-ram--palram" id="palette-ram--palram"><h2>Palette RAM / PALRAM</h2></a>
<ul>
<li><code>0x5000000</code> to <code>0x50003FF</code> (1k)</li>
</ul>
<p>Palette RAM has a 16-bit bus, which isn't really a problem because it
conceptually just holds <code>u16</code> values. There's no automatic wait state, but if
you try to access the same location that the display controller is accessing you
get bumped by 1 cycle. Since the display controller can use the palette ram any
number of times per scanline it's basically impossible to predict if you'll have
to do a wait or not during VDraw. During VBlank you won't have any wait of
course.</p>
<p>PALRAM is among the memory where there's weirdness if you try to write just one
byte: if you try to write just 1 byte, it writes that byte into <em>both</em> parts of
the larger 16-bit location. This doesn't really affect us much with PALRAM,
because palette values are all supposed to be <code>u16</code> anyway.</p>
<p>The palette memory actually contains not one, but <em>two</em> sets of palettes. First
there's 256 entries for the background palette data (starting at <code>0x5000000</code>),
and then there's 256 entries for object palette data (starting at <code>0x5000200</code>).</p>
<p>The GBA also has two modes for palette access: 8-bits-per-pixel (8bpp) and
4-bits-per-pixel (4bpp).</p>
<ul>
<li>In 8bpp mode an (8-bit) palette index value within a background or sprite
simply indexes directly into the 256 slots for that type of thing.</li>
<li>In 4bpp mode a (4-bit) palette index value within a background or sprite
specifies an index within a particular &quot;palbank&quot; (16 palette entries each),
and then a <em>separate</em> setting outside of the graphical data determines which
palbank is to be used for that background or object (the screen entry data for
backgrounds, and the object attributes for objects).</li>
</ul>
<a class="header" href="#video-ram--vram" id="video-ram--vram"><h2>Video RAM / VRAM</h2></a>
<ul>
<li><code>0x6000000</code> to <code>0x6017FFF</code> (96k)</li>
</ul>
<p>We've used this before! VRAM has a 16-bit bus and no wait. However, the same as
with PALRAM, the &quot;you might have to wait if the display controller is looking at
it&quot; rule applies here.</p>
<p>Unfortunately there's not much more exact detail that can be given about VRAM.
The use of the memory depends on the video mode that you're using.</p>
<p>One general detail of note is that you can't write individual bytes to any part
of VRAM. Depending on mode and location, you'll either get your bytes doubled
into both the upper and lower parts of the 16-bit location targeted, or you
won't even affect the memory. This usually isn't a big deal, except in two
situations:</p>
<ul>
<li>In Mode 4, if you want to change just 1 pixel, you'll have to be very careful
to read the old <code>u16</code>, overwrite just the byte you wanted to change, and then
write that back.</li>
<li>In any display mode, avoid using <code>memcopy</code> to place things into VRAM.
It's written to be byte oriented, and only does 32-bit transfers under select
conditions. The rest of the time it'll copy one byte at a time and you'll get
either garbage or nothing at all.</li>
</ul>
<a class="header" href="#object-attribute-memory--oam" id="object-attribute-memory--oam"><h2>Object Attribute Memory / OAM</h2></a>
<ul>
<li><code>0x7000000</code> to <code>0x70003FF</code> (1k)</li>
</ul>
<p>The Object Attribute Memory has a 32-bit bus and no default wait, but suffers
from the &quot;you might have to wait if the display controller is looking at it&quot;
rule. You cannot write individual bytes to OAM at all, but that's not really a
problem because all the fields of the data types within OAM are either <code>i16</code> or
<code>u16</code> anyway.</p>
<p>Object attribute memory is the wildest yet: it conceptually contains two types
of things, but they're <em>interlaced</em> with each other all the way through.</p>
<p>Now, <a href="http://problemkaputt.de/gbatek.htm#lcdobjoamattributes">GBATEK</a> and
<a href="https://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm#OAM%20(sprites)">CowByte</a>
doesn't quite give names to the two data types, though
<a href="https://www.coranac.com/tonc/text/regobj.htm#sec-oam">TONC</a> calls them
<code>OBJ_ATTR</code> and <code>OBJ_AFFINE</code>. We'll give them Rust names of course. In Rust terms
their layout would look like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[repr(C)]
pub struct ObjectAttribute {
attr0: u16,
attr1: u16,
attr2: u16,
filler: i16,
}
#[repr(C)]
pub struct AffineMatrix {
filler0: [u16; 3],
pa: i16,
filler1: [u16; 3],
pb: i16,
filler2: [u16; 3],
pc: i16,
filler3: [u16; 3],
pd: i16,
}
#}</code></pre></pre>
<p>(Note: the <code>#[repr(C)]</code> part just means that Rust must lay out the data exactly
in the order we specify, which otherwise it is not required to do).</p>
<p>So, we've got 1024 bytes in OAM and each <code>ObjectAttribute</code> value is 8 bytes, so
naturally we can support up to 128 objects.</p>
<p><em>At the same time</em>, we've got 1024 bytes in OAM and each <code>AffineMatrix</code> is 32
bytes, so we can have 32 of them.</p>
<p>But, as I said, these things are all <em>interlaced</em> with each other. See how
there's &quot;filler&quot; fields in each struct? If we imagine the OAM as being just an
array of one type or the other, indexes 0/1/2/3 of the <code>ObjectAttribute</code> array
would line up with index 0 of the <code>AffineMatrix</code> array. It's kinda weird, but
that's just how it works. When we setup functions to read and write these values
we'll have to be careful with how we do it. We probably <em>won't</em> want to use
those representations above, at least not with the <code>AffineMatrix</code> type, because
they're quite wasteful if you want to store just object attributes or just
affine matrices.</p>
<a class="header" href="#game-pak-rom--flash-rom" id="game-pak-rom--flash-rom"><h2>Game Pak ROM / Flash ROM</h2></a>
<ul>
<li><code>0x8000000</code> to <code>0x9FFFFFF</code> (wait 0)</li>
<li><code>0xA000000</code> to <code>0xBFFFFFF</code> (wait 1)</li>
<li><code>0xC000000</code> to <code>0xDFFFFFF</code> (wait 2)</li>
<li>Max of 32Mb</li>
</ul>
<p>These portions of the memory are less fixed, because they depend on the precise
details of the game pak you've inserted into the GBA. In general, they connect
to the game pak ROM and/or Flash memory, using a 16-bit bus. The ROM is
read-only, but the Flash memory (if any) allows writes.</p>
<p>The game pak ROM is listed as being in three sections, but it's actually the
same memory being effectively mirrored into three different locations. The
mirror that you choose to access the game pak through affects which wait state
setting it uses (configured via IO register of course). Unfortunately, the
details come down more to the game pak hardware that you load your game onto
than anything else, so there's not much I can say right here. We'll eventually
talk about it more later,</p>
<p>One thing of note is the way that the 16-bit bus affects us: the instructions to
execute are coming through the same bus as the rest of the game data, so we want
them to be as compact as possible. The ARM chip in the GBA supports two
different instruction sets, &quot;thumb&quot; and &quot;non-thumb&quot;. The thumb mode instructions
are 16-bit, so they can each be loaded one at a time, and the non-thumb
instructions are 32-bit, so we're at a penalty if we execute them directly out
of the game pak. However, some things will demand that we use non-thumb code, so
we'll have to deal with that eventually. It's possible to switch between modes,
but it's a pain to keep track of what mode you're in because there's not
currently support for it in Rust itself (perhaps some day). So we'll stick with
thumb code as much as we possibly can, that's why our target profile for our
builds starts with <code>thumbv4</code>.</p>
<a class="header" href="#game-pak-sram" id="game-pak-sram"><h2>Game Pak SRAM</h2></a>
<ul>
<li><code>0xE000000</code> to <code>0xE00FFFF</code> (64k)</li>
</ul>
<p>The game pak SRAM has an 8-bit bus. Why did pokemon always take so long to save?
This is why. It also has some amount of wait, but as with the ROM, the details
depend on your game pak hardware (and also as with ROM, you can adjust the
settings with an IO register, should you need to).</p>
<p>One thing to note about the SRAM is that the GBA has a Direct Memory Access
(DMA) feature that can be used for bulk memory movements in some cases, but the
DMA <em>cannot</em> access the SRAM region. You really are stuck reading and writing
one byte at a time when you're using the SRAM.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch03/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="../ch03/tiled_backgrounds.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="../ch03/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="../ch03/tiled_backgrounds.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>

201
docs/ch03/gba_rng.html Normal file
View file

@ -0,0 +1,201 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>GBA RNG - 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="../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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html" class="active"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</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="#gba-rng" id="gba-rng"><h1>GBA RNG</h1></a>
<p>TODO</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch03/object_basics.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="../ch03/memory_game.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="../ch03/object_basics.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="../ch03/memory_game.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>

228
docs/ch03/index.html Normal file
View file

@ -0,0 +1,228 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Ch 3: Memory and Objects - 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="../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"><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" class="active"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</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="#ch-3-memory-and-objects" id="ch-3-memory-and-objects"><h1>Ch 3: Memory and Objects</h1></a>
<p>Alright so we can do some basic &quot;movement&quot;, but we left a big trail in the video
memory of everywhere we went. Most of the time that's not what we want at all.
If we want more hardware support we're going to have to use a new video mode. So
far we've only used Mode 3, but modes 4 and 5 are basically the same. Instead,
we'll switch focus to using a tiled graphical mode.</p>
<p>First we will go over the complete GBA memory mapping. Part of this is the
memory for tiled graphics, but also things like all those IO registers, where
our RAM is for scratch space, all that stuff. Even if we can't put all of them
to use at once, it's helpful to have an idea of what will be available in the
long run.</p>
<p>Tiled modes bring us two big new concepts that each have their own complexity:
backgrounds and objects. They share some concepts, but fundamentally the
background is for creating a very large static space that you can scroll around
the view within, and the objects are about having a few moving bits that appear
over the background. Careful use of backgrounds and objects is key to having the
best looking GBA game, so we won't even be able to cover it all in a single
chapter.</p>
<p>And, of course, since most games are pretty boring if they're totally static
we'll touch on the kinds of RNG implementations you might want to have on a GBA.
Most general purpose RNGs that you find are rather big compared to the amount of
memory we want to give them, and they often use a lot of <code>u64</code> operations, so
they end up much slower on a 32-bit machine like the GBA (you can lower 64-bit
ops to combinations of 32-bit ops, but that's quite a bit more work). We'll
cover a few RNG options that size down the RNG to a good size and a good speed
without trading away too much in terms of quality.</p>
<p>To top it all off, we'll make a simple &quot;memory game&quot; sort of thing. There's some
face down cards in a grid, you pick one to check, then you pick the other to
check, and then if they match the pair disappears.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch02/light_cycle.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="../ch03/gba_memory.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="../ch02/light_cycle.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="../ch03/gba_memory.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>

193
docs/ch03/memory_game.html Normal file
View file

@ -0,0 +1,193 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>memory_game - 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="../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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html" class="active"><strong aria-hidden="true">5.5.</strong> memory_game</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="#memory_game" id="memory_game"><h1>memory_game</h1></a>
<p>TODO</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch03/gba_rng.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="../ch03/gba_rng.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>

View file

@ -0,0 +1,201 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Object Basics - 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="../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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html" class="active"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</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="#object-basics" id="object-basics"><h1>Object Basics</h1></a>
<p>TODO</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch03/tiled_backgrounds.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="../ch03/gba_rng.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="../ch03/tiled_backgrounds.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="../ch03/gba_rng.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

@ -0,0 +1,201 @@
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Tiled Backgrounds - 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="../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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="../ch03/tiled_backgrounds.html" class="active"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</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="#tiled-backgrounds" id="tiled-backgrounds"><h1>Tiled Backgrounds</h1></a>
<p>TODO</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../ch03/gba_memory.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="../ch03/object_basics.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="../ch03/gba_memory.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="../ch03/object_basics.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

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Introduction - Rust GBA Tutorials</title>
<title>Introduction - 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">
@ -72,7 +72,7 @@
</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="ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -137,8 +137,31 @@
<div id="content" class="content">
<main>
<a class="header" href="#introduction" id="introduction"><h1>Introduction</h1></a>
<p>Here's a book that'll help you program in Rust on the GBA.</p>
<p>It's very &quot;work in progress&quot;. At the moment there's only one demo program.</p>
<p>Here's a book that'll help you program in Rust on the Game Boy Advance (GBA).</p>
<p>It's a work in progress of course, but so is most of everything in Rust.</p>
<a class="header" href="#style-and-purpose" id="style-and-purpose"><h2>Style and Purpose</h2></a>
<p>I'm out to teach you how to program in Rust on the GBA, obviously. However,
while there <em>is</em> a <a href="https://github.com/rust-console/gba">gba</a> crate, and while I
genuinely believe it to be a good and useful crate for GBA programming, we <em>will
not</em> be using the <code>gba</code> crate within this book. In fact we won't be using any
crates at all. We can call it the <a href="https://handmadehero.org/">Handmade Hero</a>
approach, if you like.</p>
<p>I don't want to just teach you how to use the <code>gba</code> crate, I want to teach you
what you'd need to know to write the crate from scratch if it wasn't there.</p>
<p>Each chapter of the book will focus on a few things you'll need to know about
GBA programming and then present a fully self-contained example that puts those
ideas into action. Just one file per example, no dependencies, no external
assets, no fuss. The examples will be in the text of the book within code
blocks, but also you can find them in the <a href="https://github.com/rust-console/gba/tree/master/examples">examples
directory</a> of the repo
if you want to get them that way.</p>
<a class="header" href="#expected-knowledge" id="expected-knowledge"><h2>Expected Knowledge</h2></a>
<p>I will try not to ask too much of the reader ahead of time, but you are expected
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>.</p>
<p>It's very difficult to know when you've said something that someone else won't
already know about, or if you're presenting ideas out of order. If things aren't
clear please <a href="https://github.com/rust-console/gba/issues">file an issue</a> and
we'll try to address it.</p>
<a class="header" href="#getting-help" id="getting-help"><h2>Getting Help</h2></a>
<p>If you want to contact us you should join the <a href="https://discordapp.com/invite/aVESxV8">Rust Community
Discord</a> and ask in the <code>#gamedev</code>
@ -148,9 +171,10 @@ channel.</p>
<li><code>Lokathor</code> is the fool who decided to write a crate and book for it.</li>
</ul>
<p>If it's <em>not</em> a GBA specific question then you can probably ask any of the other
folks in the server as well.</p>
<a class="header" href="#other-works" id="other-works"><h2>Other Works</h2></a>
<p>If you want to read more about developing on the GBA there are some other good resources as well:</p>
folks in the server as well (there's a few hundred folks).</p>
<a class="header" href="#further-reading" id="further-reading"><h2>Further Reading</h2></a>
<p>If you want to read more about developing on the GBA there are some other good
resources as well:</p>
<ul>
<li><a href="https://www.coranac.com/tonc/text/toc.htm">Tonc</a>, a tutorial series written
for C, but it's what I based the ordering of this book's sections on.</li>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Introduction - Rust GBA Tutorials</title>
<title>Introduction - 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">
@ -72,7 +72,7 @@
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<ol class="chapter"><li><a href="introduction.html" class="active"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<ol class="chapter"><li><a href="introduction.html" class="active"><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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -137,8 +137,31 @@
<div id="content" class="content">
<main>
<a class="header" href="#introduction" id="introduction"><h1>Introduction</h1></a>
<p>Here's a book that'll help you program in Rust on the GBA.</p>
<p>It's very &quot;work in progress&quot;. At the moment there's only one demo program.</p>
<p>Here's a book that'll help you program in Rust on the Game Boy Advance (GBA).</p>
<p>It's a work in progress of course, but so is most of everything in Rust.</p>
<a class="header" href="#style-and-purpose" id="style-and-purpose"><h2>Style and Purpose</h2></a>
<p>I'm out to teach you how to program in Rust on the GBA, obviously. However,
while there <em>is</em> a <a href="https://github.com/rust-console/gba">gba</a> crate, and while I
genuinely believe it to be a good and useful crate for GBA programming, we <em>will
not</em> be using the <code>gba</code> crate within this book. In fact we won't be using any
crates at all. We can call it the <a href="https://handmadehero.org/">Handmade Hero</a>
approach, if you like.</p>
<p>I don't want to just teach you how to use the <code>gba</code> crate, I want to teach you
what you'd need to know to write the crate from scratch if it wasn't there.</p>
<p>Each chapter of the book will focus on a few things you'll need to know about
GBA programming and then present a fully self-contained example that puts those
ideas into action. Just one file per example, no dependencies, no external
assets, no fuss. The examples will be in the text of the book within code
blocks, but also you can find them in the <a href="https://github.com/rust-console/gba/tree/master/examples">examples
directory</a> of the repo
if you want to get them that way.</p>
<a class="header" href="#expected-knowledge" id="expected-knowledge"><h2>Expected Knowledge</h2></a>
<p>I will try not to ask too much of the reader ahead of time, but you are expected
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>.</p>
<p>It's very difficult to know when you've said something that someone else won't
already know about, or if you're presenting ideas out of order. If things aren't
clear please <a href="https://github.com/rust-console/gba/issues">file an issue</a> and
we'll try to address it.</p>
<a class="header" href="#getting-help" id="getting-help"><h2>Getting Help</h2></a>
<p>If you want to contact us you should join the <a href="https://discordapp.com/invite/aVESxV8">Rust Community
Discord</a> and ask in the <code>#gamedev</code>
@ -148,9 +171,10 @@ channel.</p>
<li><code>Lokathor</code> is the fool who decided to write a crate and book for it.</li>
</ul>
<p>If it's <em>not</em> a GBA specific question then you can probably ask any of the other
folks in the server as well.</p>
<a class="header" href="#other-works" id="other-works"><h2>Other Works</h2></a>
<p>If you want to read more about developing on the GBA there are some other good resources as well:</p>
folks in the server as well (there's a few hundred folks).</p>
<a class="header" href="#further-reading" id="further-reading"><h2>Further Reading</h2></a>
<p>If you want to read more about developing on the GBA there are some other good
resources as well:</p>
<ul>
<li><a href="https://www.coranac.com/tonc/text/toc.htm">Tonc</a>, a tutorial series written
for C, but it's what I based the ordering of this book's sections on.</li>
@ -169,7 +193,7 @@ art diagrams and example C struct layouts than GBATEK does.</li>
<a rel="next" href="ch0/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="ch00/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@ -183,7 +207,7 @@ art diagrams and example C struct layouts than GBATEK does.</li>
<a href="ch0/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="ch00/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>

View file

@ -3,7 +3,7 @@
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Rust GBA Tutorials</title>
<title>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">
@ -72,7 +72,7 @@
</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="ch0/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch1/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch1/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch1/io_registers.html"><strong aria-hidden="true">3.2.</strong> IO Registers</a></li><li><a href="ch1/the_display_control_register.html"><strong aria-hidden="true">3.3.</strong> The Display Control Register</a></li><li><a href="ch1/video_memory_intro.html"><strong aria-hidden="true">3.4.</strong> Video Memory Intro</a></li><li><a href="ch1/hello2.html"><strong aria-hidden="true">3.5.</strong> hello2</a></li></ol></li><li><a href="ch2/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch2/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch2/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch2/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li></ol>
<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"><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.html"><strong aria-hidden="true">5.1.</strong> GBA Memory</a></li><li><a href="ch03/tiled_backgrounds.html"><strong aria-hidden="true">5.2.</strong> Tiled Backgrounds</a></li><li><a href="ch03/object_basics.html"><strong aria-hidden="true">5.3.</strong> Object Basics</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.4.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.5.</strong> memory_game</a></li></ol></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
@ -102,7 +102,7 @@
</div>
<h1 class="menu-title">Rust GBA Tutorials</h1>
<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">
@ -137,8 +137,31 @@
<div id="content" class="content">
<main>
<a class="header" href="#introduction" id="introduction"><h1>Introduction</h1></a>
<p>Here's a book that'll help you program in Rust on the GBA.</p>
<p>It's very &quot;work in progress&quot;. At the moment there's only one demo program.</p>
<p>Here's a book that'll help you program in Rust on the Game Boy Advance (GBA).</p>
<p>It's a work in progress of course, but so is most of everything in Rust.</p>
<a class="header" href="#style-and-purpose" id="style-and-purpose"><h2>Style and Purpose</h2></a>
<p>I'm out to teach you how to program in Rust on the GBA, obviously. However,
while there <em>is</em> a <a href="https://github.com/rust-console/gba">gba</a> crate, and while I
genuinely believe it to be a good and useful crate for GBA programming, we <em>will
not</em> be using the <code>gba</code> crate within this book. In fact we won't be using any
crates at all. We can call it the <a href="https://handmadehero.org/">Handmade Hero</a>
approach, if you like.</p>
<p>I don't want to just teach you how to use the <code>gba</code> crate, I want to teach you
what you'd need to know to write the crate from scratch if it wasn't there.</p>
<p>Each chapter of the book will focus on a few things you'll need to know about
GBA programming and then present a fully self-contained example that puts those
ideas into action. Just one file per example, no dependencies, no external
assets, no fuss. The examples will be in the text of the book within code
blocks, but also you can find them in the <a href="https://github.com/rust-console/gba/tree/master/examples">examples
directory</a> of the repo
if you want to get them that way.</p>
<a class="header" href="#expected-knowledge" id="expected-knowledge"><h2>Expected Knowledge</h2></a>
<p>I will try not to ask too much of the reader ahead of time, but you are expected
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>.</p>
<p>It's very difficult to know when you've said something that someone else won't
already know about, or if you're presenting ideas out of order. If things aren't
clear please <a href="https://github.com/rust-console/gba/issues">file an issue</a> and
we'll try to address it.</p>
<a class="header" href="#getting-help" id="getting-help"><h2>Getting Help</h2></a>
<p>If you want to contact us you should join the <a href="https://discordapp.com/invite/aVESxV8">Rust Community
Discord</a> and ask in the <code>#gamedev</code>
@ -148,9 +171,10 @@ channel.</p>
<li><code>Lokathor</code> is the fool who decided to write a crate and book for it.</li>
</ul>
<p>If it's <em>not</em> a GBA specific question then you can probably ask any of the other
folks in the server as well.</p>
<a class="header" href="#other-works" id="other-works"><h2>Other Works</h2></a>
<p>If you want to read more about developing on the GBA there are some other good resources as well:</p>
folks in the server as well (there's a few hundred folks).</p>
<a class="header" href="#further-reading" id="further-reading"><h2>Further Reading</h2></a>
<p>If you want to read more about developing on the GBA there are some other good
resources as well:</p>
<ul>
<li><a href="https://www.coranac.com/tonc/text/toc.htm">Tonc</a>, a tutorial series written
for C, but it's what I based the ordering of this book's sections on.</li>
@ -165,49 +189,53 @@ art diagrams and example C struct layouts than GBATEK does.</li>
<p>Before you can build a GBA game you'll have to follow some special steps to
setup the development environment. Perhaps unfortunately, there's enough detail
here to warrant a mini-chapter all on its own.</p>
<p>Before we begin I'd like to give a special thanks to <strong>Ketsuban</strong>, who is the
wizard that arranged for all of this to be able to happen and laid out the
details of the plan to the rest of the world.</p>
<p>Once again, extra special thanks to <strong>Ketsuban</strong>, who first dove into how to
make this all work with rust and then shared it with the world.</p>
<a class="header" href="#per-system-setup" id="per-system-setup"><h2>Per System Setup</h2></a>
<p>Obviously you need your computer to have a working rust installation. However,
you'll also need to ensure that you're using a nightly toolchain. You can run
<code>rustup default nightly</code> to set nightly as the system wide default toolchain, or
you can use a <a href="https://github.com/rust-lang-nursery/rustup.rs#the-toolchain-file">toolchain
<p>Obviously you need your computer to have a <a href="https://rustup.rs/">working rust
installation</a>. However, you'll also need to ensure that
you're using a nightly toolchain (we will need it for inline assembly, among
other potential useful features). You can run <code>rustup default nightly</code> to set
nightly as the system wide default toolchain, or you can use a <a href="https://github.com/rust-lang-nursery/rustup.rs#the-toolchain-file">toolchain
file</a> to use
nightly just on a specific project, but either way we'll be assuming nightly
from now on.</p>
<p>Next you need <a href="https://devkitpro.org/wiki/Getting_Started">devkitpro</a>. They've
got a graphical installer for Windows, and <code>pacman</code> support on Linux. We'll be
using a few of their binutils for the <code>arm-none-eabi</code> target, and we'll also be
using some of their tools that are specific to GBA development, so <em>even if</em> you
already have the right binutils for whatever reason, you'll still want devkitpro
for the <code>gbafix</code> utility.</p>
nightly just on a specific project, but either way we'll be assuming the use of
nightly from now on. You'll also need the <code>rust-src</code> component so that
<code>cargo-xbuild</code> will be able to compile the core crate for us in a bit, so run
<code>rustup component add rust-src</code>.</p>
<p>Next, you need <a href="https://devkitpro.org/wiki/Getting_Started">devkitpro</a>. They've
got a graphical installer for Windows that runs nicely, and I guess <code>pacman</code>
support on Linux (I'm on Windows so I haven't tried the Linux install myself).
We'll be using a few of their general binutils for the <code>arm-none-eabi</code> target,
and we'll also be using some of their tools that are specific to GBA
development, so <em>even if</em> you already have the right binutils for whatever
reason, you'll still want devkitpro for the <code>gbafix</code> utility.</p>
<ul>
<li>On Windows you'll want something like <code>C:\devkitpro\devkitARM\bin</code> and
<code>C:\devkitpro\tools\bin</code> to be <a href="https://stackoverflow.com/q/44272416/455232">added to your
PATH</a>, depending on where you
installed it to and such.</li>
<li>On Linux you'll also want it to be added to your path, but if you're using
Linux I'll just assume you know how to do all that.</li>
Linux I'll just assume you know how to do all that. I'm told that the default
installation path is <code>/opt/devkitpro/devkitARM/bin</code>, so look there first if
you didn't select some other place.</li>
</ul>
<p>Finally, you'll need <code>cargo-xbuild</code>. Just run <code>cargo install cargo-xbuild</code> and
cargo will figure it all out for you.</p>
<a class="header" href="#per-project-setup" id="per-project-setup"><h2>Per Project Setup</h2></a>
<p>Now you'll need some particular files each time you want to start a new project.
You can find them in the root of the <a href="https://github.com/rust-console/gba">rust-console/gba
repo</a>.</p>
<p>Once the system wide tools are ready, you'll need some particular files each
time you want to start a new project. You can find them in the root of the
<a href="https://github.com/rust-console/gba">rust-console/gba repo</a>.</p>
<ul>
<li><code>thumbv4-none-agb.json</code> describes the overall GBA to cargo-xbuild so it knows
what to do. This is actually a somewhat made up target name since there's no
official target name. The GBA is essentially the same as a normal
<code>thumbv4-none-eabi</code> device, but we give it the &quot;agb&quot; signifier so that later
on we'll be able to use rust's <code>cfg</code> ability to allow our code to know if it's
specifically targeting a GBA or some other similar device (like an NDS).</li>
<li><code>thumbv4-none-agb.json</code> describes the overall GBA to cargo-xbuild (and LLVM)
so it knows what to do. Technically the GBA is <code>thumbv4-none-eabi</code>, but we
change the <code>eabi</code> to <code>agb</code> so that we can distinguish it from other <code>eabi</code>
devices when using <code>cfg</code> flags.</li>
<li><code>crt0.s</code> describes some ASM startup stuff. If you have more ASM to place here
later on this is where you can put it. You also need to build it into a
<code>crt0.o</code> file before it can actually be used, but we'll cover that below.</li>
<li><code>linker.ld</code> tells the linker more critical info about the layout expectations
that the GBA has about our program.</li>
<li><code>linker.ld</code> tells the linker all the critical info about the layout
expectations that the GBA has about our program, and that it should also
include the <code>crt0.o</code> file with our compiled rust code.</li>
</ul>
<a class="header" href="#compiling" id="compiling"><h2>Compiling</h2></a>
<p>The next steps only work once you've got some source code to build. If you need
@ -231,13 +259,13 @@ practically instant operation.</li>
as <code>--release</code>, and options, such as <code>--bin foo</code> or <code>--examples</code>, that you'd
expect <code>cargo</code> to accept.</li>
<li>You <strong>can not</strong> build and run tests this way, because they require <code>std</code>,
which the GBA doesn't have. You can still run some of your project's tests
with <code>cargo test</code>, but that builds for your local machine, so anything
specific to the GBA (such as reading and writing registers) won't be
testable that way. If you want to isolate and try out some piece code
running on the GBA you'll unfortunately have to make a demo for it in your
<code>examples/</code> directory and then run the demo in an emulator and see if it
does what you expect.</li>
which the GBA doesn't have. If you want you can still run some of your
project's tests with <code>cargo test --lib</code> or similar, but that builds for your
local machine, so anything specific to the GBA (such as reading and writing
registers) won't be testable that way. If you want to isolate and try out
some piece code running on the GBA you'll unfortunately have to make a demo
for it in your <code>examples/</code> directory and then run the demo in an emulator
and see if it does what you expect.</li>
<li>The file extension is important. <code>cargo xbuild</code> takes it as a flag to
compile dependencies with the same sysroot, so you can include crates
normally. Well, creates that work in the GBA's limited environment, but you
@ -300,7 +328,10 @@ ROM is patched in place, so we don't even need to specify a new destination.</li
</li>
</ul>
<p>And you're finally done!</p>
<p>Of course, you probably want to make a script for all that, but it's up to you.</p>
<p>Of course, you probably want to make a script for all that, but it's up to you.
On our own project we have it mostly set up within a <code>Makefile.toml</code> which runs
using the <a href="https://github.com/sagiegurari/cargo-make">cargo-make</a> plugin. It's
not really the best plugin, but it's what's available.</p>
<a class="header" href="#ch-1-hello-gba" id="ch-1-hello-gba"><h1>Ch 1: Hello GBA</h1></a>
<p>Traditionally a person writes a &quot;hello, world&quot; program so that they can test
that their development environment is setup properly and to just get a feel for
@ -310,12 +341,12 @@ will look like. All that stuff.</p>
GBA has no terminal, but it does have a screen, so instead we're going to draw
three dots to the screen.</p>
<a class="header" href="#hello1" id="hello1"><h1>hello1</h1></a>
<p>Ready? Here goes:</p>
<p>Our first example will be a totally minimal, full magic number crazy town.
Ready? Here goes:</p>
<p><code>hello1.rs</code></p>
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
@ -332,15 +363,16 @@ fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
}
}
</code></pre></pre>
<p>Throw that into your project, build the program (as described back in Chapter
0), and give it a run. You should see a red, green, and blue dot close-ish to
the middle of the screen. If you don't, something already went wrong. Double
check things, phone a friend, write your senators, try asking Ketsuban on the
<a href="https://discordapp.com/invite/aVESxV8">Rust Community Discord</a>, until you're
able to get your three dots going.</p>
<a class="header" href="#explaining-hello1" id="explaining-hello1"><h2>Explaining hello1</h2></a>
<p>Throw that into your project skeleton, build the program (as described back in
Chapter 0), and give it a run in your emulator. You should see a red, green, and
blue dot close-ish to the middle of the screen. If you don't, something already
went wrong. Double check things, phone a friend, write your senators, try asking
Ketsuban on the <a href="https://discordapp.com/invite/aVESxV8">Rust Community Discord</a>,
until you're able to get your three dots going.</p>
<a class="header" href="#a-basic-hello1-explanation" id="a-basic-hello1-explanation"><h2>A basic hello1 explanation</h2></a>
<p>So, what just happened? Even if you're used to Rust that might look pretty
strange. We'll go over each part extra carefully.</p>
strange. We'll go over most of the little parts right here, and then bigger
parts will get their own sections.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#![feature(start)]
@ -364,7 +396,6 @@ only life.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
@ -376,9 +407,6 @@ Basically, if we somehow trigger a panic, this is where the program goes.
However, right now we don't know how to get any sort of message out to the user
so... we do nothing at all. We <em>can't even return</em> from here, so we just sit in
an infinite loop. The player will have to reset the universe from the outside.</p>
<p>The <code>#[cfg(not(test))]</code> part makes this item only exist in the program when
we're <em>not</em> in a test build. This is so that <code>cargo test</code> and such work right as
much as possible.</p>
<pre><pre class="playpen"><code class="language-rust">#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
</code></pre></pre>
@ -442,18 +470,17 @@ magic numbers mean or do.</p>
<li><code>0x06000000</code> is the start of Video RAM.</li>
</ul>
<p>So we write some magic to the display control register once, then we write some
other magic to three locations of magic to the Video RAM. We get three dots,
each in their own location... so that second part makes sense at least.</p>
<p>We'll get into the magic number details in the other sections of this chapter.</p>
<a class="header" href="#sidebar-volatile" id="sidebar-volatile"><h2>Sidebar: Volatile</h2></a>
<p>We'll get into what all that is in a moment, but first let's ask ourselves: Why
are we doing <em>volatile</em> writes? You've probably never used it before at all.
What is volatile anyway?</p>
<p>Well, the optimizer is pretty aggressive some of the time, 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 right, but sometimes it's wrong.</p>
other magic to three magic locations in the Video RAM. Somehow that shows three
dots. Gotta read on to find out why!</p>
<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
@ -466,18 +493,48 @@ only relative to other volatile operations. So something like</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
c.volatile_write(5);
c.write_volatile(5);
a += b;
d.volatile_write(7);
d.write_volatile(7);
#}</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
<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 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 thread
safety concerns.</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>
<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&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))
}
}
#}</code></pre></pre>
<a class="header" href="#io-registers" id="io-registers"><h1>IO Registers</h1></a>
<p>The GBA has a large number of <strong>IO Registers</strong> (not to be confused with CPU
registers). These are special memory locations from <code>0x04000000</code> to
@ -597,8 +654,6 @@ some nifty graphical effects.</p>
binary</a>, and we get
<code>0b100_0000_0011</code>. So, that's setting Mode 3 with background 2 enabled and
nothing else special.</p>
<p>However, I think we can do better than that. This is a prime target for more
newtyping as we attempt a <code>hello2</code> program.</p>
<a class="header" href="#video-memory-intro" id="video-memory-intro"><h1>Video Memory Intro</h1></a>
<p>The GBA's Video RAM is 96k stretching from <code>0x0600_0000</code> to <code>0x0601_7FFF</code>.</p>
<p>The Video RAM can only be accessed totally freely during a Vertical Blank (aka
@ -691,9 +746,9 @@ data to fit in two pages, we compress the resolution.</p>
again we probably need to <a href="https://www.wolframalpha.com/">convert them</a> into
binary to make sense of it.</p>
<ul>
<li>0x001F: 0b11111</li>
<li>0x03E0: 0b11111_00000</li>
<li>0x7C00: 0b11111_00000_00000</li>
<li>0x001F: 0b0_00000_00000_11111</li>
<li>0x03E0: 0b0_00000_11111_00000</li>
<li>0x7C00: 0b0_11111_00000_00000</li>
</ul>
<p>Ah, of course, a red pixel, a green pixel, and a blue pixel.</p>
<a class="header" href="#hello2" id="hello2"><h1>hello2</h1></a>
@ -702,7 +757,6 @@ binary to make sense of it.</p>
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
@ -720,11 +774,12 @@ fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
}
</code></pre></pre>
<p>Now let's clean this up so that it's clearer what's going on.</p>
<p>First we'll label that display control stuff:</p>
<p>First we'll label that display control stuff, including using the <code>VolatilePtr</code>
type from the volatile explanation:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
pub const DISPCNT: VolatilePtr&lt;u16&gt; = VolatilePtr(0x04000000 as *mut u16);
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
#}</code></pre></pre>
@ -735,8 +790,11 @@ pub const BG2: u16 = 0b100_0000_0000;
pub const VRAM: usize = 0x06000000;
pub const SCREEN_WIDTH: isize = 240;
#}</code></pre></pre>
<p>And then we want a small helper function for putting together a color value.</p>
<p>Happily, this one can even be declared as a const function. At the time of
<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
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>
@ -754,7 +812,7 @@ usually helps you think about it a lot better.</p>
# #![allow(unused_variables)]
#fn main() {
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
#}</code></pre></pre>
<p>So now we've got this:</p>
@ -762,7 +820,6 @@ pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
<pre><pre class="playpen"><code class="language-rust">#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
loop {}
@ -771,7 +828,7 @@ fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
unsafe {
DISPCNT.write_volatile(MODE3 | BG2);
DISPCNT.write(MODE3 | BG2);
mode3_pixel(120, 80, rgb16(31, 0, 0));
mode3_pixel(136, 80, rgb16(0, 31, 0));
mode3_pixel(120, 96, rgb16(0, 0, 31));
@ -779,7 +836,22 @@ fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
}
}
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
#[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);
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
@ -791,13 +863,14 @@ pub const fn rgb16(red: u16, green: u16, blue: u16) -&gt; u16 {
}
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
</code></pre></pre>
<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. Still, for educational
purposes it's often best to do it yourself at least once.</p>
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>
<a class="header" href="#ch-2-user-input" id="ch-2-user-input"><h1>Ch 2: User Input</h1></a>
<p>It's all well and good to draw three pixels, but they don't do anything yet. We
want them to do something, and for that we need to get some input from the user.</p>
@ -865,15 +938,15 @@ reading and writing the key bits.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub const KEYINPUT: *mut u16 = 0x400_0130 as *mut u16;
pub const KEYINPUT: VolatilePtr&lt;u16&gt; = VolatilePtr(0x400_0130 as *mut u16);
/// A newtype over the key input state of the GBA.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct KeyInputSetting(u16);
pub fn read_key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile()) }
pub fn key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read()) }
}
#}</code></pre></pre>
<p>Now we want a way to check if a key is <em>being pressed</em>, since that's normally
@ -898,12 +971,14 @@ folded and refolded by the compiler, but we can just check.</p>
<p>It turns out that the <code>!=0</code> test is 4 instructions and the <code>==0</code> test is 6
instructions. Since we want to get savings where we can, and we'll probably
check the keys of an input often enough, we'll just always use a <code>!=0</code> test and
then adjust how we initially read the register to compensate.</p>
then adjust how we initially read the register to compensate. By using xor with
a mask for only the 10 used bits we can flip the &quot;low when pressed&quot; values so
that the entire result has active bits in all positions where a key is pressed.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub fn read_key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b1111_1111_1111_1111) }
pub fn key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b0000_0011_1111_1111) }
}
#}</code></pre></pre>
<p>Now we add a method for seeing if a key is pressed. In the full library there's
@ -1060,10 +1135,10 @@ quickly during the blank period.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub const VCOUNT: *mut u16 = 0x0400_0006 as *mut u16;
pub const VCOUNT: VolatilePtr&lt;u16&gt; = VolatilePtr(0x0400_0006 as *mut u16);
pub fn read_vcount() -&gt; u16 {
unsafe { VCOUNT.read_volatile() }
pub fn vcount() -&gt; u16 {
unsafe { VCOUNT.read() }
}
#}</code></pre></pre>
<p>Then we want two little helper functions to wait until VBlank and vdraw.</p>
@ -1073,11 +1148,11 @@ pub fn read_vcount() -&gt; u16 {
pub const SCREEN_HEIGHT: isize = 160;
pub fn wait_until_vblank() {
while read_vcount() &lt; SCREEN_HEIGHT as u16 {}
while vcount() &lt; SCREEN_HEIGHT as u16 {}
}
pub fn wait_until_vdraw() {
while read_vcount() &gt;= SCREEN_HEIGHT as u16 {}
while vcount() &gt;= SCREEN_HEIGHT as u16 {}
}
#}</code></pre></pre>
<p>And... that's it. No special types to be made this time around, it's just a
@ -1096,21 +1171,21 @@ go off the screen or if they touch their own trail.</p>
pub unsafe fn mode3_clear_screen(color: u16) {
let color = color as u32;
let bulk_color = color &lt;&lt; 16 | color;
let mut ptr = VRAM as *mut u32;
let mut ptr = VolatilePtr(VRAM as *mut u32);
for _ in 0..SCREEN_HEIGHT {
for _ in 0..(SCREEN_WIDTH / 2) {
ptr.write_volatile(bulk_color);
ptr.write(bulk_color);
ptr = ptr.offset(1);
}
}
}
pub unsafe fn mode3_draw_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
pub unsafe fn mode3_read_pixel(col: isize, row: isize) -&gt; u16 {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read_volatile()
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read()
}
#}</code></pre></pre>
<p>The draw pixel and read pixel are both pretty obvious. What's new is the clear
@ -1122,7 +1197,7 @@ screen clear is twice as fast.</p>
<pre><pre class="playpen"><code class="language-rust">#[start]
fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
unsafe {
DISPCNT.write_volatile(MODE3 | BG2);
DISPCNT.write(MODE3 | BG2);
}
let mut px = SCREEN_WIDTH / 2;
@ -1131,7 +1206,7 @@ fn main(_argc: isize, _argv: *const *const u8) -&gt; isize {
loop {
// read the input for this frame
let this_frame_keys = read_key_input();
let this_frame_keys = key_input();
// adjust game state and wait for vblank
px += 2 * this_frame_keys.column_direction() as isize;
@ -1182,9 +1257,271 @@ different colors.</p>
it's not black that means we've been here before and the player has crashed into
their own line. In this case, we reset the game without moving them to a new
location.</p>
<p>Finally, if the player is in bounds and they haven't crashed, we write their color into memory at this position.</p>
<p>Finally, if the player is in bounds and they haven't crashed, we write their
color into memory at this position.</p>
<p>Regardless of how it worked out, we hold here until vdraw starts before going to
the next loop.</p>
the next loop. That's all there is to it.</p>
<a class="header" href="#the-gba-crate-doesnt-quite-work-like-this" id="the-gba-crate-doesnt-quite-work-like-this"><h2>The gba crate doesn't quite work like this</h2></a>
<p>Once again, as with the <code>hello1</code> and <code>hello2</code> examples, the <code>gba</code> crate covers
much of this same ground as our example here, but in slightly different ways.</p>
<p>Better organization and abstractions are usually only realized once you've used
more of the whole thing you're trying to work with. If we want to have a crate
where the whole thing is well integrated with itself, then the examples would
also end up having to explain about things we haven't really touched on much
yet. It becomes a lot harder to teach.</p>
<p>So, going forward, we will continue to teach concepts and build examples that
don't directly depend on the <code>gba</code> crate. This allows the crate to freely grow
without all the past examples becoming a great inertia upon it.</p>
<a class="header" href="#ch-3-memory-and-objects" id="ch-3-memory-and-objects"><h1>Ch 3: Memory and Objects</h1></a>
<p>Alright so we can do some basic &quot;movement&quot;, but we left a big trail in the video
memory of everywhere we went. Most of the time that's not what we want at all.
If we want more hardware support we're going to have to use a new video mode. So
far we've only used Mode 3, but modes 4 and 5 are basically the same. Instead,
we'll switch focus to using a tiled graphical mode.</p>
<p>First we will go over the complete GBA memory mapping. Part of this is the
memory for tiled graphics, but also things like all those IO registers, where
our RAM is for scratch space, all that stuff. Even if we can't put all of them
to use at once, it's helpful to have an idea of what will be available in the
long run.</p>
<p>Tiled modes bring us two big new concepts that each have their own complexity:
backgrounds and objects. They share some concepts, but fundamentally the
background is for creating a very large static space that you can scroll around
the view within, and the objects are about having a few moving bits that appear
over the background. Careful use of backgrounds and objects is key to having the
best looking GBA game, so we won't even be able to cover it all in a single
chapter.</p>
<p>And, of course, since most games are pretty boring if they're totally static
we'll touch on the kinds of RNG implementations you might want to have on a GBA.
Most general purpose RNGs that you find are rather big compared to the amount of
memory we want to give them, and they often use a lot of <code>u64</code> operations, so
they end up much slower on a 32-bit machine like the GBA (you can lower 64-bit
ops to combinations of 32-bit ops, but that's quite a bit more work). We'll
cover a few RNG options that size down the RNG to a good size and a good speed
without trading away too much in terms of quality.</p>
<p>To top it all off, we'll make a simple &quot;memory game&quot; sort of thing. There's some
face down cards in a grid, you pick one to check, then you pick the other to
check, and then if they match the pair disappears.</p>
<a class="header" href="#gba-memory" id="gba-memory"><h1>GBA Memory</h1></a>
<p>The <a href="http://problemkaputt.de/gbatek.htm#gbamemorymap">GBA Memory Map</a> has
several memory portions to it, each with their own little differences. Most of
the memory has pre-determined use according to the hardware, but there is also
space for games to use as a scratch pad in whatever way the game sees fit.</p>
<p>The memory ranges listed here are <em>inclusive</em>, so they end with a lot of <code>F</code>s
and <code>E</code>s.</p>
<p>We've talked about volatile memory before, but just as a reminder I'll say that
all of the memory we'll talk about here should be accessed with volatile with
two exceptions:</p>
<ol>
<li>Work RAM (both internal and external) can be used normally, and if the
compiler is able to totally elide any reads and writes that's okay.</li>
<li>However, if you set aside any space in Work RAM where an interrupt will
communicate with the main program then that specific location will have to
keep using volatile access, since the compiler never knows when an interrupt
will actually happen.</li>
</ol>
<a class="header" href="#bios--system-rom" id="bios--system-rom"><h2>BIOS / System ROM</h2></a>
<ul>
<li><code>0x0</code> to <code>0x3FFF</code> (16k)</li>
</ul>
<p>This is special memory for the BIOS. It is &quot;read-only&quot;, but even then it's only
accessible when the program counter is pointing into the BIOS region. At all
other times you get a <a href="http://problemkaputt.de/gbatek.htm#gbaunpredictablethings">garbage
value</a> back when you
try to read out of the BIOS.</p>
<a class="header" href="#external-work-ram--ewram" id="external-work-ram--ewram"><h2>External Work RAM / EWRAM</h2></a>
<ul>
<li><code>0x2000000</code> to <code>0x203FFFF</code> (256k)</li>
</ul>
<p>This is a big pile of space, the use of which is up to each game. However, the
external work ram has only a 16-bit bus (if you read/write a 32-bit value it
silently breaks it up into two 16-bit operations) and also 2 wait cycles (extra
CPU cycles that you have to expend <em>per 16-bit bus use</em>).</p>
<p>In other words, we should think of EWRAM as if it was &quot;heap space&quot; in a normal
application. You can take the time to go store something within EWRAM, or to
load it out of EWRAM, but you should always avoid doing a critical computation
on values in EWRAM. It's a bit of a pain, but if you wanna be speedy and you
have more than just one manipulation that you want to do, you should pull the
value into a local variable, do all of your manipulations, and then push it back
out at the end.</p>
<a class="header" href="#internal-work-ram--iwram" id="internal-work-ram--iwram"><h2>Internal Work RAM / IWRAM</h2></a>
<ul>
<li><code>0x3000000</code> to <code>0x3007FFF</code> (32k)</li>
</ul>
<p>This is a smaller pile of space, but it has a 32-bit bus and no wait.</p>
<p>By default, <code>0x3007F00</code> to <code>0x3007FFF</code> is reserved for interrupt and BIOS use.
The rest of it is totally up to you. The user's stack space starts at
<code>0x3007F00</code> and proceeds <em>down</em> from there. In other words, if you start your
own customized IWRAM use at <code>0x3000000</code> and go up, eventually you might hit your
stack. However, most reasonable uses won't actually cause a memory collision.
It's just something you should know about if you're using a ton of stack or
IWRAM and then get problems.</p>
<a class="header" href="#io-registers-1" id="io-registers-1"><h2>IO Registers</h2></a>
<ul>
<li><code>0x4000000</code> to <code>0x40003FE</code></li>
</ul>
<p>We've touched upon a few of these so far, and we'll get to more later. At the
moment it is enough to say that, as you might have guessed, all of them live in
this region. Each individual register is a <code>u16</code> or <code>u32</code> and they control all
sorts of things. We'll actually be talking about some more of them in this very
chapter, because that's how we'll control some of the background and object
stuff.</p>
<a class="header" href="#palette-ram--palram" id="palette-ram--palram"><h2>Palette RAM / PALRAM</h2></a>
<ul>
<li><code>0x5000000</code> to <code>0x50003FF</code> (1k)</li>
</ul>
<p>Palette RAM has a 16-bit bus, which isn't really a problem because it
conceptually just holds <code>u16</code> values. There's no automatic wait state, but if
you try to access the same location that the display controller is accessing you
get bumped by 1 cycle. Since the display controller can use the palette ram any
number of times per scanline it's basically impossible to predict if you'll have
to do a wait or not during VDraw. During VBlank you won't have any wait of
course.</p>
<p>PALRAM is among the memory where there's weirdness if you try to write just one
byte: if you try to write just 1 byte, it writes that byte into <em>both</em> parts of
the larger 16-bit location. This doesn't really affect us much with PALRAM,
because palette values are all supposed to be <code>u16</code> anyway.</p>
<p>The palette memory actually contains not one, but <em>two</em> sets of palettes. First
there's 256 entries for the background palette data (starting at <code>0x5000000</code>),
and then there's 256 entries for object palette data (starting at <code>0x5000200</code>).</p>
<p>The GBA also has two modes for palette access: 8-bits-per-pixel (8bpp) and
4-bits-per-pixel (4bpp).</p>
<ul>
<li>In 8bpp mode an (8-bit) palette index value within a background or sprite
simply indexes directly into the 256 slots for that type of thing.</li>
<li>In 4bpp mode a (4-bit) palette index value within a background or sprite
specifies an index within a particular &quot;palbank&quot; (16 palette entries each),
and then a <em>separate</em> setting outside of the graphical data determines which
palbank is to be used for that background or object (the screen entry data for
backgrounds, and the object attributes for objects).</li>
</ul>
<a class="header" href="#video-ram--vram" id="video-ram--vram"><h2>Video RAM / VRAM</h2></a>
<ul>
<li><code>0x6000000</code> to <code>0x6017FFF</code> (96k)</li>
</ul>
<p>We've used this before! VRAM has a 16-bit bus and no wait. However, the same as
with PALRAM, the &quot;you might have to wait if the display controller is looking at
it&quot; rule applies here.</p>
<p>Unfortunately there's not much more exact detail that can be given about VRAM.
The use of the memory depends on the video mode that you're using.</p>
<p>One general detail of note is that you can't write individual bytes to any part
of VRAM. Depending on mode and location, you'll either get your bytes doubled
into both the upper and lower parts of the 16-bit location targeted, or you
won't even affect the memory. This usually isn't a big deal, except in two
situations:</p>
<ul>
<li>In Mode 4, if you want to change just 1 pixel, you'll have to be very careful
to read the old <code>u16</code>, overwrite just the byte you wanted to change, and then
write that back.</li>
<li>In any display mode, avoid using <code>memcopy</code> to place things into VRAM.
It's written to be byte oriented, and only does 32-bit transfers under select
conditions. The rest of the time it'll copy one byte at a time and you'll get
either garbage or nothing at all.</li>
</ul>
<a class="header" href="#object-attribute-memory--oam" id="object-attribute-memory--oam"><h2>Object Attribute Memory / OAM</h2></a>
<ul>
<li><code>0x7000000</code> to <code>0x70003FF</code> (1k)</li>
</ul>
<p>The Object Attribute Memory has a 32-bit bus and no default wait, but suffers
from the &quot;you might have to wait if the display controller is looking at it&quot;
rule. You cannot write individual bytes to OAM at all, but that's not really a
problem because all the fields of the data types within OAM are either <code>i16</code> or
<code>u16</code> anyway.</p>
<p>Object attribute memory is the wildest yet: it conceptually contains two types
of things, but they're <em>interlaced</em> with each other all the way through.</p>
<p>Now, <a href="http://problemkaputt.de/gbatek.htm#lcdobjoamattributes">GBATEK</a> and
<a href="https://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm#OAM%20(sprites)">CowByte</a>
doesn't quite give names to the two data types, though
<a href="https://www.coranac.com/tonc/text/regobj.htm#sec-oam">TONC</a> calls them
<code>OBJ_ATTR</code> and <code>OBJ_AFFINE</code>. We'll give them Rust names of course. In Rust terms
their layout would look like this:</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[repr(C)]
pub struct ObjectAttribute {
attr0: u16,
attr1: u16,
attr2: u16,
filler: i16,
}
#[repr(C)]
pub struct AffineMatrix {
filler0: [u16; 3],
pa: i16,
filler1: [u16; 3],
pb: i16,
filler2: [u16; 3],
pc: i16,
filler3: [u16; 3],
pd: i16,
}
#}</code></pre></pre>
<p>(Note: the <code>#[repr(C)]</code> part just means that Rust must lay out the data exactly
in the order we specify, which otherwise it is not required to do).</p>
<p>So, we've got 1024 bytes in OAM and each <code>ObjectAttribute</code> value is 8 bytes, so
naturally we can support up to 128 objects.</p>
<p><em>At the same time</em>, we've got 1024 bytes in OAM and each <code>AffineMatrix</code> is 32
bytes, so we can have 32 of them.</p>
<p>But, as I said, these things are all <em>interlaced</em> with each other. See how
there's &quot;filler&quot; fields in each struct? If we imagine the OAM as being just an
array of one type or the other, indexes 0/1/2/3 of the <code>ObjectAttribute</code> array
would line up with index 0 of the <code>AffineMatrix</code> array. It's kinda weird, but
that's just how it works. When we setup functions to read and write these values
we'll have to be careful with how we do it. We probably <em>won't</em> want to use
those representations above, at least not with the <code>AffineMatrix</code> type, because
they're quite wasteful if you want to store just object attributes or just
affine matrices.</p>
<a class="header" href="#game-pak-rom--flash-rom" id="game-pak-rom--flash-rom"><h2>Game Pak ROM / Flash ROM</h2></a>
<ul>
<li><code>0x8000000</code> to <code>0x9FFFFFF</code> (wait 0)</li>
<li><code>0xA000000</code> to <code>0xBFFFFFF</code> (wait 1)</li>
<li><code>0xC000000</code> to <code>0xDFFFFFF</code> (wait 2)</li>
<li>Max of 32Mb</li>
</ul>
<p>These portions of the memory are less fixed, because they depend on the precise
details of the game pak you've inserted into the GBA. In general, they connect
to the game pak ROM and/or Flash memory, using a 16-bit bus. The ROM is
read-only, but the Flash memory (if any) allows writes.</p>
<p>The game pak ROM is listed as being in three sections, but it's actually the
same memory being effectively mirrored into three different locations. The
mirror that you choose to access the game pak through affects which wait state
setting it uses (configured via IO register of course). Unfortunately, the
details come down more to the game pak hardware that you load your game onto
than anything else, so there's not much I can say right here. We'll eventually
talk about it more later,</p>
<p>One thing of note is the way that the 16-bit bus affects us: the instructions to
execute are coming through the same bus as the rest of the game data, so we want
them to be as compact as possible. The ARM chip in the GBA supports two
different instruction sets, &quot;thumb&quot; and &quot;non-thumb&quot;. The thumb mode instructions
are 16-bit, so they can each be loaded one at a time, and the non-thumb
instructions are 32-bit, so we're at a penalty if we execute them directly out
of the game pak. However, some things will demand that we use non-thumb code, so
we'll have to deal with that eventually. It's possible to switch between modes,
but it's a pain to keep track of what mode you're in because there's not
currently support for it in Rust itself (perhaps some day). So we'll stick with
thumb code as much as we possibly can, that's why our target profile for our
builds starts with <code>thumbv4</code>.</p>
<a class="header" href="#game-pak-sram" id="game-pak-sram"><h2>Game Pak SRAM</h2></a>
<ul>
<li><code>0xE000000</code> to <code>0xE00FFFF</code> (64k)</li>
</ul>
<p>The game pak SRAM has an 8-bit bus. Why did pokemon always take so long to save?
This is why. It also has some amount of wait, but as with the ROM, the details
depend on your game pak hardware (and also as with ROM, you can adjust the
settings with an IO register, should you need to).</p>
<p>One thing to note about the SRAM is that the GBA has a Direct Memory Access
(DMA) feature that can be used for bulk memory movements in some cases, but the
DMA <em>cannot</em> access the SRAM region. You really are stuck reading and writing
one byte at a time when you're using the SRAM.</p>
<a class="header" href="#tiled-backgrounds" id="tiled-backgrounds"><h1>Tiled Backgrounds</h1></a>
<p>TODO</p>
<a class="header" href="#object-basics" id="object-basics"><h1>Object Basics</h1></a>
<p>TODO</p>
<a class="header" href="#gba-rng" id="gba-rng"><h1>GBA RNG</h1></a>
<p>TODO</p>
<a class="header" href="#memory_game" id="memory_game"><h1>memory_game</h1></a>
<p>TODO</p>
</main>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,6 @@
#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}

View file

@ -1,7 +1,6 @@
#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
@ -10,7 +9,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
unsafe {
DISPCNT.write_volatile(MODE3 | BG2);
DISPCNT.write(MODE3 | BG2);
mode3_pixel(120, 80, rgb16(31, 0, 0));
mode3_pixel(136, 80, rgb16(0, 31, 0));
mode3_pixel(120, 96, rgb16(0, 0, 31));
@ -18,7 +17,22 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
}
}
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
#[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))
}
}
pub const DISPCNT: VolatilePtr<u16> = VolatilePtr(0x04000000 as *mut u16);
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
@ -30,5 +44,5 @@ pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
}
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}

View file

@ -1,7 +1,6 @@
#![feature(start)]
#![no_std]
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
@ -10,7 +9,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
unsafe {
DISPCNT.write_volatile(MODE3 | BG2);
DISPCNT.write(MODE3 | BG2);
}
let mut px = SCREEN_WIDTH / 2;
@ -19,7 +18,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
loop {
// read the input for this frame
let this_frame_keys = read_key_input();
let this_frame_keys = key_input();
// adjust game state and wait for vblank
px += 2 * this_frame_keys.column_direction() as isize;
@ -53,7 +52,22 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
}
}
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
#[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))
}
}
pub const DISPCNT: VolatilePtr<u16> = VolatilePtr(0x04000000 as *mut u16);
pub const MODE3: u16 = 3;
pub const BG2: u16 = 0b100_0000_0000;
@ -68,24 +82,24 @@ pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
pub unsafe fn mode3_clear_screen(color: u16) {
let color = color as u32;
let bulk_color = color << 16 | color;
let mut ptr = VRAM as *mut u32;
let mut ptr = VolatilePtr(VRAM as *mut u32);
for _ in 0..SCREEN_HEIGHT {
for _ in 0..(SCREEN_WIDTH / 2) {
ptr.write_volatile(bulk_color);
ptr.write(bulk_color);
ptr = ptr.offset(1);
}
}
}
pub unsafe fn mode3_draw_pixel(col: isize, row: isize, color: u16) {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
pub unsafe fn mode3_read_pixel(col: isize, row: isize) -> u16 {
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read_volatile()
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read()
}
pub const KEYINPUT: *mut u16 = 0x400_0130 as *mut u16;
pub const KEYINPUT: VolatilePtr<u16> = VolatilePtr(0x400_0130 as *mut u16);
/// A newtype over the key input state of the GBA.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
@ -101,8 +115,8 @@ pub enum TriBool {
Plus = 1,
}
pub fn read_key_input() -> KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b1111_1111_1111_1111) }
pub fn key_input() -> KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read() ^ 0b0000_0011_1111_1111) }
}
pub const KEY_A: u16 = 1 << 0;
@ -146,16 +160,16 @@ impl KeyInputSetting {
}
}
pub const VCOUNT: *mut u16 = 0x0400_0006 as *mut u16;
pub const VCOUNT: VolatilePtr<u16> = VolatilePtr(0x0400_0006 as *mut u16);
pub fn read_vcount() -> u16 {
unsafe { VCOUNT.read_volatile() }
pub fn vcount() -> u16 {
unsafe { VCOUNT.read() }
}
pub fn wait_until_vblank() {
while read_vcount() < SCREEN_HEIGHT as u16 {}
while vcount() < SCREEN_HEIGHT as u16 {}
}
pub fn wait_until_vdraw() {
while read_vcount() >= SCREEN_HEIGHT as u16 {}
while vcount() >= SCREEN_HEIGHT as u16 {}
}

197
examples/memory_game.rs Normal file
View file

@ -0,0 +1,197 @@
#![feature(start)]
#![no_std]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
unsafe {
DISPCNT.write(MODE3 | BG2);
}
let mut px = SCREEN_WIDTH / 2;
let mut py = SCREEN_HEIGHT / 2;
let mut color = rgb16(31, 0, 0);
loop {
// read the input for this frame
let this_frame_keys = key_input();
// adjust game state and wait for vblank
px += 2 * this_frame_keys.column_direction() as isize;
py += 2 * this_frame_keys.row_direction() as isize;
wait_until_vblank();
// draw the new game and wait until the next frame starts.
unsafe {
if px < 0 || py < 0 || px == SCREEN_WIDTH || py == SCREEN_HEIGHT {
// out of bounds, reset the screen and position.
mode3_clear_screen(0);
color = color.rotate_left(5);
px = SCREEN_WIDTH / 2;
py = SCREEN_HEIGHT / 2;
} else {
let color_here = mode3_read_pixel(px, py);
if color_here != 0 {
// crashed into our own line, reset the screen
mode3_clear_screen(0);
color = color.rotate_left(5);
} else {
// draw the new part of the line
mode3_draw_pixel(px, py, color);
mode3_draw_pixel(px, py + 1, color);
mode3_draw_pixel(px + 1, py, color);
mode3_draw_pixel(px + 1, py + 1, color);
}
}
}
wait_until_vdraw();
}
}
#[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))
}
}
pub const DISPCNT: VolatilePtr<u16> = VolatilePtr(0x04000000 as *mut u16);
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 SCREEN_HEIGHT: isize = 160;
pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
blue << 10 | green << 5 | red
}
pub unsafe fn mode3_clear_screen(color: u16) {
let color = color as u32;
let bulk_color = color << 16 | color;
let mut ptr = VolatilePtr(VRAM as *mut u32);
for _ in 0..SCREEN_HEIGHT {
for _ in 0..(SCREEN_WIDTH / 2) {
ptr.write(bulk_color);
ptr = ptr.offset(1);
}
}
}
pub unsafe fn mode3_draw_pixel(col: isize, row: isize, color: u16) {
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
pub unsafe fn mode3_read_pixel(col: isize, row: isize) -> u16 {
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read()
}
pub const KEYINPUT: VolatilePtr<u16> = VolatilePtr(0x400_0130 as *mut u16);
/// A newtype over the key input state of the GBA.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct KeyInputSetting(u16);
/// A "tribool" value helps us interpret the arrow pad.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum TriBool {
Minus = -1,
Neutral = 0,
Plus = 1,
}
pub fn key_input() -> KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read() ^ 0b0000_0011_1111_1111) }
}
pub const KEY_A: u16 = 1 << 0;
pub const KEY_B: u16 = 1 << 1;
pub const KEY_SELECT: u16 = 1 << 2;
pub const KEY_START: u16 = 1 << 3;
pub const KEY_RIGHT: u16 = 1 << 4;
pub const KEY_LEFT: u16 = 1 << 5;
pub const KEY_UP: u16 = 1 << 6;
pub const KEY_DOWN: u16 = 1 << 7;
pub const KEY_R: u16 = 1 << 8;
pub const KEY_L: u16 = 1 << 9;
impl KeyInputSetting {
pub fn contains(&self, key: u16) -> bool {
(self.0 & key) != 0
}
pub fn difference(&self, other: KeyInputSetting) -> KeyInputSetting {
KeyInputSetting(self.0 ^ other.0)
}
pub fn column_direction(&self) -> TriBool {
if self.contains(KEY_RIGHT) {
TriBool::Plus
} else if self.contains(KEY_LEFT) {
TriBool::Minus
} else {
TriBool::Neutral
}
}
pub fn row_direction(&self) -> TriBool {
if self.contains(KEY_DOWN) {
TriBool::Plus
} else if self.contains(KEY_UP) {
TriBool::Minus
} else {
TriBool::Neutral
}
}
}
pub const VCOUNT: VolatilePtr<u16> = VolatilePtr(0x0400_0006 as *mut u16);
pub fn vcount() -> u16 {
unsafe { VCOUNT.read() }
}
pub fn wait_until_vblank() {
while vcount() < SCREEN_HEIGHT as u16 {}
}
pub fn wait_until_vdraw() {
while vcount() >= SCREEN_HEIGHT as u16 {}
}
#[repr(C)]
#[align(4)]
pub struct ObjectAttributes {
attr0: u16,
attr1: u16,
attr2: u16,
filler: i16,
}
#[repr(C)]
#[align(4)]
pub struct ObjectAffine {
filler0: [u16; 3],
pa: i16,
filler1: [u16; 3],
pb: i16,
filler2: [u16; 3],
pc: i16,
filler3: [u16; 3],
pd: i16,
}

View file

@ -8,7 +8,7 @@ MEMORY {
SECTIONS {
.text : {
KEEP(crt0.o(.text));
KEEP(target/crt0.o(.text));
*(.text .text.*);
. = ALIGN(4);
} >rom = 0xff

View file

@ -1,11 +1,13 @@
//! Things that I wish were in core, but aren't.
/// A simple wrapper to any `*mut T` so that the basic "read" and "write"
/// operations are volatile.
/// A simple wrapper for any `*mut T` to adjust the basic operations.
///
/// Accessing the GBA's IO registers and video ram and specific other places on
/// **must** be done with volatile operations. Having this wrapper makes that
/// more clear for all the global const values into IO registers.
/// Read and Write are made to be volatile. Offset is made to be
/// wrapping_offset. This makes it much easier to correctly work with IO
/// Registers and all display related memory on the GBA.
///
/// As a bonus, use of this type is mostly `cargo test` safe. Reads will return
/// a `zeroed()` value instead, and writes will do nothing.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct VolatilePtr<T>(pub *mut T);
@ -25,7 +27,14 @@ impl<T> VolatilePtr<T> {
/// This method adds absolutely no additional safety, so all safety concerns
/// for a normal raw pointer volatile read apply.
pub unsafe fn read(&self) -> T {
core::ptr::read_volatile(self.0)
#[cfg(not(test))]
{
core::ptr::read_volatile(self.0)
}
#[cfg(test)]
{
core::mem::zeroed::<T>()
}
}
/// Performs a volatile write.
@ -35,16 +44,23 @@ impl<T> VolatilePtr<T> {
/// This method adds absolutely no additional safety, so all safety concerns
/// for a normal raw pointer volatile write apply.
pub unsafe fn write(&self, data: T) {
core::ptr::write_volatile(self.0, data);
#[cfg(not(test))]
{
core::ptr::write_volatile(self.0, data);
}
#[cfg(test)]
{
drop(data)
}
}
/// Offsets this address by the amount given.
/// Performs a wrapping_offset by the number of slots given to a new position.
///
/// # Safety
///
/// This is a standard offset, so all safety concerns of a normal raw pointer
/// offset apply.
/// This is a wrapping_offset, so all safety concerns of a normal raw pointer
/// wrapping_offset apply.
pub unsafe fn offset(self, count: isize) -> Self {
VolatilePtr(self.0.offset(count))
VolatilePtr(self.0.wrapping_offset(count))
}
}

View file

@ -15,7 +15,7 @@
// TODO(lokathor): IO Register newtypes.
use gba_proc_macro::register_bit;
use gba_proc_macro::{newtype, register_bit};
use super::*;
@ -24,10 +24,11 @@ use super::*;
/// * [gbatek entry](http://problemkaputt.de/gbatek.htm#lcdiodisplaycontrol)
pub const DISPCNT: VolatilePtr<u16> = VolatilePtr(0x4000000 as *mut u16);
/// A newtype over the various display control options that you have on a GBA.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct DisplayControlSetting(u16);
newtype!(
DisplayControlSetting,
u16,
"A newtype over the various display control options that you have on a GBA."
);
#[allow(missing_docs)]
impl DisplayControlSetting {
@ -56,19 +57,19 @@ impl DisplayControlSetting {
};
}
register_bit!(CGB_MODE_BIT, u16, 0b1000, cgb_mode, read);
register_bit!(PAGE_SELECT_BIT, u16, 0b1_0000, page1_enabled, read_write);
register_bit!(HBLANK_INTERVAL_FREE_BIT, u16, 0b10_0000, hblank_interval_free, read_write);
register_bit!(OBJECT_MEMORY_1D, u16, 0b100_0000, object_memory_1d, read_write);
register_bit!(FORCE_BLANK_BIT, u16, 0b1000_0000, force_blank, read_write);
register_bit!(DISPLAY_BG0_BIT, u16, 0b1_0000_0000, display_bg0, read_write);
register_bit!(DISPLAY_BG1_BIT, u16, 0b10_0000_0000, display_bg1, read_write);
register_bit!(DISPLAY_BG2_BIT, u16, 0b100_0000_0000, display_bg2, read_write);
register_bit!(DISPLAY_BG3_BIT, u16, 0b1000_0000_0000, display_bg3, read_write);
register_bit!(DISPLAY_OBJECT_BIT, u16, 0b1_0000_0000_0000, display_object, read_write);
register_bit!(DISPLAY_WINDOW0_BIT, u16, 0b10_0000_0000_0000, display_window0, read_write);
register_bit!(DISPLAY_WINDOW1_BIT, u16, 0b100_0000_0000_0000, display_window1, read_write);
register_bit!(OBJECT_WINDOW_BIT, u16, 0b1000_0000_0000_0000, display_object_window, read_write);
register_bit!(CGB_MODE_BIT, u16, 0b1000, cgb_mode);
register_bit!(PAGE_SELECT_BIT, u16, 0b1_0000, page1_enabled);
register_bit!(HBLANK_INTERVAL_FREE_BIT, u16, 0b10_0000, hblank_interval_free);
register_bit!(OBJECT_MEMORY_1D, u16, 0b100_0000, object_memory_1d);
register_bit!(FORCE_BLANK_BIT, u16, 0b1000_0000, force_blank);
register_bit!(DISPLAY_BG0_BIT, u16, 0b1_0000_0000, display_bg0);
register_bit!(DISPLAY_BG1_BIT, u16, 0b10_0000_0000, display_bg1);
register_bit!(DISPLAY_BG2_BIT, u16, 0b100_0000_0000, display_bg2);
register_bit!(DISPLAY_BG3_BIT, u16, 0b1000_0000_0000, display_bg3);
register_bit!(DISPLAY_OBJECT_BIT, u16, 0b1_0000_0000_0000, display_object);
register_bit!(DISPLAY_WINDOW0_BIT, u16, 0b10_0000_0000_0000, display_window0);
register_bit!(DISPLAY_WINDOW1_BIT, u16, 0b100_0000_0000_0000, display_window1);
register_bit!(OBJECT_WINDOW_BIT, u16, 0b1000_0000_0000_0000, display_object_window);
}
/// The six display modes available on the GBA.
@ -110,6 +111,23 @@ pub const DISPSTAT: VolatilePtr<u16> = VolatilePtr(0x4000004 as *mut u16);
/// Vertical Counter (LY)
pub const VCOUNT: VolatilePtr<u16> = VolatilePtr(0x4000006 as *mut u16);
/// Obtains the current VCount value.
pub fn vcount() -> u16 {
unsafe { VCOUNT.read() }
}
/// Performs a busy loop until VBlank starts.
pub fn wait_until_vblank() {
// TODO: make this the better version with BIOS and interrupts and such.
while vcount() < SCREEN_HEIGHT as u16 {}
}
/// Performs a busy loop until VDraw starts.
pub fn wait_until_vdraw() {
// TODO: make this the better version with BIOS and interrupts and such.
while vcount() >= SCREEN_HEIGHT as u16 {}
}
/// BG0 Control
pub const BG0CNT: VolatilePtr<u16> = VolatilePtr(0x4000008 as *mut u16);
@ -383,11 +401,6 @@ pub const SIODATA8: VolatilePtr<u16> = VolatilePtr(0x400012A as *mut u16);
/// Key Status
pub const KEYINPUT: VolatilePtr<u16> = VolatilePtr(0x4000130 as *mut u16);
/// A newtype over the key input state of the GBA.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct KeyInputSetting(u16);
/// A "tribool" value helps us interpret the arrow pad.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
@ -398,18 +411,20 @@ pub enum TriBool {
Plus = 1,
}
newtype!(KeyInputSetting, u16, "A newtype over the key input state of the GBA");
#[allow(missing_docs)]
impl KeyInputSetting {
register_bit!(A_BIT, u16, 1 << 0, a_pressed, read_write);
register_bit!(B_BIT, u16, 1 << 1, b_pressed, read_write);
register_bit!(SELECT_BIT, u16, 1 << 2, select_pressed, read_write);
register_bit!(START_BIT, u16, 1 << 3, start_pressed, read_write);
register_bit!(RIGHT_BIT, u16, 1 << 4, right_pressed, read_write);
register_bit!(LEFT_BIT, u16, 1 << 5, left_pressed, read_write);
register_bit!(UP_BIT, u16, 1 << 6, up_pressed, read_write);
register_bit!(DOWN_BIT, u16, 1 << 7, down_pressed, read_write);
register_bit!(R_BIT, u16, 1 << 8, r_pressed, read_write);
register_bit!(L_BIT, u16, 1 << 9, l_pressed, read_write);
register_bit!(A_BIT, u16, 1 << 0, a_pressed);
register_bit!(B_BIT, u16, 1 << 1, b_pressed);
register_bit!(SELECT_BIT, u16, 1 << 2, select_pressed);
register_bit!(START_BIT, u16, 1 << 3, start_pressed);
register_bit!(RIGHT_BIT, u16, 1 << 4, right_pressed);
register_bit!(LEFT_BIT, u16, 1 << 5, left_pressed);
register_bit!(UP_BIT, u16, 1 << 6, up_pressed);
register_bit!(DOWN_BIT, u16, 1 << 7, down_pressed);
register_bit!(R_BIT, u16, 1 << 8, r_pressed);
register_bit!(L_BIT, u16, 1 << 9, l_pressed);
/// Takes the difference between these keys and another set of keys.
pub fn difference(&self, other: KeyInputSetting) -> KeyInputSetting {
@ -442,8 +457,11 @@ impl KeyInputSetting {
}
/// Gets the current state of the keys
pub fn read_key_input() -> KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read() ^ 0b1111_1111_1111_1111) }
pub fn key_input() -> KeyInputSetting {
// Note(Lokathor): The 10 used bits are "low when pressed" style, but the 6
// unused bits are always low, so we XOR with this mask to get a result where
// the only active bits are currently pressed keys.
unsafe { KeyInputSetting(KEYINPUT.read() ^ 0b0000_0011_1111_1111) }
}
/// Key Interrupt Control

View file

@ -1,4 +1,5 @@
#![no_std]
#![cfg_attr(not(test), no_std)]
#![cfg_attr(not(test), feature(asm))]
#![warn(missing_docs)]
//! This crate helps you write GBA ROMs.
@ -13,6 +14,14 @@
//!
//! **Do not** use this crate in programs that aren't running on the GBA. If you
//! do, it's a giant bag of Undefined Behavior.
//!
//! # TESTING POLICY
//!
//! It is the intent of the crate authors that as much of the crate as possible
//! be written so that you can use `cargo test` for at least some parts of your
//! code without everything exploding instantly. To that end, where possible we
//! attempt to use `cfg` flags to make things safe for `cargo test`. Hopefully
//! we got it all.
pub mod core_extras;
pub(crate) use crate::core_extras::*;
@ -20,8 +29,63 @@ pub(crate) use crate::core_extras::*;
pub mod io_registers;
pub mod video_ram;
pub(crate) use crate::video_ram::*;
/// Combines the Red, Blue, and Green provided into a single color value.
pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
blue << 10 | green << 5 | red
}
/// BIOS Call: Div (GBA SWI 0x06).
///
/// Gives just the DIV output of `numerator / denominator`.
///
/// # Panics
///
/// If `denominator` is 0.
#[inline]
pub fn div(numerator: i32, denominator: i32) -> i32 {
div_modulus(numerator, denominator).0
}
/// BIOS Call: Div (GBA SWI 0x06).
///
/// Gives just the MOD output of `numerator / denominator`.
///
/// # Panics
///
/// If `denominator` is 0.
#[inline]
pub fn modulus(numerator: i32, denominator: i32) -> i32 {
div_modulus(numerator, denominator).1
}
/// BIOS Call: Div (GBA SWI 0x06).
///
/// Gives both the DIV and MOD output of `numerator / denominator`.
///
/// # Panics
///
/// If `denominator` is 0.
#[inline]
pub fn div_modulus(numerator: i32, denominator: i32) -> (i32, i32) {
assert!(denominator != 0);
#[cfg(not(test))]
{
let div_out: i32;
let mod_out: i32;
unsafe {
asm!(/* assembly template */ "swi 0x06"
:/* output operands */ "={r0}"(div_out), "={r1}"(mod_out)
:/* input operands */ "{r0}"(numerator), "{r1}"(denominator)
:/* clobbers */ "r3"
:/* options */
);
}
(div_out, mod_out)
}
#[cfg(test)]
{
(numerator / denominator, numerator % denominator)
}
}

View file

@ -13,6 +13,8 @@
//! they won't bother to check that you've set the video mode they're designed
//! for.
pub use super::*;
/// The physical width in pixels of the GBA screen.
pub const SCREEN_WIDTH: isize = 240;
@ -27,10 +29,14 @@ pub const SCREEN_HEIGHT: isize = 160;
pub const VRAM_BASE_ADDRESS: usize = 0x0600_0000;
/// Draws a pixel to the screen while in Display Mode 3, with bounds checks.
pub fn mode3_pixel(col: isize, row: isize, color: u16) {
///
/// # Panics
///
/// If `col` or `row` are out of bounds this will panic.
pub fn mode3_draw_pixel(col: isize, row: isize, color: u16) {
assert!(col >= 0 && col < SCREEN_WIDTH);
assert!(row >= 0 && row < SCREEN_HEIGHT);
unsafe { mode3_pixel_unchecked(col, row, color) }
unsafe { mode3_draw_pixel_unchecked(col, row, color) }
}
/// Draws a pixel to the screen while in Display Mode 3.
@ -44,6 +50,32 @@ pub fn mode3_pixel(col: isize, row: isize, color: u16) {
///
/// * `col` must be in `0..SCREEN_WIDTH`
/// * `row` must be in `0..SCREEN_HEIGHT`
pub unsafe fn mode3_pixel_unchecked(col: isize, row: isize, color: u16) {
core::ptr::write_volatile((VRAM_BASE_ADDRESS as *mut u16).offset(col + row * SCREEN_WIDTH), color);
pub unsafe fn mode3_draw_pixel_unchecked(col: isize, row: isize, color: u16) {
VolatilePtr(VRAM_BASE_ADDRESS as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
}
/// Reads the given pixel of video memory according to Mode 3 placement.
///
/// # Failure
///
/// If the location is out of bounds you get `None`.
pub fn mode3_read_pixel(col: isize, row: isize) -> Option<u16> {
if col >= 0 && col < SCREEN_WIDTH && row >= 0 && row < SCREEN_HEIGHT {
unsafe { Some(VolatilePtr(VRAM_BASE_ADDRESS as *mut u16).offset(col + row * SCREEN_WIDTH).read()) }
} else {
None
}
}
/// Clears the entire screen to the color specified.
pub unsafe fn mode3_clear_screen(color: u16) {
let color = color as u32;
let bulk_color = color << 16 | color;
let mut ptr = VolatilePtr(VRAM_BASE_ADDRESS as *mut u32);
for _ in 0..SCREEN_HEIGHT {
for _ in 0..(SCREEN_WIDTH / 2) {
ptr.write(bulk_color);
ptr = ptr.offset(1);
}
}
}