refactor: modularize into ES6 modules
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
This commit is contained in:
66
js/simulation.js
Normal file
66
js/simulation.js
Normal file
@@ -0,0 +1,66 @@
|
||||
// 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();
|
||||
}
|
||||
Reference in New Issue
Block a user