1
0
mirror of https://github.com/irmen/ksim65.git synced 2024-06-01 06:41:34 +00:00

fixed VIC memory banking, bitmap mode

This commit is contained in:
Irmen de Jong 2019-10-11 22:50:55 +02:00
parent 31c50991c1
commit 8a2212e34f
4 changed files with 281 additions and 199 deletions

View File

@ -6,10 +6,7 @@ import razorvine.ksim65.components.UByte
import java.awt.*
import java.awt.event.KeyEvent
import java.awt.event.KeyListener
import java.awt.image.BufferedImage
import java.awt.image.DataBufferInt
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.Timer
@ -52,167 +49,6 @@ object ScreenDefs {
val colorPalette = Palette()
}
private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryComponent) : JPanel() {
private val fullscreenImage: BufferedImage
private val fullscreenG2d: Graphics2D
private val normalCharacters = loadCharacters(false)
private val shiftedCharacters = loadCharacters(true)
init {
val ge = GraphicsEnvironment.getLocalGraphicsEnvironment()
val gd = ge.defaultScreenDevice.defaultConfiguration
fullscreenImage = gd.createCompatibleImage(ScreenDefs.SCREEN_WIDTH + 2*ScreenDefs.BORDER_SIZE,
ScreenDefs.SCREEN_HEIGHT + 2*ScreenDefs.BORDER_SIZE, Transparency.OPAQUE)
fullscreenImage.accelerationPriority = 1.0f
fullscreenG2d = fullscreenImage.graphics as Graphics2D
val size = Dimension(
fullscreenImage.width * ScreenDefs.DISPLAY_PIXEL_SCALING.toInt(),
fullscreenImage.height*ScreenDefs.DISPLAY_PIXEL_SCALING.toInt()
)
minimumSize = size
maximumSize = size
preferredSize = size
isFocusable = true
isDoubleBuffered = false
requestFocusInWindow()
}
private fun loadCharacters(shifted: Boolean): Array<BufferedImage> {
val chars = Array(256) { BufferedImage(8, 8, BufferedImage.TYPE_BYTE_BINARY).also { it.accelerationPriority=1.0f } }
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()
for (x in 0..7) {
if (charbyte and (0b10000000 ushr x) != 0)
chars[char].setRGB(x, line, 0xffffff)
}
}
}
return chars
}
override fun paint(graphics: Graphics) {
val windowG2d = graphics as Graphics2D
val vicSCROLY = ram[0xd011].toInt()
val vicVMCSB = ram[0xd018].toInt()
if(vicSCROLY and 0b10000 == 0) {
// screen blanked, only display border
fullscreenG2d.background = ScreenDefs.colorPalette[ram[0xd020]]
fullscreenG2d.clearRect(
0, 0,
ScreenDefs.SCREEN_WIDTH + 2 * ScreenDefs.BORDER_SIZE, ScreenDefs.SCREEN_HEIGHT+ 2*ScreenDefs.BORDER_SIZE)
} else {
// draw the screen border
fullscreenG2d.background = ScreenDefs.colorPalette[ram[0xd020]]
fullscreenG2d.clearRect(0, 0, ScreenDefs.SCREEN_WIDTH + 2 * ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE)
fullscreenG2d.clearRect(
0, ScreenDefs.SCREEN_HEIGHT + ScreenDefs.BORDER_SIZE,
ScreenDefs.SCREEN_WIDTH + 2 * ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE
)
fullscreenG2d.clearRect(0, ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE, ScreenDefs.SCREEN_HEIGHT)
fullscreenG2d.clearRect(
ScreenDefs.SCREEN_WIDTH + ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE,
ScreenDefs.BORDER_SIZE, ScreenDefs.SCREEN_HEIGHT
)
if(vicSCROLY and 0b100000 != 0) {
// bitmap mode 320x200
fullscreenG2d.background = ScreenDefs.colorPalette[ram[0xd021]]
fullscreenG2d.clearRect(ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
// TODO vic address offset in memory, so that medusa.prg will work
val bitmap = ram.getPages(if(vicVMCSB and 0b00001000 != 0) 32 else 0, 32)
val colorBytes = ram.getPages((vicVMCSB ushr 4) shl 2, 4)
val pixels: IntArray = (fullscreenImage.raster.dataBuffer as DataBufferInt).data
for(y in 0 until ScreenDefs.SCREEN_HEIGHT) {
for(x in 0 until ScreenDefs.SCREEN_WIDTH step 8) {
val colorbyte = ScreenDefs.SCREEN_WIDTH_CHARS*(y ushr 3) + (x ushr 3)
val bgColor = ScreenDefs.colorPalette[colorBytes[colorbyte].toInt() and 15].rgb
val fgColor = ScreenDefs.colorPalette[colorBytes[colorbyte].toInt() ushr 4].rgb
draw8Pixels(pixels, x, y, bitmap, fgColor, bgColor)
}
}
} else {
// normal character mode
fullscreenG2d.background = ScreenDefs.colorPalette[ram[0xd021]]
fullscreenG2d.clearRect(ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
redrawCharacters()
}
}
// scale and draw the image to the window, and simulate a slight scanline effect
windowG2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
windowG2d.drawImage(
fullscreenImage, 0, 0, (fullscreenImage.width * ScreenDefs.DISPLAY_PIXEL_SCALING).toInt(),
(fullscreenImage.height * ScreenDefs.DISPLAY_PIXEL_SCALING).toInt(), null
)
windowG2d.color = Color(0, 0, 0, 40)
windowG2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
val width = fullscreenImage.width * ScreenDefs.DISPLAY_PIXEL_SCALING.toInt()
val height = fullscreenImage.height * ScreenDefs.DISPLAY_PIXEL_SCALING.toInt()
for (y in 0 until height step ScreenDefs.DISPLAY_PIXEL_SCALING.toInt()) {
windowG2d.drawLine(0, y, width, y)
}
Toolkit.getDefaultToolkit().sync()
}
private fun draw8Pixels(pixels: IntArray, xstart: Int, y: Int,
bitmap: Array<UByte>, fgColorRgb: Int, bgColorRgb: Int) {
val offset = ScreenDefs.BORDER_SIZE + ScreenDefs.BORDER_SIZE*fullscreenImage.width +
xstart + y * fullscreenImage.width
val byte = bitmap[ScreenDefs.SCREEN_WIDTH_CHARS*(y and 248) + (y and 7) + (xstart and 504)].toInt()
pixels[offset + 0] = if(byte and 0b10000000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 1] = if(byte and 0b01000000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 2] = if(byte and 0b00100000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 3] = if(byte and 0b00010000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 4] = if(byte and 0b00001000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 5] = if(byte and 0b00000100 != 0) fgColorRgb else bgColorRgb
pixels[offset + 6] = if(byte and 0b00000010 != 0) fgColorRgb else bgColorRgb
pixels[offset + 7] = if(byte and 0b00000001 != 0) fgColorRgb else bgColorRgb
}
private fun redrawCharacters() {
val screen = 0x0400
val colors = 0xd800
val shifted = (ram[0xd018].toInt() and 0b00000010) != 0
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)
}
}
}
private val coloredCharacters = mutableMapOf<Triple<Int, Int, Boolean>, BufferedImage>()
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]
val colored = fullscreenG2d.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) {
val source = sourceRaster.getPixel(pixelX, pixelY, pixelArray)
if (source[0] != 0) {
coloredRaster.setPixel(pixelX, pixelY, coloredPixel)
}
}
}
coloredCharacters[Triple(char, color, shifted)] = colored
cached = colored
}
fullscreenG2d.drawImage(cached, x * 8 + ScreenDefs.BORDER_SIZE, y * 8 + ScreenDefs.BORDER_SIZE, null)
}
}
class MainC64Window(
title: String,
chargenData: ByteArray,
@ -220,14 +56,12 @@ class MainC64Window(
val cpu: Cpu6502,
val keypressCia: Cia
) : JFrame(title), KeyListener {
private val canvas = BitmapScreenPanel(chargenData, ram)
init {
defaultCloseOperation = EXIT_ON_CLOSE
isResizable = false
isFocusable = true
add(canvas)
add(Screen(chargenData, ram))
addKeyListener(this)
pack()
setLocationRelativeTo(null)

View File

@ -0,0 +1,252 @@
package razorvine.c64emu
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.MemoryComponent
import razorvine.ksim65.components.UByte
import java.awt.*
import java.awt.image.BufferedImage
import java.awt.image.DataBufferInt
import javax.swing.JPanel
/**
* The rendering logic of the screen of the C64.
* It supports: Character mode,
* High res bitmap mode (320*200), Multicolor bitmap mode (160*200).
* TODO: sprites. Multicolor character mode. Extended background color mode.
*/
internal class Screen(private val chargenData: ByteArray, val ram: MemoryComponent) : JPanel() {
private val fullscreenImage: BufferedImage
private val fullscreenG2d: Graphics2D
private val normalCharacters = loadCharacters(false)
private val shiftedCharacters = loadCharacters(true)
init {
val ge = GraphicsEnvironment.getLocalGraphicsEnvironment()
val gd = ge.defaultScreenDevice.defaultConfiguration
fullscreenImage = gd.createCompatibleImage(
ScreenDefs.SCREEN_WIDTH + 2 * ScreenDefs.BORDER_SIZE,
ScreenDefs.SCREEN_HEIGHT + 2 * ScreenDefs.BORDER_SIZE,
Transparency.OPAQUE
)
fullscreenImage.accelerationPriority = 1.0f
fullscreenG2d = fullscreenImage.graphics as Graphics2D
val size = Dimension(
fullscreenImage.width * ScreenDefs.DISPLAY_PIXEL_SCALING.toInt(),
fullscreenImage.height * ScreenDefs.DISPLAY_PIXEL_SCALING.toInt()
)
minimumSize = size
maximumSize = size
preferredSize = size
isFocusable = true
isDoubleBuffered = false
requestFocusInWindow()
}
private fun loadCharacters(shifted: Boolean): Array<BufferedImage> {
val chars = Array(256) {
BufferedImage(8, 8, BufferedImage.TYPE_BYTE_BINARY)
.also { it.accelerationPriority = 1.0f }
}
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()
for (x in 0..7) {
if (charbyte and (0b10000000 ushr x) != 0)
chars[char].setRGB(x, line, 0xffffff)
}
}
}
return chars
}
override fun paint(graphics: Graphics) {
val windowG2d = graphics as Graphics2D
val vicSCROLY = ram[0xd011].toInt()
if (vicSCROLY and 0b10000 == 0) {
// screen blanked, only display border
fullscreenG2d.background = ScreenDefs.colorPalette[ram[0xd020]]
fullscreenG2d.clearRect(
0, 0,
ScreenDefs.SCREEN_WIDTH + 2 * ScreenDefs.BORDER_SIZE,
ScreenDefs.SCREEN_HEIGHT + 2 * ScreenDefs.BORDER_SIZE
)
} else {
val vicSCROLX = ram[0xd016].toInt()
val vicVMCSB = ram[0xd018].toInt()
val multiColorMode = vicSCROLX and 0b00010000 != 0
val vicBank = when (ram[0xdd00].toInt() and 0b00000011) {
0b00 -> 0xc000
0b01 -> 0x8000
0b10 -> 0x4000
else -> 0x0000
}
// draw the screen border
fullscreenG2d.background = ScreenDefs.colorPalette[ram[0xd020]]
fullscreenG2d.clearRect(
0, 0,
ScreenDefs.SCREEN_WIDTH + 2 * ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE
)
fullscreenG2d.clearRect(
0, ScreenDefs.SCREEN_HEIGHT + ScreenDefs.BORDER_SIZE,
ScreenDefs.SCREEN_WIDTH + 2 * ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE
)
fullscreenG2d.clearRect(
0, ScreenDefs.BORDER_SIZE,
ScreenDefs.BORDER_SIZE, ScreenDefs.SCREEN_HEIGHT
)
fullscreenG2d.clearRect(
ScreenDefs.SCREEN_WIDTH + ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE,
ScreenDefs.BORDER_SIZE, ScreenDefs.SCREEN_HEIGHT
)
if (vicSCROLY and 0b00100000 != 0)
renderBitmapMode(vicBank, vicVMCSB, multiColorMode)
else {
fullscreenG2d.background = ScreenDefs.colorPalette[ram[0xd021]]
fullscreenG2d.clearRect(
ScreenDefs.BORDER_SIZE, ScreenDefs.BORDER_SIZE,
ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT
)
renderCharacterMode(vicBank, vicVMCSB, multiColorMode)
}
}
// scale and draw the image to the window, and simulate a slight scanline effect
windowG2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
windowG2d.drawImage(
fullscreenImage, 0, 0, (fullscreenImage.width * ScreenDefs.DISPLAY_PIXEL_SCALING).toInt(),
(fullscreenImage.height * ScreenDefs.DISPLAY_PIXEL_SCALING).toInt(), null
)
windowG2d.color = Color(0, 0, 0, 40)
windowG2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
val width = fullscreenImage.width * ScreenDefs.DISPLAY_PIXEL_SCALING.toInt()
val height = fullscreenImage.height * ScreenDefs.DISPLAY_PIXEL_SCALING.toInt()
for (y in 0 until height step ScreenDefs.DISPLAY_PIXEL_SCALING.toInt()) {
windowG2d.drawLine(0, y, width, y)
}
Toolkit.getDefaultToolkit().sync()
}
private fun renderCharacterMode(vicBank: Address, vicVMCSB: Int, multiColorMode: Boolean) {
if (multiColorMode) {
TODO("multicolor character mode")
} else {
// normal character mode
val screenAddress = vicBank + (vicVMCSB ushr 4) shl 10
val charsetAddress = (vicVMCSB and 0b00001110) shl 10
if (charsetAddress == 0x1000 || charsetAddress == 0x1800) {
// use built-in character ROM
for (y in 0 until ScreenDefs.SCREEN_HEIGHT_CHARS) {
for (x in 0 until ScreenDefs.SCREEN_WIDTH_CHARS) {
val char = ram[screenAddress + x + y * ScreenDefs.SCREEN_WIDTH_CHARS].toInt()
val color = ram[0xd800 + x + y * ScreenDefs.SCREEN_WIDTH_CHARS].toInt() // colors always at $d800
drawColoredChar(x, y, char, color, charsetAddress == 0x1800)
}
}
}
/* else {
// TODO: custom charsets from RAM. Currently the charset ROM is just loaded externally.
} */
}
}
private fun renderBitmapMode(vicBank: Address, vicVMCSB: Int, multiColorMode: Boolean) {
val bitmap = ram.getPages((vicBank ushr 8) + if (vicVMCSB and 0b00001000 != 0) 32 else 0, 32)
val colorBytes = ram.getPages((vicBank ushr 8) + ((vicVMCSB ushr 4) shl 2), 4)
val pixels: IntArray = (fullscreenImage.raster.dataBuffer as DataBufferInt).data
val screenColor = ScreenDefs.colorPalette[ram[0xd021]].rgb
if (multiColorMode) {
// multicolor bitmap mode 160x200
val fourColors = IntArray(4)
fourColors[0b00] = screenColor
for (y in 0 until ScreenDefs.SCREEN_HEIGHT) {
for (x in 0 until ScreenDefs.SCREEN_WIDTH/2 step 4) {
val colorIdx = ScreenDefs.SCREEN_WIDTH_CHARS * (y ushr 3) + (x ushr 2)
fourColors[0b01] = ScreenDefs.colorPalette[colorBytes[colorIdx].toInt() ushr 4].rgb
fourColors[0b10] = ScreenDefs.colorPalette[colorBytes[colorIdx].toInt()].rgb
fourColors[0b11] = ScreenDefs.colorPalette[ram[0xd800 + colorIdx].toInt()].rgb
draw4bitmapPixelsMc(pixels, x, y, bitmap, fourColors)
}
}
} else {
// bitmap mode 320x200
for (y in 0 until ScreenDefs.SCREEN_HEIGHT) {
for (x in 0 until ScreenDefs.SCREEN_WIDTH step 8) {
val colorIdx = ScreenDefs.SCREEN_WIDTH_CHARS * (y ushr 3) + (x ushr 3)
val bgColor = ScreenDefs.colorPalette[colorBytes[colorIdx].toInt()].rgb
val fgColor = ScreenDefs.colorPalette[colorBytes[colorIdx].toInt() ushr 4].rgb
draw8bitmapPixels(pixels, x, y, bitmap, fgColor, bgColor)
}
}
}
}
private fun draw8bitmapPixels(
pixels: IntArray, xstart: Int, y: Int,
bitmap: Array<UByte>, fgColorRgb: Int, bgColorRgb: Int )
{
val offset = ScreenDefs.BORDER_SIZE + ScreenDefs.BORDER_SIZE * fullscreenImage.width +
xstart + y * fullscreenImage.width
val byte = bitmap[ScreenDefs.SCREEN_WIDTH_CHARS * (y and 248) + (y and 7) + (xstart and 504)].toInt()
pixels[offset] = if (byte and 0b10000000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 1] = if (byte and 0b01000000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 2] = if (byte and 0b00100000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 3] = if (byte and 0b00010000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 4] = if (byte and 0b00001000 != 0) fgColorRgb else bgColorRgb
pixels[offset + 5] = if (byte and 0b00000100 != 0) fgColorRgb else bgColorRgb
pixels[offset + 6] = if (byte and 0b00000010 != 0) fgColorRgb else bgColorRgb
pixels[offset + 7] = if (byte and 0b00000001 != 0) fgColorRgb else bgColorRgb
}
private fun draw4bitmapPixelsMc(pixels: IntArray, xstart: Int, y: Int,
bitmap: Array<UByte>, fourColors: IntArray) {
val realx = xstart * 2
val offset = ScreenDefs.BORDER_SIZE + ScreenDefs.BORDER_SIZE * fullscreenImage.width +
realx + y * fullscreenImage.width
val byte = bitmap[ScreenDefs.SCREEN_WIDTH_CHARS * (y and 248) + (y and 7) + (realx and 504)].toInt()
val colors = listOf(
byte and 0b11000000 ushr 6,
byte and 0b00110000 ushr 4,
byte and 0b00001100 ushr 2,
byte and 0b00000011
)
pixels[offset] = fourColors[colors[0]]
pixels[offset + 1] = fourColors[colors[0]]
pixels[offset + 2] = fourColors[colors[1]]
pixels[offset + 3] = fourColors[colors[1]]
pixels[offset + 4] = fourColors[colors[2]]
pixels[offset + 5] = fourColors[colors[2]]
pixels[offset + 6] = fourColors[colors[3]]
pixels[offset + 7] = fourColors[colors[3]]
}
private val coloredCharacters = mutableMapOf<Triple<Int, Int, Boolean>, BufferedImage>()
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]
val colored = fullscreenG2d.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) {
val source = sourceRaster.getPixel(pixelX, pixelY, pixelArray)
if (source[0] != 0) {
coloredRaster.setPixel(pixelX, pixelY, coloredPixel)
}
}
}
coloredCharacters[Triple(char, color, shifted)] = colored
cached = colored
}
fullscreenG2d.drawImage(cached, x * 8 + ScreenDefs.BORDER_SIZE, y * 8 + ScreenDefs.BORDER_SIZE, null)
}
}

