serial port seems to work?

This commit is contained in:
minjaesong
2020-05-18 07:32:03 +09:00
parent 57c16bcb44
commit 9321dbceb1
7 changed files with 216 additions and 5 deletions

View File

@@ -22,9 +22,16 @@ 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();

View File

@@ -0,0 +1,55 @@
package net.torvald.tsvm.peripheral
abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolean) {
protected var recipient: BlockTransferInterface? = null
open var ready = true
open var busy = false
protected var sendmode = false; private set
open fun attachDevice(device: BlockTransferInterface?) {
recipient = device
device?.recipient = this
}
open fun areYouReady(): Boolean = recipient?.ready ?: false
open fun areYouBusy(): Boolean = recipient?.busy ?: false
open fun startSend(sendfun: ((BlockTransferInterface) -> Unit)? = null) {
if (areYouReady()) {
busy = true
ready = false
recipient?.let { recipient ->
sendfun?.invoke(recipient)
}
busy = false
ready = true
}
}
open fun startRead() {
recipient?.startSend(null)
}
/** must be called by a sender class */
open fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)? = null) {
busy = true
ready = false
writeoutfun?.invoke()
busy = false
ready = true
}
/** @param sendmode TRUE for send, FALSE for receive */
open fun setMode(sendmode: Boolean) {
this.sendmode = sendmode
}
/** @return TRUE for send, FALSE for receive */
open fun getMode(): Boolean = sendmode
open fun cableConnected(): Boolean = recipient?.recipient == this
}

View File

@@ -0,0 +1,29 @@
package net.torvald.tsvm.peripheral
import net.torvald.UnsafeHelper
import net.torvald.tsvm.VM
/**
* Implementation of single COM port
*/
internal class BlockTransferPort(val vm: VM, val portno: Int) : BlockTransferInterface(true, false) {
override fun startSend(sendfun: ((BlockTransferInterface) -> Unit)?) {
super.startSend { recipient ->
val ba = ByteArray(4096) { vm.getIO().blockTransforBlock[portno][it.toLong()] }
recipient.writeout(ba)
}
}
override fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)?) {
super.writeout(inputData) {
val copySize = minOf(4096, inputData.size).toLong()
val arrayOffset = UnsafeHelper.getArrayOffset(inputData).toLong()
UnsafeHelper.memcpyRaw(inputData, arrayOffset, null, vm.getIO().blockTransforBlock[portno].ptr, copySize)
}
}
}

View File

