Introduces a VirtualClock-based timing system replacing wall-clock Instant-based timing for hardware-accurate simulation. New modules: - virtual_clock.rs: Shared virtual time source with condvar sync - real_time_governor.rs: Thread that advances virtual time - component_timing.rs: Per-component timing constraints Key changes: - Component trait: added update_at_time(), timing(), set_virtual_clock_optional() - All Intel 400x components migrated to virtual-time-aware operation - ConfigurableSystem: start() returns Result, spawns governor thread - GUI: timing controls (speed slider, mode selector, step button) - Console: speed/mode/step/time commands - Backward compatible: legacy fallback for components without VirtualClock Reviewed-by: code review found 2 warnings (clock resume() dead code, reset() safety docs) — both fixed.
4 KiB
Phase 8: Speed/Step Controls for GUI and Console
Overview
Add simulation speed, mode, and step controls to both the egui-based GUI and the ratatui-based console interface. These controls leverage the existing VirtualClock and RealTimeGovernor APIs.
Files to Modify
src/gui/state.rs— AddTimingStatestruct toGuiStatefor virtual time display datasrc/gui/components.rs— AddTimingControlscomponent (speed slider, mode selector, step button, time display)src/gui/mod.rs— IntegrateTimingControlsinto the main render loopsrc/gui/console.rs— Add console commands:speed,mode,step,time
Detailed Design
1. GUI State (src/gui/state.rs)
Add a TimingState struct to GuiState:
pub struct TimingState {
/// Current virtual time in nanoseconds
pub virtual_time_ns: u64,
/// Total ticks elapsed
pub tick_count: u64,
/// Current speed multiplier (from VirtualClock)
pub target_speed: f64,
/// Actual measured speed (from RealTimeGovernor snapshots)
pub actual_speed: f64,
/// Current simulation mode: "RealTime", "MaxSpeed", "SingleStep"
pub mode: String,
/// Whether a step is pending (SingleStep mode)
pub step_pending: bool,
}
The update_from_system() method will be extended to:
- Access
ConfigurableSystem::get_virtual_clock()→Arc<VirtualClock> - Read
clock.now_ns(),clock.tick_count(),clock.speed_multiplier(),clock.mode(),clock.is_step_pending() - Compute actual speed using
RealTimeGovernor::take_speed_snapshot()/compute_speed()across frames
To support speed snapshot computation across frames, GuiState will hold two SpeedSnapshot instances:
pub speed_snap_prev: Option<SpeedSnapshot>,
pub speed_snap_curr: Option<SpeedSnapshot>,
2. TimingControls Component (src/gui/components.rs)
New component TimingControls with:
Speed Slider (Logarithmic Scale)
- Slider range: logarithmic from 0.001× to 100.0×
- Uses
egui::Sliderwith custom logarithmic mapping - Position 0.0 → 0.001×, position 1.0 → 100.0×
- Special "MaxSpeed" position at the far right
- Calls
clock.set_speed_multiplier()on change - Display: "Speed: 1.00× (actual: 0.98×)"
Mode Selector
- Three radio buttons: RealTime / MaxSpeed / SingleStep
- Calls
clock.set_mode()on selection change
Step Controls
- "Step" button, enabled only in SingleStep mode
- Calls
clock.trigger_step()on click - Shows "Step pending..." indicator when step is pending
Virtual Time Display
- Human-readable format: auto-selects µs, ms, or s
- Shows tick count
- Shows target vs actual speed
3. Integration (src/gui/mod.rs)
Add timing_controls: TimingControls to GuiComponents and call render_timing_controls() between the control panel and memory sections.
4. Console Commands (src/gui/console.rs)
New commands in execute_command():
| Command | Description |
|---|---|
speed <multiplier> |
Set speed multiplier (e.g., speed 0.5) |
speed |
Show current speed |
mode <realtime|maxspeed|step> |
Set simulation mode |
mode |
Show current mode |
step |
Trigger a single step (SingleStep mode) |
time |
Show virtual time and tick count |
Also add keyboard shortcuts:
+/-already exist for frequency; add new shortcuts for speed:- Keep existing
+/-for frequency control (unchanged)
- Keep existing
Logarithmic Slider Mapping
The slider position t (0.0 to 1.0) maps to speed multiplier via:
t=0.00 → 0.001×
t=0.25 → 0.01×
t=0.50 → 0.1×
t=0.75 → 1.0×
t=0.90 → 10.0×
t=1.00 → 100.0×
Formula: speed = 10^(t * 5 - 3) gives range [0.001, 100.0]
For MaxSpeed mode, we'll use a separate toggle rather than a slider position.
Implementation Order
- Add
TimingStatetosrc/gui/state.rs - Add
TimingControlscomponent tosrc/gui/components.rs - Integrate into
src/gui/mod.rs - Add console commands to
src/gui/console.rs - Build and test