diff --git a/emma/src/bin/emmagui.rs b/emma/src/bin/emmagui.rs index c681283..fb56566 100644 --- a/emma/src/bin/emmagui.rs +++ b/emma/src/bin/emmagui.rs @@ -39,8 +39,14 @@ fn main() { hello_world_window(ui); - EmmaGui::SystemMemoryRender(system.memory, 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_memory_render(system.memory, 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 e4bcf32..a268f6f 100644 --- a/emma/src/bin/support/emmagui_support.rs +++ b/emma/src/bin/support/emmagui_support.rs @@ -3,11 +3,21 @@ 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; +const CELL_WIDTH: i32 = 5i32; +const CELL_HEIGHT: i32 = 5i32; impl EmmaGui { - pub fn SystemMemoryRender(memory: Chip8SystemMemory, ui: &Ui) { + 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_memory_render(memory: Chip8SystemMemory, ui: &Ui) { ui.window("System Memory") .size([300.0, 100.0], Condition::FirstUseEver) .build(|| { @@ -16,11 +26,11 @@ impl EmmaGui { 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 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 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 { @@ -29,7 +39,7 @@ impl EmmaGui { 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], + [(x_offset + CELL_WIDTH) as f32, (y_offset + CELL_HEIGHT) as f32], target_color).build(); idx += 1; } diff --git a/emma/src/chip8/computer.rs b/emma/src/chip8/computer.rs index 680f5ca..729a591 100644 --- a/emma/src/chip8/computer.rs +++ b/emma/src/chip8/computer.rs @@ -53,7 +53,7 @@ impl Chip8Computer { match (self.state, decided_instruction) { (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SysAddr(target_address)) => { - self.pc = target_address; + self.pc = target_address as u16; }, (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CLS) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RET) => todo!(), @@ -216,27 +216,27 @@ impl Chip8Computer { 0x0000..=0x0FFF => { // 0nnn - SYS addr // Jump to a machine code routine at nnn. - decoded_instruction = Chip8CpuInstructions::SysAddr(addr_param); + decoded_instruction = Chip8CpuInstructions::SysAddr(addr_param as i16); } 0x1000..=0x1FFF => { // 1nnn - JP addr // Jump to location nnn. - decoded_instruction = Chip8CpuInstructions::JpAddr(addr_param); + decoded_instruction = Chip8CpuInstructions::JpAddr(addr_param as i16); } 0x2000..=0x2FFF => { // 2nnn - CALL addr // Call subroutine at nnn. - decoded_instruction = Chip8CpuInstructions::CallAddr(addr_param); + decoded_instruction = Chip8CpuInstructions::CallAddr(addr_param as i16); } 0x3000..=0x3FFF => { // 3xkk - SE Vx, byte // Skip next instruction if Vx = kk. - decoded_instruction = Chip8CpuInstructions::SeVxByte(x_param, byte_param) + decoded_instruction = Chip8CpuInstructions::SeVxByte(x_param as i16, byte_param as i16) } 0x4000..=0x4FFF => { // 4xkk - SNE Vx, byte // Skip next instruction if Vx != kk. - decoded_instruction = Chip8CpuInstructions::SneVxByte(x_param, byte_param); + decoded_instruction = Chip8CpuInstructions::SneVxByte(x_param as i16, byte_param as i16); } 0x5000..=0x5FF0 => { // 5xy0 - SE Vx, Vy diff --git a/emma/src/chip8/instructions.rs b/emma/src/chip8/instructions.rs index 8a6b0ef..d571e53 100644 --- a/emma/src/chip8/instructions.rs +++ b/emma/src/chip8/instructions.rs @@ -1,13 +1,13 @@ pub enum Chip8CpuInstructions { - SysAddr(u16), // 0x0nnn Exit to System Call - CLS, // 0x00E0 Clear Screen + SysAddr(i16), // 0x0nnn Exit to System Call + CLS, // * 0x00E0 Clear Screen RET, // 0x00EE Return from Subroutine - JpAddr(u16), // 0x1nnn Jump to Address - CallAddr(u16), // 0x2nnn Call Subroutine - SeVxByte(u16, u16), // 0x3xkk Skip next instruction if Vx = kk. - SneVxByte(u16, u16), // 0x4xkk Skip next instruction if Vx != kk + JpAddr(i16), // 0x1nnn Jump to Address + CallAddr(i16), // 0x2nnn Call Subroutine + SeVxByte(i16, i16), // 0x3xkk Skip next instruction if Vx = kk. + SneVxByte(i16, i16), // 0x4xkk Skip next instruction if Vx != kk SeVxVy(u16, u16), // 0x5xy0 Skip next instruction if Vx == Vy - LdVxByte(u16, u16), // 0x6xkk Set Vx = kk + LdVxByte(u16, u16), // * 0x6xkk Set Vx = kk AddVxByte(u16, u16), // 0x7xkk Set Vx = Vx + kk LdVxVy(u16, u16), // 0x8xy0 Set value of Vy in Vx OrVxVy(u16, u16), // 0x8xy1 Set Vx = Vx OR Vy @@ -19,10 +19,10 @@ pub enum Chip8CpuInstructions { SubnVxVy(u16, u16), // 0x8xy7 Set Vx = Vy - Vx (Set VF NOT Borrow) ShlVxVy(u16, u16), // 0x8xyE Shift Left SneVxVy(u16, u16), // 0x9xy0 Skip next instruction if Vx != Vy - LdIAddr(u16), // 0xAnnn VI = nnn + LdIAddr(u16), // * 0xAnnn VI = nnn JpV0Addr(u16), // 0xBnnn Jump to nnn+V0 RndVxByte(u16, u16), // 0xCxkk Vx = random byte AND kk - DrawVxVyNibble(u16, u16, u16), // 0xDxyn Display N byte sprite starting at Vx to Vy + DrawVxVyNibble(u16, u16, u16), // * 0xDxyn Display N byte sprite starting at Vx to Vy SkpVx(u16), // 0xE09E Skip next instruction if key in Vx pressed SnkpVx(u16), // 0xE0A1 Skip next instruction if key in Vx NOT pressed LdVxDt(u16), // 0xFx07 Set Vx = Delay timer @@ -36,3 +36,155 @@ pub enum Chip8CpuInstructions { LdVxI(u16), // 0xFx65 Load V0 to Vx in memory starting at I XXXXERRORINSTRUCTION, } + +#[derive(Clone)] +struct Chip8SystemState { + pub video_memory: [bool; 512], + pub memory: [u8; 4096], + pub registers: [u8; 16], + pub i: i16, + pub pc: i16, + pub sound_timer: i8, + pub delay_timer: i8 +} + +trait Chip8Instruction { + fn execute(&self, input: Chip8SystemState) -> Chip8SystemState; +} + +impl Chip8Instruction for Chip8CpuInstructions { + fn execute(&self, mut input: Chip8SystemState) -> Chip8SystemState { + match self { + Chip8CpuInstructions::SysAddr(new_address) => { + let mut new_state = input.clone(); + new_state.pc = *new_address; + new_state + } + Chip8CpuInstructions::CLS => { + input.video_memory = [false; 512]; + input + } + Chip8CpuInstructions::RET => { + input + } + Chip8CpuInstructions::JpAddr(new_address) => { + input + } + Chip8CpuInstructions::CallAddr(_) => { + input + } + Chip8CpuInstructions::SeVxByte(_, _) => { + input + } + Chip8CpuInstructions::SneVxByte(_, _) => { + input + } + Chip8CpuInstructions::SeVxVy(_, _) => { + input + } + Chip8CpuInstructions::LdVxByte(register, byte) => { + input.registers[*register as usize] = byte.to_be_bytes()[0]; + input + } + Chip8CpuInstructions::AddVxByte(_, _) => { + input + } + Chip8CpuInstructions::LdVxVy(_, _) => { + input + } + Chip8CpuInstructions::OrVxVy(_, _) => { + input + } + Chip8CpuInstructions::AndVxVy(_, _) => { + input + } + Chip8CpuInstructions::XorVxVy(_, _) => { + input + } + Chip8CpuInstructions::AddVxVy(_, _) => { + input + } + Chip8CpuInstructions::SubVxVy(_, _) => { + input + } + Chip8CpuInstructions::ShrVxVy(_, _) => { + input + } + Chip8CpuInstructions::SubnVxVy(_, _) => { + input + } + Chip8CpuInstructions::ShlVxVy(_, _) => { + input + } + Chip8CpuInstructions::SneVxVy(_, _) => { + input + } + Chip8CpuInstructions::LdIAddr(new_index) => { + input.i = *new_index as i16; + input + } + Chip8CpuInstructions::JpV0Addr(_) => { + input + } + Chip8CpuInstructions::RndVxByte(_, _) => { + input + } + Chip8CpuInstructions::DrawVxVyNibble(x, y, n) => { + // read nibble bytes from memory starting at I + + let mut did_change: bool = false; + + for draw_x in 0..*n { + let mut new_value = input.memory[(input.i + draw_x as i16) as usize]; + for draw_y in 0..8 { + } + } + + + if did_change { + input.registers[0xF] = 1u8; + } else { + input.registers[0xF] = 0u8; + } + input + } + Chip8CpuInstructions::SkpVx(_) => { + input + } + Chip8CpuInstructions::SnkpVx(_) => { + input + } + Chip8CpuInstructions::LdVxDt(_) => { + input + } + Chip8CpuInstructions::LdVxK(_) => { + input + } + Chip8CpuInstructions::LdDtVx(_) => { + input + } + Chip8CpuInstructions::LdStVx(_) => { + input + } + Chip8CpuInstructions::AddIVx(_) => { + input + } + Chip8CpuInstructions::LdFVu(_) => { + input + } + Chip8CpuInstructions::LdBVx(_) => { + input + + } + Chip8CpuInstructions::LdIVx(_) => { + input + } + Chip8CpuInstructions::LdVxI(_) => { + input + } + Chip8CpuInstructions::XXXXERRORINSTRUCTION => { + input + } + } + } +} \ No newline at end of file