WIP
richer test suite Updates imgui to have target ips and limits correctly. Initial IPS = 1000, plan to expose to user More tests for encode/decode of instructions Adding text to instruction parsing
This commit is contained in:
@@ -17,3 +17,4 @@ image = { version = "0.23" }
|
||||
imgui = { version = "0.12.0" }
|
||||
winit = { version = "0.27", features = ["x11", "mint"]}
|
||||
copypasta = { version = "0.8" }
|
||||
clap = { version = "4.5.20", features = ["derive"] }
|
||||
@@ -12,6 +12,10 @@ use gemma::chip8::computer_manager::Chip8ComputerManager;
|
||||
use gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
|
||||
use gemma::chip8::system_memory::Chip8SystemMemory;
|
||||
use support::{emmagui_support::GemmaImguiSupport, ui_state::ImGuiUiState};
|
||||
use clap::{Parser, Subcommand};
|
||||
use gemma::chip8::quirk_modes::QuirkMode;
|
||||
use gemma::chip8::quirk_modes::QuirkMode::Chip8;
|
||||
|
||||
|
||||
mod support;
|
||||
|
||||
@@ -28,8 +32,10 @@ const LIN_KEYS: [(u16, u8); 0x10] = [(537, 0x01),(538, 0x02),(539, 0x03),(540, 0
|
||||
|
||||
fn main() {
|
||||
pretty_env_logger::init();
|
||||
|
||||
let mut system = Chip8ComputerManager::default();
|
||||
let mut ui_state = ImGuiUiState::default();
|
||||
let target_ips = ui_state.target_ips;
|
||||
|
||||
support::simple_init(file!(), move |_, ui| {
|
||||
let current_time = Instant::now();
|
||||
@@ -59,9 +65,16 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
while Instant::now().duration_since(current_time).as_millis() < 16 && num_cycles < 1000 {
|
||||
system.tick();
|
||||
num_cycles += 1;
|
||||
let target_ms = ui_state.frame_time;
|
||||
let loop_start_time = Instant::now();
|
||||
while Instant::now().duration_since(current_time).as_millis() < target_ms as u128 && num_cycles < target_ips {
|
||||
if system.tick() {
|
||||
num_cycles += 1;
|
||||
}
|
||||
}
|
||||
let cycles_time = Instant::now().duration_since(loop_start_time);
|
||||
if num_cycles > 0 {
|
||||
println!("Ran for {}ms and executed {}/{} cycles.", cycles_time.as_millis(), num_cycles, target_ips);
|
||||
}
|
||||
// GUI Parts
|
||||
if ui_state.show_video {
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::ImGuiUiState;
|
||||
use crate::support::gui_file_list::GuiFileList;
|
||||
use super::ui_state;
|
||||
|
||||
const ROM_ROOT: &str = "/home/tmerritt/Projects/trevors_chip8_toy/resources/roms";
|
||||
const ROM_ROOT: &str = "/home/tmerritt/Projects/chip8_toy/resources/roms";
|
||||
|
||||
pub struct GemmaImguiSupport {}
|
||||
|
||||
@@ -25,37 +25,39 @@ const CELL_HEIGHT: i32 = 5i32;
|
||||
|
||||
impl GemmaImguiSupport {
|
||||
pub fn keypad_display(system_to_display: &Chip8Computer, ui: &Ui) {
|
||||
ui.text("Keypad");
|
||||
|
||||
for row in CHIP8_KEYBOARD {
|
||||
for key in row {
|
||||
let label = if system_to_display.keypad.pressed(key) {
|
||||
format!("*{:1x}*", key)
|
||||
} else {
|
||||
format!("{:1x}", key)
|
||||
};
|
||||
ui.text(format!("{}", label));
|
||||
ui.same_line();
|
||||
}
|
||||
ui.text("");
|
||||
}
|
||||
ui.window(format!("Keypad"))
|
||||
.size([100.0, 100.0], Condition::FirstUseEver)
|
||||
.build(|| {
|
||||
for row in CHIP8_KEYBOARD {
|
||||
for key in row {
|
||||
let label = if system_to_display.keypad.pressed(key) {
|
||||
format!("*{:1x}*", key)
|
||||
} else {
|
||||
format!("{:1x}", key)
|
||||
};
|
||||
ui.text(format!("{}", label));
|
||||
ui.same_line();
|
||||
}
|
||||
ui.text("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn video_display(system_to_control: &Chip8Computer, gui_state: &ImGuiUiState, ui: &Ui) {
|
||||
// draw area size
|
||||
let (width, height) = system_to_control.video_memory.get_resolution();
|
||||
let draw_area_size = ui.io().display_size;
|
||||
// println!("DRAW_AREA_SIZE = {}x{}", draw_area_size[0], draw_area_size[1]);
|
||||
// println!("DRAW_AREA_SIZE = {}x{}", draw_area_size[0], draw_area_size[1]);
|
||||
let cell_width = ((draw_area_size[0] as i32 / width) * 6) / 10;
|
||||
let cell_height = ((draw_area_size[1] as i32 / height) * 6) / 10;
|
||||
|
||||
ui.window(format!("Display {cell_width}x{cell_height}"))
|
||||
.size([300.0, 300.0], Condition::Once)
|
||||
.build(|| {
|
||||
let origin = ui.cursor_screen_pos();
|
||||
let origin = ui.cursor_pos();
|
||||
let fg = ui.get_window_draw_list();
|
||||
if (system_to_control.video_memory.is_highres()) {
|
||||
ui.text("High Def Video here");
|
||||
if system_to_control.video_memory.is_highres() {
|
||||
// ui.text("High Def Video here");
|
||||
for current_row in 0..=height {
|
||||
let y_offset = origin[1] as i32 + (current_row * cell_height);
|
||||
for current_column in 0..=width {
|
||||
@@ -73,10 +75,9 @@ impl GemmaImguiSupport {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ui.text("StdDef video here.");
|
||||
for current_row in 0..=height {
|
||||
for current_row in 0..height {
|
||||
let y_offset = origin[1] as i32 + (current_row * cell_height);
|
||||
for current_column in 0..=width {
|
||||
for current_column in 0..width {
|
||||
let x_offset = origin[0] as i32 + (current_column * cell_width);
|
||||
let current_origin = [x_offset as f32, y_offset as f32];
|
||||
let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32];
|
||||
@@ -94,7 +95,7 @@ impl GemmaImguiSupport {
|
||||
});
|
||||
}
|
||||
pub fn system_controls(system_to_control: &mut Chip8ComputerManager, gui_state: &mut ImGuiUiState, ui: &Ui) {
|
||||
// let mut state: Chip8Computer = system_to_control;
|
||||
// let mut state: Chip8Computer = system_to_control;
|
||||
ui.window("!!!! CONTROLS !!!!")
|
||||
.size([345.0, 200.0], Condition::FirstUseEver)
|
||||
.build(|| {
|
||||
@@ -102,7 +103,7 @@ impl GemmaImguiSupport {
|
||||
ui.text(format!("Step {:04x}", system_to_control.num_cycles()).as_str());
|
||||
|
||||
/* ROM Lister */
|
||||
let new_filename = GuiFileList::display_path(PathBuf::from("/home/tmerritt/Projects/trevors_chip8_toy/resources/roms/"), &gui_state.filename_to_load, ui);
|
||||
let new_filename = GuiFileList::display_path(PathBuf::from(ROM_ROOT), &gui_state.filename_to_load, ui);
|
||||
if !new_filename.is_empty() {
|
||||
if new_filename != gui_state.filename_to_load {
|
||||
debug!("NEW FILENAME SELECTED -> {new_filename}");
|
||||
@@ -112,19 +113,21 @@ impl GemmaImguiSupport {
|
||||
let mut buffer = Vec::new();
|
||||
debug!("PREPARING TO LOAD {}", gui_state.filename_to_load);
|
||||
// let mut input_file = File::open(Path::new("./1-chip8-logo.ch8")).expect("put 1-chip8-logo.ch8 in this directory");
|
||||
let mut input_file = File::open(Path::new(&("/home/tmerritt/Projects/trevors_chip8_toy/resources/roms/".to_string() + &gui_state.filename_to_load))).expect("put 1-chip8-logo.ch8 in this directory");
|
||||
let mut input_file = File::open(Path::new(&(ROM_ROOT.to_string() + "/" + &gui_state.filename_to_load))).expect("put 1-chip8-logo.ch8 in this directory");
|
||||
input_file.read_to_end(&mut buffer).expect("unable to read file");
|
||||
system_to_control.load_bytes_to_system_memory((&*buffer).into());
|
||||
}
|
||||
}
|
||||
ui.separator();
|
||||
if ui.button("Step") {
|
||||
system_to_control.step();
|
||||
|
||||
};
|
||||
ui.same_line();
|
||||
if ui.button("Run") {
|
||||
system_to_control.start();
|
||||
// if the system has no program loaded hide the buttons.
|
||||
if system_to_control.state().memory.peek(0x200) != 0x00 {
|
||||
if ui.button("Step") {
|
||||
system_to_control.step();
|
||||
};
|
||||
ui.same_line();
|
||||
if ui.button("Run") {
|
||||
system_to_control.start();
|
||||
}
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Stop") {
|
||||
@@ -183,55 +186,53 @@ impl GemmaImguiSupport {
|
||||
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],
|
||||
};
|
||||
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],
|
||||
};
|
||||
|
||||
let hovering = ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]);
|
||||
let is_active = data_offset == active as i32;
|
||||
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());
|
||||
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
|
||||
current_x_hover = current_column;
|
||||
current_y_hover = current_row;
|
||||
|
||||
// if we are hovering show that at the bottom...
|
||||
if hovering {
|
||||
// Optionally change the text color to indicate it's interactable
|
||||
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) {
|
||||
debug!("Offset: [{}] [0x{:02x}] Value: [{}]", data_offset, data_offset, formatted_text.clone());
|
||||
// Perform any action here, e.g., call a function, trigger an event, etc.
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the left mouse button is clicked while hovering over the text
|
||||
if ui.is_mouse_clicked(imgui::MouseButton::Left) {
|
||||
debug!("Offset: [{}] [0x{:02x}] Value: [{}]", data_offset, data_offset, formatted_text.clone());
|
||||
// Perform any action here, e.g., call a function, trigger an event, etc.
|
||||
// are we on the same line?
|
||||
if current_column != (cols - 1) {
|
||||
ui.same_line();
|
||||
}
|
||||
}
|
||||
|
||||
// are we on the same line?
|
||||
if current_column != (cols - 1) {
|
||||
ui.same_line();
|
||||
}
|
||||
}
|
||||
}
|
||||
ui.text(format!("Offset 0x{:03x}", current_x_hover * cols + current_y_hover));
|
||||
ui.text(format!("Offset 0x{:03x}", current_x_hover * cols + current_y_hover));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,8 +10,9 @@ pub struct ImGuiUiState {
|
||||
pub on_colour: ImColor32,
|
||||
pub off_colour: ImColor32,
|
||||
pub is_running: bool,
|
||||
pub frame_time: f32,
|
||||
pub last_frame_instant: Instant
|
||||
pub frame_time: u32,
|
||||
pub last_frame_instant: Instant,
|
||||
pub target_ips: i32
|
||||
}
|
||||
|
||||
impl Clone for ImGuiUiState {
|
||||
@@ -26,7 +27,8 @@ impl Clone for ImGuiUiState {
|
||||
off_colour: self.off_colour,
|
||||
is_running: self.is_running,
|
||||
frame_time: self.frame_time,
|
||||
last_frame_instant: self.last_frame_instant
|
||||
last_frame_instant: self.last_frame_instant,
|
||||
target_ips: self.target_ips
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,8 +44,9 @@ impl Default for ImGuiUiState {
|
||||
on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00),
|
||||
off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff),
|
||||
is_running: false,
|
||||
frame_time: 1.0,
|
||||
last_frame_instant: Instant::now()
|
||||
frame_time: 16,
|
||||
last_frame_instant: Instant::now(),
|
||||
target_ips: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user