Volatile

Before we focus on what the numbers mean, first let's ask ourselves: Why are we doing volatile writes? You've probably never used that keywords before at all. What is volatile anyway?

Well, the optimizer is pretty aggressive, and so it'll skip reads and writes when it thinks can. Like if you write to a pointer once, and then again a moment later, and it didn't see any other reads in between, it'll think that it can just skip doing that first write since it'll get overwritten anyway. Sometimes that's correct, but sometimes it's not.

Marking a read or write as volatile tells the compiler that it really must do that action, and in the exact order that we wrote it out. It says that there might even be special hardware side effects going on that the compiler isn't aware of. In this case, the write to the display control register sets a video mode, and the writes to the Video RAM set pixels that will show up on the screen.

Similar to "atomic" operations you might have heard about, all volatile operations are enforced to happen in the exact order that you specify them, but only relative to other volatile operations. So something like


# #![allow(unused_variables)]
#fn main() {
c.volatile_write(5);
a += b;
d.volatile_write(7);
#}

might end up changing a either before or after the change to c (since the value of a doesn't affect the write to c), but the write to d will always happen after the write to c, even though the compiler doesn't see any direct data dependency there.

If you ever go on to use volatile stuff on other platforms it's important to note that volatile doesn't make things thread-safe, you still need atomic for that. However, the GBA doesn't have threads, so we don't have to worry about those sorts of thread safety concerns (there's interrupts, but that's another matter).