@@ -180,6 +180,9 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
6L -> getTextmodeAttirbutes()
7L -> getGraphicsAttributes()
8L -> lastUsedColour
9L -> ttyFore.toByte()
10L -> ttyBack.toByte()
11L -> 1
in 0 until VM.MMIO_SIZE -> -1
else -> null
@@ -348,7 +351,7 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
}
override fun ringBell() {
TODO("Not yet implemented")
}
override fun insertTab() {
@@ -429,7 +432,7 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
override fun read(): Int {
var key: Byte
do {
Thread.sleep(4L) // if spinning rate is too fast, this function fail.
Thread.sleep(4L) // if spinning rate is too fast, this function will fail.
// Possible cause: Input event handling of GDX is done on separate thread
key = vm.getIO().mmio_read(37L)!!
} while (key == (-1).toByte())
@@ -465,7 +468,7 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
private var textCursorBlinkTimer = 0f
private val textCursorBlinkInterval = 0.5f
private var textCursorIsOn = true
private var glowDecay = if (lcdMode) 0.69f else 0.25f
private var glowDecay = if (lcdMode) 0.63f else 0.32f
private var decayColor = Color(1f, 1f, 1f, 1f - glowDecay)
fun render(delta: Float, batch: SpriteBatch, x: Float, y: Float) {

View File

@@ -5,6 +5,7 @@ import com.badlogic.gdx.InputProcessor
import net.torvald.UnsafeHelper
import net.torvald.tsvm.VM
import net.torvald.util.CircularArray
import kotlin.experimental.and
class IOSpace(val vm: VM) : PeriBase, InputProcessor {
@@ -24,6 +25,38 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
private var keyboardInputRequested = false
internal val blockTransforBlock = arrayOf(
UnsafeHelper.allocate(4096),
UnsafeHelper.allocate(4096),
UnsafeHelper.allocate(4096),
UnsafeHelper.allocate(4096)
)
private val blockTransferPorts = Array(4) { BlockTransferPort(vm, it) }
init {
blockTransferPorts[0].attachDevice(TestFunctionGenerator())
}
private fun composeBlockTransferStatus(portno: Int): Int {
return blockTransferPorts[portno].isMaster.toInt().shl(5) or
blockTransferPorts[portno].isSlave.toInt().shl(4) or
blockTransferPorts[portno].getMode().toInt().shl(3) or
blockTransferPorts[portno].busy.toInt().shl(2) or
blockTransferPorts[portno].areYouReady().toInt().shl(1) or
blockTransferPorts[portno].cableConnected().toInt()
}
private fun setBlockTransferPortStatus(portno: Int, bits: Byte) {
blockTransferPorts[portno].setMode(bits.and(0b0000_1000) != 0.toByte())
blockTransferPorts[portno].ready = bits.and(0b0000_0010) != 0.toByte()
if (bits.and(0b0000_0100) != 0.toByte()) {
if (blockTransferPorts[portno].getMode())
blockTransferPorts[portno].startSend()
else
blockTransferPorts[portno].startRead()
}
}
override fun peek(addr: Long): Byte? {
return mmio_read(addr)
}
@@ -42,6 +75,22 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
37L -> keyboardBuffer.removeTail() ?: -1
38L -> if (keyboardInputRequested) 1 else 0
in 64..67 -> vm.memsize.shr((adi - 64) * 8).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 131072..262143 -> vm.peripheralTable[1].peripheral?.mmio_read(addr - 131072)
in 262144..393215 -> vm.peripheralTable[2].peripheral?.mmio_read(addr - 262144)
in 393216..524287 -> vm.peripheralTable[3].peripheral?.mmio_read(addr - 393216)
in 524288..655359 -> vm.peripheralTable[4].peripheral?.mmio_read(addr - 524288)
in 655360..786431 -> vm.peripheralTable[5].peripheral?.mmio_read(addr - 655360)
in 786432..917503 -> vm.peripheralTable[6].peripheral?.mmio_read(addr - 786432)
in 917504..1048575 -> vm.peripheralTable[7].peripheral?.mmio_read(addr - 917504)
else -> -1
}
}
@@ -55,10 +104,25 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
keyboardInputRequested = (byte != 0.toByte())
if (keyboardInputRequested) keyboardBuffer.clear()
}
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 131072..262143 -> vm.peripheralTable[1].peripheral?.mmio_write(addr - 131072, byte)
in 262144..393215 -> vm.peripheralTable[2].peripheral?.mmio_write(addr - 262144, byte)
in 393216..524287 -> vm.peripheralTable[3].peripheral?.mmio_write(addr - 393216, byte)
in 524288..655359 -> vm.peripheralTable[4].peripheral?.mmio_write(addr - 524288, byte)
in 655360..786431 -> vm.peripheralTable[5].peripheral?.mmio_write(addr - 655360, byte)
in 786432..917503 -> vm.peripheralTable[6].peripheral?.mmio_write(addr - 786432, byte)
in 917504..1048575 -> vm.peripheralTable[7].peripheral?.mmio_write(addr - 917504, byte)
}
}
override fun dispose() {
blockTransforBlock.forEach { it.destroy() }
}
fun update(delta: Float) {
@@ -104,4 +168,6 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
override fun touchDown(p0: Int, p1: Int, p2: Int, p3: Int): Boolean {
return false
}
private fun Boolean.toInt() = if (this) 1 else 0
}

View File

