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:
2024-10-28 14:42:14 -04:00
parent 1694157e27
commit b492eb5f49
25 changed files with 1347 additions and 239 deletions
+1
View File
@@ -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"] }
+16 -3
View File
@@ -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 {
+74 -73
View File
@@ -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));
});
}
}
+8 -5
View File
@@ -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
}
}
}