feat: migrate to parking_lot mutex and add system control architecture
This commit is contained in:
parent
14060e15e5
commit
54144d10e9
29 changed files with 2387 additions and 1130 deletions
|
|
@ -6,9 +6,10 @@
|
|||
|
||||
#![cfg(test)]
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use rusty_emu::gui::GuiApp;
|
||||
use rusty_emu::system_config::{ConfigurableSystem, SystemFactory};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
|
|
@ -36,7 +37,8 @@ mod gui_integration_test_utils {
|
|||
/// Note: This function acquires the lock internally. Do NOT call it while holding the lock.
|
||||
pub fn simulate_gui_updates(system: &Arc<Mutex<ConfigurableSystem>>) {
|
||||
// Simulate the kind of updates that would happen in the GUI thread
|
||||
if let Ok(system_guard) = system.lock() {
|
||||
let system_guard = system.lock();
|
||||
{
|
||||
// Simulate some system activity
|
||||
let _ = system_guard.is_running(); // Access system state
|
||||
}
|
||||
|
|
@ -48,14 +50,19 @@ mod gui_integration_test_utils {
|
|||
|
||||
// Spawn a thread that accesses the system
|
||||
let handle = thread::spawn(move || {
|
||||
// Try to acquire the lock - return true if successful (regardless of is_running value)
|
||||
system_clone.lock().is_ok()
|
||||
// Try to acquire the lock - return true if successful (parking_lot::lock always succeeds)
|
||||
let _guard = system_clone.lock();
|
||||
true
|
||||
});
|
||||
|
||||
// Main thread also accesses the system
|
||||
let main_thread_result = system.lock().is_ok();
|
||||
// Main thread also accesses the system - but release lock before joining to avoid deadlock
|
||||
{
|
||||
let _guard = system.lock();
|
||||
// Access the system while holding the lock
|
||||
}
|
||||
let main_thread_result = true;
|
||||
|
||||
// Wait for spawned thread
|
||||
// Wait for spawned thread (lock is released, so no deadlock)
|
||||
let spawned_thread_result = handle.join().unwrap_or(false);
|
||||
|
||||
// Both threads should be able to acquire the lock without deadlock
|
||||
|
|
@ -150,7 +157,8 @@ mod gui_system_integration_tests {
|
|||
thread::spawn(move || {
|
||||
// Simulate GUI update pattern
|
||||
for _ in 0..10 {
|
||||
if let Ok(_system_guard) = system_clone.lock() {
|
||||
let _system_guard = system_clone.lock();
|
||||
{
|
||||
// Simulate some processing time
|
||||
thread::sleep(Duration::from_micros(10));
|
||||
}
|
||||
|
|
@ -196,7 +204,7 @@ mod gui_system_integration_tests {
|
|||
// Test the polling mechanism that GUI would use
|
||||
for i in 0..10 {
|
||||
{
|
||||
let system_guard = system.lock().unwrap();
|
||||
let system_guard = system.lock();
|
||||
let is_running = system_guard.is_running();
|
||||
|
||||
// Simulate state updates that would happen in GUI
|
||||
|
|
@ -221,7 +229,7 @@ mod gui_system_integration_tests {
|
|||
// In a real implementation, this would test actual memory access
|
||||
|
||||
{
|
||||
let system_guard = system.lock().unwrap();
|
||||
let system_guard = system.lock();
|
||||
// Test that system provides memory information
|
||||
let _ = system_guard.get_system_info(); // Access system info
|
||||
} // system_guard is dropped here
|
||||
|
|
@ -241,7 +249,7 @@ mod gui_system_integration_tests {
|
|||
|
||||
// Test register state structure for GUI integration
|
||||
{
|
||||
let _system_guard = system.lock().unwrap();
|
||||
let _system_guard = system.lock();
|
||||
// In a real implementation, this would access actual CPU registers
|
||||
// For now, we test the GUI state structure
|
||||
}
|
||||
|
|
@ -262,7 +270,7 @@ mod gui_system_integration_tests {
|
|||
|
||||
// Test component state monitoring for GUI
|
||||
{
|
||||
let system_guard = system.lock().unwrap();
|
||||
let system_guard = system.lock();
|
||||
let components = system_guard.get_components();
|
||||
|
||||
// Test that components are accessible (GUI would monitor these)
|
||||
|
|
@ -434,18 +442,19 @@ mod gui_error_handling_tests {
|
|||
// Hold the lock for a short time to simulate contention
|
||||
let system_clone = Arc::clone(&system);
|
||||
let lock_handle = thread::spawn(move || {
|
||||
if let Ok(_system_guard) = system_clone.lock() {
|
||||
let _system_guard = system_clone.lock();
|
||||
{
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
});
|
||||
|
||||
// Try to access from main thread (should not deadlock)
|
||||
let access_result = system.try_lock().is_ok();
|
||||
let access_result = system.try_lock().is_some();
|
||||
|
||||
lock_handle.join().unwrap();
|
||||
|
||||
// Should be able to access after the lock is released
|
||||
assert!(access_result || system.try_lock().is_ok());
|
||||
assert!(access_result || system.try_lock().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -481,7 +490,7 @@ mod gui_real_time_tests {
|
|||
|
||||
for i in 0..20 {
|
||||
{
|
||||
let _system_guard = system.lock().unwrap();
|
||||
let _system_guard = system.lock();
|
||||
// Simulate GUI state polling
|
||||
update_count += 1;
|
||||
|
||||
|
|
@ -535,7 +544,7 @@ mod gui_real_time_tests {
|
|||
// For now, we test the data structures are compatible
|
||||
|
||||
{
|
||||
let _system_guard = system.lock().unwrap();
|
||||
let _system_guard = system.lock();
|
||||
// Test memory data structure compatibility
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +568,7 @@ mod gui_real_time_tests {
|
|||
let system = create_test_system();
|
||||
|
||||
{
|
||||
let _system_guard = system.lock().unwrap();
|
||||
let _system_guard = system.lock();
|
||||
}
|
||||
|
||||
let mut gui_state = rusty_emu::gui::state::GuiState::new();
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
#![cfg(test)]
|
||||
|
||||
use eframe::egui;
|
||||
use parking_lot::Mutex;
|
||||
use rusty_emu::gui::components::*;
|
||||
use rusty_emu::gui::state::*;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Test utilities for GUI testing
|
||||
mod gui_test_utils {
|
||||
|
|
@ -304,7 +305,8 @@ mod gui_integration_tests {
|
|||
// For now, we verify the components exist and have valid state
|
||||
|
||||
// Test control panel rendering (would panic if component is invalid)
|
||||
components.render_control_panel(&mut create_test_ui(&ctx), &mut state);
|
||||
// Note: render_control_panel now takes an optional system parameter
|
||||
components.render_control_panel(&mut create_test_ui(&ctx), &mut state, None);
|
||||
|
||||
// Test memory viewer rendering
|
||||
components.render_memory_viewer(&mut create_test_ui(&ctx), &mut state);
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Initialize clock pins to Low
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
|
@ -47,10 +47,10 @@ fn test_intel_4001_state_machine_progression() {
|
|||
// Initialize control pins
|
||||
// Note: RESET is active LOW, so set it to High to ensure component is not in reset
|
||||
{
|
||||
let mut sync_guard = sync_pin.lock().unwrap();
|
||||
let mut cm_guard = cm_pin.lock().unwrap();
|
||||
let mut ci_guard = ci_pin.lock().unwrap();
|
||||
let mut reset_guard = reset_pin.lock().unwrap();
|
||||
let mut sync_guard = sync_pin.lock();
|
||||
let mut cm_guard = cm_pin.lock();
|
||||
let mut ci_guard = ci_pin.lock();
|
||||
let mut reset_guard = reset_pin.lock();
|
||||
sync_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
ci_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
|
|
@ -59,10 +59,10 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Initialize data pins to Low
|
||||
{
|
||||
let mut d0_guard = d0_pin.lock().unwrap();
|
||||
let mut d1_guard = d1_pin.lock().unwrap();
|
||||
let mut d2_guard = d2_pin.lock().unwrap();
|
||||
let mut d3_guard = d3_pin.lock().unwrap();
|
||||
let mut d0_guard = d0_pin.lock();
|
||||
let mut d1_guard = d1_pin.lock();
|
||||
let mut d2_guard = d2_pin.lock();
|
||||
let mut d3_guard = d3_pin.lock();
|
||||
d0_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
d1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
d2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
|
|
@ -78,9 +78,9 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Set up memory read operation: SYNC=1, CM=1, CI=0 (memory access)
|
||||
{
|
||||
let mut sync_guard = sync_pin.lock().unwrap();
|
||||
let mut cm_guard = cm_pin.lock().unwrap();
|
||||
let mut ci_guard = ci_pin.lock().unwrap();
|
||||
let mut sync_guard = sync_pin.lock();
|
||||
let mut cm_guard = cm_pin.lock();
|
||||
let mut ci_guard = ci_pin.lock();
|
||||
sync_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
ci_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Memory access
|
||||
|
|
@ -88,10 +88,10 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Set up address high nibble (0x1 for address 0x12)
|
||||
{
|
||||
let mut d0_guard = d0_pin.lock().unwrap();
|
||||
let mut d1_guard = d1_pin.lock().unwrap();
|
||||
let mut d2_guard = d2_pin.lock().unwrap();
|
||||
let mut d3_guard = d3_pin.lock().unwrap();
|
||||
let mut d0_guard = d0_pin.lock();
|
||||
let mut d1_guard = d1_pin.lock();
|
||||
let mut d2_guard = d2_pin.lock();
|
||||
let mut d3_guard = d3_pin.lock();
|
||||
// 0x1 = 0001 (D0=1, D1=0, D2=0, D3=0)
|
||||
d0_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
d1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
|
|
@ -104,7 +104,7 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Trigger Φ1 rising edge to start memory operation and latch high nibble
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Reset Φ1 to Low
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
||||
|
|
@ -129,10 +129,10 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Set up address low nibble (0x2 for address 0x12)
|
||||
{
|
||||
let mut d0_guard = d0_pin.lock().unwrap();
|
||||
let mut d1_guard = d1_pin.lock().unwrap();
|
||||
let mut d2_guard = d2_pin.lock().unwrap();
|
||||
let mut d3_guard = d3_pin.lock().unwrap();
|
||||
let mut d0_guard = d0_pin.lock();
|
||||
let mut d1_guard = d1_pin.lock();
|
||||
let mut d2_guard = d2_pin.lock();
|
||||
let mut d3_guard = d3_pin.lock();
|
||||
// 0x2 = 0010 (D0=0, D1=1, D2=0, D3=0)
|
||||
d0_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
d1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
|
|
@ -146,7 +146,7 @@ fn test_intel_4001_state_machine_progression() {
|
|||
// Trigger Φ1 rising edge again - ROM should stay in AddressPhase
|
||||
// (address nibbles are latched on Φ1 falling edge, not rising)
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Reset Φ1 to Low to trigger falling edge - this is when low nibble is latched
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
||||
|
|
@ -189,10 +189,10 @@ fn test_intel_4001_state_machine_progression() {
|
|||
|
||||
// Remove test drivers from data pins to allow ROM to drive bus
|
||||
{
|
||||
let mut d0_guard = d0_pin.lock().unwrap();
|
||||
let mut d1_guard = d1_pin.lock().unwrap();
|
||||
let mut d2_guard = d2_pin.lock().unwrap();
|
||||
let mut d3_guard = d3_pin.lock().unwrap();
|
||||
let mut d0_guard = d0_pin.lock();
|
||||
let mut d1_guard = d1_pin.lock();
|
||||
let mut d2_guard = d2_pin.lock();
|
||||
let mut d3_guard = d3_pin.lock();
|
||||
d0_guard.remove_driver("TEST");
|
||||
d1_guard.remove_driver("TEST");
|
||||
d2_guard.remove_driver("TEST");
|
||||
|
|
@ -203,7 +203,7 @@ fn test_intel_4001_state_machine_progression() {
|
|||
if rom.get_timing_state() == TimingState::WaitLatency {
|
||||
// Trigger Φ2 rising edge
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
|
||||
|
|
@ -221,14 +221,14 @@ fn test_intel_4001_state_machine_progression() {
|
|||
// Verify data is being driven on the bus
|
||||
// Data 0xAB has low nibble 0xB = 1011 (D0=1, D1=1, D2=0, D3=1)
|
||||
// Note: Due to bit ordering, D0 should be High, D1 should be High, D2 should be Low, D3 should be High
|
||||
assert_eq!(d0_pin.lock().unwrap().read(), PinValue::High);
|
||||
assert_eq!(d1_pin.lock().unwrap().read(), PinValue::High);
|
||||
assert_eq!(d2_pin.lock().unwrap().read(), PinValue::Low);
|
||||
assert_eq!(d3_pin.lock().unwrap().read(), PinValue::High);
|
||||
assert_eq!(d0_pin.lock().read(), PinValue::High);
|
||||
assert_eq!(d1_pin.lock().read(), PinValue::High);
|
||||
assert_eq!(d2_pin.lock().read(), PinValue::Low);
|
||||
assert_eq!(d3_pin.lock().read(), PinValue::High);
|
||||
|
||||
// Reset Φ2 to Low
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
||||
|
|
@ -240,10 +240,10 @@ fn test_intel_4001_state_machine_progression() {
|
|||
println!("Final state: {:?}", rom.get_timing_state());
|
||||
|
||||
// Verify data bus is tri-stated
|
||||
assert_eq!(d0_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d1_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d2_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d3_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d0_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d1_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d2_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d3_pin.lock().read(), PinValue::HighZ);
|
||||
}
|
||||
|
||||
/// Test to verify that unified state machine doesn't progress without proper control signals
|
||||
|
|
@ -261,8 +261,8 @@ fn test_intel_4001_state_machine_no_progression_without_signals() {
|
|||
|
||||
// Initialize clock pins to Low
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
|
@ -275,7 +275,7 @@ fn test_intel_4001_state_machine_no_progression_without_signals() {
|
|||
|
||||
// Trigger clock edges without setting up control signals
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ fn test_intel_4001_state_machine_no_progression_without_signals() {
|
|||
|
||||
// Reset Φ1 to Low
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
||||
|
|
@ -296,7 +296,7 @@ fn test_intel_4001_state_machine_no_progression_without_signals() {
|
|||
|
||||
// Trigger Φ2 rising edge
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ fn test_intel_4001_state_machine_reset() {
|
|||
|
||||
// Initialize clock pins to Low
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
||||
|
|
@ -337,9 +337,9 @@ fn test_intel_4001_state_machine_reset() {
|
|||
|
||||
// Set up memory read operation: SYNC=1, CM=1, CI=0 (memory access)
|
||||
{
|
||||
let mut sync_guard = sync_pin.lock().unwrap();
|
||||
let mut cm_guard = cm_pin.lock().unwrap();
|
||||
let mut ci_guard = ci_pin.lock().unwrap();
|
||||
let mut sync_guard = sync_pin.lock();
|
||||
let mut cm_guard = cm_pin.lock();
|
||||
let mut ci_guard = ci_pin.lock();
|
||||
sync_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
ci_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Memory access
|
||||
|
|
@ -347,7 +347,7 @@ fn test_intel_4001_state_machine_reset() {
|
|||
|
||||
// Trigger Φ1 rising edge to start memory operation
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
|
||||
|
|
@ -359,7 +359,7 @@ fn test_intel_4001_state_machine_reset() {
|
|||
|
||||
// Assert RESET (active LOW - set to Low to trigger reset)
|
||||
{
|
||||
let mut reset_guard = reset_pin.lock().unwrap();
|
||||
let mut reset_guard = reset_pin.lock();
|
||||
reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ fn create_test_ram() -> Intel4002 {
|
|||
let phi1_pin = ram.get_pin("PHI1").unwrap();
|
||||
let phi2_pin = ram.get_pin("PHI2").unwrap();
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ fn set_data_bus(ram: &Intel4002, value: u8) {
|
|||
|
||||
for i in 0..4 {
|
||||
if let Ok(pin) = ram.get_pin(&format!("D{}", i)) {
|
||||
if let Ok(mut pin_guard) = pin.lock() {
|
||||
if let Some(mut pin_guard) = pin.try_lock() {
|
||||
let bit_value = (nibble >> i) & 1;
|
||||
let pin_value = if bit_value == 1 {
|
||||
PinValue::High
|
||||
|
|
@ -74,7 +74,7 @@ fn set_data_bus(ram: &Intel4002, value: u8) {
|
|||
fn clear_data_bus_drivers(ram: &Intel4002) {
|
||||
for i in 0..4 {
|
||||
if let Ok(pin) = ram.get_pin(&format!("D{}", i)) {
|
||||
if let Ok(mut pin_guard) = pin.lock() {
|
||||
if let Some(mut pin_guard) = pin.try_lock() {
|
||||
pin_guard.remove_driver("TEST");
|
||||
}
|
||||
}
|
||||
|
|
@ -90,8 +90,8 @@ fn generate_clock_edge(ram: &mut Intel4002, phi1_high: bool, phi2_high: bool) {
|
|||
|
||||
// Set clock pins
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
|
||||
phi1_guard.set_driver(
|
||||
Some("TEST".to_string()),
|
||||
|
|
@ -217,16 +217,16 @@ fn test_ram_read_state_progression() {
|
|||
|
||||
// Read data bus value
|
||||
let mut data_value = 0;
|
||||
if d0_pin.lock().unwrap().read() == PinValue::High {
|
||||
if d0_pin.lock().read() == PinValue::High {
|
||||
data_value |= 1 << 0;
|
||||
}
|
||||
if d1_pin.lock().unwrap().read() == PinValue::High {
|
||||
if d1_pin.lock().read() == PinValue::High {
|
||||
data_value |= 1 << 1;
|
||||
}
|
||||
if d2_pin.lock().unwrap().read() == PinValue::High {
|
||||
if d2_pin.lock().read() == PinValue::High {
|
||||
data_value |= 1 << 2;
|
||||
}
|
||||
if d3_pin.lock().unwrap().read() == PinValue::High {
|
||||
if d3_pin.lock().read() == PinValue::High {
|
||||
data_value |= 1 << 3;
|
||||
}
|
||||
|
||||
|
|
@ -470,7 +470,7 @@ fn test_reset_functionality() {
|
|||
// Assert RESET (active low)
|
||||
let reset_pin = ram.get_pin("RESET").unwrap();
|
||||
{
|
||||
let mut reset_guard = reset_pin.lock().unwrap();
|
||||
let mut reset_guard = reset_pin.lock();
|
||||
reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
wait_for_pin_settlement();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rusty_emu::pin::PinValue;
|
|||
/// Test helper to set pin value with proper driver management
|
||||
fn set_pin_value(component: &Intel4003, pin_name: &str, value: PinValue, driver: &str) {
|
||||
if let Ok(pin) = component.get_pin(pin_name) {
|
||||
if let Ok(mut pin_guard) = pin.lock() {
|
||||
if let Some(mut pin_guard) = pin.try_lock() {
|
||||
pin_guard.set_driver(Some(driver.to_string()), value);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ fn set_pin_value(component: &Intel4003, pin_name: &str, value: PinValue, driver:
|
|||
/// Test helper to remove pin driver
|
||||
fn remove_pin_driver(component: &Intel4003, pin_name: &str) {
|
||||
if let Ok(pin) = component.get_pin(pin_name) {
|
||||
if let Ok(mut pin_guard) = pin.lock() {
|
||||
if let Some(mut pin_guard) = pin.try_lock() {
|
||||
pin_guard.set_driver(None, PinValue::HighZ);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
//! This test verifies that the Intel 4004 CPU state machine progresses correctly
|
||||
//! through all phases: Idle → AddressPhase → WaitLatency → DriveData → Idle
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
|
|
@ -46,16 +47,8 @@ impl CpuTestHelper {
|
|||
let phi2 = Arc::new(Mutex::new(Pin::new("PHI2".to_string())));
|
||||
|
||||
// Connect CPU to test clock
|
||||
cpu.get_pin("PHI1")
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.connect_to(phi1.clone());
|
||||
cpu.get_pin("PHI2")
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.connect_to(phi2.clone());
|
||||
cpu.get_pin("PHI1").unwrap().lock().connect_to(phi1.clone());
|
||||
cpu.get_pin("PHI2").unwrap().lock().connect_to(phi2.clone());
|
||||
|
||||
CpuTestHelper {
|
||||
cpu,
|
||||
|
|
@ -90,11 +83,9 @@ impl CpuTestHelper {
|
|||
// Phase 1: Φ1 high, Φ2 low
|
||||
self.phi1
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("clock".to_string()), PinValue::High);
|
||||
self.phi2
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("clock".to_string()), PinValue::Low);
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
|
||||
|
|
@ -104,11 +95,9 @@ impl CpuTestHelper {
|
|||
// Phase 2: Φ1 low, Φ2 high
|
||||
self.phi1
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("clock".to_string()), PinValue::Low);
|
||||
self.phi2
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("clock".to_string()), PinValue::High);
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
|
||||
|
|
@ -117,11 +106,9 @@ impl CpuTestHelper {
|
|||
// Phase 3: Both low
|
||||
self.phi1
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("clock".to_string()), PinValue::Low);
|
||||
self.phi2
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("clock".to_string()), PinValue::Low);
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
|
||||
|
|
@ -137,28 +124,18 @@ impl CpuTestHelper {
|
|||
}
|
||||
|
||||
fn set_control_pins(&self, sync: bool, cm: bool, reset: bool) {
|
||||
self.cpu
|
||||
.get_pin("SYNC")
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(
|
||||
Some("test".to_string()),
|
||||
if sync { PinValue::High } else { PinValue::Low },
|
||||
);
|
||||
self.cpu.get_pin("CM").unwrap().lock().unwrap().set_driver(
|
||||
self.cpu.get_pin("SYNC").unwrap().lock().set_driver(
|
||||
Some("test".to_string()),
|
||||
if sync { PinValue::High } else { PinValue::Low },
|
||||
);
|
||||
self.cpu.get_pin("CM").unwrap().lock().set_driver(
|
||||
Some("test".to_string()),
|
||||
if cm { PinValue::High } else { PinValue::Low },
|
||||
);
|
||||
self.cpu
|
||||
.get_pin("RESET")
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(
|
||||
Some("test".to_string()),
|
||||
if reset { PinValue::High } else { PinValue::Low },
|
||||
);
|
||||
self.cpu.get_pin("RESET").unwrap().lock().set_driver(
|
||||
Some("test".to_string()),
|
||||
if reset { PinValue::High } else { PinValue::Low },
|
||||
);
|
||||
}
|
||||
|
||||
fn drive_data_bus(&self, data: u8) {
|
||||
|
|
@ -168,7 +145,6 @@ impl CpuTestHelper {
|
|||
.get_pin(&format!("D{}", i))
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(
|
||||
Some("test".to_string()),
|
||||
if bit_value == 1 {
|
||||
|
|
@ -184,10 +160,9 @@ impl CpuTestHelper {
|
|||
let mut data = 0;
|
||||
for i in 0..4 {
|
||||
if let Ok(pin) = self.cpu.get_pin(&format!("D{}", i)) {
|
||||
if let Ok(pin_guard) = pin.lock() {
|
||||
if pin_guard.read() == PinValue::High {
|
||||
data |= 1 << i;
|
||||
}
|
||||
let pin_guard = pin.lock();
|
||||
if pin_guard.read() == PinValue::High {
|
||||
data |= 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -197,9 +172,8 @@ impl CpuTestHelper {
|
|||
fn tri_state_data_bus(&self) {
|
||||
for i in 0..4 {
|
||||
if let Ok(pin) = self.cpu.get_pin(&format!("D{}", i)) {
|
||||
if let Ok(mut pin_guard) = pin.lock() {
|
||||
pin_guard.set_driver(Some("test".to_string()), PinValue::HighZ);
|
||||
}
|
||||
let mut pin_guard = pin.lock();
|
||||
pin_guard.set_driver(Some("test".to_string()), PinValue::HighZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -294,7 +268,7 @@ fn test_intel_4004_state_machine_progression() {
|
|||
for i in 0..4 {
|
||||
let pin_name = format!("D{}", i);
|
||||
if let Ok(pin) = helper.cpu.get_pin(&pin_name) {
|
||||
let mut pin_guard = pin.lock().unwrap();
|
||||
let mut pin_guard = pin.lock();
|
||||
pin_guard.set_driver(Some("test".to_string()), PinValue::High);
|
||||
}
|
||||
}
|
||||
|
|
@ -352,7 +326,6 @@ fn test_intel_4004_reset_functionality() {
|
|||
.get_pin("RESET")
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("test".to_string()), PinValue::High);
|
||||
helper.cpu.update();
|
||||
|
||||
|
|
@ -362,7 +335,6 @@ fn test_intel_4004_reset_functionality() {
|
|||
.get_pin("RESET")
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("test".to_string()), PinValue::Low);
|
||||
|
||||
// Process the reset signal for multiple cycles to ensure it's applied
|
||||
|
|
@ -378,7 +350,6 @@ fn test_intel_4004_reset_functionality() {
|
|||
.get_pin("RESET")
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_driver(Some("test".to_string()), PinValue::High);
|
||||
helper.cpu.update();
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use parking_lot::Mutex;
|
||||
use rusty_emu::component::{BaseComponent, Component};
|
||||
use rusty_emu::components::common::intel_400x::*;
|
||||
use rusty_emu::components::memory::intel_4001::{Intel4001, IoDirection, IoMode};
|
||||
use rusty_emu::pin::{Pin, PinValue};
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
// Mock component for testing trait implementations
|
||||
|
|
@ -47,9 +48,17 @@ impl Component for MockComponent {
|
|||
false
|
||||
}
|
||||
|
||||
fn set_running(&mut self, _running: bool) {
|
||||
// No-op for mock
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Intel400xAddressHandling for MockComponent {
|
||||
|
|
@ -354,57 +363,29 @@ mod tests {
|
|||
let d3_pin = rom.get_pin("D3").unwrap();
|
||||
|
||||
// Set settlement time to 0 for immediate testing
|
||||
sync_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
cm_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
ci_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
sync_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
cm_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
ci_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
reset_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
phi1_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
phi2_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
d0_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
d1_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
d2_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
d3_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
phi1_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
phi2_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
d0_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
d1_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
d2_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
d3_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
|
||||
// Initially, all data pins should be HighZ
|
||||
assert_eq!(d0_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d1_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d2_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d3_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d0_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d1_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d2_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d3_pin.lock().read(), PinValue::HighZ);
|
||||
|
||||
// Test reset (RESET is active LOW)
|
||||
println!("=== Testing Reset ===");
|
||||
{
|
||||
let mut reset_guard = reset_pin.lock().unwrap();
|
||||
let mut reset_guard = reset_pin.lock();
|
||||
reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset
|
||||
}
|
||||
rom.update();
|
||||
|
|
@ -413,7 +394,7 @@ mod tests {
|
|||
|
||||
// Release reset (set HIGH for normal operation)
|
||||
{
|
||||
let mut reset_guard = reset_pin.lock().unwrap();
|
||||
let mut reset_guard = reset_pin.lock();
|
||||
reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset
|
||||
}
|
||||
rom.update();
|
||||
|
|
@ -466,11 +447,11 @@ mod tests {
|
|||
// Pin state snapshots
|
||||
println!(
|
||||
"Pin states: SYNC: {:?}, CM: {:?}, CI: {:?}, PHI1: {:?}, PHI2: {:?}",
|
||||
sync_pin.lock().unwrap().read(),
|
||||
cm_pin.lock().unwrap().read(),
|
||||
ci_pin.lock().unwrap().read(),
|
||||
phi1_pin.lock().unwrap().read(),
|
||||
phi2_pin.lock().unwrap().read()
|
||||
sync_pin.lock().read(),
|
||||
cm_pin.lock().read(),
|
||||
ci_pin.lock().read(),
|
||||
phi1_pin.lock().read(),
|
||||
phi2_pin.lock().read()
|
||||
);
|
||||
|
||||
println!("Test completed successfully!");
|
||||
|
|
@ -493,22 +474,22 @@ mod tests {
|
|||
// Reset to known state first (RESET is active LOW)
|
||||
{
|
||||
let reset_pin = rom.get_pin("RESET").unwrap();
|
||||
let mut reset_guard = reset_pin.lock().unwrap();
|
||||
let mut reset_guard = reset_pin.lock();
|
||||
reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset (active LOW)
|
||||
}
|
||||
rom.update();
|
||||
{
|
||||
let reset_pin = rom.get_pin("RESET").unwrap();
|
||||
let mut reset_guard = reset_pin.lock().unwrap();
|
||||
let mut reset_guard = reset_pin.lock();
|
||||
reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset (HIGH = normal operation)
|
||||
}
|
||||
rom.update();
|
||||
|
||||
// Set SYNC=1, CM=1, CI=0 for memory read
|
||||
{
|
||||
let mut sync_guard = sync_pin.lock().unwrap();
|
||||
let mut cm_guard = cm_pin.lock().unwrap();
|
||||
let mut ci_guard = ci_pin.lock().unwrap();
|
||||
let mut sync_guard = sync_pin.lock();
|
||||
let mut cm_guard = cm_pin.lock();
|
||||
let mut ci_guard = ci_pin.lock();
|
||||
sync_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
ci_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
|
|
@ -517,14 +498,14 @@ mod tests {
|
|||
|
||||
// Ensure PHI2 is low initially
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
rom.update();
|
||||
|
||||
// Ensure PHI1 is low initially
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
rom.update();
|
||||
|
|
@ -534,7 +515,7 @@ mod tests {
|
|||
|
||||
// PHI1 low to high: Address phase for high nibble
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
rom.update();
|
||||
|
|
@ -546,14 +527,14 @@ mod tests {
|
|||
|
||||
// PHI1 high to low: Complete address phase for high nibble
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
rom.update();
|
||||
|
||||
// PHI1 low to high again: Address phase for low nibble
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
rom.update();
|
||||
|
|
@ -564,7 +545,7 @@ mod tests {
|
|||
|
||||
// PHI1 high to low: Complete address phase
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
rom.update();
|
||||
|
|
@ -589,14 +570,14 @@ mod tests {
|
|||
// Release data bus from test control to allow ROM to drive it
|
||||
for i in 0..4 {
|
||||
let pin = rom.get_pin(&format!("D{}", i)).unwrap();
|
||||
let mut pin_guard = pin.lock().unwrap();
|
||||
let mut pin_guard = pin.lock();
|
||||
pin_guard.set_driver(Some("TEST".to_string()), PinValue::HighZ);
|
||||
}
|
||||
rom.update();
|
||||
|
||||
// PHI2 low to high: Data phase
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
rom.update();
|
||||
|
|
@ -612,17 +593,17 @@ mod tests {
|
|||
|
||||
// PHI2 high to low: Cleanup
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
rom.update();
|
||||
assert_eq!(rom.get_timing_state(), TimingState::Idle);
|
||||
|
||||
// Tri-state pins
|
||||
assert_eq!(d0_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d1_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d2_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d3_pin.lock().unwrap().read(), PinValue::HighZ);
|
||||
assert_eq!(d0_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d1_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d2_pin.lock().read(), PinValue::HighZ);
|
||||
assert_eq!(d3_pin.lock().read(), PinValue::HighZ);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -644,46 +625,18 @@ mod tests {
|
|||
let d3_pin = chip.get_pin("D3").unwrap();
|
||||
|
||||
// Set settlement time to 0 for immediate testing
|
||||
sync_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
cm_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
ci_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
sync_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
cm_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
ci_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
reset_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
phi1_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
phi2_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
d0_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
d1_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
d2_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
d3_pin
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
phi1_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
phi2_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
d0_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
d1_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
d2_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
d3_pin.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
|
||||
// Test memory read at minimum timing
|
||||
// Note: Intel 4004 has a 4-bit data bus, so we can only read 4 bits at a time
|
||||
|
|
@ -861,28 +814,19 @@ mod tests {
|
|||
// Set settlement times to 0
|
||||
test_sync
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
test_cm
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
test_ci
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
test_cm.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
test_ci.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
test_phi1
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
test_phi2
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
|
||||
// Initialize PHI2 to Low to ensure proper edge detection
|
||||
{
|
||||
let mut phi2_guard = test_phi2.lock().unwrap();
|
||||
let mut phi2_guard = test_phi2.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
test_chip.update();
|
||||
|
|
@ -890,9 +834,9 @@ mod tests {
|
|||
// Manually step through the state machine to verify timing
|
||||
// Set control pins for memory read
|
||||
{
|
||||
let mut sync_guard = test_sync.lock().unwrap();
|
||||
let mut cm_guard = test_cm.lock().unwrap();
|
||||
let mut ci_guard = test_ci.lock().unwrap();
|
||||
let mut sync_guard = test_sync.lock();
|
||||
let mut cm_guard = test_cm.lock();
|
||||
let mut ci_guard = test_ci.lock();
|
||||
sync_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
ci_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
|
|
@ -902,14 +846,14 @@ mod tests {
|
|||
|
||||
// Ensure PHI1 is low initially
|
||||
{
|
||||
let mut phi1_guard = test_phi1.lock().unwrap();
|
||||
let mut phi1_guard = test_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
test_chip.update();
|
||||
|
||||
// Start address phase - first PHI1 cycle for high nibble
|
||||
{
|
||||
let mut phi1_guard = test_phi1.lock().unwrap();
|
||||
let mut phi1_guard = test_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
test_chip.update();
|
||||
|
|
@ -921,7 +865,7 @@ mod tests {
|
|||
|
||||
// PHI1 falling edge - latch high nibble
|
||||
{
|
||||
let mut phi1_guard = test_phi1.lock().unwrap();
|
||||
let mut phi1_guard = test_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
test_chip.update();
|
||||
|
|
@ -929,7 +873,7 @@ mod tests {
|
|||
|
||||
// Second PHI1 cycle for low nibble
|
||||
{
|
||||
let mut phi1_guard = test_phi1.lock().unwrap();
|
||||
let mut phi1_guard = test_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
test_chip.update();
|
||||
|
|
@ -940,7 +884,7 @@ mod tests {
|
|||
|
||||
// PHI1 falling edge - latch low nibble and complete address
|
||||
{
|
||||
let mut phi1_guard = test_phi1.lock().unwrap();
|
||||
let mut phi1_guard = test_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
test_chip.update();
|
||||
|
|
@ -951,7 +895,7 @@ mod tests {
|
|||
|
||||
// PHI2 high: Data phase
|
||||
{
|
||||
let mut phi2_guard = test_phi2.lock().unwrap();
|
||||
let mut phi2_guard = test_phi2.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
test_chip.update();
|
||||
|
|
@ -963,7 +907,7 @@ mod tests {
|
|||
|
||||
// Complete cycle
|
||||
{
|
||||
let mut phi2_guard = test_phi2.lock().unwrap();
|
||||
let mut phi2_guard = test_phi2.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
test_chip.update();
|
||||
|
|
@ -984,37 +928,28 @@ mod tests {
|
|||
// Set settlement times to 0
|
||||
fast_sync
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
fast_cm
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
fast_ci
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
fast_cm.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
fast_ci.lock().set_settlement_time(Duration::from_nanos(0));
|
||||
fast_phi1
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
fast_phi2
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_settlement_time(Duration::from_nanos(0));
|
||||
|
||||
// Initialize PHI2 to Low to ensure proper edge detection
|
||||
{
|
||||
let mut phi2_guard = fast_phi2.lock().unwrap();
|
||||
let mut phi2_guard = fast_phi2.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
fast_chip.update();
|
||||
|
||||
// Set up for memory read
|
||||
{
|
||||
let mut sync_guard = fast_sync.lock().unwrap();
|
||||
let mut cm_guard = fast_cm.lock().unwrap();
|
||||
let mut ci_guard = fast_ci.lock().unwrap();
|
||||
let mut sync_guard = fast_sync.lock();
|
||||
let mut cm_guard = fast_cm.lock();
|
||||
let mut ci_guard = fast_ci.lock();
|
||||
sync_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
ci_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
|
|
@ -1023,14 +958,14 @@ mod tests {
|
|||
|
||||
// Ensure PHI1 is low initially
|
||||
{
|
||||
let mut phi1_guard = fast_phi1.lock().unwrap();
|
||||
let mut phi1_guard = fast_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
fast_chip.update();
|
||||
|
||||
// First PHI1 cycle - latch high nibble
|
||||
{
|
||||
let mut phi1_guard = fast_phi1.lock().unwrap();
|
||||
let mut phi1_guard = fast_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
fast_chip.update();
|
||||
|
|
@ -1041,14 +976,14 @@ mod tests {
|
|||
|
||||
// PHI1 falling edge - latch high nibble
|
||||
{
|
||||
let mut phi1_guard = fast_phi1.lock().unwrap();
|
||||
let mut phi1_guard = fast_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
fast_chip.update();
|
||||
|
||||
// Second PHI1 cycle - latch low nibble
|
||||
{
|
||||
let mut phi1_guard = fast_phi1.lock().unwrap();
|
||||
let mut phi1_guard = fast_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
fast_chip.update();
|
||||
|
|
@ -1059,7 +994,7 @@ mod tests {
|
|||
|
||||
// PHI1 falling edge - latch low nibble and complete address
|
||||
{
|
||||
let mut phi1_guard = fast_phi1.lock().unwrap();
|
||||
let mut phi1_guard = fast_phi1.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
fast_chip.update();
|
||||
|
|
@ -1075,14 +1010,14 @@ mod tests {
|
|||
// Release data bus from test control to allow ROM to drive it
|
||||
for i in 0..4 {
|
||||
let pin = fast_chip.get_pin(&format!("D{}", i)).unwrap();
|
||||
let mut pin_guard = pin.lock().unwrap();
|
||||
let mut pin_guard = pin.lock();
|
||||
pin_guard.set_driver(Some("TEST".to_string()), PinValue::HighZ);
|
||||
}
|
||||
fast_chip.update();
|
||||
|
||||
// Try to read data - PHI2 rising edge triggers data driving if latency elapsed
|
||||
{
|
||||
let mut phi2_guard = fast_phi2.lock().unwrap();
|
||||
let mut phi2_guard = fast_phi2.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
fast_chip.update();
|
||||
|
|
@ -1124,9 +1059,9 @@ mod tests {
|
|||
|
||||
// Set control pins for memory read
|
||||
{
|
||||
let mut sync_guard = sync_pin.lock().unwrap();
|
||||
let mut cm_guard = cm_pin.lock().unwrap();
|
||||
let mut ci_guard = ci_pin.lock().unwrap();
|
||||
let mut sync_guard = sync_pin.lock();
|
||||
let mut cm_guard = cm_pin.lock();
|
||||
let mut ci_guard = ci_pin.lock();
|
||||
sync_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
ci_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
|
|
@ -1135,21 +1070,21 @@ mod tests {
|
|||
|
||||
// Ensure PHI2 is low initially
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
chip.update();
|
||||
|
||||
// Ensure PHI1 is low initially
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
chip.update();
|
||||
|
||||
// PHI1 low to high: Address phase for high nibble
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
chip.update();
|
||||
|
|
@ -1160,14 +1095,14 @@ mod tests {
|
|||
|
||||
// PHI1 high to low: Complete address phase for high nibble
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
chip.update();
|
||||
|
||||
// PHI1 low to high again: Address phase for low nibble
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
chip.update();
|
||||
|
|
@ -1178,7 +1113,7 @@ mod tests {
|
|||
|
||||
// PHI1 high to low: Complete address phase
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi1_guard = phi1_pin.lock();
|
||||
phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
chip.update();
|
||||
|
|
@ -1208,14 +1143,14 @@ mod tests {
|
|||
// Release data bus from test control to allow ROM to drive it
|
||||
for i in 0..4 {
|
||||
let pin = chip.get_pin(&format!("D{}", i)).unwrap();
|
||||
let mut pin_guard = pin.lock().unwrap();
|
||||
let mut pin_guard = pin.lock();
|
||||
pin_guard.set_driver(Some("TEST".to_string()), PinValue::HighZ);
|
||||
}
|
||||
chip.update();
|
||||
|
||||
// PHI2 low to high: Data phase
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
chip.update();
|
||||
|
|
@ -1230,7 +1165,7 @@ mod tests {
|
|||
|
||||
// PHI2 high to low: Cleanup
|
||||
{
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock();
|
||||
phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
chip.update();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue