From u8 to Type-Safe Flags
Originally I was implementing the Status register as just a u8. A single byte which each bit represents a different "flag" (Carry, Zero, etc...). I found writing status |= 0b0000_0010 really hard to read and confusing after a while. To solve this I decided to treat Status as a struct and use the bitflags crate.
pub struct StatusArgs {
pub negative: bool,
pub overflow: bool,
pub unused: bool,
pub brk: bool,
pub decimal_mode: bool,
pub disable_interrupts: bool,
pub zero: bool,
pub carry: bool,
}
Code Comparison
// I always forgot which bit I was working with
self.registers.status |= 0x02;
// Now this reads just like a sentence and is much easier to read/write
self.registers.status.insert(Status::ZERO);
Why bitflags?
In Rust bool takes up an entire byte (8 bits) of memory. Since the Status is supposed to represent in total 8-bits we are going to use bitflags which will help map each bit.
0b0000_0001: Binary for 1. It tells Rust "This flag owns the 1st slot."0b0000_0010: Binary for 2. It tells Rust "This flag owns the 2nd slot."- ...
0b1000_0000: Binary for 1. It tells Rust "This flag owns the 1st slot."
bitflags! {
pub struct Status: u8 {
const NEGATIVE = 0b1000_0000;
const OVERFLOW = 0b0100_0000;
const UNUSED = 0b0010_0000;
const BRK = 0b0001_0000;
const DECIMAL_MODE = 0b0000_1000;
const DISABLE_INTERRUPTS = 0b0000_0100;
const ZERO = 0b0000_0010;
const CARRY = 0b0000_0001;
}
}
Resetting Status Flags
impl StatusArgs {
#[must_use]
pub const fn none() -> StatusArgs {
StatusArgs {
negative: false,
overflow: false,
unused: false,
brk: false,
decimal_mode: false,
disable_interrupts: false,
zero: false,
carry: false,
}
}
}
What is StatusArgs::none()
This of StatusArgs like a checklist. The none() returns us a blank checklist, every flag in the struct is set to false. This allows us to use a Rust feature ca;ed Struct Update Syntax (..). If I need to create a Status where only the carry flag is true, I do not need to write out all 8 flags. I can instead write:
let my_state = StatusArgs {
carry: true,
..StatusArgs::none() // leave everything else blank"
};