mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-08 22:34:03 +09:00
tvdos: concurrency and VT
This commit is contained in:
@@ -30,7 +30,18 @@ function makeHash() {
|
||||
const shellID = makeHash()
|
||||
|
||||
function print_prompt_text() {
|
||||
// VT pane indicator: shown for VT 2..6, not VT 1 (the default) so the
|
||||
// unmodified prompt is what users see when they never touch virtual
|
||||
// consoles. VT_NUM is set by vtmgr's pane bootstrap.
|
||||
let vtPrefix = ""
|
||||
if (typeof VT_NUM !== "undefined" && VT_NUM > 1) vtPrefix = "[" + VT_NUM + "] "
|
||||
if (goFancy) {
|
||||
if (vtPrefix) {
|
||||
con.color_pair(161,253)
|
||||
print(`\u00DD${VT_NUM}`)
|
||||
con.color_pair(253,161)
|
||||
con.addch(16);con.curs_right()
|
||||
}
|
||||
con.color_pair(239,161)
|
||||
print(" "+CURRENT_DRIVE+":")
|
||||
con.color_pair(161,253)
|
||||
@@ -49,9 +60,9 @@ function print_prompt_text() {
|
||||
else {
|
||||
// con.color_pair(253,255)
|
||||
if (errorlevel != 0 && errorlevel != "undefined" && errorlevel != undefined)
|
||||
print(CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + " [" + errorlevel + "]" + PROMPT_TEXT)
|
||||
print(vtPrefix + CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + " [" + errorlevel + "]" + PROMPT_TEXT)
|
||||
else
|
||||
print(CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + PROMPT_TEXT)
|
||||
print(vtPrefix + CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + PROMPT_TEXT)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,6 +631,21 @@ shell.coreutils = {
|
||||
},
|
||||
panic: function(args) {
|
||||
throw Error("Panicking command.js")
|
||||
},
|
||||
chvt: function(args) {
|
||||
// Request a switch to another virtual console. Only meaningful when
|
||||
// running inside a pane spawned by vtmgr (VT_CTRL_ADDR is set by the
|
||||
// pane bootstrap). Outside that environment this is a no-op error.
|
||||
if (args[1] === undefined) { printerrln("Usage: chvt N (1..6)"); return 1 }
|
||||
let n = parseInt(args[1])
|
||||
if (isNaN(n) || n < 1 || n > 6) { printerrln("chvt: N must be in 1..6"); return 1 }
|
||||
if (typeof VT_CTRL_ADDR === "undefined") {
|
||||
printerrln("chvt: not running under vtmgr (no VT context)"); return 1
|
||||
}
|
||||
// CTRL_SWITCH_REQUEST is byte +1 of the shared CTRL area. Dispatcher
|
||||
// picks this up on its next 30 Hz tick and performs the switch.
|
||||
sys.poke(VT_CTRL_ADDR + 1, n)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
// define command aliases here
|
||||
@@ -636,10 +662,14 @@ shell.coreutils.where = shell.coreutils.which
|
||||
Object.freeze(shell.coreutils)
|
||||
shell.stdio = {
|
||||
out: {
|
||||
print: function(s) { sys.print(s) },
|
||||
println: function(s) { if (s === undefined) sys.print("\n"); else sys.print(s+"\n") },
|
||||
printerr: function(s) { sys.print("\x1B[31m"+s+"\x1B[m") },
|
||||
printerrln: function(s) { if (s === undefined) sys.print("\n"); else sys.print("\x1B[31m"+s+"\x1B[m\n") },
|
||||
// When running inside a vtmgr virtual console, __VT_OUT routes output
|
||||
// to the pane's text-plane buffer instead of the physical GPU (which
|
||||
// the compositor would otherwise overwrite). Outside a VT the hook is
|
||||
// absent and these fall through to sys.print exactly as before.
|
||||
print: function(s) { if (globalThis.__VT_OUT) globalThis.__VT_OUT.print(s); else sys.print(s) },
|
||||
println: function(s) { if (globalThis.__VT_OUT) globalThis.__VT_OUT.println(s); else { if (s === undefined) sys.print("\n"); else sys.print(s+"\n") } },
|
||||
printerr: function(s) { if (globalThis.__VT_OUT) globalThis.__VT_OUT.printerr(s); else sys.print("\x1B[31m"+s+"\x1B[m") },
|
||||
printerrln: function(s) { if (globalThis.__VT_OUT) globalThis.__VT_OUT.printerrln(s); else { if (s === undefined) sys.print("\n"); else sys.print("\x1B[31m"+s+"\x1B[m\n") } },
|
||||
},
|
||||
pipe: {
|
||||
print: function(s) { if (shell.getPipe() === undefined) throw Error("No pipe opened"); shell.appendToCurrentPipe(s); },
|
||||
|
||||
@@ -1231,7 +1231,7 @@ function drawSeparators(style) {
|
||||
for (let x = PTNVIEW_OFFSET_X; x < SCRW - 3; x += COLSIZE_TIMELINE_FULL) {
|
||||
for (let y = 0; y < PTNVIEW_HEIGHT+1; y++) {
|
||||
let memOffset = (y+PTNVIEW_OFFSET_Y-2) * SCRW + (x-1)
|
||||
let bgColOffset = GPU_MEM - TEXT_BACK_OFF - memOffset
|
||||
let bgColOffset = vaddr(TEXT_BACK_OFF + memOffset)
|
||||
let oldBgCol = sys.peek(bgColOffset)
|
||||
if (oldBgCol == 255) {
|
||||
sys.poke(bgColOffset, colColumnSep)
|
||||
@@ -1806,6 +1806,17 @@ const TEXT_BACK_OFF = 2 + 2560
|
||||
const TEXT_CHAR_OFF = 2 + 2560 + 2560
|
||||
const TEXT_PLANES = [TEXT_CHAR_OFF, TEXT_BACK_OFF, TEXT_FORE_OFF]
|
||||
|
||||
// Direct text-VRAM addressing. On real hardware the GPU text area is addressed
|
||||
// backward (byte m at GPU_MEM - m). Under vtmgr's virtual consoles the physical
|
||||
// GPU is owned by the compositor, so direct writes must instead target this
|
||||
// pane's forward text-plane buffer (VT_TEXT_PLANE + m), which the compositor
|
||||
// blits to the screen. vaddr(m) returns the address of text-area byte m for the
|
||||
// current environment; the physical branch is identical to the old arithmetic.
|
||||
const _VT_VRAM = (typeof globalThis.VT_TEXT_PLANE !== 'undefined')
|
||||
const VRAM_BASE = _VT_VRAM ? globalThis.VT_TEXT_PLANE : GPU_MEM
|
||||
const VRAM_SGN = _VT_VRAM ? 1 : -1
|
||||
function vaddr(m) { return VRAM_BASE + VRAM_SGN * m }
|
||||
|
||||
// One scratch strip, reused across shifts
|
||||
const SCRATCH_PTR = sys.malloc(SCRW * PTNVIEW_HEIGHT)
|
||||
|
||||
@@ -1828,8 +1839,8 @@ function shiftPatternArea(dy) {
|
||||
|
||||
for (let p = 0; p < 3; p++) {
|
||||
const chanOff = TEXT_PLANES[p]
|
||||
const srcAddr = GPU_MEM - chanOff - (srcTopY - 1) * SCRW
|
||||
const dstAddr = GPU_MEM - chanOff - (dstTopY - 1) * SCRW
|
||||
const srcAddr = vaddr(chanOff + (srcTopY - 1) * SCRW)
|
||||
const dstAddr = vaddr(chanOff + (dstTopY - 1) * SCRW)
|
||||
sys.memcpy(srcAddr, SCRATCH_PTR, stripBytes)
|
||||
sys.memcpy(SCRATCH_PTR, dstAddr, stripBytes)
|
||||
}
|
||||
@@ -1850,9 +1861,9 @@ function shiftPatternAreaHorizontal(dVoice) {
|
||||
for (let p = 0; p < 3; p++) {
|
||||
const chanOff = TEXT_PLANES[p]
|
||||
for (let vr = 0; vr < PTNVIEW_HEIGHT; vr++) {
|
||||
const rowBase = GPU_MEM - chanOff - (PTNVIEW_OFFSET_Y + vr - 1) * SCRW
|
||||
sys.memcpy(rowBase - srcOff, SCRATCH_PTR, SALVAGE_HORIZ_LEN)
|
||||
sys.memcpy(SCRATCH_PTR, rowBase - dstOff, SALVAGE_HORIZ_LEN)
|
||||
const idxBase = chanOff + (PTNVIEW_OFFSET_Y + vr - 1) * SCRW
|
||||
sys.memcpy(vaddr(idxBase + srcOff), SCRATCH_PTR, SALVAGE_HORIZ_LEN)
|
||||
sys.memcpy(SCRATCH_PTR, vaddr(idxBase + dstOff), SALVAGE_HORIZ_LEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2165,9 +2176,9 @@ function shiftOrdersAreaHorizontal(dVoice) {
|
||||
for (let p = 0; p < 3; p++) {
|
||||
const chanOff = TEXT_PLANES[p]
|
||||
for (let vr = 0; vr < PTNVIEW_HEIGHT; vr++) {
|
||||
const rowBase = GPU_MEM - chanOff - (PTNVIEW_OFFSET_Y + vr - 1) * SCRW
|
||||
sys.memcpy(rowBase - srcOff, SCRATCH_PTR, stripWidth)
|
||||
sys.memcpy(SCRATCH_PTR, rowBase - dstOff, stripWidth)
|
||||
const idxBase = chanOff + (PTNVIEW_OFFSET_Y + vr - 1) * SCRW
|
||||
sys.memcpy(vaddr(idxBase + srcOff), SCRATCH_PTR, stripWidth)
|
||||
sys.memcpy(SCRATCH_PTR, vaddr(idxBase + dstOff), stripWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user