diff --git a/Cargo.lock b/Cargo.lock index aa5453e..95095bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,7 @@ version = "0.1.0" dependencies = [ "clap 2.26.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -68,6 +69,11 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lazy_static" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.30" @@ -90,6 +96,38 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rand" version = "0.3.16" @@ -99,6 +137,27 @@ dependencies = [ "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sdl2" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sdl2-sys" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.6.0" @@ -152,10 +211,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" "checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" "checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" +"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" +"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" +"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" +"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" +"checksum sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63066036ad426250ac56d23e38fd05063b38b661556acd596f4046cc92d98415" +"checksum sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b48638b7882759f3421038fcd38ad5f1ea19b119d80c99f1601933004629e34d" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" "checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd" diff --git a/Cargo.toml b/Cargo.toml index 72acb66..170d854 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ categories = ["emulators", "games"] [dependencies] rand = "^0.3" -clap = "^2.26.1" \ No newline at end of file +clap = "^2.26.1" +sdl2 = "0.30.0" \ No newline at end of file diff --git a/src/emulator.rs b/src/emulator.rs index 5b0c740..ae349b5 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -1,6 +1,16 @@ use rand; +use sdl2; +use sdl2::EventPump; +use sdl2::rect::Rect; +use sdl2::rect::Point; +use sdl2::event::Event; +use std::time::Duration; +use sdl2::video::Window; +use sdl2::render::Canvas; +use sdl2::keyboard::Keycode; use rand::distributions::{IndependentSample, Range}; +use std::thread; use std::time::Instant; use std::collections::VecDeque; @@ -50,11 +60,11 @@ impl System { program_counter: 0x200, rng: rand::thread_rng(), - last_tick: Instant::now() + last_tick: Instant::now(), } } - pub fn run(&mut self) -> Result<(), ()> { + pub fn run_cli(&mut self) -> Result<(), ()> { println!("PC\tDELAY\tSOUND\tOP\tARG1\tARG2\tARG3"); println!("--\t-----\t-----\t--\t----\t----\t----"); loop { @@ -68,7 +78,7 @@ impl System { match Opcode::from(first_byte, second_byte) { Ok(opcode) => { println!("{:?}", opcode); - self.process_opcode(opcode)?; + self.process_opcode(opcode, None, None)?; } Err((first, second)) => { println!("DATA\t{:x}{:x}", first.0, second.0); @@ -80,7 +90,44 @@ impl System { } } - fn process_opcode(&mut self, opcode: Opcode) -> Result<(), ()> { + pub fn run_gui(&mut self) -> Result<(), ()> { + let sdl_context = sdl2::init().unwrap(); + let video_subsystem = sdl_context.video().unwrap(); + + let window = video_subsystem.window("Alvin", 640, 320) + .position_centered().build().unwrap(); + + let mut canvas = window.into_canvas().accelerated().build().unwrap(); + let mut event_pump = sdl_context.event_pump().unwrap(); + + let mut running = true; + while running { + for event in event_pump.poll_iter() { + match event { + Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { + running = false; + } + _ => {} + } + } + + let first_address = self.program_counter as usize; + let second_address = (self.program_counter + 1) as usize; + + let first_byte = self.memory[first_address]; + let second_byte = self.memory[second_address]; + + if let Ok(opcode) = Opcode::from(first_byte, second_byte) { + self.process_opcode(opcode, Some(&mut event_pump), Some(&mut canvas))?; + } + + self.tick(60); + } + + Err(()) + } + + fn process_opcode(&mut self, opcode: Opcode, event_pump: Option<&mut EventPump>, canvas: Option<&mut Canvas>) -> Result<(), ()> { match opcode { Opcode::Call(address) => { self.program_counter += WORD_SIZE; @@ -236,12 +283,42 @@ impl System { self.program_counter += WORD_SIZE; } Opcode::SkipKeyPress(register) => { - // TODO(Matt): Handle key events - unimplemented!(); + if let Some(event_pump) = event_pump { + match event_pump.poll_event() { + Some(Event::KeyDown { keycode, .. }) => { + if let Some(keycode) = keycode { + let expected = self.get_register(register) as i32; + + if expected == key_map(keycode) { + self.program_counter += 2 * WORD_SIZE; + return Ok(()); + } + } + } + _ => {} + } + } + + self.program_counter += WORD_SIZE; } Opcode::SkipNoKeyPress(register) => { - // TODO(Matt): Handle key events - unimplemented!(); + if let Some(event_pump) = event_pump { + match event_pump.poll_event() { + Some(Event::KeyDown { keycode, .. }) => { + if let Some(keycode) = keycode { + let expected = self.get_register(register) as i32; + + if expected != key_map(keycode) { + self.program_counter += 2 * WORD_SIZE; + return Ok(()); + } + } + } + _ => {} + } + } + + self.program_counter += WORD_SIZE; } Opcode::StoreDelayTimer(register) => { let delay = self.delay_timer; @@ -249,6 +326,17 @@ impl System { self.program_counter += WORD_SIZE; } Opcode::StoreKeypress(register) => { + if let Some(event_pump) = event_pump { + match event_pump.wait_event() { + Event::KeyDown { keycode, .. } => { + if let Some(keycode) = keycode { + self.set_register(register, key_map(keycode) as u8); + } + } + _ => {} + } + } + self.program_counter += WORD_SIZE; } Opcode::SetDelayTimer(register) => { @@ -333,6 +421,31 @@ impl System { } } +fn key_map(keycode: Keycode) -> i32 { + match keycode { + 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, + _ => -1 + } +} + fn load_fonts(memory: &mut [u8]) { let mut i = 0x0; for sprite in SPRITE_DATA.iter() { diff --git a/src/main.rs b/src/main.rs index d9c29fb..3988ee0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ extern crate clap; extern crate rand; +extern crate sdl2; mod opcode; mod emulator; @@ -41,7 +42,7 @@ fn main() { Some("disassemble") => disassemble(buffer), Some("run") => { let mut system = System::new(buffer); - system.run(); + system.run_gui(); } _ => { println!("ERROR: command invalid or not provided")