From 1fcfbb00e8e67c94677647e908fd6f8b919d07ee Mon Sep 17 00:00:00 2001 From: Lokathor Date: Sat, 15 Dec 2018 23:05:22 -0700 Subject: [PATCH] Clear some cruft --- book/src-bak/ch01/hello1.md | 115 ----------------------------- book/src-bak/ch01/hello2.md | 132 ---------------------------------- book/src-bak/ch01/index.md | 10 --- book/src-bak/ch01/volatile.md | 70 ------------------ book/src-bak/ch02/index.md | 22 ------ 5 files changed, 349 deletions(-) delete mode 100644 book/src-bak/ch01/hello1.md delete mode 100644 book/src-bak/ch01/hello2.md delete mode 100644 book/src-bak/ch01/index.md delete mode 100644 book/src-bak/ch01/volatile.md delete mode 100644 book/src-bak/ch02/index.md diff --git a/book/src-bak/ch01/hello1.md b/book/src-bak/ch01/hello1.md deleted file mode 100644 index 561f77e..0000000 --- a/book/src-bak/ch01/hello1.md +++ /dev/null @@ -1,115 +0,0 @@ - - -## A basic hello1 explanation - -So, what just happened? Even if you're used to Rust that might look pretty -strange. We'll go over most of the little parts right here, and then bigger -parts will get their own sections. - -```rust -#![feature(start)] -``` - -This enables the [start -feature](https://doc.rust-lang.org/beta/unstable-book/language-features/start.html), -which you would normally be able to read about in the unstable book, except that -the book tells you nothing at all except to look at the [tracking -issue](https://github.com/rust-lang/rust/issues/29633). - -Basically, a GBA game is even more low-level than the _normal_ amount of -low-level that you get from Rust, so we have to tell the compiler to account for -that by specifying a `#[start]`, and we need this feature on to do that. - -```rust -#![no_std] -``` - -There's no standard library available on the GBA, so we'll have to live a core -only life. - -```rust -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} -``` - -This sets our [panic -handler](https://doc.rust-lang.org/nightly/nomicon/panic-handler.html). -Basically, if we somehow trigger a panic, this is where the program goes. -However, right now we don't know how to get any sort of message out to the user -so... we do nothing at all. We _can't even return_ from here, so we just sit in -an infinite loop. The player will have to reset the universe from the outside. - -```rust -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { -``` - -This is our `#[start]`. We call it `main`, but it's not like a `main` that you'd -see in a Rust program. It's _more like_ the sort of `main` that you'd see in a C -program, but it's still **not** that either. If you compile a `#[start]` program -for a target with an OS such as `arm-none-eabi-nm` you can open up the debug -info and see that your result will have the symbol for the C `main` along side -the symbol for the start `main` that we write here. Our start `main` is just its -own unique thing, and the inputs and outputs have to be like that because that's -how `#[start]` is specified to work in Rust. - -If you think about it for a moment you'll probably realize that, those inputs -and outputs are totally useless to us on a GBA. There's no OS on the GBA to call -our program, and there's no place for our program to "return to" when it's done. - -Side note: if you want to learn more about stuff "before main gets called" you -can watch a great [CppCon talk](https://www.youtube.com/watch?v=dOfucXtyEsU) by -Matt Godbolt (yes, that Godbolt) where he delves into quite a bit of it. The -talk doesn't really apply to the GBA, but it's pretty good. - -```rust - unsafe { -``` - -I hope you're all set for some `unsafe`, because there's a lot of it to be had. - -```rust - (0x04000000 as *mut u16).write_volatile(0x0403); -``` - -Sure! - -```rust - (0x06000000 as *mut u16).offset(120 + 80 * 240).write_volatile(0x001F); - (0x06000000 as *mut u16).offset(136 + 80 * 240).write_volatile(0x03E0); - (0x06000000 as *mut u16).offset(120 + 96 * 240).write_volatile(0x7C00); -``` - -Ah, of course. - -```rust - loop {} - } -} -``` - -And, as mentioned above, there's no place for a GBA program to "return to", so -we can't ever let `main` try to return there. Instead, we go into an infinite -`loop` that does nothing. The fact that this doesn't ever return an `isize` -value doesn't seem to bother Rust, because I guess we're at least not returning -any other type of thing instead. - -Fun fact: unlike in C++, an infinite loop with no side effects isn't Undefined -Behavior for us rustaceans... _semantically_. In truth LLVM has a [known -bug](https://github.com/rust-lang/rust/issues/28728) in this area, so we won't -actually be relying on empty loops in any future programs. - -## All Those Magic Numbers - -Alright, I cheated quite a bit in the middle there. The program works, but I -didn't really tell you why because I didn't really tell you what any of those -magic numbers mean or do. - -* `0x04000000` is the address of an IO Register called the Display Control. -* `0x06000000` is the start of Video RAM. - -So we write some magic to the display control register once, then we write some -other magic to three magic locations in the Video RAM. Somehow that shows three -dots. Gotta read on to find out why! diff --git a/book/src-bak/ch01/hello2.md b/book/src-bak/ch01/hello2.md deleted file mode 100644 index 7c991d4..0000000 --- a/book/src-bak/ch01/hello2.md +++ /dev/null @@ -1,132 +0,0 @@ -# hello2 - -Okay so let's have a look again: - -`hello1` - -```rust -#![feature(start)] -#![no_std] - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - unsafe { - (0x04000000 as *mut u16).write_volatile(0x0403); - (0x06000000 as *mut u16).offset(120 + 80 * 240).write_volatile(0x001F); - (0x06000000 as *mut u16).offset(136 + 80 * 240).write_volatile(0x03E0); - (0x06000000 as *mut u16).offset(120 + 96 * 240).write_volatile(0x7C00); - loop {} - } -} -``` - -Now let's clean this up so that it's clearer what's going on. - -First we'll label that display control stuff, including using the `VolatilePtr` -type from the volatile explanation: - -```rust -pub const DISPCNT: VolatilePtr = VolatilePtr(0x04000000 as *mut u16); -pub const MODE3: u16 = 3; -pub const BG2: u16 = 0b100_0000_0000; -``` - -Next we make some const values for the actual pixel drawing - -```rust -pub const VRAM: usize = 0x06000000; -pub const SCREEN_WIDTH: isize = 240; -``` - -Note that VRAM has to be interpreted in different ways depending on mode, so we -just leave it as `usize` and we'll cast it into the right form closer to the -actual use. - -Next we want a small helper function for putting together a color value. -Happily, this one can even be declared as a `const` function. At the time of -writing, we've got the "minimal const fn" support in nightly. It really is quite -limited, but I'm happy to let rustc and LLVM pre-compute as much as they can -when it comes to the GBA's tiny CPU. - -```rust -pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 { - blue << 10 | green << 5 | red -} -``` - -Finally, we'll make a function for drawing a pixel in Mode 3. Even though it's -just a one-liner, having the "important parts" be labeled as function arguments -usually helps you think about it a lot better. - -```rust -pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) { - VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color); -} -``` - -So now we've got this: - -`hello2` - -```rust -#![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); - mode3_pixel(120, 80, rgb16(31, 0, 0)); - mode3_pixel(136, 80, rgb16(0, 31, 0)); - mode3_pixel(120, 96, rgb16(0, 0, 31)); - loop {} - } -} - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct VolatilePtr(pub *mut T); -impl VolatilePtr { - 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 = 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 fn rgb16(red: u16, green: u16, blue: u16) -> u16 { - blue << 10 | green << 5 | red -} - -pub unsafe fn mode3_pixel(col: isize, row: isize, color: u16) { - VolatilePtr(VRAM as *mut u16).offset(col + row * SCREEN_WIDTH).write(color); -} -``` - -Exact same program that we started with, but much easier to read. - -Of course, in the full `gba` crate that this book is a part of we have these and -other elements all labeled and sorted out for you (not identically, but -similarly). Still, for educational purposes it's often best to do it yourself at -least once. diff --git a/book/src-bak/ch01/index.md b/book/src-bak/ch01/index.md deleted file mode 100644 index 7c21c79..0000000 --- a/book/src-bak/ch01/index.md +++ /dev/null @@ -1,10 +0,0 @@ -# Ch 1: Hello GBA - -Traditionally a person writes a "hello, world" program so that they can test -that their development environment is setup properly and to just get a feel for -using the tools involved. To get an idea of what a small part of a source file -will look like. All that stuff. - -Normally, you write a program that prints "hello, world" to the terminal. The -GBA has no terminal, but it does have a screen, so instead we're going to draw -three dots to the screen. diff --git a/book/src-bak/ch01/volatile.md b/book/src-bak/ch01/volatile.md deleted file mode 100644 index 940e05b..0000000 --- a/book/src-bak/ch01/volatile.md +++ /dev/null @@ -1,70 +0,0 @@ -# Volatile - -Before we focus on what the numbers mean, first let's ask ourselves: Why are we -doing _volatile_ writes? You've probably never used that keywords before at all. -What _is_ volatile anyway? - -Well, the optimizer is pretty aggressive, and so it'll skip reads and writes -when it thinks can. Like if you write to a pointer once, and then again a moment -later, and it didn't see any other reads in between, it'll think that it can -just skip doing that first write since it'll get overwritten anyway. Sometimes -that's correct, but sometimes it's not. - -Marking a read or write as _volatile_ tells the compiler that it really must do -that action, and in the exact order that we wrote it out. It says that there -might even be special hardware side effects going on that the compiler isn't -aware of. In this case, the write to the display control register sets a video -mode, and the writes to the Video RAM set pixels that will show up on the -screen. - -Similar to "atomic" operations you might have heard about, all volatile -operations are enforced to happen in the exact order that you specify them, but -only relative to other volatile operations. So something like - -```rust -c.write_volatile(5); -a += b; -d.write_volatile(7); -``` - -might end up changing `a` either before or after the change to `c` (since the -value of `a` doesn't affect the write to `c`), but the write to `d` will -_always_ happen after the write to `c`, even though the compiler doesn't see any -direct data dependency there. - -If you ever go on to use volatile stuff on other platforms it's important to -note that volatile doesn't make things thread-safe, you still need atomic for -that. However, the GBA doesn't have threads, so we don't have to worry about -those sorts of thread safety concerns (there's interrupts, but that's another -matter). - -## Volatile by default - -Of course, writing out `volatile_write` every time is more than we wanna do. -There's clarity and then there's excessive. This is a chance to write our first -[newtype](https://doc.rust-lang.org/1.0.0/style/features/types/newtype.html). -Basically a type that's got the exact same binary representation as some other -type, but new methods and trait implementations. - -We want a `*mut T` that's volatile by default, and also when we offset it... -well the verdict is slightly unclear on how `offset` vs `wrapping_offset` work -when you're using pointers that you made up out of nowhere. I've asked the -experts and they genuinely weren't sure, so we'll make an `offset` method that -does a `wrapping_offset` just to be careful. - -```rust -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct VolatilePtr(pub *mut T); -impl VolatilePtr { - 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)) - } -} -``` diff --git a/book/src-bak/ch02/index.md b/book/src-bak/ch02/index.md deleted file mode 100644 index 1263ced..0000000 --- a/book/src-bak/ch02/index.md +++ /dev/null @@ -1,22 +0,0 @@ -# Ch 2: User Input - -It's all well and good to draw three pixels, but they don't do anything yet. We -want them to do something, and for that we need to get some input from the user. - -The GBA, as I'm sure you know, has an arrow pad, A and B, L and R, Start and -Select. That's a little more than the NES/GB/CGB had, and a little less than the -SNES had. As you can guess, we get key state info from an IO register. - -Also, we will need a way to keep the program from running "too fast". On a -modern computer or console you do this with vsync info from the GPU and Monitor, -and on the GBA we'll be using vsync info from an IO register that tracks what -the display hardware is doing. - -As a way to apply our knowledge We'll make a simple "light cycle" game where -your dot leaves a trail behind them and you die if you go off the screen or if -you touch your own trail. We just make a copy of `hello2.rs` named -`light_cycle.rs` and then fill it in as we go through the chapter. Normally you -might not place the entire program into a single source file, particularly as it -grows over time, but since these are small examples it's much better to have -them be completely self contained than it is to have them be "properly -organized" for the long term.