chip8_rs/
chip8.rs

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
17/// General chip 8 struct
18pub 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    /// Create a new chip8 instance with an empty `rom`, ready for use
44    ///
45    /// # Example:
46    ///
47    /// ```
48    /// let mut chip8: Chip8 = Chip8::new();
49    ///
50    /// chip.load_rom(path);
51    ///
52    /// let rom: PathBuf = '...';
53    /// let speed: u64 = 30;
54    ///
55    /// loop {
56    ///
57    ///     chip8.Cycle();
58    ///     chip8.pretty_print_video(rom);
59    ///     thread::sleep(time::Duration::from_millis(speed);
60    /// }
61    /// ```
62    ///
63    /// ## Values
64    ///
65    /// * `registers`: all zeroes
66    /// * `memory`/`rom`: all zeroes
67    /// * `index_register`: 0
68    /// * `program_counter`: 0x200
69    /// * `stack`: all zeroes
70    /// * `stack_poionter`: 0
71    /// * `delay_timer`: 0
72    /// * `sound_timer`: 0
73    /// * `keypad`: all zeroes
74    /// * `video`: all zeroes
75    /// * `op_code`: 0
76    /// * `fontset_size`: 80
77    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    /// Runs the CHIP8 Machine forever with the currently loaded ROM.
110    /// The clock speed is determined by the passed in `speed` parameter.
111    ///
112    /// ```
113    /// loop {
114    ///     self.Cycle();
115    ///     self.pretty_print_video();
116    ///     thread::sleep(cycle_wait_time);
117    /// }
118    /// ```
119    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    /// Adds the correct function pointer tables to the newly created Chip8 object
130    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        // Chip8::OP_ERR here is just a placeholder, technically the array is already filled with
155        // OP_ERR
156        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        // Apply the newly generated tables
189        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    /// Toggle debug mode for current chip8 instance
201    pub fn debug(&mut self) {
202        // bitwise xor
203        self.debug_mode ^= true;
204        eprintln!("Debug mode activated");
205    }
206
207    /// needed for wasm
208    #[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        // keep fonts if you store them in low memory; reload them here if needed
220        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; // fixed seed for determinism
236        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    /// Loads a given rom into memory, starting from memory address 0x200
250    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    /// Returns `byte_number` amount of bytes after the `pointer` in rom
268    pub fn dump_rom(&self, start_address: usize, byte_number: usize) -> Vec<u8> {
269        let mut rom: Vec<u8> = Vec::new();
270        // for each memory address after the pointer add that address to the buffer, then return the buffer
271        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        // █ &(0xFFFFFFFF as u32)
283        //print!("\x1B[2J\x1B[1;1H");
284        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    /// Load the fontset into memory
307    fn load_fonts(&mut self) {
308        let fontset: [u8; 80] = [
309            0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
310            0x20, 0x60, 0x20, 0x20, 0x70, // 1
311            0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
312            0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
313            0x90, 0x90, 0xF0, 0x10, 0x10, // 4
314            0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
315            0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
316            0xF0, 0x10, 0x20, 0x40, 0x40, // 7
317            0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
318            0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
319            0xF0, 0x90, 0xF0, 0x90, 0x90, // A
320            0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
321            0xF0, 0x80, 0x80, 0x80, 0xF0, // C
322            0xE0, 0x90, 0x90, 0x90, 0xE0, // D
323            0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
324            0xF0, 0x80, 0xF0, 0x80, 0x80, // F];
325        ];
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            // record only the transition (press edge)
348            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    /// Use this in FX0A (wait for key): returns one press if available.
363    pub fn take_recent_press(&mut self) -> Option<u8> {
364        self.recent_presses.pop_front()
365    }
366
367    //
368    //
369    // From Now On I will define all `opcodes`, taken from here:
370    //
371    // https://austinmorlan.com/posts/chip8_emulator/
372    //
373    //
374
375    /// OPCODE 00E0 - Clear Screen
376    #[named]
377    pub fn OP_00E0(&mut self) {
378        // set video buffer to zero
379        self.video = [0; 2048];
380        if self.debug_mode {
381            eprintln!("Ran opcode: {}", function_name!());
382        }
383    }
384
385    /// OPCODE 00EE - Return from subroutine
386    #[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    /// OPCODE 1NNN - Jump to location NNN(set program counter to nnn)
397    #[named]
398    fn OP_1nnn(&mut self) {
399        // using 0x0FFF I can take the NNN from the opcode while leaving the one
400        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    /// OPCODE 2NNN - Call subroutine at location NNN
409    #[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    /// OPCODE 3XKK - Skip next instruction if Vx = kk
422    /// Since our PC has already been incremented by 2 in Cycle(), we can just increment by 2 again to skip the next instruction.
423    #[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    /// OPCODE 4XKK - Skip next instruction if Vx != kk
445    #[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        // this != is the onlh difference from the function above
460        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    /// OPCODE 5XY0 - Skip next instruction if Vx = Vy.
469    #[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    /// OPCODE 6XKK - Set Vx = kk.
484    #[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    /// OPCODE 7XKK - Set Vx = Vx + kk.
506    #[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    /// OPCODE 8XY0 - Set Vx = Vy.
520    #[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    /// OPCODE 8XY1 - Set Vx = Vx OR Vy.
533    #[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    /// OPCODE 8XY2 - Set Vx = Vx AND Vy
546    #[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    /// OPCODE 8XY3 - Set Vx = Vx XOR Vy
559    #[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    /// OPCODE 8XY4 - Set Vx = Vx + Vy, set VF = carry.
572    /// The values of Vx and Vy are added together. If the result is greater than 8 bits (i.e., > 255,) VF is set to 1, otherwise 0. Only the lowest 8 bits of the result are kept, and stored in Vx.
573    #[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    /// OPCODE 8XY5 - Set Vx = Vx - Vy, set VF = NOT borrow.
594    /// If Vx > Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the results stored in Vx.
595    #[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    /// OPCODE 8XY6 - Set Vx = Vx SHR 1.
616    /// If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.
617    #[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        // Save LSB in VF
623        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    /// OPCODE 8XY7 - SUBN Vx, Vy
632    /// If Vy > Vx, then VF is set to 1, otherwise 0. Then Vx is subtracted from Vy, and the results stored in Vx.
633    #[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] - self.registers[Vx as usize];
646        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    /// OPCODE 8XYE - Set Vx = Vx SHL 1.
654    /// If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.
655    #[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        // save MSB in VF
661        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    /// OPCODE 9XY0 - Skip next instruction if Vx != Vy
670    #[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    /// OPCODE ANNN - set I = nnn
685    #[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    /// OPCODE BNNN - Jump to location nnn + V0
696    #[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    /// OPCODE CXKK - Set Vx = random byte AND kk.
707    #[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    /// OPCODE DXYN - Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
728    #[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        // wrap if going over boundaries
737        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                // casting without error checking here is fine because col and raw wil alwyays be lower than 255(they are 64 and 32)
748                //let mut screen_pixel = self.video[(((y_pos as u16 + row) * (VIDEO_WIDTH as u16) + (x_pos as u16) + col)) as usize];
749
750                // old: 
751                //
752                // ```
753                // let video_index = ((y_pos as u16 + row) * (VIDEO_WIDTH as u16) + (x_pos as u16) + col) as usize;
754                // ```
755                //
756                // new:
757                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                // sprite pixel is on
763                if sprite_pixel != 0 {
764                    // screen pixel also on - collision
765                    if self.video[video_index] == 0xFFFFFFFF {
766                        self.registers[0xF] = 1;
767                    }
768
769                    // Effectively XOR with the sprite pixel
770                    self.video[video_index] ^= 0xFFFFFFFF;
771                }
772            }
773        }
774        if self.debug_mode {
775            eprintln!("Ran opcode: {}", function_name!());
776        }
777    }
778
779    /// OPCODE EX9E - Skip next instruction if key with the value of Vx is pressed.
780    #[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    /// OPCODE EXA1 - Skip next instruction if key with the value of Vx is not pressed
794    #[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    /// OPCODE FX07 - Set Vx = delay timer value
808    #[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    /// OPCODE FX0A - Wait for a key press, store the value of the key in Vx.
819    #[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    /// OPCODE FX15 - Set delay timer = Vx.
864    #[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    /// OPCODE FX18 - Set sound timer = Vx.
875    #[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    /// OPCODE FX1E - Set I = I + Vx.
886    #[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    /// OPCODE FX29 - Set I = location of sprite for digit Vx.
897    #[named]
898    fn OP_Fx29(&mut self) {
899        // TODO this Vx has to stay u16 bc I have to cast it either way back into index register
900        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    /// OPCODE FX33 - Store BCD representation of Vx in memory locations I, I+1, and I+2.
911    /// The interpreter takes the decimal value of Vx, and places the hundreds digit in memory at location in I, the tens digit at location I+1, and the ones digit at location I+2.
912    #[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        // ones place
918        self.memory[(self.index_register + 2) as usize] = value % 10;
919        value /= 10;
920
921        // tens place
922        self.memory[(self.index_register + 1) as usize] = value % 10;
923        value /= 10;
924
925        // hundreds place
926        self.memory[self.index_register as usize] = value % 10;
927        if self.debug_mode {
928            eprintln!("Ran opcode: {}", function_name!());
929        }
930    }
931
932    /// OPCODE FX55 -- Store registers V0 to VX in memory starting at location X
933    #[named]
934    fn OP_Fx55(&mut self) {
935        // TODO: this has to stay a u16 bc it needs to get added into index register
936        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    /// OPCODE FX65 - Read registers V0 through Vx from memory starting at location I.
947    #[named]
948    fn OP_Fx65(&mut self) {
949        // TODO: has to stay u16, bc we need to recast it anyways
950        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    /// Fallback OPCODE
961    #[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    // the opcodes are stored in memory starting from index 512, i need to decode them and map each opcode to one of my functions
1004    // The CHIP-8 Architecture uses big-endian (0x00 0xe0 -> 0x00e0)
1005
1006    pub fn Cycle(&mut self) {
1007        // Fetch opcode
1008        //let _: () = self.memory[self.program_counter as usize].checked_shl(8).unwrap_or(0);
1009        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        // increment pc before we do anything
1015        self.program_counter += 2;
1016
1017        // decode and execute
1018        self.table[((self.op_code & 0xF000).checked_shr(12).unwrap_or(0)) as usize](self);
1019
1020        // Decrement delay timer if it exists
1021        if (self.delay_timer > 0) {
1022            self.delay_timer -= 1;
1023        }
1024
1025        // Decrement sound timer if it exists
1026        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/*
1067*
1068*   UNIT TESTS
1069*
1070*/
1071
1072#[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, // 0
1085            0x20, 0x60, 0x20, 0x20, 0x70, // 1
1086            0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
1087            0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
1088            0x90, 0x90, 0xF0, 0x10, 0x10, // 4
1089            0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
1090            0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
1091            0xF0, 0x10, 0x20, 0x40, 0x40, // 7
1092            0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
1093            0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
1094            0xF0, 0x90, 0xF0, 0x90, 0x90, // A
1095            0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
1096            0xF0, 0x80, 0x80, 0x80, 0xF0, // C
1097            0xE0, 0x90, 0x90, 0x90, 0xE0, // D
1098            0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
1099            0xF0, 0x80, 0xF0, 0x80, 0x80, // F];
1100        ];
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}