From 9321dbceb1930d38cc968c29bdb1f99195296844 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Mon, 18 May 2020 07:32:03 +0900 Subject: [PATCH] serial port seems to work? --- assets/tvdos/command.js | 11 +++- .../tsvm/peripheral/BlockTransferInterface.kt | 55 ++++++++++++++++ .../tsvm/peripheral/BlockTransferPort.kt | 29 ++++++++ .../tsvm/peripheral/GraphicsAdapter.kt | 9 ++- src/net/torvald/tsvm/peripheral/IOSpace.kt | 66 +++++++++++++++++++ .../tsvm/peripheral/TestFunctionGenerator.kt | 28 ++++++++ terranmon.txt | 23 +++++++ 7 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt create mode 100644 src/net/torvald/tsvm/peripheral/BlockTransferPort.kt create mode 100644 src/net/torvald/tsvm/peripheral/TestFunctionGenerator.kt diff --git a/assets/tvdos/command.js b/assets/tvdos/command.js index 7918963..da34017 100644 --- a/assets/tvdos/command.js +++ b/assets/tvdos/command.js @@ -22,9 +22,16 @@ println("Starting TVDOS..."); greet(); -while (true) { +/*while (true) { print(get_prompt_text()); var s = read(); println(); println("String read: " + s + "@"); -} \ No newline at end of file +}*/ + +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(); \ No newline at end of file diff --git a/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt b/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt new file mode 100644 index 0000000..fe50a04 --- /dev/null +++ b/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt @@ -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 +} \ No newline at end of file diff --git a/src/net/torvald/tsvm/peripheral/BlockTransferPort.kt b/src/net/torvald/tsvm/peripheral/BlockTransferPort.kt new file mode 100644 index 0000000..058eafb --- /dev/null +++ b/src/net/torvald/tsvm/peripheral/BlockTransferPort.kt @@ -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) + } + } + + + +} \ No newline at end of file diff --git a/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt b/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt index 23b9520..4c6e2b9 100644 --- a/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt +++ b/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt @@ -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) { diff --git a/src/net/torvald/tsvm/peripheral/IOSpace.kt b/src/net/torvald/tsvm/peripheral/IOSpace.kt index c088d8d..2f724ac 100644 --- a/src/net/torvald/tsvm/peripheral/IOSpace.kt +++ b/src/net/torvald/tsvm/peripheral/IOSpace.kt @@ -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 } \ No newline at end of file diff --git a/src/net/torvald/tsvm/peripheral/TestFunctionGenerator.kt b/src/net/torvald/tsvm/peripheral/TestFunctionGenerator.kt new file mode 100644 index 0000000..710267f --- /dev/null +++ b/src/net/torvald/tsvm/peripheral/TestFunctionGenerator.kt @@ -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 +} \ No newline at end of file diff --git a/terranmon.txt b/terranmon.txt index b63f882..f94d864 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -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 \ No newline at end of file