From 88c1688a416199fb393de925928c7dc492abf482 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 25 Sep 2019 22:58:58 +0200 Subject: [PATCH] Custom c64 key mapping to make typing on a modern keyboard tolerable. Connected Restore key (backslash) to NMI. --- .idea/gradle.xml | 1 + src/main/kotlin/razorvine/c64emu/Cia.kt | 343 ++++++++++++++------ src/main/kotlin/razorvine/c64emu/GUI.kt | 42 ++- src/main/kotlin/razorvine/c64emu/c64Main.kt | 2 +- 4 files changed, 274 insertions(+), 114 deletions(-) diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 37e5426..6c402ee 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -15,6 +15,7 @@ + diff --git a/src/main/kotlin/razorvine/c64emu/Cia.kt b/src/main/kotlin/razorvine/c64emu/Cia.kt index b65f0eb..530a354 100644 --- a/src/main/kotlin/razorvine/c64emu/Cia.kt +++ b/src/main/kotlin/razorvine/c64emu/Cia.kt @@ -9,11 +9,13 @@ import java.awt.event.KeyEvent * 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. */ -class Cia(val number: Int, startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) { +class Cia(val number: Int, startAddress: Address, endAddress: Address) : MemMappedComponent(startAddress, endAddress) { private var ramBuffer = Array(endAddress - startAddress + 1) { 0x00 } private var pra = 0xff - private val hostKeyPresses = mutableSetOf() + private data class HostKeyPress(val code: Int, val rightSide: Boolean, val numpad: Boolean) + + private val hostKeyPresses = mutableSetOf() init { require(endAddress - startAddress + 1 == 256) { "cia requires exactly 256 memory bytes (16*16 mirrored)" } @@ -24,134 +26,165 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address): MemMappe } override fun reset() { + hostKeyPresses.clear() // TODO: reset TOD timer, timer A and B } override fun get(address: Address): UByte { + fun scanColumn(keys: List): UByte { + var bits = 0b10000000 + var presses = 0 + for (key in keys) { + if (key in hostKeyPresses) presses = presses or bits + bits = bits ushr 1 + } + return (presses.inv() and 255).toShort() + } + val register = (address - startAddress) and 15 - if(number==1) { + if (number == 1) { return if (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 - // TODO tweak the keyboard mapping so that keys like '=' can be pressed, - // RESTORE works (this is not a normal key but connected to the cpu's NMI line), - // Cursor up/down/left/right all work and left/right shift are different. - when(pra) { + when (pra) { 0b00000000 -> { // check if any keys are pressed at all (by checking all columns at once) - if(hostKeyPresses.isEmpty()) 0xff.toShort() else 0x00.toShort() + if (hostKeyPresses.isEmpty()) 0xff.toShort() else 0x00.toShort() } 0b11111110 -> { // read column 0 - val presses = - (if (KeyEvent.VK_DOWN in hostKeyPresses) 0b10000000 else 0) or - (if (KeyEvent.VK_F5 in hostKeyPresses) 0b01000000 else 0) or - (if (KeyEvent.VK_F3 in hostKeyPresses) 0b00100000 else 0) or - (if (KeyEvent.VK_F1 in hostKeyPresses) 0b00010000 else 0) or - (if (KeyEvent.VK_F7 in hostKeyPresses) 0b00001000 else 0) or - (if (KeyEvent.VK_RIGHT in hostKeyPresses) 0b00000100 else 0) or - (if (KeyEvent.VK_ENTER in hostKeyPresses) 0b00000010 else 0) or - (if (KeyEvent.VK_BACK_SPACE in hostKeyPresses) 0b00000001 else 0) - (presses.inv() and 255).toShort() + scanColumn( + listOf( + HostKeyPress(KeyEvent.VK_DOWN, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_F5, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_F3, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_F1, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_F7, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_RIGHT, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_ENTER, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_BACK_SPACE, rightSide = false, numpad = false) + ) + ) } 0b11111101 -> { // read column 1 - val presses = - (if(KeyEvent.VK_SHIFT in hostKeyPresses) 0b10000000 else 0) or // TODO make it LEFT shift only - (if(KeyEvent.VK_E in hostKeyPresses) 0b01000000 else 0) or - (if(KeyEvent.VK_S in hostKeyPresses) 0b00100000 else 0) or - (if(KeyEvent.VK_Z in hostKeyPresses) 0b00010000 else 0) or - (if(KeyEvent.VK_4 in hostKeyPresses) 0b00001000 else 0) or - (if(KeyEvent.VK_A in hostKeyPresses) 0b00000100 else 0) or - (if(KeyEvent.VK_W in hostKeyPresses) 0b00000010 else 0) or - (if(KeyEvent.VK_3 in hostKeyPresses) 0b00000001 else 0) - (presses.inv() and 255).toShort() + scanColumn( + listOf( + HostKeyPress(KeyEvent.VK_SHIFT, rightSide = false, numpad = false), // left shift + HostKeyPress(KeyEvent.VK_E, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_S, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_Z, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_4, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_A, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_W, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_3, rightSide = false, numpad = false) + ) + ) } 0b11111011 -> { // read column 2 - val presses = - (if (KeyEvent.VK_X in hostKeyPresses) 0b10000000 else 0) or - (if (KeyEvent.VK_T in hostKeyPresses) 0b01000000 else 0) or - (if (KeyEvent.VK_F in hostKeyPresses) 0b00100000 else 0) or - (if (KeyEvent.VK_C in hostKeyPresses) 0b00010000 else 0) or - (if (KeyEvent.VK_6 in hostKeyPresses) 0b00001000 else 0) or - (if (KeyEvent.VK_D in hostKeyPresses) 0b00000100 else 0) or - (if (KeyEvent.VK_R in hostKeyPresses) 0b00000010 else 0) or - (if (KeyEvent.VK_5 in hostKeyPresses) 0b00000001 else 0) - (presses.inv() and 255).toShort() + scanColumn( + listOf( + HostKeyPress(KeyEvent.VK_X, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_T, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_F, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_C, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_6, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_D, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_R, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_5, rightSide = false, numpad = false) + ) + ) } 0b11110111 -> { // read column 3 - val presses = - (if (KeyEvent.VK_V in hostKeyPresses) 0b10000000 else 0) or - (if (KeyEvent.VK_U in hostKeyPresses) 0b01000000 else 0) or - (if (KeyEvent.VK_H in hostKeyPresses) 0b00100000 else 0) or - (if (KeyEvent.VK_B in hostKeyPresses) 0b00010000 else 0) or - (if (KeyEvent.VK_8 in hostKeyPresses) 0b00001000 else 0) or - (if (KeyEvent.VK_G in hostKeyPresses) 0b00000100 else 0) or - (if (KeyEvent.VK_Y in hostKeyPresses) 0b00000010 else 0) or - (if (KeyEvent.VK_7 in hostKeyPresses) 0b00000001 else 0) - (presses.inv() and 255).toShort() + scanColumn( + listOf( + HostKeyPress(KeyEvent.VK_V, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_U, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_H, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_B, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_8, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_G, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_Y, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_7, rightSide = false, numpad = false) + ) + ) } 0b11101111 -> { // read column 4 - val presses = - (if (KeyEvent.VK_N in hostKeyPresses) 0b10000000 else 0) or - (if (KeyEvent.VK_O in hostKeyPresses) 0b01000000 else 0) or - (if (KeyEvent.VK_K in hostKeyPresses) 0b00100000 else 0) or - (if (KeyEvent.VK_M in hostKeyPresses) 0b00010000 else 0) or - (if (KeyEvent.VK_0 in hostKeyPresses) 0b00001000 else 0) or - (if (KeyEvent.VK_J in hostKeyPresses) 0b00000100 else 0) or - (if (KeyEvent.VK_I in hostKeyPresses) 0b00000010 else 0) or - (if (KeyEvent.VK_9 in hostKeyPresses) 0b00000001 else 0) - (presses.inv() and 255).toShort() + scanColumn( + listOf( + HostKeyPress(KeyEvent.VK_N, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_O, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_K, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_M, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_0, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_J, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_I, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_9, rightSide = false, numpad = false) + ) + ) } 0b11011111 -> { // read column 5 - val presses = - (if (KeyEvent.VK_COMMA in hostKeyPresses) 0b10000000 else 0) or - (if (KeyEvent.VK_OPEN_BRACKET in hostKeyPresses) 0b01000000 else 0) or // '[' = @ - (if (KeyEvent.VK_SEMICOLON in hostKeyPresses) 0b00100000 else 0) or // ';' -> : - (if (KeyEvent.VK_PERIOD in hostKeyPresses) 0b00010000 else 0) or - (if (KeyEvent.VK_MINUS in hostKeyPresses) 0b00001000 else 0) or - (if (KeyEvent.VK_L in hostKeyPresses) 0b00000100 else 0) or - (if (KeyEvent.VK_P in hostKeyPresses) 0b00000010 else 0) or - (if (KeyEvent.VK_PLUS in hostKeyPresses) 0b00000001 else 0) - (presses.inv() and 255).toShort() + scanColumn( + listOf( + HostKeyPress(KeyEvent.VK_COMMA, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_AT, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_COLON, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_PERIOD, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_MINUS, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_L, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_P, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_PLUS, rightSide = false, numpad = false) + ) + ) } 0b10111111 -> { // read column 6 - val presses = - (if (KeyEvent.VK_SLASH in hostKeyPresses) 0b10000000 else 0) or - (if (KeyEvent.VK_BACK_SLASH in hostKeyPresses) 0b01000000 else 0) or // '\' -> up arrow - (if (KeyEvent.VK_EQUALS in hostKeyPresses) 0b00100000 else 0) or - (if (KeyEvent.VK_SHIFT in hostKeyPresses) 0b00010000 else 0) or // TODO RIGHT shift only - (if (KeyEvent.VK_HOME in hostKeyPresses) 0b00001000 else 0) or - (if (KeyEvent.VK_QUOTE in hostKeyPresses) 0b00000100 else 0) or // ' -> ; - (if (KeyEvent.VK_CLOSE_BRACKET in hostKeyPresses) 0b00000010 else 0) or // ']' = * - (if (KeyEvent.VK_END in hostKeyPresses) 0b00000001 else 0) // END -> pound key - (presses.inv() and 255).toShort() + scanColumn( + listOf( + HostKeyPress(KeyEvent.VK_SLASH, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_CIRCUMFLEX, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_EQUALS, rightSide = false, numpad = false), + HostKeyPress( + KeyEvent.VK_SHIFT, + rightSide = true, + numpad = false + ), // right shift + HostKeyPress(KeyEvent.VK_HOME, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_SEMICOLON, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_ASTERISK, rightSide = false, numpad = false), + HostKeyPress( + KeyEvent.VK_DEAD_TILDE, + rightSide = false, + numpad = false + ) // pound sign + ) + ) } 0b01111111 -> { // read column 7 - val presses = - (if (KeyEvent.VK_ESCAPE in hostKeyPresses) 0b10000000 else 0) or // esc -> STOP - (if (KeyEvent.VK_Q in hostKeyPresses) 0b01000000 else 0) or - (if (KeyEvent.VK_ALT in hostKeyPresses) 0b00100000 else 0) or // alt -> Commodore - (if (KeyEvent.VK_SPACE in hostKeyPresses) 0b00010000 else 0) or - (if (KeyEvent.VK_2 in hostKeyPresses) 0b00001000 else 0) or - (if (KeyEvent.VK_CONTROL in hostKeyPresses) 0b00000100 else 0) or - (if (KeyEvent.VK_BACK_QUOTE in hostKeyPresses) 0b00000010 else 0) or // '`' -> left arrow - (if (KeyEvent.VK_1 in hostKeyPresses) 0b00000001 else 0) - (presses.inv() and 255).toShort() + scanColumn( + listOf( + HostKeyPress(KeyEvent.VK_ESCAPE, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_Q, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_ALT, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_SPACE, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_2, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_CONTROL, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_BACK_QUOTE, rightSide = false, numpad = false), + HostKeyPress(KeyEvent.VK_1, rightSide = false, numpad = false) + ) + ) } - else -> { + else -> { // invalid column selection 0xff } } - } - else ramBuffer[register] + } else ramBuffer[register] } // CIA #2 is not emulated yet @@ -161,7 +194,7 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address): MemMappe override fun set(address: Address, data: UByte) { val register = (address - startAddress) and 15 ramBuffer[register] = data - if(number==1) { + if (number == 1) { when (register) { 0x00 -> { // PRA data port A (select keyboard matrix column) @@ -173,9 +206,127 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address): MemMappe } fun hostKeyPressed(event: KeyEvent) { - if(event.id==KeyEvent.KEY_PRESSED) - hostKeyPresses.add(event.keyCode) - else if(event.id==KeyEvent.KEY_RELEASED) - hostKeyPresses.remove(event.keyCode) + val rightSide = event.keyLocation == KeyEvent.KEY_LOCATION_RIGHT + val numpad = event.keyLocation == KeyEvent.KEY_LOCATION_NUMPAD + val shift = HostKeyPress(KeyEvent.VK_SHIFT, rightSide = true, numpad = false) + + fun register(eventId: Int, vararg keys: HostKeyPress) { + if (eventId == KeyEvent.KEY_PRESSED) keys.forEach { hostKeyPresses.add(it) } + else keys.forEach { hostKeyPresses.remove(it) } + } + + fun unregister(keyCode: Int) { + hostKeyPresses.removeAll { it.code == keyCode } + } + + // to avoid some 'stuck' keys, if we receive a shift/control/alt RELEASE, we wipe the keyboard buffer + // (this can happen becase we're changing the keycode for some pressed keys below, + // and a released key doesn't always match the pressed keycode anymore then) + if (event.id == KeyEvent.KEY_RELEASED && event.keyCode in listOf( + KeyEvent.VK_SHIFT, + KeyEvent.VK_CONTROL, + KeyEvent.VK_ALT, + KeyEvent.VK_ALT_GRAPH + ) + ) hostKeyPresses.clear() + + // try to remap the keys a bit so a modern PC keyboard maps better to the keys of the C64 + when { + event.keyChar == '@' -> { + unregister(KeyEvent.VK_SHIFT) + register(event.id, HostKeyPress(KeyEvent.VK_AT, rightSide = false, numpad = false)) + } + event.keyChar == '^' -> { + unregister(KeyEvent.VK_SHIFT) + register(event.id, HostKeyPress(KeyEvent.VK_CIRCUMFLEX, rightSide = false, numpad = false)) + } + event.keyChar == '&' -> { + register(event.id, shift, HostKeyPress(KeyEvent.VK_6, rightSide = false, numpad = false)) + } + event.keyChar == '*' -> { + unregister(KeyEvent.VK_SHIFT) + register(event.id, HostKeyPress(KeyEvent.VK_ASTERISK, rightSide = false, numpad = false)) + } + event.keyChar == '(' -> { + register(event.id, shift, HostKeyPress(KeyEvent.VK_8, rightSide = false, numpad = false)) + } + event.keyChar == ')' -> { + register(event.id, shift, HostKeyPress(KeyEvent.VK_9, rightSide = false, numpad = false)) + } + event.keyChar == '[' -> { + register(event.id, shift, HostKeyPress(KeyEvent.VK_COLON, rightSide = false, numpad = false)) + } + event.keyChar == ']' -> { + register(event.id, shift, HostKeyPress(KeyEvent.VK_SEMICOLON, rightSide = false, numpad = false)) + } + event.keyChar == '+' -> { + unregister(KeyEvent.VK_SHIFT) + register(event.id, HostKeyPress(KeyEvent.VK_PLUS, rightSide = false, numpad = false)) + } + event.keyChar == '"' -> { + register(event.id, HostKeyPress(KeyEvent.VK_2, rightSide = false, numpad = false)) + } + event.keyChar == ':' -> { + unregister(KeyEvent.VK_SHIFT) + register(event.id, HostKeyPress(KeyEvent.VK_COLON, rightSide = false, numpad = false)) + } + event.keyChar == '~' -> { + unregister(KeyEvent.VK_SHIFT) + register(event.id, HostKeyPress(KeyEvent.VK_DEAD_TILDE, rightSide = false, numpad = false)) + } + event.keyChar == '\'' -> { + register(event.id, shift, HostKeyPress(KeyEvent.VK_7, rightSide = false, numpad = false)) + } + else -> when (event.keyCode) { + KeyEvent.VK_CONTROL, KeyEvent.VK_TAB -> { + // both controls and the tab key map to the 'single left control' + register(event.id, HostKeyPress(KeyEvent.VK_CONTROL, rightSide = false, numpad = false)) + } + KeyEvent.VK_ALT, KeyEvent.VK_ALT_GRAPH -> { + // both alts map to the 'commodore key' (same left alt) + register(event.id, HostKeyPress(KeyEvent.VK_ALT, rightSide = false, numpad = false)) + } + KeyEvent.VK_F2 -> { + // F2 = shift+F1 + val func = HostKeyPress(KeyEvent.VK_F1, rightSide = false, numpad = false) + register(event.id, shift, func) + } + KeyEvent.VK_F4 -> { + // F4 = shift+F3 + val func = HostKeyPress(KeyEvent.VK_F3, rightSide = false, numpad = false) + register(event.id, shift, func) + } + KeyEvent.VK_F6 -> { + // F6 = shift+F5 + val func = HostKeyPress(KeyEvent.VK_F5, rightSide = false, numpad = false) + register(event.id, shift, func) + } + KeyEvent.VK_F8 -> { + // F8 = shift+F7 + val func = HostKeyPress(KeyEvent.VK_F7, rightSide = false, numpad = false) + register(event.id, shift, func) + } + KeyEvent.VK_INSERT -> { + // insert = shift+backspace(del) + val backspace = HostKeyPress(KeyEvent.VK_BACK_SPACE, rightSide = false, numpad = false) + register(event.id, shift, backspace) + } + KeyEvent.VK_UP -> { + // up = shift+down + val cursor = HostKeyPress(KeyEvent.VK_DOWN, rightSide = false, numpad = false) + register(event.id, shift, cursor) + } + KeyEvent.VK_LEFT -> { + // left = shift+right + val cursor = HostKeyPress(KeyEvent.VK_RIGHT, rightSide = false, numpad = false) + register(event.id, shift, cursor) + } + else -> { + // just map the key as usual + val hostkey = HostKeyPress(event.keyCode, rightSide, numpad) + register(event.id, hostkey) + } + } + } } } diff --git a/src/main/kotlin/razorvine/c64emu/GUI.kt b/src/main/kotlin/razorvine/c64emu/GUI.kt index f27b415..c62dd9f 100644 --- a/src/main/kotlin/razorvine/c64emu/GUI.kt +++ b/src/main/kotlin/razorvine/c64emu/GUI.kt @@ -1,5 +1,6 @@ package razorvine.c64emu +import razorvine.ksim65.Cpu6502 import razorvine.ksim65.components.MemoryComponent import java.awt.* import java.awt.image.BufferedImage @@ -60,13 +61,13 @@ private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryCompo private fun loadCharacters(shifted: Boolean): Array { val chars = Array(256) { BufferedImage(8, 8, BufferedImage.TYPE_BYTE_BINARY) } - val offset = if(shifted) 256*8 else 0 + val offset = if (shifted) 256 * 8 else 0 // val color = ScreenDefs.colorPalette[14].rgb - for(char in 0..255) { - for(line in 0..7) { - val charbyte = chargenData[offset + char*8 + line].toInt() - for(x in 0..7) { - if(charbyte and (0b10000000 ushr x) !=0 ) + for (char in 0..255) { + for (line in 0..7) { + val charbyte = chargenData[offset + char * 8 + line].toInt() + for (x in 0..7) { + if (charbyte and (0b10000000 ushr x) != 0) chars[char].setRGB(x, line, 0xffffff) } } @@ -92,10 +93,10 @@ private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryCompo val shifted = (ram[0xd018].toInt() and 0b00000010) != 0 g2d.background = ScreenDefs.colorPalette[ram[0xd021].toInt() and 15] g2d.clearRect(0, 0, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT) - for(y in 0 until ScreenDefs.SCREEN_HEIGHT_CHARS) { - for(x in 0 until ScreenDefs.SCREEN_WIDTH_CHARS) { - val char = ram[screen + x + y*ScreenDefs.SCREEN_WIDTH_CHARS].toInt() - val color = ram[colors + x + y*ScreenDefs.SCREEN_WIDTH_CHARS].toInt() + for (y in 0 until ScreenDefs.SCREEN_HEIGHT_CHARS) { + for (x in 0 until ScreenDefs.SCREEN_WIDTH_CHARS) { + val char = ram[screen + x + y * ScreenDefs.SCREEN_WIDTH_CHARS].toInt() + val color = ram[colors + x + y * ScreenDefs.SCREEN_WIDTH_CHARS].toInt() drawColoredChar(x, y, char, color and 15, shifted) } } @@ -105,18 +106,18 @@ private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryCompo private fun drawColoredChar(x: Int, y: Int, char: Int, color: Int, shifted: Boolean) { var cached = coloredCharacters[Triple(char, color, shifted)] - if(cached==null) { - cached = if(shifted) shiftedCharacters[char] else normalCharacters[char] + if (cached == null) { + cached = if (shifted) shiftedCharacters[char] else normalCharacters[char] val colored = g2d.deviceConfiguration.createCompatibleImage(8, 8, BufferedImage.BITMASK) val sourceRaster = cached.raster val coloredRaster = colored.raster val pixelArray = IntArray(4) val javaColor = ScreenDefs.colorPalette[color] val coloredPixel = listOf(javaColor.red, javaColor.green, javaColor.blue, javaColor.alpha).toIntArray() - for(pixelY in 0..7) { - for(pixelX in 0..7) { + for (pixelY in 0..7) { + for (pixelX in 0..7) { val source = sourceRaster.getPixel(pixelX, pixelY, pixelArray) - if(source[0]!=0) { + if (source[0] != 0) { coloredRaster.setPixel(pixelX, pixelY, coloredPixel) } } @@ -132,6 +133,7 @@ class MainC64Window( title: String, chargenData: ByteArray, val ram: MemoryComponent, + val cpu: Cpu6502, val keypressCia: Cia ) : JFrame(title), KeyListener { private val canvas = BitmapScreenPanel(chargenData, ram) @@ -195,7 +197,7 @@ class MainC64Window( addKeyListener(this) pack() setLocationRelativeTo(null) - location = Point(location.x/2, location.y) + location = Point(location.x / 2, location.y) setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, mutableSetOf()) setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, mutableSetOf()) requestFocusInWindow() @@ -218,8 +220,14 @@ class MainC64Window( override fun keyTyped(event: KeyEvent) {} override fun keyPressed(event: KeyEvent) { - keypressCia.hostKeyPressed(event) + // '\' is mapped as RESTORE, this causes a NMI on the cpu + if (event.keyChar == '\\') { + cpu.nmi() + } else { + keypressCia.hostKeyPressed(event) + } } + override fun keyReleased(event: KeyEvent) { keypressCia.hostKeyPressed(event) } diff --git a/src/main/kotlin/razorvine/c64emu/c64Main.kt b/src/main/kotlin/razorvine/c64emu/c64Main.kt index 61cea8a..4044296 100644 --- a/src/main/kotlin/razorvine/c64emu/c64Main.kt +++ b/src/main/kotlin/razorvine/c64emu/c64Main.kt @@ -32,7 +32,7 @@ class C64Machine(title: String) : IVirtualMachine { // TODO: implement something so that RND(0) actually works in basic. (cia timer?) private val debugWindow = DebugWindow(this) - private val hostDisplay = MainC64Window(title, chargenData, ram, cia1) + private val hostDisplay = MainC64Window(title, chargenData, ram, cpu, cia1) private var paused = false init {