From 2cf9af4a6ec80b4d25fbc971fbddd8a539e895a3 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 9 Sep 2019 04:51:18 +0200 Subject: [PATCH] implemented sim timer and clock --- sim65/src/Sim65Main.kt | 27 +++++++-- sim65/src/components/RealTimeClock.kt | 79 +++++++++++++++++++++++++++ sim65/src/components/Timer.kt | 73 ++++++++++++++++++++++--- 3 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 sim65/src/components/RealTimeClock.kt diff --git a/sim65/src/Sim65Main.kt b/sim65/src/Sim65Main.kt index 8a9b3d349..f38290467 100644 --- a/sim65/src/Sim65Main.kt +++ b/sim65/src/Sim65Main.kt @@ -25,20 +25,37 @@ private fun startSimulator(args: Array) { val ram = Ram(0, 0xffff) ram[RESET_vector] = 0x00 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 timer = Timer(0xd100, 0xd103) + val clock = RealTimeClock(0xd100, 0xd108) + val timer = Timer(0xd200, 0xd203) val bus = Bus() bus.add(cpu) bus.add(parallel) + bus.add(clock) bus.add(timer) bus.add(ram) bus.reset() - cpu.tracing = true - - while (true) { - bus.clock() + try { + while (true) { + bus.clock() + } + } catch (ix: InstructionError) { + // ignore } + + ram.hexDump(0x2000, 0x2008) } diff --git a/sim65/src/components/RealTimeClock.kt b/sim65/src/components/RealTimeClock.kt new file mode 100644 index 000000000..7b4178464 --- /dev/null +++ b/sim65/src/components/RealTimeClock.kt @@ -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 */ + } +} diff --git a/sim65/src/components/Timer.kt b/sim65/src/components/Timer.kt index b87d459ac..55d482b1f 100644 --- a/sim65/src/components/Timer.kt +++ b/sim65/src/components/Timer.kt @@ -1,28 +1,85 @@ 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 { require(endAddress - startAddress + 1 == 4) { "timer needs exactly 4 memory bytes" } } override fun clock() { - counter++ - if (counter > 0xffffffff) - counter = 0 - println("TIMER CLOCK $counter") + if (enabled && interval > 0) { + counter++ + if (counter == interval) { + if (nmi) + println("TODO: timer causes CPU nmi $counter") // TODO + else + println("TODO: timer causes CPU irq $counter") // TODO + counter = 0 + } + } } override fun reset() { counter = 0 + interval = 0 + enabled = false + nmi = false } 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) { - 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) + } + } } }