mirror of
https://github.com/irmen/ksim65.git
synced 2024-06-28 15:29:53 +00:00
now mapped most of the keys of the c64 emulator
This commit is contained in:
parent
19de88be4c
commit
dfec693ba0
|
@ -42,7 +42,7 @@ dependencies {
|
|||
|
||||
application {
|
||||
applicationName = "ksim65vm"
|
||||
mainClassName = "razorvine.examplemachine.MachineMainKt"
|
||||
mainClassName = "razorvine.examplemachines.MachineMainKt"
|
||||
}
|
||||
|
||||
tasks.named<Test>("test") {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package razorvine.c64emu
|
||||
|
||||
import razorvine.ksim65.components.MemoryComponent
|
||||
import razorvine.ksim65.components.UByte
|
||||
import java.awt.*
|
||||
import java.awt.image.BufferedImage
|
||||
import java.awt.event.*
|
||||
|
@ -19,7 +20,7 @@ object ScreenDefs {
|
|||
const val SCREEN_HEIGHT_CHARS = 25
|
||||
const val SCREEN_WIDTH = SCREEN_WIDTH_CHARS * 8
|
||||
const val SCREEN_HEIGHT = SCREEN_HEIGHT_CHARS * 8
|
||||
const val DISPLAY_PIXEL_SCALING: Double = 2.0
|
||||
const val DISPLAY_PIXEL_SCALING: Double = 3.0
|
||||
|
||||
val colorPalette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
|
||||
Color(0x000000), // 0 = black
|
||||
|
@ -130,7 +131,7 @@ private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryCompo
|
|||
|
||||
class MainWindow(title: String, chargenData: ByteArray, val ram: MemoryComponent) : JFrame(title), KeyListener {
|
||||
private val canvas = BitmapScreenPanel(chargenData, ram)
|
||||
private val keyboardBuffer = ArrayDeque<Char>()
|
||||
private val keyboardBuffer = ArrayDeque<KeyEvent>()
|
||||
private var borderTop: JPanel
|
||||
private var borderBottom: JPanel
|
||||
private var borderLeft: JPanel
|
||||
|
@ -210,13 +211,11 @@ class MainWindow(title: String, chargenData: ByteArray, val ram: MemoryComponent
|
|||
var kbbLen = ram[0xc6]
|
||||
while(kbbLen<=10 && keyboardBuffer.isNotEmpty()) {
|
||||
try {
|
||||
val petscii = when(val char = keyboardBuffer.pop()) {
|
||||
'\n' -> 13 // enter
|
||||
'\b' -> 20 // backspace ('delete')
|
||||
else -> Petscii.encodePetscii(char.toString(), true)[0]
|
||||
val petscii = keyEventToPetscii(keyboardBuffer.pop())
|
||||
if(petscii > 0) {
|
||||
ram[0x277 + kbbLen] = petscii
|
||||
kbbLen++
|
||||
}
|
||||
ram[0x277 + kbbLen] = petscii
|
||||
kbbLen++
|
||||
} catch(ccx: CharConversionException) {
|
||||
// ignore character
|
||||
}
|
||||
|
@ -228,14 +227,136 @@ class MainWindow(title: String, chargenData: ByteArray, val ram: MemoryComponent
|
|||
repaintTimer.start()
|
||||
}
|
||||
|
||||
// keyboard events:
|
||||
override fun keyTyped(event: KeyEvent) {
|
||||
// println("KEY TYPED: $event '${event.keyChar}'")
|
||||
keyboardBuffer.add(event.keyChar)
|
||||
while (keyboardBuffer.size > 8)
|
||||
keyboardBuffer.pop()
|
||||
private fun keyEventToPetscii(ke: KeyEvent): UByte {
|
||||
if(ke.isActionKey) {
|
||||
// function keys, cursor keys etc.
|
||||
if(ke.id == KeyEvent.KEY_PRESSED) {
|
||||
return when (ke.keyCode) {
|
||||
KeyEvent.VK_F1 -> 0x85
|
||||
KeyEvent.VK_F2 -> 0x86
|
||||
KeyEvent.VK_F3 -> 0x87
|
||||
KeyEvent.VK_F4 -> 0x88
|
||||
KeyEvent.VK_F5 -> 0x89
|
||||
KeyEvent.VK_F6 -> 0x8a
|
||||
KeyEvent.VK_F7 -> 0x8b
|
||||
KeyEvent.VK_F8 -> 0x8c
|
||||
KeyEvent.VK_UP -> 0x91
|
||||
KeyEvent.VK_DOWN -> 0x11
|
||||
KeyEvent.VK_LEFT -> 0x9d
|
||||
KeyEvent.VK_RIGHT -> 0x1d
|
||||
KeyEvent.VK_HOME -> {
|
||||
if(ke.modifiersEx and KeyEvent.SHIFT_DOWN_MASK != 0)
|
||||
0x93 // clear
|
||||
else
|
||||
0x13 // home
|
||||
}
|
||||
KeyEvent.VK_INSERT -> 0x94 //insert
|
||||
else -> 0 // no mapped key
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(ke.id == KeyEvent.KEY_PRESSED) {
|
||||
return when(ke.keyChar) {
|
||||
'\u001b' -> {
|
||||
if(ke.isShiftDown) 0x83
|
||||
else 0x03
|
||||
} // break
|
||||
'\n' -> 0x0d // enter
|
||||
'\b' -> 0x14 // backspace ('delete')
|
||||
'1' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x90 // black
|
||||
ke.isAltDown -> 0x81 // orange
|
||||
else -> '1'.toShort()
|
||||
}
|
||||
}
|
||||
'2' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x05 // white
|
||||
ke.isAltDown -> 0x95 // brown
|
||||
else -> '2'.toShort()
|
||||
}
|
||||
}
|
||||
'3' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x1c // red
|
||||
ke.isAltDown -> 0x96 // pink
|
||||
else -> '3'.toShort()
|
||||
}
|
||||
}
|
||||
'4' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x9f // cyan
|
||||
ke.isAltDown -> 0x97 // dark grey
|
||||
else -> '4'.toShort()
|
||||
}
|
||||
}
|
||||
'5' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x9c // purple
|
||||
ke.isAltDown -> 0x98 // grey
|
||||
else -> '5'.toShort()
|
||||
}
|
||||
}
|
||||
'6' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x1e // green
|
||||
ke.isAltDown -> 0x99 // light green
|
||||
else -> '6'.toShort()
|
||||
}
|
||||
}
|
||||
'7' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x1f // blue
|
||||
ke.isAltDown -> 0x9a // light blue
|
||||
else -> '7'.toShort()
|
||||
}
|
||||
}
|
||||
'8' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x9e // yellow
|
||||
ke.isAltDown -> 0x9b // light grey
|
||||
else -> '8'.toShort()
|
||||
}
|
||||
}
|
||||
'9' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x12 // reverse on
|
||||
else -> '9'.toShort()
|
||||
}
|
||||
}
|
||||
'0' -> {
|
||||
when {
|
||||
ke.isControlDown -> 0x92 // reverse off
|
||||
else -> '0'.toShort()
|
||||
}
|
||||
}
|
||||
'`' -> 0x5f // left arrow
|
||||
'\\' -> 0x5e // up arrow
|
||||
'|' -> 0x7e // pi
|
||||
'}' -> 0x5c // pound
|
||||
else -> Petscii.encodePetscii(ke.keyChar.toString(), true)[0]
|
||||
}
|
||||
}
|
||||
else if(ke.id == KeyEvent.KEY_RELEASED) {
|
||||
if(ke.keyCode==KeyEvent.VK_SHIFT && ke.modifiersEx and KeyEvent.CTRL_DOWN_MASK != 0) {
|
||||
return 0x0e // lo+up charset
|
||||
}
|
||||
else if(ke.keyCode==KeyEvent.VK_CONTROL && ke.modifiersEx and KeyEvent.SHIFT_DOWN_MASK != 0) {
|
||||
return 0x0e // lo+up charset
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0 // no mapped key
|
||||
}
|
||||
|
||||
override fun keyPressed(event: KeyEvent) {}
|
||||
override fun keyReleased(event: KeyEvent) {}
|
||||
// keyboard events:
|
||||
override fun keyTyped(event: KeyEvent) {}
|
||||
|
||||
override fun keyPressed(event: KeyEvent) {
|
||||
keyboardBuffer += event
|
||||
}
|
||||
override fun keyReleased(event: KeyEvent) {
|
||||
keyboardBuffer += event
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@ 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
|
||||
*/
|
||||
class VicII(startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) {
|
||||
private var ramBuffer = Array<UByte>(endAddress - startAddress + 1) { 0 }
|
||||
private var rasterIrqLine = 0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package razorvine.c64emu
|
||||
|
||||
import razorvine.examplemachine.DebugWindow
|
||||
import razorvine.examplemachines.DebugWindow
|
||||
import kotlin.concurrent.scheduleAtFixedRate
|
||||
import razorvine.ksim65.Bus
|
||||
import razorvine.ksim65.Cpu6502
|
||||
|
@ -30,6 +30,7 @@ class C64Machine(title: String) : IVirtualMachine {
|
|||
|
||||
private val debugWindow = DebugWindow(this)
|
||||
private val hostDisplay = MainWindow(title, chargenData, ram)
|
||||
private var paused = false
|
||||
|
||||
init {
|
||||
hostDisplay.iconImage = ImageIcon(javaClass.getResource("/icon.png")).image
|
||||
|
@ -56,9 +57,13 @@ class C64Machine(title: String) : IVirtualMachine {
|
|||
}
|
||||
}
|
||||
|
||||
override var paused = false
|
||||
|
||||
override fun stepInstruction() {
|
||||
override fun pause(paused: Boolean) {
|
||||
this.paused = paused
|
||||
}
|
||||
|
||||
override fun step() {
|
||||
// step a single full instruction
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
bus.clock()
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
|
@ -70,7 +75,7 @@ class C64Machine(title: String) : IVirtualMachine {
|
|||
timer.scheduleAtFixedRate(1, 1) {
|
||||
if(!paused) {
|
||||
repeat(400) {
|
||||
stepInstruction()
|
||||
step()
|
||||
if(vic.currentRasterLine == 255) {
|
||||
// we force an irq here ourselves rather than fully emulating the VIC-II's raster IRQ
|
||||
// or the CIA timer IRQ/NMI.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package razorvine.examplemachine
|
||||
package razorvine.examplemachines
|
||||
|
||||
import razorvine.ksim65.Bus
|
||||
import razorvine.ksim65.Cpu6502
|
||||
|
@ -225,16 +225,16 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("debugger"), ActionL
|
|||
updateCpu(vm.cpu, vm.bus)
|
||||
}
|
||||
"step" -> {
|
||||
vm.stepInstruction()
|
||||
vm.step()
|
||||
updateCpu(vm.cpu, vm.bus)
|
||||
}
|
||||
"pause" -> {
|
||||
vm.paused = true
|
||||
vm.pause(true)
|
||||
pauseBt.actionCommand = "continue"
|
||||
pauseBt.text = "Cont."
|
||||
}
|
||||
"continue" -> {
|
||||
vm.paused = false
|
||||
vm.pause(false)
|
||||
pauseBt.actionCommand = "pause"
|
||||
pauseBt.text = "Pause"
|
||||
}
|
||||
|
@ -262,11 +262,11 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("debugger"), ActionL
|
|||
|
||||
class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener, IHostInterface {
|
||||
private val canvas = BitmapScreenPanel()
|
||||
val keyboardBuffer = ArrayDeque<Char>()
|
||||
var mousePos = Point(0, 0)
|
||||
var leftButton = false
|
||||
var rightButton = false
|
||||
var middleButton = false
|
||||
private val keyboardBuffer = ArrayDeque<Char>()
|
||||
private var mousePos = Point(0, 0)
|
||||
private var leftButton = false
|
||||
private var rightButton = false
|
||||
private var middleButton = false
|
||||
|
||||
init {
|
||||
val borderWidth = 16
|
|
@ -1,4 +1,4 @@
|
|||
package razorvine.examplemachine
|
||||
package razorvine.examplemachines
|
||||
|
||||
import kotlin.concurrent.scheduleAtFixedRate
|
||||
import razorvine.ksim65.Bus
|
||||
|
@ -23,6 +23,7 @@ class EhBasicMachine(title: String): IVirtualMachine {
|
|||
ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS,
|
||||
ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
|
||||
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
|
||||
private var paused = false
|
||||
|
||||
init {
|
||||
hostDisplay.iconImage = ImageIcon(javaClass.getResource("/icon.png")).image
|
||||
|
@ -38,9 +39,12 @@ class EhBasicMachine(title: String): IVirtualMachine {
|
|||
hostDisplay.start()
|
||||
}
|
||||
|
||||
override var paused = false
|
||||
override fun pause(paused: Boolean) {
|
||||
this.paused = paused
|
||||
}
|
||||
|
||||
override fun stepInstruction() {
|
||||
override fun step() {
|
||||
// step a full single instruction
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
bus.clock()
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
|
@ -51,7 +55,7 @@ class EhBasicMachine(title: String): IVirtualMachine {
|
|||
timer.scheduleAtFixedRate(1, 1) {
|
||||
if(!paused) {
|
||||
repeat(500) {
|
||||
stepInstruction()
|
||||
step()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package razorvine.examplemachine
|
||||
package razorvine.examplemachines
|
||||
|
||||
import kotlin.concurrent.scheduleAtFixedRate
|
||||
import razorvine.ksim65.Bus
|
||||
|
@ -26,6 +26,7 @@ class VirtualMachine(title: String) : IVirtualMachine {
|
|||
ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
|
||||
private val mouse = Mouse(0xd300, 0xd305, hostDisplay)
|
||||
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
|
||||
private var paused = false
|
||||
|
||||
init {
|
||||
hostDisplay.iconImage = ImageIcon(javaClass.getResource("/icon.png")).image
|
||||
|
@ -50,9 +51,12 @@ class VirtualMachine(title: String) : IVirtualMachine {
|
|||
hostDisplay.start()
|
||||
}
|
||||
|
||||
override var paused = false
|
||||
override fun pause(paused: Boolean) {
|
||||
this.paused = paused
|
||||
}
|
||||
|
||||
override fun stepInstruction() {
|
||||
override fun step() {
|
||||
// step a full single instruction
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
bus.clock()
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
|
@ -64,7 +68,7 @@ class VirtualMachine(title: String) : IVirtualMachine {
|
|||
timer.scheduleAtFixedRate(1, 1) {
|
||||
if(!paused) {
|
||||
repeat(50) {
|
||||
stepInstruction()
|
||||
step()
|
||||
}
|
||||
debugWindow.updateCpu(cpu, bus)
|
||||
val duration = System.currentTimeMillis() - startTime
|
|
@ -1,9 +1,9 @@
|
|||
package razorvine.ksim65
|
||||
|
||||
interface IVirtualMachine {
|
||||
fun stepInstruction()
|
||||
fun step()
|
||||
fun pause(paused: Boolean)
|
||||
|
||||
var paused: Boolean
|
||||
val cpu: Cpu6502
|
||||
val bus: Bus
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package razorvine.ksim65.components
|
||||
|
||||
import razorvine.examplemachine.ScreenDefs
|
||||
import razorvine.examplemachines.ScreenDefs
|
||||
import razorvine.ksim65.IHostInterface
|
||||
import kotlin.math.min
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 2.7 KiB |
Loading…
Reference in New Issue
Block a user