From be6e652982eba415ab7dd3284e0558d6bdfc6246 Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Fri, 18 Oct 2024 15:34:49 -0400 Subject: [PATCH] Adds 'name' and 'operand' to Chip8Instruction --- gemma/src/chip8/instructions.rs | 230 ++++++++++++++++---------- gemmaegui/src/bin/gemmaegui.rs | 51 ++++-- gemmaegui/src/bin/gemmaegui_viewer.rs | 61 +++++++ 3 files changed, 243 insertions(+), 99 deletions(-) create mode 100644 gemmaegui/src/bin/gemmaegui_viewer.rs diff --git a/gemma/src/chip8/instructions.rs b/gemma/src/chip8/instructions.rs index 54d3c11..0569a0b 100644 --- a/gemma/src/chip8/instructions.rs +++ b/gemma/src/chip8/instructions.rs @@ -1,6 +1,6 @@ use std::arch::x86_64::_mm_xor_pd; use std::fmt::{Debug, Display, Formatter}; -use std::ops::{BitAnd, Shr}; +use std::ops::{BitAnd, Deref, Shr}; use std::time::Instant; use log::debug; use rand::{random, Rng}; @@ -21,7 +21,7 @@ kk or byte - An 8-bit value, the lowest 8 bits of the instruction pub enum Chip8CpuInstructions { /// 0nnn /// Exit to System Call at nnn - SysAddr(i16), + SysAddr(u16), /// 00E0 /// Clear the display. CLS, @@ -35,13 +35,13 @@ pub enum Chip8CpuInstructions { /// Jump to location nnn. /// /// The interpreter sets the program counter to nnn. - JpAddr(i16), + JpAddr(u16), /// 2nnn /// Call subroutine at nnn. /// /// The interpreter increments the stack pointer, then puts the current PC on the top /// of the stack. The PC is then set to nnn. - CallAddr(i16), + CallAddr(u16), /// 0x3xkk /// Skip next instruction if Vx = kk. /// @@ -215,118 +215,175 @@ pub enum Chip8CpuInstructions { XXXXERRORINSTRUCTION, } -impl Display for Chip8CpuInstructions { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", format!("{}", match self { - Chip8CpuInstructions::SysAddr(x) => { - format!("SYS 0x{:04x}", x) +impl Chip8CpuInstructions { + pub fn name(&self) -> &str { + match self { + Chip8CpuInstructions::SysAddr(_) => { + "SYS" } Chip8CpuInstructions::CLS => { - String::from("CLS") + "CLS" } Chip8CpuInstructions::RET => { - String::from("RET") + "RET" } - Chip8CpuInstructions::JpAddr(x) => { - format!("JP 0x{:04x}", x) + Chip8CpuInstructions::JpAddr(_) => { + "JPA" } - Chip8CpuInstructions::CallAddr(x) => { - format!("SUB 0x{:04x}", x) + Chip8CpuInstructions::CallAddr(_) => { + "CALL" } - Chip8CpuInstructions::SeVxByte(x, byte) => { - format!("SeVxByte 0x{:02x}, 0x{:02x}", x, byte) + Chip8CpuInstructions::SeVxByte(_, _) => { + "SeVxByte" } - Chip8CpuInstructions::SneVxByte(x, byte) => { - format!("SneVxByte 0x{:02x}, 0x{:02x}", x, byte) + Chip8CpuInstructions::SneVxByte(_, _) => { + "SneVxByte" } - Chip8CpuInstructions::SeVxVy(x, y) => { - format!("SeVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::SeVxVy(_, _) => { + "SeVeVy" } - Chip8CpuInstructions::LdVxByte(x, byte) => { - format!("LdVxByte 0x{:02x}, 0x{:02x}", x, byte) + Chip8CpuInstructions::LdVxByte(_, _) => { + "LdVxByte" } - Chip8CpuInstructions::AddVxByte(x, byte) => { - format!("AddVxByte 0x{:02x}, 0x{:02x}", x, byte) + Chip8CpuInstructions::AddVxByte(_, _) => { + "AddVxByte" } - Chip8CpuInstructions::LdVxVy(x, y) => { - format!("LdVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::LdVxVy(_, _) => { + "LdVxVy" } - Chip8CpuInstructions::OrVxVy(x, y) => { - format!("OrVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::OrVxVy(_, _) => { + "OrVxVy" } - Chip8CpuInstructions::AndVxVy(x, y) => { - format!("AndVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::AndVxVy(_, _) => { + "AndVxVy" } - Chip8CpuInstructions::XorVxVy(x, y) => { - format!("XorVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::XorVxVy(_, _) => { + "XorVxVy" } - Chip8CpuInstructions::AddVxVy(x, y) => { - format!("AddVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::AddVxVy(_, _) => { + "AddVxVy" } - Chip8CpuInstructions::SubVxVy(x, y) => { - format!("SubVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::SubVxVy(_, _) => { + "SubVxVy" } - Chip8CpuInstructions::ShrVxVy(x, y) => { - format!("ShrVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::ShrVxVy(_, _) => { + "ShrVxVy" } - Chip8CpuInstructions::SubnVxVy(x, y) => { - format!("SubnVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::SubnVxVy(_, _) => { + "SubnVxVy" } - Chip8CpuInstructions::ShlVxVy(x, y) => { - format!("ShlVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::ShlVxVy(_, _) => { + "ShlVxVy" } - Chip8CpuInstructions::SneVxVy(x, y) => { - format!("SneVxVy 0x{:02x}, 0x{:02x}", x, y) + Chip8CpuInstructions::SneVxVy(_, _) => { + "SneVxVy" } - Chip8CpuInstructions::LdIAddr(addr) => { - format!("LdIAddr 0x{:04x}", addr) + Chip8CpuInstructions::LdIAddr(_) => { + "LdIAddr" } - Chip8CpuInstructions::JpV0Addr(addr) => { - format!("JpV0Addr 0x{:04x}", addr) + Chip8CpuInstructions::JpV0Addr(_) => { + "JpV0Addr" } - Chip8CpuInstructions::RndVxByte(x, byte) => { - format!("RndVxByte 0x:{:02x}, 0x{:02x}", x, byte) + Chip8CpuInstructions::RndVxByte(_, _) => { + "RndVxByte" } - Chip8CpuInstructions::DrawVxVyNibble(x, y, nibble) => { - format!("DrawVxVyNibble 0x:{:02x}, 0x{:02x}, 0x{:02x}", x, y, nibble) + Chip8CpuInstructions::DrawVxVyNibble(_, _, _) => { + "DrawVxVyNibble" } - Chip8CpuInstructions::SkpVx(x) => { - format!("SkpVx 0x{:02x}", x) + Chip8CpuInstructions::SkpVx(_) => { + "SkpVx" } - Chip8CpuInstructions::SnkpVx(x) => { - format!("SnkpVx 0x{:02x}", x) + Chip8CpuInstructions::SnkpVx(_) => { + "SnkpVx" } - Chip8CpuInstructions::LdVxDt(x) => { - format!("LdVxDt 0x{:02x}", x) + Chip8CpuInstructions::LdVxDt(_) => { + "LdVxDt" } - Chip8CpuInstructions::LdVxK(x) => { - format!("LdVxK 0x{:02x}", x) + Chip8CpuInstructions::LdVxK(_) => { + "LdVxK" } - Chip8CpuInstructions::LdDtVx(x) => { - format!("LdDtVx 0x{:02x}", x) + Chip8CpuInstructions::LdDtVx(_) => { + "LdDtVx" } - Chip8CpuInstructions::LdStVx(x) => { - format!("LdStVx 0x{:02x}", x) + Chip8CpuInstructions::LdStVx(_) => { + "LdStVx" } - Chip8CpuInstructions::AddIVx(x) => { - format!("AddIVx 0x{:02x}", x) + Chip8CpuInstructions::AddIVx(_) => { + "AddIVx" } - Chip8CpuInstructions::LdFVx(x) => { - format!("LdFVx 0x{:02x}", x) + Chip8CpuInstructions::LdFVx(_) => { + "LdFVx" } - Chip8CpuInstructions::LdBVx(x) => { - format!("LdBVx 0x{:02x}", x) + Chip8CpuInstructions::LdBVx(_) => { + "LdBVx" } - Chip8CpuInstructions::LdIVx(x) => { - format!("LdIVx 0x{:02x}", x) + Chip8CpuInstructions::LdIVx(_) => { + "LdIVx" } - Chip8CpuInstructions::LdVxI(i) => { - format!("LdVxI 0x{:02x}", i) + Chip8CpuInstructions::LdVxI(_) => { + "LdVxI" } XXXXERRORINSTRUCTION => { - String::from("INVALID INSTRUCTION") + "XX ERROR XX" } - })) + } + } + + pub fn operands(&self) -> String { + match self { + Chip8CpuInstructions::SysAddr(addr) | + Chip8CpuInstructions::JpV0Addr(addr) | + Chip8CpuInstructions::JpAddr(addr) | + Chip8CpuInstructions::LdIAddr(addr) | + Chip8CpuInstructions::CallAddr(addr) => { + format!("{addr:04x}") + } + Chip8CpuInstructions::SeVxByte(x, byte) | + Chip8CpuInstructions::SneVxByte(x, byte) | + Chip8CpuInstructions::LdVxByte(x, byte) | + Chip8CpuInstructions::RndVxByte(x, byte) | + Chip8CpuInstructions::AddVxByte(x, byte) => { + format!("{x:02x}, {byte:04x}") + } + Chip8CpuInstructions::SeVxVy(x,y) | + Chip8CpuInstructions::LdVxVy(x,y) | + Chip8CpuInstructions::OrVxVy(x,y) | + Chip8CpuInstructions::AndVxVy(x,y) | + Chip8CpuInstructions::XorVxVy(x,y) | + Chip8CpuInstructions::AddVxVy(x,y) | + Chip8CpuInstructions::SubVxVy(x,y) | + Chip8CpuInstructions::ShrVxVy(x,y) | + Chip8CpuInstructions::SubnVxVy(x,y) | + Chip8CpuInstructions::ShlVxVy(x,y) | + Chip8CpuInstructions::SneVxVy(x,y) => { + format!("{x:02x}, {y:02x}") + } + Chip8CpuInstructions::DrawVxVyNibble(x,y,nibble) => { + format!("{x:02x}, {y:02x}, {nibble:02x}") + } + Chip8CpuInstructions::LdDtVx(x) | + Chip8CpuInstructions::LdStVx(x) | + Chip8CpuInstructions::AddIVx(x) | + Chip8CpuInstructions::LdFVx(x) | + Chip8CpuInstructions::LdBVx(x) | + Chip8CpuInstructions::LdIVx(x) | + Chip8CpuInstructions::SkpVx(x) | + Chip8CpuInstructions::LdVxDt(x) | + Chip8CpuInstructions::LdVxK(x) | + Chip8CpuInstructions::LdVxI(x) | + Chip8CpuInstructions::SnkpVx(x) => { + format!("{x:02x}") + } + _ => { + "".parse().unwrap() + } + } + } +} + +impl Display for Chip8CpuInstructions { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {}", self.name(), self.operands()) } } @@ -386,9 +443,9 @@ impl Chip8CpuInstructions { match input { 0x00E0 => Chip8CpuInstructions::CLS, 0x00EE => Chip8CpuInstructions::RET, - 0x0000..=0x0FFF => Chip8CpuInstructions::SysAddr(addr_param as i16), - 0x1000..=0x1FFF => Chip8CpuInstructions::JpAddr(addr_param as i16), - 0x2000..=0x2FFF => Chip8CpuInstructions::CallAddr(addr_param as i16), + 0x0000..=0x0FFF => Chip8CpuInstructions::SysAddr(addr_param), + 0x1000..=0x1FFF => Chip8CpuInstructions::JpAddr(addr_param), + 0x2000..=0x2FFF => Chip8CpuInstructions::CallAddr(addr_param), 0x3000..=0x3FFF => Chip8CpuInstructions::SeVxByte(x_param, byte_param), 0x4000..=0x4FFF => Chip8CpuInstructions::SneVxByte(x_param, byte_param), 0x5000..=0x5FF0 if input & 0x01 == 0 => Chip8CpuInstructions::SeVxVy(x_param, y_param), @@ -412,9 +469,9 @@ impl Chip8CpuInstructions { 0xC000..=0xCFFF => Chip8CpuInstructions::RndVxByte(x_param, byte_param), 0xD000..=0xDFFF => Chip8CpuInstructions::DrawVxVyNibble(x_param, y_param, nibble_param), 0xE09E..=0xEFA1 => match last_byte { - 0x9E => Chip8CpuInstructions::SkpVx(ubln), - 0xA1 => Chip8CpuInstructions::SnkpVx(ubln), - _ => XXXXERRORINSTRUCTION + 0x9E => Chip8CpuInstructions::SkpVx(ubln), + 0xA1 => Chip8CpuInstructions::SnkpVx(ubln), + _ => XXXXERRORINSTRUCTION } 0xF007..=0xFF65 => match last_byte { 0x07 => Chip8CpuInstructions::LdVxDt(ubln), @@ -432,7 +489,7 @@ impl Chip8CpuInstructions { } } pub fn execute(&self, input: &mut Chip8Computer) -> Chip8Computer { -// print!("INSTRUCTION {}", self); + // print!("INSTRUCTION {}", self); let start_time = Instant::now(); let start_pc = input.registers.peek_pc(); input.registers.poke_pc(start_pc + 2); @@ -624,7 +681,7 @@ impl Chip8CpuInstructions { // Set I = nnn. // // The value of register I is set to nnn. - // debug!("LdiAddr [0x{new_index:3x}]"); + // debug!("LdiAddr [0x{new_index:3x}]"); input.registers.poke_i(*new_index); } // 0xBnnn Jump to nnn+V0 @@ -680,7 +737,6 @@ impl Chip8CpuInstructions { }; input.registers.poke(0xf, target); - } Chip8CpuInstructions::SkpVx(x) => { // Ex9E - SKP Vx @@ -811,7 +867,7 @@ impl Chip8CpuInstructions { Chip8CpuInstructions::XXXXERRORINSTRUCTION => {} }; let cycle_time = Instant::now().duration_since(start_time).as_nanos(); -// println!("\t\tTook {cycle_time}ms"); + // println!("\t\tTook {cycle_time}ms"); input.to_owned() } } diff --git a/gemmaegui/src/bin/gemmaegui.rs b/gemmaegui/src/bin/gemmaegui.rs index da2ac2f..17e4340 100644 --- a/gemmaegui/src/bin/gemmaegui.rs +++ b/gemmaegui/src/bin/gemmaegui.rs @@ -8,24 +8,50 @@ use gemma::chip8::computer_manager::Chip8ComputerManager; mod support; +#[derive(Default)] +struct DisplayOptions { + pub video: bool, + pub registers: bool, + pub memory: bool +} +pub struct GemmaViewerState { + pub selected_file_index: i32, + pub selected_filename: String, + pub display_options: DisplayOptions +} + +impl Default for GemmaViewerState { + fn default() -> Self { + GemmaViewerState { + selected_file_index: -1, + selected_filename: String::new(), + display_options: Default::default() + } + } +} + +impl GemmaViewerState { + pub fn new() -> GemmaViewerState { + GemmaViewerState { + ..Default::default() + } + } +} + fn main() -> eframe::Result { println!("Taxation is Theft"); + let mut computer = Chip8ComputerManager::new(); + let mut state = GemmaViewerState::new(); + let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]), ..Default::default() }; - // let mut state = GemmaEGuiState::default(); - let mut computer = Chip8ComputerManager::new(); - let mut cps_counter = 0; - let mut last_counter_update = Instant::now(); - let cps_refresh = 5; - - let mut last_frame_start = Instant::now(); - - eframe::run_simple_native("EGUI Emma", options, move |ctx, _frame| { + eframe::run_simple_native("EGUI Gemma", options, move |ctx, _frame| { egui::CentralPanel::default().show(ctx, |ui| { + computer.tick(); let local_computer = computer.state(); //if state.display_video { GemmaEguiSupport::video_view(local_computer, ui); @@ -40,7 +66,6 @@ fn main() -> eframe::Result { // if state.display_registers { GemmaEguiSupport::registers_view(&local_computer, ui); // } - computer.tick(); ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { if ui.button("Start").clicked() { computer.core_should_run = true; @@ -58,8 +83,10 @@ fn main() -> eframe::Result { // state.is_running = false; } }); - // - // if ui.button(format!("Load {}", state.selected_rom_filename)).clicked() { + + if ui.button(format!("Load {}", state.selected_filename)).clicked() { + + } // // load the bin... // let read_bin = std::fs::read(PathBuf::from(format!("resources/roms/{}", state.selected_rom_filename))).unwrap(); // // ...then feed the system. diff --git a/gemmaegui/src/bin/gemmaegui_viewer.rs b/gemmaegui/src/bin/gemmaegui_viewer.rs new file mode 100644 index 0000000..981c15c --- /dev/null +++ b/gemmaegui/src/bin/gemmaegui_viewer.rs @@ -0,0 +1,61 @@ +use egui::Ui; +use gemma::chip8::instructions::Chip8CpuInstructions; + +/// GemmaEGui - Viewer +/// +/// +/// This program lets a user open a CH8 file and it will be decoded +/// as Chip-8 Instructions. +/// Colour variants for instructions show colours for +/// -> Jumps +/// -> Load +/// -> Store +/// -> Timers +/// -> Math (Add, Sub) +/// -> Logic +/// -> Video + +fn display_instruction(offset: i32, to_display: &Chip8CpuInstructions, ui: &mut Ui) { + ui.label(format!("{offset:04x} {}", to_display.name())); + ui.label(format!("{}", to_display.operands())); + ui.end_row(); +} + +fn display_instructions(base_offset: i32, instructions: Vec, ui: &mut Ui) { + egui::Grid::new("my_grid") + .min_col_width(200.0) + .show(ui, |ui| { + for (index, instruction) in instructions.iter().enumerate() { + display_instruction(base_offset + index as i32, instruction, ui); + } + }); +} + +fn main() -> eframe::Result { + let mut edit_space: String = String::new(); + + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default().with_inner_size([640.0, 480.0]), + ..Default::default() + }; + + eframe::run_simple_native("Gemma - Chip8 Machine Code Viewer", options, move |ctx, frame| { + egui::CentralPanel::default().show(ctx, |ui| { + ui.label("Taxation is Theft"); + // file picker + ui.vertical_centered(|ui| { + if ui.button("Load File").clicked() { + println!("Clicked load file"); + } + }); + ui.label("File Picker Herre"); + ui.label("display of file here"); + + ui.vertical(|ui| { + display_instruction(0x010, &Chip8CpuInstructions::AddIVx(0x01), ui); + display_instruction(0x012, &Chip8CpuInstructions::RndVxByte(0x01, 0x02), ui); + }); + ui.text_edit_multiline(&mut edit_space); + }); + }) +} \ No newline at end of file