Removed obsolete file
This commit is contained in:
parent
633463e370
commit
3cdf99630c
1 changed files with 0 additions and 515 deletions
515
src/console.rs
515
src/console.rs
|
|
@ -1,515 +0,0 @@
|
||||||
//! # Console Interface Module
|
|
||||||
//!
|
|
||||||
//! Interactive terminal-based user interface for the Intel MCS-4 emulator.
|
|
||||||
//! Provides real-time system monitoring, debugging capabilities, and user controls.
|
|
||||||
//!
|
|
||||||
//! ## Features
|
|
||||||
//! - Real-time RAM and register display
|
|
||||||
//! - Interactive command interface
|
|
||||||
//! - System state monitoring
|
|
||||||
//! - Configurable display options
|
|
||||||
//! - Graceful interrupt handling
|
|
||||||
|
|
||||||
use crossterm::{
|
|
||||||
event::{self, Event, KeyCode},
|
|
||||||
execute,
|
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
|
||||||
};
|
|
||||||
use ratatui::{
|
|
||||||
backend::CrosstermBackend,
|
|
||||||
layout::{Constraint, Direction, Layout, Rect},
|
|
||||||
style::{Color, Modifier, Style},
|
|
||||||
text::{Line, Span},
|
|
||||||
widgets::{Block, Borders, Paragraph, Wrap},
|
|
||||||
Frame, Terminal,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::io;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use std::thread;
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
use crate::system_config::ConfigurableSystem;
|
|
||||||
|
|
||||||
/// Console configuration structure
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct ConsoleConfig {
|
|
||||||
pub enabled: bool,
|
|
||||||
pub refresh_rate_ms: u64,
|
|
||||||
pub show_ram: bool,
|
|
||||||
pub show_registers: bool,
|
|
||||||
pub show_system_info: bool,
|
|
||||||
pub ram_banks_per_row: usize,
|
|
||||||
pub max_ram_rows: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ConsoleConfig {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
enabled: true,
|
|
||||||
refresh_rate_ms: 100,
|
|
||||||
show_ram: true,
|
|
||||||
show_registers: true,
|
|
||||||
show_system_info: true,
|
|
||||||
ram_banks_per_row: 4,
|
|
||||||
max_ram_rows: 5,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Console UI application state
|
|
||||||
pub struct ConsoleApp {
|
|
||||||
system: Arc<Mutex<ConfigurableSystem>>,
|
|
||||||
config: ConsoleConfig,
|
|
||||||
running: bool,
|
|
||||||
command_buffer: String,
|
|
||||||
show_help: bool,
|
|
||||||
selected_pane: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConsoleApp {
|
|
||||||
pub fn new(system: Arc<Mutex<ConfigurableSystem>>, config: ConsoleConfig) -> Self {
|
|
||||||
Self {
|
|
||||||
system,
|
|
||||||
config,
|
|
||||||
running: false,
|
|
||||||
command_buffer: String::new(),
|
|
||||||
show_help: false,
|
|
||||||
selected_pane: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
// Setup terminal
|
|
||||||
enable_raw_mode().map_err(|e| format!("Failed to enable raw mode: {}", e))?;
|
|
||||||
let mut stdout = io::stdout();
|
|
||||||
execute!(stdout, EnterAlternateScreen)
|
|
||||||
.map_err(|e| format!("Failed to enter alternate screen: {}", e))?;
|
|
||||||
|
|
||||||
let backend = CrosstermBackend::new(stdout);
|
|
||||||
let mut terminal = Terminal::new(backend)?;
|
|
||||||
|
|
||||||
self.running = true;
|
|
||||||
let mut last_draw = Instant::now();
|
|
||||||
|
|
||||||
// Main event loop
|
|
||||||
while self.running {
|
|
||||||
let now = Instant::now();
|
|
||||||
|
|
||||||
// Handle input
|
|
||||||
if let Ok(true) = event::poll(Duration::from_millis(10)) {
|
|
||||||
if let Ok(Event::Key(key)) = event::read() {
|
|
||||||
self.handle_key_event(key.code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update display at regular intervals
|
|
||||||
if now.duration_since(last_draw) >= Duration::from_millis(self.config.refresh_rate_ms) {
|
|
||||||
if let Err(e) = terminal.draw(|f| self.draw_ui(f)) {
|
|
||||||
eprintln!("DEBUG: Failed to draw UI: {}", e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last_draw = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if system should still be running
|
|
||||||
if let Ok(system) = self.system.lock() {
|
|
||||||
if !system.is_running() && !self.show_help {
|
|
||||||
// System stopped, show final state briefly
|
|
||||||
if let Err(e) = terminal.draw(|f| self.draw_ui(f)) {
|
|
||||||
eprintln!("DEBUG: Failed to draw final UI: {}", e);
|
|
||||||
}
|
|
||||||
thread::sleep(Duration::from_millis(500));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Small delay to prevent busy waiting
|
|
||||||
thread::sleep(Duration::from_millis(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore terminal
|
|
||||||
disable_raw_mode().map_err(|e| format!("Failed to disable raw mode: {}", e))?;
|
|
||||||
execute!(terminal.backend_mut(), LeaveAlternateScreen)
|
|
||||||
.map_err(|e| format!("Failed to leave alternate screen: {}", e))?;
|
|
||||||
terminal
|
|
||||||
.show_cursor()
|
|
||||||
.map_err(|e| format!("Failed to show cursor: {}", e))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_key_event(&mut self, key: KeyCode) {
|
|
||||||
match key {
|
|
||||||
KeyCode::Char('q') | KeyCode::Char('Q') | KeyCode::Esc => {
|
|
||||||
println!("DEBUG: Quit key pressed, stopping console");
|
|
||||||
self.running = false;
|
|
||||||
if let Ok(mut system) = self.system.lock() {
|
|
||||||
system.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KeyCode::Char('h') | KeyCode::Char('H') => {
|
|
||||||
println!("DEBUG: Help key pressed");
|
|
||||||
self.show_help = !self.show_help;
|
|
||||||
}
|
|
||||||
KeyCode::Char('r') | KeyCode::Char('R') => {
|
|
||||||
println!("DEBUG: Run key pressed");
|
|
||||||
if let Ok(mut system) = self.system.lock() {
|
|
||||||
if system.is_running() {
|
|
||||||
system.stop();
|
|
||||||
} else {
|
|
||||||
system.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KeyCode::Char('s') | KeyCode::Char('S') => {
|
|
||||||
println!("DEBUG: Stop key pressed");
|
|
||||||
if let Ok(mut system) = self.system.lock() {
|
|
||||||
system.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KeyCode::Char(' ') => {
|
|
||||||
println!("DEBUG: Space key pressed - single step not implemented");
|
|
||||||
// Single step (if supported)
|
|
||||||
// This would require adding step functionality to the system
|
|
||||||
}
|
|
||||||
KeyCode::Tab => {
|
|
||||||
println!("DEBUG: Tab key pressed - switching panes");
|
|
||||||
self.selected_pane = (self.selected_pane + 1) % 3;
|
|
||||||
}
|
|
||||||
KeyCode::Backspace => {
|
|
||||||
println!("DEBUG: Backspace key pressed");
|
|
||||||
self.command_buffer.pop();
|
|
||||||
}
|
|
||||||
KeyCode::Enter => {
|
|
||||||
println!(
|
|
||||||
"DEBUG: Enter key pressed - executing command: '{}'",
|
|
||||||
self.command_buffer
|
|
||||||
);
|
|
||||||
self.execute_command();
|
|
||||||
self.command_buffer.clear();
|
|
||||||
}
|
|
||||||
KeyCode::Char(c) => {
|
|
||||||
println!("DEBUG: Character key pressed: '{}'", c);
|
|
||||||
if c.is_ascii_alphabetic() || c.is_ascii_digit() {
|
|
||||||
self.command_buffer.push(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
println!("DEBUG: Unhandled key pressed: {:?}", key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_command(&mut self) {
|
|
||||||
let cmd = self.command_buffer.trim().to_lowercase();
|
|
||||||
println!("DEBUG: Executing command: '{}'", cmd);
|
|
||||||
|
|
||||||
match cmd.as_str() {
|
|
||||||
"quit" | "exit" | "q" => {
|
|
||||||
println!("DEBUG: Executing quit command");
|
|
||||||
self.running = false;
|
|
||||||
if let Ok(mut system) = self.system.lock() {
|
|
||||||
system.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"run" | "r" => {
|
|
||||||
println!("DEBUG: Executing run command");
|
|
||||||
if let Ok(mut system) = self.system.lock() {
|
|
||||||
system.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"stop" | "s" => {
|
|
||||||
println!("DEBUG: Executing stop command");
|
|
||||||
if let Ok(mut system) = self.system.lock() {
|
|
||||||
system.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"help" | "h" => {
|
|
||||||
println!("DEBUG: Toggling help display");
|
|
||||||
self.show_help = !self.show_help;
|
|
||||||
}
|
|
||||||
"reset" => {
|
|
||||||
println!("DEBUG: Executing reset command");
|
|
||||||
if let Ok(mut system) = self.system.lock() {
|
|
||||||
system.stop();
|
|
||||||
// Reset would need to be implemented in the system
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"status" => {
|
|
||||||
println!("DEBUG: Executing status command");
|
|
||||||
if let Ok(system) = self.system.lock() {
|
|
||||||
let info = system.get_system_info();
|
|
||||||
println!("System: {} - {}", info.name, info.description);
|
|
||||||
println!(
|
|
||||||
"Components: {}, Running: {}",
|
|
||||||
info.component_count,
|
|
||||||
system.is_running()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"ram" => {
|
|
||||||
println!("DEBUG: Executing RAM display command");
|
|
||||||
if let Ok(_system) = self.system.lock() {
|
|
||||||
println!("RAM display requested - would show RAM contents here");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"" => {
|
|
||||||
// Empty command - do nothing
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
println!("DEBUG: Unknown command: '{}'", cmd);
|
|
||||||
println!("Available commands: quit, run, stop, help, reset, status, ram");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_ui(&self, f: &mut Frame) {
|
|
||||||
let size = f.size();
|
|
||||||
|
|
||||||
if self.show_help {
|
|
||||||
self.draw_help_screen(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create main layout with proper constraints
|
|
||||||
let chunks = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints([
|
|
||||||
Constraint::Length(4), // Title bar
|
|
||||||
Constraint::Min(8), // Main content
|
|
||||||
Constraint::Length(3), // Command bar
|
|
||||||
])
|
|
||||||
.split(size);
|
|
||||||
|
|
||||||
// Title bar
|
|
||||||
let title_text = vec![
|
|
||||||
Line::from(vec![Span::styled(
|
|
||||||
"Intel MCS-4 Emulator Console",
|
|
||||||
Style::default()
|
|
||||||
.fg(Color::Cyan)
|
|
||||||
.add_modifier(Modifier::BOLD),
|
|
||||||
)]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::raw("Commands: "),
|
|
||||||
Span::styled("q/Q", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw("=quit, "),
|
|
||||||
Span::styled("r/R", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw("=run, "),
|
|
||||||
Span::styled("s/S", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw("=stop, "),
|
|
||||||
Span::styled("h/H", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw("=help"),
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
|
|
||||||
let title = Paragraph::new(title_text)
|
|
||||||
.block(Block::default().borders(Borders::ALL).title("Status"))
|
|
||||||
.wrap(Wrap { trim: true });
|
|
||||||
f.render_widget(title, chunks[0]);
|
|
||||||
|
|
||||||
// Main content area
|
|
||||||
let content_chunks = Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.constraints([
|
|
||||||
Constraint::Percentage(50), // Left pane
|
|
||||||
Constraint::Percentage(50), // Right pane
|
|
||||||
])
|
|
||||||
.split(chunks[1]);
|
|
||||||
|
|
||||||
// Left pane - System info and registers
|
|
||||||
self.draw_system_info(f, content_chunks[0]);
|
|
||||||
|
|
||||||
// Right pane - RAM contents
|
|
||||||
self.draw_ram_contents(f, content_chunks[1]);
|
|
||||||
|
|
||||||
// Command bar
|
|
||||||
let command_text = if self.command_buffer.is_empty() {
|
|
||||||
"Enter command (type 'h' for help)..."
|
|
||||||
} else {
|
|
||||||
&self.command_buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
let command_bar = Paragraph::new(command_text)
|
|
||||||
.style(Style::default().fg(Color::White))
|
|
||||||
.block(Block::default().borders(Borders::ALL).title("Command"));
|
|
||||||
f.render_widget(command_bar, chunks[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_help_screen(&self, f: &mut Frame) {
|
|
||||||
let size = f.size();
|
|
||||||
let help_text = vec![
|
|
||||||
Line::from(vec![Span::styled(
|
|
||||||
"Intel MCS-4 Emulator Console Help",
|
|
||||||
Style::default()
|
|
||||||
.fg(Color::Cyan)
|
|
||||||
.add_modifier(Modifier::BOLD),
|
|
||||||
)]),
|
|
||||||
Line::from(""),
|
|
||||||
Line::from(vec![Span::styled(
|
|
||||||
"Commands:",
|
|
||||||
Style::default().add_modifier(Modifier::BOLD),
|
|
||||||
)]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::styled(" q, quit, exit", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw(" - Exit emulator"),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::styled(" r, run", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw(" - Start/stop system execution"),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::styled(" s, stop", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw(" - Stop system execution"),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::styled(" h, help", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw(" - Show/hide this help"),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::styled(" reset", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw(" - Reset system"),
|
|
||||||
]),
|
|
||||||
Line::from(""),
|
|
||||||
Line::from(vec![Span::styled(
|
|
||||||
"Navigation:",
|
|
||||||
Style::default().add_modifier(Modifier::BOLD),
|
|
||||||
)]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::styled(" Tab", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw(" - Switch between panes"),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::styled(" Enter", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw(" - Execute command"),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
Span::styled(" Backspace", Style::default().fg(Color::Yellow)),
|
|
||||||
Span::raw(" - Delete character"),
|
|
||||||
]),
|
|
||||||
Line::from(""),
|
|
||||||
Line::from(vec![Span::raw("Press any key to return to main view...")]),
|
|
||||||
];
|
|
||||||
|
|
||||||
let help = Paragraph::new(help_text)
|
|
||||||
.style(Style::default().fg(Color::White))
|
|
||||||
.wrap(Wrap { trim: true })
|
|
||||||
.block(Block::default().borders(Borders::ALL).title("Help"));
|
|
||||||
f.render_widget(help, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_system_info(&self, f: &mut Frame, area: Rect) {
|
|
||||||
let info_chunks = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints([
|
|
||||||
Constraint::Length(8), // System info
|
|
||||||
Constraint::Min(5), // Registers
|
|
||||||
])
|
|
||||||
.split(area);
|
|
||||||
|
|
||||||
// System information
|
|
||||||
let system_info = match self.system.lock() {
|
|
||||||
Ok(system) => match system.get_system_info() {
|
|
||||||
info => vec![
|
|
||||||
Line::from(vec![Span::raw(format!("System: {}", info.name))]),
|
|
||||||
Line::from(vec![Span::raw(format!(
|
|
||||||
"Description: {}",
|
|
||||||
info.description
|
|
||||||
))]),
|
|
||||||
Line::from(vec![Span::raw(format!(
|
|
||||||
"Components: {}",
|
|
||||||
info.component_count
|
|
||||||
))]),
|
|
||||||
Line::from(vec![Span::raw(format!("CPU Speed: {} Hz", info.cpu_speed))]),
|
|
||||||
Line::from(vec![Span::raw(format!(
|
|
||||||
"ROM Size: {} bytes",
|
|
||||||
info.rom_size
|
|
||||||
))]),
|
|
||||||
Line::from(vec![Span::raw(format!(
|
|
||||||
"RAM Size: {} nibbles",
|
|
||||||
info.ram_size
|
|
||||||
))]),
|
|
||||||
Line::from(vec![Span::raw(format!("Running: {}", system.is_running()))]),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
Err(_) => {
|
|
||||||
vec![Line::from(vec![Span::raw(
|
|
||||||
"System information unavailable",
|
|
||||||
)])]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let system_widget = Paragraph::new(system_info)
|
|
||||||
.block(
|
|
||||||
Block::default()
|
|
||||||
.borders(Borders::ALL)
|
|
||||||
.title("System Information"),
|
|
||||||
)
|
|
||||||
.wrap(Wrap { trim: true });
|
|
||||||
f.render_widget(system_widget, info_chunks[0]);
|
|
||||||
|
|
||||||
// CPU register display (enhanced with execution status)
|
|
||||||
let register_info = vec![
|
|
||||||
Line::from(vec![Span::raw("CPU Registers:")]),
|
|
||||||
Line::from(vec![Span::raw("Status: Running (check console output)")]),
|
|
||||||
Line::from(vec![Span::raw("PC: 0x000 (see DEBUG output)")]),
|
|
||||||
Line::from(vec![Span::raw("ACC: 0x0 (see DEBUG output)")]),
|
|
||||||
Line::from(vec![Span::raw(
|
|
||||||
"Instructions: Executing (see DEBUG output)",
|
|
||||||
)]),
|
|
||||||
];
|
|
||||||
|
|
||||||
let register_widget = Paragraph::new(register_info)
|
|
||||||
.block(
|
|
||||||
Block::default()
|
|
||||||
.borders(Borders::ALL)
|
|
||||||
.title("CPU Registers"),
|
|
||||||
)
|
|
||||||
.wrap(Wrap { trim: true });
|
|
||||||
f.render_widget(register_widget, info_chunks[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_ram_contents(&self, f: &mut Frame, area: Rect) {
|
|
||||||
let mut ram_info = vec![Line::from(vec![Span::raw("RAM Contents:")])];
|
|
||||||
|
|
||||||
// Try to get actual RAM data from the system
|
|
||||||
match self.system.lock() {
|
|
||||||
Ok(_system) => {
|
|
||||||
// This is a simplified version - in a real implementation,
|
|
||||||
// we would need to access the actual RAM components
|
|
||||||
// For now, show a more informative placeholder
|
|
||||||
ram_info.push(Line::from(vec![Span::raw("Reading RAM contents...")]));
|
|
||||||
|
|
||||||
// Show some sample memory ranges
|
|
||||||
for bank in 0..4 {
|
|
||||||
let mut bank_data = format!("Bank {}: [", bank);
|
|
||||||
for i in 0..20 {
|
|
||||||
if i > 0 && i % 4 == 0 {
|
|
||||||
bank_data.push(' ');
|
|
||||||
}
|
|
||||||
bank_data.push_str("00");
|
|
||||||
}
|
|
||||||
bank_data.push(']');
|
|
||||||
ram_info.push(Line::from(vec![Span::raw(bank_data)]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
ram_info.push(Line::from(vec![Span::raw("Unable to access RAM data")]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ram_widget = Paragraph::new(ram_info)
|
|
||||||
.block(Block::default().borders(Borders::ALL).title("RAM Contents"))
|
|
||||||
.wrap(Wrap { trim: true });
|
|
||||||
f.render_widget(ram_widget, area);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Public interface for launching the console
|
|
||||||
pub fn run_console(
|
|
||||||
system: Arc<Mutex<ConfigurableSystem>>,
|
|
||||||
config: ConsoleConfig,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut app = ConsoleApp::new(system, config);
|
|
||||||
app.run()
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue