diff --git a/README.md b/README.md index 5c33c5f..d0bce75 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # chip8-rs CHIP-8 emulator written in Rust. -(Done from the Go implementation: https://github.com/arnaucube/go-chip8) +(Done with the Go implementation: https://github.com/arnaucube/go-chip8) https://en.wikipedia.org/wiki/CHIP-8 diff --git a/chip8/src/lib.rs b/chip8/src/lib.rs index 4a5553a..f2293d8 100644 --- a/chip8/src/lib.rs +++ b/chip8/src/lib.rs @@ -16,7 +16,7 @@ pub struct Chip8 { sound_timer: u8, stack: [u16; 16], sp: isize, - key: [u8; 16], + pub key: [u8; 16], pub draw_flag: bool, } @@ -71,12 +71,13 @@ impl Chip8 { } } pub fn emulate_cycle(&mut self) { - self.opcode = (self.memory[self.pc as usize] as u16) << 8 - | self.memory[(self.pc + 1) as usize] as u16; + self.opcode = ((self.memory[self.pc as usize] as u16) << 8) + | (self.memory[(self.pc + 1) as usize] as u16); let x: usize = ((self.opcode & 0x0F00) >> 8) as usize; let y: usize = ((self.opcode & 0x00F0) >> 4) as usize; let nn: u8 = (self.opcode & 0x00FF) as u8; let nnn: u16 = (self.opcode & 0x0FFF) as u16; + // println!("{:?} {:?}", self.opcode, self.pc); // Decode Opcode // https://en.wikipedia.org/wiki/CHIP-8#Opcode_table @@ -275,7 +276,7 @@ impl Chip8 { if self.gfx[pos] == 1 { self.v[0xF] = 1; } else { - self.v[0xF] ^= 1; + self.gfx[pos] ^= 1; } } } @@ -367,7 +368,7 @@ impl Chip8 { } self.pc += 2; } - 0x0064 => { + 0x0065 => { // 0xFX65 Fills V0 to VX (including VX) with values // from memory starting at address I. The offset from I // is increased by 1 for each value written, but I @@ -382,6 +383,15 @@ impl Chip8 { } _ => println!("opc {:x}", self.opcode), } + if self.delay_timer > 0 { + self.delay_timer -= 1; + } + if self.sound_timer > 0 { + if self.sound_timer == 1 { + println!("Beep"); + } + self.sound_timer -= 1; + } } } diff --git a/roms/TETRIS b/roms/TETRIS new file mode 100644 index 0000000..9f5e087 Binary files /dev/null and b/roms/TETRIS differ diff --git a/roms/chip8-picture.ch8 b/roms/chip8-picture.ch8 new file mode 100644 index 0000000..74ab4bf Binary files /dev/null and b/roms/chip8-picture.ch8 differ diff --git a/roms/invaders.c8 b/roms/invaders.c8 new file mode 100755 index 0000000..3ada8df Binary files /dev/null and b/roms/invaders.c8 differ diff --git a/roms/pong.c8 b/roms/pong.c8 new file mode 100755 index 0000000..6af8d1e Binary files /dev/null and b/roms/pong.c8 differ diff --git a/roms/slipperyslope.ch8 b/roms/slipperyslope.ch8 new file mode 100644 index 0000000..d4f20f5 Binary files /dev/null and b/roms/slipperyslope.ch8 differ diff --git a/src/main.rs b/src/main.rs index db27990..10c71ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,11 @@ +use std::collections::HashMap; +use std::{thread, time}; extern crate sdl2; +use sdl2::event::Event; +use sdl2::keyboard::Keycode; use sdl2::pixels::Color; +use sdl2::rect::Rect; use sdl2::render::Canvas; use clap::{App, Arg}; @@ -11,7 +16,9 @@ struct SdlEmulator { w: usize, h: usize, zoom: usize, + sdl_context: sdl2::Sdl, canvas: Canvas, + vkeys: HashMap, chip8: Chip8, } @@ -23,26 +30,97 @@ impl SdlEmulator { let video_subsystem = sdl_context.video().unwrap(); let window = video_subsystem - .window("rust-sdl2 demo", 800, 600) + .window("rust-sdl2 demo", (w * zoom) as u32, (h * zoom) as u32) .position_centered() .build() .unwrap(); let mut canvas = window.into_canvas().build().unwrap(); + let mut vkeys: HashMap = HashMap::new(); + vkeys.insert(Keycode::Num1, 0x01); + vkeys.insert(Keycode::Num2, 0x02); + vkeys.insert(Keycode::Num3, 0x03); + vkeys.insert(Keycode::Num4, 0x0c); + vkeys.insert(Keycode::Q, 0x04); + vkeys.insert(Keycode::W, 0x05); + vkeys.insert(Keycode::E, 0x06); + vkeys.insert(Keycode::R, 0x07); + vkeys.insert(Keycode::A, 0x08); + vkeys.insert(Keycode::S, 0x09); + vkeys.insert(Keycode::D, 0x0E); + vkeys.insert(Keycode::F, 0x0A); + vkeys.insert(Keycode::Z, 0x00); + vkeys.insert(Keycode::X, 0x0B); + vkeys.insert(Keycode::V, 0x0F); + SdlEmulator { w, h, zoom, + sdl_context, canvas, + vkeys, chip8: c, } } fn draw_graphics(&mut self) { - // TODO + self.canvas.set_draw_color(Color::RGB(0, 0, 0)); + self.canvas.clear(); + self.canvas.set_draw_color(Color::RGB(255, 255, 255)); + for y in 0..self.h { + for x in 0..self.w { + let pixel = self.chip8.gfx[y * self.w + x]; + if pixel != 0 { + self.canvas.fill_rect(Rect::new( + (x * self.zoom) as i32, + (y * self.zoom) as i32, + (self.zoom) as u32, + (self.zoom) as u32, + )); + } + } + } + + self.canvas.present(); + self.chip8.draw_flag = false; } - fn set_keys(&mut self) { - // TODO + fn set_keys(&mut self) -> Result<(), String> { + let mut events = self.sdl_context.event_pump()?; + for event in events.poll_iter() { + match event { + Event::Quit { .. } => { + println!("Quit"); + std::process::exit(0); + } + Event::KeyDown { + keycode: Some(keycode), + .. + } => { + println!("k {:?}", keycode); + if self.vkeys.contains_key(&keycode) { + let k_hex = self.vkeys.get(&keycode).unwrap(); + self.chip8.key[*k_hex as usize] = 1; + } + } + Event::KeyUp { + keycode: Some(keycode), + .. + } => { + println!("k {:?}", keycode); + if self.vkeys.contains_key(&keycode) { + let k_hex = self.vkeys.get(&keycode).unwrap(); + self.chip8.key[*k_hex as usize] = 0; + } + if keycode == Keycode::Escape { + println!("EXIT"); + std::process::exit(0); + } + } + _ => {} + } + } + Ok(()) } } @@ -66,12 +144,14 @@ fn main() { println!("{:?}", file); let mut e = SdlEmulator::new(64, 32, 8); + e.chip8.load_game(file); + loop { e.chip8.emulate_cycle(); if e.chip8.draw_flag { e.draw_graphics(); } e.set_keys(); - // delay + std::thread::sleep(time::Duration::from_millis(1000 / 60)); } }