diff --git a/Cargo.lock b/Cargo.lock index 4815b5d..c6b11fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,6 +121,21 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.86" @@ -233,6 +248,16 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "beep" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add99ab8e6fa29e525696f04be01c6e18815f5d799e026a06c8b09af8301bd5a" +dependencies = [ + "lazy_static", + "nix 0.20.2", +] + [[package]] name = "bit_field" version = "0.10.2" @@ -241,9 +266,9 @@ checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" -version = "1.3.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitflags" @@ -339,7 +364,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "log", "nix 0.25.1", "slotmap", @@ -473,6 +498,20 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e10e7569f6ca78ef7664d7d651115172d4875c4410c050306bccde856a99a49" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] + [[package]] name = "clipboard-win" version = "3.1.1" @@ -507,7 +546,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "block", "cocoa-foundation", "core-foundation", @@ -523,7 +562,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "block", "cocoa-foundation", "core-foundation", @@ -539,7 +578,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "block", "core-foundation", "core-graphics-types", @@ -636,7 +675,7 @@ version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "core-foundation", "core-graphics-types", "foreign-types 0.3.2", @@ -649,7 +688,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "core-foundation", "core-graphics-types", "foreign-types 0.5.0", @@ -662,7 +701,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "core-foundation", "libc", ] @@ -824,6 +863,17 @@ dependencies = [ "byteorder", ] +[[package]] +name = "dimensioned" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b0a86c5d31c93238ff4b694fa31f3acdf67440770dc314c57d90e433914397" +dependencies = [ + "generic-array", + "num-traits", + "typenum", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -878,7 +928,10 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" name = "emmaemu" version = "0.1.0" dependencies = [ + "beep", + "chrono", "copypasta 0.8.2", + "dimensioned", "glium", "image 0.23.14", "imgui", @@ -1034,7 +1087,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "freetype-sys", "libc", ] @@ -1050,6 +1103,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "gethostname" version = "0.2.3" @@ -1312,6 +1375,29 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icrate" version = "0.0.4" @@ -1393,7 +1479,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8addafa5cecf0515812226e806913814e02ce38d10215778082af5174abe5669" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "cfg-if", "imgui-sys", "mint", @@ -1799,7 +1885,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "jni-sys", "ndk-sys 0.4.1+23.1.7779620", "num_enum 0.5.11", @@ -1906,13 +1992,26 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945" +dependencies = [ + "bitflags 1.2.1", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + [[package]] name = "nix" version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "cfg-if", "libc", "memoffset 0.6.5", @@ -1925,7 +2024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ "autocfg", - "bitflags 1.3.2", + "bitflags 1.2.1", "cfg-if", "libc", "memoffset 0.6.5", @@ -2415,7 +2514,7 @@ version = "0.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "crc32fast", "deflate", "miniz_oxide 0.3.7", @@ -2427,7 +2526,7 @@ version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "crc32fast", "fdeflate", "flate2", @@ -2727,7 +2826,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", ] [[package]] @@ -2736,7 +2835,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", ] [[package]] @@ -3016,7 +3115,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "calloop 0.10.6", "dlib", "lazy_static", @@ -3410,6 +3509,12 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8686b91785aff82828ed725225925b33b4fde44c4bb15876e5f7c832724c420a" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -3570,7 +3675,7 @@ version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "downcast-rs", "libc", "nix 0.24.3", @@ -3643,7 +3748,7 @@ version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "wayland-client 0.29.5", "wayland-commons", "wayland-scanner 0.29.5", @@ -3846,6 +3951,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.36.1" @@ -4100,7 +4214,7 @@ version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb796d6fbd86b2fd896c9471e6f04d39d750076ebe5680a3958f00f5ab97657c" dependencies = [ - "bitflags 1.3.2", + "bitflags 1.2.1", "cocoa 0.24.1", "core-foundation", "core-graphics 0.22.3", diff --git a/emma/Cargo.toml b/emma/Cargo.toml index 5a7f6f9..260314c 100644 --- a/emma/Cargo.toml +++ b/emma/Cargo.toml @@ -16,3 +16,6 @@ pretty_env_logger = "0.5.0" copypasta = "0.8" rand = "0.9.0-alpha.2" log = "0.4.22" +beep = "0.3.0" +chrono = "0.4.38" +dimensioned = "0.8.0" diff --git a/emma/src/bin/emmagui.rs b/emma/src/bin/emmagui.rs index e242e6b..a7b15ab 100644 --- a/emma/src/bin/emmagui.rs +++ b/emma/src/bin/emmagui.rs @@ -35,18 +35,37 @@ fn hello_world_window(ui: &Ui) { }); } +struct UiState { + pub show_registers: bool, + pub show_memory: bool, + pub show_video: bool +} + +impl Default for UiState { + fn default() -> Self { + UiState { + show_registers: true, + show_memory: true, + show_video: true + } + } +} + fn main() { pretty_env_logger::init(); let mut system = Chip8Computer::default(); - + let mut ui_state = UiState::default(); support::simple_init(file!(), move |_, ui| { // hello_world_window(ui); EmmaGui::system_controls(&mut system, ui); + EmmaGui::registers_view(&system, ui); - EmmaGui::hex_memory_display(system.memory.clone(), 0x100, 0x10,ui); + let active_instruction = system.pc; + EmmaGui::hex_memory_display(system.memory.clone(), (0x100, 0x10), active_instruction as i16, ui); + EmmaGui::video_display(&system, ui); // EmmaGui::system_memory_render(system.memory, ui); diff --git a/emma/src/bin/support/clipboard.rs b/emma/src/bin/support/clipboard.rs index dd74d06..e69de29 100644 --- a/emma/src/bin/support/clipboard.rs +++ b/emma/src/bin/support/clipboard.rs @@ -1,18 +0,0 @@ -use copypasta::{ClipboardContext, ClipboardProvider}; -use imgui::ClipboardBackend; - -pub struct ClipboardSupport(pub ClipboardContext); - -pub fn init() -> Option { - ClipboardContext::new().ok().map(ClipboardSupport) -} - -impl ClipboardBackend for ClipboardSupport { - fn get(&mut self) -> Option { - self.0.get_contents().ok() - } - fn set(&mut self, text: &str) { - // ignore errors? - let _ = self.0.set_contents(text.to_owned()); - } -} diff --git a/emma/src/bin/support/emmagui_support.rs b/emma/src/bin/support/emmagui_support.rs index e9bc96a..6781c5b 100644 --- a/emma/src/bin/support/emmagui_support.rs +++ b/emma/src/bin/support/emmagui_support.rs @@ -8,12 +8,38 @@ use emmaemu::chip8::computer::Chip8Computer; use emmaemu::chip8::system_memory::Chip8SystemMemory; use emmaemu::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH}; + pub struct EmmaGui {} const CELL_WIDTH: i32 = 5i32; const CELL_HEIGHT: i32 = 5i32; impl EmmaGui { + pub fn video_display(system_to_control: &Chip8Computer, ui: &Ui) { + ui.window("Display") + .size([300.0, 300.0], Condition::FirstUseEver) + .build(|| { + let origin = ui.cursor_screen_pos(); + let fg = ui.get_window_draw_list(); + ui.text("This is the video display."); + for current_row in 0..31 { + for current_column in 0..64 { + let x_offset = origin[0] as i32 + (current_column * 5); + let y_offset = origin[1] as i32 + (current_row * 5); + let current_origin = [x_offset as f32, y_offset as f32]; + let current_limit = [(x_offset + 5) as f32, (y_offset + 5) as f32]; + let memory_offset = (current_row * 64 + current_column) as u16; + let to_render = system_to_control.video_memory.peek(memory_offset); + let color: ImColor32 = if to_render { + ImColor32::from_rgb(0xff, 0x00, 0x00) + } else { + ImColor32::from_rgb(0x00, 0x00, 0xff) + }; + fg.add_rect_filled_multicolor(current_origin, current_limit, color, color, color, color); + } + } + }); + } pub fn system_controls(system_to_control: &mut Chip8Computer, ui: &Ui) { ui.window("!!!! CONTROLS !!!!") .size([200.0, 200.0], Condition::FirstUseEver) @@ -31,6 +57,9 @@ impl EmmaGui { input_file.read_to_end(&mut buffer).expect("unable to read file"); system_to_control.load_bytes_to_memory(0x200, buffer.into()); } + if ui.button("Reset") { + *system_to_control = Chip8Computer::new(); + } }); } @@ -38,24 +67,27 @@ impl EmmaGui { ui.window("Registers") .size([400.0, 500.0], Condition::FirstUseEver) .build(|| { - ui.text("Registers"); - for i in 0..0x10 { - ui.text(format!("V{:X}: {}", i, system.registers[i as usize])); - if i != 7 { + ui.text("Registers"); + for i in 0..0x10 { + ui.text(format!("V{:X}: {}", i, system.registers[i as usize])); + if i != 7 { + ui.same_line(); + } + } + ui.text(""); + ui.text(format!("I: {:03X}", system.i_register)); ui.same_line(); - } - } - ui.text(""); - ui.text(format!("I: {:03X}", system.i_register)); - ui.same_line(); - ui.text(format!("ST: {:02X}", system.sound_timer)); - ui.same_line(); - ui.text(format!("DT: {:02X}", system.delay_timer)); - ui.text(format!("PC: {:02X}", system.pc)); - ui.text(format!("SP: {:02X}", system.sp));}); + ui.text(format!("ST: {:02X}", system.sound_timer.current())); + ui.same_line(); + ui.text(format!("DT: {:02X}", system.delay_timer.current())); + ui.text(format!("PC: {:02X}", system.pc)); + ui.text(format!("SP: {:02X}", system.sp)); + }); } - pub fn hex_memory_display(bytes: Chip8SystemMemory, rows: i32, cols: i32, ui: &Ui) { + pub fn hex_memory_display(bytes: Chip8SystemMemory, position: (i32, i32), active: i16, ui: &Ui) { + let rows = position.0; + let cols = position.1; ui.window("System Memory") .size([400.0, 300.0], Condition::FirstUseEver) .build(|| { @@ -75,9 +107,21 @@ impl EmmaGui { y: text_location[1] + text_size[1], }; - if ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]) { + let hovering = ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]); + let is_active = data_offset == active as i32; + + ui.text_colored(if hovering { + [0., 1., 1., 1.] + } else if is_active { + [1., 0., 1., 1.] + } else { + [1., 1., 0., 1.] + }, formatted_text.clone()); + + + // if we are hovering show that at the bottom... + if hovering { // Optionally change the text color to indicate it's interactable - ui.text_colored([1.0, 0.0, 0.0, 1.0], formatted_text.clone()); current_x_hover = current_column; current_y_hover = current_row; @@ -86,10 +130,9 @@ impl EmmaGui { println!("Offset: [{}] [0x{:02x}] Value: [{}]", data_offset, data_offset, formatted_text.clone()); // Perform any action here, e.g., call a function, trigger an event, etc. } - } else { - // Default color text when not hovering - ui.text(formatted_text); } + + // are we on the same line? if current_column != (cols - 1) { ui.same_line(); } diff --git a/emma/src/bin/support/mod.rs b/emma/src/bin/support/mod.rs index 2819e41..a0be20e 100644 --- a/emma/src/bin/support/mod.rs +++ b/emma/src/bin/support/mod.rs @@ -10,8 +10,25 @@ use imgui_winit_support::{HiDpiMode, WinitPlatform}; use std::path::Path; use std::time::Instant; -pub mod clipboard; pub mod emmagui_support; +use copypasta::{ClipboardContext, ClipboardProvider}; +use imgui::ClipboardBackend; + +pub struct ClipboardSupport(pub ClipboardContext); + +pub fn clipboard_init() -> Option { + ClipboardContext::new().ok().map(ClipboardSupport) +} + +impl ClipboardBackend for ClipboardSupport { + fn get(&mut self) -> Option { + self.0.get_contents().ok() + } + fn set(&mut self, text: &str) { + // ignore errors? + let _ = self.0.set_contents(text.to_owned()); + } +} pub const FONT_SIZE: f32 = 13.0; @@ -42,7 +59,7 @@ where .build(&event_loop); let mut renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer"); - if let Some(backend) = clipboard::init() { + if let Some(backend) = clipboard_init() { imgui.set_clipboard_backend(backend); } else { eprintln!("Failed to initialize clipboard"); diff --git a/emma/src/chip8/computer.rs b/emma/src/chip8/computer.rs index d5f024e..08c9a56 100644 --- a/emma/src/chip8/computer.rs +++ b/emma/src/chip8/computer.rs @@ -1,5 +1,7 @@ use log::{debug, error}; +use crate::chip8::delay_timer::DelayTimer; use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION; +use crate::chip8::sound_timer::SoundTimer; use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT}; use super::{ @@ -13,8 +15,8 @@ pub struct Chip8Computer { pub sp: u8, pub memory: Chip8SystemMemory, pub registers: [u8; 16], - pub sound_timer: u8, - pub delay_timer: u8, + pub sound_timer: SoundTimer, + pub delay_timer: DelayTimer, pub i_register: u16, pub video_memory: Chip8Video, pub state: Chip8CpuStates, @@ -28,8 +30,8 @@ impl Default for Chip8Computer { memory: Chip8SystemMemory::default(), video_memory: Chip8Video::default(), registers: [0; CHIP8_REGISTER_COUNT as usize], - sound_timer: 0xFF, - delay_timer: 0xFF, + sound_timer: SoundTimer::new(), + delay_timer: DelayTimer::new(), i_register: 0x0000, state: Chip8CpuStates::WaitingForInstruction, } @@ -50,7 +52,7 @@ impl Chip8Computer { } } - pub fn step_system(&mut self) -> Self { + pub fn step_system(&mut self) -> &mut Chip8Computer { // read the next instruction let mut working_instruction: u16 = 0b0000000000000000; @@ -61,7 +63,9 @@ impl Chip8Computer { let decoded_instruction = Chip8Computer::decode_instruction(working_instruction); - println!("DECODED INSTRUCTION = {:?}", decoded_instruction); + // println!("DECODED INSTRUCTION = {:?}", decoded_instruction); + // start by moving to the next instruction + self.pc += 2; match (self.state, decoded_instruction) { (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SysAddr(target_address)) => { @@ -70,150 +74,136 @@ impl Chip8Computer { } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CLS) => { debug!("INST: CLS"); - self.pc += 0x2; + for i in 0..(64 * 32) { + self.video_memory.poke(i, false); + } } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RET) => { - debug!("INST: RET"); + debug!("INST* RET"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpAddr(new_address)) => { - debug!("INST: JP_ADDR: {new_address}"); + debug!("INST: JP_ADDR: {new_address:4x}"); self.pc = new_address as u16; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CallAddr(sub_address)) => { - debug!("INST: CALL_ADDR: {sub_address}"); - self.pc += 0x2; + debug!("INST* CALL_ADDR: {sub_address:4x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxByte(vx_register, byte)) => { - debug!("INST: SeVxByte: {vx_register}/{byte}"); - self.pc += 0x2; + debug!("INST: SeVxByte: 0x{vx_register:1x}/0x{byte:2x}"); + self.registers[vx_register as usize] = byte as u8; + } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxByte(vx_register, byte)) => { - debug!("INST: SneVxByte: {vx_register}/{byte}"); - self.pc += 0x2; + debug!("INST: SneVxByte: 0x{vx_register:1x}/0x{byte:2x}"); + if self.registers[vx_register as usize] == byte as u8 { + self.pc += 2; + } } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxVy(vx_register, vy_register)) => { - debug!("INST: SeVxVy: {vx_register}/{vy_register}"); - self.pc += 0x2; + debug!("INST* SeVxVy: 0x{vx_register:1x}/0x{vy_register:1x}"); + if self.registers[vx_register as usize] == self.registers[vy_register as usize] { + self.pc += 2; + }; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxByte(vx_register, byte)) => { - debug!("INST: LdVxByte: {vx_register}/{byte}"); - self.pc += 0x2; + debug!("INST* LdVxByte: 0x{vx_register:1x}/0x{byte:2x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxByte(vx_register, byte)) => { - debug!("INST: AddVxByte: {vx_register}/{byte}"); - self.pc += 0x2; + debug!("INST: AddVxByte: 0x{vx_register:1x}/0x{byte:2x}"); + self.registers[vx_register as usize] += byte as u8; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxVy(vx_register, vy_register)) => { - debug!("INST: LdVxVy: {vx_register}/{vy_register}"); + debug!("INST: LdVxVy: 0x{vx_register:1x}/0x{vy_register:1x}"); self.registers[vx_register as usize] = self.registers[vy_register as usize]; - self.pc += 0x2; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::OrVxVy(vx_register, vy_register)) => { - debug!("INST: OrVxVy: {vx_register}/{vy_register}"); + debug!("INST: OrVxVy: {vx_register}/{vy_register:1x}"); self.registers[vx_register as usize] = self.registers[vx_register as usize] | self.registers[vy_register as usize]; - self.pc += 0x2; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AndVxVy(vx_register, vy_register)) => { - debug!("INST: AndVxVy: {vx_register}/{vy_register}"); + debug!("INST: AndVxVy: {vx_register:1x}/{vy_register:1x}"); self.registers[vx_register as usize] = self.registers[vx_register as usize] & self.registers[vy_register as usize]; - self.pc += 0x2; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::XorVxVy(vx_register, vy_register)) => { - debug!("INST: XorVxVy: {vx_register}/{vy_register}"); + debug!("INST: XorVxVy: {vx_register:1x}/{vy_register:1x}"); self.registers[vx_register as usize] = self.registers[vx_register as usize] ^ self.registers[vy_register as usize]; - self.pc += 0x2; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxVy(vx_register, vy_register)) => { - debug!("INST: AddVxVy: {vx_register}/{vy_register}"); - self.pc += 0x2; + debug!("INST: AddVxVy: {vx_register:1x}/{vy_register:1x}"); + self.registers[vx_register as usize] += self.registers[vy_register as usize]; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubVxVy(vx_register, vy_register)) => { - debug!("INST: SubVxVy: {vx_register}/{vy_register}"); - self.pc += 0x2; + debug!("INST: SubVxVy: {vx_register:1x}/{vy_register:1x}"); + self.registers[vx_register as usize] -= self.registers[vy_register as usize]; } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShrVxVy(vx_register, vy_register)) => { - debug!("INST: ShrVxVy: {vx_register}/{vy_register}"); - self.pc += 0x2; + debug!("INST* ShrVxVy: {vx_register:1x}/{vy_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubnVxVy(vx_register, vy_register)) => { - debug!("INST: SubnVxVy: {vx_register}/{vy_register}"); - self.pc += 0x2; + debug!("INST* SubnVxVy: {vx_register:1x}/{vy_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShlVxVy(vx_register, vy_register)) => { - debug!("INST: ShlVxVy: {vx_register}/{vy_register}"); - self.pc += 0x2; + debug!("INST* ShlVxVy: {vx_register:1x}/{vy_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxVy(vx_register, vy_register)) => { - debug!("INST: SneVxVy: {vx_register}/{vy_register}"); - self.pc += 0x2; + debug!("INST: SneVxVy: {vx_register:1x}/{vy_register:1x}"); + if self.registers[vx_register as usize] != self.registers[vy_register as usize] { + self.pc += 02; + } } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIAddr(addr)) => { - debug!("INST: LdIAddr: {addr}"); - self.pc += 0x2; + debug!("INST* LdIAddr: [0x{addr:4x}]"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpV0Addr(addr)) => { - debug!("INST: JpV0Addr: {addr}"); - self.pc += 0x2; + debug!("INST* JpV0Addr: 0x{addr:4x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RndVxByte(vx_register, byte)) => { - debug!("INST: RndVxByte: {vx_register}/{byte}"); - self.pc += 0x2; + debug!("INST* RndVxByte: 0x{vx_register:1x}/0x{byte:2x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::DrawVxVyNibble(vx_register, vy_register, nibble)) => { - debug!("INST: DrawVxVyNibble: {vx_register}/{vy_register}/{nibble}"); - self.pc += 0x2; + debug!("INST* DrawVxVyNibble: 0x{vx_register:1x}/0x{vy_register:1x}/0x{nibble:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SkpVx(vx_register)) => { - debug!("INST: SkpVx: {vx_register}"); - self.pc += 0x2; + debug!("INST* SkpVx: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SnkpVx(vx_register)) => { - debug!("INST: SnkpVx: {vx_register}"); - self.pc += 0x2; + debug!("INST* SnkpVx: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxDt(vx_register)) => { - debug!("INST: LdVxDt: {vx_register}"); - self.pc += 0x2; + debug!("INST* LdVxDt: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxK(vx_register)) => { - debug!("INST: LdVxK: {vx_register}"); - self.pc += 0x2; + debug!("INST* LdVxK: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdDtVx(vx_register)) => { - debug!("INST: LdDtVx: {vx_register}"); - self.pc += 0x2; + debug!("INST* LdDtVx: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdStVx(vx_register)) => { - debug!("INST: SkpVx: {vx_register}"); - self.pc += 0x2; + debug!("INST* SkpVx: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddIVx(vx_register)) => { - debug!("INST: AddIVx: {vx_register}"); - self.pc += 0x2; + debug!("INST* AddIVx: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdFVx(_)) => { - debug!("INST: LdFVu:"); - self.pc += 0x2; + debug!("INST* LdFVu:"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdBVx(vx_register)) => { - debug!("INST: LdBVx: {vx_register}"); - self.pc += 0x2; + debug!("INST* LdBVx: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIVx(vx_register)) => { - debug!("INST: LdIVx: {vx_register}"); - self.pc += 0x2; + debug!("INST* LdIVx: 0x{vx_register:1x}"); } (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxI(vx_register)) => { - debug!("INST: LdVxI: {vx_register}"); - self.pc += 0x2; + debug!("INST* LdVxI: 0x{vx_register:1x}"); } _ => { error!("UNABLE TO PROCEED. CPU IN UNKNOWN STATE"); } } - - self.clone() + self.sound_timer.tick(); + self.delay_timer.tick(); + self } // nnn or addr - A 12-bit value, the lowest 12 bits of the instruction @@ -369,7 +359,7 @@ impl Chip8Computer { // RND Vx, byte Chip8CpuInstructions::RndVxByte(x_param, byte_param) } - 0xD000..0xDFFF => { + 0xD000..=0xDFFF => { // DRAW Vx, Vy, nibble Chip8CpuInstructions::DrawVxVyNibble(x_param, y_param, nibble_param) @@ -387,7 +377,7 @@ impl Chip8Computer { } } } - 0xF007..0xFF65 => { + 0xF007..=0xFF65 => { println!("COMPARING LAST BYTE FROM TODECODE: {:2x} to {:4x} with {:2x}", last_byte, to_decode, ubln); match last_byte { 0x07 => { @@ -430,6 +420,8 @@ impl Chip8Computer { #[cfg(test)] mod test { + use rand::random; + use crate::constants::CHIP8_VIDEO_MEMORY; use super::*; #[test] @@ -486,5 +478,23 @@ mod test { // assert!(matches!(Chip8Computer::decode_instruction(0x8ab8), Chip8CpuInstructions::XXXXERRORINSTRUCTION)); // assert!(matches!(Chip8Computer::decode_instruction(0xeaba), Chip8CpuInstructions::XXXXERRORINSTRUCTION)); } + + #[test] + fn cls_test() { + let mut start_system = Chip8Computer::new(); + let mut targets = Vec::new(); + for i in 0..10 { + let new_address: i16 = random(); + let new_address = new_address % CHIP8_MEMORY_SIZE as i16; + start_system.video_memory.poke(new_address as u16, true); + targets.push(new_address); + } + start_system.memory.poke(0x200, 0x00); + start_system.memory.poke(0x201, 0xe0); + start_system.step_system(); + for i in 0..CHIP8_MEMORY_SIZE { + assert!(!start_system.video_memory.peek(i as u16)); + } + } } diff --git a/emma/src/chip8/delay_timer.rs b/emma/src/chip8/delay_timer.rs index e69de29..3f81824 100644 --- a/emma/src/chip8/delay_timer.rs +++ b/emma/src/chip8/delay_timer.rs @@ -0,0 +1,25 @@ +#[derive(Clone, Copy)] +pub struct DelayTimer { + counter: i32 +} + +impl DelayTimer { + pub fn current(&self) -> i32 { + self.counter + } + + pub fn new() -> Self { + DelayTimer { + counter: 0xff + } + } + pub fn set_timer(&mut self, new_value: i32) { + self.counter = new_value + } + + pub fn tick(&mut self) { + if self.counter > 0 { + self.counter -= 1; + } + } +} \ No newline at end of file diff --git a/emma/src/chip8/sound_timer.rs b/emma/src/chip8/sound_timer.rs index e69de29..376f8d6 100644 --- a/emma/src/chip8/sound_timer.rs +++ b/emma/src/chip8/sound_timer.rs @@ -0,0 +1,33 @@ +use std::{thread, time}; +use beep::beep; +use dimensioned::si; + +#[derive(Clone, Copy)] +pub struct SoundTimer { + counter: i32 +} + +impl SoundTimer { + pub fn current(&self) -> i32 { + self.counter + } + + pub fn new() -> Self { + SoundTimer { + counter: 0 + } + } + pub fn set_timer(&mut self, new_value: i32) { + self.counter = new_value + } + + pub fn tick(&mut self) { + if self.counter > 0 { + self.counter -= 1; + thread::spawn(|| { + beep(440).expect("Unable to beep"); + thread::sleep(time::Duration::from_millis(500)); + }).join().expect("Unable to spawn beep thread"); + } + } +}