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:
parent
b4a6709646
commit
81ae12b809
@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 -> {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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')+" ")
|
||||
}
|
||||
|
@ -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 -> {
|
||||
|
@ -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 */ }
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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'")
|
||||
|
@ -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() {}
|
||||
|
@ -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 */ }
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user