Split monolithic index.html into: - js/constants.js - gate config, colors, dimensions - js/state.js - shared application state - js/gates.js - evaluation logic, port geometry - js/renderer.js - canvas drawing - js/waveform.js - GTKWave-style signal viewer - js/simulation.js - clock tick engine - js/events.js - mouse, keyboard, UI handlers - js/app.js - entry point - css/style.css - all styles
67 lines
2.0 KiB
JavaScript
67 lines
2.0 KiB
JavaScript
// Clock simulation engine
|
|
import { state } from './state.js';
|
|
import { evaluateAll } from './gates.js';
|
|
import { forceRecordSample } from './waveform.js';
|
|
|
|
export function simTick() {
|
|
// Toggle all CLOCK gates
|
|
state.gates.forEach(g => {
|
|
if (g.type === 'CLOCK') {
|
|
g.value = g.value ? 0 : 1;
|
|
}
|
|
});
|
|
evaluateAll();
|
|
// Force record even if evaluateAll didn't detect change
|
|
if (state.recording && state.waveformVisible) {
|
|
forceRecordSample();
|
|
}
|
|
}
|
|
|
|
export function startSim() {
|
|
if (state.simRunning) return;
|
|
const hasClocks = state.gates.some(g => g.type === 'CLOCK');
|
|
if (!hasClocks) { alert('Place a CLOCK gate first!'); return; }
|
|
|
|
state.simRunning = true;
|
|
|
|
// Auto-open waveform panel
|
|
if (!state.waveformVisible) {
|
|
state.waveformVisible = true;
|
|
document.getElementById('waveform-panel').classList.add('visible');
|
|
document.getElementById('sim-btn').classList.add('active');
|
|
// Trigger resize via event so renderer picks it up
|
|
window.dispatchEvent(new Event('resize'));
|
|
}
|
|
|
|
state.simInterval = setInterval(simTick, state.simSpeed);
|
|
updateSimUI();
|
|
}
|
|
|
|
export function stopSim() {
|
|
state.simRunning = false;
|
|
if (state.simInterval) clearInterval(state.simInterval);
|
|
state.simInterval = null;
|
|
updateSimUI();
|
|
}
|
|
|
|
export function updateSimUI() {
|
|
const btn = document.getElementById('sim-run-btn');
|
|
if (state.simRunning) {
|
|
btn.textContent = '⏹ Stop';
|
|
btn.classList.add('active');
|
|
} else {
|
|
btn.textContent = '▶ Run';
|
|
btn.classList.remove('active');
|
|
}
|
|
document.getElementById('sim-speed-label').textContent = `${state.simSpeed}ms`;
|
|
}
|
|
|
|
export function adjustSpeed(delta) {
|
|
state.simSpeed = Math.max(50, Math.min(2000, state.simSpeed + delta));
|
|
if (state.simRunning) {
|
|
clearInterval(state.simInterval);
|
|
state.simInterval = setInterval(simTick, state.simSpeed);
|
|
}
|
|
updateSimUI();
|
|
}
|