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}