mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 19:01:30 +11:00
part of ch3
This commit is contained in:
parent
06e8e61eb2
commit
39176c19ee
|
@ -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
237
book/src/ch03/gba_memory.md
Normal 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
2
book/src/ch03/gba_rng.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# GBA RNG
|
||||
TODO
|
|
@ -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.
|
||||
|
|
2
book/src/ch03/memory_game.md
Normal file
2
book/src/ch03/memory_game.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# memory_game
|
||||
TODO
|
2
book/src/ch03/object_basics.md
Normal file
2
book/src/ch03/object_basics.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Object Basics
|
||||
TODO
|
2
book/src/ch03/tiled_backgrounds.md
Normal file
2
book/src/ch03/tiled_backgrounds.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Tiled Backgrounds
|
||||
TODO
|
|
@ -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 "agb" 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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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) -> 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<u16> = 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 "minimal const fn" support in nightly. It really is quite
|
||||
limited, but I'm happy to let rustc and LLVM pre-compute as much as they can
|
||||
when it comes to the GBA's tiny CPU.</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: &core::panic::PanicInfo) -> ! {
|
|||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
unsafe {
|
||||
DISPCNT.write_volatile(MODE3 | BG2);
|
||||
DISPCNT.write(MODE3 | BG2);
|
||||
mode3_pixel(120, 80, rgb16(31, 0, 0));
|
||||
mode3_pixel(136, 80, rgb16(0, 31, 0));
|
||||
mode3_pixel(120, 96, rgb16(0, 0, 31));
|
||||
|
@ -217,7 +221,22 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
|||
}
|
||||
}
|
||||
|
||||
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct VolatilePtr<T>(pub *mut T);
|
||||
impl<T> VolatilePtr<T> {
|
||||
pub unsafe fn read(&self) -> T {
|
||||
core::ptr::read_volatile(self.0)
|
||||
}
|
||||
pub unsafe fn write(&self, data: T) {
|
||||
core::ptr::write_volatile(self.0, data);
|
||||
}
|
||||
pub unsafe fn offset(self, count: isize) -> Self {
|
||||
VolatilePtr(self.0.wrapping_offset(count))
|
||||
}
|
||||
}
|
||||
|
||||
pub const DISPCNT: VolatilePtr<u16> = VolatilePtr(0x04000000 as *mut u16);
|
||||
pub const MODE3: u16 = 3;
|
||||
pub const BG2: u16 = 0b100_0000_0000;
|
||||
|
||||
|
@ -229,7 +248,7 @@ pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
|
|||
}
|
||||
|
||||
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
|
||||
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
|
||||
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
|
||||
}
|
||||
</code></pre></pre>
|
||||
<p>Exact same program that we started with, but much easier to read.</p>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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<T>(pub *mut T);
|
||||
impl<T> VolatilePtr<T> {
|
||||
pub unsafe fn read(&self) -> T {
|
||||
core::ptr::read_volatile(self.0)
|
||||
}
|
||||
pub unsafe fn write(&self, data: T) {
|
||||
core::ptr::write_volatile(self.0, data);
|
||||
}
|
||||
pub unsafe fn offset(self, count: isize) -> Self {
|
||||
VolatilePtr(self.0.wrapping_offset(count))
|
||||
}
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
|
||||
</main>
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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 << 16 | color;
|
||||
let mut ptr = VRAM as *mut u32;
|
||||
let mut ptr = VolatilePtr(VRAM as *mut u32);
|
||||
for _ in 0..SCREEN_HEIGHT {
|
||||
for _ in 0..(SCREEN_WIDTH / 2) {
|
||||
ptr.write_volatile(bulk_color);
|
||||
ptr.write(bulk_color);
|
||||
ptr = ptr.offset(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn mode3_draw_pixel(col: isize, row: isize, color: u16) {
|
||||
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
|
||||
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
|
||||
}
|
||||
|
||||
pub unsafe fn mode3_read_pixel(col: isize, row: isize) -> u16 {
|
||||
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read_volatile()
|
||||
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read()
|
||||
}
|
||||
#}</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) -> 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) -> 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;
|
||||
|
|
|
@ -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<u16> = VolatilePtr(0x400_0130 as *mut u16);
|
||||
|
||||
/// A newtype over the key input state of the GBA.
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||
#[repr(transparent)]
|
||||
pub struct KeyInputSetting(u16);
|
||||
|
||||
pub fn read_key_input() -> KeyInputSetting {
|
||||
unsafe { KeyInputSetting(KEYINPUT.read_volatile()) }
|
||||
pub fn key_input() -> KeyInputSetting {
|
||||
unsafe { KeyInputSetting(KEYINPUT.read()) }
|
||||
}
|
||||
#}</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() -> KeyInputSetting {
|
||||
pub fn key_input() -> KeyInputSetting {
|
||||
unsafe { KeyInputSetting(KEYINPUT.read_volatile() ^ 0b0000_0011_1111_1111) }
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
|
|
|
@ -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<u16> = VolatilePtr(0x0400_0006 as *mut u16);
|
||||
|
||||
pub fn read_vcount() -> u16 {
|
||||
unsafe { VCOUNT.read_volatile() }
|
||||
pub fn vcount() -> 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() -> u16 {
|
|||
pub const SCREEN_HEIGHT: isize = 160;
|
||||
|
||||
pub fn wait_until_vblank() {
|
||||
while read_vcount() < SCREEN_HEIGHT as u16 {}
|
||||
while vcount() < SCREEN_HEIGHT as u16 {}
|
||||
}
|
||||
|
||||
pub fn wait_until_vdraw() {
|
||||
while read_vcount() >= SCREEN_HEIGHT as u16 {}
|
||||
while vcount() >= SCREEN_HEIGHT as u16 {}
|
||||
}
|
||||
#}</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
412
docs/ch03/gba_memory.html
Normal 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 "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 <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 "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.</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 "palbank" (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 "you might have to wait if the display controller is looking at
|
||||
it" 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 "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 <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 "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 <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, "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 <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
201
docs/ch03/gba_rng.html
Normal 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>
|
|
@ -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 "movement", but we left a big trail in the video
|
||||
memory of everywhere we went. Most of the time that's not what we want at all.
|
||||
If we want more hardware support we're going to have to use a new video mode. So
|
||||
far we've only used Mode 3, but modes 4 and 5 are basically the same. Instead,
|
||||
we'll switch focus to using a tiled graphical mode.</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 "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.</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
193
docs/ch03/memory_game.html
Normal 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>
|
201
docs/ch03/object_basics.html
Normal file
201
docs/ch03/object_basics.html
Normal 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>
|
201
docs/ch03/tiled_backgrounds.html
Normal file
201
docs/ch03/tiled_backgrounds.html
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
442
docs/print.html
442
docs/print.html
|
@ -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 "agb" 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<T>(pub *mut T);
|
||||
impl<T> VolatilePtr<T> {
|
||||
pub unsafe fn read(&self) -> T {
|
||||
core::ptr::read_volatile(self.0)
|
||||
}
|
||||
pub unsafe fn write(&self, data: T) {
|
||||
core::ptr::write_volatile(self.0, data);
|
||||
}
|
||||
pub unsafe fn offset(self, count: isize) -> Self {
|
||||
VolatilePtr(self.0.wrapping_offset(count))
|
||||
}
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<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) -> 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<u16> = 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 "minimal const fn" support in nightly. It really is quite
|
||||
limited, but I'm happy to let rustc and LLVM pre-compute as much as they can
|
||||
when it comes to the GBA's tiny CPU.</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: &core::panic::PanicInfo) -> ! {
|
|||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
unsafe {
|
||||
DISPCNT.write_volatile(MODE3 | BG2);
|
||||
DISPCNT.write(MODE3 | BG2);
|
||||
mode3_pixel(120, 80, rgb16(31, 0, 0));
|
||||
mode3_pixel(136, 80, rgb16(0, 31, 0));
|
||||
mode3_pixel(120, 96, rgb16(0, 0, 31));
|
||||
|
@ -802,7 +836,22 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
|||
}
|
||||
}
|
||||
|
||||
pub const DISPCNT: *mut u16 = 0x04000000 as *mut u16;
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct VolatilePtr<T>(pub *mut T);
|
||||
impl<T> VolatilePtr<T> {
|
||||
pub unsafe fn read(&self) -> T {
|
||||
core::ptr::read_volatile(self.0)
|
||||
}
|
||||
pub unsafe fn write(&self, data: T) {
|
||||
core::ptr::write_volatile(self.0, data);
|
||||
}
|
||||
pub unsafe fn offset(self, count: isize) -> Self {
|
||||
VolatilePtr(self.0.wrapping_offset(count))
|
||||
}
|
||||
}
|
||||
|
||||
pub const DISPCNT: VolatilePtr<u16> = VolatilePtr(0x04000000 as *mut u16);
|
||||
pub const MODE3: u16 = 3;
|
||||
pub const BG2: u16 = 0b100_0000_0000;
|
||||
|
||||
|
@ -814,7 +863,7 @@ pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
|
|||
}
|
||||
|
||||
pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) {
|
||||
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
|
||||
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
|
||||
}
|
||||
</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<u16> = VolatilePtr(0x400_0130 as *mut u16);
|
||||
|
||||
/// A newtype over the key input state of the GBA.
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||
#[repr(transparent)]
|
||||
pub struct KeyInputSetting(u16);
|
||||
|
||||
pub fn read_key_input() -> KeyInputSetting {
|
||||
unsafe { KeyInputSetting(KEYINPUT.read_volatile()) }
|
||||
pub fn key_input() -> KeyInputSetting {
|
||||
unsafe { KeyInputSetting(KEYINPUT.read()) }
|
||||
}
|
||||
#}</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() -> KeyInputSetting {
|
||||
pub fn key_input() -> 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<u16> = VolatilePtr(0x0400_0006 as *mut u16);
|
||||
|
||||
pub fn read_vcount() -> u16 {
|
||||
unsafe { VCOUNT.read_volatile() }
|
||||
pub fn vcount() -> 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() -> u16 {
|
|||
pub const SCREEN_HEIGHT: isize = 160;
|
||||
|
||||
pub fn wait_until_vblank() {
|
||||
while read_vcount() < SCREEN_HEIGHT as u16 {}
|
||||
while vcount() < SCREEN_HEIGHT as u16 {}
|
||||
}
|
||||
|
||||
pub fn wait_until_vdraw() {
|
||||
while read_vcount() >= SCREEN_HEIGHT as u16 {}
|
||||
while vcount() >= SCREEN_HEIGHT as u16 {}
|
||||
}
|
||||
#}</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 << 16 | color;
|
||||
let mut ptr = VRAM as *mut u32;
|
||||
let mut ptr = VolatilePtr(VRAM as *mut u32);
|
||||
for _ in 0..SCREEN_HEIGHT {
|
||||
for _ in 0..(SCREEN_WIDTH / 2) {
|
||||
ptr.write_volatile(bulk_color);
|
||||
ptr.write(bulk_color);
|
||||
ptr = ptr.offset(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn mode3_draw_pixel(col: isize, row: isize, color: u16) {
|
||||
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write_volatile(color);
|
||||
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color);
|
||||
}
|
||||
|
||||
pub unsafe fn mode3_read_pixel(col: isize, row: isize) -> u16 {
|
||||
(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read_volatile()
|
||||
VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).read()
|
||||
}
|
||||
#}</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) -> 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) -> 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 "movement", but we left a big trail in the video
|
||||
memory of everywhere we went. Most of the time that's not what we want at all.
|
||||
If we want more hardware support we're going to have to use a new video mode. So
|
||||
far we've only used Mode 3, but modes 4 and 5 are basically the same. Instead,
|
||||
we'll switch focus to using a tiled graphical mode.</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 "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.</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 "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 <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 "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.</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 "palbank" (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 "you might have to wait if the display controller is looking at
|
||||
it" 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 "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 <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 "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 <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, "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 <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
197
examples/memory_game.rs
Normal 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,
|
||||
}
|
Loading…
Reference in a new issue