part of ch3

This commit is contained in:
Lokathor 2018-11-18 22:19:13 -07:00
parent 06e8e61eb2
commit 39176c19ee
31 changed files with 2205 additions and 171 deletions

View file

@ -15,8 +15,8 @@
* [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 Memory](ch03/gba_memory.md)
* [GBA RNG](ch03/gba_rng.md)
* [memory_game](ch03/memory_game.md)

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 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).
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

View file

@ -4,9 +4,13 @@ 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 focus on using a tiled mode. The tiled modes take less time to arrange,
which means more time for game computations. If your game has much complexity at
all, you'll naturally want to use a tiled mode to display it.
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
@ -16,11 +20,6 @@ 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.
Of course, once we're all set drawing the objects and backgrounds, we'll want
them to start keeping track of what's where, and maybe store info on stuff
that's off screen. That means it's finally time to go over the GBA's memory
layout so that we know where we have scratch space to work with.
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
@ -30,4 +29,6 @@ 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.
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

@ -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="../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></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">
@ -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

View file

@ -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="../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></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">
@ -165,9 +165,10 @@ 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>
<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)]
@ -265,10 +266,8 @@ 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>But what <em>exactly</em> is going on? Well that's what the whole rest of this chapter
(and this book) is about.</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>

View file

@ -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="../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></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">
@ -159,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>
@ -174,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>
@ -193,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>
@ -209,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));
@ -217,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;
@ -229,7 +248,7 @@ 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>

View file

@ -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="../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></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">

View file

@ -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="../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></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">

View file

@ -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="../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></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">
@ -221,8 +221,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>
</main>

View file

@ -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="../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></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">
@ -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>

View file

@ -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="../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></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" 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">
@ -157,9 +157,9 @@ 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
@ -170,6 +170,35 @@ 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>

View file

@ -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="../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></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">

View file

@ -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="../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></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">
@ -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;

View file

@ -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="../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></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">
@ -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
@ -224,7 +224,7 @@ that the entire result has active bits in all positions where a key is pressed.<
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub fn read_key_input() -&gt; KeyInputSetting {
pub fn key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b0000_0011_1111_1111) }
}
#}</code></pre></pre>

View file

@ -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="../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></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">
@ -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

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>

View file

@ -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="../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></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" 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">
@ -137,6 +137,34 @@
<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>
@ -149,6 +177,10 @@
<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>
@ -163,6 +195,10 @@
<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>

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

@ -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="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></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">
@ -159,7 +159,7 @@ if you want to get them that way.</p>
<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
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>

View file

@ -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="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></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">
@ -159,7 +159,7 @@ if you want to get them that way.</p>
<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
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>

View file

@ -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="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></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">
@ -159,7 +159,7 @@ if you want to get them that way.</p>
<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
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>
@ -189,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
@ -255,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
@ -365,9 +369,10 @@ 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>
<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)]
@ -465,10 +470,8 @@ 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>But what <em>exactly</em> is going on? Well that's what the whole rest of this chapter
(and this book) is about.</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.
@ -490,9 +493,9 @@ 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
@ -503,6 +506,35 @@ 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
@ -622,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
@ -716,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>
@ -744,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>
@ -759,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>
@ -778,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>
@ -794,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));
@ -802,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;
@ -814,7 +863,7 @@ 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>
@ -889,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
@ -928,7 +977,7 @@ that the entire result has active bits in all positions where a key is pressed.<
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
pub fn read_key_input() -&gt; KeyInputSetting {
pub fn key_input() -&gt; KeyInputSetting {
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b0000_0011_1111_1111) }
}
#}</code></pre></pre>
@ -1086,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>
@ -1099,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
@ -1122,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
@ -1148,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;
@ -1157,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;
@ -1224,6 +1273,255 @@ yet. It becomes a lot harder to teach.</p>
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

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,
}