View File

@ -65,7 +65,7 @@ class C64Machine(title: String) : IVirtualMachine {
hostDisplay.start(30)
}
fun breakpointKernelLoad(cpu: Cpu6502, pc: Address): Cpu6502.BreakpointResultAction {
private fun breakpointKernelLoad(cpu: Cpu6502, pc: Address): Cpu6502.BreakpointResultAction {
if (cpu.regA == 0) {
val fnlen = ram[0xb7] // file name length
val fa = ram[0xba] // device number
@ -85,7 +85,7 @@ class C64Machine(title: String) : IVirtualMachine {
} else return Cpu6502.BreakpointResultAction(changePC = 0xf707) // 'device not present' (VERIFY command not supported)
}
fun breakpointKernelSave(cpu: Cpu6502, pc: Address): Cpu6502.BreakpointResultAction {
private fun breakpointKernelSave(cpu: Cpu6502, pc: Address): Cpu6502.BreakpointResultAction {
val fnlen = ram[0xb7] // file name length
// val fa = ram[0xba] // device number
// val sa = ram[0xb9] // secondary address
@ -107,16 +107,12 @@ class C64Machine(title: String) : IVirtualMachine {
} else Cpu6502.BreakpointResultAction(changePC = 0xf710) // 'missing file name'
}
fun breakpointBRK(cpu: Cpu6502, pc: Address): Cpu6502.BreakpointResultAction {
private fun breakpointBRK(cpu: Cpu6502, pc: Address): Cpu6502.BreakpointResultAction {
throw Cpu6502.InstructionError("BRK instruction hit at $${hexW(pc)}")
}
private fun searchAndLoadFile(
filename: String,
device: UByte,
secondary: UByte,
basicLoadAddress: Address
): Address? {
private fun searchAndLoadFile(filename: String,
device: UByte, secondary: UByte, basicLoadAddress: Address): Address? {
when (filename) {
"*" -> {
// load the first file in the directory
@ -170,11 +166,9 @@ class C64Machine(title: String) : IVirtualMachine {
}
}
private fun makeDirListing(
dirname: String,
files: Map<Pair<String, String>, Pair<File, Long>>,
basicLoadAddress: Address
): Array<UByte> {
private fun makeDirListing(dirname: String,
files: Map<Pair<String, String>, Pair<File, Long>>, basicLoadAddress: Address): Array<UByte>
{
var address = basicLoadAddress
val listing = mutableListOf<UByte>()
fun addLine(lineNumber: Int, line: String) {
@ -193,8 +187,8 @@ class C64Machine(title: String) : IVirtualMachine {
totalBlocks += blocksize
val filename = it.key.first.take(16)
val padding1 = " ".substring(blocksize.toString().length)
val padding2 = " ".substring(filename.length)
addLine(blocksize, "$padding1 \"$filename\" $padding2 ${it.key.second.take(3).padEnd(3)}")
val padding2 = " ".substring(filename.length)
addLine(blocksize, "$padding1 \"$filename\" $padding2${it.key.second.take(3).padEnd(3)}")
}
addLine(kotlin.math.max(0, 664 - totalBlocks), "BLOCKS FREE.")
listing.add(0)
@ -249,19 +243,31 @@ class C64Machine(title: String) : IVirtualMachine {
}.start()
val timer = java.util.Timer("cpu-cycle", true)
timer.scheduleAtFixedRate(0, 1000L/VicII.framerate) {
if(!paused) {
timer.scheduleAtFixedRate(0, 1000L / VicII.framerate) {
if (!paused) {
// we synchronise cpu cycles to the vertical blank of the Vic chip
// this should result in ~1 Mhz cpu speed
try {
while (vic.vsync) step()
while (!vic.vsync) step()
} catch(rx: RuntimeException) {
JOptionPane.showMessageDialog(hostDisplay, "Run time error: $rx", "Error during execution", JOptionPane.ERROR_MESSAGE)
} catch (rx: RuntimeException) {
JOptionPane.showMessageDialog(
hostDisplay,
"Run time error: $rx",
"Error during execution",
JOptionPane.ERROR_MESSAGE
)
this.cancel()
} catch(ex: Error) {
JOptionPane.showMessageDialog(hostDisplay, "Run time error: $ex", "Error during execution", JOptionPane.ERROR_MESSAGE)
throw rx
} catch (ex: Error) {
JOptionPane.showMessageDialog(
hostDisplay,
"Run time error: $ex",
"Error during execution",
JOptionPane.ERROR_MESSAGE
)
this.cancel()
throw ex
}
}
}

View File

@ -16,8 +16,6 @@ open class Cpu6502 : BusComponent() {
var tracing: ((state:String) -> Unit)? = null
var totalCycles = 0L
protected set
private var speedMeasureCycles = 0L
private var speedMeasureStart = System.nanoTime()
private var resetTime = System.nanoTime()
var breakpointForBRK: BreakpointHandler? = null
@ -166,14 +164,6 @@ open class Cpu6502 : BusComponent() {
totalCycles)
}
fun startSpeedMeasureInterval() {
speedMeasureCycles = totalCycles
speedMeasureStart = System.nanoTime()
}
fun measureAvgIntervalSpeedKhz() =
(totalCycles-speedMeasureCycles).toDouble() / (System.nanoTime() - speedMeasureStart) * 1_000_000
// has an interrupt been requested?
protected enum class Interrupt {
IRQ,