Unified the 400x state machine for address latching

Fixed timing issues
This commit is contained in:
Jan-Peter von Hunnius 2025-11-14 18:51:10 +01:00
parent e17d6ad177
commit 633463e370
26 changed files with 11904 additions and 2471 deletions

View file

@ -6,7 +6,7 @@
#![cfg(test)]
use rusty_emu::gui::{run_gui, GuiApp};
use rusty_emu::gui::GuiApp;
use rusty_emu::system_config::{ConfigurableSystem, SystemFactory};
use std::sync::{Arc, Mutex};
use std::thread;
@ -18,6 +18,7 @@ mod gui_integration_test_utils {
/// Create a test system for integration testing
pub fn create_test_system() -> Arc<Mutex<ConfigurableSystem>> {
println!("Starting create_test_system");
let factory = SystemFactory::new();
Arc::new(Mutex::new(
factory.create_from_json("configs/mcs4_basic.json").unwrap(),
@ -34,7 +35,7 @@ mod gui_integration_test_utils {
/// Simulate GUI state updates over time
pub fn simulate_gui_updates(system: &Arc<Mutex<ConfigurableSystem>>) {
// Simulate the kind of updates that would happen in the GUI thread
if let Ok(mut system_guard) = system.lock() {
if let Ok(system_guard) = system.lock() {
// Simulate some system activity
let _ = system_guard.is_running(); // Access system state
}
@ -79,12 +80,7 @@ mod gui_system_integration_tests {
let system_clone = Arc::clone(&system);
// Test that GUI can be created with a system
let mut app = GuiApp::new(&eframe::CreationContext {
egui_ctx: Default::default(),
integration_info: Default::default(),
storage: None,
build_info: Default::default(),
});
let mut app = GuiApp::new_for_test();
// Set the system
app.set_system(system);
@ -105,12 +101,7 @@ mod gui_system_integration_tests {
fn test_gui_state_synchronization() {
let system = create_test_system();
let mut app = GuiApp::new(&eframe::CreationContext {
egui_ctx: Default::default(),
integration_info: Default::default(),
storage: None,
build_info: Default::default(),
});
let mut app = GuiApp::new_for_test();
app.set_system(Arc::clone(&system));
@ -136,6 +127,24 @@ mod gui_system_integration_tests {
assert!(thread_safety_ok, "System should support thread-safe access");
}
#[test]
fn test_gui_invalid_system_handling() {
// Test GUI behavior with invalid or corrupted system state
let system = create_mock_system();
let mut app = GuiApp::new_for_test();
// Test setting system that might be invalid
app.set_system(system);
// GUI should handle this gracefully
assert!(app.gui_state.system_loaded);
// Test error state handling
app.gui_state.set_error("System access error".to_string());
assert_eq!(app.gui_state.get_error(), Some("System access error"));
}
#[test]
fn test_gui_concurrent_state_access() {
let system = create_test_system();
@ -147,8 +156,7 @@ mod gui_system_integration_tests {
thread::spawn(move || {
// Simulate GUI update pattern
for _ in 0..10 {
if let Ok(mut system_guard) = system_clone.lock() {
let _ = system_guard.is_running();
if let Ok(_system_guard) = system_clone.lock() {
// Simulate some processing time
thread::sleep(Duration::from_micros(10));
}
@ -193,7 +201,8 @@ mod gui_system_integration_tests {
// Test the polling mechanism that GUI would use
for i in 0..10 {
if let Ok(system_guard) = system.lock() {
{
let system_guard = system.lock().unwrap();
let is_running = system_guard.is_running();
// Simulate state updates that would happen in GUI
@ -203,7 +212,7 @@ mod gui_system_integration_tests {
// Simulate state change at midpoint
assert!(is_running || !is_running); // Just verify we can read state
}
}
} // system_guard is dropped here
// Small delay to simulate GUI update interval
thread::sleep(Duration::from_micros(100));
@ -217,17 +226,18 @@ mod gui_system_integration_tests {
// Test memory state structure for GUI integration
// In a real implementation, this would test actual memory access
if let Ok(system_guard) = system.lock() {
{
let system_guard = system.lock().unwrap();
// Test that system provides memory information
let _ = system_guard.get_system_info(); // Access system info
} // system_guard is dropped here
// Verify GUI state can hold memory data
let gui_state = rusty_emu::gui::state::GuiState::new();
assert_eq!(gui_state.memory_state.ram_contents.len(), 4);
// Verify GUI state can hold memory data
let gui_state = rusty_emu::gui::state::GuiState::new();
assert_eq!(gui_state.memory_state.ram_contents.len(), 4);
for bank in &gui_state.memory_state.ram_contents {
assert_eq!(bank.len(), 4);
}
for bank in &gui_state.memory_state.ram_contents {
assert_eq!(bank.len(), 4);
}
}
@ -236,19 +246,20 @@ mod gui_system_integration_tests {
let system = create_test_system();
// Test register state structure for GUI integration
if let Ok(_system_guard) = system.lock() {
{
let _system_guard = system.lock().unwrap();
// In a real implementation, this would access actual CPU registers
// For now, we test the GUI state structure
let gui_state = rusty_emu::gui::state::GuiState::new();
// Verify register state structure
assert_eq!(gui_state.register_state.accumulator, 0);
assert!(!gui_state.register_state.carry_flag);
assert_eq!(gui_state.register_state.program_counter, 0);
assert_eq!(gui_state.register_state.index_registers.len(), 16);
assert_eq!(gui_state.register_state.stack_pointer, 0);
}
let gui_state = rusty_emu::gui::state::GuiState::new();
// Verify register state structure
assert_eq!(gui_state.register_state.accumulator, 0);
assert!(!gui_state.register_state.carry_flag);
assert_eq!(gui_state.register_state.program_counter, 0);
assert_eq!(gui_state.register_state.index_registers.len(), 16);
assert_eq!(gui_state.register_state.stack_pointer, 0);
}
#[test]
@ -256,21 +267,22 @@ mod gui_system_integration_tests {
let system = create_test_system();
// Test component state monitoring for GUI
if let Ok(system_guard) = system.lock() {
{
let system_guard = system.lock().unwrap();
let components = system_guard.get_components();
// Test that components are accessible (GUI would monitor these)
assert!(!components.is_empty());
} // system_guard is dropped here
// Test GUI state structure for component monitoring
let gui_state = rusty_emu::gui::state::GuiState::new();
// Test GUI state structure for component monitoring
let gui_state = rusty_emu::gui::state::GuiState::new();
// Verify component state structure
assert!(!gui_state.component_states.cpu_running);
assert!(!gui_state.component_states.ram_running);
assert!(!gui_state.component_states.rom_running);
assert!(!gui_state.component_states.clock_running);
}
// Verify component state structure
assert!(!gui_state.component_states.cpu_running);
assert!(!gui_state.component_states.ram_running);
assert!(!gui_state.component_states.rom_running);
assert!(!gui_state.component_states.clock_running);
}
#[test]
@ -279,12 +291,7 @@ mod gui_system_integration_tests {
let system = create_test_system();
// Test GUI creation and system integration
let mut app = GuiApp::new(&eframe::CreationContext {
egui_ctx: Default::default(),
integration_info: Default::default(),
storage: None,
build_info: Default::default(),
});
let mut app = GuiApp::new_for_test();
app.set_system(system);
@ -299,16 +306,18 @@ mod gui_system_integration_tests {
#[test]
fn test_gui_performance_characteristics() {
println!("Starting test_gui_performance_characteristics");
let system = create_test_system();
// Test GUI update performance characteristics
let start_time = std::time::Instant::now();
for _ in 0..100 {
if let Ok(_system_guard) = system.lock() {
{
let _system_guard = system.lock().unwrap();
// Simulate GUI state update
simulate_gui_updates(&system);
}
} // _system_guard is dropped here
}
let elapsed = start_time.elapsed();
@ -342,18 +351,13 @@ mod gui_system_integration_tests {
let system = create_test_system();
// Test that GUI state remains consistent during updates
let mut app = GuiApp::new(&eframe::CreationContext {
egui_ctx: Default::default(),
integration_info: Default::default(),
storage: None,
build_info: Default::default(),
});
let mut app = GuiApp::new_for_test();
app.set_system(Arc::clone(&system));
// Simulate multiple state updates
for i in 0..10 {
if let Some(sys) = app.get_system() {
if let Some(_sys) = app.get_system() {
// In a real implementation, this would call update_from_system
// For now, we verify the state structure remains consistent
@ -381,12 +385,7 @@ mod gui_error_handling_tests {
// Test GUI behavior with invalid or corrupted system state
let system = create_mock_system();
let mut app = GuiApp::new(&eframe::CreationContext {
egui_ctx: Default::default(),
integration_info: Default::default(),
storage: None,
build_info: Default::default(),
});
let mut app = GuiApp::new_for_test();
// Test setting system that might be invalid
app.set_system(system);
@ -410,7 +409,7 @@ mod gui_error_handling_tests {
thread::spawn(move || {
state_clone.set_error(format!("Error from thread {}", i));
thread::sleep(Duration::from_micros(10));
state_clone.get_error()
state_clone.get_error().map(|s| s.to_string())
})
})
.collect();
@ -484,7 +483,8 @@ mod gui_real_time_tests {
let mut last_cycle_count = 0;
for i in 0..20 {
if let Ok(_system_guard) = system.lock() {
{
let _system_guard = system.lock().unwrap();
// Simulate GUI state polling
update_count += 1;
@ -493,9 +493,9 @@ mod gui_real_time_tests {
// In real implementation, this would be: gui_state.cycle_count = system.get_cycle_count()
last_cycle_count = i; // Simulate increasing cycle count
}
} // _system_guard is dropped here
thread::sleep(Duration::from_micros(50)); // Simulate GUI update interval
}
thread::sleep(Duration::from_micros(50)); // Simulate GUI update interval
}
assert_eq!(update_count, 20);
@ -510,10 +510,11 @@ mod gui_real_time_tests {
let start_time = std::time::Instant::now();
for _ in 0..50 {
if let Ok(_system_guard) = system.lock() {
{
let _system_guard = system.lock().unwrap();
// Simulate rapid GUI updates
simulate_gui_updates(&system);
}
} // _system_guard is dropped here
}
let elapsed = start_time.elapsed();
@ -533,21 +534,23 @@ mod gui_real_time_tests {
// In a real implementation, this would test actual memory synchronization
// For now, we test the data structures are compatible
if let Ok(_system_guard) = system.lock() {
{
let _system_guard = system.lock().unwrap();
// Test memory data structure compatibility
let gui_state = rusty_emu::gui::state::GuiState::new();
// Verify memory layout matches expected Intel 4002 structure
assert_eq!(gui_state.memory_state.ram_contents.len(), 4); // 4 banks
for bank in &gui_state.memory_state.ram_contents {
assert_eq!(bank.len(), 4); // 4 bytes per bank
}
// Test bank selection bounds
gui_state.memory_state.selected_bank = 0;
gui_state.memory_state.selected_bank = 3; // Should be valid
}
let mut gui_state = rusty_emu::gui::state::GuiState::new();
// Verify memory layout matches expected Intel 4002 structure
assert_eq!(gui_state.memory_state.ram_contents.len(), 4); // 4 banks
for bank in &gui_state.memory_state.ram_contents {
assert_eq!(bank.len(), 4); // 4 bytes per bank
}
// Test bank selection bounds
gui_state.memory_state.selected_bank = 0;
gui_state.memory_state.selected_bank = 3; // Should be valid
}
#[test]
@ -555,21 +558,23 @@ mod gui_real_time_tests {
// Test register state synchronization between system and GUI
let system = create_test_system();
if let Ok(_system_guard) = system.lock() {
let gui_state = rusty_emu::gui::state::GuiState::new();
// Verify register layout matches Intel 4004 structure
assert_eq!(gui_state.register_state.index_registers.len(), 16); // 16 index registers
// Test register value bounds
gui_state.register_state.accumulator = 0x0F; // 4-bit value (0-15)
gui_state.register_state.carry_flag = true;
// Test program counter bounds (12-bit address)
gui_state.register_state.program_counter = 0xFFF; // Maximum 12-bit value
// Test stack pointer bounds (4-bit value)
gui_state.register_state.stack_pointer = 0x0F; // Maximum 4-bit value
{
let _system_guard = system.lock().unwrap();
}
let mut gui_state = rusty_emu::gui::state::GuiState::new();
// Verify register layout matches Intel 4004 structure
assert_eq!(gui_state.register_state.index_registers.len(), 16); // 16 index registers
// Test register value bounds
gui_state.register_state.accumulator = 0x0F; // 4-bit value (0-15)
gui_state.register_state.carry_flag = true;
// Test program counter bounds (12-bit address)
gui_state.register_state.program_counter = 0xFFF; // Maximum 12-bit value
// Test stack pointer bounds (4-bit value)
gui_state.register_state.stack_pointer = 0x0F; // Maximum 4-bit value
}
}