-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.rs
135 lines (117 loc) · 4.71 KB
/
main.rs
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use c8::{HEIGHT, RAM_SIZE, WIDTH};
use minifb::{Key, Scale, Window, WindowOptions};
use std::{env, fs};
use rodio::Sink;
mod c8;
fn main() {
println!("CHIP-8 Interpreter/Emulator");
let mut c8 = c8::C8::new();
let args: Vec<String> = env::args().collect();
// Read ROM
let file_name = &args[1];
let rom = match fs::read(file_name) {
Ok(file) => file,
Err(e) => panic!("Cound't load file: {}", e.to_string()),
};
c8.load_ram(&rom);
println!("{:?}", rom);
// Setup Audio
let audio_device = rodio::default_output_device().unwrap();
let audio_sink = Sink::new(&audio_device);
let audio_source = rodio::source::SineWave::new(440);
audio_sink.append(audio_source);
audio_sink.pause();
// Setup Window
let mut window = Window::new(
&format!("CHIP-8: {}", file_name),
WIDTH,
HEIGHT,
WindowOptions {
scale: Scale::X16,
..WindowOptions::default()
},
)
.expect("Unable to open a Window");
// Using limit_update_rate minifb will check how much time has passed since
// the last time and if it's less than the selected time it will sleep for
// the remainder of it. This means that if more time has spent than the set
// time (external code taking longer) minifb will not do any waiting at all
// so there is no loss in CPU performance with this feature.
// Source: https://docs.rs/minifb/0.16.0/minifb/struct.Window.html#method.limit_update_rate
let display_refresh_rate: f64 = if args.len() <= 2 { 480.0 } else { args[2].parse::<f64>().unwrap() };
let runloop_timer_default: usize = (display_refresh_rate / 60.0) as usize;
window.limit_update_rate(Some(std::time::Duration::from_secs_f64(1.0 / display_refresh_rate)));
let mut executing = true;
let mut wait_for_key: usize = 0;
let mut update_counter: usize = runloop_timer_default;
while window.is_open() && !window.is_key_down(Key::Escape) && c8.pc <= RAM_SIZE as u16 {
let mut key_press: [bool; 16] = [false; 16];
window.get_keys().map(|keys| {
for t in keys {
match t {
Key::Key1 => key_press[0x1] = true,
Key::Key2 => key_press[0x2] = true,
Key::Key3 => key_press[0x3] = true,
Key::Key4 => key_press[0xc] = true,
Key::Q => key_press[0x4] = true,
Key::W => key_press[0x5] = true,
Key::E => key_press[0x6] = true,
Key::R => key_press[0xd] = true,
Key::A => key_press[0x7] = true,
Key::S => key_press[0x8] = true,
Key::D => key_press[0x9] = true,
Key::F => key_press[0xe] = true,
Key::Z => key_press[0xa] = true,
Key::X => key_press[0x0] = true,
Key::C => key_press[0xb] = true,
Key::V => key_press[0xf] = true,
_ => (),
}
}
});
for j in 0..16 {
if key_press[j] {
if wait_for_key != 0 {
executing = false;
c8.v[wait_for_key] = j as u8;
wait_for_key = 0;
break;
}
}
}
if executing {
wait_for_key = c8.run(&key_press);
}
// 60 Hz
if update_counter == 0 {
// The delay timer is active whenever the delay timer register (DT)
// is non-zero. This timer does nothing more than subtract 1 from
// the value of DT at a rate of 60Hz. When DT reaches 0, it
// deactivates.
if c8.dt > 0 {
c8.dt -= 1;
}
// The sound timer is active whenever the sound timer register (ST)
// is non-zero. This timer also decrements at a rate of 60Hz,
// however, as long as ST's value is greater than zero, the Chip-8
// buzzer will sound. When ST reaches zero, the sound timer
// deactivates.
// The sound produced by the Chip-8 interpreter has only one tone.
// The frequency of this tone is decided by the author of the
// interpreter.
if c8.st > 0 {
audio_sink.play();
c8.st -= 1;
} else if c8.st == 0 {
audio_sink.pause();
}
// Update Window
window
.update_with_buffer(&c8.display, WIDTH, HEIGHT)
.unwrap();
update_counter = runloop_timer_default;
} else {
update_counter -= 1;
}
}
}