mirror of
https://github.com/irmen/prog8.git
synced 2025-02-19 11:31:07 +00:00
implemented sim timer and clock
This commit is contained in:
parent
bdcd10512f
commit
2cf9af4a6e
@ -25,20 +25,37 @@ private fun startSimulator(args: Array<String>) {
|
|||||||
val ram = Ram(0, 0xffff)
|
val ram = Ram(0, 0xffff)
|
||||||
ram[RESET_vector] = 0x00
|
ram[RESET_vector] = 0x00
|
||||||
ram[RESET_vector + 1] = 0x10
|
ram[RESET_vector + 1] = 0x10
|
||||||
|
// // read the RTC and write the date+time to $2000
|
||||||
|
// for(b in listOf(0xa0, 0x00, 0xb9, 0x00, 0xd1, 0x99, 0x00, 0x20, 0xc8, 0xc0, 0x09, 0xd0, 0xf5, 0x00).withIndex()) {
|
||||||
|
// ram[0x1000+b.index] = b.value.toShort()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// set the timer to $22aa00 and enable it on regular irq
|
||||||
|
for(b in listOf(0xa9, 0x00, 0x8d, 0x00, 0xd2, 0xa9, 0x00, 0x8d, 0x01, 0xd2, 0xa9, 0xaa, 0x8d, 0x02,
|
||||||
|
0xd2, 0xa9, 0x22, 0x8d, 0x03, 0xd2, 0xa9, 0x01, 0x8d, 0x00, 0xd2, 0x4c, 0x19, 0x10).withIndex()) {
|
||||||
|
ram[0x1000+b.index] = b.value.toShort()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val parallel = ParallelPort(0xd000, 0xd001)
|
val parallel = ParallelPort(0xd000, 0xd001)
|
||||||
val timer = Timer(0xd100, 0xd103)
|
val clock = RealTimeClock(0xd100, 0xd108)
|
||||||
|
val timer = Timer(0xd200, 0xd203)
|
||||||
|
|
||||||
val bus = Bus()
|
val bus = Bus()
|
||||||
bus.add(cpu)
|
bus.add(cpu)
|
||||||
bus.add(parallel)
|
bus.add(parallel)
|
||||||
|
bus.add(clock)
|
||||||
bus.add(timer)
|
bus.add(timer)
|
||||||
bus.add(ram)
|
bus.add(ram)
|
||||||
bus.reset()
|
bus.reset()
|
||||||
|
|
||||||
cpu.tracing = true
|
try {
|
||||||
|
while (true) {
|
||||||
while (true) {
|
bus.clock()
|
||||||
bus.clock()
|
}
|
||||||
|
} catch (ix: InstructionError) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ram.hexDump(0x2000, 0x2008)
|
||||||
}
|
}
|
||||||
|
79
sim65/src/components/RealTimeClock.kt
Normal file
79
sim65/src/components/RealTimeClock.kt
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package sim65.components
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A real-time clock (time of day clock).
|
||||||
|
* byte value
|
||||||
|
* 00 year (lsb)
|
||||||
|
* 01 year (msb)
|
||||||
|
* 02 month, 1-12
|
||||||
|
* 03 day, 1-31
|
||||||
|
* 04 hour, 0-23
|
||||||
|
* 05 minute, 0-59
|
||||||
|
* 06 second, 0-59
|
||||||
|
* 07 millisecond, 0-999 (lsb)
|
||||||
|
* 08 millisecond, 0-999 (msb)
|
||||||
|
*/
|
||||||
|
class RealTimeClock(startAddress: Address, endAddress: Address) : MemMappedComponent(startAddress, endAddress) {
|
||||||
|
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(endAddress - startAddress + 1 == 9) { "rtc needs exactly 9 memory bytes" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clock() {
|
||||||
|
/* not updated on clock pulse */
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
/* never reset */
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun get(address: Address): UByte {
|
||||||
|
when (address - startAddress) {
|
||||||
|
0 -> {
|
||||||
|
val year = calendar.get(Calendar.YEAR)
|
||||||
|
return (year and 255).toShort()
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
val year = calendar.get(Calendar.YEAR)
|
||||||
|
return (year ushr 8).toShort()
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
val month = calendar.get(Calendar.MONTH) + 1
|
||||||
|
return month.toShort()
|
||||||
|
}
|
||||||
|
3 -> {
|
||||||
|
val day = calendar.get(Calendar.DAY_OF_MONTH)
|
||||||
|
return day.toShort()
|
||||||
|
}
|
||||||
|
4 -> {
|
||||||
|
val hour = calendar.get(Calendar.HOUR_OF_DAY)
|
||||||
|
return hour.toShort()
|
||||||
|
}
|
||||||
|
5 -> {
|
||||||
|
val minute = calendar.get(Calendar.MINUTE)
|
||||||
|
return minute.toShort()
|
||||||
|
}
|
||||||
|
6 -> {
|
||||||
|
val second = calendar.get(Calendar.SECOND)
|
||||||
|
return second.toShort()
|
||||||
|
}
|
||||||
|
7 -> {
|
||||||
|
val ms = calendar.get(Calendar.MILLISECOND)
|
||||||
|
return (ms and 255).toShort()
|
||||||
|
}
|
||||||
|
8 -> {
|
||||||
|
val ms = calendar.get(Calendar.MILLISECOND)
|
||||||
|
return (ms ushr 8).toShort()
|
||||||
|
}
|
||||||
|
else -> return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun set(address: Address, data: UByte) {
|
||||||
|
/* real time clock can't be set */
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +1,85 @@
|
|||||||
package sim65.components
|
package sim65.components
|
||||||
|
|
||||||
class Timer(startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) {
|
/**
|
||||||
private var counter: Long = 0
|
* A programmable timer. Causes an IRQ or NMI at specified 24-bits intervals.
|
||||||
|
* byte value
|
||||||
|
* 00 control register bit 0=enable bit 1=nmi (instead of irq)
|
||||||
|
* 01 24 bits interval value, bits 0-7 (lo)
|
||||||
|
* 02 24 bits interval value, bits 8-15 (mid)
|
||||||
|
* 03 24 bits interval value, bits 16-23 (hi)
|
||||||
|
*/
|
||||||
|
class Timer(startAddress: Address, endAddress: Address) : MemMappedComponent(startAddress, endAddress) {
|
||||||
|
private var counter: Int = 0
|
||||||
|
private var interval: Int = 0
|
||||||
|
private var enabled = false
|
||||||
|
private var nmi = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(endAddress - startAddress + 1 == 4) { "timer needs exactly 4 memory bytes" }
|
require(endAddress - startAddress + 1 == 4) { "timer needs exactly 4 memory bytes" }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clock() {
|
override fun clock() {
|
||||||
counter++
|
if (enabled && interval > 0) {
|
||||||
if (counter > 0xffffffff)
|
counter++
|
||||||
counter = 0
|
if (counter == interval) {
|
||||||
println("TIMER CLOCK $counter")
|
if (nmi)
|
||||||
|
println("TODO: timer causes CPU nmi $counter") // TODO
|
||||||
|
else
|
||||||
|
println("TODO: timer causes CPU irq $counter") // TODO
|
||||||
|
counter = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() {
|
override fun reset() {
|
||||||
counter = 0
|
counter = 0
|
||||||
|
interval = 0
|
||||||
|
enabled = false
|
||||||
|
nmi = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override operator fun get(address: Address): UByte {
|
override operator fun get(address: Address): UByte {
|
||||||
TODO("timer read $address")
|
when (address - startAddress) {
|
||||||
|
0 -> {
|
||||||
|
var data = 0
|
||||||
|
if (enabled) data = data or 0b00000001
|
||||||
|
if (nmi) data = data or 0b00000010
|
||||||
|
return data.toShort()
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
return (counter and 0xff).toShort()
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
return ((counter ushr 8) and 0xff).toShort()
|
||||||
|
}
|
||||||
|
3 -> {
|
||||||
|
return ((counter ushr 16) and 0xff).toShort()
|
||||||
|
}
|
||||||
|
else -> return 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override operator fun set(address: Address, data: UByte) {
|
override operator fun set(address: Address, data: UByte) {
|
||||||
TODO("timer write $address = $data")
|
when (address - startAddress) {
|
||||||
|
0 -> {
|
||||||
|
val i = data.toInt()
|
||||||
|
val newEnabled = (i and 0b00000001) != 0
|
||||||
|
nmi = (i and 0b00000010) != 0
|
||||||
|
if(newEnabled && !enabled) {
|
||||||
|
// timer is set to enabled (was disabled) - reset the counter
|
||||||
|
counter = 0
|
||||||
|
}
|
||||||
|
enabled = newEnabled
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
interval = (interval and 0x7fffff00) or data.toInt()
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
interval = (interval and 0x7fff00ff) or (data.toInt() shl 8)
|
||||||
|
}
|
||||||
|
3 -> {
|
||||||
|
interval = (interval and 0x7f00ffff) or (data.toInt() shl 16)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user