1use std::{
2 sync::{
3 Arc,
4 atomic::{AtomicU16, Ordering},
5 },
6 time::{Duration, SystemTime, UNIX_EPOCH},
7};
8use crate::{
11 ApplicationError, BASE_SCREEN_HEIGHT, BASE_SCREEN_WIDTH, Draw, ReadInputState,
12 emulator::{
13 fonts::{BIG_FONT, BIG_FONT_ADDR, FONT, FONT_ADDR},
14 instructions::{Instruction, KeyStateToCheck},
15 logical_operator::{Direction, LogicalOperator},
16 quirks::{QuirksFields, QuirksMode},
17 sub_commands::{FontVariant, SubCommand},
18 },
19 twister_rand::MarsenneTwister32,
20 utils::u8_to_arr,
21};
22
23#[derive(Debug)]
25pub struct Emulator<T: Draw, P: ReadInputState> {
26 memory: [u8; 0x1000],
27 stack: Vec<usize>,
28 variable_registers: [u8; 16],
29 screen_buffer: Vec<u8>,
30 index_register: usize,
31 program_counter: usize,
32 delay_timer: Arc<AtomicU16>,
33 sound_timer: Arc<AtomicU16>,
34 drawer: T,
35 input_provider: P,
36 max_draw_delay: Duration,
37 last_draw: SystemTime,
38 quirks: QuirksFields,
39 screen_width: usize,
40 screen_height: usize,
41 rng: MarsenneTwister32,
42}
43
44impl<T: Draw, P: ReadInputState> Emulator<T, P> {
45 pub fn init(program: Vec<u8>, drawer: T, input_provider: P) -> Result<Self, ApplicationError> {
48 let seed = SystemTime::now()
49 .duration_since(UNIX_EPOCH)
50 .expect("Now is always after UNIX Epoch");
51
52 let mut emulator = Self {
53 memory: [0; 0x1000],
54 stack: vec![],
55 variable_registers: [0; 16],
56 screen_buffer: vec![0; BASE_SCREEN_WIDTH * BASE_SCREEN_HEIGHT],
57 index_register: 0,
58 program_counter: 0x200,
59 delay_timer: Arc::new(AtomicU16::new(0)),
60 sound_timer: Arc::new(AtomicU16::new(0)),
61 drawer,
62 input_provider,
63 max_draw_delay: Duration::from_millis(7),
64 last_draw: SystemTime::now(),
65 quirks: QuirksMode::Chip8.into(),
66 screen_width: 64,
67 screen_height: 32,
68 rng: MarsenneTwister32::new((seed.as_micros() % u32::MAX as u128) as u32),
69 };
70
71 emulator.set_mem_block(&FONT, FONT_ADDR)?;
72 emulator.set_mem_block(&BIG_FONT, BIG_FONT_ADDR)?;
73 emulator.set_mem_block(&program, 0x200)?;
74
75 let delay_timer = emulator.delay_timer.clone();
76 let sound_timer = emulator.sound_timer.clone();
77 std::thread::spawn(move || {
78 loop {
79 let old_val = delay_timer.load(Ordering::Relaxed);
80 if old_val > 0 {
81 delay_timer.store(old_val - 1, Ordering::Relaxed);
82 }
83
84 let old_val = sound_timer.load(Ordering::Relaxed);
85 if old_val > 0 {
86 sound_timer.store(old_val - 1, Ordering::Relaxed);
87 }
88 std::thread::sleep(Duration::from_millis(6));
89 }
90 });
91
92 Ok(emulator)
93 }
94
95 pub fn run_blocking(&mut self) {
98 loop {
99 let instruction = self.fetch();
100 self.execute(instruction);
101 }
102 }
103
104 pub fn reset(&mut self, program: Vec<u8>) -> Result<(), ApplicationError> {
106 self.memory = [0; 0x1000];
107 self.stack = vec![];
108 self.variable_registers = [0; 16];
109 self.screen_buffer = vec![0; BASE_SCREEN_WIDTH * BASE_SCREEN_HEIGHT];
110 self.index_register = 0;
111 self.program_counter = 0x200;
112 self.max_draw_delay = Duration::from_millis(7);
113 self.last_draw = SystemTime::now();
114 self.quirks = QuirksMode::Chip8.into();
115 self.screen_width = 64;
116 self.screen_height = 32;
117 self.set_mem_block(&program, 0x200)?;
118 Ok(())
119 }
120
121 pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) -> &mut Self {
123 self.quirks = quirks_mode.into();
124 self
125 }
126
127 pub fn with_custom_quirks(&mut self, quirks: QuirksFields) -> &mut Self {
129 self.quirks = quirks;
130 self
131 }
132
133 pub fn set_max_draw_delay(&mut self, rate: Duration) -> &mut Self {
136 self.max_draw_delay = rate;
137 self
138 }
139
140 fn fetch(&mut self) -> Instruction {
141 let tophalf = self.memory[self.program_counter];
142 let bothalf = self.memory[self.program_counter + 1];
143 self.program_counter = (self.program_counter + 2) % self.memory.len();
144 (((tophalf as u16) << 8) | bothalf as u16).into()
145 }
146
147 fn set_high_res(&mut self) {
148 self.screen_width = BASE_SCREEN_WIDTH << 1;
149 self.screen_height = BASE_SCREEN_HEIGHT << 1;
150 }
151
152 fn set_low_res(&mut self) {
153 self.screen_width = BASE_SCREEN_WIDTH;
154 self.screen_height = BASE_SCREEN_HEIGHT;
155 }
156
157 fn execute(&mut self, instruction: Instruction) {
158 match instruction {
159 Instruction::ClearScreen => {
160 self.clear_screen();
161 }
162 Instruction::Draw {
163 x_register,
164 y_register,
165 height,
166 } => {
167 self.draw(x_register, y_register, height);
168 }
169 Instruction::Jump(address) => self.program_counter = address as usize,
170 Instruction::SetIndexRegister(address) => self.index_register = address as usize,
171 Instruction::SetGeneralRegister { register, value } => {
172 self.variable_registers[register] = value
173 }
174 Instruction::AddToRegister { register, value } => {
175 let val: u16 = value as u16 + self.variable_registers[register] as u16;
176 self.variable_registers[register] = (val & 0xFF) as u8;
177 }
178 Instruction::SkipEqValueWithRegisterContents { register, value } => {
179 let vx_value = self.variable_registers[register];
180 if vx_value == value {
181 self.program_counter += 2;
182 }
183 }
184 Instruction::SkipNotEqValueWithRegisterContents { register, value } => {
185 let vx_value = self.variable_registers[register];
186 if vx_value != value {
187 self.program_counter += 2;
188 }
189 }
190 Instruction::SkipEqRegisters {
191 register_x,
192 register_y,
193 } => {
194 let vx_value = self.variable_registers[register_x];
195 let vy_value = self.variable_registers[register_y];
196 if vx_value == vy_value {
197 self.program_counter += 2;
198 }
199 }
200 Instruction::SkipNotEqRegisters {
201 register_x,
202 register_y,
203 } => {
204 let vx_value = self.variable_registers[register_x];
205 let vy_value = self.variable_registers[register_y];
206 if vx_value != vy_value {
207 self.program_counter += 2;
208 }
209 }
210 Instruction::LogicalOperator {
211 operator,
212 register_x,
213 register_y,
214 } => {
215 self.perform_logical_operator(register_x, register_y, operator);
216 }
217 Instruction::JumpWithOffset {
218 register_x,
219 address,
220 } => {
221 if self.quirks.jumping {
222 self.program_counter = address + self.variable_registers[register_x] as usize;
223 } else {
224 self.program_counter = address + self.variable_registers[0] as usize;
225 }
226 }
227 Instruction::Random {
228 register_x,
229 val_to_and,
230 } => {
231 let randint = (self.rng.generate() % 255) as u8;
232 self.variable_registers[register_x] = randint & val_to_and;
233 }
234 Instruction::Return => {
235 if let Some(val) = self.stack.pop() {
236 self.program_counter = val;
237 };
238 }
239 Instruction::Call(memory_addr) => {
240 self.stack.push(self.program_counter);
241 self.program_counter = memory_addr;
242 }
243 Instruction::SubCommand { register, command } => {
244 self.perform_sub_command(command, register)
245 }
246 Instruction::SkipIfKey {
247 register,
248 state_to_check,
249 } => {
250 self.skip_if_key(state_to_check, register);
251 }
252 Instruction::SetHiRes => {
253 self.set_high_res();
254 self.screen_buffer
255 .resize(self.screen_width * self.screen_height, 0);
256 self.wait_to_display();
257 self.drawer
258 .draw_buffer(&self.screen_buffer, self.screen_width, self.screen_height);
259 }
260 Instruction::SetLoRes => {
261 self.set_low_res();
262 self.screen_buffer
263 .resize(self.screen_width * self.screen_height, 0);
264 self.wait_to_display();
265 self.drawer
266 .draw_buffer(&self.screen_buffer, self.screen_width, self.screen_height);
267 }
268 Instruction::ScrollDown { amount } => {
269 let px_to_shift = self.screen_width * amount as usize;
270 let mut new_buffer = vec![0; px_to_shift];
271 new_buffer.extend(&self.screen_buffer);
272 new_buffer.resize(self.screen_width * self.screen_height, 0);
273 self.screen_buffer = new_buffer;
274 }
275 Instruction::ScrollRight => {
276 let new_buffer: Vec<u8> = self
277 .screen_buffer
278 .chunks(self.screen_width)
279 .flat_map(|x| {
280 let mut row = vec![0, 0, 0, 0];
281 row.extend(x);
282 row.resize(self.screen_width, 0);
283 row
284 })
285 .collect();
286 self.screen_buffer = new_buffer;
287 }
288 Instruction::ScrollLeft => {
289 let new_buffer: Vec<u8> = self
290 .screen_buffer
291 .chunks(self.screen_width)
292 .flat_map(|x| {
293 let mut row = x[4..].to_vec();
294 row.resize(self.screen_width, 0);
295 row
296 })
297 .collect();
298 self.screen_buffer = new_buffer;
299 }
300 Instruction::Unimplemented(val) => {
301 eprintln!("UNIMPLEMENTED: {}", val)
302 }
303 }
304 }
305
306 fn skip_if_key(&mut self, state_to_check: KeyStateToCheck, register: usize) {
307 if let Ok(keys) = self.input_provider.read_keys_state() {
308 let current_key_state = keys[(self.variable_registers[register] & 0xF) as usize];
309 match state_to_check {
310 KeyStateToCheck::IsPressed => {
311 if current_key_state > 0 {
312 self.program_counter += 2;
313 }
314 }
315 KeyStateToCheck::NotPressed => {
316 if current_key_state == 0 {
317 self.program_counter += 2;
318 }
319 }
320 KeyStateToCheck::Invalid => {}
321 }
322 };
323 }
324
325 fn perform_sub_command(&mut self, command: SubCommand, register: usize) {
326 match command {
327 SubCommand::ReadDelayTimer => {
328 self.variable_registers[register] = self.delay_timer.load(Ordering::Relaxed) as u8;
329 }
330 SubCommand::SetDelayTimer => {
331 self.delay_timer
332 .store(self.variable_registers[register] as u16, Ordering::Relaxed);
333 }
334 SubCommand::SetSoundTimer => {
335 self.sound_timer
336 .store(self.variable_registers[register] as u16, Ordering::Relaxed);
337 }
338 SubCommand::AddToIndexRegister => {
339 self.index_register += self.variable_registers[register] as usize;
340 }
341 SubCommand::GetFontCharacter(FontVariant::Small) => {
342 self.index_register =
343 FONT_ADDR + (self.variable_registers[register] & 0xF) as usize * 5;
344 }
345 SubCommand::GetFontCharacter(FontVariant::Big) => {
346 self.index_register =
347 BIG_FONT_ADDR + (self.variable_registers[register]) as usize * 10;
348 }
349 SubCommand::DecimalConversion => {
350 let val = self.variable_registers[register];
351 let val = u8_to_arr(val);
352
353 for (i, val) in val.iter().enumerate() {
354 let wrapped = (self.index_register + i) % self.memory.len();
355 if let Some(x) = self.memory.get_mut(wrapped) {
356 *x = *val;
357 };
358 }
359 }
360 SubCommand::LoadFrom => {
361 for (i, reg) in self.variable_registers[0..=register].iter_mut().enumerate() {
362 let wrapped = (self.index_register + i) % self.memory.len();
363 if let Some(x) = self.memory.get(wrapped) {
364 *reg = *x;
365 }
366 }
367
368 if self.quirks.memory {
369 self.index_register += register + 1;
370 }
371 }
372 SubCommand::StoreTo => {
373 for (i, reg) in self.variable_registers[0..=register].iter().enumerate() {
374 let wrapped = (self.index_register + i) % self.memory.len();
375 if let Some(x) = self.memory.get_mut(wrapped) {
376 *x = *reg;
377 }
378 }
379 if self.quirks.memory {
380 self.index_register += register + 1;
381 }
382 }
383 SubCommand::GetKey => {
384 let mut key_pressed = false;
385 if let Ok(keys) = self.input_provider.read_keys_state() {
386 for (i, key) in keys.iter().enumerate() {
387 if *key > 0 {
388 self.variable_registers[register] = i as u8;
389 key_pressed = true;
390 break;
391 }
392 }
393 }
394 if !key_pressed {
395 self.program_counter -= 2;
396 } else {
397 self.input_provider.reset_keys_state();
398 };
399 }
400 SubCommand::Unimplemented(_value) => {}
401 }
402 }
403
404 fn perform_logical_operator(
405 &mut self,
406 register_x: usize,
407 register_y: usize,
408 operator: LogicalOperator,
409 ) {
410 match operator {
411 LogicalOperator::Set => {
412 self.variable_registers[register_x] = self.variable_registers[register_y];
413 }
414 LogicalOperator::BinaryOr => {
415 self.variable_registers[register_x] |= self.variable_registers[register_y];
416 if self.quirks.vf_reset {
417 self.variable_registers[0xF] = 0;
418 }
419 }
420 LogicalOperator::BinaryAnd => {
421 self.variable_registers[register_x] &= self.variable_registers[register_y];
422 if self.quirks.vf_reset {
423 self.variable_registers[0xF] = 0;
424 }
425 }
426 LogicalOperator::LogicalXor => {
427 self.variable_registers[register_x] ^= self.variable_registers[register_y];
428 if self.quirks.vf_reset {
429 self.variable_registers[0xF] = 0;
430 }
431 }
432 LogicalOperator::AddAffectingCarry => {
433 let res = self.variable_registers[register_x] as u16
434 + self.variable_registers[register_y] as u16;
435 self.variable_registers[register_x] = (res & 0xFF) as u8;
436 self.variable_registers[0xF] = if res > 255 { 1 } else { 0 };
437 }
438 LogicalOperator::Subtract => {
439 let res = self.variable_registers[register_x] as i16
440 - self.variable_registers[register_y] as i16;
441 self.variable_registers[register_x] = (res & 0xFF) as u8;
442 self.variable_registers[0xF] = if res >= 0 { 1 } else { 0 };
443 }
444 LogicalOperator::SubtractReverse => {
445 let res = self.variable_registers[register_y] as i16
446 - self.variable_registers[register_x] as i16;
447 self.variable_registers[register_x] = (res & 0xFF) as u8;
448 self.variable_registers[0xF] = if res >= 0 { 1 } else { 0 };
449 }
450 LogicalOperator::Shift(direction) => {
451 if !self.quirks.shifting {
454 self.variable_registers[register_x] = self.variable_registers[register_y];
455 }
456 match direction {
457 Direction::Left => {
458 let top = self.variable_registers[register_x] & 0b1000_0000;
459 let res = self.variable_registers[register_x] << 1;
460 self.variable_registers[register_x] = res;
461 if top > 0 {
462 self.variable_registers[0xF] = 1
463 } else {
464 self.variable_registers[0xF] = 0
465 };
466 }
467 Direction::Right => {
468 let bot = self.variable_registers[register_x] & 0b1;
469 let res = self.variable_registers[register_x] >> 1;
470 self.variable_registers[register_x] = res;
471 if bot > 0 {
472 self.variable_registers[0xF] = 1
473 } else {
474 self.variable_registers[0xF] = 0
475 };
476 }
477 }
478 }
479 LogicalOperator::Invalid => {}
480 }
481 }
482
483 fn draw(&mut self, x_register: usize, y_register: usize, height: u8) {
484 let (x_value, y_value) = (
485 (self.variable_registers[x_register] % self.screen_width as u8) as u16,
486 (self.variable_registers[y_register] % self.screen_height as u8) as u16,
487 );
488 self.variable_registers[0xF] = 0;
489
490 let start_loc = y_value * self.screen_width as u16 + x_value;
491
492 let (width, height) = { if height == 0 { (16, 16) } else { (8, height) } };
493
494 for i in 0..height {
496 let mut overdrawn_y = false;
497 let sprite_row = if width == 8 {
498 let wrapped_mem_index = (self.index_register + i as usize) % self.memory.len();
499 let Some(sprite_row) = self.memory.get(wrapped_mem_index) else {
500 break;
501 };
502 *sprite_row as u16
503 } else {
504 let wrapped_mem_index_first_half =
505 (self.index_register + (i * 2) as usize) % self.memory.len();
506 let Some(sprite_left_half) = self.memory.get(wrapped_mem_index_first_half) else {
507 break;
508 };
509 let wrapped_mem_index_second_half =
510 (self.index_register + (i * 2 + 1) as usize) % self.memory.len();
511 let Some(sprite_right_half) = self.memory.get(wrapped_mem_index_second_half) else {
512 break;
513 };
514 (*sprite_left_half as u16) << 8 | *sprite_right_half as u16
515 };
516
517 let current_loc = start_loc + self.screen_width as u16 * i as u16;
518
519 if y_value + i as u16 > (self.screen_height - 1) as u16 {
520 if self.quirks.clipping {
521 continue;
522 } else {
523 overdrawn_y = true;
524 }
525 }
526 for j in 0..width {
528 let mut overdrawn_x = false;
529 let mask: u16 = 0b1 << (width - j - 1);
530
531 if (x_value + j) > (self.screen_width - 1) as u16 {
532 if self.quirks.clipping {
533 continue;
534 } else {
535 overdrawn_x = true;
536 }
537 }
538
539 let mut to_get_index = current_loc + j;
540
541 if overdrawn_x {
545 to_get_index -= self.screen_width as u16;
546 }
547
548 if overdrawn_y {
552 to_get_index -= (self.screen_width * self.screen_height) as u16;
553 }
554
555 if let Some(x) = self.screen_buffer.get_mut((to_get_index) as usize) {
556 let pixel = if (mask & sprite_row) > 0 { 1 } else { 0 };
557 if pixel > 0 && *x > 0 {
559 self.variable_registers[0xF] = 1;
560 }
561 *x ^= pixel;
562 }
563 }
564 }
565 self.wait_to_display();
566 self.drawer
567 .draw_buffer(&self.screen_buffer, self.screen_width, self.screen_height);
568 }
569
570 fn wait_to_display(&mut self) {
571 let now = SystemTime::now();
572 let time_since_last_draw = now
573 .duration_since(self.last_draw)
574 .expect("Earlier is before now.");
575
576 if time_since_last_draw < self.max_draw_delay {
577 std::thread::sleep(self.max_draw_delay - time_since_last_draw);
578 }
579 self.last_draw = SystemTime::now();
580 }
581
582 fn clear_screen(&mut self) {
583 for i in self.screen_buffer.iter_mut() {
584 *i = 0;
585 }
586 self.drawer.clear_screen();
587 }
588
589 fn set_mem_block(&mut self, set: &[u8], start_addr: usize) -> Result<(), ApplicationError> {
590 let end_addr = start_addr + set.len();
591 if end_addr > self.memory.len() {
592 return Err(ApplicationError::MemoryLocationOutOfRange {
593 max_addr: self.memory.len() - set.len(),
594 });
595 }
596 let x = &mut self.memory[start_addr..end_addr];
597 for (i, item) in x.iter_mut().enumerate() {
598 *item = set[i];
599 }
600 Ok(())
601 }
602}
603
604#[derive(Debug)]
607pub struct EmulatorState {
608 pub memory: [u8; 0x1000],
609 pub stack: Vec<usize>,
610 pub variable_registers: [u8; 16],
611 pub screen_buffer: Vec<u8>,
612 pub index_register: usize,
613 pub program_counter: usize,
614 pub last_instruction: Instruction,
615}
616
617impl<T: Draw, P: ReadInputState> Iterator for Emulator<T, P> {
618 type Item = EmulatorState;
619
620 fn next(&mut self) -> Option<Self::Item> {
621 let instruction = self.fetch();
622 self.execute(instruction.clone());
623 Some(EmulatorState {
624 last_instruction: instruction,
625 memory: self.memory,
626 stack: self.stack.clone(),
627 variable_registers: self.variable_registers,
628 screen_buffer: self.screen_buffer.clone(),
629 index_register: self.index_register,
630 program_counter: self.program_counter,
631 })
632 }
633}
634
635#[cfg(test)]
636mod tests {
637 struct DummyInput;
638 struct DebugDrawer;
639 impl Draw for DebugDrawer {
640 fn draw_buffer(&mut self, _: &[u8], _: usize, _: usize) {}
641 fn clear_screen(&mut self) {}
642 }
643 impl ReadInputState for DummyInput {
644 fn read_keys_state(&self) -> Result<[u8; 16], String> {
645 Ok([0; 16])
646 }
647 fn reset_keys_state(&mut self) {}
648 }
649
650 use super::*;
651
652 #[test]
653 fn it_can_fetch_an_instruction() {
654 let mut emulator =
655 Emulator::<DebugDrawer, DummyInput>::init(vec![], DebugDrawer, DummyInput)
656 .expect("All initial memory is in range");
657
658 emulator
659 .set_mem_block(&FONT, FONT_ADDR)
660 .expect("Should be able to set font");
661
662 emulator.memory[0x200] = 0x00;
664 emulator.memory[0x201] = 0xE0;
665
666 emulator.memory[0x202] = 0xDE;
668 emulator.memory[0x203] = 0xF5;
669
670 emulator.memory[0x204] = 0x6E;
672 emulator.memory[0x205] = 0xAB;
673
674 emulator.memory[0x206] = 0x7E;
676 emulator.memory[0x207] = 0xAB;
677
678 emulator.memory[0x208] = 0xA1;
680 emulator.memory[0x209] = 0x23;
681
682 emulator.memory[0x20A] = 0x11;
684 emulator.memory[0x20B] = 0x23;
685
686 emulator.memory[0x20C] = 0x31;
688 emulator.memory[0x20D] = 0x23;
689
690 emulator.memory[0x20E] = 0x41;
692 emulator.memory[0x20F] = 0x23;
693
694 emulator.memory[0x210] = 0x51;
696 emulator.memory[0x211] = 0x20;
697
698 emulator.memory[0x212] = 0x91;
700 emulator.memory[0x213] = 0x20;
701
702 emulator.program_counter = 0x200;
703
704 let instruction = emulator.fetch();
705 assert!(matches!(instruction, Instruction::ClearScreen));
706
707 let instruction = emulator.fetch();
708 assert!(matches!(
709 instruction,
710 Instruction::Draw {
711 x_register: 0xE,
712 y_register: 0xF,
713 height: 0x5
714 }
715 ));
716
717 let instruction = emulator.fetch();
718 assert!(matches!(
719 instruction,
720 Instruction::SetGeneralRegister {
721 register: 0xE,
722 value: 0xAB
723 }
724 ));
725
726 let instruction = emulator.fetch();
727 assert!(matches!(
728 instruction,
729 Instruction::AddToRegister {
730 register: 0xE,
731 value: 0xAB
732 }
733 ));
734
735 let instruction = emulator.fetch();
736 assert!(matches!(instruction, Instruction::SetIndexRegister(0x123)));
737
738 let instruction = emulator.fetch();
739 assert!(matches!(instruction, Instruction::Jump(0x123)));
740
741 let instruction = emulator.fetch();
742 assert!(matches!(
743 instruction,
744 Instruction::SkipEqValueWithRegisterContents {
745 register: 0x1,
746 value: 0x23
747 }
748 ));
749
750 let instruction = emulator.fetch();
751 assert!(matches!(
752 instruction,
753 Instruction::SkipNotEqValueWithRegisterContents {
754 register: 0x1,
755 value: 0x23
756 }
757 ));
758
759 let instruction = emulator.fetch();
760 assert!(matches!(
761 instruction,
762 Instruction::SkipEqRegisters {
763 register_x: 0x1,
764 register_y: 0x2
765 }
766 ));
767
768 let instruction = emulator.fetch();
769 assert!(matches!(
770 instruction,
771 Instruction::SkipNotEqRegisters {
772 register_x: 0x1,
773 register_y: 0x2
774 }
775 ));
776 }
777}