rust8 0.2.1

A Chip-8 Emulator Library in Rust
Documentation
use self::constants::{DEFAULT_PROGRAM_ADDRESS, FONT_SPRITES, FONT_SPRITE_SIZE, STACK_SIZE};
use self::data_register::{DataRegister, DataRegisters};
use self::graphic::Screen;
use self::keyboard::{Key, Keyboard};
use self::memory::{Memory, WriteError};

pub mod constants;
pub mod cpu;
pub mod data_register;
pub mod graphic;
pub mod instruction;
pub mod keyboard;
pub mod memory;

#[derive(PartialEq)]
enum Blocked {
    No,
    WaitingOnKeyUp(DataRegister),
}

pub struct Chip8 {
    pub memory: Memory,

    pub data_registers: DataRegisters,
    pub address_register: usize,
    pub sound_timer: u8,
    pub delay_timer: u8,
    pub program_counter: usize,

    keyboard: Keyboard,
    pub stack: Vec<usize>,
    pub screen: Screen,
    in_jump: bool,
    blocked: Blocked,
}

impl Default for Chip8 {
    fn default() -> Self {
        Chip8 {
            data_registers: DataRegisters::new(),
            address_register: 0,
            keyboard: Keyboard::new(),
            in_jump: false,
            blocked: Blocked::No,
            delay_timer: 0,
            sound_timer: 0,
            stack: Vec::with_capacity(STACK_SIZE),
            program_counter: DEFAULT_PROGRAM_ADDRESS,
            memory: Memory::new(),
            screen: Screen::new(),
        }
    }
}

impl Chip8 {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn reset(&mut self) {
        self.data_registers.reset();
        self.address_register = 0;
        self.in_jump = false;
        self.delay_timer = 0;
        self.sound_timer = 0;
        self.stack.clear();
        self.program_counter = DEFAULT_PROGRAM_ADDRESS;
        self.memory.clear();
        self.screen.clear();
        self.blocked = Blocked::No;
    }

    pub fn key_up(&mut self, key: Key) {
        self.keyboard.key_up(key);
        self.handle_key_up_interrupt(key)
    }

    pub fn key_down(&mut self, key: Key) {
        self.keyboard.key_down(key);
    }

    fn load_font_sprites(&mut self) {
        for (i, sprite) in FONT_SPRITES.iter().enumerate() {
            self.memory
                .write_unrestricted(sprite, i * FONT_SPRITE_SIZE)
                .unwrap();
        }
    }

    pub fn load_program_to_address(
        &mut self,
        program: &[u8],
        address: usize,
    ) -> Result<(), WriteError> {
        self.reset();
        self.load_font_sprites();

        self.memory.write_restricted(program, address)?;
        self.program_counter = address;

        Ok(())
    }

    pub fn load_program(&mut self, program: &[u8]) -> Result<(), WriteError> {
        self.load_program_to_address(program, DEFAULT_PROGRAM_ADDRESS)
    }

    pub fn is_blocked(&self) -> bool {
        self.blocked != Blocked::No
    }
}