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
|
|
@ -1,7 +1,6 @@
|
|||
# Intel 400x Common Functionality
|
||||
|
||||
This module provides shared functionality for all Intel 400x series chips (4001, 4002, 4003, 4004). It contains common
|
||||
traits, utilities, and behaviors that are used across multiple components.
|
||||
This module provides shared functionality for all Intel 400x series chips (4001, 4002, 4003, 4004) through a unified state machine architecture. It contains common traits, utilities, and behaviors that are used across multiple components.
|
||||
|
||||
## Purpose
|
||||
|
||||
|
|
@ -12,13 +11,114 @@ The Intel 400x series shares many common characteristics:
|
|||
- **12-bit address space** (8-bit addresses in two 4-bit cycles)
|
||||
- **Common timing constraints** and access patterns
|
||||
- **Similar pin configurations** and control signals
|
||||
- **Shared state machine patterns** for memory operations
|
||||
- **Unified state machine patterns** for all operations
|
||||
|
||||
Rather than duplicating this code in each component, it's centralized here for maintainability and consistency.
|
||||
|
||||
## Architecture
|
||||
## Unified State Machine Architecture
|
||||
|
||||
### Trait-Based Design
|
||||
### Overview
|
||||
|
||||
The Intel 400x series now uses a unified state machine approach that replaces individual chip state machines with a single, extensible framework. This approach provides several benefits:
|
||||
|
||||
1. **Consistency**: All components follow the same basic state transition patterns
|
||||
2. **Maintainability**: Common logic is centralized in the state machine engine
|
||||
3. **Extensibility**: New chip types can be added by implementing the `Intel400xComponentBehavior` trait
|
||||
4. **Testability**: Components can be tested independently with mock behaviors
|
||||
|
||||
### Key Components
|
||||
|
||||
#### Intel400xComponentBehavior Trait
|
||||
|
||||
This trait defines the interface that all Intel 400x components must implement to work with the unified state machine architecture. It allows each component to provide its own specific behavior while still following the common state machine framework.
|
||||
|
||||
```rust
|
||||
pub trait Intel400xComponentBehavior {
|
||||
fn get_component_type(&self) -> Intel400xComponentType;
|
||||
fn on_state_entry(&mut self, state: Intel400xUnifiedState);
|
||||
fn on_state_exit(&mut self, state: Intel400xUnifiedState);
|
||||
fn handle_component_event(&mut self, event: Intel400xEvent) -> bool;
|
||||
fn execute_state_logic(&mut self, state: Intel400xUnifiedState);
|
||||
fn responds_to_address(&self) -> bool;
|
||||
}
|
||||
```
|
||||
|
||||
#### Intel400xComponentType
|
||||
|
||||
Enumeration that identifies the specific type of Intel 400x component being modeled:
|
||||
|
||||
```rust
|
||||
pub enum Intel400xComponentType {
|
||||
Intel4001, // ROM (Read-Only Memory)
|
||||
Intel4002, // RAM (Random Access Memory)
|
||||
Intel4003, // Shift Register
|
||||
Intel4004, // CPU (Central Processing Unit)
|
||||
}
|
||||
```
|
||||
|
||||
#### Intel400xUnifiedState
|
||||
|
||||
Enumeration representing all possible states for any Intel 400x component in the unified state machine:
|
||||
|
||||
```rust
|
||||
pub enum Intel400xUnifiedState {
|
||||
// Common states (shared across all components)
|
||||
Idle,
|
||||
AddressPhase,
|
||||
WaitLatency,
|
||||
DriveData,
|
||||
|
||||
// Component-specific states
|
||||
ReadData, // Intel 4002 (RAM) specific
|
||||
WriteData, // Intel 4002 (RAM) specific
|
||||
OutputPort, // Intel 4002 (RAM) specific
|
||||
ShiftData, // Intel 4003 (Shift Register) specific
|
||||
LoadData, // Intel 4003 (Shift Register) specific
|
||||
FetchInstruction, // Intel 4004 (CPU) specific
|
||||
ExecuteInstruction, // Intel 4004 (CPU) specific
|
||||
}
|
||||
```
|
||||
|
||||
#### Intel400xEvent
|
||||
|
||||
Enumeration representing events that can trigger state transitions:
|
||||
|
||||
```rust
|
||||
pub enum Intel400xEvent {
|
||||
ClockPhi1Rising,
|
||||
ClockPhi1Falling,
|
||||
ClockPhi2Rising,
|
||||
ClockPhi2Falling,
|
||||
SyncActive,
|
||||
SyncInactive,
|
||||
ChipSelect,
|
||||
ChipDeselect,
|
||||
ResetActive,
|
||||
ResetInactive,
|
||||
AddressComplete,
|
||||
LatencyElapsed,
|
||||
DataReady,
|
||||
OperationComplete,
|
||||
}
|
||||
```
|
||||
|
||||
#### Intel400xStateMachine
|
||||
|
||||
The core state machine engine that manages state transitions and coordinates with component behaviors:
|
||||
|
||||
```rust
|
||||
pub struct Intel400xStateMachine {
|
||||
component_type: Intel400xComponentType,
|
||||
current_state: Intel400xUnifiedState,
|
||||
previous_state: Intel400xUnifiedState,
|
||||
address_high_nibble: Option<u8>,
|
||||
address_low_nibble: Option<u8>,
|
||||
address_latch_time: Option<Instant>,
|
||||
access_time: Duration,
|
||||
}
|
||||
```
|
||||
|
||||
## Trait-Based Design
|
||||
|
||||
The common functionality is organized around several key traits:
|
||||
|
||||
|
|
@ -28,19 +128,9 @@ Intel400xDataBus - Data bus read/write operations
|
|||
Intel400xAddressHandling - Address latching and assembly
|
||||
Intel400xControlPins - Control signal reading
|
||||
Intel400xResetHandling - Reset signal handling
|
||||
Intel400xTimingState - Memory operation state machines
|
||||
Intel400xTimingState - Memory operation state management
|
||||
```
|
||||
|
||||
### State Machine
|
||||
|
||||
All Intel 400x memory operations follow a common pattern:
|
||||
|
||||
```
|
||||
Idle → AddressPhase → WaitLatency → DriveData → Idle
|
||||
```
|
||||
|
||||
Each phase has specific timing requirements and bus usage patterns.
|
||||
|
||||
## Core Traits
|
||||
|
||||
### Intel400xClockHandling
|
||||
|
|
@ -139,8 +229,8 @@ pub trait Intel400xResetHandling {
|
|||
fn get_base(&self) -> &BaseComponent;
|
||||
|
||||
// Reset operations
|
||||
fn handle_reset(&self, reset_pin_name: &str) -> bool;
|
||||
fn perform_reset(&self); // Component-specific reset logic
|
||||
fn handle_reset(&mut self, reset_pin_name: &str) -> bool;
|
||||
fn perform_reset(&mut self); // Component-specific reset logic
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -156,8 +246,8 @@ Manages memory operation timing and state machines:
|
|||
```rust
|
||||
pub trait Intel400xTimingState {
|
||||
// State management
|
||||
fn get_timing_state(&self) -> TimingState;
|
||||
fn set_timing_state(&mut self, state: TimingState);
|
||||
fn get_timing_state(&self) -> MemoryState;
|
||||
fn set_timing_state(&mut self, state: MemoryState);
|
||||
|
||||
// Address tracking
|
||||
fn get_address_latch_time(&self) -> Option<Instant>;
|
||||
|
|
@ -179,6 +269,31 @@ pub trait Intel400xTimingState {
|
|||
- Timing constraint management
|
||||
- Address tracking and validation
|
||||
|
||||
## State Machine Operation
|
||||
|
||||
### State Transition Logic
|
||||
|
||||
The unified state machine operates by:
|
||||
|
||||
1. Receiving events from the component or external sources
|
||||
2. Determining the next state based on current state and event
|
||||
3. Calling appropriate state entry/exit methods on the component behavior
|
||||
4. Executing state-specific logic through the component behavior
|
||||
|
||||
### Common State Transitions
|
||||
|
||||
1. **Idle → AddressPhase**: Triggered by chip select when component responds to address
|
||||
2. **AddressPhase → WaitLatency**: After both address nibbles are latched
|
||||
3. **WaitLatency → Component-Specific State**: After access time has elapsed
|
||||
4. **Component-Specific State → Idle**: When operation completes
|
||||
|
||||
### Component-Specific Behaviors
|
||||
|
||||
- **Intel 4001 (ROM)**: Transitions to DriveData to provide read-only data
|
||||
- **Intel 4002 (RAM)**: Transitions to ReadData, WriteData, or OutputPort based on operation
|
||||
- **Intel 4003 (Shift Register)**: Ignores address transmission, goes directly to ShiftData
|
||||
- **Intel 4004 (CPU)**: Uses FetchInstruction and ExecuteInstruction states
|
||||
|
||||
## Timing Constants
|
||||
|
||||
### Standard Timing Values
|
||||
|
|
@ -201,13 +316,11 @@ Each component type uses appropriate timing constants:
|
|||
- **Shift Register (4003)**: 200ns fast access time
|
||||
- **CPU (4004)**: Internal operation timing
|
||||
|
||||
## State Machine
|
||||
|
||||
### Memory Operation States
|
||||
## Memory Operation States
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum TimingState {
|
||||
pub enum MemoryState {
|
||||
Idle, // No memory operation in progress
|
||||
AddressPhase, // Currently latching address nibbles
|
||||
WaitLatency, // Address latched, waiting for access time
|
||||
|
|
@ -215,22 +328,6 @@ pub enum TimingState {
|
|||
}
|
||||
```
|
||||
|
||||
### State Transition Logic
|
||||
|
||||
1. **Idle → AddressPhase**: Triggered by SYNC high + Φ1 rising edge
|
||||
2. **AddressPhase → WaitLatency**: After both address nibbles latched
|
||||
3. **WaitLatency → DriveData**: After access time has elapsed
|
||||
4. **DriveData → Idle**: On Φ2 falling edge (bus tri-stated)
|
||||
|
||||
### Hardware Timing
|
||||
|
||||
Each state has specific timing requirements:
|
||||
|
||||
- **Address Setup**: 100ns minimum before latching
|
||||
- **Data Valid**: 200ns maximum from address valid to data available
|
||||
- **Bus Hold**: Data held until Φ2 falling edge
|
||||
- **Tri-state Delay**: 150ns maximum to high impedance after disable
|
||||
|
||||
## Utility Functions
|
||||
|
||||
### Pin Operations
|
||||
|
|
@ -256,11 +353,60 @@ All pin operations include proper error handling:
|
|||
- **Pin not found**: Return appropriate error messages
|
||||
- **Invalid states**: Graceful degradation
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Implementing the Intel400xComponentBehavior Trait
|
||||
|
||||
```rust
|
||||
struct MyComponent {
|
||||
// Component fields...
|
||||
state_machine: Intel400xStateMachine,
|
||||
}
|
||||
|
||||
impl Intel400xComponentBehavior for MyComponent {
|
||||
fn get_component_type(&self) -> Intel400xComponentType {
|
||||
Intel400xComponentType::Intel4001 // Example type
|
||||
}
|
||||
|
||||
fn on_state_entry(&mut self, state: Intel400xUnifiedState) {
|
||||
match state {
|
||||
Intel400xUnifiedState::AddressPhase => {
|
||||
// Prepare for address latching
|
||||
}
|
||||
Intel400xUnifiedState::DriveData => {
|
||||
// Prepare for data transfer
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// ... implement other methods
|
||||
}
|
||||
```
|
||||
|
||||
### Using the Unified State Machine
|
||||
|
||||
```rust
|
||||
// Create a state machine for an Intel 4001 ROM chip
|
||||
let mut state_machine = Intel400xStateMachine::new(
|
||||
Intel400xComponentType::Intel4001,
|
||||
Duration::from_nanos(500)
|
||||
);
|
||||
|
||||
// Process a chip select event
|
||||
let new_state = process_event_direct(
|
||||
&mut state_machine,
|
||||
Intel400xEvent::ChipSelect
|
||||
);
|
||||
|
||||
assert_eq!(new_state, Intel400xUnifiedState::AddressPhase);
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Comprehensive Test Suite
|
||||
|
||||
The common functionality is thoroughly tested with:
|
||||
The unified state machine is thoroughly tested with:
|
||||
|
||||
1. **Unit Tests**: Test individual functions and algorithms
|
||||
2. **Mock Tests**: Test with controlled hardware inputs
|
||||
|
|
@ -269,76 +415,26 @@ The common functionality is thoroughly tested with:
|
|||
|
||||
### Testable Areas
|
||||
|
||||
- **Timing constants validation**
|
||||
- **Address assembly algorithms**
|
||||
- **State machine transitions**
|
||||
- **Address latching algorithms**
|
||||
- **Component-specific behaviors**
|
||||
- **Clock edge detection accuracy**
|
||||
- **Data bus bit operations**
|
||||
- **Pin operation safety**
|
||||
|
||||
### Mock System
|
||||
## Benefits of the Unified Approach
|
||||
|
||||
A comprehensive mock system allows testing without real hardware:
|
||||
|
||||
```rust
|
||||
// Create mock component for testing
|
||||
let mut mock_component = MockIntel400xComponent::new("TestComponent");
|
||||
|
||||
// Set up test scenario
|
||||
mock_component.set_clock_values(PinValue::High, PinValue::Low);
|
||||
|
||||
// Test behavior
|
||||
assert!(mock_component.is_phi1_rising_edge(PinValue::Low));
|
||||
```
|
||||
|
||||
## Usage in Components
|
||||
|
||||
### Implementation Pattern
|
||||
|
||||
Components implement the relevant traits:
|
||||
|
||||
```rust
|
||||
impl Intel400xClockHandling for MyComponent {
|
||||
fn get_base(&self) -> &BaseComponent {
|
||||
&self.base
|
||||
}
|
||||
}
|
||||
|
||||
impl Intel400xDataBus for MyComponent {
|
||||
fn get_base(&self) -> &BaseComponent {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn read_data_bus(&self) -> u8 {
|
||||
// Use common data bus reading logic
|
||||
let mut data = 0;
|
||||
for i in 0..4 {
|
||||
if let Ok(pin) = self.get_base().get_pin(&format!("D{}", i)) {
|
||||
if let Ok(pin_guard) = pin.lock() {
|
||||
if pin_guard.read() == PinValue::High {
|
||||
data |= 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data & 0x0F
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Benefits
|
||||
|
||||
1. **Code Reuse**: Common functionality shared across components
|
||||
2. **Consistency**: Uniform behavior across all 400x components
|
||||
3. **Maintainability**: Changes to common logic update all components
|
||||
4. **Testability**: Common code can be tested once and reused
|
||||
5. **Type Safety**: Traits ensure proper implementation
|
||||
1. **Code Reuse**: Common state transition logic is shared across all components
|
||||
2. **Consistency**: All components follow the same timing and state patterns
|
||||
3. **Maintainability**: Changes to common behavior only need to be made in one place
|
||||
4. **Extensibility**: New chip types can be added without modifying the core state machine
|
||||
5. **Testability**: The state machine can be tested independently of specific components
|
||||
|
||||
## Hardware Accuracy
|
||||
|
||||
### Timing Considerations
|
||||
|
||||
The common code implements hardware-accurate timing where possible:
|
||||
The unified state machine implements hardware-accurate timing where possible:
|
||||
|
||||
- **Clock Edge Detection**: Proper Φ1/Φ2 edge detection
|
||||
- **Address Latching**: Two-phase address capture
|
||||
|
|
@ -356,19 +452,19 @@ The common code implements hardware-accurate timing where possible:
|
|||
### Planned Improvements
|
||||
|
||||
1. **Enhanced Timing Simulation**
|
||||
- More accurate sub-nanosecond timing
|
||||
- Better clock phase relationship modeling
|
||||
- Improved signal propagation delays
|
||||
- More accurate sub-nanosecond timing
|
||||
- Better clock phase relationship modeling
|
||||
- Improved signal propagation delays
|
||||
|
||||
2. **Extended Component Support**
|
||||
- Support for additional Intel 400x variants
|
||||
- Enhanced I/O device support
|
||||
- Better peripheral modeling
|
||||
- Support for additional Intel 400x variants
|
||||
- Enhanced I/O device support
|
||||
- Better peripheral modeling
|
||||
|
||||
3. **Testing Improvements**
|
||||
- More sophisticated mock scenarios
|
||||
- Better timing verification tools
|
||||
- Enhanced debugging capabilities
|
||||
- More sophisticated mock scenarios
|
||||
- Better timing verification tools
|
||||
- Enhanced debugging capabilities
|
||||
|
||||
### Extension Points
|
||||
|
||||
|
|
@ -403,5 +499,4 @@ The common functionality depends on:
|
|||
- **Shared Code**: No duplication across components
|
||||
- **Efficient State Storage**: Compact state representation
|
||||
|
||||
This common functionality module provides a solid foundation for all Intel 400x components while maintaining high
|
||||
performance and hardware accuracy.
|
||||
This unified state machine architecture provides a solid foundation for all Intel 400x components while maintaining high performance and hardware accuracy.
|
||||
Loading…
Add table
Add a link
Reference in a new issue