mirror of
https://github.com/irmen/ksim65.git
synced 2024-06-01 06:41:34 +00:00
added joystick to C64 emulation (via numpad keys)
This commit is contained in:
parent
99942748f9
commit
7522d3cb3b
BIN
c64testprgs/joytest.prg
Normal file
BIN
c64testprgs/joytest.prg
Normal file
Binary file not shown.
BIN
free-c64-roms/basic
Normal file
BIN
free-c64-roms/basic
Normal file
Binary file not shown.
BIN
free-c64-roms/chargen
Normal file
BIN
free-c64-roms/chargen
Normal file
Binary file not shown.
BIN
free-c64-roms/kernal
Normal file
BIN
free-c64-roms/kernal
Normal file
Binary file not shown.
24
free-c64-roms/readme.txt
Normal file
24
free-c64-roms/readme.txt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
Free/open source roms for the C64
|
||||||
|
|
||||||
|
See https://github.com/MEGA65/open-roms
|
||||||
|
|
||||||
|
The following copyright notices apply to the entirety of this package,
|
||||||
|
including each source file, unless otherwise noted in each file or directory.
|
||||||
|
|
||||||
|
Copyright Paul Gardner-Stephen, 2019.
|
||||||
|
Copyright Roman Standzikowski (FeralChil64), 2019-2020.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,20 @@ import java.awt.event.KeyEvent
|
||||||
/**
|
/**
|
||||||
* Minimal simulation of the MOS 6526 CIA chip.
|
* Minimal simulation of the MOS 6526 CIA chip.
|
||||||
* Depending on what CIA it is (1 or 2), some registers do different things on the C64.
|
* Depending on what CIA it is (1 or 2), some registers do different things on the C64.
|
||||||
* This implementation provides a working keyboard matrix, TOD clock, and the essentials of the timer A and B.
|
* This implementation provides a working keyboard matrix, joystick in port#2 (cia 1),
|
||||||
|
* time of day clock, and the essentials of the timer A and B.
|
||||||
*/
|
*/
|
||||||
class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemMappedComponent(startAddress, endAddress) {
|
class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemMappedComponent(startAddress, endAddress) {
|
||||||
private var ramBuffer = Array<UByte>(endAddress-startAddress+1) { 0 }
|
private var ramBuffer = Array<UByte>(endAddress-startAddress+1) { 0 }
|
||||||
private var regPRA = 0xff
|
private var regPRA = 0xff
|
||||||
|
|
||||||
|
// joystick in port 2 configuration (only works on cia#1)
|
||||||
|
private var joy2up = false
|
||||||
|
private var joy2down = false
|
||||||
|
private var joy2left = false
|
||||||
|
private var joy2right = false
|
||||||
|
private var joy2fire = false
|
||||||
|
|
||||||
class TimeOfDay {
|
class TimeOfDay {
|
||||||
private var updatedAt = 0L
|
private var updatedAt = 0L
|
||||||
private var startedAt = 0L
|
private var startedAt = 0L
|
||||||
|
@ -125,6 +133,11 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
|
||||||
timerAset = 0
|
timerAset = 0
|
||||||
timerBactual = 0
|
timerBactual = 0
|
||||||
timerBset = 0
|
timerBset = 0
|
||||||
|
joy2up = false
|
||||||
|
joy2down = false
|
||||||
|
joy2left = false
|
||||||
|
joy2right = false
|
||||||
|
joy2fire = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override operator fun get(offset: Int): UByte {
|
override operator fun get(offset: Int): UByte {
|
||||||
|
@ -139,9 +152,22 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
|
||||||
}
|
}
|
||||||
|
|
||||||
val register = offset and 15
|
val register = offset and 15
|
||||||
if (number == 1 && register == 0x01) {
|
|
||||||
// register 1 on CIA#1 is the keyboard data port
|
if(number==1) {
|
||||||
|
// first CIA has keyboard matrix
|
||||||
|
if(register==0x00) {
|
||||||
|
// reading $dc00 is joystick in port #2
|
||||||
|
return (0b01100000
|
||||||
|
or (if(joy2up) 0 else 0b00000001)
|
||||||
|
or (if(joy2down) 0 else 0b00000010)
|
||||||
|
or (if(joy2left) 0 else 0b00000100)
|
||||||
|
or (if(joy2right) 0 else 0b00001000)
|
||||||
|
or (if(joy2fire) 0 else 0b00010000)).toShort()
|
||||||
|
} else if(register==0x01) {
|
||||||
|
// register 1 on CIA#1 is the keyboard data port (and joystick #1...)
|
||||||
// if bit is cleared in PRA, contains keys pressed in that column of the matrix
|
// if bit is cleared in PRA, contains keys pressed in that column of the matrix
|
||||||
|
// NOTE: we do not emulate a joystick in port #1 as this conflicts with the keyboard.
|
||||||
|
// just use the joystick in port #2 for now...
|
||||||
return when (regPRA) {
|
return when (regPRA) {
|
||||||
0b00000000 -> {
|
0b00000000 -> {
|
||||||
// check if any keys are pressed at all (by checking all columns at once)
|
// check if any keys are pressed at all (by checking all columns at once)
|
||||||
|
@ -203,7 +229,8 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
|
||||||
0xff
|
0xff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else ramBuffer[register]
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return when (register) {
|
return when (register) {
|
||||||
0x04 -> (timerAactual and 0xff).toShort()
|
0x04 -> (timerAactual and 0xff).toShort()
|
||||||
|
@ -224,19 +251,6 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toBCD(data: Int): UByte {
|
|
||||||
val tens = data/10
|
|
||||||
val ones = data-tens*10
|
|
||||||
return ((tens shl 4) or ones).toShort()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fromBCD(bcd: UByte): Int {
|
|
||||||
val ibcd = bcd.toInt()
|
|
||||||
val tens = ibcd ushr 4
|
|
||||||
val ones = ibcd and 0x0f
|
|
||||||
return tens*10+ones
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun set(offset: Int, data: UByte) {
|
override operator fun set(offset: Int, data: UByte) {
|
||||||
val register = offset and 15
|
val register = offset and 15
|
||||||
if (number == 1 && register == 0x00) {
|
if (number == 1 && register == 0x00) {
|
||||||
|
@ -296,6 +310,19 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun toBCD(data: Int): UByte {
|
||||||
|
val tens = data/10
|
||||||
|
val ones = data-tens*10
|
||||||
|
return ((tens shl 4) or ones).toShort()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fromBCD(bcd: UByte): Int {
|
||||||
|
val ibcd = bcd.toInt()
|
||||||
|
val tens = ibcd ushr 4
|
||||||
|
val ones = ibcd and 0x0f
|
||||||
|
return tens*10+ones
|
||||||
|
}
|
||||||
|
|
||||||
fun hostKeyPressed(event: KeyEvent) {
|
fun hostKeyPressed(event: KeyEvent) {
|
||||||
val rightSide = event.keyLocation == KeyEvent.KEY_LOCATION_RIGHT
|
val rightSide = event.keyLocation == KeyEvent.KEY_LOCATION_RIGHT
|
||||||
val numpad = event.keyLocation == KeyEvent.KEY_LOCATION_NUMPAD
|
val numpad = event.keyLocation == KeyEvent.KEY_LOCATION_NUMPAD
|
||||||
|
@ -374,4 +401,15 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setJoystick2(up: Boolean, down: Boolean, left: Boolean, right: Boolean, fire: Boolean) {
|
||||||
|
if(number!=1)
|
||||||
|
throw NotImplementedError("joystick port 2 is connected to cia#1")
|
||||||
|
|
||||||
|
joy2up = up
|
||||||
|
joy2down = down
|
||||||
|
joy2left = left
|
||||||
|
joy2right = right
|
||||||
|
joy2fire = fire
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,16 +82,50 @@ class MainC64Window(title: String, chargen: Rom, val ram: MemoryComponent, val c
|
||||||
// keyboard events:
|
// keyboard events:
|
||||||
override fun keyTyped(event: KeyEvent) {}
|
override fun keyTyped(event: KeyEvent) {}
|
||||||
|
|
||||||
|
private var joy2up = false
|
||||||
|
private var joy2down = false
|
||||||
|
private var joy2left = false
|
||||||
|
private var joy2right = false
|
||||||
|
private var joy2fire = false
|
||||||
|
|
||||||
override fun keyPressed(event: KeyEvent) {
|
override fun keyPressed(event: KeyEvent) {
|
||||||
// '\' is mapped as RESTORE, this causes a NMI on the cpu
|
// '\' is mapped as RESTORE, this causes a NMI on the cpu
|
||||||
if (event.keyChar == '\\') {
|
if (event.keyChar == '\\') {
|
||||||
cpu.nmiAsserted = true
|
cpu.nmiAsserted = true
|
||||||
|
} else {
|
||||||
|
if(event.keyLocation==KeyEvent.KEY_LOCATION_NUMPAD) {
|
||||||
|
// numpad is joystick #2
|
||||||
|
if (event.keyChar in "789") joy2up = true
|
||||||
|
if (event.keyChar in "123") joy2down = true
|
||||||
|
if (event.keyChar in "741") joy2left = true
|
||||||
|
if (event.keyChar in "963") joy2right = true
|
||||||
|
if (event.keyChar in "05\n") joy2fire = true
|
||||||
|
keypressCia.setJoystick2(joy2up, joy2down, joy2left, joy2right, joy2fire)
|
||||||
} else {
|
} else {
|
||||||
keypressCia.hostKeyPressed(event)
|
keypressCia.hostKeyPressed(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun keyReleased(event: KeyEvent) {
|
override fun keyReleased(event: KeyEvent) {
|
||||||
|
if(event.keyLocation==KeyEvent.KEY_LOCATION_NUMPAD) {
|
||||||
|
// numpad is joystick #2
|
||||||
|
if (event.keyChar in "789") joy2up = false
|
||||||
|
if (event.keyChar in "123") joy2down = false
|
||||||
|
if (event.keyChar in "741") joy2left = false
|
||||||
|
if (event.keyChar in "963") joy2right = false
|
||||||
|
if (event.keyChar in "05\n") joy2fire = false
|
||||||
|
keypressCia.setJoystick2(joy2up, joy2down, joy2left, joy2right, joy2fire)
|
||||||
|
} else {
|
||||||
keypressCia.hostKeyPressed(event)
|
keypressCia.hostKeyPressed(event)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
joy2up = false
|
||||||
|
joy2down = false
|
||||||
|
joy2left = false
|
||||||
|
joy2right = false
|
||||||
|
joy2fire = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,11 @@ class C64Machine(title: String) : IVirtualMachine {
|
||||||
while (cpu.instrCycles > 0) bus.clock()
|
while (cpu.instrCycles > 0) bus.clock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
bus.reset()
|
||||||
|
hostDisplay.reset()
|
||||||
|
}
|
||||||
|
|
||||||
override fun executeMonitorCommand(command: String) = monitor.command(command)
|
override fun executeMonitorCommand(command: String) = monitor.command(command)
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
|
|
|
@ -182,6 +182,7 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
|
||||||
|
|
||||||
}
|
}
|
||||||
"reset" -> {
|
"reset" -> {
|
||||||
|
vm.reset()
|
||||||
vm.bus.reset()
|
vm.bus.reset()
|
||||||
updateCpu(vm.cpu, vm.bus)
|
updateCpu(vm.cpu, vm.bus)
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,4 +242,8 @@ class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener
|
||||||
else keyboardBuffer.pop()
|
else keyboardBuffer.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
// when the reset button is pressed
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,11 @@ class VirtualMachine(title: String) : IVirtualMachine {
|
||||||
while (cpu.instrCycles > 0) bus.clock()
|
while (cpu.instrCycles > 0) bus.clock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
bus.reset()
|
||||||
|
hostDisplay.reset()
|
||||||
|
}
|
||||||
|
|
||||||
override fun executeMonitorCommand(command: String) = monitor.command(command)
|
override fun executeMonitorCommand(command: String) = monitor.command(command)
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.io.File
|
||||||
interface IVirtualMachine {
|
interface IVirtualMachine {
|
||||||
fun step()
|
fun step()
|
||||||
fun pause(paused: Boolean)
|
fun pause(paused: Boolean)
|
||||||
|
fun reset()
|
||||||
fun getZeroAndStackPages(): Array<UByte>
|
fun getZeroAndStackPages(): Array<UByte>
|
||||||
fun loadFileInRam(file: File, loadAddress: Address?)
|
fun loadFileInRam(file: File, loadAddress: Address?)
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
version=1.8
|
version=1.9-dev
|
||||||
|
|
Loading…
Reference in New Issue
Block a user