From 4dcfe3a6ff07be5365132376028ea20b579e8001 Mon Sep 17 00:00:00 2001 From: rnentjes Date: Sat, 23 Aug 2025 17:44:25 +0200 Subject: [PATCH] Refactor `PlatformSpecific` functions with `time` and `setTimeout`, optimize `RewindStep` substeps handling, update `MTMCClock` timing logic, enhance frame processing, and integrate `updateJsDisplay` for dynamic updates in `Main`. --- .../kotlin/mtmc/emulator/MTMCClock.kt | 30 ++++++++++++------- .../mtmc/emulator/MonTanaMiniComputer.kt | 10 +++---- .../kotlin/mtmc/emulator/RewindStep.kt | 7 +++-- .../kotlin/mtmc/util/PlatformSpecific.kt | 4 +++ src/jsMain/kotlin/mtmc/Main.kt | 19 ++++++++++++ .../kotlin/mtmc/util/PlatformSpecific.js.kt | 20 ++++--------- src/jsMain/kotlin/mtmc/view/ControlView.kt | 2 +- .../kotlin/mtmc/util/PlatformSpecific.jvm.kt | 6 +++- 8 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/commonMain/kotlin/mtmc/emulator/MTMCClock.kt b/src/commonMain/kotlin/mtmc/emulator/MTMCClock.kt index 7cf161d..b669918 100644 --- a/src/commonMain/kotlin/mtmc/emulator/MTMCClock.kt +++ b/src/commonMain/kotlin/mtmc/emulator/MTMCClock.kt @@ -3,6 +3,8 @@ package mtmc.emulator import mtmc.emulator.MonTanaMiniComputer.ComputerStatus import mtmc.util.currentTimeMillis import mtmc.util.requestAnimationFrame +import mtmc.util.setTimeout +import mtmc.util.time import kotlin.math.max import kotlin.math.min @@ -27,21 +29,22 @@ class MTMCClock( var frame = 0 fun run() { - requestAnimationFrame { handleFrame(it) } + requestAnimationFrame { handleFrame() } } - fun handleFrame(time: Double) { + fun handleFrame() { // figure out how many instructions to execute this 'time' duration // maximize time so we don't hang if the emulator is too slow + val time = time() if (lastFrame == 0.0) { lastFrame = time - requestAnimationFrame { handleFrame(it) } + requestAnimationFrame { handleFrame() } return } val delta = time - lastFrame lastFrame = time - val actualTime = min(delta / 1000.0, 0.0166) + val timeToProcess = min(delta, 16.0) // assume 1Hz = 1 instruction/second if (computer.getStatus() == ComputerStatus.EXECUTING) { @@ -50,23 +53,28 @@ class MTMCClock( speed = 1L } - instructionsToRun += actualTime * speed - val pulse: Long = instructionsToRun.toLong() + instructionsToRun += timeToProcess * speed / 1000.0 + val pulse: Long = instructionsToRun.toLong() + 1 instructionsToRun -= pulse - val time = currentTimeMillis() + val start = time() val ir = computer.pulse(pulse) instructions += ir + val duration = (time() - start) + val actual = ir / (delta / 1000.0) if (frame % 100 == 0) { - val duration = currentTimeMillis() - time - println("Instructions ran: $ir (delta = ${delta.toFloat()}, actualTime = ${actualTime.toFloat()}, speed = $speed (actual=${(ir / delta * 1000).toLong()}), duration = $duration)") + println("Instructions ran: $ir (delta = ${delta.toFloat()}, timeToProcess = ${timeToProcess.toFloat()}, speed = $speed (actual=${actual.toLong()}), duration = $duration)") } virtual += instructions - ips = (instructions / actualTime).toLong() + ips = (instructions / timeToProcess).toLong() frame++ - requestAnimationFrame { handleFrame(it) } + if (duration > timeToProcess) { + setTimeout({ handleFrame() }) + } else { + requestAnimationFrame { handleFrame() } + } } //println("Executed " + instructions + " instructions at a rate of " + ips + " ips (speed = " + speed + ")") diff --git a/src/commonMain/kotlin/mtmc/emulator/MonTanaMiniComputer.kt b/src/commonMain/kotlin/mtmc/emulator/MonTanaMiniComputer.kt index 54a0781..9e1a086 100644 --- a/src/commonMain/kotlin/mtmc/emulator/MonTanaMiniComputer.kt +++ b/src/commonMain/kotlin/mtmc/emulator/MonTanaMiniComputer.kt @@ -32,7 +32,7 @@ class MonTanaMiniComputer { var clock: MTMCClock = MTMCClock(this) var fileSystem: FileSystem = FileSystem(this) - var rewindSteps = Array(MAX_REWIND_STEPS) { null } + var rewindSteps = Array(MAX_REWIND_STEPS) { RewindStep() } var rewindIndex = -1 // listeners @@ -133,11 +133,9 @@ class MonTanaMiniComputer { } fun fetchAndExecute() { - currentRewindStep = RewindStep() - currentRewindStep?.let { - rewindIndex = (rewindIndex + 1) % rewindSteps.size - rewindSteps.set(rewindIndex, it) - } + rewindIndex = (rewindIndex + 1) % rewindSteps.size + rewindSteps[rewindIndex].index = 0 + fetchCurrentInstruction() val instruction = getRegisterValue(Register.IR) if (isDoubleWordInstruction(instruction)) { diff --git a/src/commonMain/kotlin/mtmc/emulator/RewindStep.kt b/src/commonMain/kotlin/mtmc/emulator/RewindStep.kt index 3bf4e47..db8b983 100644 --- a/src/commonMain/kotlin/mtmc/emulator/RewindStep.kt +++ b/src/commonMain/kotlin/mtmc/emulator/RewindStep.kt @@ -3,13 +3,16 @@ package mtmc.emulator import mtmc.util.Runnable class RewindStep { - var subSteps: MutableList = mutableListOf() + var subSteps: Array = Array(10) { {} } + var index = 0 fun rewind() { subSteps.reversed().forEach({ obj: Runnable? -> obj!!.invoke() }) } fun addSubStep(subStep: Runnable?) { - subSteps.add(subStep) + if (subStep != null && index < subSteps.size) { + subSteps[index++] = subStep + } } } diff --git a/src/commonMain/kotlin/mtmc/util/PlatformSpecific.kt b/src/commonMain/kotlin/mtmc/util/PlatformSpecific.kt index 734bcef..7c64c23 100644 --- a/src/commonMain/kotlin/mtmc/util/PlatformSpecific.kt +++ b/src/commonMain/kotlin/mtmc/util/PlatformSpecific.kt @@ -2,6 +2,10 @@ package mtmc.util expect fun currentTimeMillis(): Double +expect fun time(): Double + expect fun requestAnimationFrame(action: (Double) -> Unit) +expect fun setTimeout(action: () -> Unit) + expect fun immediateTimeout(action: (Double) -> Unit): Int diff --git a/src/jsMain/kotlin/mtmc/Main.kt b/src/jsMain/kotlin/mtmc/Main.kt index 1722535..4aafeb4 100644 --- a/src/jsMain/kotlin/mtmc/Main.kt +++ b/src/jsMain/kotlin/mtmc/Main.kt @@ -1,7 +1,9 @@ package mtmc import kotlinx.browser.document +import kotlinx.browser.window import mtmc.emulator.MonTanaMiniComputer +import mtmc.util.currentTimeMillis import mtmc.view.DisplayView import mtmc.view.MTMCView import nl.astraeus.komp.Komponent @@ -21,4 +23,21 @@ fun main() { mainView.requestUpdate() display.requestUpdate() + + window.requestAnimationFrame { updateJsDisplay() } +} + +var lastMemoryUpdate = currentTimeMillis() +var updateState = true + +fun updateJsDisplay() { + display.requestUpdate() + if (currentTimeMillis() - lastMemoryUpdate > 125) { + if (updateState) { + mainView.registerView.requestUpdate() + mainView.memoryView.requestUpdate() + } + lastMemoryUpdate = currentTimeMillis() + } + window.requestAnimationFrame { updateJsDisplay() } } diff --git a/src/jsMain/kotlin/mtmc/util/PlatformSpecific.js.kt b/src/jsMain/kotlin/mtmc/util/PlatformSpecific.js.kt index 2a74fad..4504626 100644 --- a/src/jsMain/kotlin/mtmc/util/PlatformSpecific.js.kt +++ b/src/jsMain/kotlin/mtmc/util/PlatformSpecific.js.kt @@ -1,27 +1,19 @@ package mtmc.util import kotlinx.browser.window -import mtmc.display -import mtmc.mainView import kotlin.js.Date -var lastMemoryUpdate = currentTimeMillis() -var updateState = true - actual fun currentTimeMillis(): Double = Date().getTime() actual fun requestAnimationFrame(action: (Double) -> Unit) { window.requestAnimationFrame { action(it) - - display.requestUpdate() - if (currentTimeMillis() - lastMemoryUpdate > 125) { - if (updateState) { - mainView.registerView.requestUpdate() - mainView.memoryView.requestUpdate() - } - lastMemoryUpdate = currentTimeMillis() - } } } actual fun immediateTimeout(action: (Double) -> Unit): Int = window.setTimeout(action, 0) + +actual fun time(): Double = window.performance.now() + +actual fun setTimeout(action: () -> Unit) { + window.setTimeout(action) +} \ No newline at end of file diff --git a/src/jsMain/kotlin/mtmc/view/ControlView.kt b/src/jsMain/kotlin/mtmc/view/ControlView.kt index c7fc16b..b1e8091 100644 --- a/src/jsMain/kotlin/mtmc/view/ControlView.kt +++ b/src/jsMain/kotlin/mtmc/view/ControlView.kt @@ -14,7 +14,7 @@ import kotlinx.html.span import mtmc.display import mtmc.emulator.MonTanaMiniComputer import mtmc.mainView -import mtmc.util.updateState +import mtmc.updateState import nl.astraeus.komp.HtmlBuilder import nl.astraeus.komp.Komponent import org.w3c.dom.HTMLSelectElement diff --git a/src/jvmMain/kotlin/mtmc/util/PlatformSpecific.jvm.kt b/src/jvmMain/kotlin/mtmc/util/PlatformSpecific.jvm.kt index 119a65b..d614ccd 100644 --- a/src/jvmMain/kotlin/mtmc/util/PlatformSpecific.jvm.kt +++ b/src/jvmMain/kotlin/mtmc/util/PlatformSpecific.jvm.kt @@ -5,4 +5,8 @@ actual fun requestAnimationFrame(action: (Double) -> Unit) { error("requestAnimationFrame is not supported on JVM") } -actual fun immediateTimeout(action: (Double) -> Unit): Int = 0 \ No newline at end of file +actual fun immediateTimeout(action: (Double) -> Unit): Int = 0 + +actual fun time(): Double = System.nanoTime() * 1000.0 + +actual fun setTimeout(action: () -> Unit) {} \ No newline at end of file