mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
more input reading|js console app
This commit is contained in:
44
assets/jscon.js
Normal file
44
assets/jscon.js
Normal file
@@ -0,0 +1,44 @@
|
||||
function readConsoleInput() {
|
||||
var cmdbuf = "";
|
||||
var key = -1;
|
||||
while (key != 10 && key != 13) {
|
||||
key = vm.readKey();
|
||||
// printable chars
|
||||
if (key >= 32 && key <= 126) {
|
||||
var s = String.fromCharCode(key);
|
||||
cmdbuf += s;
|
||||
print(s);
|
||||
}
|
||||
// backspace
|
||||
else if (key == 8 && cmdbuf.length > 0) {
|
||||
cmdbuf = cmdbuf.substring(0, cmdbuf.length - 1);
|
||||
print(String.fromCharCode(key));
|
||||
}
|
||||
// up down key
|
||||
else if (key >= 19 && key <= 20) {
|
||||
return key;
|
||||
}
|
||||
// left right key
|
||||
else if (key >= 19 && key <= 20) {
|
||||
//
|
||||
}
|
||||
}
|
||||
return cmdbuf;
|
||||
}
|
||||
|
||||
println("JS Console");
|
||||
while (true) {
|
||||
print("JS> ");
|
||||
|
||||
var cmdbuf = readConsoleInput();
|
||||
|
||||
if (typeof cmdbuf == "string") {
|
||||
println();
|
||||
try {
|
||||
println(eval(cmdbuf));
|
||||
}
|
||||
catch (e) {
|
||||
println(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,16 +22,9 @@ println("Starting TVDOS...");
|
||||
|
||||
greet();
|
||||
|
||||
/*while (true) {
|
||||
while (true) {
|
||||
print(get_prompt_text());
|
||||
var s = read();
|
||||
println();
|
||||
println("String read: " + s + "@");
|
||||
}*/
|
||||
|
||||
println(vm.peek(-4093)); // expecting an odd number
|
||||
vm.poke(-4093, 6);
|
||||
for (i = 0; i < 4096; i++) {
|
||||
print(String.fromCharCode(vm.peek(-4097 - i)));
|
||||
}
|
||||
println();
|
||||
}
|
||||
@@ -51,7 +51,8 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
||||
vm.getInputStream = { gpu.getInputStream() }
|
||||
|
||||
// TEST PRG
|
||||
val fr = FileReader("./assets/tvdos/command.js")
|
||||
//val fr = FileReader("./assets/tvdos/command.js")
|
||||
val fr = FileReader("./assets/jscon.js")
|
||||
val prg = fr.readText()
|
||||
fr.close()
|
||||
|
||||
|
||||
@@ -23,10 +23,16 @@ class VMJSR223Delegate(val vm: VM) {
|
||||
}
|
||||
fun println() = print('\n')
|
||||
|
||||
//fun readKey() = vm.inputStream.read()
|
||||
fun readKey(): Int {
|
||||
val inputStream = vm.getInputStream()
|
||||
var key: Int = inputStream.read()
|
||||
inputStream.close()
|
||||
return key
|
||||
}
|
||||
|
||||
/**
|
||||
* Read series of key inputs until Enter/Return key is pressed
|
||||
* Read series of key inputs until Enter/Return key is pressed. Backspace will work but any other non-printable
|
||||
* characters (e.g. arrow keys) won't work.
|
||||
*/
|
||||
fun read(): String {
|
||||
val inputStream = vm.getInputStream()
|
||||
|
||||
@@ -8,6 +8,7 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea
|
||||
open var busy = false
|
||||
|
||||
protected var sendmode = false; private set
|
||||
open var blockSize = 0
|
||||
|
||||
open fun attachDevice(device: BlockTransferInterface?) {
|
||||
recipient = device
|
||||
@@ -39,10 +40,14 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea
|
||||
open fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)? = null) {
|
||||
busy = true
|
||||
ready = false
|
||||
blockSize = minOf(inputData.size, BLOCK_SIZE)
|
||||
writeoutfun?.invoke()
|
||||
busy = false
|
||||
ready = true
|
||||
}
|
||||
abstract fun hasNext(): Boolean
|
||||
open fun doYouHaveNext(): Boolean = recipient?.hasNext() ?: false
|
||||
open fun yourBlockSize(): Int = recipient?.blockSize ?: 0
|
||||
|
||||
/** @param sendmode TRUE for send, FALSE for receive */
|
||||
open fun setMode(sendmode: Boolean) {
|
||||
@@ -52,4 +57,8 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea
|
||||
open fun getMode(): Boolean = sendmode
|
||||
|
||||
open fun cableConnected(): Boolean = recipient?.recipient == this
|
||||
|
||||
companion object {
|
||||
const val BLOCK_SIZE = 4096
|
||||
}
|
||||
}
|
||||
@@ -8,19 +8,22 @@ import net.torvald.tsvm.VM
|
||||
*/
|
||||
internal class BlockTransferPort(val vm: VM, val portno: Int) : BlockTransferInterface(true, false) {
|
||||
|
||||
internal var hasNext = false
|
||||
|
||||
override fun startSend(sendfun: ((BlockTransferInterface) -> Unit)?) {
|
||||
super.startSend { recipient ->
|
||||
val ba = ByteArray(4096) { vm.getIO().blockTransforBlock[portno][it.toLong()] }
|
||||
val ba = ByteArray(BLOCK_SIZE) { vm.getIO().blockTransferRx[portno][it.toLong()] }
|
||||
recipient.writeout(ba)
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean = hasNext
|
||||
|
||||
override fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)?) {
|
||||
super.writeout(inputData) {
|
||||
val copySize = minOf(4096, inputData.size).toLong()
|
||||
val copySize = minOf(BLOCK_SIZE, inputData.size).toLong()
|
||||
val arrayOffset = UnsafeHelper.getArrayOffset(inputData).toLong()
|
||||
UnsafeHelper.memcpyRaw(inputData, arrayOffset, null, vm.getIO().blockTransforBlock[portno].ptr, copySize)
|
||||
UnsafeHelper.memcpyRaw(inputData, arrayOffset, null, vm.getIO().blockTransferRx[portno].ptr, copySize)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,16 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||
/** Absolute y-position of the computer GUI */
|
||||
var guiPosY = 0
|
||||
|
||||
/** Accepts a keycode */
|
||||
private val keyboardBuffer = CircularArray<Byte>(32, true)
|
||||
private var mouseX: Short = 0
|
||||
private var mouseY: Short = 0
|
||||
private var mouseDown = false
|
||||
|
||||
private var keyboardInputRequested = false
|
||||
|
||||
internal val blockTransforBlock = arrayOf(
|
||||
internal val blockTransferRx = arrayOf(
|
||||
UnsafeHelper.allocate(4096),
|
||||
UnsafeHelper.allocate(4096),
|
||||
UnsafeHelper.allocate(4096),
|
||||
UnsafeHelper.allocate(4096)
|
||||
)
|
||||
internal val blockTransferTx = arrayOf(
|
||||
UnsafeHelper.allocate(4096),
|
||||
UnsafeHelper.allocate(4096),
|
||||
UnsafeHelper.allocate(4096),
|
||||
@@ -33,6 +35,8 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||
)
|
||||
private val blockTransferPorts = Array(4) { BlockTransferPort(vm, it) }
|
||||
|
||||
private val keyEventBuffers = ByteArray(8)
|
||||
|
||||
init {
|
||||
blockTransferPorts[0].attachDevice(TestFunctionGenerator())
|
||||
}
|
||||
@@ -71,17 +75,33 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||
in 0..31 -> keyboardBuffer[(addr.toInt())] ?: -1
|
||||
in 32..33 -> (mouseX.toInt() shr (adi - 32).times(8)).toByte()
|
||||
in 34..35 -> (mouseY.toInt() shr (adi - 34).times(8)).toByte()
|
||||
36L -> if (mouseDown) 1 else 0
|
||||
36L -> mouseDown.toInt().toByte()
|
||||
37L -> keyboardBuffer.removeTail() ?: -1
|
||||
38L -> if (keyboardInputRequested) 1 else 0
|
||||
38L -> keyboardInputRequested.toInt().toByte()
|
||||
39L -> rawInputFunctionLatched.toInt().toByte()
|
||||
in 40..47 -> keyEventBuffers[adi - 40]
|
||||
|
||||
in 64..67 -> vm.memsize.shr((adi - 64) * 8).toByte()
|
||||
68L -> (uptimeCounterLatched.toInt() or RTClatched.toInt().shl(1)).toByte()
|
||||
|
||||
in 72..79 -> systemUptime.ushr((adi - 72) * 8).and(255).toByte()
|
||||
in 80..87 -> rtc.ushr((adi - 80) * 8).and(255).toByte()
|
||||
|
||||
4084L -> (blockTransferPorts[0].yourBlockSize().toByte())
|
||||
4085L -> (blockTransferPorts[0].doYouHaveNext().toInt().shl(7) or blockTransferPorts[0].yourBlockSize().ushr(8).and(15)).toByte()
|
||||
4086L -> (blockTransferPorts[1].yourBlockSize().toByte())
|
||||
4087L -> (blockTransferPorts[1].doYouHaveNext().toInt().shl(7) or blockTransferPorts[1].yourBlockSize().ushr(8).and(15)).toByte()
|
||||
4088L -> (blockTransferPorts[2].yourBlockSize().toByte())
|
||||
4089L -> (blockTransferPorts[2].doYouHaveNext().toInt().shl(7) or blockTransferPorts[2].yourBlockSize().ushr(8).and(15)).toByte()
|
||||
4090L -> (blockTransferPorts[3].yourBlockSize().toByte())
|
||||
4091L -> (blockTransferPorts[4].doYouHaveNext().toInt().shl(7) or blockTransferPorts[3].yourBlockSize().ushr(8).and(15)).toByte()
|
||||
|
||||
in 4092..4095 -> composeBlockTransferStatus(adi - 4092).toByte()
|
||||
|
||||
in 4096..8191 -> blockTransforBlock[0][addr - 4096]
|
||||
in 8192..12287 -> blockTransforBlock[1][addr - 8192]
|
||||
in 12288..16383 -> blockTransforBlock[2][addr - 12288]
|
||||
in 16384..20479 -> blockTransforBlock[3][addr - 16384]
|
||||
in 4096..8191 -> blockTransferRx[0][addr - 4096]
|
||||
in 8192..12287 -> blockTransferRx[1][addr - 8192]
|
||||
in 12288..16383 -> blockTransferRx[2][addr - 12288]
|
||||
in 16384..20479 -> blockTransferRx[3][addr - 16384]
|
||||
|
||||
in 131072..262143 -> vm.peripheralTable[1].peripheral?.mmio_read(addr - 131072)
|
||||
in 262144..393215 -> vm.peripheralTable[2].peripheral?.mmio_read(addr - 262144)
|
||||
@@ -101,15 +121,43 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||
when (addr) {
|
||||
37L -> keyboardBuffer.appendHead(byte)
|
||||
38L -> {
|
||||
keyboardInputRequested = (byte != 0.toByte())
|
||||
keyboardInputRequested = (byte.isNonZero())
|
||||
if (keyboardInputRequested) keyboardBuffer.clear()
|
||||
}
|
||||
39L -> rawInputFunctionLatched = (byte.isNonZero())
|
||||
in 40..47 -> keyEventBuffers[adi - 40] = byte
|
||||
68L -> {
|
||||
uptimeCounterLatched = byte.and(0b01).isNonZero()
|
||||
RTClatched = byte.and(0b10).isNonZero()
|
||||
}
|
||||
|
||||
4084L -> blockTransferPorts[0].blockSize = blockTransferPorts[0].blockSize.and(0xFF00) or byte.toInt().and(255)
|
||||
4085L -> {
|
||||
blockTransferPorts[0].hasNext = (byte < 0)
|
||||
blockTransferPorts[0].blockSize = blockTransferPorts[0].blockSize.and(0x00FF) or byte.toInt().and(15)
|
||||
}
|
||||
4086L -> blockTransferPorts[1].blockSize = blockTransferPorts[1].blockSize.and(0xFF00) or byte.toInt().and(255)
|
||||
4087L -> {
|
||||
blockTransferPorts[1].hasNext = (byte < 0)
|
||||
blockTransferPorts[1].blockSize = blockTransferPorts[1].blockSize.and(0x00FF) or byte.toInt().and(15)
|
||||
}
|
||||
4088L -> blockTransferPorts[2].blockSize = blockTransferPorts[2].blockSize.and(0xFF00) or byte.toInt().and(255)
|
||||
4089L -> {
|
||||
blockTransferPorts[2].hasNext = (byte < 0)
|
||||
blockTransferPorts[2].blockSize = blockTransferPorts[2].blockSize.and(0x00FF) or byte.toInt().and(15)
|
||||
}
|
||||
4090L -> blockTransferPorts[3].blockSize = blockTransferPorts[3].blockSize.and(0xFF00) or byte.toInt().and(255)
|
||||
4091L -> {
|
||||
blockTransferPorts[3].hasNext = (byte < 0)
|
||||
blockTransferPorts[3].blockSize = blockTransferPorts[3].blockSize.and(0x00FF) or byte.toInt().and(15)
|
||||
}
|
||||
|
||||
in 4092..4095 -> setBlockTransferPortStatus(adi - 4092, byte)
|
||||
|
||||
in 4096..8191 -> blockTransforBlock[0][addr - 4096] = byte
|
||||
in 8192..12287 -> blockTransforBlock[1][addr - 8192] = byte
|
||||
in 12288..16383 -> blockTransforBlock[2][addr - 12288] = byte
|
||||
in 16384..20479 -> blockTransforBlock[3][addr - 16384] = byte
|
||||
in 4096..8191 -> blockTransferTx[0][addr - 4096] = byte
|
||||
in 8192..12287 -> blockTransferTx[1][addr - 8192] = byte
|
||||
in 12288..16383 -> blockTransferTx[2][addr - 12288] = byte
|
||||
in 16384..20479 -> blockTransferTx[3][addr - 16384] = byte
|
||||
|
||||
in 131072..262143 -> vm.peripheralTable[1].peripheral?.mmio_write(addr - 131072, byte)
|
||||
in 262144..393215 -> vm.peripheralTable[2].peripheral?.mmio_write(addr - 262144, byte)
|
||||
@@ -122,13 +170,47 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
blockTransforBlock.forEach { it.destroy() }
|
||||
blockTransferRx.forEach { it.destroy() }
|
||||
blockTransferTx.forEach { it.destroy() }
|
||||
}
|
||||
|
||||
private var mouseX: Short = 0
|
||||
private var mouseY: Short = 0
|
||||
private var mouseDown = false
|
||||
private var systemUptime = 0L
|
||||
private var rtc = 0L
|
||||
|
||||
fun update(delta: Float) {
|
||||
mouseX = (Gdx.input.x + guiPosX).toShort()
|
||||
mouseY = (Gdx.input.y + guiPosY).toShort()
|
||||
mouseDown = Gdx.input.isTouched
|
||||
if (rawInputFunctionLatched) {
|
||||
rawInputFunctionLatched = false
|
||||
|
||||
// store mouse info
|
||||
mouseX = (Gdx.input.x + guiPosX).toShort()
|
||||
mouseY = (Gdx.input.y + guiPosY).toShort()
|
||||
mouseDown = Gdx.input.isTouched
|
||||
|
||||
// strobe keys to fill the key read buffer
|
||||
var keysPushed = 0
|
||||
keyEventBuffers.fill(0)
|
||||
for (k in 1..254) {
|
||||
if (Gdx.input.isKeyPressed(k)) {
|
||||
keyEventBuffers[keysPushed] = k.toByte()
|
||||
keysPushed += 1
|
||||
}
|
||||
|
||||
if (keysPushed >= 8) break
|
||||
}
|
||||
}
|
||||
|
||||
if (uptimeCounterLatched) {
|
||||
uptimeCounterLatched = false
|
||||
systemUptime = vm.getUptime()
|
||||
}
|
||||
|
||||
if (RTClatched) {
|
||||
RTClatched = false
|
||||
rtc = System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
|
||||
override fun touchUp(p0: Int, p1: Int, p2: Int, p3: Int): Boolean {
|
||||
@@ -140,7 +222,8 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||
}
|
||||
|
||||
override fun keyTyped(p0: Char): Boolean {
|
||||
if (keyboardInputRequested) {
|
||||
if (keyboardInputRequested && !ttySpecialKeyLatched && p0.toInt() > 0) {
|
||||
println("[IO] Key typed: ${p0.toInt()}")
|
||||
keyboardBuffer.appendHead(p0.toByte())
|
||||
return true
|
||||
}
|
||||
@@ -154,15 +237,28 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||
}
|
||||
|
||||
override fun keyUp(p0: Int): Boolean {
|
||||
return false
|
||||
ttySpecialKeyLatched = false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchDragged(p0: Int, p1: Int, p2: Int): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
private var keyboardInputRequested = false
|
||||
private var uptimeCounterLatched = false
|
||||
private var RTClatched = false
|
||||
private var rawInputFunctionLatched = false
|
||||
private var ttySpecialKeyLatched = false
|
||||
// UP DN LE RI
|
||||
private var specialKey = listOf(19,20,21,22).toSortedSet()
|
||||
override fun keyDown(p0: Int): Boolean {
|
||||
return false
|
||||
if (keyboardInputRequested && !ttySpecialKeyLatched && p0 in specialKey) {
|
||||
println("[IO] Key down: $p0")
|
||||
keyboardBuffer.appendHead(p0.toByte())
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchDown(p0: Int, p1: Int, p2: Int, p3: Int): Boolean {
|
||||
@@ -170,4 +266,5 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||
}
|
||||
|
||||
private fun Boolean.toInt() = if (this) 1 else 0
|
||||
}
|
||||
private fun Byte.isNonZero() = this != 0.toByte()
|
||||
}
|
||||
|
||||
14
src/net/torvald/tsvm/peripheral/SerialDiskDrive.kt
Normal file
14
src/net/torvald/tsvm/peripheral/SerialDiskDrive.kt
Normal file
@@ -0,0 +1,14 @@
|
||||
package net.torvald.tsvm.peripheral
|
||||
|
||||
import java.util.*
|
||||
|
||||
class SerialDiskDrive : BlockTransferInterface(false, true) {
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
val diskID: UUID = UUID(0, 0)
|
||||
|
||||
|
||||
}
|
||||
@@ -18,6 +18,8 @@ Nunc mollis nibh vitae sapien consequat, ut vestibulum sem pharetra. Aliquam iac
|
||||
super.startSend { it.writeout(msg) }
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean = false
|
||||
|
||||
override fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)?) {
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ IO Device
|
||||
Endianness: little
|
||||
Note: Always takes up the peripheral slot of zero
|
||||
|
||||
Latching: latching is used to "lock" the fluctuating values when you attempt to read them so you would get
|
||||
reliable values when you try to read them, especially the multibyte values where another byte would
|
||||
change after you read one byte, e.g. System uptime in nanoseconds
|
||||
|
||||
MMIO
|
||||
|
||||
0..31 RO: Raw Keyboard Buffer read. Won't shift the key buffer
|
||||
@@ -51,11 +55,37 @@ MMIO
|
||||
37 RW: Read/Write single key input. Key buffer will be shifted. Manual writing is
|
||||
usually unnecessary as such action must be automatically managed via LibGDX
|
||||
input processing.
|
||||
38 RW: Request keyboard input be read. Write nonzero value to enable, write zero to
|
||||
Stores ASCII code representing the character, plus:
|
||||
19: Up arrow
|
||||
20: Down arrow
|
||||
21: Left arrow
|
||||
22: Right arrow
|
||||
38 RW: Request keyboard input be read (TTY Function). Write nonzero value to enable, write zero to
|
||||
close it. Keyboard buffer will be cleared whenever request is received, so
|
||||
MAKE SURE YOU REQUEST THE KEY INPUT ONLY ONCE!
|
||||
39 WO: Latch Key/Mouse Input (Raw Input function). Write nonzero value to latch.
|
||||
Stores LibGDX Key code
|
||||
40..47 RO: Key Press buffer
|
||||
stores keys that are held down. Can accomodate 8-key rollover (in keyboard geeks' terms)
|
||||
|
||||
64..67 RO: User area memory size in bytes
|
||||
68 WO: Counter latch
|
||||
0b 0000 00ba
|
||||
a: System uptime
|
||||
b: RTC
|
||||
72..79 RO: System uptime in nanoseconds
|
||||
80..87 RO: RTC in microseconds
|
||||
|
||||
4084..4091 RO: Block transfer status
|
||||
0b nnnnnnnn a000 mmmm
|
||||
|
||||
n-read: size of the block from the other device, LSB (4096-full block size is zero)
|
||||
m-read: size of the block from the other device, MSB (4096-full block size is zero)
|
||||
a-read: if the other device hasNext (doYouHaveNext), false if device not present
|
||||
|
||||
n-write: size of the block I'm sending, LSB (4096-full block size is zero)
|
||||
m-write: size of the block I'm sending, MSB (4096-full block size is zero)
|
||||
a-write: if there's more to send (hasNext)
|
||||
|
||||
4092..4095 RW: Block transfer control for Port 1 through 4
|
||||
0b 00ms abcd
|
||||
|
||||
Reference in New Issue
Block a user