diff --git a/src/chip_8.rs b/src/chip_8.rs new file mode 100644 index 0000000..f24ae48 --- /dev/null +++ b/src/chip_8.rs @@ -0,0 +1,4 @@ +pub mod chip_8; + +mod cpu; +mod display; diff --git a/src/chip_8/chip_8.rs b/src/chip_8/chip_8.rs new file mode 100644 index 0000000..07c1695 --- /dev/null +++ b/src/chip_8/chip_8.rs @@ -0,0 +1,90 @@ +use super::cpu::cpu::CPU; +use super::display::Display; + +use std::io::Read; + +pub fn run() { + let mut cpu = CPU::new(); + cpu.ram.init_fonts(); //TODO: load in the RAM + cpu.clock.clock_hz = 60.; + load_rom("src/chip_8/roms/CAVE.ch8", &mut cpu); + + let sdl_context = sdl2::init().unwrap(); + let mut display = Display::init(&sdl_context, cpu.db.scale); + let mut event_listener = sdl_context.event_pump().unwrap(); + + 'runner: loop { + for event in event_listener.poll_iter() { + match event { + sdl2::event::Event::Quit { .. } => break 'runner, + sdl2::event::Event::KeyDown { + keycode: Some(sdl2::keyboard::Keycode::Escape), + .. + } => break 'runner, + sdl2::event::Event::KeyDown { + keycode: Some(sdl2::keyboard::Keycode::RightBracket), + .. + } => { + println!( + "Increasing cpu clock from {:5} Hz to {:5} Hz", + cpu.clock.clock_hz, + cpu.clock.clock_hz + 10. + ); + cpu.clock.clock_hz += 10.; + } + sdl2::event::Event::KeyDown { + keycode: Some(sdl2::keyboard::Keycode::LeftBracket), + .. + } => { + println!( + "Decreasing cpu clock from {:5} Hz to {:5} Hz", + cpu.clock.clock_hz, + cpu.clock.clock_hz - 10. + ); + cpu.clock.clock_hz -= 10.; + } + sdl2::event::Event::KeyDown { + keycode: Some(sdl2::keyboard::Keycode::Backspace), + .. + } => { + cpu.pc.0 = 0x200; + } + sdl2::event::Event::KeyDown { + keycode: Some(keycode), + .. + } => { + if let Some(key_index) = cpu.keypad.compute_keycode(keycode) { + cpu.keypad.press(key_index); + } + } + sdl2::event::Event::KeyUp { + keycode: Some(keycode), + .. + } => { + if let Some(key_index) = cpu.keypad.compute_keycode(keycode) { + cpu.keypad.release(key_index); + } + } + _ => {} + } + } + + cpu.dt.tick(); + cpu.st.tick(); + if cpu.clock.tick() { + cpu.fetch(); + cpu.decode(); + if cpu.decode_match("D???") { + display.draw(&cpu.db.db) + } + } + } +} + +fn load_rom(filename: &str, cpu: &mut CPU) { + let mut f = std::fs::File::open(&filename).expect("no file found"); + let metadata = std::fs::metadata(&filename).expect("unable to read metadata"); + let mut buffer = vec![0; metadata.len() as usize]; + f.read(&mut buffer).expect("buffer overflow"); + cpu.ram.write_rom(&buffer); +} diff --git a/src/chip_8/chip_8_base_interpreter.rs b/src/chip_8/chip_8_base_interpreter.rs deleted file mode 100644 index 549e493..0000000 --- a/src/chip_8/chip_8_base_interpreter.rs +++ /dev/null @@ -1,822 +0,0 @@ -// CHIP-8 means Compact Hexadecimal Interpretive Programming - 8-bit -use ::sdl2; - -use rand::Rng; -use std::io::Read; - -const DISPLAY_WIDTH: usize = 64; -const DISPLAY_HEIGHT: usize = 32; -const DISPLAY_SCALE: u32 = 30; - -pub struct ProgramCounter(usize); -pub struct DisplayBuffer([[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH]); -pub struct Ram { - ram: [u8; 4 * 1024], - font_address: usize, - rom_address: usize, -} -pub struct Registers { - x_0: u8, - x_1: u8, - x_2: u8, - x_3: u8, - x_4: u8, - x_5: u8, - x_6: u8, - x_7: u8, - x_8: u8, - x_9: u8, - x_a: u8, - x_b: u8, - x_c: u8, - x_d: u8, - x_e: u8, - x_f: u8, -} -pub struct Clock { - tick: u8, - clock_hz: f64, - elapsed: std::time::SystemTime, -} -pub struct Keypad { - key_status: [bool; 0x10], - keys: std::collections::HashMap, -} -pub struct OpCodes { - opcode: u16, - n1: u8, - n2: u8, - n3: u8, - n4: u8, - x: usize, - y: usize, - n: u8, - nn: u8, - nnn: usize, - str_to_hex_helper: std::collections::HashMap>, // Helper -} - -impl ProgramCounter { - fn init() -> ProgramCounter { - ProgramCounter { 0: 0x200 } - } - - fn increment(&mut self) { - self.0 += 2; - } - - fn decrement(&mut self) { - self.0 -= 2; - } -} - -impl Registers { - fn init() -> Registers { - Registers { - x_0: 0, - x_1: 0, - x_2: 0, - x_3: 0, - x_4: 0, - x_5: 0, - x_6: 0, - x_7: 0, - x_8: 0, - x_9: 0, - x_a: 0, - x_b: 0, - x_c: 0, - x_d: 0, - x_e: 0, - x_f: 0, - } - } - - fn get(&self, register: usize) -> u8 { - assert!(register <= 0xF); - match register { - 0x0 => self.x_0, - 0x1 => self.x_1, - 0x2 => self.x_2, - 0x3 => self.x_3, - 0x4 => self.x_4, - 0x5 => self.x_5, - 0x6 => self.x_6, - 0x7 => self.x_7, - 0x8 => self.x_8, - 0x9 => self.x_9, - 0xA => self.x_a, - 0xB => self.x_b, - 0xC => self.x_c, - 0xD => self.x_d, - 0xE => self.x_e, - 0xF => self.x_f, - _ => 0, - } - } - - fn set(&mut self, register: usize, value: u8) { - assert!(register <= 0xF); - match register { - 0x0 => self.x_0 = value, - 0x1 => self.x_1 = value, - 0x2 => self.x_2 = value, - 0x3 => self.x_3 = value, - 0x4 => self.x_4 = value, - 0x5 => self.x_5 = value, - 0x6 => self.x_6 = value, - 0x7 => self.x_7 = value, - 0x8 => self.x_8 = value, - 0x9 => self.x_9 = value, - 0xA => self.x_a = value, - 0xB => self.x_b = value, - 0xC => self.x_c = value, - 0xD => self.x_d = value, - 0xE => self.x_e = value, - 0xF => self.x_f = value, - _ => {} - } - } -} - -impl Ram { - fn init() -> Ram { - Ram { - ram: [0x00; 4 * 1024], - font_address: 0x50 as usize, - rom_address: 0x200 as usize, - } - } - - fn init_fonts(&mut self) { - let fonts: [u8; 80] = [ - 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 - 0x20, 0x60, 0x20, 0x20, 0x70, // 1 - 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 - 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 - 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 - 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 - 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 - 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 - 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 - 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 - 0xF0, 0x90, 0xF0, 0x90, 0x90, // A - 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B - 0xF0, 0x80, 0x80, 0x80, 0xF0, // C - 0xE0, 0x90, 0x90, 0x90, 0xE0, // D - 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E - 0xF0, 0x80, 0xF0, 0x80, 0x80, // F - ]; - for i in 0..fonts.len() { - self.ram[i + self.font_address] = fonts[i]; - } - } - - fn load_rom(&mut self, rom: &[u8]) { - assert!( - rom.len() <= self.ram.len() - 0x200, - "ROM is bigger than Chip-8 RAM" - ); - for i in 0..rom.len() { - self.ram[self.rom_address + i] = rom[i]; - } - } - - fn read8(&self, addr: usize) -> u8 { - assert!( - addr <= self.ram.len(), - "addr = {}, self.0.len() = {}", - addr, - self.ram.len() - ); - self.ram[addr] - } - - fn read16(&self, addr: usize) -> u16 { - assert!( - addr < self.ram.len(), - "addr = {}, self.0.len() = {}", - addr, - self.ram.len() - ); - (self.ram[addr] as u16) << 8 | self.ram[addr + 1] as u16 - } - - fn write(&mut self, addr: usize, value: u8) { - assert!( - addr < self.ram.len(), - "addr = {}, self.0.len() = {}", - addr, - self.ram.len() - ); - self.ram[addr] = value; - } -} - -impl Clock { - fn init() -> Clock { - Clock { - tick: 0xFF, - clock_hz: 60., - elapsed: std::time::SystemTime::now(), - } - } - - fn tick(&mut self) -> bool { - let mut res: bool = false; - match self.elapsed.elapsed() { - Ok(elapsed) => { - if elapsed.as_secs_f64() >= self.clock_hz_as_secs_f64() { - if self.tick > 0 { - self.tick -= 1; - } - self.reset_elapsed(); - res = true; - } - } - Err(e) => { - println!("Error: {:?}", e); - } - } - res - } - - fn reset_elapsed(&mut self) { - self.elapsed = std::time::SystemTime::now(); - } - - fn clock_hz_as_secs_f64(&self) -> f64 { - 1. / self.clock_hz - } -} - -impl Keypad { - fn init() -> Keypad { - Keypad { - key_status: [false; 0x10], - keys: [ - (sdl2::keyboard::Keycode::Num1, 0x1), - (sdl2::keyboard::Keycode::Num2, 0x2), - (sdl2::keyboard::Keycode::Num3, 0x3), - (sdl2::keyboard::Keycode::Num4, 0xC), - (sdl2::keyboard::Keycode::Q, 0x4), - (sdl2::keyboard::Keycode::W, 0x5), - (sdl2::keyboard::Keycode::E, 0x6), - (sdl2::keyboard::Keycode::R, 0xD), - (sdl2::keyboard::Keycode::A, 0x7), - (sdl2::keyboard::Keycode::S, 0x8), - (sdl2::keyboard::Keycode::D, 0x9), - (sdl2::keyboard::Keycode::F, 0xE), - (sdl2::keyboard::Keycode::Z, 0xA), - (sdl2::keyboard::Keycode::X, 0x0), - (sdl2::keyboard::Keycode::C, 0xB), - (sdl2::keyboard::Keycode::V, 0xF), - ] - .iter() - .cloned() - .collect(), - } - } - - fn compute_keycode(&self, keycode: sdl2::keyboard::Keycode) -> Option { - match self.keys.get(&keycode) { - Some(chip8_key) => Some(*chip8_key), - None => None, - } - } - - fn get(&mut self, pos: usize) -> bool { - self.key_status[pos] - } - - fn being_pressed(&self) -> Option { - for key in 0x0..0x10 { - if self.key_status[key] { - return Some(key as u8); - } - } - None - } - - fn press(&mut self, key: usize) { - self.key_status[key] = true; - } - - fn release(&mut self, key: usize) { - self.key_status[key] = false; - } -} - -impl DisplayBuffer { - fn init() -> DisplayBuffer { - DisplayBuffer { - 0: [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH], - } - } - - fn clear(&mut self) { - self.0 = [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH]; - } -} - -impl OpCodes { - fn init(opcode: u16) -> OpCodes { - let n1 = (opcode & 0xF000) >> 12; - let n2 = (opcode & 0xF00) >> 8; - let n3 = (opcode & 0xF0) >> 4; - let n4 = opcode & 0xF; - let nn = opcode & 0xFF; - let nnn = opcode & 0xFFF; - - OpCodes { - opcode: opcode, - n1: n1 as u8, - n2: n2 as u8, - n3: n3 as u8, - n4: n4 as u8, - x: n2 as usize, - y: n3 as usize, - n: n4 as u8, - nn: nn as u8, - nnn: nnn as usize, - - str_to_hex_helper: [ - ('0', Some(0x0)), - ('1', Some(0x1)), - ('2', Some(0x2)), - ('3', Some(0x3)), - ('4', Some(0x4)), - ('5', Some(0x5)), - ('6', Some(0x6)), - ('7', Some(0x7)), - ('8', Some(0x8)), - ('9', Some(0x9)), - ('A', Some(0xA)), - ('B', Some(0xB)), - ('C', Some(0xC)), - ('D', Some(0xD)), - ('E', Some(0xE)), - ('F', Some(0xF)), - ('?', None), - ] - .iter() - .cloned() - .collect(), - } - } -} - -struct CPU { - pc: ProgramCounter, // Program Counter - i: usize, // Index Register - stack: Vec, // Function Stack - dt: Clock, // Delay Timer - st: Clock, // Sound Timer - clock: Clock, // CPU Clock - registers: Registers, // Registers - ram: Ram, // RAM - keypad: Keypad, // Keypad - db: DisplayBuffer, // Display Buffer - op: OpCodes, // Operation Code -} - -impl CPU { - fn init() -> CPU { - CPU { - pc: ProgramCounter::init(), - i: 0, - stack: vec![], - dt: Clock::init(), - st: Clock::init(), - clock: Clock::init(), - registers: Registers::init(), - ram: Ram::init(), - keypad: Keypad::init(), - db: DisplayBuffer::init(), - op: OpCodes::init(0000), - } - } - - fn fetch(&mut self) { - self.op = OpCodes::init(self.ram.read16(self.pc.0)); - self.pc.increment(); - } - - fn decode(&mut self) { - //TODO: function pointers - if self.decode_match("00E0") { - op_00e0(self); - } else if self.decode_match("1???") { - op_1nnn(self); - } else if self.decode_match("00EE") { - op_00ee(self); - } else if self.decode_match("2???") { - op_2nnn(self); - } else if self.decode_match("3???") { - op_3xnn(self); - } else if self.decode_match("4???") { - op_4xnn(self); - } else if self.decode_match("5??0") { - op_5xy0(self); - } else if self.decode_match("9??0") { - op_9xy0(self); - } else if self.decode_match("6???") { - op_6xnn(self); - } else if self.decode_match("7???") { - op_7xnn(self); - } else if self.decode_match("8??0") { - op_8xy0(self); - } else if self.decode_match("8??1") { - op_8xy1(self); - } else if self.decode_match("8??2") { - op_8xy2(self); - } else if self.decode_match("8??3") { - op_8xy3(self); - } else if self.decode_match("8??4") { - op_8xy4(self); - } else if self.decode_match("8??5") { - op_8xy5(self); - } else if self.decode_match("8??6") { - op_8xy6(self); - } else if self.decode_match("8??7") { - op_8xy7(self); - } else if self.decode_match("8??E") { - op_8xye(self); - } else if self.decode_match("A???") { - op_annn(self); - } else if self.decode_match("B???") { - op_bnnn(self); - } else if self.decode_match("C???") { - op_cxnn(self); - } else if self.decode_match("D???") { - op_dxyn(self); - } else if self.decode_match("E?9E") { - op_ex9e(self); - } else if self.decode_match("E?A1") { - op_exa1(self); - } else if self.decode_match("F??7") { - op_fx07(self); - } else if self.decode_match("F?15") { - op_fx15(self); - } else if self.decode_match("F?18") { - op_fx18(self); - } else if self.decode_match("F?1E") { - op_fx1e(self); - } else if self.decode_match("F?0A") { - op_fx0a(self); - } else if self.decode_match("F?29") { - op_fx29(self); - } else if self.decode_match("F?33") { - op_fx33(self); - } else if self.decode_match("F?55") { - op_fx55(self); - } else if self.decode_match("F?65") { - op_fx65(self); - } else { - println! {"Unknown instruction: {:04x}", self.op.opcode}; - } - } - - fn decode_match(&self, hex_code: &str) -> bool { - assert!( - hex_code.len() == 4, - "Instruction with wrong size. All chip-8 instructions have 16 bits" - ); - assert!(hex_code.ne("????"), "???? is a invalid instruction"); - let mut res: bool = false; - for (i, c) in hex_code.chars().enumerate() { - match self.op.str_to_hex_helper.get(&c) { - Some(None) => { - res = true; - } - Some(Some(hex)) => { - if !self.compare_nibble(i, &hex) { - res = false; - break; - } - } - _ => { - res = false; - break; - } - } - } - res - } - - fn compare_nibble(&self, pos: usize, nibble: &u8) -> bool { - match pos { - 0 => *nibble == self.op.n1, - 1 => *nibble == self.op.n2, - 2 => *nibble == self.op.n3, - 3 => *nibble == self.op.n4, - _ => false, - } - } -} - -pub fn run() { - let mut cpu = CPU::init(); - cpu.ram.init_fonts(); //TODO: load in the RAM - cpu.clock.clock_hz = 60.; - load_rom("src/chip_8/roms/CAVE.ch8", &mut cpu); - - let sdl_context = sdl2::init().unwrap(); - let mut display = crate::chip_8::display::Display::init(&sdl_context, DISPLAY_SCALE); - let mut event_listener = sdl_context.event_pump().unwrap(); - - 'runner: loop { - for event in event_listener.poll_iter() { - match event { - sdl2::event::Event::Quit { .. } => break 'runner, - sdl2::event::Event::KeyDown { - keycode: Some(sdl2::keyboard::Keycode::Escape), - .. - } => break 'runner, - sdl2::event::Event::KeyDown { - keycode: Some(sdl2::keyboard::Keycode::RightBracket), - .. - } => { - println!( - "Increasing cpu clock from {:5} Hz to {:5} Hz", - cpu.clock.clock_hz, - cpu.clock.clock_hz + 10. - ); - cpu.clock.clock_hz += 10.; - } - sdl2::event::Event::KeyDown { - keycode: Some(sdl2::keyboard::Keycode::LeftBracket), - .. - } => { - println!( - "Decreasing cpu clock from {:5} Hz to {:5} Hz", - cpu.clock.clock_hz, - cpu.clock.clock_hz - 10. - ); - cpu.clock.clock_hz -= 10.; - } - sdl2::event::Event::KeyDown { - keycode: Some(sdl2::keyboard::Keycode::Backspace), - .. - } => { - cpu.pc.0 = 0x200; - } - sdl2::event::Event::KeyDown { - keycode: Some(keycode), - .. - } => { - if let Some(key_index) = cpu.keypad.compute_keycode(keycode) { - cpu.keypad.press(key_index); - } - } - sdl2::event::Event::KeyUp { - keycode: Some(keycode), - .. - } => { - if let Some(key_index) = cpu.keypad.compute_keycode(keycode) { - cpu.keypad.release(key_index); - } - } - _ => {} - } - } - - cpu.dt.tick(); - cpu.st.tick(); - if cpu.clock.tick() { - cpu.fetch(); - cpu.decode(); - if cpu.decode_match("D???") { - display.draw(&cpu.db.0) - } - } - } -} - -fn load_rom(filename: &str, cpu: &mut CPU) { - let mut f = std::fs::File::open(&filename).expect("no file found"); - let metadata = std::fs::metadata(&filename).expect("unable to read metadata"); - let mut buffer = vec![0; metadata.len() as usize]; - f.read(&mut buffer).expect("buffer overflow"); - cpu.ram.load_rom(&buffer); -} - -fn op_00e0(cpu: &mut CPU) { - cpu.db.clear(); -} - -fn op_1nnn(cpu: &mut CPU) { - cpu.pc.0 = cpu.op.nnn; -} - -fn op_00ee(cpu: &mut CPU) { - let value = cpu.stack.pop(); - match value { - Some(value) => { - cpu.pc.0 = value; - } - _ => {} - } -} - -fn op_2nnn(cpu: &mut CPU) { - cpu.stack.push(cpu.pc.0); - cpu.pc.0 = cpu.op.nnn; -} - -fn op_3xnn(cpu: &mut CPU) { - if cpu.registers.get(cpu.op.x) == cpu.op.nn { - cpu.pc.increment(); - } -} - -fn op_4xnn(cpu: &mut CPU) { - if cpu.registers.get(cpu.op.x) != cpu.op.nn { - cpu.pc.increment(); - } -} - -fn op_5xy0(cpu: &mut CPU) { - if cpu.registers.get(cpu.op.x) == cpu.registers.get(cpu.op.y) { - cpu.pc.increment(); - } -} - -fn op_9xy0(cpu: &mut CPU) { - if cpu.registers.get(cpu.op.x) != cpu.registers.get(cpu.op.y) { - cpu.pc.increment(); - } -} - -fn op_6xnn(cpu: &mut CPU) { - cpu.registers.set(cpu.op.x, cpu.op.nn); -} - -fn op_7xnn(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - cpu.registers.set(cpu.op.x, cpu.op.nn.wrapping_add(vx)); -} - -fn op_8xy0(cpu: &mut CPU) { - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vy); -} - -fn op_8xy1(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vx | vy); -} - -fn op_8xy2(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vx & vy); -} - -fn op_8xy3(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vx ^ vy); -} - -fn op_8xy4(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vx.wrapping_add(vy)); -} - -fn op_8xy5(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vx.wrapping_sub(vy)); - cpu.registers.x_f = if vx > vy { 1 } else { 0 }; -} - -fn op_8xy6(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vy >> 1); - cpu.registers.x_f = vx & 0x1; -} - -fn op_8xy7(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vy.wrapping_sub(vx)); - cpu.registers.x_f = if vy > vx { 1 } else { 0 }; -} - -fn op_8xye(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - let vy = cpu.registers.get(cpu.op.y); - cpu.registers.set(cpu.op.x, vy << 1); - cpu.registers.x_f = (vx & 0x80) >> 7; -} - -fn op_annn(cpu: &mut CPU) { - cpu.i = cpu.op.nnn; -} - -fn op_bnnn(cpu: &mut CPU) { - cpu.pc.0 = cpu.op.nnn + cpu.registers.x_0 as usize; -} - -fn op_cxnn(cpu: &mut CPU) { - let mut rng = rand::thread_rng(); - cpu.registers - .set(cpu.op.x, rng.gen_range(0x0..0xFF) & cpu.op.nn); -} - -fn op_dxyn(cpu: &mut CPU) { - let mut vf: bool = false; - let value = cpu.op.n as usize; - let ori_x = cpu.registers.get(cpu.op.x) as usize % DISPLAY_WIDTH; - let ori_y = cpu.registers.get(cpu.op.y) as usize % DISPLAY_HEIGHT; - - for row in 0..value { - let y = ori_y + row; - if y >= DISPLAY_HEIGHT { - break; - } - - let sprite = cpu.ram.read8(cpu.i + row); - for pixel_position in 0..8 { - let x = ori_x + pixel_position; - if x >= DISPLAY_WIDTH { - break; - } - - let memory_pixel: bool = (sprite & (1 << (7 - pixel_position))) > 0; - let display_pixel: bool = cpu.db.0[x][y]; - cpu.db.0[x][y] = memory_pixel ^ display_pixel; - vf = (memory_pixel && display_pixel) || vf; - } - } - cpu.registers.x_f = if vf { 1 } else { 0 }; -} - -fn op_ex9e(cpu: &mut CPU) { - if cpu.keypad.get(cpu.registers.get(cpu.op.x) as usize) { - cpu.pc.increment(); - } -} - -fn op_exa1(cpu: &mut CPU) { - if !cpu.keypad.get(cpu.registers.get(cpu.op.x) as usize) { - cpu.pc.increment(); - } -} - -fn op_fx07(cpu: &mut CPU) { - cpu.registers.set(cpu.op.x, cpu.dt.tick); -} - -fn op_fx15(cpu: &mut CPU) { - cpu.dt.tick = cpu.registers.get(cpu.op.x); -} - -fn op_fx18(cpu: &mut CPU) { - cpu.st.tick = cpu.registers.get(cpu.op.x); -} - -fn op_fx1e(cpu: &mut CPU) { - cpu.i += cpu.registers.get(cpu.op.x) as usize; -} - -fn op_fx0a(cpu: &mut CPU) { - match cpu.keypad.being_pressed() { - Some(key) => { - cpu.registers.set(cpu.op.x, key); - } - _ => { - cpu.pc.decrement(); - } - } -} - -fn op_fx29(cpu: &mut CPU) { - let char = (cpu.registers.get(cpu.op.x) & 0xF) as usize; - cpu.i = cpu.ram.font_address + char * 5; -} - -fn op_fx33(cpu: &mut CPU) { - let vx = cpu.registers.get(cpu.op.x); - cpu.ram.write(cpu.i, vx / 100); - cpu.ram.write(cpu.i + 1, vx / 10 % 10); - cpu.ram.write(cpu.i + 2, vx % 10); -} - -fn op_fx55(cpu: &mut CPU) { - let i = cpu.i; - for regs in 0x0..(cpu.op.x + 1) { - cpu.ram.write(i + regs, cpu.registers.get(regs)); - } -} - -fn op_fx65(cpu: &mut CPU) { - let i = cpu.i; - for regs in 0x0..(cpu.op.x + 1) { - cpu.registers.set(regs, cpu.ram.read8(i + regs)); - } -} diff --git a/src/chip_8/cpu.rs b/src/chip_8/cpu.rs new file mode 100644 index 0000000..8299370 --- /dev/null +++ b/src/chip_8/cpu.rs @@ -0,0 +1,9 @@ +pub mod cpu; + +mod clock; +mod display_buffer; +mod keypad; +mod opcodes; +mod program_counter; +mod ram; +mod registers; diff --git a/src/chip_8/cpu/clock.rs b/src/chip_8/cpu/clock.rs new file mode 100644 index 0000000..7ee67c5 --- /dev/null +++ b/src/chip_8/cpu/clock.rs @@ -0,0 +1,44 @@ +use std::time::SystemTime; + +pub struct Clock { + pub tick: u8, + pub clock_hz: f64, + elapsed: SystemTime, +} + +impl Clock { + pub fn new() -> Clock { + Clock { + tick: 0xFF, + clock_hz: 60., + elapsed: SystemTime::now(), + } + } + + pub fn tick(&mut self) -> bool { + let mut res: bool = false; + match self.elapsed.elapsed() { + Ok(elapsed) => { + if elapsed.as_secs_f64() >= self.clock_hz_as_secs_f64() { + if self.tick > 0 { + self.tick -= 1; + } + self.reset_elapsed(); + res = true; + } + } + Err(e) => { + println!("Error: {:?}", e); + } + } + res + } + + pub fn reset_elapsed(&mut self) { + self.elapsed = SystemTime::now(); + } + + pub fn clock_hz_as_secs_f64(&self) -> f64 { + 1. / self.clock_hz + } +} diff --git a/src/chip_8/cpu/cpu.rs b/src/chip_8/cpu/cpu.rs new file mode 100644 index 0000000..a36846d --- /dev/null +++ b/src/chip_8/cpu/cpu.rs @@ -0,0 +1,378 @@ +use super::clock::Clock; +use super::display_buffer::{DisplayBuffer, DISPLAY_HEIGHT, DISPLAY_WIDTH}; +use super::keypad::Keypad; +use super::opcodes::OpCodes; +use super::program_counter::ProgramCounter; +use super::ram::RAM; +use super::registers::Registers; + +use rand::Rng; + +pub struct CPU { + pub pc: ProgramCounter, + pub i: usize, + pub stack: Vec, + pub dt: Clock, + pub st: Clock, + pub clock: Clock, + pub registers: Registers, + pub ram: RAM, + pub keypad: Keypad, + pub db: DisplayBuffer, + pub op: OpCodes, +} + +impl CPU { + pub fn new() -> CPU { + CPU { + pc: ProgramCounter::new(), + i: 0, + stack: vec![], + dt: Clock::new(), + st: Clock::new(), + clock: Clock::new(), + registers: Registers::new(), + ram: RAM::new(), + keypad: Keypad::new(), + db: DisplayBuffer::new(10), + op: OpCodes::new(0000), + } + } + + pub fn fetch(&mut self) { + self.op = OpCodes::new(self.ram.read16(self.pc.0)); + self.pc.increment(); + } + + pub fn decode(&mut self) { + //TODO: function pointers + if self.decode_match("00E0") { + op_00e0(self); + } else if self.decode_match("1???") { + op_1nnn(self); + } else if self.decode_match("00EE") { + op_00ee(self); + } else if self.decode_match("2???") { + op_2nnn(self); + } else if self.decode_match("3???") { + op_3xnn(self); + } else if self.decode_match("4???") { + op_4xnn(self); + } else if self.decode_match("5??0") { + op_5xy0(self); + } else if self.decode_match("9??0") { + op_9xy0(self); + } else if self.decode_match("6???") { + op_6xnn(self); + } else if self.decode_match("7???") { + op_7xnn(self); + } else if self.decode_match("8??0") { + op_8xy0(self); + } else if self.decode_match("8??1") { + op_8xy1(self); + } else if self.decode_match("8??2") { + op_8xy2(self); + } else if self.decode_match("8??3") { + op_8xy3(self); + } else if self.decode_match("8??4") { + op_8xy4(self); + } else if self.decode_match("8??5") { + op_8xy5(self); + } else if self.decode_match("8??6") { + op_8xy6(self); + } else if self.decode_match("8??7") { + op_8xy7(self); + } else if self.decode_match("8??E") { + op_8xye(self); + } else if self.decode_match("A???") { + op_annn(self); + } else if self.decode_match("B???") { + op_bnnn(self); + } else if self.decode_match("C???") { + op_cxnn(self); + } else if self.decode_match("D???") { + op_dxyn(self); + } else if self.decode_match("E?9E") { + op_ex9e(self); + } else if self.decode_match("E?A1") { + op_exa1(self); + } else if self.decode_match("F??7") { + op_fx07(self); + } else if self.decode_match("F?15") { + op_fx15(self); + } else if self.decode_match("F?18") { + op_fx18(self); + } else if self.decode_match("F?1E") { + op_fx1e(self); + } else if self.decode_match("F?0A") { + op_fx0a(self); + } else if self.decode_match("F?29") { + op_fx29(self); + } else if self.decode_match("F?33") { + op_fx33(self); + } else if self.decode_match("F?55") { + op_fx55(self); + } else if self.decode_match("F?65") { + op_fx65(self); + } else { + println! {"Unknown instruction: {:04x}", self.op.opcode}; + } + } + + pub fn decode_match(&self, hex_code: &str) -> bool { + assert!( + hex_code.len() == 4, + "Instruction with wrong size. All chip-8 instructions have 16 bits" + ); + assert!(hex_code.ne("????"), "???? is a invalid instruction"); + let mut res: bool = true; + for (i, c) in hex_code.chars().enumerate() { + match self.op.str_to_hex_helper.get(&c) { + Some(None) => { + res = true; + } + Some(Some(hex)) => { + if !self.compare_nibble(i, &hex) { + res = false; + break; + } + } + _ => { + res = false; + break; + } + } + } + res + } + + fn compare_nibble(&self, pos: usize, nibble: &u8) -> bool { + match pos { + 0 => *nibble == self.op.n1, + 1 => *nibble == self.op.n2, + 2 => *nibble == self.op.n3, + 3 => *nibble == self.op.n4, + _ => false, + } + } +} + +fn op_00e0(cpu: &mut CPU) { + cpu.db.clear(); +} + +fn op_1nnn(cpu: &mut CPU) { + cpu.pc.0 = cpu.op.nnn; +} + +fn op_00ee(cpu: &mut CPU) { + let value = cpu.stack.pop(); + match value { + Some(value) => { + cpu.pc.0 = value; + } + _ => {} + } +} + +fn op_2nnn(cpu: &mut CPU) { + cpu.stack.push(cpu.pc.0); + cpu.pc.0 = cpu.op.nnn; +} + +fn op_3xnn(cpu: &mut CPU) { + if cpu.registers.get(cpu.op.x) == cpu.op.nn { + cpu.pc.increment(); + } +} + +fn op_4xnn(cpu: &mut CPU) { + if cpu.registers.get(cpu.op.x) != cpu.op.nn { + cpu.pc.increment(); + } +} + +fn op_5xy0(cpu: &mut CPU) { + if cpu.registers.get(cpu.op.x) == cpu.registers.get(cpu.op.y) { + cpu.pc.increment(); + } +} + +fn op_9xy0(cpu: &mut CPU) { + if cpu.registers.get(cpu.op.x) != cpu.registers.get(cpu.op.y) { + cpu.pc.increment(); + } +} + +fn op_6xnn(cpu: &mut CPU) { + cpu.registers.set(cpu.op.x, cpu.op.nn); +} + +fn op_7xnn(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + cpu.registers.set(cpu.op.x, cpu.op.nn.wrapping_add(vx)); +} + +fn op_8xy0(cpu: &mut CPU) { + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vy); +} + +fn op_8xy1(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vx | vy); +} + +fn op_8xy2(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vx & vy); +} + +fn op_8xy3(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vx ^ vy); +} + +fn op_8xy4(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vx.wrapping_add(vy)); +} + +fn op_8xy5(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vx.wrapping_sub(vy)); + cpu.registers.x_f = if vx > vy { 1 } else { 0 }; +} + +fn op_8xy6(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vy >> 1); + cpu.registers.x_f = vx & 0x1; +} + +fn op_8xy7(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vy.wrapping_sub(vx)); + cpu.registers.x_f = if vy > vx { 1 } else { 0 }; +} + +fn op_8xye(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + let vy = cpu.registers.get(cpu.op.y); + cpu.registers.set(cpu.op.x, vy << 1); + cpu.registers.x_f = (vx & 0x80) >> 7; +} + +fn op_annn(cpu: &mut CPU) { + cpu.i = cpu.op.nnn; +} + +fn op_bnnn(cpu: &mut CPU) { + cpu.pc.0 = cpu.op.nnn + cpu.registers.x_0 as usize; +} + +fn op_cxnn(cpu: &mut CPU) { + let mut rng = rand::thread_rng(); + cpu.registers + .set(cpu.op.x, rng.gen_range(0x0..0xFF) & cpu.op.nn); +} + +fn op_dxyn(cpu: &mut CPU) { + let mut vf: bool = false; + let value = cpu.op.n as usize; + let ori_x = cpu.registers.get(cpu.op.x) as usize % DISPLAY_WIDTH; + let ori_y = cpu.registers.get(cpu.op.y) as usize % DISPLAY_HEIGHT; + + for row in 0..value { + let y = ori_y + row; + if y >= DISPLAY_HEIGHT { + break; + } + + let sprite = cpu.ram.read8(cpu.i + row); + for pixel_position in 0..8 { + let x = ori_x + pixel_position; + if x >= DISPLAY_WIDTH { + break; + } + + let memory_pixel: bool = (sprite & (1 << (7 - pixel_position))) > 0; + let display_pixel: bool = cpu.db.db[x][y]; + cpu.db.db[x][y] = memory_pixel ^ display_pixel; + vf = (memory_pixel && display_pixel) || vf; + } + } + cpu.registers.x_f = if vf { 1 } else { 0 }; +} + +fn op_ex9e(cpu: &mut CPU) { + if cpu.keypad.get(cpu.registers.get(cpu.op.x) as usize) { + cpu.pc.increment(); + } +} + +fn op_exa1(cpu: &mut CPU) { + if !cpu.keypad.get(cpu.registers.get(cpu.op.x) as usize) { + cpu.pc.increment(); + } +} + +fn op_fx07(cpu: &mut CPU) { + cpu.registers.set(cpu.op.x, cpu.dt.tick); +} + +fn op_fx15(cpu: &mut CPU) { + cpu.dt.tick = cpu.registers.get(cpu.op.x); +} + +fn op_fx18(cpu: &mut CPU) { + cpu.st.tick = cpu.registers.get(cpu.op.x); +} + +fn op_fx1e(cpu: &mut CPU) { + cpu.i += cpu.registers.get(cpu.op.x) as usize; +} + +fn op_fx0a(cpu: &mut CPU) { + match cpu.keypad.being_pressed() { + Some(key) => { + cpu.registers.set(cpu.op.x, key); + } + _ => { + cpu.pc.decrement(); + } + } +} + +fn op_fx29(cpu: &mut CPU) { + let char = (cpu.registers.get(cpu.op.x) & 0xF) as usize; + cpu.i = cpu.ram.font_address + char * 5; +} + +fn op_fx33(cpu: &mut CPU) { + let vx = cpu.registers.get(cpu.op.x); + cpu.ram.write(cpu.i, vx / 100); + cpu.ram.write(cpu.i + 1, vx / 10 % 10); + cpu.ram.write(cpu.i + 2, vx % 10); +} + +fn op_fx55(cpu: &mut CPU) { + let i = cpu.i; + for regs in 0x0..(cpu.op.x + 1) { + cpu.ram.write(i + regs, cpu.registers.get(regs)); + } +} + +fn op_fx65(cpu: &mut CPU) { + let i = cpu.i; + for regs in 0x0..(cpu.op.x + 1) { + cpu.registers.set(regs, cpu.ram.read8(i + regs)); + } +} diff --git a/src/chip_8/cpu/display_buffer.rs b/src/chip_8/cpu/display_buffer.rs new file mode 100644 index 0000000..026cfb3 --- /dev/null +++ b/src/chip_8/cpu/display_buffer.rs @@ -0,0 +1,20 @@ +pub const DISPLAY_WIDTH: usize = 64; +pub const DISPLAY_HEIGHT: usize = 32; + +pub struct DisplayBuffer { + pub db: [[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH], + pub scale: u32, +} + +impl DisplayBuffer { + pub fn new(scale: u32) -> DisplayBuffer { + DisplayBuffer { + db: [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH], + scale: scale, + } + } + + pub fn clear(&mut self) { + self.db = [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH]; + } +} diff --git a/src/chip_8/cpu/keypad.rs b/src/chip_8/cpu/keypad.rs new file mode 100644 index 0000000..fb70353 --- /dev/null +++ b/src/chip_8/cpu/keypad.rs @@ -0,0 +1,64 @@ +use sdl2::keyboard::Keycode; +use std::collections::HashMap; + +pub struct Keypad { + pub key_status: [bool; 0x10], + pub keys: HashMap, +} + +impl Keypad { + pub fn new() -> Keypad { + Keypad { + key_status: [false; 0x10], + keys: [ + (Keycode::Num1, 0x1), + (Keycode::Num2, 0x2), + (Keycode::Num3, 0x3), + (Keycode::Num4, 0xC), + (Keycode::Q, 0x4), + (Keycode::W, 0x5), + (Keycode::E, 0x6), + (Keycode::R, 0xD), + (Keycode::A, 0x7), + (Keycode::S, 0x8), + (Keycode::D, 0x9), + (Keycode::F, 0xE), + (Keycode::Z, 0xA), + (Keycode::X, 0x0), + (Keycode::C, 0xB), + (Keycode::V, 0xF), + ] + .iter() + .cloned() + .collect(), + } + } + + pub fn compute_keycode(&self, keycode: Keycode) -> Option { + match self.keys.get(&keycode) { + Some(chip8_key) => Some(*chip8_key), + None => None, + } + } + + pub fn get(&mut self, pos: usize) -> bool { + self.key_status[pos] + } + + pub fn being_pressed(&self) -> Option { + for key in 0x0..0x10 { + if self.key_status[key] { + return Some(key as u8); + } + } + None + } + + pub fn press(&mut self, key: usize) { + self.key_status[key] = true; + } + + pub fn release(&mut self, key: usize) { + self.key_status[key] = false; + } +} diff --git a/src/chip_8/cpu/opcodes.rs b/src/chip_8/cpu/opcodes.rs new file mode 100644 index 0000000..cf221da --- /dev/null +++ b/src/chip_8/cpu/opcodes.rs @@ -0,0 +1,62 @@ +use std::collections::HashMap; + +pub struct OpCodes { + pub opcode: u16, + pub n1: u8, + pub n2: u8, + pub n3: u8, + pub n4: u8, + pub x: usize, + pub y: usize, + pub n: u8, + pub nn: u8, + pub nnn: usize, + pub str_to_hex_helper: HashMap>, // Helper +} + +impl OpCodes { + pub fn new(opcode: u16) -> OpCodes { + let n1 = (opcode & 0xF000) >> 12; + let n2 = (opcode & 0xF00) >> 8; + let n3 = (opcode & 0xF0) >> 4; + let n4 = opcode & 0xF; + let nn = opcode & 0xFF; + let nnn = opcode & 0xFFF; + + OpCodes { + opcode: opcode, + n1: n1 as u8, + n2: n2 as u8, + n3: n3 as u8, + n4: n4 as u8, + x: n2 as usize, + y: n3 as usize, + n: n4 as u8, + nn: nn as u8, + nnn: nnn as usize, + + str_to_hex_helper: [ + ('0', Some(0x0)), + ('1', Some(0x1)), + ('2', Some(0x2)), + ('3', Some(0x3)), + ('4', Some(0x4)), + ('5', Some(0x5)), + ('6', Some(0x6)), + ('7', Some(0x7)), + ('8', Some(0x8)), + ('9', Some(0x9)), + ('A', Some(0xA)), + ('B', Some(0xB)), + ('C', Some(0xC)), + ('D', Some(0xD)), + ('E', Some(0xE)), + ('F', Some(0xF)), + ('?', None), + ] + .iter() + .cloned() + .collect(), + } + } +} diff --git a/src/chip_8/cpu/program_counter.rs b/src/chip_8/cpu/program_counter.rs new file mode 100644 index 0000000..db19657 --- /dev/null +++ b/src/chip_8/cpu/program_counter.rs @@ -0,0 +1,15 @@ +pub struct ProgramCounter(pub usize); + +impl ProgramCounter { + pub fn new() -> ProgramCounter { + ProgramCounter { 0: 0x200 } + } + + pub fn increment(&mut self) { + self.0 += 2; + } + + pub fn decrement(&mut self) { + self.0 -= 2; + } +} diff --git a/src/chip_8/cpu/ram.rs b/src/chip_8/cpu/ram.rs new file mode 100644 index 0000000..53540b5 --- /dev/null +++ b/src/chip_8/cpu/ram.rs @@ -0,0 +1,79 @@ +pub struct RAM { + ram: [u8; 4 * 1024], + pub font_address: usize, + rom_address: usize, +} + +impl RAM { + pub fn new() -> RAM { + RAM { + ram: [0x00; 4 * 1024], + font_address: 0x50 as usize, + rom_address: 0x200 as usize, + } + } + + pub fn init_fonts(&mut self) { + let fonts: [u8; 80] = [ + 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 + 0x20, 0x60, 0x20, 0x20, 0x70, // 1 + 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 + 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 + 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 + 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 + 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 + 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 + 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 + 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 + 0xF0, 0x90, 0xF0, 0x90, 0x90, // A + 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B + 0xF0, 0x80, 0x80, 0x80, 0xF0, // C + 0xE0, 0x90, 0x90, 0x90, 0xE0, // D + 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E + 0xF0, 0x80, 0xF0, 0x80, 0x80, // F + ]; + for i in 0..fonts.len() { + self.ram[i + self.font_address] = fonts[i]; + } + } + + pub fn write_rom(&mut self, rom: &[u8]) { + assert!( + rom.len() <= self.ram.len() - 0x200, + "ROM is bigger than Chip-8 RAM" + ); + for i in 0..rom.len() { + self.ram[self.rom_address + i] = rom[i]; + } + } + + pub fn read8(&self, addr: usize) -> u8 { + assert!( + addr <= self.ram.len(), + "addr = {}, self.0.len() = {}", + addr, + self.ram.len() + ); + self.ram[addr] + } + + pub fn read16(&self, addr: usize) -> u16 { + assert!( + addr < self.ram.len(), + "addr = {}, self.0.len() = {}", + addr, + self.ram.len() + ); + (self.ram[addr] as u16) << 8 | self.ram[addr + 1] as u16 + } + + pub fn write(&mut self, addr: usize, value: u8) { + assert!( + addr < self.ram.len(), + "addr = {}, self.0.len() = {}", + addr, + self.ram.len() + ); + self.ram[addr] = value; + } +} diff --git a/src/chip_8/cpu/registers.rs b/src/chip_8/cpu/registers.rs new file mode 100644 index 0000000..b457eac --- /dev/null +++ b/src/chip_8/cpu/registers.rs @@ -0,0 +1,87 @@ +pub struct Registers { + pub x_0: u8, + x_1: u8, + x_2: u8, + x_3: u8, + x_4: u8, + x_5: u8, + x_6: u8, + x_7: u8, + x_8: u8, + x_9: u8, + x_a: u8, + x_b: u8, + x_c: u8, + x_d: u8, + x_e: u8, + pub x_f: u8, +} + +impl Registers { + pub fn new() -> Registers { + Registers { + x_0: 0, + x_1: 0, + x_2: 0, + x_3: 0, + x_4: 0, + x_5: 0, + x_6: 0, + x_7: 0, + x_8: 0, + x_9: 0, + x_a: 0, + x_b: 0, + x_c: 0, + x_d: 0, + x_e: 0, + x_f: 0, + } + } + + pub fn get(&self, register: usize) -> u8 { + assert!(register <= 0xF); + match register { + 0x0 => self.x_0, + 0x1 => self.x_1, + 0x2 => self.x_2, + 0x3 => self.x_3, + 0x4 => self.x_4, + 0x5 => self.x_5, + 0x6 => self.x_6, + 0x7 => self.x_7, + 0x8 => self.x_8, + 0x9 => self.x_9, + 0xA => self.x_a, + 0xB => self.x_b, + 0xC => self.x_c, + 0xD => self.x_d, + 0xE => self.x_e, + 0xF => self.x_f, + _ => 0, + } + } + + pub fn set(&mut self, register: usize, value: u8) { + assert!(register <= 0xF); + match register { + 0x0 => self.x_0 = value, + 0x1 => self.x_1 = value, + 0x2 => self.x_2 = value, + 0x3 => self.x_3 = value, + 0x4 => self.x_4 = value, + 0x5 => self.x_5 = value, + 0x6 => self.x_6 = value, + 0x7 => self.x_7 = value, + 0x8 => self.x_8 = value, + 0x9 => self.x_9 = value, + 0xA => self.x_a = value, + 0xB => self.x_b = value, + 0xC => self.x_c = value, + 0xD => self.x_d = value, + 0xE => self.x_e = value, + 0xF => self.x_f = value, + _ => {} + } + } +} diff --git a/src/chip_8/display.rs b/src/chip_8/display.rs index 0a17a60..1583be1 100644 --- a/src/chip_8/display.rs +++ b/src/chip_8/display.rs @@ -1,11 +1,15 @@ +use sdl2::render::Canvas; +use sdl2::pixels::Color; +use sdl2::rect::Rect; + const WIDTH: usize = 64; const HEIGHT: usize = 32; pub struct Display { - canvas: sdl2::render::Canvas, + canvas: Canvas, scale: u32, - off_color: sdl2::pixels::Color, - on_color: sdl2::pixels::Color, + off_color: Color, + on_color: Color, } impl Display { @@ -23,8 +27,8 @@ impl Display { Display { canvas: canvas, scale: scale, - off_color: sdl2::pixels::Color::RGB(125, 23, 123), - on_color: sdl2::pixels::Color::RGB(180, 180, 255), + off_color: Color::RGB(0, 0, 0), + on_color: Color::RGB(255, 255, 255), } } @@ -41,7 +45,7 @@ impl Display { let width = self.scale; let height = self.scale; self.canvas - .fill_rect(sdl2::rect::Rect::new(x, y, width, height)) + .fill_rect(Rect::new(x, y, width, height)) .expect("Failed to draw pixel"); } } diff --git a/src/chip_8/mod.rs b/src/chip_8/mod.rs deleted file mode 100644 index e92a311..0000000 --- a/src/chip_8/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod chip_8_base_interpreter; -pub mod display; -pub mod super_chip_interpreter; diff --git a/src/chip_8/super_chip_interpreter.rs b/src/chip_8/super_chip_interpreter.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/chip_8/super_chip_interpreter.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main.rs b/src/main.rs index de1e936..c97178a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ mod chip_8; fn main() { - chip_8::chip_8_base_interpreter::run(); + chip_8::chip_8::run(); }