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.

This commit is contained in:
2025-08-23 17:44:25 +02:00
parent f14f316e38
commit 4dcfe3a6ff
8 changed files with 63 additions and 35 deletions

View File

@@ -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 + ")")

View File

@@ -32,7 +32,7 @@ class MonTanaMiniComputer {
var clock: MTMCClock = MTMCClock(this)
var fileSystem: FileSystem = FileSystem(this)
var rewindSteps = Array<RewindStep?>(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)) {

View File

@@ -3,13 +3,16 @@ package mtmc.emulator
import mtmc.util.Runnable
class RewindStep {
var subSteps: MutableList<Runnable?> = mutableListOf()
var subSteps: Array<Runnable> = 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
}
}
}

View File

@@ -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

View File

@@ -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() }
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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
actual fun immediateTimeout(action: (Double) -> Unit): Int = 0
actual fun time(): Double = System.nanoTime() * 1000.0
actual fun setTimeout(action: () -> Unit) {}