Unified the 400x state machine for address latching
Fixed timing issues
This commit is contained in:
parent
e17d6ad177
commit
633463e370
26 changed files with 11904 additions and 2471 deletions
547
tests/intel_4002_state_machine_test.rs
Normal file
547
tests/intel_4002_state_machine_test.rs
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
//! Intel 4002 RAM Unified State Machine Diagnostic Test
|
||||
//!
|
||||
//! This test isolates Intel 4002 RAM unified state machine to verify that it correctly
|
||||
//! progresses through all states: Idle → AddressPhase → WaitLatency → ReadData/WriteData/OutputPort → Idle
|
||||
//!
|
||||
//! The test focuses on unified state machine progression without involving other system components.
|
||||
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use rusty_emu::component::Component;
|
||||
use rusty_emu::components::common::intel_400x::{Intel400xTimingState, TimingState};
|
||||
use rusty_emu::components::memory::intel_4002::Intel4002;
|
||||
use rusty_emu::pin::PinValue;
|
||||
|
||||
/// Test helper to create a test RAM with minimal setup
|
||||
fn create_test_ram() -> Intel4002 {
|
||||
// Create RAM with 1ns access time for fast testing
|
||||
let mut ram = Intel4002::new_with_access_time("TEST_RAM".to_string(), 1);
|
||||
|
||||
// Initialize RAM with test data using write_ram_direct
|
||||
for (i, &value) in [0x0A, 0x0B, 0x0C, 0x0D, 0x0E].iter().enumerate() {
|
||||
ram.write_ram_direct(i as u8, value).unwrap();
|
||||
}
|
||||
|
||||
ram
|
||||
}
|
||||
|
||||
/// Test helper to wait for pin settlement time
|
||||
fn wait_for_pin_settlement() {
|
||||
thread::sleep(Duration::from_nanos(10)); // 10ns settlement time
|
||||
}
|
||||
|
||||
/// Test helper to set control pins for RAM operation
|
||||
fn setup_ram_operation(ram: &Intel4002, sync_high: bool, cm_high: bool) {
|
||||
let sync_pin = ram.get_pin("SYNC").unwrap();
|
||||
// P0 is actually CM pin for Intel 4002, so we should use it as CM pin
|
||||
let cm_pin = ram.get_pin("CM").unwrap();
|
||||
|
||||
// Set control pins
|
||||
{
|
||||
let mut sync_guard = sync_pin.lock().unwrap();
|
||||
let mut cm_guard = cm_pin.lock().unwrap();
|
||||
|
||||
sync_guard.set_driver(
|
||||
Some("TEST".to_string()),
|
||||
if sync_high {
|
||||
PinValue::High
|
||||
} else {
|
||||
PinValue::Low
|
||||
},
|
||||
);
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::Low); // Start with CM low for read operation
|
||||
}
|
||||
|
||||
wait_for_pin_settlement();
|
||||
}
|
||||
|
||||
/// Test helper to set data bus value
|
||||
fn set_data_bus(ram: &Intel4002, value: u8) {
|
||||
let nibble = value & 0x0F; // Only lower 4 bits
|
||||
|
||||
for i in 0..4 {
|
||||
if let Ok(pin) = ram.get_pin(&format!("D{}", i)) {
|
||||
if let Ok(mut pin_guard) = pin.lock() {
|
||||
let bit_value = (nibble >> i) & 1;
|
||||
let pin_value = if bit_value == 1 {
|
||||
PinValue::High
|
||||
} else {
|
||||
PinValue::Low
|
||||
};
|
||||
pin_guard.set_driver(Some("TEST".to_string()), pin_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait_for_pin_settlement();
|
||||
}
|
||||
|
||||
/// Test helper to clear data bus drivers
|
||||
fn clear_data_bus_drivers(ram: &Intel4002) {
|
||||
for i in 0..4 {
|
||||
if let Ok(pin) = ram.get_pin(&format!("D{}", i)) {
|
||||
if let Ok(mut pin_guard) = pin.lock() {
|
||||
pin_guard.remove_driver("TEST");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait_for_pin_settlement();
|
||||
}
|
||||
|
||||
/// Test helper to generate a clock edge
|
||||
fn generate_clock_edge(ram: &mut Intel4002, phi1_high: bool, phi2_high: bool) {
|
||||
let phi1_pin = ram.get_pin("PHI1").unwrap();
|
||||
let phi2_pin = ram.get_pin("PHI2").unwrap();
|
||||
|
||||
// Set clock pins
|
||||
{
|
||||
let mut phi1_guard = phi1_pin.lock().unwrap();
|
||||
let mut phi2_guard = phi2_pin.lock().unwrap();
|
||||
|
||||
phi1_guard.set_driver(
|
||||
Some("TEST".to_string()),
|
||||
if phi1_high {
|
||||
PinValue::High
|
||||
} else {
|
||||
PinValue::Low
|
||||
},
|
||||
);
|
||||
phi2_guard.set_driver(
|
||||
Some("TEST".to_string()),
|
||||
if phi2_high {
|
||||
PinValue::High
|
||||
} else {
|
||||
PinValue::Low
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
wait_for_pin_settlement();
|
||||
|
||||
// Update to process: edge
|
||||
ram.update();
|
||||
}
|
||||
|
||||
/// Test helper to generate a complete clock cycle
|
||||
fn generate_clock_cycle(ram: &mut Intel4002) {
|
||||
// Start with both clocks low
|
||||
generate_clock_edge(ram, false, false);
|
||||
|
||||
// Φ1 rising edge
|
||||
generate_clock_edge(ram, true, false);
|
||||
|
||||
// Φ1 falling edge
|
||||
generate_clock_edge(ram, false, false);
|
||||
|
||||
// Φ2 rising edge
|
||||
generate_clock_edge(ram, false, true);
|
||||
|
||||
// Φ2 falling edge
|
||||
generate_clock_edge(ram, false, false);
|
||||
}
|
||||
|
||||
/// Test RAM read operation state progression
|
||||
#[test]
|
||||
fn test_ram_read_state_progression() {
|
||||
println!("=== Testing RAM Read Operation State Progression ===");
|
||||
|
||||
let mut ram = create_test_ram();
|
||||
|
||||
// Initially should be in idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
println!("Initial state: {:?}", ram.get_timing_state());
|
||||
|
||||
// Set up for RAM read operation
|
||||
setup_ram_operation(&ram, true, true); // SYNC=1, CM=1 for RAM operation
|
||||
|
||||
// Set address high nibble (0x0) on data bus
|
||||
set_data_bus(&ram, 0x0);
|
||||
|
||||
// Generate Φ1 rising edge to start address phase and latch high nibble
|
||||
generate_clock_edge(&mut ram, true, false);
|
||||
|
||||
// Should have transitioned to AddressPhase and latched high nibble
|
||||
assert_eq!(ram.get_timing_state(), TimingState::AddressPhase);
|
||||
assert_eq!(ram.get_address_high_nibble(), Some(0x0));
|
||||
println!(
|
||||
"After high nibble: state={:?}, high_nibble={:?}",
|
||||
ram.get_timing_state(),
|
||||
ram.get_address_high_nibble()
|
||||
);
|
||||
|
||||
// Φ1 falling edge
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Set address low nibble (0x1) on data bus
|
||||
set_data_bus(&ram, 0x1);
|
||||
|
||||
// Generate Φ1 rising edge to latch low nibble
|
||||
generate_clock_edge(&mut ram, true, false);
|
||||
|
||||
// Should have latched low nibble
|
||||
assert_eq!(ram.get_address_low_nibble(), Some(0x1));
|
||||
println!(
|
||||
"After low nibble: high_nibble={:?}, low_nibble={:?}",
|
||||
ram.get_address_high_nibble(),
|
||||
ram.get_address_low_nibble()
|
||||
);
|
||||
|
||||
// Φ1 falling edge
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Should have assembled full address and transitioned to WaitLatency
|
||||
// Note: We can't directly access last_address, ram_state, or full_address_ready as they are private
|
||||
// We can infer state from the timing state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::WaitLatency);
|
||||
println!(
|
||||
"Address latched: high_nibble={:?}, low_nibble={:?}",
|
||||
ram.get_address_high_nibble(),
|
||||
ram.get_address_low_nibble()
|
||||
);
|
||||
|
||||
// Clear data bus drivers before RAM drives it
|
||||
clear_data_bus_drivers(&ram);
|
||||
|
||||
// Generate Φ2 rising edge to handle data operation
|
||||
generate_clock_edge(&mut ram, false, true);
|
||||
|
||||
// Should have transitioned to ReadData state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::DriveData);
|
||||
println!("After Φ2 rising: state={:?}", ram.get_timing_state());
|
||||
|
||||
// Check that RAM is driving data bus with correct data
|
||||
let d0_pin = ram.get_pin("D0").unwrap();
|
||||
let d1_pin = ram.get_pin("D1").unwrap();
|
||||
let d2_pin = ram.get_pin("D2").unwrap();
|
||||
let d3_pin = ram.get_pin("D3").unwrap();
|
||||
|
||||
// Read: data bus value
|
||||
let mut data_value = 0;
|
||||
if d0_pin.lock().unwrap().read() == PinValue::High {
|
||||
data_value |= 1 << 0;
|
||||
}
|
||||
if d1_pin.lock().unwrap().read() == PinValue::High {
|
||||
data_value |= 1 << 1;
|
||||
}
|
||||
if d2_pin.lock().unwrap().read() == PinValue::High {
|
||||
data_value |= 1 << 2;
|
||||
}
|
||||
if d3_pin.lock().unwrap().read() == PinValue::High {
|
||||
data_value |= 1 << 3;
|
||||
}
|
||||
|
||||
// Should be reading: value at address 0x01 (0x0B from our test data)
|
||||
assert_eq!(data_value, 0x0B);
|
||||
println!("Data bus value: 0x{:X} (expected: 0x0B)", data_value);
|
||||
|
||||
// Generate Φ2 falling edge to complete operation
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Should have returned to idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
println!("Final state: {:?}", ram.get_timing_state());
|
||||
|
||||
println!("✅ RAM read operation state progression test passed!");
|
||||
}
|
||||
|
||||
/// Test RAM write operation state progression
|
||||
#[test]
|
||||
fn test_ram_write_state_progression() {
|
||||
println!("=== Testing RAM Write Operation State Progression ===");
|
||||
|
||||
let mut ram = create_test_ram();
|
||||
|
||||
// Initially should be in idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
println!("Initial state: {:?}", ram.get_timing_state());
|
||||
|
||||
// Set up for RAM write operation
|
||||
setup_ram_operation(&ram, true, true); // SYNC=1, CM=1 for RAM operation
|
||||
|
||||
// Set address high nibble (0x0) on data bus
|
||||
set_data_bus(&ram, 0x0);
|
||||
|
||||
// Generate Φ1 rising edge to start address phase and latch high nibble
|
||||
generate_clock_edge(&mut ram, true, false);
|
||||
|
||||
// Should have transitioned to AddressPhase and latched high nibble
|
||||
assert_eq!(ram.get_timing_state(), TimingState::AddressPhase);
|
||||
assert_eq!(ram.get_address_high_nibble(), Some(0x0));
|
||||
println!(
|
||||
"After high nibble: state={:?}, high_nibble={:?}",
|
||||
ram.get_timing_state(),
|
||||
ram.get_address_high_nibble()
|
||||
);
|
||||
|
||||
// Φ1 falling edge
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Set address low nibble (0x2) on data bus
|
||||
set_data_bus(&ram, 0x2);
|
||||
|
||||
// Generate Φ1 rising edge to latch low nibble
|
||||
generate_clock_edge(&mut ram, true, false);
|
||||
|
||||
// Should have latched low nibble
|
||||
assert_eq!(ram.get_address_low_nibble(), Some(0x2));
|
||||
println!(
|
||||
"After low nibble: high_nibble={:?}, low_nibble={:?}",
|
||||
ram.get_address_high_nibble(),
|
||||
ram.get_address_low_nibble()
|
||||
);
|
||||
|
||||
// Φ1 falling edge
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Should have assembled full address and transitioned to WaitLatency
|
||||
// Note: We can't directly access last_address, ram_state, or full_address_ready as they are private
|
||||
// We can infer state from the timing state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::WaitLatency);
|
||||
println!(
|
||||
"Address latched: high_nibble={:?}, low_nibble={:?}",
|
||||
ram.get_address_high_nibble(),
|
||||
ram.get_address_low_nibble()
|
||||
);
|
||||
|
||||
// Set CM high for write operation
|
||||
let cm_pin = ram.get_pin("CM").unwrap();
|
||||
{
|
||||
let mut cm_guard = cm_pin.lock().unwrap();
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
wait_for_pin_settlement();
|
||||
|
||||
// Set data to write (0x0F) on data bus
|
||||
set_data_bus(&ram, 0x0F);
|
||||
|
||||
// Generate Φ2 rising edge to handle data operation
|
||||
generate_clock_edge(&mut ram, false, true);
|
||||
|
||||
// Should have transitioned to WriteData state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::DriveData);
|
||||
println!("After Φ2 rising: state={:?}", ram.get_timing_state());
|
||||
|
||||
// Generate Φ2 falling edge to complete operation
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Should have returned to idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
println!("Final state: {:?}", ram.get_timing_state());
|
||||
|
||||
// Verify that data was written correctly
|
||||
assert_eq!(ram.read_ram(0x02).unwrap(), 0x0F);
|
||||
println!("Written data verified: address 0x02 = 0x0F");
|
||||
|
||||
println!("✅ RAM write operation state progression test passed!");
|
||||
}
|
||||
|
||||
/// Test output port operation state progression
|
||||
#[test]
|
||||
fn test_output_port_state_progression() {
|
||||
println!("=== Testing Output Port Operation State Progression ===");
|
||||
|
||||
let mut ram = create_test_ram();
|
||||
|
||||
// Initially should be in idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
println!("Initial state: {:?}", ram.get_timing_state());
|
||||
|
||||
// Set up for output port operation
|
||||
setup_ram_operation(&ram, true, true); // SYNC=1, CM=1 for RAM operation
|
||||
|
||||
// Set address high nibble (0x1) on data bus (for output port 0x14-0x17)
|
||||
set_data_bus(&ram, 0x1);
|
||||
|
||||
// Generate Φ1 rising edge to start address phase and latch high nibble
|
||||
generate_clock_edge(&mut ram, true, false);
|
||||
|
||||
// Should have transitioned to AddressPhase and latched high nibble
|
||||
assert_eq!(ram.get_timing_state(), TimingState::AddressPhase);
|
||||
assert_eq!(ram.get_address_high_nibble(), Some(0x1));
|
||||
println!(
|
||||
"After high nibble: state={:?}, high_nibble={:?}",
|
||||
ram.get_timing_state(),
|
||||
ram.get_address_high_nibble()
|
||||
);
|
||||
|
||||
// Φ1 falling edge
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Set address low nibble (0x4) on data bus (for output port 0 address 0x14)
|
||||
set_data_bus(&ram, 0x4);
|
||||
|
||||
// Generate Φ1 rising edge to latch low nibble
|
||||
generate_clock_edge(&mut ram, true, false);
|
||||
|
||||
// Should have latched low nibble
|
||||
assert_eq!(ram.get_address_low_nibble(), Some(0x4));
|
||||
println!(
|
||||
"After low nibble: high_nibble={:?}, low_nibble={:?}",
|
||||
ram.get_address_high_nibble(),
|
||||
ram.get_address_low_nibble()
|
||||
);
|
||||
|
||||
// Φ1 falling edge
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Should have assembled full address and transitioned to WaitLatency
|
||||
// Note: We can't directly access last_address, ram_state, or full_address_ready as they are private
|
||||
// We can infer state from the timing state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::WaitLatency);
|
||||
println!(
|
||||
"Address latched: high_nibble={:?}, low_nibble={:?}",
|
||||
ram.get_address_high_nibble(),
|
||||
ram.get_address_low_nibble()
|
||||
);
|
||||
|
||||
// Set CM high for write operation
|
||||
let cm_pin = ram.get_pin("CM").unwrap();
|
||||
{
|
||||
let mut cm_guard = cm_pin.lock().unwrap();
|
||||
cm_guard.set_driver(Some("TEST".to_string()), PinValue::High);
|
||||
}
|
||||
wait_for_pin_settlement();
|
||||
|
||||
// Set data to write (0x05) on data bus
|
||||
set_data_bus(&ram, 0x05);
|
||||
|
||||
// Generate Φ2 rising edge to handle data operation
|
||||
generate_clock_edge(&mut ram, false, true);
|
||||
|
||||
// Should have transitioned to OutputPort state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::DriveData);
|
||||
println!("After Φ2 rising: state={:?}", ram.get_timing_state());
|
||||
|
||||
// Generate Φ2 falling edge to complete operation
|
||||
generate_clock_edge(&mut ram, false, false);
|
||||
|
||||
// Should have returned to idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
println!("Final state: {:?}", ram.get_timing_state());
|
||||
|
||||
// Verify that output port was set correctly
|
||||
assert_eq!(ram.get_io_port(0).unwrap(), 0x05);
|
||||
println!("Output port 0 set to: 0x05");
|
||||
|
||||
println!("✅ Output port operation state progression test passed!");
|
||||
}
|
||||
|
||||
/// Test that unified state machine doesn't progress without proper signals
|
||||
#[test]
|
||||
fn test_no_progression_without_signals() {
|
||||
println!("=== Testing No State Progression Without Proper Signals ===");
|
||||
|
||||
let mut ram = create_test_ram();
|
||||
|
||||
// Initially should be in idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
|
||||
// Generate clock cycles without proper control signals
|
||||
for i in 0..5 {
|
||||
generate_clock_cycle(&mut ram);
|
||||
println!("Cycle {}: state={:?}", i + 1, ram.get_timing_state());
|
||||
|
||||
// Should remain in idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
}
|
||||
|
||||
println!("✅ No progression without signals test passed!");
|
||||
}
|
||||
|
||||
/// Test reset functionality
|
||||
#[test]
|
||||
fn test_reset_functionality() {
|
||||
println!("=== Testing Reset Functionality ===");
|
||||
|
||||
let mut ram = create_test_ram();
|
||||
|
||||
// Set up some state first
|
||||
setup_ram_operation(&ram, true, true);
|
||||
set_data_bus(&ram, 0x0);
|
||||
generate_clock_edge(&mut ram, true, false);
|
||||
|
||||
// Should have transitioned to AddressPhase
|
||||
assert_eq!(ram.get_timing_state(), TimingState::AddressPhase);
|
||||
println!("Before reset: state={:?}", ram.get_timing_state());
|
||||
|
||||
// Assert RESET (active low)
|
||||
let reset_pin = ram.get_pin("RESET").unwrap();
|
||||
{
|
||||
let mut reset_guard = reset_pin.lock().unwrap();
|
||||
reset_guard.set_driver(Some("TEST".to_string()), PinValue::Low);
|
||||
}
|
||||
wait_for_pin_settlement();
|
||||
|
||||
// Update with RESET low - should clear all state
|
||||
ram.update();
|
||||
|
||||
// Should have returned to idle state
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
println!("After reset: state={:?}", ram.get_timing_state());
|
||||
|
||||
// Verify address state is cleared
|
||||
assert_eq!(ram.get_address_high_nibble(), None);
|
||||
assert_eq!(ram.get_address_low_nibble(), None);
|
||||
assert_eq!(ram.get_full_address_ready(), false);
|
||||
|
||||
println!("✅ Reset functionality test passed!");
|
||||
}
|
||||
|
||||
/// Test complete unified state machine progression for all operations
|
||||
#[test]
|
||||
fn test_complete_state_machine_progression() {
|
||||
println!("=== Testing Complete Unified State Machine Progression ===");
|
||||
|
||||
let mut ram = create_test_ram();
|
||||
|
||||
// Test 1: RAM Read Operation
|
||||
println!("Test 1: RAM Read Operation");
|
||||
setup_ram_operation(&ram, true, true);
|
||||
set_data_bus(&ram, 0x0);
|
||||
generate_clock_edge(&mut ram, true, false); // Φ1 rising - latch high nibble
|
||||
generate_clock_edge(&mut ram, false, false); // Φ1 falling
|
||||
set_data_bus(&ram, 0x1);
|
||||
generate_clock_edge(&mut ram, true, false); // Φ1 rising - latch low nibble
|
||||
generate_clock_edge(&mut ram, false, false); // Φ1 falling
|
||||
clear_data_bus_drivers(&ram);
|
||||
generate_clock_edge(&mut ram, false, true); // Φ2 rising - read data
|
||||
generate_clock_edge(&mut ram, false, false); // Φ2 falling - return to idle
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
println!("✅ RAM Read Operation completed");
|
||||
|
||||
// Test 2: RAM Write Operation
|
||||
println!("Test 2: RAM Write Operation");
|
||||
setup_ram_operation(&ram, true, true);
|
||||
set_data_bus(&ram, 0x0);
|
||||
generate_clock_edge(&mut ram, true, false); // Φ1 rising - latch high nibble
|
||||
generate_clock_edge(&mut ram, false, false); // Φ1 falling
|
||||
set_data_bus(&ram, 0x2);
|
||||
generate_clock_edge(&mut ram, true, false); // Φ1 rising - latch low nibble
|
||||
generate_clock_edge(&mut ram, false, false); // Φ1 falling
|
||||
set_data_bus(&ram, 0x0F);
|
||||
generate_clock_edge(&mut ram, false, true); // Φ2 rising - write data
|
||||
generate_clock_edge(&mut ram, false, false); // Φ2 falling - return to idle
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
assert_eq!(ram.read_ram(0x02).unwrap(), 0x0F);
|
||||
println!("✅ RAM Write Operation completed");
|
||||
|
||||
// Test 3: Output Port Operation
|
||||
println!("Test 3: Output Port Operation");
|
||||
setup_ram_operation(&ram, true, true);
|
||||
set_data_bus(&ram, 0x1);
|
||||
generate_clock_edge(&mut ram, true, false); // Φ1 rising - latch high nibble
|
||||
generate_clock_edge(&mut ram, false, false); // Φ1 falling
|
||||
set_data_bus(&ram, 0x4);
|
||||
generate_clock_edge(&mut ram, true, false); // Φ1 rising - latch low nibble
|
||||
generate_clock_edge(&mut ram, false, false); // Φ1 falling
|
||||
set_data_bus(&ram, 0x05);
|
||||
generate_clock_edge(&mut ram, false, true); // Φ2 rising - write to output port
|
||||
generate_clock_edge(&mut ram, false, false); // Φ2 falling - return to idle
|
||||
assert_eq!(ram.get_timing_state(), TimingState::Idle);
|
||||
assert_eq!(ram.get_io_port(0).unwrap(), 0x05);
|
||||
println!("✅ Output Port Operation completed");
|
||||
|
||||
println!("✅ Complete unified state machine progression test passed!");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue