1
0
mirror of https://github.com/irmen/ksim65.git synced 2024-11-15 09:05:52 +00:00

memory components reading and writing now done via offset instead of address

This commit is contained in:
Irmen de Jong 2020-02-05 01:02:27 +01:00
parent b4a6709646
commit 81ae12b809
17 changed files with 75 additions and 67 deletions

View File

@ -1,6 +1,7 @@
package razorvine.c64emu
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.Rom
import razorvine.ksim65.components.UByte
/**
@ -12,15 +13,16 @@ import razorvine.ksim65.components.UByte
*
* TODO: mapping the RAM/ROMs in and out of the other banks in the address space (controlled by loram and hiram).
*/
class Bus6510(private val ioPort: CpuIoPort, chargenData: ByteArray): razorvine.ksim65.Bus() {
private val characterData = chargenData.map { (it.toInt() and 255).toShort() }.toShortArray()
class Bus6510(private val ioPort: CpuIoPort,
private val chargen: Rom,
private val basic: Rom,
private val kernal: Rom): razorvine.ksim65.Bus() {
override fun read(address: Address): UByte {
if(address in 0xd000..0xe000) {
if(!ioPort.charen) {
// character rom is enabled in this address range (instead of I/O)
return characterData[address-0xd000]
return chargen[address-chargen.startAddress]
}
}

View File

@ -125,7 +125,7 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
timerBset = 0
}
override fun get(address: Address): UByte {
override operator fun get(offset: Int): UByte {
fun scanColumn(vararg keys: HostKeyPress): UByte {
var bits = 0b10000000
var presses = 0
@ -136,7 +136,7 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
return (presses.inv() and 255).toShort()
}
val register = (address-startAddress) and 15
val register = offset and 15
if (number == 1 && register == 0x01) {
// register 1 on CIA#1 is the keyboard data port
// if bit is cleared in PRA, contains keys pressed in that column of the matrix
@ -235,8 +235,8 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
return tens*10+ones
}
override fun set(address: Address, data: UByte) {
val register = (address-startAddress) and 15
override operator fun set(offset: Int, data: UByte) {
val register = offset and 15
if (number == 1 && register == 0x00) {
// PRA data port A (select keyboard matrix column)
regPRA = data.toInt()

View File

@ -1,7 +1,6 @@
package razorvine.c64emu
import razorvine.ksim65.Cpu6502
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.MemMappedComponent
import razorvine.ksim65.components.UByte
@ -23,14 +22,14 @@ class CpuIoPort(val cpu: Cpu6502) : MemMappedComponent(0x0000, 0x0001) {
override fun clock() { }
override fun reset() { }
override fun get(address: Address): UByte {
return if(address==0) dataDirections.toShort() else {
override operator fun get(offset: Int): UByte {
return if(offset==0) dataDirections.toShort() else {
(ioPort or dataDirections.inv() and 0b00111111).toShort()
}
}
override fun set(address: Address, data: UByte) {
if(address==0) {
override operator fun set(offset: Int, data: UByte) {
if(offset==0) {
dataDirections = data.toInt()
determineRoms()
} else {

View File

@ -2,6 +2,7 @@ package razorvine.c64emu
import razorvine.ksim65.Cpu6502
import razorvine.ksim65.components.MemoryComponent
import razorvine.ksim65.components.Rom
import razorvine.ksim65.components.UByte
import java.awt.Color
import java.awt.KeyboardFocusManager
@ -52,14 +53,14 @@ object ScreenDefs {
val colorPalette = Palette()
}
class MainC64Window(title: String, chargenData: ByteArray, val ram: MemoryComponent, val cpu: Cpu6502, val keypressCia: Cia) :
class MainC64Window(title: String, chargen: Rom, val ram: MemoryComponent, val cpu: Cpu6502, val keypressCia: Cia) :
JFrame(title), KeyListener {
init {
defaultCloseOperation = EXIT_ON_CLOSE
isResizable = false
isFocusable = true
add(Screen(chargenData, ram))
add(Screen(chargen, ram))
addKeyListener(this)
pack()
setLocationRelativeTo(null)

View File

@ -2,6 +2,7 @@ package razorvine.c64emu
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.MemoryComponent
import razorvine.ksim65.components.Rom
import razorvine.ksim65.components.UByte
import java.awt.*
import java.awt.image.BufferedImage
@ -14,7 +15,7 @@ import javax.swing.JPanel
* High res bitmap mode (320*200), Multicolor bitmap mode (160*200).
* TODO: Multicolor character mode. Extended background color mode.
*/
internal class Screen(private val chargenData: ByteArray, val ram: MemoryComponent) : JPanel() {
internal class Screen(private val chargen: Rom, val ram: MemoryComponent) : JPanel() {
private val fullscreenImage: BufferedImage
private val fullscreenG2d: Graphics2D
@ -43,7 +44,7 @@ internal class Screen(private val chargenData: ByteArray, val ram: MemoryCompone
val offset = if (shifted) 256*8 else 0
for (char in 0..255) {
for (line in 0..7) {
val charbyte = chargenData[offset+char*8+line].toInt()
val charbyte = chargen[offset+char*8+line].toInt()
for (x in 0..7) {
if (charbyte and (0b10000000 ushr x) != 0) chars[char].setRGB(x, line, 0xffffff)
}

View File

@ -50,8 +50,8 @@ class VicII(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
interruptStatusRegisterD019 = 0
}
override fun get(address: Address): UByte {
return when (val register = (address-startAddress) and 63) {
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()
@ -61,8 +61,8 @@ class VicII(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
}
}
override fun set(address: Address, data: UByte) {
val register = (address-startAddress) and 63
override operator fun set(offset: Int, data: UByte) {
val register = offset and 63
ramBuffer[register] = data
when (register) {
0x11 -> {

View File

@ -25,23 +25,31 @@ import kotlin.concurrent.scheduleAtFixedRate
*/
class C64Machine(title: String) : IVirtualMachine {
private val romsPath = determineRomPath()
private val chargenData = romsPath.resolve("chargen").toFile().readBytes()
private val basicData = romsPath.resolve("basic").toFile().readBytes()
private val kernalData = romsPath.resolve("kernal").toFile().readBytes()
private val chargenRom = Rom(0xd000, 0xdfff).also {
val chargenData = romsPath.resolve("chargen").toFile().readBytes()
it.load(chargenData)
}
private val basicRom = Rom(0xa000, 0xbfff).also {
val basicData = romsPath.resolve("basic").toFile().readBytes()
it.load(basicData)
}
private val kernalRom = Rom(0xe000, 0xffff).also {
val kernalData = romsPath.resolve("kernal").toFile().readBytes()
it.load(kernalData)
}
override val cpu = Cpu6502()
val cpuIoPort = CpuIoPort(cpu)
override val bus = Bus6510(cpuIoPort, chargenData)
override val bus = Bus6510(cpuIoPort, chargenRom, basicRom, kernalRom)
val ram = Ram(0x0000, 0xffff)
val vic = VicII(0xd000, 0xd3ff, cpu)
val cia1 = Cia(1, 0xdc00, 0xdcff, cpu)
val cia2 = Cia(2, 0xdd00, 0xddff, cpu)
val basicRom = Rom(0xa000, 0xbfff).also { it.load(basicData) }
val kernalRom = Rom(0xe000, 0xffff).also { it.load(kernalData) }
private val monitor = Monitor(bus, cpu)
private val debugWindow = DebugWindow(this)
private val hostDisplay = MainC64Window(title, chargenData, ram, cpu, cia1)
private val hostDisplay = MainC64Window(title, chargenRom, ram, cpu, cia1)
private var paused = false
init {
@ -49,8 +57,8 @@ class C64Machine(title: String) : IVirtualMachine {
cpu.addBreakpoint(0xffd8, ::breakpointKernelSave) // intercept SAVE subroutine in the kernal
cpu.breakpointForBRK = ::breakpointBRK
bus += basicRom
bus += kernalRom
bus += basicRom // TODO remove this
bus += kernalRom // TODO remove this
bus += vic
bus += cia1
bus += cia2

View File

@ -45,7 +45,7 @@ open class Bus {
open fun read(address: Address): UByte {
memComponents.forEach {
if (address >= it.startAddress && address <= it.endAddress) {
val data = it[address]
val data = it[address - it.startAddress]
require(data in 0..255) { "data at address $address must be a byte 0..255, but is $data" }
return data
}
@ -60,7 +60,8 @@ open class Bus {
open fun write(address: Address, data: UByte) {
require(data in 0..255) { "data written to address $address must be a byte 0..255" }
memComponents.forEach {
if (address >= it.startAddress && address <= it.endAddress) it[address] = data
if (address >= it.startAddress && address <= it.endAddress)
it[address-it.startAddress] = data
}
}

View File

@ -28,8 +28,8 @@ abstract class BusComponent {
* Most I/O components fall into this category.
*/
abstract class MemMappedComponent(val startAddress: Address, val endAddress: Address) : BusComponent() {
abstract operator fun get(address: Address): UByte
abstract operator fun set(address: Address, data: UByte)
abstract operator fun get(offset: Int): UByte
abstract operator fun set(offset: Int, data: UByte)
init {
require(endAddress >= startAddress)
@ -39,7 +39,7 @@ abstract class MemMappedComponent(val startAddress: Address, val endAddress: Add
fun hexDump(from: Address, to: Address, charmapper: ((Short) -> Char)? = null) {
(from..to).chunked(16).forEach {
print("\$${it.first().toString(16).padStart(4, '0')} ")
val bytes = it.map { address -> get(address) }
val bytes = it.map { address -> get(address - startAddress) }
bytes.forEach { byte ->
print(byte.toString(16).padStart(2, '0')+" ")
}

View File

@ -62,8 +62,8 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
host.clearScreen()
}
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> charposX.toShort()
0x01 -> charposY.toShort()
0x02 -> {
@ -87,8 +87,8 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
}
}
override operator fun set(address: Address, data: UByte) {
when (address-startAddress) {
override operator fun set(offset: Int, data: UByte) {
when (offset) {
0x00 -> charposX = data.toInt()
0x01 -> charposY = data.toInt()
0x02 -> {

View File

@ -23,13 +23,12 @@ class Keyboard(startAddress: Address, endAddress: Address, private val host: IHo
override fun clock() {}
override fun reset() {}
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> host.keyboard()?.toShort() ?: 0
else -> 0xff
}
}
override operator fun set(address: Address, data: UByte) { /* read-only device */
}
override operator fun set(offset: Int, data: UByte) { /* read-only device */ }
}

View File

@ -25,8 +25,8 @@ class Mouse(startAddress: Address, endAddress: Address, private val host: IHostI
private var mouse = host.mouse()
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> (mouse.x and 0xff).toShort()
0x01 -> (mouse.x ushr 8).toShort()
0x02 -> (mouse.y and 0xff).toShort()
@ -41,7 +41,7 @@ class Mouse(startAddress: Address, endAddress: Address, private val host: IHostI
}
}
override operator fun set(address: Address, data: UByte) {
if (address-startAddress == 0x05) mouse = host.mouse()
override operator fun set(offset: Int, data: UByte) {
if (offset == 0x05) mouse = host.mouse()
}
}

View File

@ -18,14 +18,14 @@ class ParallelPort(startAddress: Address, endAddress: Address) : MemMappedCompon
override fun clock() {}
override fun reset() {}
override operator fun get(address: Address): UByte {
return if (address == startAddress) dataByte
override operator fun get(offset: Int): UByte {
return if (offset == 0) dataByte
else 0xff
}
override operator fun set(address: Address, data: UByte) {
if (address == startAddress) dataByte = data
else if (address == endAddress) {
override operator fun set(offset: Int, data: UByte) {
if (offset == 0) dataByte = data
else if (offset == 1) {
if ((data.toInt() and 1) == 1) {
val char = dataByte.toChar()
println("PARALLEL WRITE: '$char'")

View File

@ -10,10 +10,10 @@ import java.io.InputStream
class Ram(startAddress: Address, endAddress: Address) : MemoryComponent(startAddress, endAddress) {
override val data = Array<UByte>(endAddress-startAddress+1) { 0 }
override operator fun get(address: Address): UByte = data[address-startAddress]
override operator fun get(offset: Int): UByte = data[offset]
override operator fun set(address: Address, data: UByte) {
this.data[address-startAddress] = data
override operator fun set(offset: Int, data: UByte) {
this.data[offset] = data
}
override fun clock() {}

View File

@ -34,8 +34,8 @@ class RealTimeClock(startAddress: Address, endAddress: Address) : MemMappedCompo
/* never reset */
}
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> {
val year = LocalDate.now().year
(year and 255).toShort()
@ -61,7 +61,5 @@ class RealTimeClock(startAddress: Address, endAddress: Address) : MemMappedCompo
}
}
override operator fun set(address: Address, data: UByte) {
/* real time clock can't be set */
}
override operator fun set(offset: Int, data: UByte) { /* real time clock can't be set */ }
}

View File

@ -12,9 +12,8 @@ class Rom(startAddress: Address, endAddress: Address, initialData: Array<UByte>?
require(endAddress-startAddress+1 == data.size) { "rom address range doesn't match size of data bytes" }
}
override operator fun get(address: Address): UByte = data[address-startAddress]
override operator fun set(address: Address, data: UByte) { /* read-only */
}
override operator fun get(offset: Int): UByte = data[offset]
override operator fun set(offset: Int, data: UByte) { /* read-only */ }
override fun clock() {}
override fun reset() {}

View File

@ -47,8 +47,8 @@ class Timer(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
nmi = false
}
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> {
var data = 0
if (enabled) data = data or 0b00000001
@ -62,8 +62,8 @@ class Timer(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
}
}
override operator fun set(address: Address, data: UByte) {
when (address-startAddress) {
override operator fun set(offset: Int, data: UByte) {
when (offset) {
0x00 -> {
val i = data.toInt()
enabled = (i and 0b00000001) != 0