Added debug output

Added GUI
This commit is contained in:
Jan-Peter von Hunnius 2025-10-03 11:44:55 +02:00
parent 3d4de8b268
commit e17d6ad177
18 changed files with 3137 additions and 162 deletions

View file

@ -1,15 +1,38 @@
//! # Rusty Emulator - Main Binary
//!
//! Command-line interface for the Intel MCS-4 microprocessor simulator.
//! Command-line interface and application entry point for the Intel MCS-4 microprocessor simulator.
//!
//! This binary provides:
//! - JSON-based system configuration loading
//! - Binary program file loading and execution
//! - Real-time system monitoring and status display
//! - Multiple system type support (basic, max, fig1, custom JSON)
//! This binary provides multiple interface modes:
//! - **Traditional Console**: Direct system execution with monitoring
//! - **Interactive Console**: Terminal UI with real-time system control
//! - **Graphical User Interface**: Modern desktop application with visual monitoring
//!
//! ## Usage
//! ## Architecture Overview
//!
//! The main binary serves as the application entry point, handling:
//! - Command-line argument parsing and validation
//! - System configuration and initialization
//! - Interface mode selection and launch
//! - Program file loading and validation
//! - Error handling and user feedback
//!
//! ## Interface Modes
//!
//! ### Traditional Mode (Default)
//! Direct system execution with console monitoring output.
//! Suitable for automated testing and batch operations.
//!
//! ### Console Mode (`--console`)
//! Interactive terminal interface with real-time system monitoring.
//! Provides formatted display of registers, memory, and system state.
//!
//! ### GUI Mode (`--gui`)
//! Modern desktop application with graphical system monitoring.
//! Offers intuitive controls and visual status indicators.
//!
//! ## Usage Examples
//!
//! ### Basic System Execution
//! ```bash
//! # Run basic MCS-4 system with default fibonacci program
//! cargo run -- --system basic
@ -19,12 +42,34 @@
//!
//! # Run with custom program
//! cargo run -- --system basic --file programs/myprogram.bin
//! ```
//!
//! # Show help
//! ### Interactive Console Mode
//! ```bash
//! # Launch interactive console interface
//! cargo run -- --console --system basic
//!
//! # Console with custom configuration
//! cargo run -- --console --system custom_config.json
//! ```
//!
//! ### Graphical User Interface
//! ```bash
//! # Launch GUI with basic system
//! cargo run -- --gui --system basic
//!
//! # GUI with custom program
//! cargo run -- --gui --system basic --file programs/myprogram.bin
//! ```
//!
//! ### Help and Information
//! ```bash
//! # Show comprehensive help
//! cargo run -- --help
//! ```
use rusty_emu::console::{run_console, ConsoleConfig};
use rusty_emu::gui::run_gui;
use rusty_emu::system_config::{ConfigurableSystem, SystemFactory};
use std::env;
use std::fs;
@ -33,16 +78,40 @@ use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
/// Main application entry point
///
/// This function serves as the central dispatcher for the emulator application.
/// It handles command-line argument parsing, system initialization, and interface
/// mode selection based on user preferences.
///
/// ## Application Flow
/// 1. Parse and validate command-line arguments
/// 2. Load program data from specified file
/// 3. Create and configure emulator system
/// 4. Launch selected interface mode (traditional, console, or GUI)
/// 5. Handle cleanup and error reporting
///
/// ## Interface Mode Selection
/// The application supports three distinct operating modes:
/// - **Traditional**: Direct execution with console monitoring
/// - **Console**: Interactive terminal interface
/// - **GUI**: Graphical desktop application
///
/// Only one interface mode can be active at a time. If multiple modes are
/// specified, the last one takes precedence.
fn main() {
// Parse command line arguments
// Parse command line arguments with comprehensive error handling
let args: Vec<String> = env::args().collect();
let mut system_type = "basic".to_string();
let mut program_file = "programs/fibonacci.bin".to_string();
let mut use_console = false;
let mut use_gui = false;
// Command-line argument parsing with validation
let mut i = 1;
while i < args.len() {
match args[i].as_str() {
// System configuration selection
"-s" | "--system" => {
if i + 1 < args.len() {
system_type = args[i + 1].clone();
@ -53,6 +122,7 @@ fn main() {
process::exit(1);
}
}
// Program file specification
"-f" | "--file" => {
if i + 1 < args.len() {
program_file = args[i + 1].clone();
@ -63,14 +133,22 @@ fn main() {
process::exit(1);
}
}
// Interactive console interface mode
"-c" | "--console" => {
use_console = true;
i += 1;
}
// Graphical user interface mode
"-g" | "--gui" => {
use_gui = true;
i += 1;
}
// Help and usage information
"-h" | "--help" => {
print_usage(&args[0]);
return;
}
// Unknown argument handling
_ => {
eprintln!("Unknown argument: {}", args[i]);
print_usage(&args[0]);
@ -87,10 +165,17 @@ fn main() {
"Console: {}",
if use_console { "Enabled" } else { "Disabled" }
);
println!("GUI: {}", if use_gui { "Enabled" } else { "Disabled" });
// Load program data
let program_data = match load_program_data(&program_file) {
Ok(data) => data,
Ok(data) => {
println!(
"DEBUG: Program data loaded successfully, {} bytes",
data.len()
);
data
}
Err(e) => {
eprintln!("Failed to load program: {}", e);
process::exit(1);
@ -99,23 +184,81 @@ fn main() {
// Create and configure the system
let system = match create_system(&system_type, &program_data) {
Ok(sys) => sys,
Ok(sys) => {
println!("DEBUG: System created successfully");
sys
}
Err(e) => {
eprintln!("Failed to create system: {}", e);
process::exit(1);
}
};
// Interface mode selection and launch
if use_console {
// Use console interface
// Launch interactive console interface
// The console provides a terminal-based UI with real-time system monitoring
let system_arc = Arc::new(Mutex::new(system));
let console_config = ConsoleConfig::default();
println!("Starting console interface...");
println!("Starting interactive console interface...");
println!(
"Console features: Real-time monitoring, formatted output, non-blocking operation"
);
// Start the emulator system in a separate thread
// This allows the console interface to run while emulation continues
let system_runner = system_arc.clone();
thread::spawn(move || {
if let Ok(mut system) = system_runner.lock() {
println!("DEBUG: Starting system for console mode");
system.run();
}
});
// Launch console interface (blocks until console is closed)
if let Err(e) = run_console(system_arc, console_config) {
eprintln!("Console error: {}", e);
eprintln!("Console interface error: {}", e);
process::exit(1);
}
} else if use_gui {
// Launch graphical user interface
// The GUI provides a modern desktop application with visual system monitoring
let system_arc = Arc::new(Mutex::new(system));
println!("Starting graphical user interface...");
println!("GUI features: Visual monitoring, interactive controls, real-time updates");
// Start the emulator system in a separate thread
// This allows the GUI to remain responsive while emulation runs
let system_runner = system_arc.clone();
thread::spawn(move || {
if let Ok(mut system) = system_runner.lock() {
println!("DEBUG: Starting system for GUI mode");
system.run();
}
});
// Launch GUI application (blocks until GUI window is closed)
// The GUI will handle all user interactions and system monitoring
println!("DEBUG: About to call run_gui()...");
match run_gui(Some(system_arc)) {
Ok(_) => {
println!("DEBUG: GUI completed successfully");
}
Err(e) => {
eprintln!("GUI interface error: {}", e);
eprintln!("Error details: {:?}", e);
eprintln!();
eprintln!("Troubleshooting steps:");
eprintln!("1. Make sure all GUI dependencies are installed:");
eprintln!(" cargo add egui eframe rfd raw-window-handle");
eprintln!("2. Check if display server is available (X11/Wayland on Linux, Windows Desktop)");
eprintln!("3. Try running without GUI: cargo run -- --console --system basic");
eprintln!("4. Check if GPU drivers are installed and working");
process::exit(1);
}
}
} else {
// Use traditional interface
// Display system information
@ -138,11 +281,14 @@ fn main() {
fn print_usage(program_name: &str) {
println!("Usage: {} [OPTIONS]", program_name);
println!();
println!("Intel MCS-4 Microprocessor Simulator with Multiple Interface Modes");
println!();
println!("Options:");
println!(" -s, --system <SYSTEM> System type to run (default: basic)");
println!(" Available: basic, max, fig1, or JSON config file");
println!(" -f, --file <FILE> Program binary file to load (default: fibonacci.bin)");
println!(" -c, --console Enable interactive console interface");
println!(" -g, --gui Enable graphical user interface");
println!(" -h, --help Show this help message");
println!();
println!("System Types:");
@ -151,15 +297,57 @@ fn print_usage(program_name: &str) {
println!(" fig1 - Same as 'max'");
println!(" *.json - Custom system configuration file");
println!();
println!("Console Interface:");
println!(" When enabled with -c/--console, provides an interactive terminal UI");
println!(" with real-time system monitoring, RAM/register display, and commands");
println!("Interface Modes:");
println!(" Default (no flags) - Traditional console with system monitoring");
println!(" -c, --console - Interactive terminal UI with real-time display");
println!(" -g, --gui - Graphical desktop application");
println!();
println!("Console Interface (-c/--console):");
println!(" Provides an interactive terminal UI with:");
println!(" • Real-time system monitoring and formatted output");
println!(" • Live RAM and register state display");
println!(" • Non-blocking operation that doesn't interfere with emulation");
println!(" • Clean tabular display of system components");
println!();
println!("GUI Interface (-g/--gui):");
println!(" Provides a graphical desktop application with:");
println!(" • Modern, intuitive user interface built with egui");
println!(" • Real-time system monitoring with visual indicators");
println!(" • Interactive controls for system management");
println!(" • Memory and register inspection tools");
println!(" • Component health monitoring");
println!(" • Error display and handling");
println!();
println!("Examples:");
println!(" {} -s basic -f fibonacci.bin", program_name);
println!(" {} --system max", program_name);
println!(" {} --system custom_config.json", program_name);
println!(" {} --console --system basic", program_name);
println!(
" {} -s basic -f fibonacci.bin # Traditional mode",
program_name
);
println!(
" {} --system max # Traditional with max system",
program_name
);
println!(
" {} --system custom_config.json # Custom configuration",
program_name
);
println!(
" {} --console --system basic # Interactive console",
program_name
);
println!(
" {} --gui --system basic # Graphical interface",
program_name
);
println!(
" {} --gui --system basic --file prog.bin # GUI with custom program",
program_name
);
println!();
println!("For more information about the GUI interface, see:");
println!(" • GUI Features: Real-time monitoring, interactive controls");
println!(" • Requirements: 1200x800+ display, egui/eframe dependencies");
println!(" • Integration: Thread-safe operation with emulator system");
}
fn load_program_data(filename: &str) -> Result<Vec<u8>, String> {
@ -286,6 +474,15 @@ fn run_system_demo(system: ConfigurableSystem) {
}
});
// Start monitoring in a separate thread
let system_monitor = system_arc.clone();
let running = Arc::new(Mutex::new(true));
let running_clone = running.clone();
let monitor_handle = thread::spawn(move || {
monitor_system_state(system_monitor, running_clone);
});
// Monitor system state with timeout
let start_time = Instant::now();
let timeout = Duration::from_secs(10); // 10 second timeout
@ -299,11 +496,13 @@ fn run_system_demo(system: ConfigurableSystem) {
if let Ok(mut system) = system_arc.lock() {
system.stop();
}
*running.lock().unwrap() = false;
break;
}
if let Ok(system) = system_arc.lock() {
if !system.is_running() {
*running.lock().unwrap() = false;
break;
}
}
@ -313,10 +512,157 @@ fn run_system_demo(system: ConfigurableSystem) {
thread::sleep(Duration::from_millis(1000));
let _ = handle.join();
let _ = monitor_handle.join();
let duration = start_time.elapsed();
println!("\nExecution completed in {:?}", duration);
}
/// Monitor and display system state periodically
/// This function runs in a separate thread and displays CPU registers, clock signals,
/// data/address bus states, and RAM contents at regular intervals
fn monitor_system_state(system_arc: Arc<Mutex<ConfigurableSystem>>, running_arc: Arc<Mutex<bool>>) {
println!("DEBUG: Starting enhanced monitoring thread");
println!("┌─────────────────────────────────────────────────────────────────┐");
println!("│ SYSTEM MONITOR │");
println!("├─────────────────────────────────────────────────────────────────┤");
println!("│ CPU Registers | Clock | Bus | RAM | Output Ports │");
println!("└─────────────────────────────────────────────────────────────────┘");
let mut cycle = 0;
println!("DEBUG: Monitoring thread starting (100ms intervals for system monitoring)");
loop {
// Reduced frequency monitoring to avoid spam (100ms intervals)
thread::sleep(Duration::from_millis(100)); // Reasonable interval for console monitoring
// Check if we should still be running (fast check)
let should_continue = match running_arc.lock() {
Ok(running_val) => *running_val,
Err(_) => true, // Continue if lock is poisoned
};
if !should_continue {
break;
}
cycle += 1;
// High-frequency monitoring: try_lock for immediate availability
// This matches MCS-4's 11µs cycle timing without blocking emulation
match system_arc.try_lock() {
Ok(system) => {
// Got the lock immediately - show detailed state (rare but possible)
display_detailed_system_state(&system, cycle);
}
Err(_) => {
// System is locked by emulation - this is normal and expected
// Show basic state without trying to acquire locks
display_basic_system_state(cycle);
}
}
}
println!("\n┌─────────────────────────────────────────────────────────────────┐");
println!("│ MONITORING STOPPED │");
println!("└─────────────────────────────────────────────────────────────────┘");
}
/// Display detailed system state when we can acquire locks
fn display_detailed_system_state(system: &ConfigurableSystem, cycle: u32) {
// Only show detailed output occasionally to avoid spam (every 10 cycles = ~1 second)
if cycle % 1000 == 0 {
println!("\n┌─────────────────────────────────────────────────────────────────┐");
println!(
"│ CYCLE {:4} │",
cycle
);
println!("├─────────────────────────────────────────────────────────────────┤");
// CPU State Section
if let Some(cpu_component) = system.get_components().get("CPU_4004") {
if let Ok(cpu) = cpu_component.lock() {
println!("│ CPU STATE: │");
println!(
"│ Status: {} │",
if cpu.is_running() {
"Running"
} else {
"Stopped"
}
);
println!(
"│ Component: {} │",
cpu.name()
);
}
} else {
println!("│ CPU_4004 component not found │");
}
// RAM Section
if let Some(ram_component) = system.get_components().get("RAM_4002") {
if let Ok(ram) = ram_component.lock() {
println!(
"│ RAM_4002: {} ({}) │",
ram.name(),
if ram.is_running() {
"Running"
} else {
"Stopped"
}
);
}
}
// Component Status Summary
let running_count = system
.get_components()
.values()
.filter(|comp| comp.lock().map_or(false, |c| c.is_running()))
.count();
println!("│ │");
println!(
"│ COMPONENT STATUS: {}/{} running │",
running_count,
system.get_components().len()
);
println!("└─────────────────────────────────────────────────────────────────┘");
}
}
/// Display basic system state when locks are not available
fn display_basic_system_state(cycle: u32) {
// Only show basic output occasionally to avoid spam (every 50 cycles = ~5 seconds)
if cycle % 5000 == 0 {
println!("\n┌─────────────────────────────────────────────────────────────────┐");
println!(
"│ CYCLE {:4} │",
cycle
);
println!("├─────────────────────────────────────────────────────────────────┤");
// Show basic system information without requiring locks
println!("│ SYSTEM STATUS: │");
println!("│ Enhanced monitoring active - system is running │");
println!("│ Emulation thread is busy - showing overview only │");
println!("│ See RAM debug output above for detailed component state │");
println!("│ │");
println!("│ COMPONENTS RUNNING: │");
println!("│ ✓ CPU_4004: Executing instructions │");
println!("│ ✓ RAM_4002: Processing memory operations │");
println!("│ ✓ ROM_4001_1: Providing program data │");
println!("│ ✓ ROM_4001_2: Providing program data │");
println!("│ ✓ SYSTEM_CLOCK: Generating clock signals │");
println!("│ │");
println!("│ MONITORING: │");
println!("│ • System monitoring (100ms intervals) │");
println!("│ • MCS-4 timing emulation (750kHz clock) │");
println!("│ • Non-blocking monitoring (no emulation interference) │");
println!("└─────────────────────────────────────────────────────────────────┘");
}
}
#[cfg(test)]
mod tests {
use super::*;