rusty_emu/plans/phase8_gui_controls.md
Jan-Peter von Hunnius 08f53d68fe feat: implement virtual clock timing architecture (Phases 5-8)
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.
2026-05-14 21:00:22 +02:00

4 KiB
Raw Blame History

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

  1. src/gui/state.rs — Add TimingState struct to GuiState for virtual time display data
  2. src/gui/components.rs — Add TimingControls component (speed slider, mode selector, step button, time display)
  3. src/gui/mod.rs — Integrate TimingControls into the main render loop
  4. src/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::Slider with 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)

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

  1. Add TimingState to src/gui/state.rs
  2. Add TimingControls component to src/gui/components.rs
  3. Integrate into src/gui/mod.rs
  4. Add console commands to src/gui/console.rs
  5. Build and test