2019-09-11 00:39:58 +00:00
|
|
|
package razorvine.ksim65.components
|
2019-09-11 00:17:59 +00:00
|
|
|
|
2019-09-14 19:11:20 +00:00
|
|
|
import razorvine.ksim65.Bus
|
|
|
|
|
2019-09-11 00:17:59 +00:00
|
|
|
typealias UByte = Short
|
|
|
|
typealias Address = Int
|
|
|
|
|
|
|
|
|
2019-09-14 19:11:20 +00:00
|
|
|
/**
|
|
|
|
* Base class for any component connected to the system bus.
|
|
|
|
*/
|
2019-09-11 00:17:59 +00:00
|
|
|
abstract class BusComponent {
|
|
|
|
lateinit var bus: Bus
|
|
|
|
|
2019-09-15 03:04:57 +00:00
|
|
|
/**
|
|
|
|
* One clock cycle on the bus
|
|
|
|
*/
|
2019-09-11 00:17:59 +00:00
|
|
|
abstract fun clock()
|
2019-09-15 03:04:57 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset all devices on the bus
|
|
|
|
*/
|
2019-09-11 00:17:59 +00:00
|
|
|
abstract fun reset()
|
|
|
|
}
|
|
|
|
|
2019-09-14 19:11:20 +00:00
|
|
|
/**
|
|
|
|
* Base class for components that have registers mapped into the cpu's address space.
|
|
|
|
* Most I/O components fall into this category.
|
|
|
|
*/
|
2019-09-11 00:19:33 +00:00
|
|
|
abstract class MemMappedComponent(val startAddress: Address, val endAddress: Address) : BusComponent() {
|
2020-02-05 00:02:27 +00:00
|
|
|
abstract operator fun get(offset: Int): UByte
|
|
|
|
abstract operator fun set(offset: Int, data: UByte)
|
2019-09-11 00:17:59 +00:00
|
|
|
|
|
|
|
init {
|
2019-09-11 00:19:33 +00:00
|
|
|
require(endAddress >= startAddress)
|
|
|
|
require(startAddress >= 0 && endAddress <= 0xffff) { "can only have 16-bit address space" }
|
2019-09-11 00:17:59 +00:00
|
|
|
}
|
|
|
|
|
2019-10-12 10:35:18 +00:00
|
|
|
fun hexDump(from: Address, to: Address, charmapper: ((Short) -> Char)? = null) {
|
2019-09-11 00:19:33 +00:00
|
|
|
(from..to).chunked(16).forEach {
|
2019-09-11 00:17:59 +00:00
|
|
|
print("\$${it.first().toString(16).padStart(4, '0')} ")
|
2020-02-05 00:02:27 +00:00
|
|
|
val bytes = it.map { address -> get(address - startAddress) }
|
2019-09-11 00:17:59 +00:00
|
|
|
bytes.forEach { byte ->
|
2019-10-12 10:35:18 +00:00
|
|
|
print(byte.toString(16).padStart(2, '0')+" ")
|
2019-09-11 00:17:59 +00:00
|
|
|
}
|
|
|
|
print(" ")
|
2019-10-12 10:35:18 +00:00
|
|
|
val chars = if (charmapper != null) bytes.map { b -> charmapper(b) }
|
2021-07-06 21:37:19 +00:00
|
|
|
else bytes.map { b -> if (b in 32..255) b.toInt().toChar() else '.' }
|
2019-09-14 16:58:45 +00:00
|
|
|
println(chars.joinToString(""))
|
2019-09-11 00:17:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-14 19:11:20 +00:00
|
|
|
/**
|
|
|
|
* Base class for components that actually contain memory (RAM or ROM chips).
|
|
|
|
*/
|
2019-10-12 10:35:18 +00:00
|
|
|
abstract class MemoryComponent(startAddress: Address, endAddress: Address) : MemMappedComponent(startAddress, endAddress) {
|
2019-09-16 23:18:32 +00:00
|
|
|
|
|
|
|
abstract val data: Array<UByte>
|
2019-09-15 03:04:57 +00:00
|
|
|
|
|
|
|
init {
|
2019-10-12 10:35:18 +00:00
|
|
|
require(startAddress and 0xff == 0 && endAddress and 0xff == 0xff) { "address range must span complete page(s)" }
|
2019-09-15 03:04:57 +00:00
|
|
|
}
|
2019-09-21 13:57:14 +00:00
|
|
|
|
2020-02-01 16:19:43 +00:00
|
|
|
fun getBlock(start: Int, length: Int): Array<UByte> = data.copyOfRange(start, start+length)
|
2019-09-11 00:17:59 +00:00
|
|
|
}
|