@@ -0,0 +1,28 @@
package net.torvald.tsvm.peripheral
class TestFunctionGenerator : BlockTransferInterface(true, false) {
val msg = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ipsum magna, ultrices eu leo eu, consequat eleifend arcu. Nam tempor nunc aliquam mi cursus mollis. Aenean dictum iaculis dolor eget porttitor. Fusce vulputate dui id mauris ultricies, non aliquet nulla pulvinar. Integer consectetur nulla at cursus cursus. Nullam enim nisl, elementum a fermentum sed, suscipit id sapien. Duis eget enim lacinia, aliquam sapien ac, commodo risus. Morbi at enim sem. Aenean sollicitudin purus et sem porttitor, convallis ultricies nulla posuere. Suspendisse euismod sagittis vestibulum. Mauris lorem nisl, placerat et finibus non, cursus non ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse finibus non dui vel tempor. Nam rhoncus ligula et massa sagittis fringilla. Cras convallis pellentesque nulla in rutrum.
Quisque ac orci sodales, semper neque eu, consequat lacus. Nulla suscipit orci felis, id tempor quam ultrices quis. Integer eu vulputate risus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas posuere sem sed erat tristique laoreet. Sed in ante est. Fusce nec est ut nunc aliquam condimentum viverra non ex. Pellentesque nisi ante, efficitur id neque sit amet, convallis tincidunt sapien. Nunc condimentum rutrum nisi, eu lobortis libero tempor non. Morbi euismod venenatis tincidunt. Nulla facilisi. Ut interdum nec nisi pharetra pretium.
Sed condimentum semper erat convallis vulputate. Donec rhoncus sodales faucibus. Morbi pulvinar elit quis lectus accumsan, a sagittis turpis scelerisque. Praesent at interdum quam. In hac habitasse platea dictumst. Vestibulum vulputate sem id massa maximus, quis malesuada nisl vestibulum. Nam fermentum feugiat tortor non imperdiet. Cras elementum ipsum at magna consectetur pellentesque. Etiam gravida mi sed magna venenatis pulvinar. Aenean scelerisque justo eu volutpat mattis.
Pellentesque faucibus tempus nibh, nec ultricies tortor aliquam at. Vestibulum nec imperdiet nulla. Nulla imperdiet neque vel ultrices molestie. Sed elementum sed quam id hendrerit. Ut sit amet scelerisque purus, eu porttitor enim. Curabitur luctus a lectus vitae commodo. Aenean sollicitudin metus non consequat molestie. Nulla ut venenatis lacus. Phasellus cursus erat et lorem sagittis elementum.
Nam in aliquet velit, vitae aliquam sapien. Phasellus imperdiet nulla augue, fermentum malesuada dolor hendrerit nec. Phasellus finibus dictum risus, tincidunt tincidunt turpis egestas ut. Pellentesque dapibus ipsum orci, vel volutpat justo sollicitudin a. Curabitur ut rhoncus ex. Maecenas ac dui vitae mauris iaculis sollicitudin. Etiam ac augue vitae elit consectetur condimentum et non turpis. Phasellus nunc leo, ultricies eu massa ut, elementum auctor odio. Duis interdum in est in suscipit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse suscipit vel tortor id lacinia. Nunc maximus turpis maximus arcu viverra, eu facilisis felis tincidunt. Curabitur id lectus libero.
Nunc mollis nibh vitae sapien consequat, ut vestibulum sem pharetra. Aliquam iaculis, felis ut auctor porta, ipsum diam laoreet ex, sed egestas lacus est at neque. Aenean venenatis blandit arcu at porta. Nunc sed est magna. Duis pulvinar, nulla eu tristique mattis, dui diam malesuada sem, ac condimentum turpis nunc iaculis urna. Nam et ligula aliquet, fermentum lectus nec, consectetur ipsum. Proin convallis, mi id consectetur lobortis, urna nulla pellentesque odio, a finibus tortor nisl nec tortor. Suspendisse blandit nisl in magna hendrerit tristique. Cras sit amet metus et lacus rutrum tempus. In sapien elit, facilisis quis tristique a, vestibulum a massa. Donec ligula diam, posuere ac velit eget, lobortis tincidunt ante. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam lectus massa, egestas eu urna id, tempor pulvinar odio. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam in suscipit mauris, quis faucibus dui. Cras tincidunt turpe es.""".toByteArray(Charsets.US_ASCII)
override fun startSend(sendfun: ((BlockTransferInterface) -> Unit)?) {
super.startSend { it.writeout(msg) }
}
override fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)?) {
}
override fun setMode(sendmode: Boolean) {
}
override fun getMode(): Boolean = true
}

View File

@@ -57,6 +57,28 @@ MMIO
64..67 RO: User area memory size in bytes
4092..4095 RW: Block transfer control for Port 1 through 4
0b 00ms abcd
m-readonly: device in master setup
s-readonly: device in slave setup
a: 1 for send, 0 for receive
b-write: 1 to start sending if a-bit is set; if f-bit is unset, make other device to start sending
b-read: if this bit is set, you're currently receiving something (aka busy)
c-write: I'm ready to receive
c-read: Are you ready to receive?
d-read: Are you there? (if the other device's recipient is myself)
NOTE: not ready AND not busy (bits b and d set when read) means the device is not connected to the port
4096..8191 RW: Buffer for block transfer lane #1
8192..12287 RW: Buffer for block transfer lane #2
12288..16383 RW: Buffer for block transfer lane #3
16384..20479 RW: Buffer for block transfer lane #4
--------------------------------------------------------------------------------
@@ -126,5 +148,6 @@ MMIO
10 RW
current TTY background colour (useful for print() function)
Text-mode-font-ROM is immutable and does not belong to VRAM
Even in the text mode framebuffer is still being drawn onto the screen, and the texts are drawn on top of it