virtual terminal wip

This commit is contained in:
minjaesong
2025-07-24 23:02:12 +09:00
parent 923137d459
commit a4cf087bfa
6 changed files with 110 additions and 13 deletions

View File

@@ -723,11 +723,24 @@ Object.freeze(_TVDOS.DRV.FS.DEVCON)
///////////////////////////////////////////////////////////////////////////////
let mkvtcontext = (index, VMEM) => {
return { // VT0 is reserved for symlink to physical terminal
isActive: (index === 0 || index === "0"),
buffer: (index === 0 || index === "0") ? undefined : VMEM
// TODO: getCursorYX, setCursorYX, setCursorX, setCursorY, getTextForeBack, setTextFore, setTextBack
// all read/write form the VMEM
}
}
// byte-to-byte copy of the 512 KB of VRAM
function mkdevvt(index) {
// VT0 is reserved for symlink to the physical terminal
if (isNaN(index)) return false // check for non-numerics and undefined
if (index !== index || index <= 0) return false // check for NaN, 0 and negative values
// check if the device already exists
if (_TVDOS.DRV.FS['DEV'+index] != undefined) return false
if (_TVDOS.DRV.FS['DEVVT'+index] != undefined) return false
let VDEV = {}
let VMEM = new Int8Array(512 * 1024)
@@ -782,6 +795,7 @@ VDEV.mkFile = () => {}
VDEV.remove = () => {}
VDEV.exists = () => true
_TVDOS.VT_CONTEXTS[index] = mkvtcontext(index, VMEM)
_TVDOS.DRV.FS['DEVVT'+index] = VDEV
Object.freeze(_TVDOS.DRV.FS['DEVVT'+index])
@@ -846,6 +860,9 @@ _TVDOS.DRV.FS.DEVPT.mkDir = () => {}
_TVDOS.DRV.FS.DEVPT.mkFile = () => {}
_TVDOS.DRV.FS.DEVPT.remove = () => {}
_TVDOS.DRV.FS.DEVPT.exists = () => true
mkvtcontext(0)
Object.freeze(_TVDOS.DRV.FS.DEVPT)
///////////////////////////////////////////////////////////////////////////////

View File

@@ -56,11 +56,33 @@ let runner = undefined
function startNewInstance() {
runner = parallel.attachProgram("TVDOS", parallel.spawnNewContext(), bios)
serial.println("Starting new instance "+runner)
parallel.launch(runner)
sys.sleep(1000)
}
function startNewInstanceOnVT(vtIndex) {
if (isNaN(index) || index !== index) throw Error("VT index must be a numeric value")
if (index <= 0) throw Error(`VT index cannot be zero or negative (${vtIndex})`)
// Ensure VT exists
if (!_TVDOS.VT_CONTEXTS[vtIndex]) {
mkdevvt(vtIndex)
}
// Create context with VT binding
let contextInit = `_TVDOS.CURRENT_VT = ${vtIndex};${bios}`
runner = parallel.attachProgram(`TVDOS-VT${vtIndex}`, parallel.spawnNewContext(), contextInit)
serial.println(`Starting new instance ${runner} on VT${vtIndex}`)
parallel.launch(runner)
sys.sleep(50)
}
const randomkeypusher = `
while (1) {
sys.poke(-38, 65 + (Math.random()*26)|0)

View File

@@ -456,7 +456,11 @@ con.move = function(y, x) {
//print("\x1B["+(y|0)+";"+(x|0)+"H");
// NOT using ANSI escape sequence as it conflicts with some multilingual drive which redefines PRINT function
// and obviously this method is faster albeit less genuine :p
graphics.setCursorYX(y|0, x|0);
let activeVT = _TVDOS.ACTIVE_VT || 0 // 0 is physical terminal
let vt = _TVDOS.VT_CONTEXTS[activeVT]
vt.setCursorYX(y|0, x|0)
};
con.addch = function(c) {
graphics.putSymbol(c|0);
@@ -474,22 +478,25 @@ con.getmaxyx = function() {
return graphics.getTermDimension(); // [rows, cols]
};
con.getyx = function() {
return graphics.getCursorYX();
let activeVT = _TVDOS.ACTIVE_VT || 0 // 0 is physical terminal
let vt = _TVDOS.VT_CONTEXTS[activeVT]
return vt.getCursorYX()
};
con.curs_up = function() {
let [y,x] = graphics.getCursorYX();
let [y,x] = con.getyx();
con.move(y-1,x);
};
con.curs_down = function() {
let [y,x] = graphics.getCursorYX();
let [y,x] = con.getyx();
con.move(y+1,x);
};
con.curs_left = function() {
let [y,x] = graphics.getCursorYX();
let [y,x] = con.getyx();
con.move(y,x-1);
};
con.curs_right = function() {
let [y,x] = graphics.getCursorYX();
let [y,x] = con.getyx();
con.move(y,x+1);
};
con.hitterminate = function() { // ^C

View File

@@ -4,6 +4,7 @@ import net.torvald.UnsafeHelper
import net.torvald.UnsafePtr
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toHex
import net.torvald.tsvm.peripheral.*
import org.graalvm.polyglot.Context
import java.io.InputStream
import java.io.OutputStream
import java.nio.charset.Charset
@@ -67,6 +68,51 @@ class VM(
var stopDown = false
var sysrqDown = false
private var currentContext: Context? = null
fun setCurrentJSContext(context: Context) {
currentContext = context
}
private fun getCurrentJSContext(): Context {
return currentContext ?: throw IllegalStateException("No JavaScript context available")
}
// VT tracking of the VM
private var currentVTIndex = 0 // default to physical terminal
private val vtOutputStream = mutableMapOf<Int, OutputStream>()
private val vtInputStream = mutableMapOf<Int, InputStream>()
fun getCurrentVT(): Int {
// try to read from JS context
try {
val context = getCurrentJSContext()
val currentVT = context.eval("js", "_TVDOS.CURRENT_VT || 0").asInt()
return currentVT
}
catch (e: Exception) {
return currentVTIndex
}
}
fun setCurrentVT(vtIndex: Int) {
currentVTIndex = vtIndex
// Also update JavaScript context if available
try {
val context = getCurrentJSContext()
context.eval("js", "_TVDOS.CURRENT_VT = $vtIndex")
}
catch (e: Exception) {
// Context not available, continue with local tracking
}
}
var romMapping = 255
internal set

View File

@@ -143,14 +143,16 @@ class VMJSR223Delegate(private val vm: VM) {
}
fun print(s: Any) {
//System.out.print("[Nashorn] $s")
//System.out.print(s)
vm.getPrintStream().write("$s".toByteArray(VM.CHARSET))
//vm.getPrintStream().write("$s".toByteArray(VM.CHARSET))
val vtIndex = vm.getCurrentVT() // Get current VT from VM context
val outputStream = vm.getVTOutputStream(vtIndex)
outputStream.write("$s".toByteArray(VM.CHARSET))
}
fun println(s: Any = "") {
System.out.println("[Graal] $s")
//System.out.println(s)
vm.getPrintStream().write(("$s\n").toByteArray(VM.CHARSET))
//vm.getPrintStream().write(("$s\n").toByteArray(VM.CHARSET))
val vtIndex = vm.getCurrentVT() // Get current VT from VM context
val outputStream = vm.getVTOutputStream(vtIndex)
outputStream.write("$s\n".toByteArray(VM.CHARSET))
}
/**

View File

@@ -80,6 +80,9 @@ object VMRunnerFactory {
val fr = this::class.java.classLoader.getResourceAsStream("net/torvald/tsvm/JS_INIT.js")
val prg = fr.readAllBytes().decodeToString()
vm.setCurrentJSContext(context)
context.eval("js", sanitiseJS(prg))
}