mirror of
https://github.com/irmen/ksim65.git
synced 2024-06-07 13:43:49 +00:00
disassem in debug window
This commit is contained in:
parent
261b6738b4
commit
bbda51fdda
|
@ -7,9 +7,9 @@ import java.util.ArrayDeque
|
|||
import javax.imageio.ImageIO
|
||||
import javax.swing.event.MouseInputListener
|
||||
import razorvine.ksim65.IHostInterface
|
||||
import razorvine.ksim65.components.MemoryComponent
|
||||
import java.awt.event.*
|
||||
import javax.swing.*
|
||||
import javax.swing.border.LineBorder
|
||||
|
||||
|
||||
/**
|
||||
|
@ -101,8 +101,7 @@ private class BitmapScreenPanel : JPanel() {
|
|||
fun clearScreen() {
|
||||
g2d.background = ScreenDefs.BG_COLOR
|
||||
g2d.clearRect(0, 0, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
|
||||
cursorX = 0
|
||||
cursorY = 0
|
||||
cursorPos(0, 0)
|
||||
}
|
||||
|
||||
fun setPixel(x: Int, y: Int, onOff: Boolean) {
|
||||
|
@ -134,29 +133,34 @@ private class BitmapScreenPanel : JPanel() {
|
|||
)
|
||||
}
|
||||
|
||||
fun blinkCursor(x: Int, y: Int) {
|
||||
fun cursorPos(x: Int, y: Int) {
|
||||
if(x!=cursorX || y!=cursorY)
|
||||
cursorState=true
|
||||
cursorX = x
|
||||
cursorY = y
|
||||
}
|
||||
|
||||
fun blinkCursor() {
|
||||
cursorState = !cursorState
|
||||
}
|
||||
}
|
||||
|
||||
class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
|
||||
val cyclesTf = JTextField("00000000000000")
|
||||
val speedKhzTf = JTextField("0000000")
|
||||
val regAtf = JTextField("000")
|
||||
val regXtf = JTextField("000")
|
||||
val regYtf = JTextField("000")
|
||||
val regPCtf = JTextField("00000")
|
||||
val regSPtf = JTextField("000")
|
||||
val regPtf = JTextArea("NV-BDIZC\n000000000")
|
||||
val opcodeTf = JTextField("000")
|
||||
val mnemonicTf = JTextField("brk ")
|
||||
val disassemTf = JTextField("00 00 00 lda (fffff),x")
|
||||
private val pauseBt = JButton("Pause").also { it.actionCommand = "pause" }
|
||||
|
||||
init {
|
||||
isFocusable = true
|
||||
defaultCloseOperation = EXIT_ON_CLOSE
|
||||
preferredSize = Dimension(250, 600)
|
||||
preferredSize = Dimension(350, 600)
|
||||
val cpuPanel = JPanel(GridBagLayout())
|
||||
cpuPanel.border = BorderFactory.createTitledBorder("CPU: ${vm.cpu.name}")
|
||||
val gc = GridBagConstraints()
|
||||
|
@ -165,22 +169,22 @@ class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
|
|||
gc.gridx = 0
|
||||
gc.gridy = 0
|
||||
val cyclesLb = JLabel("cycles")
|
||||
val speedKhzLb = JLabel("speed (kHz)")
|
||||
val regAlb = JLabel("A")
|
||||
val regXlb = JLabel("X")
|
||||
val regYlb = JLabel("Y")
|
||||
val regSPlb = JLabel("SP")
|
||||
val regPClb = JLabel("PC")
|
||||
val regPlb = JLabel("Status")
|
||||
val opcodeLb = JLabel("opcode")
|
||||
val mnemonicLb = JLabel("mnemonic")
|
||||
listOf(cyclesLb, regAlb, regXlb, regYlb, regSPlb, regPClb, regPlb, opcodeLb, mnemonicLb).forEach {
|
||||
val disassemLb = JLabel("Instruction")
|
||||
listOf(cyclesLb, speedKhzLb, regAlb, regXlb, regYlb, regSPlb, regPClb, regPlb, disassemLb).forEach {
|
||||
cpuPanel.add(it, gc)
|
||||
gc.gridy++
|
||||
}
|
||||
gc.anchor = GridBagConstraints.WEST
|
||||
gc.gridx = 1
|
||||
gc.gridy = 0
|
||||
listOf(cyclesTf, regAtf, regXtf, regYtf, regSPtf, regPCtf, regPtf, opcodeTf, mnemonicTf).forEach {
|
||||
listOf(cyclesTf, speedKhzTf, regAtf, regXtf, regYtf, regSPtf, regPCtf, regPtf, disassemTf).forEach {
|
||||
it.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
|
||||
it.isEditable = false
|
||||
if(it is JTextField) {
|
||||
|
@ -215,11 +219,11 @@ class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
|
|||
when(e.actionCommand) {
|
||||
"reset" -> {
|
||||
vm.bus.reset()
|
||||
updateCpu(vm.cpu)
|
||||
updateCpu(vm.cpu, vm.ram)
|
||||
}
|
||||
"step" -> {
|
||||
vm.stepInstruction()
|
||||
updateCpu(vm.cpu)
|
||||
updateCpu(vm.cpu, vm.ram)
|
||||
}
|
||||
"pause" -> {
|
||||
vm.paused = true
|
||||
|
@ -237,7 +241,7 @@ class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
|
|||
}
|
||||
}
|
||||
|
||||
fun updateCpu(cpu: Cpu6502) {
|
||||
fun updateCpu(cpu: Cpu6502, mem: MemoryComponent) {
|
||||
cyclesTf.text = cpu.totalCycles.toString()
|
||||
regAtf.text = cpu.hexB(cpu.regA)
|
||||
regXtf.text = cpu.hexB(cpu.regX)
|
||||
|
@ -245,8 +249,7 @@ class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
|
|||
regPtf.text = "NV-BDIZC\n" + cpu.regP.asByte().toString(2).padStart(8, '0')
|
||||
regPCtf.text = cpu.hexW(cpu.regPC)
|
||||
regSPtf.text = cpu.hexB(cpu.regSP)
|
||||
opcodeTf.text = cpu.hexB(cpu.currentOpcode)
|
||||
mnemonicTf.text = cpu.currentMnemonic
|
||||
disassemTf.text = cpu.disassembleOneInstruction(mem.data, cpu.regPC, mem.startAddress).first.substringAfter(' ').trim()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,7 +325,14 @@ class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener
|
|||
|
||||
fun start() {
|
||||
// repaint the screen's back buffer ~60 times per second
|
||||
val repaintTimer = Timer(1000 / 60) { repaint() }
|
||||
var cursorBlink = 0L
|
||||
val repaintTimer = Timer(1000 / 60) {
|
||||
repaint()
|
||||
if(it.`when` - cursorBlink > 200L) {
|
||||
cursorBlink = it.`when`
|
||||
canvas.blinkCursor()
|
||||
}
|
||||
}
|
||||
repaintTimer.initialDelay = 0
|
||||
repaintTimer.start()
|
||||
}
|
||||
|
@ -369,15 +379,13 @@ class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener
|
|||
|
||||
// the overrides required for IHostDisplay:
|
||||
override fun clearScreen() = canvas.clearScreen()
|
||||
|
||||
override fun setPixel(x: Int, y: Int) = canvas.setPixel(x, y, true)
|
||||
override fun clearPixel(x: Int, y: Int) = canvas.setPixel(x, y, false)
|
||||
override fun getPixel(x: Int, y: Int) = canvas.getPixel(x, y)
|
||||
override fun setChar(x: Int, y: Int, character: Char) = canvas.setChar(x, y, character)
|
||||
override fun cursor(x: Int, y: Int) = canvas.cursorPos(x, y)
|
||||
override fun scrollUp() = canvas.scrollUp()
|
||||
override fun mouse(): IHostInterface.MouseInfo {
|
||||
return IHostInterface.MouseInfo(mousePos.x, mousePos.y, leftButton, rightButton, middleButton)
|
||||
}
|
||||
override fun mouse() = IHostInterface.MouseInfo(mousePos.x, mousePos.y, leftButton, rightButton, middleButton)
|
||||
|
||||
override fun keyboard(): Char? {
|
||||
return if (keyboardBuffer.isEmpty())
|
||||
|
@ -386,7 +394,4 @@ class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener
|
|||
keyboardBuffer.pop()
|
||||
}
|
||||
|
||||
override fun blinkCursor(x: Int, y: Int) {
|
||||
canvas.blinkCursor(x, y)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,12 +55,16 @@ class VirtualMachine(title: String) {
|
|||
|
||||
fun start() {
|
||||
val timer = java.util.Timer("clock", true)
|
||||
val startTime = System.currentTimeMillis()
|
||||
timer.scheduleAtFixedRate(1, 1) {
|
||||
if(!paused) {
|
||||
repeat(10) {
|
||||
repeat(5) {
|
||||
stepInstruction()
|
||||
}
|
||||
debugWindow.updateCpu(cpu)
|
||||
debugWindow.updateCpu(cpu, ram)
|
||||
val duration = System.currentTimeMillis() - startTime
|
||||
val speedKhz = cpu.totalCycles.toDouble() / duration
|
||||
debugWindow.speedKhzTf.text = "%.1f".format(speedKhz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,115 +143,122 @@ open class Cpu6502(private val stopOnBrk: Boolean = false) : BusComponent() {
|
|||
return hexdigits[hiNibble].toString() + hexdigits[loNibble]
|
||||
}
|
||||
|
||||
fun disassemble(component: MemoryComponent, from: Address, to: Address) =
|
||||
disassemble(component.copyOfMem(), component.startAddress, from, to)
|
||||
fun disassemble(memory: MemoryComponent, from: Address, to: Address) =
|
||||
disassemble(memory.data, memory.startAddress, from, to)
|
||||
|
||||
fun disassemble(memory: Array<UByte>, baseAddress: Address, from: Address, to: Address): List<String> {
|
||||
var location = from - baseAddress
|
||||
val spacing1 = " "
|
||||
val spacing2 = " "
|
||||
val spacing3 = " "
|
||||
val result = mutableListOf<String>()
|
||||
|
||||
while (location <= (to - baseAddress)) {
|
||||
val byte = memory[location]
|
||||
var line = "\$${hexW(location+baseAddress)} ${hexB(byte)} "
|
||||
location++
|
||||
val opcode = instructions[byte.toInt()]
|
||||
when (opcode.mode) {
|
||||
AddrMode.Acc -> {
|
||||
line += "$spacing1 ${opcode.mnemonic} a"
|
||||
}
|
||||
AddrMode.Imp -> {
|
||||
line += "$spacing1 ${opcode.mnemonic}"
|
||||
}
|
||||
AddrMode.Imm -> {
|
||||
val value = memory[location++]
|
||||
line += "${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(value)}"
|
||||
}
|
||||
AddrMode.Zp -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)}"
|
||||
}
|
||||
AddrMode.Zpr -> {
|
||||
// addressing mode used by the 65C02, put here for convenience
|
||||
val zpAddr = memory[location++]
|
||||
val rel = memory[location++]
|
||||
val target =
|
||||
if (rel <= 0x7f)
|
||||
location + rel + baseAddress
|
||||
else
|
||||
location - (256 - rel) + baseAddress
|
||||
line += "${hexB(zpAddr)} ${hexB(rel)} $spacing3 ${opcode.mnemonic} \$${hexB(zpAddr)}, \$${hexW(target, true)}"
|
||||
}
|
||||
AddrMode.Izp -> {
|
||||
// addressing mode used by the 65C02, put here for convenience
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$(${hexB(zpAddr)})"
|
||||
}
|
||||
AddrMode.IaX -> {
|
||||
// addressing mode used by the 65C02, put here for convenience
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val absAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$(${hexW(absAddr)},x)"
|
||||
}
|
||||
AddrMode.ZpX -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},x"
|
||||
}
|
||||
AddrMode.ZpY -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},y"
|
||||
}
|
||||
AddrMode.Rel -> {
|
||||
val rel = memory[location++]
|
||||
val target =
|
||||
if (rel <= 0x7f)
|
||||
location + rel + baseAddress
|
||||
else
|
||||
location - (256 - rel) + baseAddress
|
||||
line += "${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(target, true)}"
|
||||
}
|
||||
AddrMode.Abs -> {
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val absAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)}"
|
||||
}
|
||||
AddrMode.AbsX -> {
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val absAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},x"
|
||||
}
|
||||
AddrMode.AbsY -> {
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val absAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},y"
|
||||
}
|
||||
AddrMode.Ind -> {
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val indirectAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} (\$${hexW(indirectAddr)})"
|
||||
}
|
||||
AddrMode.IzX -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)},x)"
|
||||
}
|
||||
AddrMode.IzY -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)}),y"
|
||||
}
|
||||
}
|
||||
result.add(line)
|
||||
val dis = disassembleOneInstruction(memory, location, baseAddress)
|
||||
result.add(dis.first)
|
||||
location = dis.second
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun disassembleOneInstruction(memory: Array<UByte>, address: Address, baseAddress: Address): Pair<String, Address> {
|
||||
val spacing1 = " "
|
||||
val spacing2 = " "
|
||||
val spacing3 = " "
|
||||
var location = address
|
||||
val byte = memory[location]
|
||||
var line = "\$${hexW(location+baseAddress)} ${hexB(byte)} "
|
||||
location++
|
||||
val opcode = instructions[byte.toInt()]
|
||||
when (opcode.mode) {
|
||||
AddrMode.Acc -> {
|
||||
line += "$spacing1 ${opcode.mnemonic} a"
|
||||
}
|
||||
AddrMode.Imp -> {
|
||||
line += "$spacing1 ${opcode.mnemonic}"
|
||||
}
|
||||
AddrMode.Imm -> {
|
||||
val value = memory[location++]
|
||||
line += "${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(value)}"
|
||||
}
|
||||
AddrMode.Zp -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)}"
|
||||
}
|
||||
AddrMode.Zpr -> {
|
||||
// addressing mode used by the 65C02, put here for convenience
|
||||
val zpAddr = memory[location++]
|
||||
val rel = memory[location++]
|
||||
val target =
|
||||
if (rel <= 0x7f)
|
||||
location + rel + baseAddress
|
||||
else
|
||||
location - (256 - rel) + baseAddress
|
||||
line += "${hexB(zpAddr)} ${hexB(rel)} $spacing3 ${opcode.mnemonic} \$${hexB(zpAddr)}, \$${hexW(target, true)}"
|
||||
}
|
||||
AddrMode.Izp -> {
|
||||
// addressing mode used by the 65C02, put here for convenience
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$(${hexB(zpAddr)})"
|
||||
}
|
||||
AddrMode.IaX -> {
|
||||
// addressing mode used by the 65C02, put here for convenience
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val absAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$(${hexW(absAddr)},x)"
|
||||
}
|
||||
AddrMode.ZpX -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},x"
|
||||
}
|
||||
AddrMode.ZpY -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},y"
|
||||
}
|
||||
AddrMode.Rel -> {
|
||||
val rel = memory[location++]
|
||||
val target =
|
||||
if (rel <= 0x7f)
|
||||
location + rel + baseAddress
|
||||
else
|
||||
location - (256 - rel) + baseAddress
|
||||
line += "${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(target, true)}"
|
||||
}
|
||||
AddrMode.Abs -> {
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val absAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)}"
|
||||
}
|
||||
AddrMode.AbsX -> {
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val absAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},x"
|
||||
}
|
||||
AddrMode.AbsY -> {
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val absAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},y"
|
||||
}
|
||||
AddrMode.Ind -> {
|
||||
val lo = memory[location++]
|
||||
val hi = memory[location++]
|
||||
val indirectAddr = lo.toInt() or (hi.toInt() shl 8)
|
||||
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} (\$${hexW(indirectAddr)})"
|
||||
}
|
||||
AddrMode.IzX -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)},x)"
|
||||
}
|
||||
AddrMode.IzY -> {
|
||||
val zpAddr = memory[location++]
|
||||
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)}),y"
|
||||
}
|
||||
}
|
||||
return Pair(line, location)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the cpu
|
||||
*/
|
||||
|
|
|
@ -10,10 +10,10 @@ interface IHostInterface {
|
|||
fun setPixel(x: Int, y: Int)
|
||||
fun clearPixel(x: Int, y: Int)
|
||||
fun setChar(x: Int, y: Int, character: Char)
|
||||
fun cursor(x: Int, y: Int)
|
||||
fun scrollUp()
|
||||
fun mouse(): MouseInfo
|
||||
fun keyboard(): Char?
|
||||
fun blinkCursor(x: Int, y: Int)
|
||||
|
||||
class MouseInfo(val x: Int, val y: Int, val left: Boolean, val right: Boolean, val middle: Boolean)
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ abstract class MemMappedComponent(val startAddress: Address, val endAddress: Add
|
|||
*/
|
||||
abstract class MemoryComponent(startAddress: Address, endAddress: Address) :
|
||||
MemMappedComponent(startAddress, endAddress) {
|
||||
abstract fun copyOfMem(): Array<UByte>
|
||||
|
||||
abstract val data: Array<UByte>
|
||||
|
||||
init {
|
||||
require(startAddress and 0xff == 0 && endAddress and 0xff == 0xff) {"address range must span complete page(s)"}
|
||||
|
|
|
@ -22,11 +22,11 @@ import kotlin.math.min
|
|||
* 04 pixel X pos (msb)
|
||||
* 05 pixel Y pos (lsb)
|
||||
* 06 pixel Y pos (msb)
|
||||
* 07 read or write pixel value at pX, pY
|
||||
* 08 cursor X position (r/w)
|
||||
* 09 cursor Y position (r/w)
|
||||
* 0a read or write character at cursor pos, updates cursor position, scrolls up if necessary
|
||||
* control characters: 0x08=backspace, 0x09=tab, 0x0a=newline, 0x0c=formfeed(clear screen), 0x0d=carriagereturn
|
||||
* 07 r/w pixel value at pX, pY
|
||||
* 08 cursor X position
|
||||
* 09 cursor Y position
|
||||
* 0a r/w character at cursor pos, updates cursor position, scrolls up if necessary
|
||||
* control chars: 8=backspace, 9=tab, 10=newline, 12=form feed (clear screen), 13=carriage return
|
||||
*/
|
||||
class Display(
|
||||
startAddress: Address, endAddress: Address,
|
||||
|
@ -49,16 +49,10 @@ class Display(
|
|||
private var pixelX = 0
|
||||
private var pixelY = 0
|
||||
private val charMatrix = Array<ShortArray>(charHeight) { ShortArray(charWidth) } // matrix[y][x] to access
|
||||
private var cursorCycles = 0
|
||||
|
||||
override fun clock() {
|
||||
// if the system clock is synced to the display refresh,
|
||||
// you *could* add a Vertical Blank interrupt here.
|
||||
// for now, only the cursor blinking is controlled by this.
|
||||
cursorCycles++
|
||||
if(cursorCycles % 8000 == 0) {
|
||||
host.blinkCursor(cursorX, cursorY)
|
||||
}
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
|
@ -136,7 +130,7 @@ class Display(
|
|||
}
|
||||
0x09 -> {
|
||||
// tab
|
||||
cursorX = (cursorX and 248) + 8
|
||||
cursorX = (cursorX and 0b11111000) + 8
|
||||
if(cursorX >= charWidth) {
|
||||
cursorX = 0
|
||||
cursorDown()
|
||||
|
@ -161,6 +155,7 @@ class Display(
|
|||
}
|
||||
}
|
||||
}
|
||||
host.cursor(cursorX, cursorY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,32 +8,26 @@ import java.net.URL
|
|||
* A RAM chip with read/write memory.
|
||||
*/
|
||||
class Ram(startAddress: Address, endAddress: Address) : MemoryComponent(startAddress, endAddress) {
|
||||
private val memory = ShortArray(endAddress - startAddress + 1)
|
||||
override val data = Array<UByte>(endAddress - startAddress + 1) { 0 }
|
||||
|
||||
override operator fun get(address: Address): UByte = memory[address - startAddress]
|
||||
override operator fun get(address: Address): UByte = data[address - startAddress]
|
||||
|
||||
override operator fun set(address: Address, data: UByte) {
|
||||
memory[address - startAddress] = data
|
||||
this.data[address - startAddress] = data
|
||||
}
|
||||
|
||||
override fun copyOfMem(): Array<UByte> = memory.toTypedArray()
|
||||
|
||||
override fun clock() {}
|
||||
|
||||
override fun reset() {
|
||||
// contents of RAM doesn't change on a reset
|
||||
}
|
||||
|
||||
fun fill(data: UByte) {
|
||||
memory.fill(data)
|
||||
}
|
||||
fun fill(data: UByte) = this.data.fill(data)
|
||||
|
||||
/**
|
||||
* Load a c64-style prg program. This file type has the load address as the first two bytes.
|
||||
*/
|
||||
fun loadPrg(filename: String) {
|
||||
loadPrg(File(filename).inputStream())
|
||||
}
|
||||
fun loadPrg(filename: String) = loadPrg(File(filename).inputStream())
|
||||
|
||||
/**
|
||||
* Load a c64-style prg program. This file type has the load address as the first two bytes.
|
||||
|
@ -43,7 +37,7 @@ class Ram(startAddress: Address, endAddress: Address) : MemoryComponent(startAdd
|
|||
val loadAddress = (bytes[0].toInt() or (bytes[1].toInt() shl 8)) and 65535
|
||||
val baseAddress = loadAddress - startAddress
|
||||
bytes.drop(2).forEachIndexed { index, byte ->
|
||||
memory[baseAddress + index] =
|
||||
data[baseAddress + index] =
|
||||
if (byte >= 0)
|
||||
byte.toShort()
|
||||
else
|
||||
|
@ -67,13 +61,13 @@ class Ram(startAddress: Address, endAddress: Address) : MemoryComponent(startAdd
|
|||
fun load(data: Array<UByte>, address: Address) =
|
||||
data.forEachIndexed { index, byte ->
|
||||
val baseAddress = address - startAddress
|
||||
memory[baseAddress + index] = byte
|
||||
this.data[baseAddress + index] = byte
|
||||
}
|
||||
|
||||
fun load(data: ByteArray, address: Address) =
|
||||
data.forEachIndexed { index, byte ->
|
||||
val baseAddress = address - startAddress
|
||||
memory[baseAddress + index] =
|
||||
this.data[baseAddress + index] =
|
||||
if (byte >= 0)
|
||||
byte.toShort()
|
||||
else
|
||||
|
|
|
@ -3,21 +3,16 @@ package razorvine.ksim65.components
|
|||
/**
|
||||
* A ROM chip (read-only memory).
|
||||
*/
|
||||
class Rom(startAddress: Address, endAddress: Address, data: Array<UByte>? = null) : MemoryComponent(startAddress, endAddress) {
|
||||
private val memory =
|
||||
if (data == null)
|
||||
ShortArray(endAddress - startAddress - 1)
|
||||
else
|
||||
ShortArray(data.size) { index -> data[index] }
|
||||
class Rom(startAddress: Address, endAddress: Address, initialData: Array<UByte>? = null) : MemoryComponent(startAddress, endAddress) {
|
||||
override val data: Array<UByte> =
|
||||
initialData?.copyOf() ?: Array<UByte>(endAddress - startAddress - 1) { 0 }
|
||||
|
||||
init {
|
||||
if (data != null)
|
||||
require(endAddress - startAddress + 1 == data.size) { "rom address range doesn't match size of data bytes" }
|
||||
require(endAddress - startAddress + 1 == data.size) { "rom address range doesn't match size of data bytes" }
|
||||
}
|
||||
|
||||
override operator fun get(address: Address): UByte = memory[address - startAddress]
|
||||
override operator fun get(address: Address): UByte = data[address - startAddress]
|
||||
override operator fun set(address: Address, data: UByte) { /* read-only */ }
|
||||
override fun copyOfMem(): Array<UByte> = memory.toTypedArray()
|
||||
override fun clock() {}
|
||||
override fun reset() {}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,22 @@ start
|
|||
txs
|
||||
cli
|
||||
|
||||
; ------- print stuff
|
||||
lda #10
|
||||
sta DISPLAY+8
|
||||
sta DISPLAY+9
|
||||
ldx #5
|
||||
printloop
|
||||
ldy #32
|
||||
printloop2
|
||||
sty DISPLAY+10
|
||||
iny
|
||||
bne printloop2
|
||||
dex
|
||||
bne printloop
|
||||
|
||||
; ------- fill the screen
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
fillscreen
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user