mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-10 23:04:04 +09:00
somewhat accurate baud rate delay simulator
This commit is contained in:
@@ -196,7 +196,9 @@ VRAM Bank 0 (256 kB)
|
|||||||
|
|
||||||
Endianness: little
|
Endianness: little
|
||||||
|
|
||||||
From the start of the memory space:
|
|
||||||
|
Memory Space
|
||||||
|
|
||||||
250880 bytes
|
250880 bytes
|
||||||
Framebuffer
|
Framebuffer
|
||||||
3 bytes
|
3 bytes
|
||||||
@@ -675,6 +677,9 @@ Sound Adapter
|
|||||||
|
|
||||||
Endianness: little
|
Endianness: little
|
||||||
|
|
||||||
|
|
||||||
|
Memory Space
|
||||||
|
|
||||||
0..114687 RW: Sample bin
|
0..114687 RW: Sample bin
|
||||||
114688..131071 RW: Instrument bin (256 instruments, 64 bytes each)
|
114688..131071 RW: Instrument bin (256 instruments, 64 bytes each)
|
||||||
131072..196607 RW: Play data 1
|
131072..196607 RW: Play data 1
|
||||||
@@ -833,3 +838,68 @@ MMIO
|
|||||||
92..103 RW : DMA Lane 6 Props
|
92..103 RW : DMA Lane 6 Props
|
||||||
104..115 RW : DMA Lane 7 Props
|
104..115 RW : DMA Lane 7 Props
|
||||||
116..127 RW : DMA Lane 8 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
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package net.torvald.tsvm.peripheral
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
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
|
var recipient: BlockTransferInterface? = null; protected set
|
||||||
|
|
||||||
@@ -34,7 +34,9 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea
|
|||||||
ready.setRelease(false)
|
ready.setRelease(false)
|
||||||
|
|
||||||
recipient?.let {
|
recipient?.let {
|
||||||
this.blockSize.set(startSendImpl(it))
|
val bytesSent = startSendImpl(it)
|
||||||
|
this.blockSize.set(bytesSent)
|
||||||
|
applyBaudRateDelay(bytesSent)
|
||||||
//println("[BlockTransferInterface.startSend()] recipients blocksize = ${this.blockSize}")
|
//println("[BlockTransferInterface.startSend()] recipients blocksize = ${this.blockSize}")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,8 +62,13 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea
|
|||||||
fun writeout(inputData: ByteArray) {
|
fun writeout(inputData: ByteArray) {
|
||||||
busy.setRelease(true)
|
busy.setRelease(true)
|
||||||
ready.setRelease(false)
|
ready.setRelease(false)
|
||||||
blockSize.setRelease(minOf(inputData.size, BLOCK_SIZE))
|
|
||||||
|
val bytesReceived = minOf(inputData.size, BLOCK_SIZE)
|
||||||
|
blockSize.setRelease(bytesReceived)
|
||||||
writeoutImpl(inputData)
|
writeoutImpl(inputData)
|
||||||
|
|
||||||
|
applyBaudRateDelay(bytesReceived)
|
||||||
|
|
||||||
busy.setRelease(false)
|
busy.setRelease(false)
|
||||||
ready.setRelease(true)
|
ready.setRelease(true)
|
||||||
}
|
}
|
||||||
@@ -90,6 +97,38 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea
|
|||||||
const val UNIT_SEP = 0x1F.toByte()
|
const val UNIT_SEP = 0x1F.toByte()
|
||||||
const val END_OF_SEND_BLOCK = 0x17.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 {
|
fun ByteArray.trimNull(): ByteArray {
|
||||||
|
|||||||
Reference in New Issue
Block a user