rust8/chip8/
mod.rs

1use self::constants::{DEFAULT_PROGRAM_ADDRESS, FONT_SPRITES, FONT_SPRITE_SIZE, STACK_SIZE};
2use self::data_register::{DataRegister, DataRegisters};
3use self::graphic::Screen;
4use self::keyboard::{Key, Keyboard};
5use self::memory::{Memory, WriteError};
6
7pub mod constants;
8pub mod cpu;
9pub mod data_register;
10pub mod graphic;
11pub mod instruction;
12pub mod keyboard;
13pub mod memory;
14
15#[derive(PartialEq)]
16enum Blocked {
17    No,
18    WaitingOnKeyUp(DataRegister),
19}
20
21pub struct Chip8 {
22    pub memory: Memory,
23
24    pub data_registers: DataRegisters,
25    pub address_register: usize,
26    pub sound_timer: u8,
27    pub delay_timer: u8,
28    pub program_counter: usize,
29
30    keyboard: Keyboard,
31    pub stack: Vec<usize>,
32    pub screen: Screen,
33    in_jump: bool,
34    blocked: Blocked,
35}
36
37impl Default for Chip8 {
38    fn default() -> Self {
39        Chip8 {
40            data_registers: DataRegisters::new(),
41            address_register: 0,
42            keyboard: Keyboard::new(),
43            in_jump: false,
44            blocked: Blocked::No,
45            delay_timer: 0,
46            sound_timer: 0,
47            stack: Vec::with_capacity(STACK_SIZE),
48            program_counter: DEFAULT_PROGRAM_ADDRESS,
49            memory: Memory::new(),
50            screen: Screen::new(),
51        }
52    }
53}
54
55impl Chip8 {
56    pub fn new() -> Self {
57        Self::default()
58    }
59
60    pub fn reset(&mut self) {
61        self.data_registers.reset();
62        self.address_register = 0;
63        self.in_jump = false;
64        self.delay_timer = 0;
65        self.sound_timer = 0;
66        self.stack.clear();
67        self.program_counter = DEFAULT_PROGRAM_ADDRESS;
68        self.memory.clear();
69        self.screen.clear();
70        self.blocked = Blocked::No;
71    }
72
73    pub fn key_up(&mut self, key: Key) {
74        self.keyboard.key_up(key);
75        self.handle_key_up_interrupt(key)
76    }
77
78    pub fn key_down(&mut self, key: Key) {
79        self.keyboard.key_down(key);
80    }
81
82    fn load_font_sprites(&mut self) {
83        for (i, sprite) in FONT_SPRITES.iter().enumerate() {
84            self.memory
85                .write_unrestricted(sprite, i * FONT_SPRITE_SIZE)
86                .unwrap();
87        }
88    }
89
90    pub fn load_program_to_address(
91        &mut self,
92        program: &[u8],
93        address: usize,
94    ) -> Result<(), WriteError> {
95        self.reset();
96        self.load_font_sprites();
97
98        self.memory.write_restricted(program, address)?;
99        self.program_counter = address;
100
101        Ok(())
102    }
103
104    pub fn load_program(&mut self, program: &[u8]) -> Result<(), WriteError> {
105        self.load_program_to_address(program, DEFAULT_PROGRAM_ADDRESS)
106    }
107
108    pub fn is_blocked(&self) -> bool {
109        self.blocked != Blocked::No
110    }
111}