1#![allow(non_snake_case)]
2#![allow(unused_parens)]
3#![allow(dead_code)]
4
5use std::{convert::TryFrom, ops::ShlAssign};
6use std::fs::File;
7use std::io::prelude::*;
8use std::convert::TryInto;
9use std::path::PathBuf;
10use std::ops::ShrAssign;
11use std::collections::VecDeque;
12use std::{thread, time};
13
14use function_name::named;
15
16
17pub struct Chip8 {
19 registers: [u8; 16],
20 memory: [u8; 4096],
21 index_register: u16,
22 program_counter: u16,
23 stack: [u16; 16],
24 stack_pointer: u8,
25 delay_timer: u8,
26 sound_timer: u8,
27 pub keypad: [u8; 16],
28 recent_presses: VecDeque<u8>,
29 pub video: [u32; 64 * 32],
30 op_code: u16,
31 table: [fn(&mut Chip8); 0xF+1],
32 table0: [fn(&mut Chip8); 0xE+1],
33 table8: [fn(&mut Chip8); 0xE+1],
34 tableE: [fn(&mut Chip8); 0xE+1],
35 tableF: [fn(&mut Chip8); 0x65+1],
36 debug_mode: bool,
37 last_opcode: u16,
38 rng_state: u32,
39}
40
41
42impl Chip8 {
43 pub fn new() -> Self {
78
79 let mut chip8: Chip8 = Chip8 {
80 registers: [0; 16],
81 memory: [0; 4096],
82 index_register: 0,
83 program_counter: 0x200,
84 stack: [0; 16],
85 stack_pointer: 0,
86 delay_timer: 0,
87 sound_timer: 0,
88 keypad: [0; 16],
89 recent_presses: VecDeque::new(),
90 video: [0; 2048],
91 op_code: 0,
92 table: [Chip8::OP_ERR; 0xF+1],
93 table0: [Chip8::OP_ERR; 0xE+1],
94 table8: [Chip8::OP_ERR; 0xE+1],
95 tableE: [Chip8::OP_ERR; 0xE+1],
96 tableF: [Chip8::OP_ERR; 0x65+1],
97 debug_mode: false,
98 last_opcode: 0,
99 rng_state: 77,
100 };
101
102 chip8.load_fonts();
103 chip8.add_table();
104
105 return chip8;
106 }
107
108 pub fn last_opcode(&self) -> u16 { self.last_opcode }
109 pub fn play(&mut self, speed: u64) {
120 let cycle_wait_time = time::Duration::from_millis(speed);
121
122 loop {
123 self.Cycle();
124 self.pretty_print_video();
125 thread::sleep(cycle_wait_time);
126 }
127 }
128
129 pub fn add_table(&mut self) {
131 if (self.debug_mode) {
132 eprintln!("Loading tables");
133 }
134
135 let table: [fn(&mut Chip8); 0xF+1] = [
136 Chip8::Table0,
137 Chip8::OP_1nnn,
138 Chip8::OP_2nnn,
139 Chip8::OP_3xkk,
140 Chip8::OP_4xkk,
141 Chip8::OP_5xy0,
142 Chip8::OP_6xkk,
143 Chip8::OP_7xkk,
144 Chip8::Table8,
145 Chip8::OP_9xy0,
146 Chip8::OP_Annn,
147 Chip8::OP_Bnnn,
148 Chip8::OP_Cxkk,
149 Chip8::OP_Dxyn,
150 Chip8::TableE,
151 Chip8::TableF
152 ];
153
154 let mut table0: [fn(&mut Chip8); 0xE+1] = [Chip8::OP_ERR; 0xE+1];
157 let mut table8: [fn(&mut Chip8); 0xE+1] = [Chip8::OP_ERR; 0xE+1];
158 let mut tableE: [fn(&mut Chip8); 0xE+1] = [Chip8::OP_ERR; 0xE+1];
159 let mut tableF: [fn(&mut Chip8); 0x65+1] = [Chip8::OP_ERR; 0x65+1];
160
161 table0[0x0] = Chip8::OP_00E0;
162 table0[0xE] = Chip8::OP_00EE;
163
164 table8[0x0] = Chip8::OP_8xy0;
165 table8[0x1] = Chip8::OP_8xy1;
166 table8[0x2] = Chip8::OP_8xy2;
167 table8[0x3] = Chip8::OP_8xy3;
168 table8[0x4] = Chip8::OP_8xy4;
169 table8[0x5] = Chip8::OP_8xy5;
170 table8[0x6] = Chip8::OP_8xy6;
171 table8[0x7] = Chip8::OP_8xy7;
172 table8[0xE] = Chip8::OP_8xyE;
173
174 tableE[0x1] = Chip8::OP_ExA1;
175 tableE[0xE] = Chip8::OP_Ex9E;
176
177 tableF[0x07] = Chip8::OP_Fx07;
178 tableF[0x0A] = Chip8::OP_Fx0A;
179 tableF[0x15] = Chip8::OP_Fx15;
180 tableF[0x18] = Chip8::OP_Fx18;
181 tableF[0x1E] = Chip8::OP_Fx1E;
182 tableF[0x29] = Chip8::OP_Fx29;
183 tableF[0x33] = Chip8::OP_Fx33;
184 tableF[0x55] = Chip8::OP_Fx55;
185 tableF[0x65] = Chip8::OP_Fx65;
186
187
188 self.table = table;
190 self.table0 = table0;
191 self.table8 = table8;
192 self.tableE = tableE;
193 self.tableF = tableF;
194
195 if (self.debug_mode) {
196 eprintln!("Tables loaded");
197 }
198 }
199
200 pub fn debug(&mut self) {
202 self.debug_mode ^= true;
204 eprintln!("Debug mode activated");
205 }
206
207 #[inline]
209 fn rand_byte(&mut self) -> u8 {
210 let mut x = if self.rng_state == 0 { 0x1234_5678 } else { self.rng_state };
211 x ^= x << 13;
212 x ^= x >> 17;
213 x ^= x << 5;
214 self.rng_state = x;
215 (x & 0xFF) as u8
216 }
217
218 pub fn reset_hard(&mut self) {
219 self.memory.fill(0);
221 self.load_fonts();
222
223 self.program_counter = 0x200;
224 self.index_register = 0;
225 self.stack_pointer = 0;
226 self.stack.fill(0);
227
228 self.video.fill(0);
229 self.delay_timer = 0;
230 self.sound_timer = 0;
231
232 self.video.fill(0);
233 self.keypad.fill(0);
234
235 self.rng_state = 0x1234_5678; self.last_opcode = 0;
237 }
238
239 pub fn reset_and_load_bytes(&mut self, rom: &[u8]) -> Result<(), Chip8Error> {
240 self.reset_hard();
241 const START: usize = 0x200;
242 if START + rom.len() > self.memory.len() {
243 return Err(Chip8Error::MemOob(START + rom.len()));
244 }
245 self.memory[START..START + rom.len()].copy_from_slice(rom);
246 Ok(())
247 }
248
249 pub fn load_rom(&mut self, path: PathBuf) -> Result<(), std::io::Error> {
251 let bytes = std::fs::read(path)?;
252 self.reset_and_load_bytes(&bytes).map_err(|_| std::io::ErrorKind::InvalidData.into())
253 }
254
255 pub fn load_rom_bytes(&mut self, rom: &[u8]) {
256 const START: usize = 0x200;
257
258 let mem_len = self.memory.len();
259 if START >= mem_len {
260 return;
261 }
262
263 let copy_len = rom.len().min(mem_len - START);
264 self.memory[START..START + copy_len].copy_from_slice(&rom[..copy_len]);
265 }
266
267 pub fn dump_rom(&self, start_address: usize, byte_number: usize) -> Vec<u8> {
269 let mut rom: Vec<u8> = Vec::new();
270 for i in start_address..start_address + byte_number {
272 rom.push(self.memory[i]);
273 }
274 return rom;
275 }
276
277 pub fn export_video(&mut self) -> &[u32; 64 * 32] {
278 &self.video
279 }
280
281 pub fn pretty_print_video(&mut self) {
282 print!("\x1B[2J\x1B[1;1H");
285 let mut new_vec = self.video.iter().peekable();
286 let mut rows: Vec<Vec<_>> = vec![];
287 while new_vec.peek().is_some() {
288 let chunk: Vec<_> = new_vec.by_ref().take(64).collect();
289 rows.push(chunk);
290 }
291
292 for row in rows {
293 let mut current_row = "".to_string();
294
295 for pixel in row {
296 if (pixel == &(0xFFFFFFFF as u32)) {
297 current_row.push('█');
298 } else {
299 current_row.push(' ');
300 }
301 }
302 println!("{}", current_row);
303 }
304 }
305
306 fn load_fonts(&mut self) {
308 let fontset: [u8; 80] = [
309 0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0, 0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0, 0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0, 0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0, 0xF0, 0x80, 0x80, 0x80, 0xF0, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0, 0xF0, 0x80, 0xF0, 0x80, 0x80, ];
326
327 let fontset_start_address = 0x50;
328
329 if (self.debug_mode) {
330 eprintln!("Loading fontset");
331 }
332
333 for i in 0..fontset.len() {
334 self.memory[fontset_start_address + i as usize] = fontset[i as usize];
335 }
336
337 if (self.debug_mode) {
338 eprintln!("Fontset loaded");
339 }
340 }
341
342 #[inline]
343 pub fn key_down(&mut self, k: u8) {
344 let idx = k as usize;
345 if self.keypad[idx] == 0 {
346 self.keypad[idx] = 1;
347 self.recent_presses.push_back(k);
349 }
350 }
351
352 #[inline]
353 pub fn key_up(&mut self, k: u8) {
354 self.keypad[k as usize] = 0;
355 }
356
357 #[inline]
358 pub fn is_key_down(&self, k: u8) -> bool {
359 self.keypad[k as usize] != 0
360 }
361
362 pub fn take_recent_press(&mut self) -> Option<u8> {
364 self.recent_presses.pop_front()
365 }
366
367 #[named]
377 pub fn OP_00E0(&mut self) {
378 self.video = [0; 2048];
380 if self.debug_mode {
381 eprintln!("Ran opcode: {}", function_name!());
382 }
383 }
384
385 #[named]
387 fn OP_00EE(&mut self) {
388 self.stack_pointer = self.stack_pointer - 1;
389
390 self.program_counter = self.stack[self.stack_pointer as usize];
391 if self.debug_mode {
392 eprintln!("Ran opcode: {}", function_name!());
393 }
394 }
395
396 #[named]
398 fn OP_1nnn(&mut self) {
399 let address: u16 = self.op_code & 0x0FFF;
401
402 self.program_counter = address;
403 if self.debug_mode {
404 eprintln!("Ran opcode: {}", function_name!());
405 }
406 }
407
408 #[named]
410 fn OP_2nnn(&mut self) {
411 let address: u16 = self.op_code & 0x0FFF;
412
413 self.stack[self.stack_pointer as usize] = self.program_counter;
414 self.stack_pointer = self.stack_pointer + 1;
415 self.program_counter = address;
416 if self.debug_mode {
417 eprintln!("Ran opcode: {}", function_name!());
418 }
419 }
420
421 #[named]
424 fn OP_3xkk(&mut self) {
425 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
426 let byte: u16 = self.op_code & 0x00FF;
427
428 let byte: u8 = match u8::try_from(byte) {
429 Ok(number) => number,
430 Err(error) => panic!(
431 "Could not turn u16 into u8 in OPCODE: 3XKK. Error: {}",
432 error
433 ),
434 };
435
436 if self.registers[Vx as usize] == byte {
437 self.program_counter += 2;
438 }
439 if self.debug_mode {
440 eprintln!("Ran opcode: {}", function_name!());
441 }
442 }
443
444 #[named]
446 fn OP_4xkk(&mut self) {
447 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
448
449 let byte: u16 = self.op_code & 0x00FF;
450
451 let byte: u8 = match u8::try_from(byte) {
452 Ok(number) => number,
453 Err(error) => panic!(
454 "Could not turn u16 into u8 in OPCODE: 3XKK. Error: {}",
455 error
456 ),
457 };
458
459 if self.registers[Vx as usize] != byte {
461 self.program_counter += 2;
462 }
463 if self.debug_mode {
464 eprintln!("Ran opcode: {}", function_name!());
465 }
466 }
467
468 #[named]
470 fn OP_5xy0(&mut self) {
471 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
472
473 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
474
475 if self.registers[Vx as usize] == self.registers[Vy as usize] {
476 self.program_counter += 2;
477 }
478 if self.debug_mode {
479 eprintln!("Ran opcode: {}", function_name!());
480 }
481 }
482
483 #[named]
485 fn OP_6xkk(&mut self) {
486 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
487
488 let byte: u16 = self.op_code & 0x00FF;
489
490 let byte: u8 = match u8::try_from(byte) {
491 Ok(number) => number,
492 Err(error) => panic!(
493 "Could not turn u16 into u8 in OPCODE 6XKK. Error: {}",
494 error
495 ),
496 };
497
498 self.registers[Vx as usize] = byte;
499 if self.debug_mode {
500 eprintln!("Ran opcode: {}", function_name!());
501 }
502
503 }
504
505 #[named]
507 fn OP_7xkk(&mut self) {
508 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
509
510 let byte: u8 = (self.op_code as u8) & 0x00FF;
511
512 self.registers[Vx as usize] = (((self.registers[Vx as usize] as u16) + byte as u16) % 256) as u8;
513
514 if self.debug_mode {
515 eprintln!("Ran opcode: {}", function_name!());
516 }
517 }
518
519 #[named]
521 fn OP_8xy0(&mut self) {
522 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
523
524 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
525
526 self.registers[Vx as usize] = self.registers[Vy as usize];
527 if self.debug_mode {
528 eprintln!("Ran opcode: {}", function_name!());
529 }
530 }
531
532 #[named]
534 fn OP_8xy1(&mut self) {
535 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
536
537 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
538
539 self.registers[Vx as usize] |= self.registers[Vy as usize];
540 if self.debug_mode {
541 eprintln!("Ran opcode: {}", function_name!());
542 }
543 }
544
545 #[named]
547 fn OP_8xy2(&mut self) {
548 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
549
550 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
551
552 self.registers[Vx as usize] &= self.registers[Vy as usize];
553 if self.debug_mode {
554 eprintln!("Ran opcode: {}", function_name!());
555 }
556 }
557
558 #[named]
560 fn OP_8xy3(&mut self) {
561 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
562
563 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
564
565 self.registers[Vx as usize] ^= self.registers[Vy as usize];
566 if self.debug_mode {
567 eprintln!("Ran opcode: {}", function_name!());
568 }
569 }
570
571 #[named]
574 fn OP_8xy4(&mut self) {
575 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
576
577 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
578
579 let sum: u16 = self.registers[Vx as usize] as u16 + self.registers[Vy as usize] as u16;
580
581 if sum > 255 {
582 self.registers[0xF] = 1;
583 } else {
584 self.registers[0xF] = 0;
585 }
586
587 self.registers[Vx as usize] = (sum & 0xFF) as u8;
588 if self.debug_mode {
589 eprintln!("Ran opcode: {}", function_name!());
590 }
591 }
592
593 #[named]
596 fn OP_8xy5(&mut self) {
597 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
598
599 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
600
601 if self.registers[Vx as usize] > self.registers[Vy as usize] {
602 self.registers[0xF] = 1;
603 } else {
604 self.registers[0xF] = 0;
605 }
606
607
608 self.registers[Vx as usize] = self.registers[Vx as usize].wrapping_sub(self.registers[Vy as usize]);
609
610 if self.debug_mode {
611 eprintln!("Ran opcode: {}", function_name!());
612 }
613 }
614
615 #[named]
618 fn OP_8xy6(&mut self) {
619 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
620
621
622 self.registers[0xF] = self.registers[Vx as usize] & 0x1;
624
625 self.registers[Vx as usize].shr_assign(1);
626 if self.debug_mode {
627 eprintln!("Ran opcode: {}", function_name!());
628 }
629 }
630
631 #[named]
634 fn OP_8xy7(&mut self) {
635 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
636
637 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
638
639 if self.registers[Vy as usize] > self.registers[Vx as usize] {
640 self.registers[0xF] = 1;
641 } else {
642 self.registers[0xF] = 0;
643 }
644
645 self.registers[Vx as usize] = self.registers[Vy as usize].wrapping_sub(self.registers[Vx as usize]);
647
648 if self.debug_mode {
649 eprintln!("Ran opcode: {}", function_name!());
650 }
651 }
652
653 #[named]
656 fn OP_8xyE(&mut self) {
657 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
658
659
660 self.registers[0xF] = (self.registers[Vx as usize] & 0x80).checked_shr(7).unwrap_or(0);
662
663 self.registers[Vx as usize].shl_assign(1);
664 if self.debug_mode {
665 eprintln!("Ran opcode: {}", function_name!());
666 }
667 }
668
669 #[named]
671 fn OP_9xy0(&mut self) {
672 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
673
674 let Vy: u16 = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
675
676 if self.registers[Vx as usize] != self.registers[Vy as usize] {
677 self.program_counter += 2;
678 }
679 if self.debug_mode {
680 eprintln!("Ran opcode: {}", function_name!());
681 }
682 }
683
684 #[named]
686 fn OP_Annn(&mut self) {
687 let address: u16 = self.op_code & 0x0FFF;
688
689 self.index_register = address;
690 if self.debug_mode {
691 eprintln!("Ran opcode: {}", function_name!());
692 }
693 }
694
695 #[named]
697 fn OP_Bnnn(&mut self) {
698 let address: u16 = self.op_code & 0x0FFF;
699
700 self.program_counter = self.registers[0] as u16 + address;
701 if self.debug_mode {
702 eprintln!("Ran opcode: {}", function_name!());
703 }
704 }
705
706 #[named]
708 fn OP_Cxkk(&mut self) {
709 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
710
711 let byte: u16 = self.op_code & 0x00FF;
712
713 let byte: u8 = match u8::try_from(byte) {
714 Ok(number) => number,
715 Err(error) => panic!(
716 "Could not turn u16 into u8 in OPCODE CXKK. Error: {}",
717 error
718 ),
719 };
720
721 self.registers[Vx as usize] = self.rand_byte() & byte;
722 if self.debug_mode {
723 eprintln!("Ran opcode: {}", function_name!());
724 }
725 }
726
727 #[named]
729 fn OP_Dxyn(&mut self) {
730 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
731 let Vy = (self.op_code & 0x00F0).checked_shr(4).unwrap_or(0);
732 let height = self.op_code & 0x000F;
733 let VIDEO_WIDTH: u8 = 64;
734 let VIDEO_HEIGHT: u8 = 32;
735
736 let x_pos: u8 = self.registers[Vx as usize] % VIDEO_WIDTH;
738 let y_pos: u8 = self.registers[Vy as usize] % VIDEO_HEIGHT;
739
740 self.registers[0xF] = 0;
741
742 for row in 0..height {
743 let sprite_byte: u8 = self.memory[(self.index_register + row) as usize];
744
745 for col in 0..8 {
746 let sprite_pixel = sprite_byte & ((0x80 as u16).checked_shr(col as u32).unwrap_or(0) as u8);
747 let video_index = ((y_pos as u16).wrapping_add(row) * (VIDEO_WIDTH as u16))
758 .wrapping_add(x_pos as u16)
759 .wrapping_add(col) as usize;
760
761
762 if sprite_pixel != 0 {
764 if self.video[video_index] == 0xFFFFFFFF {
766 self.registers[0xF] = 1;
767 }
768
769 self.video[video_index] ^= 0xFFFFFFFF;
771 }
772 }
773 }
774 if self.debug_mode {
775 eprintln!("Ran opcode: {}", function_name!());
776 }
777 }
778
779 #[named]
781 fn OP_Ex9E(&mut self) {
782 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
783 let key: u8 = self.registers[Vx as usize];
784
785 if self.keypad[key as usize] != 0 {
786 self.program_counter += 2;
787 }
788 if self.debug_mode {
789 eprintln!("Ran opcode: {}", function_name!());
790 }
791 }
792
793 #[named]
795 fn OP_ExA1(&mut self) {
796 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
797 let key: u8 = self.registers[Vx as usize];
798
799 if self.keypad[key as usize] == 0 {
800 self.program_counter += 2;
801 }
802 if self.debug_mode {
803 eprintln!("Ran opcode: {}", function_name!());
804 }
805 }
806
807 #[named]
809 fn OP_Fx07(&mut self) {
810 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
811
812 self.registers[Vx as usize] = self.delay_timer;
813 if self.debug_mode {
814 eprintln!("Ran opcode: {}", function_name!());
815 }
816 }
817
818 #[named]
820 fn OP_Fx0A(&mut self) {
821 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
822
823 if self.keypad[0] != 0 {
824 self.registers[Vx as usize] = 0;
825 } else if self.keypad[1] != 0 {
826 self.registers[Vx as usize] = 1;
827 } else if self.keypad[2] != 0 {
828 self.registers[Vx as usize] = 2;
829 } else if self.keypad[3] != 0 {
830 self.registers[Vx as usize] = 3;
831 } else if self.keypad[4] != 0 {
832 self.registers[Vx as usize] = 4;
833 } else if self.keypad[5] != 0 {
834 self.registers[Vx as usize] = 5;
835 } else if self.keypad[6] != 0 {
836 self.registers[Vx as usize] = 6;
837 } else if self.keypad[7] != 0 {
838 self.registers[Vx as usize] = 7;
839 } else if self.keypad[8] != 0 {
840 self.registers[Vx as usize] = 8;
841 } else if self.keypad[9] != 0 {
842 self.registers[Vx as usize] = 9;
843 } else if self.keypad[10] != 0 {
844 self.registers[Vx as usize] = 10;
845 } else if self.keypad[11] != 0 {
846 self.registers[Vx as usize] = 11;
847 } else if self.keypad[12] != 0 {
848 self.registers[Vx as usize] = 12;
849 } else if self.keypad[13] != 0 {
850 self.registers[Vx as usize] = 13;
851 } else if self.keypad[14] != 0 {
852 self.registers[Vx as usize] = 14;
853 } else if self.keypad[15] != 0 {
854 self.registers[Vx as usize] = 15;
855 } else {
856 self.program_counter -= 2;
857 }
858 if self.debug_mode {
859 eprintln!("Ran opcode: {}", function_name!());
860 }
861 }
862
863 #[named]
865 fn OP_Fx15(&mut self) {
866 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
867
868 self.delay_timer = self.registers[Vx as usize];
869 if self.debug_mode {
870 eprintln!("Ran opcode: {}", function_name!());
871 }
872 }
873
874 #[named]
876 fn OP_Fx18(&mut self) {
877 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
878
879 self.sound_timer = self.registers[Vx as usize];
880 if self.debug_mode {
881 eprintln!("Ran opcode: {}", function_name!());
882 }
883 }
884
885 #[named]
887 fn OP_Fx1E(&mut self) {
888 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
889
890 self.index_register += self.registers[Vx as usize] as u16;
891 if self.debug_mode {
892 eprintln!("Ran opcode: {}", function_name!());
893 }
894 }
895
896 #[named]
898 fn OP_Fx29(&mut self) {
899 let Vx: u16 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0);
901 let digit = self.registers[Vx as usize];
902 let fontset_start_address = 0x50;
903
904 self.index_register = (fontset_start_address + (5*digit)) as u16;
905 if self.debug_mode {
906 eprintln!("Ran opcode: {}", function_name!());
907 }
908 }
909
910 #[named]
913 fn OP_Fx33(&mut self) {
914 let Vx: u8 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
915 let mut value: u8 = self.registers[Vx as usize];
916
917 self.memory[(self.index_register + 2) as usize] = value % 10;
919 value /= 10;
920
921 self.memory[(self.index_register + 1) as usize] = value % 10;
923 value /= 10;
924
925 self.memory[self.index_register as usize] = value % 10;
927 if self.debug_mode {
928 eprintln!("Ran opcode: {}", function_name!());
929 }
930 }
931
932 #[named]
934 fn OP_Fx55(&mut self) {
935 let Vx: u16 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0);
937
938 for i in 0..(Vx +1) {
939 self.memory[(self.index_register + i) as usize] = self.registers[i as usize];
940 }
941 if self.debug_mode {
942 eprintln!("Ran opcode: {}", function_name!());
943 }
944 }
945
946 #[named]
948 fn OP_Fx65(&mut self) {
949 let Vx: u16 = (self.op_code & 0x0F00).checked_shr(8).unwrap_or(0).try_into().unwrap();
951
952 for i in 0..(Vx +1) {
953 self.registers[i as usize] = self.memory[(self.index_register + i) as usize];
954 }
955 if self.debug_mode {
956 eprintln!("Ran opcode: {}", function_name!());
957 }
958 }
959
960 #[named]
962 fn OP_ERR(&mut self) {
963 eprintln!("[ERROR]: Opcode {} not valid", self.op_code);
964 if self.debug_mode {
965 eprintln!("Ran opcode: {}", function_name!());
966 }
967 }
968
969
970 #[named]
971 fn Table0(&mut self) {
972 if self.debug_mode {
973 eprintln!("Running table: {}", function_name!());
974 }
975 self.table0[(self.op_code & 0x000F) as usize](self);
976 }
977
978 #[named]
979 fn Table8(&mut self) {
980 if self.debug_mode {
981 eprintln!("Running table: {}", function_name!());
982 }
983 self.table8[(self.op_code & 0x000F) as usize](self);
984 }
985
986 #[named]
987 fn TableE(&mut self) {
988 if self.debug_mode {
989 eprintln!("Running table: {}", function_name!());
990 }
991 self.tableE[(self.op_code & 0x000F) as usize](self);
992 }
993
994 #[named]
995 fn TableF(&mut self) {
996 if self.debug_mode {
997 eprintln!("Running table: {}", function_name!());
998 }
999 self.tableF[(self.op_code & 0x00FF) as usize](self);
1000 }
1001
1002
1003 pub fn Cycle(&mut self) {
1007 self.op_code = ((self.memory[self.program_counter as usize] as u16).checked_shl(8).unwrap_or(0)) | self.memory[(self.program_counter + 1) as usize] as u16;
1010 if (self.debug_mode) {
1011 eprintln!("Opcode: {}", &self.op_code);
1012 }
1013 self.last_opcode = self.op_code;
1014 self.program_counter += 2;
1016
1017 self.table[((self.op_code & 0xF000).checked_shr(12).unwrap_or(0)) as usize](self);
1019
1020 if (self.delay_timer > 0) {
1022 self.delay_timer -= 1;
1023 }
1024
1025 if (self.sound_timer > 0) {
1027 self.sound_timer -= 1;
1028 }
1029
1030 }
1031
1032}
1033
1034#[derive(Debug, Clone)]
1035pub enum Chip8Error {
1036 UnknownOpcode(u16),
1037 PcOob(u16),
1038 MemOob(usize),
1039 StackOverflow,
1040 StackUnderflow,
1041 BadRegisterIndex(u8),
1042}
1043
1044use std::fmt;
1045
1046impl fmt::Display for Chip8Error {
1047 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1048 match self {
1049 Chip8Error::UnknownOpcode(op) =>
1050 write!(f, "Unknown opcode: {:04X}", op),
1051 Chip8Error::PcOob(pc) =>
1052 write!(f, "PC out of bounds: {:04X}", pc),
1053 Chip8Error::MemOob(addr) =>
1054 write!(f, "Memory access out of bounds: {:#X}", addr),
1055 Chip8Error::StackOverflow =>
1056 write!(f, "Stack overflow"),
1057 Chip8Error::StackUnderflow =>
1058 write!(f, "Stack underflow"),
1059 Chip8Error::BadRegisterIndex(r) =>
1060 write!(f, "Invalid register index: {}", r),
1061 }
1062 }
1063}
1064
1065
1066#[cfg(test)]
1073mod tests {
1074 use crate::Chip8;
1075
1076 #[test]
1077 fn add_two() {
1078 assert_eq!(2, 1 +1);
1079 }
1080
1081 #[test]
1082 fn check_fontset() {
1083 let fontset: [u8; 80] = [
1084 0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0, 0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0, 0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0, 0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0, 0xF0, 0x80, 0x80, 0x80, 0xF0, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0, 0xF0, 0x80, 0xF0, 0x80, 0x80, ];
1101
1102 let fontset_start_address = 0x50;
1103
1104 let chip8: Chip8 = Chip8::new();
1105
1106 for i in 0..fontset.len() {
1107 assert_eq!(chip8.memory[fontset_start_address + i as usize], fontset[i as usize]);
1108 }
1109
1110 }
1111}