8.4 KiB
8.4 KiB
Observer Pattern and UI Layout Configuration Implementation Plan
Overview
This plan implements two key improvements to the rusty_emu project:
- Observer Pattern: Replace inefficient polling with event-driven state updates
- UI Layout Configuration: Enable configurable GUI layouts from JSON config files
Current Issues
Performance Issues
- Console polls system state at 100ms intervals (inefficient)
- GUI uses
try_lock()but still has potential contention - No way to configure GUI layout from JSON config
Architecture Limitations
- Tight coupling between components and UI
- No standardized way to notify UI of state changes
- Hardcoded UI layouts
Solution Architecture
Observer Pattern Implementation
graph TD
A[SystemObserver Trait] --> B[CPU Observer]
A --> C[RAM Observer]
A --> D[ROM Observer]
B --> E[ConfigurableSystem]
C --> E
D --> E
E --> F[Console UI]
E --> G[GUI Interface]
F --> H[Event-driven Updates]
G --> H
UI Layout Configuration
graph LR
A[SystemConfig JSON] --> B[UI Layout Section]
B --> C[Component Positions]
B --> D[Component Sizes]
B --> E[Display Options]
C --> F[GUI Renderer]
D --> F
E --> F
Implementation Details
1. SystemObserver Trait (Fine-grained with Filtering)
#[derive(Debug, Clone)]
pub enum ObserverFilter {
All,
CpuOnly,
MemoryOnly,
StateChangesOnly,
RegisterChangesOnly,
}
pub trait SystemObserver: Send + Sync {
fn get_filter(&self) -> ObserverFilter { return ObserverFilter::All; }
fn on_state_change(&self, component: &str, old_state: ComponentState, new_state: ComponentState);
fn on_ram_change(&self, chip: &str, bank: usize, address: u8, old_value: u8, new_value: u8);
fn on_rom_change(&self, chip: &str, address: u16, old_value: u8, new_value: u8);
fn on_cpu_register_change(&self, cpu: &str, register: &str, old_value: u8, new_value: u8);
fn on_cpu_pc_change(&self, cpu: &str, old_pc: u16, new_pc: u16);
fn on_cpu_instruction_executed(&self, cpu: &str, instruction: u8, pc: u16);
}
2. Enhanced SystemConfig
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemConfig {
pub name: String,
pub description: String,
pub version: String,
pub metadata: HashMap<String, serde_json::Value>,
pub components: HashMap<String, ComponentConfig>,
pub connections: HashMap<String, ConnectionConfig>,
pub layout: Option<LayoutConfig>,
// NEW: UI Layout configuration
pub ui_layout: Option<UiLayoutConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UiLayoutConfig {
pub console: Option<ConsoleLayoutConfig>,
pub gui: Option<GuiLayoutConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuiLayoutConfig {
pub components: HashMap<String, ComponentLayoutConfig>,
pub grid_size: Option<[usize; 2]>,
pub refresh_rate_ms: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentLayoutConfig {
pub position: [usize; 2],
pub size: [usize; 2],
pub visible: Option<bool>,
pub display_format: Option<String>,
}
3. Observer Registration in ConfigurableSystem
pub struct ConfigurableSystem {
config: SystemConfig,
components: HashMap<String, Arc<Mutex<Box<dyn Component>>>>,
is_running: Arc<Mutex<bool>>,
component_handles: Arc<Mutex<Option<ComponentHandles>>>,
// NEW: Observer registry
observers: Arc<Mutex<Vec<Box<dyn SystemObserver>>>>,
}
4. Component Integration
Each component will notify observers of state changes:
- Intel4004 CPU: Register changes, PC changes, instruction execution
- Intel4001 ROM: Memory reads, address changes
- Intel4002 RAM: Memory reads/writes, I/O changes
5. UI Updates
Console Updates (Performance Target: 50% CPU reduction, sub-10ms responsiveness)
- Replace 100ms polling with event-driven updates using observer pattern
- Observer receives notifications and updates display immediately
- Implement filtering to reduce unnecessary UI updates
- Target: Reduce CPU usage by 50% compared to current polling
- Target: Update responsiveness to under 10ms for state changes
GUI Updates
- Use layout configuration from JSON for component positioning/sizing
- Position components according to config (basic implementation)
- Show/hide components based on config visibility settings
- Use observer pattern for real-time updates
- Support configurable refresh rates from UI layout config
Configuration Examples
Enhanced JSON Config
{
"name": "IntelMcs4",
"description": "Basic MCS-4 System with CPU, Clock, 2 ROMs, and 1 RAM",
"version": "1.0",
"metadata": {
"author": "RustyEmu",
"created": "2024-01-01",
"cpu_speed": 750000,
"architecture": "mcs4",
"rom_count": 2,
"ram_count": 1
},
"components": {
"CPU_4004": {
"single": {
"component_type": "intel_4004",
"name": "CPU_4004",
"properties": {
"clock_speed": 750000
}
}
}
// ... other components
},
"connections": {
// ... existing connections
},
"layout": {
"grid_size": [10, 10],
"positions": {
"cpu": [1, 1],
"clock": [0, 0],
"rom1": [2, 0],
"rom2": [3, 0],
"ram": [2, 2]
}
},
"ui_layout": {
"console": {
"refresh_rate_ms": 50,
"show_ram": true,
"show_registers": true,
"show_system_info": true
},
"gui": {
"grid_size": [20, 20],
"components": {
"CPU_4004": {
"position": [1, 1],
"size": [20, 10],
"visible": true,
"display_format": "hex"
},
"RAM_4002": {
"position": [3, 2],
"size": [25, 15],
"visible": true,
"display_format": "hex"
},
"ROM_4001_1": {
"position": [2, 0],
"size": [20, 8],
"visible": true,
"display_format": "hex"
}
},
"refresh_rate_ms": 60
}
}
}
Benefits
Performance Improvements
- Reduced CPU usage: Event-driven vs polling
- Better responsiveness: Immediate updates vs 100ms delays
- Less contention: Observer pattern reduces lock contention
User Experience
- Configurable layouts: Users can customize UI arrangement
- Persistent settings: Layouts saved in config files
- Flexible display options: Show/hide components, change formats
Architecture Benefits
- Loose coupling: Components don't depend on UI
- Extensibility: Easy to add new observers
- Maintainability: Clear separation of concerns
Implementation Steps
- Add SystemObserver trait to
system_config.rs - Extend SystemConfig with UI layout configuration
- Add observer registration to
ConfigurableSystem - Implement observer notifications in Intel4004 CPU
- Implement observer notifications in Intel4001 ROM
- Implement observer notifications in Intel4002 RAM
- Update console.rs to use observer pattern
- Update GUI to use observer pattern and layout configuration
- Add UI layout configuration to existing JSON configs
- Test the observer pattern and UI layout system
- Update documentation with new features
Testing Strategy
Unit Tests
- Test observer registration and notification
- Test UI layout configuration parsing
- Test component state change notifications
Integration Tests
- Test console with observer pattern
- Test GUI with layout configuration
- Test end-to-end state change propagation
Performance Tests
- Measure CPU usage reduction
- Test responsiveness improvements
- Validate lock contention reduction
Backward Compatibility
- Existing configs without
ui_layoutsection will use defaults (console: 100ms, current GUI layout) - Observer pattern is additive - doesn't break existing code, components work without observers
- ConfigurableSystem will handle missing
ui_layoutgracefully with sensible defaults - Gradual migration path: existing configs continue to work, new configs get enhanced features
- No breaking changes to existing JSON configs - only additive new section
Future Enhancements
- Multiple observer types: Different observers for different concerns
- Layout templates: Predefined layouts for different use cases
- Dynamic layout editing: Runtime layout modification
- Observer filtering: Selective notification based on component types