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.
117 lines
4 KiB
Markdown
117 lines
4 KiB
Markdown
# 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`:
|
||
|
||
```rust
|
||
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:
|
||
```rust
|
||
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
|