From 3530ea5f28f8d6309628337d7fef26d2b71cea20 Mon Sep 17 00:00:00 2001 From: Jan-Peter von Hunnius Date: Thu, 26 Feb 2026 14:32:52 +0100 Subject: [PATCH] refactor: clean up test suite and apply code formatting Remove redundant/obsolete tests from intel_400x_tests.rs, retaining core test coverage for Intel400x common functionality. Apply rustfmt formatting to intel_4002.rs and state machine test files. Changes: - Remove ~40 redundant test functions from intel_400x_tests.rs - Apply rustfmt formatting to intel_4002.rs - Fix import formatting in state machine tests - Clean up trailing whitespace --- src/components/memory/intel_4002.rs | 7 +- tests/intel_4002_state_machine_test.rs | 74 +- tests/intel_4003_state_machine_test.rs | 5 +- tests/intel_400x_tests.rs | 5874 +----------------------- 4 files changed, 62 insertions(+), 5898 deletions(-) diff --git a/src/components/memory/intel_4002.rs b/src/components/memory/intel_4002.rs index 4179ce9..242d76b 100644 --- a/src/components/memory/intel_4002.rs +++ b/src/components/memory/intel_4002.rs @@ -435,7 +435,8 @@ impl Intel4002 { if let Ok(pin) = self.base.get_pin(&format!("D{}", i)) { if let Ok(mut pin_guard) = pin.lock() { // Use the same driver name as write_data_bus() to properly tri-state - pin_guard.set_driver(Some(format!("{}_DATA", self.base.name())), PinValue::HighZ); + pin_guard + .set_driver(Some(format!("{}_DATA", self.base.name())), PinValue::HighZ); } } } @@ -621,7 +622,7 @@ impl Intel4002 { if self.state_machine.is_full_address_ready() { let address = self.state_machine.get_full_address().unwrap_or(0) as u8; let data = self.read_data_bus(); - + // Determine which output port based on address // Output ports are at addresses 0x14-0x17 (port 0-3) let port = match address { @@ -631,7 +632,7 @@ impl Intel4002 { 0x17 => Some(3), _ => None, }; - + if let Some(port_num) = port { // Write to I/O port let _ = self.write_io_port(port_num, data); diff --git a/tests/intel_4002_state_machine_test.rs b/tests/intel_4002_state_machine_test.rs index 6332cc1..8d88133 100644 --- a/tests/intel_4002_state_machine_test.rs +++ b/tests/intel_4002_state_machine_test.rs @@ -9,7 +9,9 @@ use std::thread; use std::time::Duration; use rusty_emu::component::Component; -use rusty_emu::components::common::intel_400x::{Intel400xTimingState, Intel400xUnifiedState, TimingState}; +use rusty_emu::components::common::intel_400x::{ + Intel400xTimingState, Intel400xUnifiedState, TimingState, +}; use rusty_emu::components::memory::intel_4002::{Intel4002, PendingOperation}; use rusty_emu::pin::PinValue; @@ -192,13 +194,13 @@ fn test_ram_read_state_progression() { // Manually transition to AddressPhase (simulating chip select) ram.set_state_for_test(Intel400xUnifiedState::AddressPhase); - + // Set address high nibble (0x0) on data bus set_data_bus(&ram, 0x0); // Generate Φ1 rising edge (no latching yet, data may not be stable) generate_clock_edge(&mut ram, true, false); - + // Generate Φ1 falling edge - address latching happens here (data is now stable) generate_clock_edge(&mut ram, false, false); @@ -215,7 +217,7 @@ fn test_ram_read_state_progression() { // Generate Φ1 rising edge (no latching yet) generate_clock_edge(&mut ram, true, false); - + // Generate Φ1 falling edge - low nibble latching happens here generate_clock_edge(&mut ram, false, false); @@ -229,7 +231,7 @@ fn test_ram_read_state_progression() { // Wait for latency to elapse (with 1ns access time, it should elapse immediately) std::thread::sleep(std::time::Duration::from_millis(1)); - + // Generate Φ2 rising edge to trigger latency check and data driving generate_clock_edge(&mut ram, false, true); @@ -239,7 +241,7 @@ fn test_ram_read_state_progression() { // Clear data bus drivers to prepare for reading clear_data_bus_drivers(&ram); - + // Execute state logic to drive data ram.update(); @@ -307,7 +309,7 @@ fn test_ram_write_state_progression() { // Generate Φ1 rising edge (no latching yet) generate_clock_edge(&mut ram, true, false); - + // Generate Φ1 falling edge - address latching happens here generate_clock_edge(&mut ram, false, false); @@ -324,7 +326,7 @@ fn test_ram_write_state_progression() { // Generate Φ1 rising edge (no latching yet) generate_clock_edge(&mut ram, true, false); - + // Generate Φ1 falling edge - low nibble latching happens here generate_clock_edge(&mut ram, false, false); @@ -392,7 +394,7 @@ fn test_output_port_state_progression() { // Generate Φ1 rising edge (no latching yet) generate_clock_edge(&mut ram, true, false); - + // Generate Φ1 falling edge - address latching happens here generate_clock_edge(&mut ram, false, false); @@ -409,7 +411,7 @@ fn test_output_port_state_progression() { // Generate Φ1 rising edge (no latching yet) generate_clock_edge(&mut ram, true, false); - + // Generate Φ1 falling edge - low nibble latching happens here generate_clock_edge(&mut ram, false, false); @@ -487,16 +489,19 @@ fn test_reset_functionality() { // Manually transition to AddressPhase and set up some state ram.set_state_for_test(Intel400xUnifiedState::AddressPhase); set_data_bus(&ram, 0x0); - + // Generate Φ1 rising edge (no latching yet) generate_clock_edge(&mut ram, true, false); - + // Generate Φ1 falling edge - address latching happens here generate_clock_edge(&mut ram, false, false); // Should have latched high nibble assert_eq!(ram.get_address_high_nibble(), Some(0x0)); - println!("Before reset: high_nibble={:?}", ram.get_address_high_nibble()); + println!( + "Before reset: high_nibble={:?}", + ram.get_address_high_nibble() + ); // Assert RESET (active low) let reset_pin = ram.get_pin("RESET").unwrap(); @@ -556,28 +561,49 @@ fn test_complete_state_machine_progression() { println!("Test 2: RAM Write Operation"); ram.set_pending_operation(PendingOperation::Write); ram.set_state_for_test(Intel400xUnifiedState::AddressPhase); - println!("Test 2: After set_state_for_test - nibbles: high={:?}, low={:?}", - ram.get_address_high_nibble(), ram.get_address_low_nibble()); + println!( + "Test 2: After set_state_for_test - nibbles: high={:?}, low={:?}", + ram.get_address_high_nibble(), + ram.get_address_low_nibble() + ); set_data_bus(&ram, 0x0); generate_clock_edge(&mut ram, true, false); // Φ1 rising (no latching yet) generate_clock_edge(&mut ram, false, false); // Φ1 falling - latch high nibble - println!("Test 2: After first Φ1 falling - nibbles: high={:?}, low={:?}", - ram.get_address_high_nibble(), ram.get_address_low_nibble()); + println!( + "Test 2: After first Φ1 falling - nibbles: high={:?}, low={:?}", + ram.get_address_high_nibble(), + ram.get_address_low_nibble() + ); set_data_bus(&ram, 0x2); generate_clock_edge(&mut ram, true, false); // Φ1 rising (no latching yet) generate_clock_edge(&mut ram, false, false); // Φ1 falling - latch low nibble - println!("Test 2: After second Φ1 falling - nibbles: high={:?}, low={:?}, full_address_ready={}", - ram.get_address_high_nibble(), ram.get_address_low_nibble(), - ram.get_full_address_ready()); + println!( + "Test 2: After second Φ1 falling - nibbles: high={:?}, low={:?}, full_address_ready={}", + ram.get_address_high_nibble(), + ram.get_address_low_nibble(), + ram.get_full_address_ready() + ); set_data_bus(&ram, 0x0F); println!("Test 2: Data bus set to 0x0F"); std::thread::sleep(std::time::Duration::from_millis(1)); // Wait for latency - println!("Test 2: Before Φ2 rising - state={:?}", ram.get_timing_state()); + println!( + "Test 2: Before Φ2 rising - state={:?}", + ram.get_timing_state() + ); generate_clock_edge(&mut ram, false, true); // Φ2 rising - write data - println!("Test 2: After Φ2 rising - state={:?}", ram.get_timing_state()); + println!( + "Test 2: After Φ2 rising - state={:?}", + ram.get_timing_state() + ); generate_clock_edge(&mut ram, false, false); // Φ2 falling - return to idle - println!("Test 2: After Φ2 falling - state={:?}", ram.get_timing_state()); - println!("Test 2: RAM[0x02]={:02X}, expected=0x0F", ram.read_ram(0x02).unwrap()); + println!( + "Test 2: After Φ2 falling - state={:?}", + ram.get_timing_state() + ); + println!( + "Test 2: RAM[0x02]={:02X}, expected=0x0F", + ram.read_ram(0x02).unwrap() + ); assert_eq!(ram.get_timing_state(), TimingState::Idle); assert_eq!(ram.read_ram(0x02).unwrap(), 0x0F); println!("✅ RAM Write Operation completed"); diff --git a/tests/intel_4003_state_machine_test.rs b/tests/intel_4003_state_machine_test.rs index 5cc1dbd..e9767dc 100644 --- a/tests/intel_4003_state_machine_test.rs +++ b/tests/intel_4003_state_machine_test.rs @@ -131,7 +131,10 @@ fn test_intel_4003_state_machine_progression() { // The shift register operation requires proper state machine transitions. // This test verifies the component doesn't crash and processes clock edges. // Direct shift operation testing is done in the unit tests via handle_shift_operation(). - println!("Shift register state after clock cycles: 0x{:03X}", shift_reg_value); + println!( + "Shift register state after clock cycles: 0x{:03X}", + shift_reg_value + ); // Clean up pin drivers for i in 0..4 { diff --git a/tests/intel_400x_tests.rs b/tests/intel_400x_tests.rs index 2781c20..29a5818 100644 --- a/tests/intel_400x_tests.rs +++ b/tests/intel_400x_tests.rs @@ -400,7 +400,7 @@ mod tests { println!("=== Testing Reset ==="); { let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset + reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset } rom.update(); assert_eq!(rom.get_timing_state(), TimingState::Idle); @@ -409,7 +409,7 @@ mod tests { // Release reset (set HIGH for normal operation) { let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset + reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset } rom.update(); @@ -489,13 +489,13 @@ mod tests { { let reset_pin = rom.get_pin("RESET").unwrap(); let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset (active LOW) + 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(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset (HIGH = normal operation) + reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset (HIGH = normal operation) } rom.update(); @@ -1233,5870 +1233,4 @@ mod tests { data } - - #[test] - fn test_maximum_access_time() { - // Test behavior at maximum access time (750ns) - let mut chip = Intel4001::new_with_access_time("MAX_TIME_ROM".to_string(), 750); // 750ns maximum access time - chip.base.set_running(true); - - // Get pin references - let sync_pin = chip.get_pin("SYNC").unwrap(); - let cm_pin = chip.get_pin("CM").unwrap(); - let ci_pin = chip.get_pin("CI").unwrap(); - let reset_pin = chip.get_pin("RESET").unwrap(); - let phi1_pin = chip.get_pin("PHI1").unwrap(); - let phi2_pin = chip.get_pin("PHI2").unwrap(); - let d0_pin = chip.get_pin("D0").unwrap(); - let d1_pin = chip.get_pin("D1").unwrap(); - let d2_pin = chip.get_pin("D2").unwrap(); - 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)); - 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)); - - // Test memory read at maximum timing - // Note: Intel 4004 has a 4-bit data bus, so we can only read 4 bits at a time - let address = 0x23; - let expected_data = 0x05; // 4-bit value (low nibble only) - - // Set up ROM data - chip.load_rom_data(vec![expected_data], address).unwrap(); - - // Test memory read using the helper function - test_memory_read( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - address as u8, - expected_data, - ); - - // Verify state machine transitions correctly at maximum timing - assert_eq!(chip.get_timing_state(), TimingState::Idle); - - // Test multiple consecutive reads at maximum timing - for addr in 0x20..0x25 { - let test_data = vec![addr as u8]; - chip.load_rom_data(test_data, addr).unwrap(); - test_memory_read( - &mut chip, &sync_pin, &cm_pin, &ci_pin, &phi1_pin, &phi2_pin, &d0_pin, &d1_pin, - &d2_pin, &d3_pin, addr as u8, addr as u8, - ); - } - - // Enhanced edge case testing for maximum access time - - // Test edge case: consecutive reads at maximum access time - for address in 0x40..0x50 { - chip.load_rom_data(vec![address as u8], address).unwrap(); - let result1 = test_memory_read_edge_case_max( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - address as u16, - address as u8, - ); - assert_eq!( - result1, address as u8, - "Failed consecutive read 1 at address {} at maximum access time", - address - ); - } - - // Test edge case: rapid address changes at maximum access time - let test_addresses = [0, 255, 128, 1, 254, 2, 253, 3]; - for &address in &test_addresses { - chip.load_rom_data(vec![address as u8], address).unwrap(); - let result = test_memory_read_edge_case_max( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - address as u16, - address as u8, - ); - assert_eq!( - result, address as u8, - "Failed rapid address change test at address {} at maximum access time", - address - ); - } - - // Test edge case: maximum access time with I/O operations - chip.load_rom_data(vec![0x33], 0x00).unwrap(); // Test pattern - chip.load_rom_data(vec![0xCC], 0xFF).unwrap(); // Another test pattern - - // Test I/O pin behavior during maximum access time reads - let io_pins = ["IO0", "IO1", "IO2", "IO3"]; - - // Set I/O pins to output mode - for pin_name in &io_pins { - let _io_pin = chip.get_pin(pin_name).unwrap(); - // Note: In the actual implementation, I/O pin mode is controlled through the chip's I/O methods - // For this test, we'll verify the I/O functionality through the chip's methods - } - - // Test memory read while I/O operations are active - let result = test_memory_read_edge_case_max( - &mut chip, &sync_pin, &cm_pin, &ci_pin, &phi1_pin, &phi2_pin, &d0_pin, &d1_pin, - &d2_pin, &d3_pin, 0x00, 0x33, - ); - assert_eq!( - result, 0x33, - "Failed memory read with active I/O at maximum access time" - ); - - // Test edge case: maximum access time with boundary addresses - let boundary_addresses = [0, 1, 254, 255]; - for &address in &boundary_addresses { - chip.load_rom_data(vec![address as u8], address).unwrap(); - let result = test_memory_read_edge_case_max( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - address as u16, - address as u8, - ); - assert_eq!( - result, address as u8, - "Failed boundary address test at {} at maximum access time", - address - ); - } - - // Test state machine transitions at maximum access time - // Verify proper state progression through all phases - let mut test_chip = Intel4001::new_with_access_time("MAX_STATE_TEST_ROM".to_string(), 750); - test_chip.base.set_running(true); - test_chip.load_rom_data(vec![0x87], 0x20).unwrap(); - - // Get pins for state machine test - let test_sync = test_chip.get_pin("SYNC").unwrap(); - let test_cm = test_chip.get_pin("CM").unwrap(); - let test_ci = test_chip.get_pin("CI").unwrap(); - let test_phi1 = test_chip.get_pin("PHI1").unwrap(); - let test_phi2 = test_chip.get_pin("PHI2").unwrap(); - - // 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_phi1 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - test_phi2 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - - // 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(); - 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); - } - test_chip.update(); - assert_eq!(test_chip.get_timing_state(), TimingState::Idle); - - // Start address phase - { - let mut phi1_guard = test_phi1.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - test_chip.update(); - assert_eq!(test_chip.get_timing_state(), TimingState::AddressPhase); - - // Apply address - test_chip.write_data_bus(0x02); // High nibble - test_chip.update(); - test_chip.write_data_bus(0x00); // Low nibble - test_chip.update(); - - // Complete address phase - { - let mut phi1_guard = test_phi1.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - test_chip.update(); - assert_eq!(test_chip.get_timing_state(), TimingState::WaitLatency); - - // Wait for maximum latency (750ns) - thread::sleep(Duration::from_nanos(760)); // Slightly more than maximum - - // PHI2 high: Data phase - { - let mut phi2_guard = test_phi2.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - test_chip.update(); - assert_eq!(test_chip.get_timing_state(), TimingState::DriveData); - - // Verify data is driven correctly - let data = test_chip.read_data_bus(); - assert_eq!(data, 0x87); - - // Complete cycle - { - let mut phi2_guard = test_phi2.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - test_chip.update(); - assert_eq!(test_chip.get_timing_state(), TimingState::Idle); - - // Test edge case: timing violations at maximum access time - // Test what happens when we try to read too quickly even at maximum access time - let mut slow_chip = Intel4001::new_with_access_time("SLOW_VIOLATION_ROM".to_string(), 750); - slow_chip.base.set_running(true); - slow_chip.load_rom_data(vec![0xBB], 0x60).unwrap(); - - let slow_sync = slow_chip.get_pin("SYNC").unwrap(); - let slow_cm = slow_chip.get_pin("CM").unwrap(); - let slow_ci = slow_chip.get_pin("CI").unwrap(); - let slow_phi1 = slow_chip.get_pin("PHI1").unwrap(); - let slow_phi2 = slow_chip.get_pin("PHI2").unwrap(); - - // Set settlement times to 0 - slow_sync - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - slow_cm - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - slow_ci - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - slow_phi1 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - slow_phi2 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - - // Set up for memory read - { - let mut sync_guard = slow_sync.lock().unwrap(); - let mut cm_guard = slow_cm.lock().unwrap(); - let mut ci_guard = slow_ci.lock().unwrap(); - 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); - } - slow_chip.update(); - - // Start address phase - { - let mut phi1_guard = slow_phi1.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - slow_chip.update(); - - // Apply address quickly - slow_chip.write_data_bus(0x06); // High nibble - slow_chip.update(); - slow_chip.write_data_bus(0x00); // Low nibble - slow_chip.update(); - - // Complete address phase - { - let mut phi1_guard = slow_phi1.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - slow_chip.update(); - - // Try to read data immediately without waiting for maximum latency - { - let mut phi2_guard = slow_phi2.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - slow_chip.update(); - - // At maximum access time, the chip should still be in WaitLatency - let state = slow_chip.get_timing_state(); - assert!( - state == TimingState::WaitLatency || state == TimingState::DriveData, - "Expected WaitLatency or DriveData, got {:?}", - state - ); - - // Wait for proper timing and then verify data - thread::sleep(Duration::from_nanos(760)); - slow_chip.update(); - - // Now data should be valid - let data = slow_chip.read_data_bus(); - assert_eq!(data, 0xBB); - - // Test edge case: clock stretching at maximum access time - // Test what happens when clock edges are delayed - let mut stretch_chip = Intel4001::new_with_access_time("STRETCH_ROM".to_string(), 750); - stretch_chip.base.set_running(true); - stretch_chip.load_rom_data(vec![0xDD], 0x70).unwrap(); - - let stretch_sync = stretch_chip.get_pin("SYNC").unwrap(); - let stretch_cm = stretch_chip.get_pin("CM").unwrap(); - let stretch_ci = stretch_chip.get_pin("CI").unwrap(); - let stretch_phi1 = stretch_chip.get_pin("PHI1").unwrap(); - let stretch_phi2 = stretch_chip.get_pin("PHI2").unwrap(); - - // Set settlement times to 0 - stretch_sync - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - stretch_cm - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - stretch_ci - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - stretch_phi1 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - stretch_phi2 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - - // Set up for memory read - { - let mut sync_guard = stretch_sync.lock().unwrap(); - let mut cm_guard = stretch_cm.lock().unwrap(); - let mut ci_guard = stretch_ci.lock().unwrap(); - 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); - } - stretch_chip.update(); - - // Start address phase with stretched clock - { - let mut phi1_guard = stretch_phi1.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - stretch_chip.update(); - - // Apply address with delays between nibbles - stretch_chip.write_data_bus(0x07); // High nibble - thread::sleep(Duration::from_nanos(100)); // Delay between nibbles - stretch_chip.update(); - stretch_chip.write_data_bus(0x00); // Low nibble - thread::sleep(Duration::from_nanos(100)); // Delay after low nibble - stretch_chip.update(); - - // Complete address phase with stretched clock - { - let mut phi1_guard = stretch_phi1.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - stretch_chip.update(); - - // Wait for maximum latency with additional stretching - thread::sleep(Duration::from_nanos(800)); // More than maximum - - // PHI2 high with stretched clock: Data phase - { - let mut phi2_guard = stretch_phi2.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - stretch_chip.update(); - - // Verify data is driven correctly even with clock stretching - let data = stretch_chip.read_data_bus(); - assert_eq!(data, 0xDD); - - // Complete cycle - { - let mut phi2_guard = stretch_phi2.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - stretch_chip.update(); - assert_eq!(stretch_chip.get_timing_state(), TimingState::Idle); - } - - // Helper function for edge case memory read testing at maximum access time - fn test_memory_read_edge_case_max( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - _d0_pin: &Arc>, - _d1_pin: &Arc>, - _d2_pin: &Arc>, - _d3_pin: &Arc>, - address: u16, - _expected_data: u8, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for maximum access time (750ns) - thread::sleep(Duration::from_nanos(760)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for data to be driven - thread::sleep(Duration::from_nanos(10)); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - #[test] - fn test_address_setup_hold_times() { - // Test address setup and hold timing requirements with comprehensive edge cases - let mut chip = Intel4001::new_with_access_time("SETUP_HOLD_ROM".to_string(), 500); // Standard access time - chip.base.set_running(true); - - // Get pin references - let sync_pin = chip.get_pin("SYNC").unwrap(); - let cm_pin = chip.get_pin("CM").unwrap(); - let ci_pin = chip.get_pin("CI").unwrap(); - let reset_pin = chip.get_pin("RESET").unwrap(); - let phi1_pin = chip.get_pin("PHI1").unwrap(); - let phi2_pin = chip.get_pin("PHI2").unwrap(); - let d0_pin = chip.get_pin("D0").unwrap(); - let d1_pin = chip.get_pin("D1").unwrap(); - let d2_pin = chip.get_pin("D2").unwrap(); - 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)); - 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)); - - // Test address setup time (minimum 100ns before PHI2 rising edge) - // Note: Intel 4004 has a 4-bit data bus, so we can only read 4 bits at a time - let address = 0x34; - let expected_data = 0x06; // 4-bit value (low nibble only) - - // Set up ROM data - chip.load_rom_data(vec![expected_data], address).unwrap(); - - // Test memory read using the helper function - test_memory_read( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - address as u8, - expected_data, - ); - - // Test multiple address setup/hold scenarios - for test_addr in 0x30..0x35 { - let test_data = vec![test_addr as u8 * 2]; - chip.load_rom_data(test_data, test_addr).unwrap(); - test_memory_read( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - test_addr as u8, - test_addr as u8 * 2, - ); - } - - // Enhanced edge case testing for address setup and hold times - - // Test edge case: minimum address setup time (100ns) - // Address must be stable for at least 100ns before PHI2 rising edge - let setup_test_addresses = [0x10, 0x20, 0x30, 0x40, 0x50]; - for &test_addr in &setup_test_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with minimum setup time - let result = test_address_setup_time( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 100, - ); // 100ns setup time - assert_eq!( - result, test_addr as u8, - "Failed minimum setup time test at address {}", - test_addr - ); - } - - // Test edge case: address hold time after PHI2 rising edge - // Address must remain stable for at least 50ns after PHI2 rising edge - let hold_test_addresses = [0x11, 0x21, 0x31, 0x41, 0x51]; - for &test_addr in &hold_test_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with minimum hold time - let result = test_address_hold_time( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 50, - ); // 50ns hold time - assert_eq!( - result, test_addr as u8, - "Failed minimum hold time test at address {}", - test_addr - ); - } - - // Test edge case: address setup time violations - // Test what happens when address changes too close to PHI2 rising edge - let mut violation_chip = Intel4001::new_with_access_time("VIOLATION_ROM".to_string(), 500); - violation_chip.base.set_running(true); - violation_chip.load_rom_data(vec![0x99], 0x60).unwrap(); - - let violation_sync = violation_chip.get_pin("SYNC").unwrap(); - let violation_cm = violation_chip.get_pin("CM").unwrap(); - let violation_ci = violation_chip.get_pin("CI").unwrap(); - let violation_phi1 = violation_chip.get_pin("PHI1").unwrap(); - let violation_phi2 = violation_chip.get_pin("PHI2").unwrap(); - - // Set settlement times to 0 - violation_sync - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - violation_cm - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - violation_ci - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - violation_phi1 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - violation_phi2 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - - // Test setup time violation - let result = test_address_setup_time( - &mut violation_chip, - &violation_sync, - &violation_cm, - &violation_ci, - &violation_phi1, - &violation_phi2, - 0x60, - 50, - ); // Only 50ns setup time (violation) - // The chip might still work due to implementation tolerances, but this tests the edge case - println!("Setup time violation test result: 0x{:02x}", result); - - // Test edge case: address hold time violations - // Test what happens when address changes too soon after PHI2 rising edge - let result = test_address_hold_time( - &mut violation_chip, - &violation_sync, - &violation_cm, - &violation_ci, - &violation_phi1, - &violation_phi2, - 0x60, - 25, - ); // Only 25ns hold time (violation) - // The chip might still work due to implementation tolerances, but this tests the edge case - println!("Hold time violation test result: 0x{:02x}", result); - - // Test edge case: address stability during both setup and hold - let stability_test_addresses = [0x70, 0x71, 0x72, 0x73, 0x74]; - for &test_addr in &stability_test_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with both setup and hold times - let result = test_address_stability( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 100, - 50, - ); // 100ns setup, 50ns hold - assert_eq!( - result, test_addr as u8, - "Failed address stability test at address {}", - test_addr - ); - } - - // Test edge case: address transitions at different phases - // Test address changes during different clock phases - let phase_test_addresses = [0x80, 0x81, 0x82, 0x83]; - for &test_addr in &phase_test_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test address transition during PHI1 high - let result1 = test_address_transition_timing( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - "PHI1_HIGH", - ); - assert_eq!( - result1, test_addr as u8, - "Failed address transition during PHI1_HIGH at address {}", - test_addr - ); - - // Test address transition during PHI1 low - let result2 = test_address_transition_timing( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - "PHI1_LOW", - ); - assert_eq!( - result2, test_addr as u8, - "Failed address transition during PHI1_LOW at address {}", - test_addr - ); - } - - // Test edge case: address nibble timing - // Test timing between high and low nibble latching - let nibble_test_addresses = [0x90, 0x91, 0x92, 0x93]; - for &test_addr in &nibble_test_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different delays between nibbles - for nibble_delay in [0, 50, 100, 200] { - let result = test_nibble_timing( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - nibble_delay, - ); - assert_eq!( - result, test_addr as u8, - "Failed nibble timing test with {}ns delay at address {}", - nibble_delay, test_addr - ); - } - } - - // Test edge case: address setup with I/O operations - // Test address timing when I/O operations are active - chip.load_rom_data(vec![0xA5], 0xA0).unwrap(); - chip.set_io_mode(IoMode::Output); - chip.set_io_direction(0, IoDirection::Output).unwrap(); - chip.set_io_port(0, 0x0F).unwrap(); - - let result = test_address_setup_with_io( - &mut chip, &sync_pin, &cm_pin, &ci_pin, &phi1_pin, &phi2_pin, 0xA0, 100, - ); - assert_eq!(result, 0xA5, "Failed address setup with active I/O"); - - // Test edge case: address setup at different clock frequencies - // Test address timing with different clock periods - let clock_periods = [100, 200, 500, 1000]; // ns - for &period in &clock_periods { - chip.load_rom_data(vec![0xB0 + (period / 100) as u8], 0xB0) - .unwrap(); - - let result = test_address_setup_with_clock_period( - &mut chip, &sync_pin, &cm_pin, &ci_pin, &phi1_pin, &phi2_pin, 0xB0, 100, period, - ); - assert_eq!( - result, - 0xB0 + (period / 100) as u8, - "Failed address setup with clock period {}ns", - period - ); - } - } - - // Helper function for testing address setup time - fn test_address_setup_time( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - setup_time_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for specified setup time - thread::sleep(Duration::from_nanos(setup_time_ns)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing address hold time - fn test_address_hold_time( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - hold_time_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for specified hold time - thread::sleep(Duration::from_nanos(hold_time_ns)); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing address stability - fn test_address_stability( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - setup_time_ns: u64, - hold_time_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for setup time - thread::sleep(Duration::from_nanos(setup_time_ns)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // Wait for hold time - thread::sleep(Duration::from_nanos(hold_time_ns)); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing address transition timing - fn test_address_transition_timing( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - phase: &str, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - match phase { - "PHI1_HIGH" => { - // PHI1 low to high: Address phase for high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble during PHI1 high - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble during PHI1 high - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - } - "PHI1_LOW" => { - // Set PHI1 high first - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set PHI1 low - this latches whatever was on the bus - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Set high nibble during PHI1 low - won't be latched yet - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 low to high: Next address phase cycle - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 low to high again - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - } - _ => panic!("Invalid phase: {}", phase), - } - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing nibble timing - fn test_nibble_timing( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - nibble_delay_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Delay between nibbles - thread::sleep(Duration::from_nanos(nibble_delay_ns)); - - // PHI1 low to high again: Address phase for low nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing address setup with I/O operations - fn test_address_setup_with_io( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - setup_time_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Perform I/O operation during address setup - chip.set_io_mode(IoMode::Output); - chip.set_io_direction(1, IoDirection::Output).unwrap(); - chip.set_io_port(1, 0x0A).unwrap(); - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for specified setup time - thread::sleep(Duration::from_nanos(setup_time_ns)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing address setup with different clock periods - fn test_address_setup_with_clock_period( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - setup_time_ns: u64, - clock_period_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // PHI1 low to high: Address phase for high nibble with clock period consideration - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for half clock period - thread::sleep(Duration::from_nanos(clock_period_ns / 2)); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for half clock period - thread::sleep(Duration::from_nanos(clock_period_ns / 2)); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for specified setup time - thread::sleep(Duration::from_nanos(setup_time_ns)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - #[test] - fn test_clock_edge_relationships() { - // Test proper timing relationships between clock edges with comprehensive edge cases - let mut chip = Intel4001::new_with_access_time("CLOCK_EDGE_ROM".to_string(), 400); // Medium access time - chip.base.set_running(true); - - // Get pin references - let sync_pin = chip.get_pin("SYNC").unwrap(); - let cm_pin = chip.get_pin("CM").unwrap(); - let ci_pin = chip.get_pin("CI").unwrap(); - let reset_pin = chip.get_pin("RESET").unwrap(); - let phi1_pin = chip.get_pin("PHI1").unwrap(); - let phi2_pin = chip.get_pin("PHI2").unwrap(); - let d0_pin = chip.get_pin("D0").unwrap(); - let d1_pin = chip.get_pin("D1").unwrap(); - let d2_pin = chip.get_pin("D2").unwrap(); - 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)); - 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)); - - // Test memory read with focus on clock edge relationships - // Note: Intel 4004 has a 4-bit data bus, so we can only read 4 bits at a time - let address = 0x45; - let expected_data = 0x07; // 4-bit value (low nibble only) - - // Set up ROM data - chip.load_rom_data(vec![expected_data], address).unwrap(); - - // Test memory read using the helper function - test_memory_read( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - address as u8, - expected_data, - ); - - // Test multiple clock edge scenarios - for test_addr in 0x40..0x45 { - let test_data = vec![test_addr as u8 * 3]; - chip.load_rom_data(test_data, test_addr).unwrap(); - test_memory_read( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - test_addr as u8, - test_addr as u8 * 3, - ); - } - - // Enhanced edge case testing for clock edge relationships - - // Test edge case: PHI1 and PHI2 non-overlapping operation - // Verify that PHI1 and PHI2 never overlap (both high at the same time) - let non_overlap_addresses = [0x10, 0x20, 0x30, 0x40]; - for &test_addr in &non_overlap_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - let result = test_phi1_phi2_non_overlapping( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - ); - assert_eq!( - result, test_addr as u8, - "Failed PHI1/PHI2 non-overlapping test at address {}", - test_addr - ); - } - - // Test edge case: PHI1 leading edge timing - // Test address latching on PHI1 rising edge - let leading_edge_addresses = [0x11, 0x21, 0x31, 0x41]; - for &test_addr in &leading_edge_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - let result = test_phi1_leading_edge( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - ); - assert_eq!( - result, test_addr as u8, - "Failed PHI1 leading edge test at address {}", - test_addr - ); - } - - // Test edge case: PHI2 trailing edge timing - // Test data valid on PHI2 falling edge - let trailing_edge_addresses = [0x12, 0x22, 0x32, 0x42]; - for &test_addr in &trailing_edge_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - let result = test_phi2_trailing_edge( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - ); - assert_eq!( - result, test_addr as u8, - "Failed PHI2 trailing edge test at address {}", - test_addr - ); - } - - // Test edge case: clock edge spacing - // Test minimum and maximum spacing between clock edges - let spacing_addresses = [0x13, 0x23, 0x33, 0x43]; - for &test_addr in &spacing_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test minimum spacing - let result1 = test_clock_edge_spacing( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 50, - ); // 50ns spacing - assert_eq!( - result1, test_addr as u8, - "Failed minimum clock edge spacing test at address {}", - test_addr - ); - - // Test maximum spacing - let result2 = test_clock_edge_spacing( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 1000, - ); // 1000ns spacing - assert_eq!( - result2, test_addr as u8, - "Failed maximum clock edge spacing test at address {}", - test_addr - ); - } - - // Test edge case: clock edge jitter - // Test behavior with clock edge timing variations - let jitter_addresses = [0x14, 0x24, 0x34, 0x44]; - for &test_addr in &jitter_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with positive jitter - let result1 = test_clock_edge_jitter( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 20, - ); // 20ns positive jitter - assert_eq!( - result1, test_addr as u8, - "Failed positive jitter test at address {}", - test_addr - ); - - // Test with negative jitter - let result2 = test_clock_edge_jitter( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - -20, - ); // 20ns negative jitter - assert_eq!( - result2, test_addr as u8, - "Failed negative jitter test at address {}", - test_addr - ); - } - - // Test edge case: clock edge violations - // Test what happens when clock edges occur too close together - let mut violation_chip = Intel4001::new_with_access_time("VIOLATION_CHIP".to_string(), 400); - violation_chip.base.set_running(true); - violation_chip.load_rom_data(vec![0x99], 0x50).unwrap(); - - let violation_sync = violation_chip.get_pin("SYNC").unwrap(); - let violation_cm = violation_chip.get_pin("CM").unwrap(); - let violation_ci = violation_chip.get_pin("CI").unwrap(); - let violation_phi1 = violation_chip.get_pin("PHI1").unwrap(); - let violation_phi2 = violation_chip.get_pin("PHI2").unwrap(); - - // Set settlement times to 0 - violation_sync - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - violation_cm - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - violation_ci - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - violation_phi1 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - violation_phi2 - .lock() - .unwrap() - .set_settlement_time(Duration::from_nanos(0)); - - // Test clock edge violation - let result = test_clock_edge_violation( - &mut violation_chip, - &violation_sync, - &violation_cm, - &violation_ci, - &violation_phi1, - &violation_phi2, - 0x50, - 10, - ); // 10ns spacing (violation) - // The chip might still work due to implementation tolerances, but this tests the edge case - println!("Clock edge violation test result: 0x{:02x}", result); - - // Test edge case: clock edge sequences - // Test different sequences of clock edges - let sequence_addresses = [0x15, 0x25, 0x35, 0x45]; - for &test_addr in &sequence_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test normal sequence: PHI1 high -> PHI1 low -> PHI2 high -> PHI2 low - let result1 = test_clock_edge_sequence( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - "NORMAL", - ); - assert_eq!( - result1, test_addr as u8, - "Failed normal clock edge sequence test at address {}", - test_addr - ); - - // Test reversed sequence: PHI2 high -> PHI2 low -> PHI1 high -> PHI1 low - let result2 = test_clock_edge_sequence( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - "REVERSED", - ); - // This might not work correctly, but tests the edge case - println!( - "Reversed clock edge sequence test result at address {}: 0x{:02x}", - test_addr, result2 - ); - - // Test simultaneous sequence: PHI1 and PHI2 high at same time - let result3 = test_clock_edge_sequence( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - "SIMULTANEOUS", - ); - // This should not work correctly, but tests the edge case - println!( - "Simultaneous clock edge sequence test result at address {}: 0x{:02x}", - test_addr, result3 - ); - } - - // Test edge case: clock edge duty cycle - // Test different duty cycles for PHI1 and PHI2 - let duty_cycle_addresses = [0x16, 0x26, 0x36, 0x46]; - for &test_addr in &duty_cycle_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test 25% duty cycle - let result1 = test_clock_edge_duty_cycle( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 25, - ); - assert_eq!( - result1, test_addr as u8, - "Failed 25% duty cycle test at address {}", - test_addr - ); - - // Test 50% duty cycle - let result2 = test_clock_edge_duty_cycle( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 50, - ); - assert_eq!( - result2, test_addr as u8, - "Failed 50% duty cycle test at address {}", - test_addr - ); - - // Test 75% duty cycle - let result3 = test_clock_edge_duty_cycle( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - 75, - ); - assert_eq!( - result3, test_addr as u8, - "Failed 75% duty cycle test at address {}", - test_addr - ); - } - - // Test edge case: clock edge frequency - // Test different clock frequencies - let frequency_addresses = [0x17, 0x27, 0x37, 0x47]; - let frequencies = [1000, 2000, 5000, 10000]; // Hz (periods: 1ms, 0.5ms, 0.2ms, 0.1ms) - for (i, &test_addr) in frequency_addresses.iter().enumerate() { - chip.load_rom_data(vec![test_addr as u8], (test_addr as u16).into()) - .unwrap(); - - let result = test_clock_edge_frequency( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - frequencies[i], - ); - assert_eq!( - result, test_addr as u8, - "Failed clock frequency test at address {} with frequency {}Hz", - test_addr, frequencies[i] - ); - } - } - - // Helper function for testing PHI1/PHI2 non-overlapping operation - fn test_phi1_phi2_non_overlapping( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Verify PHI2 is still low - assert_eq!(phi2_pin.lock().unwrap().read(), PinValue::Low); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(410)); // Slightly more than access time - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Verify PHI1 is still low - assert_eq!(phi1_pin.lock().unwrap().read(), PinValue::Low); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing PHI1 leading edge timing - fn test_phi1_leading_edge( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Verify state is Idle before PHI1 rising edge - assert_eq!(chip.get_timing_state(), TimingState::Idle); - - // PHI1 low to high: Address phase for high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Verify state is AddressPhase after PHI1 rising edge - assert_eq!(chip.get_timing_state(), TimingState::AddressPhase); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(410)); // Slightly more than access time - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing PHI2 trailing edge timing - fn test_phi2_trailing_edge( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(410)); // Slightly more than access time - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Verify state is DriveData after PHI2 rising edge - assert_eq!(chip.get_timing_state(), TimingState::DriveData); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Verify state is Idle after PHI2 falling edge - assert_eq!(chip.get_timing_state(), TimingState::Idle); - - data - } - - // Helper function for testing clock edge spacing - fn test_clock_edge_spacing( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - spacing_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for specified spacing between PHI1 falling and PHI2 rising - thread::sleep(Duration::from_nanos(spacing_ns)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing clock edge jitter - fn test_clock_edge_jitter( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - jitter_ns: i64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // PHI1 low to high: Address phase for high nibble with jitter - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - - // Apply jitter (positive or negative) - if jitter_ns > 0 { - thread::sleep(Duration::from_nanos(jitter_ns as u64)); - } - - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble with jitter - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - - // Apply jitter (positive or negative) - if jitter_ns > 0 { - thread::sleep(Duration::from_nanos(jitter_ns as u64)); - } - - chip.update(); - - // PHI1 low to high again: Address phase for low nibble with jitter - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - - // Apply jitter (positive or negative) - if jitter_ns > 0 { - thread::sleep(Duration::from_nanos(jitter_ns as u64)); - } - - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address with jitter - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - - // Apply jitter (positive or negative) - if jitter_ns > 0 { - thread::sleep(Duration::from_nanos(jitter_ns as u64)); - } - - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(410)); // Slightly more than access time - - // 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(); - pin_guard.set_driver(Some("TEST".to_string()), PinValue::HighZ); - } - chip.update(); - - // PHI2 low to high: Data phase with jitter - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - - // Apply jitter (positive or negative) - if jitter_ns > 0 { - thread::sleep(Duration::from_nanos(jitter_ns as u64)); - } - - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup with jitter - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - - // Apply jitter (positive or negative) - if jitter_ns > 0 { - thread::sleep(Duration::from_nanos(jitter_ns as u64)); - } - - chip.update(); - - data - } - - // Helper function for testing clock edge violations - fn test_clock_edge_violation( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - spacing_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for very short spacing (violation) - thread::sleep(Duration::from_nanos(spacing_ns)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing clock edge sequences - fn test_clock_edge_sequence( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - sequence: &str, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset (active LOW) - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset (HIGH = normal operation) - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - match sequence { - "NORMAL" => { - // Normal sequence: PHI1 high -> PHI1 low -> PHI1 high -> PHI1 low (two cycles for address) -> PHI2 high -> PHI2 low - // PHI1 low to high: Address phase for high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - thread::sleep(Duration::from_nanos(410)); - - // 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(); - pin_guard.set_driver(Some("TEST".to_string()), PinValue::HighZ); - } - chip.update(); - - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - let data = chip.read_data_bus(); - - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - return data; - } - "REVERSED" => { - // Reversed sequence: PHI2 high -> PHI2 low -> PHI1 high -> PHI1 low - // This is an invalid sequence for the Intel 4004 - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - thread::sleep(Duration::from_nanos(410)); - - // 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(); - pin_guard.set_driver(Some("TEST".to_string()), PinValue::HighZ); - } - chip.update(); - - return chip.read_data_bus(); - } - "SIMULTANEOUS" => { - // Simultaneous sequence: PHI1 and PHI2 high at same time - // This is an invalid sequence for the Intel 4004 (non-overlapping clocks required) - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - thread::sleep(Duration::from_nanos(410)); - - // 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(); - pin_guard.set_driver(Some("TEST".to_string()), PinValue::HighZ); - } - chip.update(); - - return chip.read_data_bus(); - } - _ => panic!("Invalid sequence: {}", sequence), - } - } - - // Helper function for testing clock edge duty cycle - fn test_clock_edge_duty_cycle( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - duty_cycle_percent: u8, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset (active LOW) - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset (HIGH = normal operation) - } - chip.update(); - - // 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(); - 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); - } - chip.update(); - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Calculate timing based on duty cycle - let total_period_ns = 1000; // 1kHz clock - let high_time_ns = (total_period_ns * duty_cycle_percent as u64) / 100; - - // PHI1 low to high: Address phase for high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for high time - thread::sleep(Duration::from_nanos(high_time_ns)); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for high time - thread::sleep(Duration::from_nanos(high_time_ns)); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(410)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for high time - thread::sleep(Duration::from_nanos(high_time_ns)); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing clock edge frequency - fn test_clock_edge_frequency( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - frequency_hz: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset (active LOW) - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset (HIGH = normal operation) - } - chip.update(); - - // 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(); - 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); - } - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Calculate timing based on frequency - let period_ns = 1_000_000_000 / frequency_hz; // Convert Hz to nanoseconds - let half_period_ns = period_ns / 2; - - // PHI1 low to high: Address phase for high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for half period - thread::sleep(Duration::from_nanos(half_period_ns)); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for half period - thread::sleep(Duration::from_nanos(half_period_ns)); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(410)); - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for half period - thread::sleep(Duration::from_nanos(half_period_ns)); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing access time tolerance - fn test_access_time_tolerance(chip: &mut Intel4001, address: u16, _expected_data: u8) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset (active LOW) - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset (HIGH = normal operation) - } - chip.update(); - - // Get pins - let sync_pin = chip.get_pin("SYNC").unwrap(); - let cm_pin = chip.get_pin("CM").unwrap(); - let ci_pin = chip.get_pin("CI").unwrap(); - let phi1_pin = chip.get_pin("PHI1").unwrap(); - let phi2_pin = chip.get_pin("PHI2").unwrap(); - - // 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(); - 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); - } - - // Ensure PHI2 is low initially - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble on data bus - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch high nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - 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(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set low nibble on data bus - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Latch low nibble and complete address - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with tolerance - let access_time = chip.get_access_time(); - thread::sleep(Duration::from_nanos(access_time + 50)); // Add 50ns tolerance - - // 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(); - 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(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing memory read tolerance - fn test_memory_read_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - timing_variation_ns: u64, - ) -> u8 { - // Reset to known state (RESET is active LOW) - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Assert reset (active LOW) - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); // Release reset (HIGH = normal operation) - } - chip.update(); - - // 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(); - 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); - } - - // PHI1 low to high: Address phase with timing variation - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - thread::sleep(Duration::from_nanos(timing_variation_ns)); // Add timing variation - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase with timing variation - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - thread::sleep(Duration::from_nanos(timing_variation_ns)); // Add timing variation - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // PHI2 low to high: Data phase with timing variation - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - thread::sleep(Duration::from_nanos(timing_variation_ns)); // Add timing variation - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup with timing variation - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - thread::sleep(Duration::from_nanos(timing_variation_ns)); // Add timing variation - chip.update(); - - data - } - - // Helper function for testing timing variation tolerance - fn test_timing_variation_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - variation_ns: u64, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // 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(); - 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); - } - - // PHI1 low to high: Address phase with variation - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble with variation - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - thread::sleep(Duration::from_nanos(variation_ns)); - chip.update(); - - // Set low nibble with variation - chip.write_data_bus((address & 0x0F) as u8); - thread::sleep(Duration::from_nanos(variation_ns)); - chip.update(); - - // PHI1 high to low: Complete address phase with variation - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with variation - thread::sleep(Duration::from_nanos(510 + variation_ns)); - - // PHI2 low to high: Data phase with variation - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup with variation - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing clock period tolerance - fn test_clock_period_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - clock_period_ns: u64, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // 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(); - 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); - } - - // PHI1 low to high: Address phase with clock period consideration - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for half clock period - thread::sleep(Duration::from_nanos(clock_period_ns / 2)); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Wait for half clock period - thread::sleep(Duration::from_nanos(clock_period_ns / 2)); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for clock period - thread::sleep(Duration::from_nanos(clock_period_ns)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for half clock period - thread::sleep(Duration::from_nanos(clock_period_ns / 2)); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing address setup tolerance - fn test_address_setup_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - setup_time_ns: u64, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for specified setup time - thread::sleep(Duration::from_nanos(setup_time_ns)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing address hold tolerance - fn test_address_hold_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - hold_time_ns: u64, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time - thread::sleep(Duration::from_nanos(510)); // Slightly more than access time - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Wait for specified hold time - thread::sleep(Duration::from_nanos(hold_time_ns)); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing voltage and temperature tolerance - fn test_voltage_temperature_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - voltage: f64, - temperature: f64, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Simulate voltage and temperature effects - // In a real implementation, this would affect timing parameters - // For this test, we'll just add a delay based on voltage and temperature - let voltage_delay = if voltage < 5.0 { - 20 - } else if voltage > 5.0 { - 10 - } else { - 0 - }; - let temperature_delay = if temperature < 25.0 { - 15 - } else if temperature > 25.0 { - 25 - } else { - 0 - }; - let total_delay = voltage_delay + temperature_delay; - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with voltage/temperature compensation - thread::sleep(Duration::from_nanos(510 + total_delay)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing voltage tolerance - fn test_voltage_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - voltage: f64, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Simulate voltage effects - // In a real implementation, this would affect timing parameters - // For this test, we'll just add a delay based on voltage - let voltage_delay = if voltage < 5.0 { - 20 - } else if voltage > 5.0 { - 10 - } else { - 0 - }; - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with voltage compensation - thread::sleep(Duration::from_nanos(510 + voltage_delay)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing temperature tolerance - fn test_temperature_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - temperature: f64, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Simulate temperature effects - // In a real implementation, this would affect timing parameters - // For this test, we'll just add a delay based on temperature - let temperature_delay = if temperature < 25.0 { - 15 - } else if temperature > 25.0 { - 25 - } else { - 0 - }; - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with temperature compensation - thread::sleep(Duration::from_nanos(510 + temperature_delay)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing manufacturing tolerance - fn test_manufacturing_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - variation_percent: i32, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Simulate manufacturing variations - // In a real implementation, this would affect timing parameters - // For this test, we'll just add a delay based on variation - let base_access_time = 500; // ns - let variation = (base_access_time * variation_percent as u64) / 100; - let adjusted_access_time = base_access_time + variation; - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for adjusted access time - thread::sleep(Duration::from_nanos(adjusted_access_time + 10)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing manufacturing variation - fn test_manufacturing_variation( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - variation_type: &str, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Simulate manufacturing variations - // In a real implementation, this would affect timing parameters - // For this test, we'll just add a delay based on variation type - let variation_delay = match variation_type { - "FAST" => -50, // 50ns faster - "SLOW" => 100, // 100ns slower - "TYPICAL" => 0, // No variation - "MIN" => -100, // 100ns faster (minimum) - "MAX" => 200, // 200ns slower (maximum) - _ => 0, - }; - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with variation - let base_access_time = 500; // ns - let adjusted_access_time = if variation_delay >= 0 { - base_access_time + variation_delay as u64 - } else { - base_access_time - (-variation_delay) as u64 - }; - thread::sleep(Duration::from_nanos(adjusted_access_time + 10)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing aging tolerance - fn test_aging_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - years: u32, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Simulate aging effects - // In a real implementation, this would affect timing parameters - // For this test, we'll just add a delay based on years - let aging_delay = years * 5; // 5ns per year - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with aging compensation - thread::sleep(Duration::from_nanos((510 + aging_delay) as u64)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing aging effect - fn test_aging_effect( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - aging_effect: &str, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Simulate aging effects - // In a real implementation, this would affect timing parameters - // For this test, we'll just add a delay based on aging effect - let aging_delay = match aging_effect { - "FRESH" => 0, // No aging - "WORN" => 50, // 50ns slower - "DEGRADED" => 100, // 100ns slower - "FAILING" => 200, // 200ns slower - _ => 0, - }; - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with aging compensation - thread::sleep(Duration::from_nanos(510 + aging_delay)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - // Helper function for testing extreme condition tolerance - fn test_extreme_condition_tolerance( - chip: &mut Intel4001, - sync_pin: &Arc>, - cm_pin: &Arc>, - ci_pin: &Arc>, - phi1_pin: &Arc>, - phi2_pin: &Arc>, - address: u16, - _expected_data: u8, - voltage: f64, - temperature: f64, - aging_years: u32, - ) -> u8 { - // Reset to known state - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - { - let reset_pin = chip.get_pin("RESET").unwrap(); - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Simulate extreme condition effects - // In a real implementation, this would affect timing parameters - // For this test, we'll just add a delay based on conditions - let voltage_delay = if voltage < 5.0 { - 20 - } else if voltage > 5.0 { - 10 - } else { - 0 - }; - let temperature_delay = if temperature < 25.0 { - 15 - } else if temperature > 25.0 { - 25 - } else { - 0 - }; - let aging_delay = aging_years * 5; // 5ns per year - let total_delay = voltage_delay + temperature_delay + aging_delay; - - // 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(); - 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); - } - - // PHI1 low to high: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Set high nibble - chip.write_data_bus(((address >> 4) & 0x0F) as u8); - chip.update(); - - // Set low nibble - chip.write_data_bus((address & 0x0F) as u8); - chip.update(); - - // PHI1 high to low: Complete address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - // Wait for access time with extreme condition compensation - thread::sleep(Duration::from_nanos((510 + total_delay) as u64)); - - // PHI2 low to high: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - chip.update(); - - // Read data - let data = chip.read_data_bus(); - - // PHI2 high to low: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - chip.update(); - - data - } - - #[test] - fn test_timing_tolerances() { - // Test behavior with timing variations and tolerances with comprehensive edge cases - let mut chip = Intel4001::new_with_access_time("TOLERANCE_ROM".to_string(), 500); // Standard access time - chip.base.set_running(true); - - // Get pin references - let sync_pin = chip.get_pin("SYNC").unwrap(); - let cm_pin = chip.get_pin("CM").unwrap(); - let ci_pin = chip.get_pin("CI").unwrap(); - let reset_pin = chip.get_pin("RESET").unwrap(); - let phi1_pin = chip.get_pin("PHI1").unwrap(); - let phi2_pin = chip.get_pin("PHI2").unwrap(); - let d0_pin = chip.get_pin("D0").unwrap(); - let d1_pin = chip.get_pin("D1").unwrap(); - let d2_pin = chip.get_pin("D2").unwrap(); - 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)); - 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)); - - // Test memory read with various timing tolerances - let address = 0x78; - let expected_data = 0x0A; // 4-bit value (low nibble only) - - // Set up ROM data - chip.load_rom_data(vec![expected_data], address).unwrap(); - - // Test memory read using the helper function - test_memory_read( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - address as u8, - expected_data, - ); - - // Test multiple timing tolerance scenarios - for test_addr in 0x78..0x80 { - let test_data = vec![test_addr as u8 * 2]; - chip.load_rom_data(test_data, test_addr).unwrap(); - test_memory_read( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - &d0_pin, - &d1_pin, - &d2_pin, - &d3_pin, - test_addr as u8, - test_addr as u8 * 2, - ); - } - - // Enhanced edge case testing for timing tolerances - - // Test edge case: access time tolerance variations - let tolerance_addresses = [0x10, 0x20, 0x30, 0x40]; - for &test_addr in &tolerance_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - let result = test_access_time_tolerance(&mut chip, test_addr as u16, test_addr as u8); - assert_eq!( - result, test_addr as u8, - "Failed access time tolerance test at address {}", - test_addr - ); - } - - // Test edge case: memory read with timing variations - let variation_addresses = [0x11, 0x21, 0x31, 0x41]; - for &test_addr in &variation_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different timing variations - for variation in [0, 10, 20, 50, 100] { - let result = test_memory_read_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - variation, - ); - assert_eq!( - result, test_addr as u8, - "Failed memory read tolerance test with {}ns variation at address {}", - variation, test_addr - ); - } - } - - // Test edge case: timing variation tolerance - let variation_test_addresses = [0x12, 0x22, 0x32, 0x42]; - for &test_addr in &variation_test_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different timing variations - for variation in [0, 25, 50, 75, 100] { - let result = test_timing_variation_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - variation, - ); - assert_eq!( - result, test_addr as u8, - "Failed timing variation tolerance test with {}ns variation at address {}", - variation, test_addr - ); - } - } - - // Test edge case: clock period tolerance - let clock_period_addresses = [0x13, 0x23, 0x33, 0x43]; - for &test_addr in &clock_period_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different clock periods - for period in [100, 200, 500, 1000] { - let result = test_clock_period_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - period, - ); - assert_eq!( - result, test_addr as u8, - "Failed clock period tolerance test with {}ns period at address {}", - period, test_addr - ); - } - } - - // Test edge case: address setup tolerance - let setup_tolerance_addresses = [0x14, 0x24, 0x34, 0x44]; - for &test_addr in &setup_tolerance_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different setup times - for setup_time in [50, 100, 150, 200] { - let result = test_address_setup_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - setup_time, - ); - assert_eq!( - result, test_addr as u8, - "Failed address setup tolerance test with {}ns setup time at address {}", - setup_time, test_addr - ); - } - } - - // Test edge case: address hold tolerance - let hold_tolerance_addresses = [0x15, 0x25, 0x35, 0x45]; - for &test_addr in &hold_tolerance_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different hold times - for hold_time in [25, 50, 75, 100] { - let result = test_address_hold_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - hold_time, - ); - assert_eq!( - result, test_addr as u8, - "Failed address hold tolerance test with {}ns hold time at address {}", - hold_time, test_addr - ); - } - } - - // Test edge case: voltage and temperature tolerance - let voltage_temp_addresses = [0x16, 0x26, 0x36, 0x46]; - for &test_addr in &voltage_temp_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different voltage and temperature combinations - let test_conditions = [ - (4.5, 0.0), // Low voltage, low temperature - (5.0, 25.0), // Nominal voltage, nominal temperature - (5.5, 50.0), // High voltage, high temperature - (4.0, -10.0), // Very low voltage, very low temperature - (6.0, 70.0), // Very high voltage, very high temperature - ]; - - for (voltage, temperature) in test_conditions { - let result = test_voltage_temperature_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - voltage, - temperature, - ); - assert_eq!( - result, test_addr as u8, - "Failed voltage/temperature tolerance test at address {} with {}V, {}°C", - test_addr, voltage, temperature - ); - } - } - - // Test edge case: voltage tolerance - let voltage_addresses = [0x17, 0x27, 0x37, 0x47]; - for &test_addr in &voltage_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different voltages - let test_voltages = [3.5, 4.0, 4.5, 5.0, 5.5, 6.0]; - for voltage in test_voltages { - let result = test_voltage_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - voltage, - ); - assert_eq!( - result, test_addr as u8, - "Failed voltage tolerance test at address {} with {}V", - test_addr, voltage - ); - } - } - - // Test edge case: temperature tolerance - let temperature_addresses = [0x18, 0x28, 0x38, 0x48]; - for &test_addr in &temperature_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different temperatures - let test_temperatures = [-20.0, 0.0, 25.0, 50.0, 70.0, 85.0]; - for temperature in test_temperatures { - let result = test_temperature_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - temperature, - ); - assert_eq!( - result, test_addr as u8, - "Failed temperature tolerance test at address {} with {}°C", - test_addr, temperature - ); - } - } - - // Test edge case: manufacturing tolerance - let manufacturing_addresses = [0x19, 0x29, 0x39, 0x49]; - for &test_addr in &manufacturing_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different manufacturing variations - let variations = [-20, -10, 0, 10, 20]; // Percentage variation - for variation in variations { - let result = test_manufacturing_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - variation, - ); - assert_eq!( - result, test_addr as u8, - "Failed manufacturing tolerance test at address {} with {}% variation", - test_addr, variation - ); - } - } - - // Test edge case: manufacturing variation - let manufacturing_var_addresses = [0x1A, 0x2A, 0x3A, 0x4A]; - for &test_addr in &manufacturing_var_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different manufacturing variation types - let variation_types = ["FAST", "SLOW", "TYPICAL", "MIN", "MAX"]; - for variation_type in variation_types { - let result = test_manufacturing_variation( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - variation_type, - ); - assert_eq!( - result, test_addr as u8, - "Failed manufacturing variation test at address {} with {} variation", - test_addr, variation_type - ); - } - } - - // Test edge case: aging tolerance - let aging_addresses = [0x1B, 0x2B, 0x3B, 0x4B]; - for &test_addr in &aging_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different aging years - let aging_years = [0, 1, 5, 10, 20, 30]; - for years in aging_years { - let result = test_aging_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - years, - ); - assert_eq!( - result, test_addr as u8, - "Failed aging tolerance test at address {} with {} years", - test_addr, years - ); - } - } - - // Test edge case: aging effect - let aging_effect_addresses = [0x1C, 0x2C, 0x3C, 0x4C]; - for &test_addr in &aging_effect_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with different aging effects - let aging_effects = ["FRESH", "WORN", "DEGRADED", "FAILING"]; - for aging_effect in aging_effects { - let result = test_aging_effect( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - aging_effect, - ); - assert_eq!( - result, test_addr as u8, - "Failed aging effect test at address {} with {} effect", - test_addr, aging_effect - ); - } - } - - // Test edge case: extreme condition tolerance - let extreme_addresses = [0x1D, 0x2D, 0x3D, 0x4D]; - for &test_addr in &extreme_addresses { - chip.load_rom_data(vec![test_addr as u8], test_addr) - .unwrap(); - - // Test with extreme combinations of voltage, temperature, and aging - let extreme_conditions = [ - (3.5, -20.0, 30), // Low voltage, low temperature, high aging - (6.0, 85.0, 30), // High voltage, high temperature, high aging - (4.0, 0.0, 20), // Low voltage, low temperature, medium aging - (5.5, 70.0, 10), // High voltage, high temperature, low aging - ]; - - for (voltage, temperature, aging_years) in extreme_conditions { - let result = test_extreme_condition_tolerance( - &mut chip, - &sync_pin, - &cm_pin, - &ci_pin, - &phi1_pin, - &phi2_pin, - test_addr as u16, - test_addr as u8, - voltage, - temperature, - aging_years, - ); - assert_eq!(result, test_addr as u8, - "Failed extreme condition tolerance test at address {} with {}V, {}°C, {} years", - test_addr, voltage, temperature, aging_years); - } - } - - // Test with different access times - let mut fast_chip = Intel4001::new_with_access_time("FAST_ROM".to_string(), 200); - fast_chip.base.set_running(true); - let mut slow_chip = Intel4001::new_with_access_time("SLOW_ROM".to_string(), 750); - slow_chip.base.set_running(true); - - // Test fast chip - let fast_address = 0x90; - let fast_expected = 0x12; - fast_chip - .load_rom_data(vec![fast_expected], fast_address) - .unwrap(); - - // Test slow chip - let slow_address = 0xA0; - let slow_expected = 0x34; - slow_chip - .load_rom_data(vec![slow_expected], slow_address) - .unwrap(); - - // Both chips should work correctly with their respective access times - // Note: We can't directly test the timing differences without more complex - // timing simulation, but we can verify that both chips can read data correctly - } - - #[test] - fn comprehensive_intel4001_integration_test() { - // Setup section - println!("=== Comprehensive Intel 4001 Integration Test: Setup ==="); - - // Create Intel4001 with fast access time - let mut rom = Intel4001::new_with_access_time("TestROM".to_string(), 1); // 1ns for fast access - rom.base.set_running(true); - - // Load test data: simple arithmetic sequence - let test_data = vec![ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x10, 0x20, 0x30, 0x40, 0x50, 0xFF, - ]; - rom.load_rom_data(test_data.clone(), 0).unwrap(); - - // Verify test data loaded - for (i, &data) in test_data.iter().enumerate() { - assert_eq!(rom.read_rom(i as u8).unwrap(), data); - } - - // Get pin references - let sync_pin = rom.get_pin("SYNC").unwrap(); - let cm_pin = rom.get_pin("CM").unwrap(); - let ci_pin = rom.get_pin("CI").unwrap(); - let reset_pin = rom.get_pin("RESET").unwrap(); - let phi1_pin = rom.get_pin("PHI1").unwrap(); - let phi2_pin = rom.get_pin("PHI2").unwrap(); - let d0_pin = rom.get_pin("D0").unwrap(); - let d1_pin = rom.get_pin("D1").unwrap(); - let d2_pin = rom.get_pin("D2").unwrap(); - 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)); - 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)); - - // 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); - - // Set initial pin states - // Set reset high initially - { - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::Idle); - assert_eq!(rom.get_io_mode(), IoMode::Input); - - // Set reset low - { - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - - // Memory Access Verification Section - println!("=== Memory Access Verification ==="); - - // Set data bus to 0 to avoid interference - for i in 0..4 { - let pin = rom.get_pin(&format!("D{}", i)).unwrap(); - let mut pin_guard = pin.lock().unwrap(); - pin_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - - // Ensure state is Idle - { - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - rom.update(); - { - let mut reset_guard = reset_pin.lock().unwrap(); - reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::Idle); - - // Set SYNC=High, CM=High, CI=Low for memory mode. - { - let mut sync_guard = sync_pin.lock().unwrap(); - let mut cm_guard = cm_pin.lock().unwrap(); - let mut ci_guard = ci_pin.lock().unwrap(); - 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); - } - - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::Idle); - - // Now loop over test addresses - for (i, &expected_data) in test_data.iter().enumerate() { - let address = i as u8; - println!( - "Testing address 0x{:02x} with expected data 0x{:02x}", - address, expected_data - ); - - // Ensure PHI2 is Low - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - - // Ensure PHI1 is Low for rising edge - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - rom.update(); - - // PHI1 rising: Address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::AddressPhase); - - // Write high nibble - rom.write_data_bus((address >> 4) & 0x0F); - rom.update(); - - // Write low nibble - rom.write_data_bus(address & 0x0F); - rom.update(); - rom.update(); // Additional update to trigger state transition - assert_eq!(rom.get_timing_state(), TimingState::WaitLatency); - - // Wait for latency (1ns, but since access time is 200ns, need to wait) - thread::sleep(Duration::from_nanos(10)); // As in existing test - - // PHI2 rising: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::DriveData); - - // Check data on bus - let data = rom.read_data_bus(); - assert_eq!(data, expected_data); - - // PHI2 falling: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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); - } - - println!("Memory Access Verification completed successfully!"); - - // Pin-Level Testing Section - println!("=== Pin-Level Testing ==="); - - // Set control pins to Low for initial state testing - { - 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 phi1_guard = phi1_pin.lock().unwrap(); - let mut phi2_guard = phi2_pin.lock().unwrap(); - 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); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - - // Test each pin's initial state (HighZ for data/IO, Low for control) - 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); - - // I/O pins should also be HighZ initially - let io0_pin = rom.get_pin("IO0").unwrap(); - let io1_pin = rom.get_pin("IO1").unwrap(); - let io2_pin = rom.get_pin("IO2").unwrap(); - let io3_pin = rom.get_pin("IO3").unwrap(); - assert_eq!(io0_pin.lock().unwrap().read(), PinValue::HighZ); - assert_eq!(io1_pin.lock().unwrap().read(), PinValue::HighZ); - assert_eq!(io2_pin.lock().unwrap().read(), PinValue::HighZ); - assert_eq!(io3_pin.lock().unwrap().read(), PinValue::HighZ); - - // Control pins should be Low initially - assert_eq!(sync_pin.lock().unwrap().read(), PinValue::Low); - assert_eq!(cm_pin.lock().unwrap().read(), PinValue::Low); - assert_eq!(ci_pin.lock().unwrap().read(), PinValue::Low); - assert_eq!(reset_pin.lock().unwrap().read(), PinValue::Low); // After setting to Low - assert_eq!(phi1_pin.lock().unwrap().read(), PinValue::Low); - assert_eq!(phi2_pin.lock().unwrap().read(), PinValue::Low); - - // Set drivers for each pin (High, Low) and verify read values - // Test D0: Set to High - { - let mut d0_guard = d0_pin.lock().unwrap(); - d0_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - assert_eq!(d0_pin.lock().unwrap().read(), PinValue::High); - - // Test D0: Set to Low - { - let mut d0_guard = d0_pin.lock().unwrap(); - d0_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - assert_eq!(d0_pin.lock().unwrap().read(), PinValue::Low); - - // Test SYNC: Set to High - { - let mut sync_guard = sync_pin.lock().unwrap(); - sync_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - assert_eq!(sync_pin.lock().unwrap().read(), PinValue::High); - - // Test SYNC: Set to Low - { - let mut sync_guard = sync_pin.lock().unwrap(); - sync_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - assert_eq!(sync_pin.lock().unwrap().read(), PinValue::Low); - - // Test HighZ state for data and IO pins - // D0 back to HighZ - { - let mut d0_guard = d0_pin.lock().unwrap(); - d0_guard.set_driver(Some("TEST".to_string()), PinValue::HighZ); - } - assert_eq!(d0_pin.lock().unwrap().read(), PinValue::HighZ); - - // IO0 to HighZ (should already be) - assert_eq!(io0_pin.lock().unwrap().read(), PinValue::HighZ); - - // Simulate clock edges (PHI1/2 rising/falling) and check for state changes - // Set up for memory access to trigger state changes - { - let mut sync_guard = sync_pin.lock().unwrap(); - let mut cm_guard = cm_pin.lock().unwrap(); - let mut ci_guard = ci_pin.lock().unwrap(); - 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 - } - rom.update(); // Update to process pin changes - - // PHI1 rising: Should start address phase - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::AddressPhase); - - // Latch address nibbles to progress state - rom.write_data_bus(0x00); // High nibble - rom.update(); - - // PHI1 falling - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - rom.update(); - - // PHI1 rising again for low nibble - { - let mut phi1_guard = phi1_pin.lock().unwrap(); - phi1_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - rom.write_data_bus(0x00); // Low nibble - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::WaitLatency); - - // Latency is immediate for testing - - // PHI2 rising: Data phase - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::DriveData); - - // PHI2 falling: Cleanup - { - let mut phi2_guard = phi2_pin.lock().unwrap(); - phi2_guard.set_driver(Some("TEST".to_string()), PinValue::Low); - } - rom.update(); - assert_eq!(rom.get_timing_state(), TimingState::Idle); - - // Assert pin values match expectations - // After cleanup, 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); - - println!("Pin-Level Testing completed successfully!"); - - // I/O Integration Testing Section - println!("=== I/O Integration Testing ==="); - - // Set CI=High for I/O mode - { - let mut ci_guard = ci_pin.lock().unwrap(); - ci_guard.set_driver(Some("TEST".to_string()), PinValue::High); - } - rom.update(); - - // Test each I/O port (0-3): Set mode to Output, write data, verify port value and direction - for port in 0..4 { - println!("Testing I/O port {}", port); - - // Set to Output mode - rom.set_io_direction(port, IoDirection::Output).unwrap(); - rom.set_io_mode(IoMode::Output); - rom.update(); - - // Write data to port - let test_value = ((port + 1) * 0x05) as u8; // 0x05, 0x0A, 0x0F, 0x14 - rom.set_io_port(port, test_value).unwrap(); - rom.update(); - - // Verify port value - assert_eq!(rom.get_io_port(port).unwrap(), test_value); - - // Verify direction - assert_eq!(rom.get_io_direction(port).unwrap(), IoDirection::Output); - - // Test I/O direction control and data flow - // In output mode, data should be driven to I/O pins - // Note: In real hardware, output would drive the pin, but in this sim, it's internal - // For testing, we check the latch - assert_eq!(rom.get_output_latch(), test_value); - } - - // Test Input mode - for port in 0..4 { - println!("Testing I/O port {} in Input mode", port); - - rom.set_io_direction(port, IoDirection::Input).unwrap(); - rom.set_io_mode(IoMode::Input); - rom.update(); - - // Set port value for input - let input_value = ((port + 1) * 0x03) as u8; // 0x03, 0x06, 0x09, 0x0C - rom.set_io_port(port, input_value).unwrap(); - rom.update(); - - // Verify port value - assert_eq!(rom.get_io_port(port).unwrap(), input_value); - - // Verify direction - assert_eq!(rom.get_io_direction(port).unwrap(), IoDirection::Input); - - // In input mode, reading should get the value - assert_eq!(rom.get_input_latch(), input_value); - } - - // Test RDM/WRM operations via control pins - // Simulate WRM (Write ROM, but for I/O) - rom.set_io_mode(IoMode::Output); - rom.write_data_bus(0x0F); // Data to write - rom.update(); - // For port 0 - rom.write_data_bus(0x00); // Address port 0 - rom.update(); - // This should set the port - assert_eq!(rom.get_io_port(0).unwrap(), 0x0F); - - // Simulate RDM (Read Data Memory, for I/O) - rom.set_io_mode(IoMode::Input); - rom.write_data_bus(0x00); // Address port 0 - rom.update(); - // Should read the value - assert_eq!(rom.get_input_latch(), 0x0F); - - println!("I/O Integration Testing completed successfully!"); - - // Debugging Features Section - println!("=== Debugging Features ==="); - - // Include comprehensive logging and state inspection - rom.debug_state_transitions("Comprehensive Test"); - - // Provide pin state snapshots at each test phase - println!( - "Final 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() - ); - - println!( - "Data pins: D0: {:?}, D1: {:?}, D2: {:?}, D3: {:?}", - d0_pin.lock().unwrap().read(), - d1_pin.lock().unwrap().read(), - d2_pin.lock().unwrap().read(), - d3_pin.lock().unwrap().read() - ); - - println!( - "I/O pins: IO0: {:?}, IO1: {:?}, IO2: {:?}, IO3: {:?}", - io0_pin.lock().unwrap().read(), - io1_pin.lock().unwrap().read(), - io2_pin.lock().unwrap().read(), - io3_pin.lock().unwrap().read() - ); - - // Enable step-through debugging of memory access cycles - // (Already done in memory access section) - - // Include failure analysis and diagnostic information - // If any assertion fails, the test will stop with details - - println!("Debugging Features completed successfully!"); - - // Test Data Section - println!("=== Test Data ==="); - - // Use a known test program (e.g., simple arithmetic sequence) - // Already loaded: vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x10, 0x20, 0x30, 0x40, 0x50, 0xFF] - - // Include edge case data patterns for thorough testing - let edge_cases = vec![ - (0x00, "All zeros"), - (0xFF, "All ones"), - (0x55, "Alternating bits"), - (0xAA, "Alternating bits inverted"), - (0x0F, "Low nibble ones"), - (0xF0, "High nibble ones"), - ]; - - for (data, desc) in edge_cases { - println!("Testing edge case: {} (0x{:02x})", desc, data); - rom.load_rom_data(vec![data; 256], 0).unwrap(); - let read_data = rom.read_rom(0).unwrap(); - assert_eq!(read_data, data, "Failed for {}", desc); - } - - // Provide both valid and invalid test scenarios - // Valid: addresses 0-255 - for addr in 0..10 { - // Test first 10 - let data = rom.read_rom(addr).unwrap(); - assert_eq!(data, 0x00); // Since we loaded all zeros last - } - - // Test boundary address 0xFF - assert_eq!(rom.read_rom(255).unwrap(), 0x00); // Since we loaded all zeros - - println!("Test Data completed successfully!"); - - println!("Comprehensive Intel 4001 Integration Test completed successfully!"); - } }