1
0
mirror of https://github.com/irmen/ksim65.git synced 2024-06-06 22:29:33 +00:00
ksim65/src/main/kotlin/razorvine/c64emu/VicII.kt

76 lines
2.7 KiB
Kotlin

package razorvine.c64emu
import razorvine.ksim65.Cpu6502
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.MemMappedComponent
import razorvine.ksim65.components.UByte
/**
* Minimal simulation of the VIC-II graphics chip
* It only has some logic to keep track of the raster line
* This chip is the PAL version (50 Hz screen refresh, 312 vertical raster lines)
*/
class VicII(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemMappedComponent(startAddress, endAddress) {
private var ramBuffer = Array<UByte>(endAddress-startAddress+1) { 0xff }
private var rasterIrqLine = 0
private var scanlineClocks = 0
private var interruptStatusRegisterD019 = 0
var currentRasterLine = 1
val vsync: Boolean
get() = currentRasterLine == 0
companion object {
const val framerate = 50
const val rasterlines = 312
}
init {
require(endAddress-startAddress+1 == 0x400) { "vic-II requires exactly 1024 memory bytes (64*16 mirrored)" }
ramBuffer[0x1a] = 0 // initially, disable IRQs
}
override fun clock() {
scanlineClocks++
if (scanlineClocks == 63) {
scanlineClocks = 0
currentRasterLine++
if (currentRasterLine >= rasterlines) currentRasterLine = 0
interruptStatusRegisterD019 = if (currentRasterLine == rasterIrqLine) {
// signal that current raster line is equal to the desired IRQ raster line
// schedule an IRQ as well if the raster interrupt is enabled
if ((ramBuffer[0x1a].toInt() and 1) != 0) cpu.irqAsserted = true
interruptStatusRegisterD019 or 0b10000001
} else interruptStatusRegisterD019 and 0b11111110
}
}
override fun reset() {
rasterIrqLine = 0
currentRasterLine = 1
interruptStatusRegisterD019 = 0
}
override operator fun get(offset: Int): UByte {
return when (val register = offset and 63) {
0x11 -> (0b00011011 or ((currentRasterLine and 0b100000000) ushr 1)).toShort()
0x12 -> {
(currentRasterLine and 255).toShort()
}
0x19 -> interruptStatusRegisterD019.toShort()
else -> ramBuffer[register]
}
}
override operator fun set(offset: Int, data: UByte) {
val register = offset and 63
ramBuffer[register] = data
when (register) {
0x11 -> {
val rasterHigh = (data.toInt() ushr 7) shl 8
rasterIrqLine = (rasterIrqLine and 0x00ff) or rasterHigh
}
0x12 -> rasterIrqLine = (rasterIrqLine and 0xff00) or data.toInt()
}
}
}