Adds ComputerManager so no write access to the computer directly happens.
ComputerManager has a thread to run the CPU whenever its told to either step or run. It can be told to stop the CPU too. Cycle count and keystate feedback is available along with read-only of the computer from status()
This commit is contained in:
@@ -8,6 +8,7 @@ use gemma::{
|
||||
use imgui::*;
|
||||
use sys::{ImColor, ImVec2, ImVector_ImU32};
|
||||
use rand::random;
|
||||
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};
|
||||
@@ -27,7 +28,7 @@ const LIN_KEYS: [(u16, u8); 0x10] = [(537, 0x01),(538, 0x02),(539, 0x03),(540, 0
|
||||
|
||||
fn main() {
|
||||
pretty_env_logger::init();
|
||||
let mut system = Chip8Computer::default();
|
||||
let mut system = Chip8ComputerManager::default();
|
||||
let mut ui_state = ImGuiUiState::default();
|
||||
|
||||
support::simple_init(file!(), move |_, ui| {
|
||||
@@ -35,61 +36,51 @@ fn main() {
|
||||
|
||||
// Key Checks
|
||||
let down_keys = ui.io().keys_down;
|
||||
|
||||
// START DEBUG CODE TO DISPLAY WHAT KEYS WE TRAPPED
|
||||
for (idx, val) in down_keys.iter().enumerate() {
|
||||
if *val {
|
||||
println!("{idx} = {val}");
|
||||
}
|
||||
}
|
||||
// END DEBUG CODE
|
||||
|
||||
|
||||
for (key_code, key_reg) in LIN_KEYS {
|
||||
if down_keys[key_code as usize] {
|
||||
system.keypad.push_key(key_reg);
|
||||
system.state = WaitingForInstruction;
|
||||
system.press_key(key_reg);
|
||||
system.press_key(key_reg);
|
||||
system.wait_for_instruction();
|
||||
} else {
|
||||
// do we need to release it?
|
||||
if system.keypad.pressed(key_reg) {
|
||||
system.keypad.release_key(key_reg);
|
||||
|
||||
if system.is_key_pressed(key_reg) {
|
||||
system.release_key(key_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next Tick Check
|
||||
let time_since_last_tick = current_time.duration_since(ui_state.last_frame_instant).as_millis();
|
||||
if ui_state.is_running && time_since_last_tick > ui_state.frame_time as u128 {
|
||||
match system.state {
|
||||
gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction => {
|
||||
// this is the 'regular' mode for the CPU when we get here
|
||||
system.step_system();
|
||||
},
|
||||
gemma::chip8::cpu_states::Chip8CpuStates::WaitingForKey => {
|
||||
// waiting for a keychange...
|
||||
},
|
||||
gemma::chip8::cpu_states::Chip8CpuStates::ExecutingInstruction => { // should never see this.
|
||||
},
|
||||
gemma::chip8::cpu_states::Chip8CpuStates::Error => {
|
||||
panic!("System in undefined state.");
|
||||
},
|
||||
}
|
||||
ui_state.last_frame_instant = current_time;
|
||||
}
|
||||
system.tick();
|
||||
|
||||
|
||||
// GUI Parts
|
||||
if ui_state.show_video {
|
||||
GemmaImguiSupport::video_display(&system, &ui_state, ui);
|
||||
GemmaImguiSupport::video_display(&system.state(), &ui_state, ui);
|
||||
}
|
||||
|
||||
GemmaImguiSupport::system_controls(&mut system, &mut ui_state, ui);
|
||||
|
||||
if ui_state.show_registers {
|
||||
GemmaImguiSupport::registers_view(&system, ui);
|
||||
GemmaImguiSupport::registers_view(&system.state(), ui);
|
||||
}
|
||||
|
||||
if ui_state.show_memory {
|
||||
let active_instruction = system.registers.peek_pc();
|
||||
GemmaImguiSupport::hex_memory_display(system.memory.clone(), (0x100, 0x10), active_instruction as i16, ui);
|
||||
let active_instruction = system.state().registers.peek_pc();
|
||||
GemmaImguiSupport::hex_memory_display(system.state().memory.clone(), (0x100, 0x10), active_instruction as i16, ui);
|
||||
}
|
||||
|
||||
if ui_state.show_keypad {
|
||||
GemmaImguiSupport::keypad_display(&system, ui);
|
||||
GemmaImguiSupport::keypad_display(&system.state(), ui);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,10 +7,13 @@ use std::time::Duration;
|
||||
use imgui::{Condition, ImColor32, Ui};
|
||||
use log::debug;
|
||||
use gemma::chip8::computer::Chip8Computer;
|
||||
use gemma::chip8::computer_manager::Chip8ComputerManager;
|
||||
use gemma::chip8::computer_manager::ManagerDumpables::{Keyboard, Registers, Video};
|
||||
use gemma::chip8::keypad::Keypad;
|
||||
use gemma::chip8::system_memory::Chip8SystemMemory;
|
||||
use gemma::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
|
||||
use crate::ImGuiUiState;
|
||||
|
||||
use crate::support::gui_file_list::GuiFileList;
|
||||
use super::ui_state;
|
||||
|
||||
pub struct GemmaImguiSupport {}
|
||||
@@ -18,35 +21,6 @@ pub struct GemmaImguiSupport {}
|
||||
const CELL_WIDTH: i32 = 5i32;
|
||||
const CELL_HEIGHT: i32 = 5i32;
|
||||
|
||||
struct GuiFileList {}
|
||||
|
||||
impl GuiFileList {
|
||||
pub fn display_path(root: PathBuf, selected_filename: &String, ui: &Ui) -> String {
|
||||
let mut working_filename = selected_filename.clone();
|
||||
ui.text(format!("Displaying {}", root.to_str().unwrap_or("Unable to parse path")));
|
||||
|
||||
let mut known_files: Vec<OsString> = vec![];
|
||||
|
||||
for entry in read_dir(root.as_path()).unwrap() {
|
||||
known_files.push(entry.unwrap().file_name());
|
||||
}
|
||||
|
||||
known_files.sort();
|
||||
|
||||
for (index, entry) in known_files.iter().enumerate() {
|
||||
let mut working_select = ui.selectable_config(format!("{}", entry.clone().into_string().unwrap()));
|
||||
if entry.to_str().unwrap().to_string() == selected_filename.as_str().to_string() {
|
||||
working_select = working_select.selected(true);
|
||||
}
|
||||
if working_select.build() {
|
||||
debug!("SELECTED {index} / {entry:?}");
|
||||
working_filename = entry.clone().into_string().unwrap();
|
||||
};
|
||||
}
|
||||
working_filename
|
||||
}
|
||||
}
|
||||
|
||||
impl GemmaImguiSupport {
|
||||
pub fn keypad_display(system_to_display: &Chip8Computer, ui: &Ui) {
|
||||
ui.text("Keypad");
|
||||
@@ -96,12 +70,13 @@ impl GemmaImguiSupport {
|
||||
}
|
||||
});
|
||||
}
|
||||
pub fn system_controls(system_to_control: &mut Chip8Computer, gui_state: &mut ImGuiUiState, ui: &Ui) {
|
||||
pub fn system_controls(system_to_control: &mut Chip8ComputerManager, gui_state: &mut ImGuiUiState, ui: &Ui) {
|
||||
// let mut state: Chip8Computer = system_to_control;
|
||||
ui.window("!!!! CONTROLS !!!!")
|
||||
.size([345.0, 200.0], Condition::FirstUseEver)
|
||||
.build(|| {
|
||||
/* System Step Counter */
|
||||
ui.text(format!("Step {:04x}", system_to_control.num_cycles).as_str());
|
||||
ui.text(format!("Step {:04x}", system_to_control.num_cycles()).as_str());
|
||||
|
||||
/* ROM Lister */
|
||||
let new_filename = GuiFileList::display_path(PathBuf::from("resources/roms"), &gui_state.filename_to_load, ui);
|
||||
@@ -112,43 +87,39 @@ impl GemmaImguiSupport {
|
||||
}
|
||||
if ui.button("Load Program") {
|
||||
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(&("resources/roms/".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_memory(0x200, (&buffer).into());
|
||||
system_to_control.load_bytes_to_system_memory((&*buffer).into());
|
||||
}
|
||||
}
|
||||
ui.separator();
|
||||
if ui.button("Step") {
|
||||
system_to_control.step_system();
|
||||
system_to_control.one_step = true;
|
||||
};
|
||||
ui.same_line();
|
||||
if ui.button("Run") {
|
||||
gui_state.is_running = true;
|
||||
debug!("STARTING THE SYSTEM");
|
||||
system_to_control.core_should_run = true;
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Stop") {
|
||||
gui_state.is_running = false;
|
||||
debug!("STOPPING THE SYSTEM");
|
||||
system_to_control.core_should_run = false;
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Reset") {
|
||||
gui_state.is_running = false;
|
||||
*system_to_control = Chip8Computer::new();
|
||||
system_to_control.reset();
|
||||
}
|
||||
if ui.button("Dump Video Memory") {
|
||||
println!("{}", system_to_control.dump_video_to_string());
|
||||
println!("{}", system_to_control.dump_to_string(Video));
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Dump Keypad State") {
|
||||
debug!("{}", system_to_control.dump_keypad_to_string());
|
||||
debug!("{}", system_to_control.dump_to_string(Keyboard));
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Dump Registers") {
|
||||
debug!("{}", system_to_control.dump_registers_to_string());
|
||||
debug!("{}", system_to_control.dump_to_string(Registers));
|
||||
}
|
||||
ui.separator();
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
use std::ffi::OsString;
|
||||
use std::fs::read_dir;
|
||||
use std::path::PathBuf;
|
||||
use imgui::Ui;
|
||||
use log::debug;
|
||||
|
||||
pub struct GuiFileList {}
|
||||
|
||||
impl GuiFileList {
|
||||
pub fn display_path(root: PathBuf, selected_filename: &String, ui: &Ui) -> String {
|
||||
let mut working_filename = selected_filename.clone();
|
||||
ui.text(format!("Displaying {}", root.to_str().unwrap_or("Unable to parse path")));
|
||||
|
||||
let mut known_files: Vec<OsString> = vec![];
|
||||
|
||||
for entry in read_dir(root.as_path()).unwrap() {
|
||||
known_files.push(entry.unwrap().file_name());
|
||||
}
|
||||
|
||||
known_files.sort();
|
||||
|
||||
for (index, entry) in known_files.iter().enumerate() {
|
||||
let mut working_select = ui.selectable_config(format!("{}", entry.clone().into_string().unwrap()));
|
||||
if entry.to_str().unwrap().to_string() == selected_filename.as_str().to_string() {
|
||||
working_select = working_select.selected(true);
|
||||
}
|
||||
if working_select.build() {
|
||||
debug!("SELECTED {index} / {entry:?}");
|
||||
working_filename = entry.clone().into_string().unwrap();
|
||||
};
|
||||
}
|
||||
working_filename
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ use glium::glutin::surface::WindowSurface;
|
||||
use glium::{Display, Surface};
|
||||
use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui};
|
||||
use imgui_glium_renderer::Renderer;
|
||||
use imgui_winit_support::winit::dpi::LogicalSize;
|
||||
use imgui_winit_support::winit::event::{Event, WindowEvent};
|
||||
use imgui_winit_support::winit::event_loop::EventLoop;
|
||||
use imgui_winit_support::winit::window::WindowBuilder;
|
||||
@@ -12,6 +11,8 @@ use std::time::Instant;
|
||||
|
||||
pub mod ui_state;
|
||||
pub mod emmagui_support;
|
||||
mod gui_file_list;
|
||||
|
||||
use copypasta::{ClipboardContext, ClipboardProvider};
|
||||
use imgui::ClipboardBackend;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user