Files
logic-gates/js/simulation.js

67 lines
1.9 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) 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();
}