mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-12 15:44:05 +09:00
tty state machine wip
This commit is contained in:
@@ -33,17 +33,43 @@ class GraphicsJSR223Delegate(val vm: VM) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun GraphicsAdapter._loadbulk(fromAddr: Int, toAddr: Int, length: Int) {
|
fun storeBulk(fromAddr: Int, toAddr: Int, length: Int) {
|
||||||
if (toAddr < 250880) {
|
getFirstGPU()?.let {
|
||||||
UnsafeHelper.memcpy(
|
it._storebulk(fromAddr, toAddr, length)
|
||||||
vm.usermem.ptr + fromAddr,
|
|
||||||
(this.framebuffer.pixels as DirectBuffer).address() + toAddr,
|
|
||||||
length.toLong()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else if (toAddr < 250972) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun GraphicsAdapter._loadbulk(fromAddr: Int, toAddr: Int, length: Int) {
|
||||||
|
UnsafeHelper.memcpy(
|
||||||
|
vm.usermem.ptr + fromAddr,
|
||||||
|
(this.framebuffer.pixels as DirectBuffer).address() + toAddr,
|
||||||
|
length.toLong()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GraphicsAdapter._storebulk(fromAddr: Int, toAddr: Int, length: Int) {
|
||||||
|
UnsafeHelper.memcpy(
|
||||||
|
(this.framebuffer.pixels as DirectBuffer).address() + fromAddr,
|
||||||
|
vm.usermem.ptr + toAddr,
|
||||||
|
length.toLong()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GraphicsAdapter._loadSprite(spriteNum: Int, ptr: Int) {
|
||||||
|
UnsafeHelper.memcpy(
|
||||||
|
vm.usermem.ptr + ptr,
|
||||||
|
(this.spriteAndTextArea).ptr + (260 * spriteNum) + 4,
|
||||||
|
256
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GraphicsAdapter._storeSprite(spriteNum: Int, ptr: Int) {
|
||||||
|
UnsafeHelper.memcpy(
|
||||||
|
(this.spriteAndTextArea).ptr + (260 * spriteNum) + 4,
|
||||||
|
vm.usermem.ptr + ptr,
|
||||||
|
256
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package net.torvald.tsvm.peripheral
|
package net.torvald.tsvm.peripheral
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.Queue
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements standard TTY that can interpret some of the ANSI escape sequences
|
* Implements standard TTY that can interpret some of the ANSI escape sequences
|
||||||
@@ -19,8 +19,8 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
|||||||
|
|
||||||
abstract fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte = ttyFore.toByte(), backColour: Byte = ttyBack.toByte())
|
abstract fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte = ttyFore.toByte(), backColour: Byte = ttyBack.toByte())
|
||||||
|
|
||||||
private var ttyMode = Queue<Byte>() // stores escape sequences like: <ESC> [
|
private var ttyEscState = TTY_ESC_STATE.INITIAL
|
||||||
|
private val ttyEscArguments = Stack<Int>()
|
||||||
/**
|
/**
|
||||||
* ONLY accepts a character to either process the escape sequence, or say the input character is allowed to print.
|
* ONLY accepts a character to either process the escape sequence, or say the input character is allowed to print.
|
||||||
* This function will alter the internal state of the TTY intepreter (aka this very class)
|
* This function will alter the internal state of the TTY intepreter (aka this very class)
|
||||||
@@ -31,40 +31,164 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
|||||||
* @return true if character should be printed as-is
|
* @return true if character should be printed as-is
|
||||||
*/
|
*/
|
||||||
private fun acceptChar(char: Byte): Boolean {
|
private fun acceptChar(char: Byte): Boolean {
|
||||||
TODO()
|
fun reject(): Boolean {
|
||||||
|
ttyEscState = TTY_ESC_STATE.INITIAL
|
||||||
if (ESC == char) {
|
ttyEscArguments.clear()
|
||||||
// beginning of the escape sequence
|
return true
|
||||||
if (ttyMode.isEmpty) {
|
|
||||||
ttyMode.addLast(char)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Any escape sequences
|
fun accept(execute: () -> Unit): Boolean {
|
||||||
else if (ttyMode.size >= 1) {
|
ttyEscState = TTY_ESC_STATE.INITIAL
|
||||||
// make a state machine; if the machine should move into accepting state: accept a char, and return false;
|
execute.invoke()
|
||||||
// for a rejecting state (sequence not in the transition table): clear the ttyMode, and return false;
|
ttyEscArguments.clear()
|
||||||
// for a terminating state (escape sequence is terminated successfully): run interpretCSI(), and return false.
|
|
||||||
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
fun registerNewNumberArg(newnum: Byte, newState: TTY_ESC_STATE) {
|
||||||
|
ttyEscArguments.push(char.toInt() - 0x30)
|
||||||
|
ttyEscState = newState
|
||||||
|
}
|
||||||
|
fun appendToExistingNumber(newnum: Byte) {
|
||||||
|
ttyEscArguments.push(ttyEscArguments.pop() * 10 + (newnum.toInt() - 0x30))
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO()
|
||||||
|
|
||||||
|
when (ttyEscState) {
|
||||||
|
TTY_ESC_STATE.INITIAL -> {
|
||||||
|
if (char == ESC) {
|
||||||
|
ttyEscState = TTY_ESC_STATE.ESC
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TTY_ESC_STATE.ESC -> {
|
||||||
|
when (char.toChar()) {
|
||||||
|
'c' -> return accept { resetTtyStatus() }
|
||||||
|
'[' -> ttyEscState = TTY_ESC_STATE.CSI
|
||||||
|
else -> return reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TTY_ESC_STATE.CSI -> {
|
||||||
|
when (char.toChar()) {
|
||||||
|
'A' -> return accept { cursorUp() }
|
||||||
|
'B' -> return accept { cursorDown() }
|
||||||
|
'C' -> return accept { cursorFwd() }
|
||||||
|
'D' -> return accept { cursorBack() }
|
||||||
|
'E' -> return accept { cursorNextLine() }
|
||||||
|
'F' -> return accept { cursorPrevLine() }
|
||||||
|
'G' -> return accept { cursorX() }
|
||||||
|
'J' -> return accept { eraseInDisp() }
|
||||||
|
'K' -> return accept { eraseInLine() }
|
||||||
|
'S' -> return accept { scrollUp() }
|
||||||
|
'T' -> return accept { scrollDown() }
|
||||||
|
'm' -> return accept { sgrOneArg() }
|
||||||
|
';' -> {
|
||||||
|
ttyEscArguments.push(0)
|
||||||
|
ttyEscState = TTY_ESC_STATE.SEP1
|
||||||
|
}
|
||||||
|
in '0'..'9' -> registerNewNumberArg(char, TTY_ESC_STATE.NUM1)
|
||||||
|
else -> return reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TTY_ESC_STATE.NUM1 -> {
|
||||||
|
when (char.toChar()) {
|
||||||
|
'A' -> return accept { cursorUp(ttyEscArguments.pop()) }
|
||||||
|
'B' -> return accept { cursorDown(ttyEscArguments.pop()) }
|
||||||
|
'C' -> return accept { cursorFwd(ttyEscArguments.pop()) }
|
||||||
|
'D' -> return accept { cursorBack(ttyEscArguments.pop()) }
|
||||||
|
'E' -> return accept { cursorNextLine(ttyEscArguments.pop()) }
|
||||||
|
'F' -> return accept { cursorPrevLine(ttyEscArguments.pop()) }
|
||||||
|
'G' -> return accept { cursorX(ttyEscArguments.pop()) }
|
||||||
|
'J' -> return accept { eraseInDisp(ttyEscArguments.pop()) }
|
||||||
|
'K' -> return accept { eraseInLine(ttyEscArguments.pop()) }
|
||||||
|
'S' -> return accept { scrollUp(ttyEscArguments.pop()) }
|
||||||
|
'T' -> return accept { scrollDown(ttyEscArguments.pop()) }
|
||||||
|
'm' -> return accept { sgrOneArg(ttyEscArguments.pop()) }
|
||||||
|
';' -> ttyEscState = TTY_ESC_STATE.SEP1
|
||||||
|
in '0'..'9' -> appendToExistingNumber(char)
|
||||||
|
else -> return reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TTY_ESC_STATE.NUM2 -> {
|
||||||
|
when (char.toChar()) {
|
||||||
|
in '0'..'9' -> appendToExistingNumber(char)
|
||||||
|
'H' -> return accept {
|
||||||
|
val arg2 = ttyEscArguments.pop()
|
||||||
|
val arg1 = ttyEscArguments.pop()
|
||||||
|
cursorXY(arg1, arg2)
|
||||||
|
}
|
||||||
|
';' -> ttyEscState = TTY_ESC_STATE.SEP2
|
||||||
|
else -> return reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TTY_ESC_STATE.NUM3 -> {
|
||||||
|
when (char.toChar()) {
|
||||||
|
in '0'..'9' -> appendToExistingNumber(char)
|
||||||
|
'm' -> return accept {
|
||||||
|
val arg3 = ttyEscArguments.pop()
|
||||||
|
val arg2 = ttyEscArguments.pop()
|
||||||
|
val arg1 = ttyEscArguments.pop()
|
||||||
|
sgrThreeArg(arg1, arg2, arg3)
|
||||||
|
}
|
||||||
|
else -> return reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TTY_ESC_STATE.SEP1 -> {
|
||||||
|
when (char.toChar()) {
|
||||||
|
in '0'..'9' -> registerNewNumberArg(char, TTY_ESC_STATE.NUM2)
|
||||||
|
'H' -> return accept {
|
||||||
|
val arg1 = ttyEscArguments.pop()
|
||||||
|
cursorXY(arg1, 0)
|
||||||
|
}
|
||||||
|
';' -> {
|
||||||
|
ttyEscArguments.push(0)
|
||||||
|
ttyEscState = TTY_ESC_STATE.SEP2
|
||||||
|
}
|
||||||
|
else -> return reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TTY_ESC_STATE.SEP2 -> {
|
||||||
|
when (char.toChar()) {
|
||||||
|
'm' -> return accept {
|
||||||
|
val arg2 = ttyEscArguments.pop()
|
||||||
|
val arg1 = ttyEscArguments.pop()
|
||||||
|
sgrThreeArg(arg1, arg2, 0)
|
||||||
|
}
|
||||||
|
in '0'..'9' -> registerNewNumberArg(char, TTY_ESC_STATE.NUM3)
|
||||||
|
else -> return reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretEscapeSequence() {
|
abstract fun resetTtyStatus()
|
||||||
TODO()
|
abstract fun cursorUp(arg: Int = 1)
|
||||||
}
|
abstract fun cursorDown(arg: Int = 1)
|
||||||
|
abstract fun cursorFwd(arg: Int = 1)
|
||||||
|
abstract fun cursorBack(arg: Int = 1)
|
||||||
|
abstract fun cursorNextLine(arg: Int = 1)
|
||||||
|
abstract fun cursorPrevLine(arg: Int = 1)
|
||||||
|
abstract fun cursorX(arg: Int = 1) // aka Cursor Horizintal Absolute
|
||||||
|
abstract fun eraseInDisp(arg: Int = 0)
|
||||||
|
abstract fun eraseInLine(arg: Int = 0)
|
||||||
|
abstract fun scrollUp(arg: Int = 1)
|
||||||
|
abstract fun scrollDown(arg: Int = 1)
|
||||||
|
abstract fun sgrOneArg(arg: Int = 0)
|
||||||
|
abstract fun sgrThreeArg(arg1: Int, arg2: Int, arg3: Int)
|
||||||
|
abstract fun cursorXY(arg1: Int, arg2: Int)
|
||||||
|
|
||||||
private val ESC = 0x1B.toByte()
|
private val ESC = 0x1B.toByte()
|
||||||
private val LBRACKET = 0x5B.toByte()
|
|
||||||
|
|
||||||
private val FORE_DEFAULT = 254
|
private val FORE_DEFAULT = 254
|
||||||
private val BACK_DEFAULT = 255
|
private val BACK_DEFAULT = 255
|
||||||
|
|
||||||
|
|
||||||
|
private enum class TTY_ESC_STATE {
|
||||||
|
INITIAL, ESC, CSI, NUM1, SEP1, NUM2, SEP2, NUM3
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -82,11 +206,13 @@ digraph G {
|
|||||||
CSI -> CursorBack [label="D"]
|
CSI -> CursorBack [label="D"]
|
||||||
CSI -> CursorNextLine [label="E"]
|
CSI -> CursorNextLine [label="E"]
|
||||||
CSI -> CursorPrevLine [label="F"]
|
CSI -> CursorPrevLine [label="F"]
|
||||||
CSI -> CursorY [label="G"]
|
CSI -> CursorX [label="G"]
|
||||||
CSI -> EraseDisp [label="J"]
|
CSI -> EraseInDisp [label="J"]
|
||||||
CSI -> EraseLine [label="K"]
|
CSI -> EraseInLine [label="K"]
|
||||||
CSI -> ScrollUp [label="S"]
|
CSI -> ScrollUp [label="S"]
|
||||||
CSI -> ScrollDown [label="T"]
|
CSI -> ScrollDown [label="T"]
|
||||||
|
CSI -> SGR [label="m"]
|
||||||
|
CSI -> separator1 [label="; (zero)"]
|
||||||
|
|
||||||
numeral -> numeral [label="0..9"]
|
numeral -> numeral [label="0..9"]
|
||||||
numeral -> CursorUp [label="A"]
|
numeral -> CursorUp [label="A"]
|
||||||
@@ -95,25 +221,29 @@ digraph G {
|
|||||||
numeral -> CursorBack [label="D"]
|
numeral -> CursorBack [label="D"]
|
||||||
numeral -> CursorNextLine [label="E"]
|
numeral -> CursorNextLine [label="E"]
|
||||||
numeral -> CursorPrevLine [label="F"]
|
numeral -> CursorPrevLine [label="F"]
|
||||||
numeral -> CursorY [label="G"]
|
numeral -> CursorX [label="G"]
|
||||||
numeral -> EraseDisp [label="J"]
|
numeral -> EraseInDisp [label="J"]
|
||||||
numeral -> EraseLine [label="K"]
|
numeral -> EraseInLine [label="K"]
|
||||||
numeral -> ScrollUp [label="S"]
|
numeral -> ScrollUp [label="S"]
|
||||||
numeral -> ScrollDown [label="T"]
|
numeral -> ScrollDown [label="T"]
|
||||||
|
|
||||||
numeral -> SGR [label="(any unacceptable char)"]
|
numeral -> SGR [label="m"]
|
||||||
|
|
||||||
numeral -> separator1 [label=";"]
|
numeral -> separator1 [label=";"]
|
||||||
|
|
||||||
separator1 -> numeral2 [label="0..9"]
|
separator1 -> numeral2 [label="0..9"]
|
||||||
|
separator1 -> separator2 [label="; (zero)"]
|
||||||
|
separator1 -> CursorPos [label="H (zero)"]
|
||||||
|
|
||||||
numeral2 -> numeral2 [label="0..9"]
|
numeral2 -> numeral2 [label="0..9"]
|
||||||
numeral2 -> CursorPos [label="H"]
|
numeral2 -> CursorPos [label="H"]
|
||||||
|
|
||||||
numeral2 -> separator2 [label=";"]
|
numeral2 -> separator2 [label=";"]
|
||||||
|
|
||||||
separator2 -> numeral3 [label="0..9"]
|
separator2 -> numeral3 [label="0..9"]
|
||||||
numeral3 -> numeral3 [label="0..9"]
|
numeral3 -> numeral3 [label="0..9"]
|
||||||
|
|
||||||
numeral3 -> "SGR-Colour" [label="(any unacceptable char)"]
|
separator2 -> "SGR-Colour" [label="m (zero)"]
|
||||||
|
numeral3 -> "SGR-Colour" [label="m"]
|
||||||
|
|
||||||
ESC [shape=Mdiamond]
|
ESC [shape=Mdiamond]
|
||||||
Reset -> end
|
Reset -> end
|
||||||
@@ -123,9 +253,9 @@ digraph G {
|
|||||||
CursorBack -> end
|
CursorBack -> end
|
||||||
CursorNextLine -> end
|
CursorNextLine -> end
|
||||||
CursorPrevLine -> end
|
CursorPrevLine -> end
|
||||||
CursorY -> end
|
CursorX -> end
|
||||||
EraseDisp -> end
|
EraseInDisp -> end
|
||||||
EraseLine -> end
|
EraseInLine -> end
|
||||||
ScrollUp -> end
|
ScrollUp -> end
|
||||||
ScrollDown -> end
|
ScrollDown -> end
|
||||||
CursorPos -> end
|
CursorPos -> end
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_RO
|
|||||||
private val chrrom0 = Texture("./FontROM7x14.png")
|
private val chrrom0 = Texture("./FontROM7x14.png")
|
||||||
private val faketex: Texture
|
private val faketex: Texture
|
||||||
|
|
||||||
private val spriteAndTextArea = UnsafeHelper.allocate(10660L)
|
internal val spriteAndTextArea = UnsafeHelper.allocate(10660L)
|
||||||
private val unusedArea = ByteArray(92)
|
private val unusedArea = ByteArray(92)
|
||||||
|
|
||||||
private val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) DRAW_SHADER_FRAG_LCD else DRAW_SHADER_FRAG)
|
private val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) DRAW_SHADER_FRAG_LCD else DRAW_SHADER_FRAG)
|
||||||
|
|||||||
Reference in New Issue
Block a user