From 46001c73f8b74a234ec7e011f7d2f4ef23f5fde5 Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Fri, 3 May 2024 22:24:34 -0500 Subject: [PATCH] Reset btn, small QoL --- vweb/src/forge_simulator.jsx | 54 +++++++++++++++++++++++------------- vweb/src/simulator.css | 8 ++++-- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/vweb/src/forge_simulator.jsx b/vweb/src/forge_simulator.jsx index 0e840b8..584a5f7 100644 --- a/vweb/src/forge_simulator.jsx +++ b/vweb/src/forge_simulator.jsx @@ -8,19 +8,21 @@ export default function({ src: defaultSrc }) { let [activeTab, setActiveTab] = useState('editor') // Support for the tabbar const [assembly, setAssembly] = useState(null) // The compiled assembly code const [binary, setBinary] = useState(null) // The assembled binary - const [cpu, _setCpu] = useState(() => new WasmCPU()) // The actual CPU emulator + const [cpu, setCpu] = useState(() => new WasmCPU()) // The actual CPU emulator const [errors, setErrors] = useState(null) // What's displayed on the compile errors tab const [status, setStatus] = useState('') // The contents of the status bar // Whether the emulator should be running. Has to be a ref because the CPU setTimeout loop won't ever see changes in it otherwise const running = useRef(false) - const [currentFile, setCurrentFile] = useState(() => (Object.keys(window.localStorage).sort()[0] || 'example')) - useEffect(() => { - if (!currentFile) { - setCurrentFile('example') - window.localStorage.setItem('example', defaultSrc) + const [currentFile, setCurrentFile] = useState(() => { + const files = Object.keys(window.localStorage).sort() + if (files[0]) { // If there are any, select the first one + return files[0] + } else { // If it's empty, create an example.frg and put some default src in it + window.localStorage.setItem('example.frg', undent(defaultSrc)) + return 'example.frg' } - }, []) + }) const selectFile = useCallback((name) => { setSrc(window.localStorage.getItem(name)) @@ -32,8 +34,9 @@ export default function({ src: defaultSrc }) { let name = null while(!name || fileList.indexOf(name) >= 0) { name = prompt('Create new file named:') + if (!name.match(/\.frg$/)) { name += '.frg' } } - window.localStorage[name] = '' + window.localStorage[name] = `// ${name}` selectFile(name) }, []) @@ -68,35 +71,47 @@ export default function({ src: defaultSrc }) { setBinary(bin) // Store that setStatus(`Compiled ${bin.length} bytes`) // Success! setErrors(null) // Clear the old error messages off the tab + return { bin, errors: null } } catch (err) { if (err.message) { err = err.message } // How we get this differs between forge and asm console.error(err) // Meh setErrors(err) // Show full compiler errors setStatus("Failed to compile") // Short status line message + return { bin: null, errors: err } } }, [src]) // Callback for the run button const run = useCallback(() => { - cpu.load(binary) + let bin = binary + if (!bin) { + const result = build() + if (result.errors) { return } + else { bin = result.bin } + } + cpu.load(bin) cpu.reset() cpu.start() running.current = true setStatus('Running...') const time_slice = () => { + if (!running.current) { return } // If someone's flipped the flag, don't run the cycles. cpu.safe_run(100_000) // We want a good number of cycles here: too short is too slow; too fast is nonresponsive - if (!cpu.halted() && running.current) { // Stop if we've hit the stop btn or if it's at a hlt + if (!cpu.halted()) { // Stop if we've hit the stop btn or if it's at a hlt setTimeout(time_slice, 0) // Otherwise reschedule this for the end of the event loop - } else { - if (running.current) { // If this is true, we stopped from hlt, so update the status - // (if they hit the button then the status has already been updated) - setStatus('Terminated') - running.current = false - } + } else { // We finished! + setStatus('Terminated') + running.current = false } } setTimeout(time_slice, 0) - }, [cpu, binary, running]) + }, [cpu, binary, running, build]) + + const reset = useCallback(() => { + running.current = false + setStatus('Reset') + setCpu(new WasmCPU()) + }, []) // Callback for the stop button const stop = useCallback(() => { @@ -116,7 +131,7 @@ export default function({ src: defaultSrc }) { return ( <> - +
{content}
@@ -158,7 +173,7 @@ function Tabbar({ activeTab, setActiveTab, anyErrors }) { } // Toolbar of the controls for the simulator -function Toolbar({activeTab, running, compile, build, run, stop, addFile, removeFile }) { +function Toolbar({activeTab, running, compile, build, run, stop, reset, addFile, removeFile }) { let buildBtn, runBtn // TODO: Make this assemble on assembly tab, make that editable buildBtn = [Build] @@ -176,6 +191,7 @@ function Toolbar({activeTab, running, compile, build, run, stop, addFile, remove [del]
+ [Reset] {buildBtn} {runBtn}
diff --git a/vweb/src/simulator.css b/vweb/src/simulator.css index 6e3b96f..64ed7cb 100644 --- a/vweb/src/simulator.css +++ b/vweb/src/simulator.css @@ -68,7 +68,11 @@ a { color: #cccccc; } /* Colors of tabs and buttons */ .tabbar a.active { background-color: #686868; } .buttons .run, .file-buttons .new { color: #66bb66 } -.buttons .stop, .file-buttons .del { color: #bb6666 } +.buttons .stop, .file-buttons .del, .button[data-tab=errors] { color: #bb6666 } .buttons .build { color: #aaaaff; } +.buttons .reset { color: #bbbb66; } .files .file.selected-file { background-color: #686868 !important; } -.files .file:hover { background-color: #505050; } \ No newline at end of file +.files .file:hover, .button:hover, .file-buttons a:hover, .buttons a:hover { + background-color: #505050; + user-select: none; +} \ No newline at end of file