diff --git a/terranmon.txt b/terranmon.txt index 7ca5c72..d3d6930 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -196,7 +196,9 @@ VRAM Bank 0 (256 kB) Endianness: little -From the start of the memory space: + +Memory Space + 250880 bytes Framebuffer 3 bytes @@ -675,6 +677,9 @@ Sound Adapter Endianness: little + +Memory Space + 0..114687 RW: Sample bin 114688..131071 RW: Instrument bin (256 instruments, 64 bytes each) 131072..196607 RW: Play data 1 @@ -833,3 +838,68 @@ MMIO 92..103 RW : DMA Lane 6 Props 104..115 RW : DMA Lane 7 Props 116..127 RW : DMA Lane 8 Props + +-------------------------------------------------------------------------------- + +High Speed Disk Peripheral Adapter (HSDPA) + +Endianness: Little + +MMIO + +0..2 RW: Block transfer status for Disk 1 + 0b nnnn nnnn, nnnn nnnn , a00z mmmm + + n-read: size of the block from the other device, LSB (1048576-full block size is zero) + m-read: size of the block from the other device, MSB (1048576-full block size is zero) + a-read: if the other device hasNext (doYouHaveNext), false if device not present + z-read: set if the size is actually 0 instead of 1048576 (overrides n and m parameters) + + n-write: size of the block I'm sending, LSB (1048576-full block size is zero) + m-write: size of the block I'm sending, MSB (1048576-full block size is zero) + a-write: if there's more to send (hasNext) + z-write: set if the size is actually 0 instead of 1048576 (overrides n and m parameters) +3..5 RW: Block transfer status for Disk 2 +6..8 RW: Block transfer status for Disk 3 +9..11 RW: Block transfer status for Disk 4 +12..15 RW: Block transfer control for Disk 1 through 4 + 0b 0000 abcd + + a: 1 for send, 0 for receive + + b-write: 1 to start sending if a-bit is set; if a-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 +16..19 RW: 8-bit status code for the disk +20 RW: Currently active disk (0: deselect all disk, 1: select disk #1, ...) + + Selecting a disk will automatically unset and hold down "I'm ready to receive" flags of the other disks, + however, the target disk will NOT have its "I'm ready to receive" flag automatically set. + +-- SEQUENTIAL IO SUPPORT MODULE -- + +NOTE: Sequential I/O will clobber the peripheral memory space. + +256..257 RW: Sequential I/O control flags + +258 RW: Opcode + 0x00 - No operation + 0x01 - Skip (arg 1) bytes + 0x02 - Read (arg 1) bytes and store to core memory pointer (arg 2) + 0x03 - Write (arg 1) bytes using data from the core memory from pointer (arg 2) + 0xFF - Terminate sequential I/O session and free up the memory space +259..261 RW: Argument #1 +262..264 RW: Argument #2 +265..267 RW: Argument #3 +268..270 RW: Argument #4 + + +Memory Space + +0..1048575 RW: Buffer for the block transfer lane diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt index 28f0874..6430d1f 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt @@ -3,7 +3,7 @@ package net.torvald.tsvm.peripheral import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger -abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolean) { +abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolean, val baudRate: Int = 20_000_000) { var recipient: BlockTransferInterface? = null; protected set @@ -34,7 +34,9 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea ready.setRelease(false) recipient?.let { - this.blockSize.set(startSendImpl(it)) + val bytesSent = startSendImpl(it) + this.blockSize.set(bytesSent) + applyBaudRateDelay(bytesSent) //println("[BlockTransferInterface.startSend()] recipients blocksize = ${this.blockSize}") } @@ -60,8 +62,13 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea fun writeout(inputData: ByteArray) { busy.setRelease(true) ready.setRelease(false) - blockSize.setRelease(minOf(inputData.size, BLOCK_SIZE)) + + val bytesReceived = minOf(inputData.size, BLOCK_SIZE) + blockSize.setRelease(bytesReceived) writeoutImpl(inputData) + + applyBaudRateDelay(bytesReceived) + busy.setRelease(false) ready.setRelease(true) } @@ -90,6 +97,38 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea const val UNIT_SEP = 0x1F.toByte() const val END_OF_SEND_BLOCK = 0x17.toByte() } + + + private var lastTransmissionTime = 0L + + /** + * Calculates and applies appropriate delay based on data size and baud rate + * @param byteCount Number of bytes being transmitted + */ + protected fun applyBaudRateDelay(byteCount: Int) { + // Calculate delay in milliseconds + // Baud rate is bits per second, and we assume 10 bits per byte (8 data bits + start/stop bits) + val bitsTransmitted = byteCount * 10 + val expectedTransmissionTimeMs = (bitsTransmitted * 1000L) / baudRate + + val currentTime = System.nanoTime() / 1000000L + val elapsedTime = if (lastTransmissionTime > 0) currentTime - lastTransmissionTime else 0 + + // Only sleep if we need to slow down the transmission + if (elapsedTime < expectedTransmissionTimeMs) { + val sleepTime = expectedTransmissionTimeMs - elapsedTime + try { + Thread.sleep(sleepTime) + println("Sleep $sleepTime ms for $byteCount bytes") + } + catch (e: InterruptedException) { + // Handle interruption if needed + } + } + + // Update last transmission time + lastTransmissionTime = System.nanoTime() / 1000000L + } } fun ByteArray.trimNull(): ByteArray {