diff --git a/TerranBASICexecutable/src/net/torvald/tsvm/TerranBASIC.java b/TerranBASICexecutable/src/net/torvald/tsvm/TerranBASIC.java index 3368baa..43867b7 100644 --- a/TerranBASICexecutable/src/net/torvald/tsvm/TerranBASIC.java +++ b/TerranBASICexecutable/src/net/torvald/tsvm/TerranBASIC.java @@ -25,7 +25,7 @@ public class TerranBASIC { appConfig.setWindowedMode(WIDTH, HEIGHT); - VM tbasvm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{TBASRelBios.INSTANCE}); + VM tbasvm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{TBASRelBios.INSTANCE}); EmulInstance tbasrunner = new EmulInstance(tbasvm, "net.torvald.tsvm.peripheral.ReferenceGraphicsAdapter", "assets/disk0", 560, 448); new Lwjgl3Application(new VMGUI(tbasrunner, WIDTH, HEIGHT), appConfig); } diff --git a/assets/disk1/!BOOTSEC b/assets/disk1/!BOOTSEC new file mode 100644 index 0000000..da786b1 --- /dev/null +++ b/assets/disk1/!BOOTSEC @@ -0,0 +1 @@ +let p=_BIOS.FIRST_BOOTABLE_PORT;com.sendMessage(p[0],"DEVRST\x17");com.sendMessage(p[0],'OPENR"WORKBENCH",'+p[1]);let r=com.getStatusCode(p[0]);if(0==r)if(com.sendMessage(p[0],"READ"),r=com.getStatusCode(p[0]),0==r){let g=com.pullMessage(p[0]);eval(g)}else println("I/O Error");else println("WORKBENCH not found");println("Shutting down...");println("It is now safe to turn off the power"); diff --git a/assets/disk1/WORKBENCH b/assets/disk1/WORKBENCH new file mode 100644 index 0000000..d491950 --- /dev/null +++ b/assets/disk1/WORKBENCH @@ -0,0 +1,33 @@ +con.move(2,1) + + + +let prog1 = "while(1){print(1);sys.sleep(600);}" +let prog2 = "while(1){print(2);sys.sleep(500);}" + +let context1 = parallel.spawnNewContext() +let context2 = parallel.spawnNewContext() + +let runner1 = parallel.attachProgram(context1, prog1) +let runner2 = parallel.attachProgram(context2, prog2) + +con.move(2,1) +parallel.launch(runner1) +parallel.launch(runner2) + + +let exit = false + +while (!exit) { + + parallel.suspend(runner1) + parallel.suspend(runner2) + let [y,x] = con.getyx() + con.move(1,2) + print(`Used mem: ${sys.getUsedMem()} ; ${Math.random()} `) + con.move(y,x) + parallel.resume(runner1) + parallel.resume(runner2) + + sys.spin() +} \ No newline at end of file diff --git a/tsvm_core/src/net/torvald/tsvm/VM.kt b/tsvm_core/src/net/torvald/tsvm/VM.kt index f86ce39..2c9368d 100644 --- a/tsvm_core/src/net/torvald/tsvm/VM.kt +++ b/tsvm_core/src/net/torvald/tsvm/VM.kt @@ -1,5 +1,6 @@ package net.torvald.tsvm +import kotlinx.coroutines.Job import net.torvald.UnsafeHelper import net.torvald.UnsafePtr import net.torvald.tsvm.peripheral.IOSpace @@ -19,6 +20,7 @@ class ErrorIllegalAccess(vm: VM, addr: Long) : RuntimeException("Segmentation fa */ class VM( + val assetsDir: String, _memsize: Long, val worldInterface: WorldInterface, val roms: Array // first ROM must contain the BIOS @@ -26,8 +28,10 @@ class VM( val id = java.util.Random().nextInt() + internal val contexts = ArrayList() + val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong()) - private val MALLOC_UNIT = 64 + val MALLOC_UNIT = 64 private val mallocBlockSize = (memsize / MALLOC_UNIT).toInt() internal val usermem = UnsafeHelper.allocate(memsize) @@ -57,7 +61,15 @@ class VM( init() } + fun killAllContexts() { + contexts.forEach { it.interrupt() } + contexts.clear() + } + fun init() { + killAllContexts() + + peripheralTable[0] = PeripheralEntry( IOSpace(this), HW_RESERVE_SIZE, @@ -83,6 +95,7 @@ class VM( } fun dispose() { + killAllContexts() usermem.destroy() peripheralTable.forEach { it.peripheral?.dispose() } } @@ -151,6 +164,7 @@ class VM( private val mallocMap = BitSet(mallocBlockSize) private val mallocSizes = HashMap() // HashMap + var allocatedBlockCount = 0; private set private fun findEmptySpace(blockSize: Int): Int? { var cursorHead = 0 @@ -180,6 +194,7 @@ class VM( val allocBlocks = ceil(size.toDouble() / MALLOC_UNIT).toInt() val blockStart = findEmptySpace(allocBlocks) ?: throw OutOfMemoryError() + allocatedBlockCount += allocBlocks mallocSizes[blockStart] = allocBlocks return blockStart * MALLOC_UNIT } @@ -190,6 +205,7 @@ class VM( mallocMap.set(index, index + count, false) mallocSizes.remove(index) + allocatedBlockCount -= count } internal data class VMNativePtr(val address: Int, val size: Int) diff --git a/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt index e0199b3..8258b13 100644 --- a/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt @@ -1,5 +1,8 @@ package net.torvald.tsvm +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUlong import java.nio.charset.Charset @@ -140,10 +143,32 @@ class VMJSR223Delegate(val vm: VM) { } fun waitForMemChg(addr: Int, andMask: Int) = waitForMemChg(addr, andMask, 0) + fun getUsedMem() = vm.allocatedBlockCount * vm.MALLOC_UNIT } class VMSerialDebugger(val vm: VM) { fun print(s: Any?) = System.out.print("$s") fun println(s: Any?) = System.out.println("$s") fun printerr(s: Any?) = System.err.println("$s") +} + +class Parallel(val vm: VM) { + fun spawnNewContext(): VMRunner { + return VMRunnerFactory(vm.assetsDir, vm, "js") + } + fun attachProgram(context: VMRunner, program: String): Thread { + Thread { context.eval(program) }.let { + vm.contexts.add(it) + return it + } + } + fun launch(thread: Thread) { + thread.start() + } + fun suspend(thread: Thread) { + thread.suspend() + } + fun resume(thread: Thread) { + thread.resume() + } } \ No newline at end of file diff --git a/tsvm_core/src/net/torvald/tsvm/VMRunnerFactory.kt b/tsvm_core/src/net/torvald/tsvm/VMRunnerFactory.kt index 5635b8d..0d26154 100644 --- a/tsvm_core/src/net/torvald/tsvm/VMRunnerFactory.kt +++ b/tsvm_core/src/net/torvald/tsvm/VMRunnerFactory.kt @@ -8,6 +8,7 @@ import javax.script.ScriptEngineManager abstract class VMRunner(val extension: String) { abstract suspend fun executeCommand(command: String) abstract suspend fun evalGlobal(command: String) + abstract fun eval(command: String) abstract fun close() } @@ -65,6 +66,7 @@ object VMRunnerFactory { bind.putMember("base64", Base64Delegate) bind.putMember("com", SerialHelperDelegate(vm)) bind.putMember("dma", DMADelegate(vm)) + bind.putMember("parallel", Parallel(vm)) val fr = FileReader("$assetsRoot/JS_INIT.js") val prg = fr.readText() @@ -83,6 +85,16 @@ object VMRunnerFactory { } } + override fun eval(command: String) { + try { + context.eval("js", encapsulateJS(sanitiseJS(command))) + } + catch (e: javax.script.ScriptException) { + System.err.println("ScriptException from the script:") + System.err.println(command.substring(0, minOf(1024, command.length))) + throw e + } } + override suspend fun evalGlobal(command: String) { context.eval("js", "\"use strict\";" + sanitiseJS(command)) } diff --git a/tsvm_executable/src/net/torvald/tsvm/AppLoader.java b/tsvm_executable/src/net/torvald/tsvm/AppLoader.java index a8153f7..d87e3e9 100644 --- a/tsvm_executable/src/net/torvald/tsvm/AppLoader.java +++ b/tsvm_executable/src/net/torvald/tsvm/AppLoader.java @@ -32,15 +32,17 @@ public class AppLoader { // VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{OEMBios.INSTANCE, BasicRom.INSTANCE}); // VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{TandemBios.INSTANCE, BasicRom.INSTANCE}); // VM vm = new VM(128 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, WPBios.INSTANCE}); - VM vm = new VM(2048 << 10, new TheRealWorld(), new VMProgramRom[]{TsvmBios.INSTANCE}); - VM pipvm = new VM(4096, new TheRealWorld(), new VMProgramRom[]{PipBios.INSTANCE, PipROM.INSTANCE}); + VM vm = new VM("./assets", 2048 << 10, new TheRealWorld(), new VMProgramRom[]{TsvmBios.INSTANCE}); + VM pipvm = new VM("./assets", 4096, new TheRealWorld(), new VMProgramRom[]{PipBios.INSTANCE, PipROM.INSTANCE}); - EmulInstance reference = new EmulInstance(vm, "net.torvald.tsvm.peripheral.ReferenceGraphicsAdapter", "assets/disk0", 560, 448); - EmulInstance reference2 = new EmulInstance(vm, "net.torvald.tsvm.peripheral.ReferenceLikeLCD", "assets/disk0", 560, 448); - EmulInstance term = new EmulInstance(vm, "net.torvald.tsvm.peripheral.Term", "assets/disk0", 720, 480); - EmulInstance portable = new EmulInstance(vm, "net.torvald.tsvm.peripheral.CharacterLCDdisplay", "assets/disk0", 628, 302); + String diskPath = "assets/disk1"; + + EmulInstance reference = new EmulInstance(vm, "net.torvald.tsvm.peripheral.ReferenceGraphicsAdapter", diskPath, 560, 448); + EmulInstance reference2 = new EmulInstance(vm, "net.torvald.tsvm.peripheral.ReferenceLikeLCD", diskPath, 560, 448); + EmulInstance term = new EmulInstance(vm, "net.torvald.tsvm.peripheral.Term", diskPath, 720, 480); + EmulInstance portable = new EmulInstance(vm, "net.torvald.tsvm.peripheral.CharacterLCDdisplay", diskPath, 628, 302); EmulInstance wp = new EmulInstance(vm, "net.torvald.tsvm.peripheral.WpTerm", "assets/wpdisk", 810, 360); - EmulInstance pip = new EmulInstance(pipvm, null, "assets/disk0", 640, 480, CollectionsKt.listOf(new Pair(1, new PeripheralEntry2( + EmulInstance pip = new EmulInstance(pipvm, null, diskPath, 640, 480, CollectionsKt.listOf(new Pair(1, new PeripheralEntry2( 32768L, 1, 0, diff --git a/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt b/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt index 13d9085..01b0d82 100644 --- a/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt +++ b/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt @@ -123,7 +123,7 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe if (usememvwr) memvwr = Memvwr(vm) - vmRunner = VMRunnerFactory("./assets", vm, "js") + vmRunner = VMRunnerFactory(vm.assetsDir, vm, "js") coroutineJob = GlobalScope.launch { vmRunner.executeCommand(vm.roms[0]!!.readAll()) }