diff --git a/Cargo.lock b/Cargo.lock index 803df16..f64f60c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -885,6 +885,7 @@ dependencies = [ "imgui-glium-renderer", "imgui-winit-support", "pretty_env_logger", + "rand 0.9.0-alpha.2", "ratatui", "winit 0.27.5", ] @@ -2554,8 +2555,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e256ff62cee3e03def855c4d4260106d2bb1696fdc01af03e9935b993720a5" +dependencies = [ + "rand_chacha 0.9.0-alpha.2", + "rand_core 0.9.0-alpha.2", + "zerocopy", ] [[package]] @@ -2565,7 +2577,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d299e9db34f6623b2a9e86c015d6e173d5f46d64d4b9b8cc46ae8a982a50b04c" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0-alpha.2", ] [[package]] @@ -2577,6 +2599,16 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_core" +version = "0.9.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e93f5a5e3c528cda9acb0928c31b2ba868c551cc46e67b778075e34aab9906" +dependencies = [ + "getrandom", + "zerocopy", +] + [[package]] name = "ratatui" version = "0.28.0" @@ -2624,8 +2656,8 @@ dependencies = [ "once_cell", "paste", "profiling", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "simd_helpers", "system-deps", "thiserror", diff --git a/emma/Cargo.toml b/emma/Cargo.toml index b747c4b..8c7be6b 100644 --- a/emma/Cargo.toml +++ b/emma/Cargo.toml @@ -14,3 +14,4 @@ imgui-winit-support = { version = "0.12.0" } winit = { version = "0.27", features = ["x11", "mint"] } pretty_env_logger = "0.5.0" copypasta = "0.8" +rand = "0.9.0-alpha.2" diff --git a/emma/src/bin/emmagui.rs b/emma/src/bin/emmagui.rs index fb56566..eab2db5 100644 --- a/emma/src/bin/emmagui.rs +++ b/emma/src/bin/emmagui.rs @@ -5,9 +5,12 @@ use emmaemu::{ use imgui::*; use ratatui::symbols::half_block; use sys::{ImColor, ImVec2, ImVector_ImU32}; +use rand::random; +use emmaemu::chip8::system_memory::Chip8SystemMemory; use support::emmagui_support::EmmaGui; mod support; + fn hello_world_window(ui: &Ui) { let mut value = 1; @@ -34,21 +37,20 @@ fn hello_world_window(ui: &Ui) { fn main() { - let system = Chip8Computer::default(); + let mut system = Chip8Computer::default(); + support::simple_init(file!(), move |_, ui| { - hello_world_window(ui); + // hello_world_window(ui); - let mut to_display = Box::new(Vec::new()); - for i in 0..0xFF { - to_display.push(i); - } - EmmaGui::hex_memory_display(to_display, 0x7F, 0x80,ui); + EmmaGui::system_controls(&mut system, ui); + EmmaGui::registers_view(&system, ui); + EmmaGui::hex_memory_display(system.memory.clone(), 0x100, 0x10,ui); - EmmaGui::system_memory_render(system.memory, ui); + // EmmaGui::system_memory_render(system.memory, ui); - system.memory.gui_render(ui); + // system.memory.gui_render(ui); }); } diff --git a/emma/src/bin/support/emmagui_support.rs b/emma/src/bin/support/emmagui_support.rs index a268f6f..5d4fc72 100644 --- a/emma/src/bin/support/emmagui_support.rs +++ b/emma/src/bin/support/emmagui_support.rs @@ -1,50 +1,124 @@ use imgui::{Condition, ImColor32, Ui}; +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 hex_memory_display(bytes: Box>, rows: i32, cols: i32, ui: &Ui) { - // display a block of data - for current_row in 0..rows { - for current_column in 0..cols { - let data_offset = current_row * cols + current_column; - ui.text(format!("{:02x}", bytes[data_offset as usize])); + pub fn system_controls(system_to_control: &mut Chip8Computer, ui: &Ui) { + ui.window("!!!! CONTROLS !!!!") + .size([200.0, 200.0], Condition::FirstUseEver) + .build(|| { + ui.text("Computer Controls"); + + if ui.button("Step") { + system_to_control.step_system(); + }; + if ui.button("Load Program") { + println!("Load a program to start at 0x200"); + } + if ui.button("Clear System Memory") { + println!("Clear Memory"); + } + }); + } + + pub fn registers_view(system: &Chip8Computer, ui: &Ui) { + 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.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));}); } - pub fn system_memory_render(memory: Chip8SystemMemory, ui: &Ui) { - ui.window("System Memory") - .size([300.0, 100.0], Condition::FirstUseEver) - .build(|| { - ui.text("Rendering System Memory Here"); - let draw_list = ui.get_foreground_draw_list(); - let mut idx = 0; - for row in 0..CHIP8_VIDEO_HEIGHT { - for column in 0..CHIP8_VIDEO_WIDTH { - let x_offset = column * CELL_WIDTH; - let y_offset = row * CELL_WIDTH; - let start_point = [x_offset as f32, y_offset as f32]; - let end_point = [(x_offset + CELL_WIDTH) as f32, - (y_offset + CELL_HEIGHT) as f32 - ]; - let memory_offset = (row * CHIP8_VIDEO_WIDTH) + column; - let target_color = if memory.peek(memory_offset as u16) == 0 { - ImColor32::BLACK - } else { - ImColor32::WHITE - }; - draw_list.add_rect([x_offset as f32, y_offset as f32], - [(x_offset + CELL_WIDTH) as f32, (y_offset + CELL_HEIGHT) as f32], - target_color).build(); - idx += 1; - } - } + pub fn hex_memory_display(bytes: Chip8SystemMemory, rows: i32, cols: i32, ui: &Ui) { + ui.window("System Memory") + .size([400.0, 300.0], Condition::FirstUseEver) + .build(|| { + let mut current_x_hover: i32 = 0; + let mut current_y_hover: i32 = 0; + // display a block of data + for current_row in 0..rows { + ui.text(format!("{:02x}", current_row * cols)); + ui.same_line(); + for current_column in 0..cols { + let data_offset = current_row * cols + current_column; + let formatted_text = format!("{:02x}", bytes.peek(data_offset as u16)); + let text_location = ui.cursor_screen_pos(); + let text_size = ui.calc_text_size(formatted_text.clone()); + let bounding_box = imgui::sys::ImVec2 { + x: text_location[0] + text_size[0], + y: text_location[1] + text_size[1], + }; - }); + if ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]) { + // Optionally change the text color to indicate it's interactable + ui.text_colored([1.0, 0.0, 0.0, 1.0], formatted_text); + current_x_hover = current_column; + current_y_hover = current_row; + + // Check if the left mouse button is clicked while hovering over the text + if ui.is_mouse_clicked(imgui::MouseButton::Left) { + println!("Text was clicked!"); + // Perform any action here, e.g., call a function, trigger an event, etc. + } + } else { + // Default color text when not hovering + ui.text(formatted_text); + } + if current_column != (cols - 1) { + ui.same_line(); + } + } + } + ui.text(format!("Offset 0x{:03x}", current_x_hover * cols + current_y_hover)); + }); + } + + pub fn system_memory_render(memory: Chip8SystemMemory, ui: &Ui) { + ui.window("System Memory") + .size([300.0, 100.0], Condition::FirstUseEver) + .build(|| { + ui.text("Rendering System Memory Here"); + let draw_list = ui.get_foreground_draw_list(); + let mut idx = 0; + for row in 0..CHIP8_VIDEO_HEIGHT { + for column in 0..CHIP8_VIDEO_WIDTH { + let x_offset = column * CELL_WIDTH; + let y_offset = row * CELL_WIDTH; + let start_point = [x_offset as f32, y_offset as f32]; + let end_point = [(x_offset + CELL_WIDTH) as f32, + (y_offset + CELL_HEIGHT) as f32 + ]; + let memory_offset = (row * CHIP8_VIDEO_WIDTH) + column; + let target_color = if memory.peek(memory_offset as u16) == 0 { + ImColor32::BLACK + } else { + ImColor32::WHITE + }; + draw_list.add_rect([x_offset as f32, y_offset as f32], + [(x_offset + CELL_WIDTH) as f32, (y_offset + CELL_HEIGHT) as f32], + target_color).build(); + idx += 1; + } + } + }); } } \ No newline at end of file diff --git a/emma/src/chip8/computer.rs b/emma/src/chip8/computer.rs index 729a591..b26a2c6 100644 --- a/emma/src/chip8/computer.rs +++ b/emma/src/chip8/computer.rs @@ -47,11 +47,12 @@ impl Chip8Computer { let low_byte = self.memory.clone().peek(self.pc + 1) as u16; working_instruction = high_byte | low_byte; - let decided_instruction = + let decoded_instruction = Chip8Computer::decode_instruction(self.clone(), working_instruction); + println!("DECODED INSTRUCTION = {:?}", decoded_instruction); - match (self.state, decided_instruction) { + match (self.state, decoded_instruction) { (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SysAddr(target_address)) => { self.pc = target_address as u16; }, diff --git a/emma/src/chip8/instructions.rs b/emma/src/chip8/instructions.rs index d571e53..f881a21 100644 --- a/emma/src/chip8/instructions.rs +++ b/emma/src/chip8/instructions.rs @@ -1,3 +1,4 @@ +#[derive(Debug)] pub enum Chip8CpuInstructions { SysAddr(i16), // 0x0nnn Exit to System Call CLS, // * 0x00E0 Clear Screen diff --git a/emma/src/chip8/system_memory.rs b/emma/src/chip8/system_memory.rs index de8dfa2..aa8dc31 100644 --- a/emma/src/chip8/system_memory.rs +++ b/emma/src/chip8/system_memory.rs @@ -5,6 +5,7 @@ use ratatui::{style::Style, widgets::Widget}; use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH}; +pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200; pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0]; pub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70]; pub const CHIP8FONT_2: [u8; 5] = [0xF0, 0x10, 0xF0, 0x80, 0xF0]; @@ -53,10 +54,7 @@ const cell_width: i32 = 5i32; const cell_height: i32 = 5i32; impl Chip8SystemMemory { - pub fn gui_render(self, ui: &Ui) { - } - - pub fn peek(self, address: u16) -> u8 { + pub fn peek(self, address: u16) -> u8 { self.memory[address as usize] } @@ -65,6 +63,17 @@ impl Chip8SystemMemory { self } + pub fn load_program(to_load_into: [u8; CHIP8_MEMORY_SIZE as usize], program_data: Box>) -> [u8; CHIP8_MEMORY_SIZE as usize] { + let mut load_target = to_load_into.clone(); + + // loop through the program data starting at 0x200 + for load_index in 0..program_data.len() { + load_target[load_index + CHIP8_PROGRAM_LOAD_OFFSET as usize] = program_data[load_index]; + } + + load_target + } + pub fn load_to_memory( to_load_into: [u8; CHIP8_MEMORY_SIZE as usize], ) -> [u8; CHIP8_MEMORY_SIZE as usize] { diff --git a/emma/src/constants.rs b/emma/src/constants.rs index 6f11c9e..a90ba74 100644 --- a/emma/src/constants.rs +++ b/emma/src/constants.rs @@ -1,5 +1,5 @@ pub const CHIP8_REGISTER_COUNT: i32 = 16; -pub const CHIP8_MEMORY_SIZE: i32 = 2048i32; +pub const CHIP8_MEMORY_SIZE: i32 = 4096i32; pub const CHIP8_VIDEO_WIDTH: i32 = 64i32; pub const CHIP8_VIDEO_HEIGHT: i32 = 32i32; pub const CHIP8_VIDEO_MEMORY: usize = (CHIP8_VIDEO_HEIGHT * CHIP8_VIDEO_WIDTH) as usize;