1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! This crate provides the internal implementations for a chip 8 interpreter/emulator.
//!
//! It currently provides two external traits that need to be implemented by the user of the crate
//! (a third trait might be added if sound is ever supported), the Draw and ReadInputState traits.
//!
//! The main idea that I was hoping to achieve here was to not have any external dependencies so I
//! can load the interpreter on to almost any device I want in future without needing to rewrite the
//! entire application.
//!
//! Once the abovementioned traits are implemented, the interpreter will call these functions
//! when appropriate.
//!
//! For example implementations see the examples directory.
//!
//! # Usage:
//! ```
//! // These would be your own implementation
//! struct Drawer;
//! struct InputReader;
//!
//! impl chip_eight::Draw for Drawer {
//! fn draw_buffer(&mut self, screen_buf: &[u8], screen_width: usize, screen_height: usize) { todo!() }
//! fn clear_screen(&mut self) { todo!() }
//! }
//! impl chip_eight::ReadInputState for InputReader {
//! fn read_keys_state(&self) -> Result<[u8; 16], String> { todo!() }
//! fn reset_keys_state(&mut self) { todo!() }
//! }
//!
//! let (drawer, input_reader) = (Drawer, InputReader);
//! let program = vec![]; // Read it from somewhere
//!
//! let mut emulator = chip_eight::Emulator::init(program, drawer, input_reader)
//! .expect("The chip 8 program is probably too large");
//!
//! emulator
//! .set_max_draw_delay(std::time::Duration::from_millis(6))
//! .set_quirks_mode(chip_eight::QuirksMode::Chip8);
//!
//! // Most simply you can then run the emulator as follows:
//! // EITHER: emulator.run_blocking();
//! // OR:
//! for emulator_state in emulator {
//! // Here emulator_state gives you access to the previous instruction as well as
//! // This is the expensive way of using the emulator, but is nice for debuggers
//! //(Just breaking here for the doctest)
//! break;
//! }
//! ```
use ;
pub use *;
const BASE_SCREEN_WIDTH: usize = 64;
const BASE_SCREEN_HEIGHT: usize = 32;
/// Implement this trait on a type and use it to draw to or clear the screen.
/// Implement this trait on a type and use it to read input state.
/// Currently the only ApplicationError variant is the program being too large to fit in the
/// interpreter's memory.