2019-09-20 20:12:58 +00:00
|
|
|
package razorvine.examplemachines
|
2019-09-15 03:04:57 +00:00
|
|
|
|
2019-10-09 01:24:51 +00:00
|
|
|
import razorvine.ksim65.*
|
2019-09-15 03:04:57 +00:00
|
|
|
import razorvine.ksim65.components.*
|
2019-10-08 21:11:18 +00:00
|
|
|
import java.io.File
|
|
|
|
import javax.swing.ImageIcon
|
|
|
|
import javax.swing.JOptionPane
|
2019-10-07 21:28:04 +00:00
|
|
|
|
2019-09-15 03:04:57 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A virtual computer constructed from the various virtual components
|
|
|
|
*/
|
2019-09-19 19:29:33 +00:00
|
|
|
class VirtualMachine(title: String) : IVirtualMachine {
|
|
|
|
override val bus = Bus()
|
2019-09-29 09:29:11 +00:00
|
|
|
override val cpu = Cpu6502()
|
2019-09-15 03:04:57 +00:00
|
|
|
val ram = Ram(0x0000, 0xffff)
|
|
|
|
private val rtc = RealTimeClock(0xd100, 0xd108)
|
|
|
|
private val timer = Timer(0xd200, 0xd203, cpu)
|
|
|
|
|
2019-10-09 01:24:51 +00:00
|
|
|
private val monitor = Monitor(bus, cpu)
|
2019-09-15 03:04:57 +00:00
|
|
|
private val debugWindow = DebugWindow(this)
|
2019-09-18 23:22:11 +00:00
|
|
|
private val hostDisplay = MainWindow(title)
|
2019-10-13 06:16:28 +00:00
|
|
|
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS)
|
2019-09-18 18:57:46 +00:00
|
|
|
private val mouse = Mouse(0xd300, 0xd305, hostDisplay)
|
2019-09-15 03:04:57 +00:00
|
|
|
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
|
2019-09-20 20:12:58 +00:00
|
|
|
private var paused = false
|
2019-09-15 03:04:57 +00:00
|
|
|
|
|
|
|
init {
|
|
|
|
ram[Cpu6502.RESET_vector] = 0x00
|
2019-10-12 10:35:18 +00:00
|
|
|
ram[Cpu6502.RESET_vector+1] = 0x10
|
2019-09-28 23:26:31 +00:00
|
|
|
ram.loadPrg(javaClass.getResourceAsStream("/vmdemo.prg"), null)
|
2019-09-15 03:04:57 +00:00
|
|
|
|
|
|
|
bus += rtc
|
|
|
|
bus += timer
|
|
|
|
bus += display
|
|
|
|
bus += mouse
|
|
|
|
bus += keyboard
|
|
|
|
bus += ram
|
|
|
|
bus += cpu
|
|
|
|
bus.reset()
|
|
|
|
|
2019-10-05 13:14:26 +00:00
|
|
|
hostDisplay.iconImage = ImageIcon(javaClass.getResource("/icon.png")).image
|
|
|
|
debugWindow.iconImage = hostDisplay.iconImage
|
2019-10-12 10:35:18 +00:00
|
|
|
debugWindow.setLocation(hostDisplay.location.x+hostDisplay.width, hostDisplay.location.y)
|
2019-09-15 03:04:57 +00:00
|
|
|
debugWindow.isVisible = true
|
2019-09-19 19:29:33 +00:00
|
|
|
hostDisplay.isVisible = true
|
2019-10-04 18:39:57 +00:00
|
|
|
hostDisplay.start(30)
|
2019-09-15 03:04:57 +00:00
|
|
|
}
|
|
|
|
|
2020-02-01 16:19:43 +00:00
|
|
|
override fun getZeroAndStackPages(): Array<UByte> = ram.getBlock(0, 512)
|
2019-09-21 13:57:14 +00:00
|
|
|
|
2019-09-23 23:22:54 +00:00
|
|
|
override fun loadFileInRam(file: File, loadAddress: Address?) {
|
2019-10-12 10:35:18 +00:00
|
|
|
if (file.extension == "prg" && loadAddress == null) ram.loadPrg(file.inputStream(), null)
|
|
|
|
else ram.load(file.readBytes(), loadAddress!!)
|
2019-09-23 23:22:54 +00:00
|
|
|
}
|
|
|
|
|
2019-09-20 20:12:58 +00:00
|
|
|
override fun pause(paused: Boolean) {
|
|
|
|
this.paused = paused
|
|
|
|
}
|
2019-09-15 03:04:57 +00:00
|
|
|
|
2019-09-20 20:12:58 +00:00
|
|
|
override fun step() {
|
|
|
|
// step a full single instruction
|
2019-09-16 00:31:48 +00:00
|
|
|
while (cpu.instrCycles > 0) bus.clock()
|
|
|
|
bus.clock()
|
|
|
|
while (cpu.instrCycles > 0) bus.clock()
|
|
|
|
}
|
|
|
|
|
2020-03-01 17:38:00 +00:00
|
|
|
override fun reset() {
|
|
|
|
bus.reset()
|
|
|
|
hostDisplay.reset()
|
|
|
|
}
|
|
|
|
|
2019-10-09 01:24:51 +00:00
|
|
|
override fun executeMonitorCommand(command: String) = monitor.command(command)
|
|
|
|
|
2019-09-16 00:31:48 +00:00
|
|
|
fun start() {
|
2019-10-02 00:13:29 +00:00
|
|
|
javax.swing.Timer(50) {
|
2019-09-21 13:57:14 +00:00
|
|
|
debugWindow.updateCpu(cpu, bus)
|
|
|
|
}.start()
|
2019-09-27 20:38:36 +00:00
|
|
|
|
2019-10-13 06:16:28 +00:00
|
|
|
// a simple loop to run the cpu, not targeting a specific desired clock frequency
|
|
|
|
// (but with a small sleep to not run flat out)
|
|
|
|
while(true) {
|
|
|
|
if(paused) {
|
|
|
|
Thread.sleep(200)
|
|
|
|
} else {
|
2019-10-08 21:11:18 +00:00
|
|
|
try {
|
2020-02-16 12:39:46 +00:00
|
|
|
repeat(500) { step() }
|
2019-10-12 10:35:18 +00:00
|
|
|
} catch (rx: RuntimeException) {
|
2019-10-08 21:11:18 +00:00
|
|
|
JOptionPane.showMessageDialog(hostDisplay, "Run time error: $rx", "Error during execution", JOptionPane.ERROR_MESSAGE)
|
2019-10-13 06:16:28 +00:00
|
|
|
break
|
2019-10-12 10:35:18 +00:00
|
|
|
} catch (ex: Error) {
|
2019-10-08 21:11:18 +00:00
|
|
|
JOptionPane.showMessageDialog(hostDisplay, "Run time error: $ex", "Error during execution", JOptionPane.ERROR_MESSAGE)
|
2019-10-13 06:16:28 +00:00
|
|
|
break
|
2019-10-07 21:28:04 +00:00
|
|
|
}
|
2020-02-16 12:39:46 +00:00
|
|
|
Thread.sleep(10)
|
2019-09-16 00:31:48 +00:00
|
|
|
}
|
2019-09-15 03:04:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-27 22:44:56 +00:00
|
|
|
fun main() {
|
2019-09-15 03:04:57 +00:00
|
|
|
val machine = VirtualMachine("KSim65 demo virtual machine - using ksim65 v${Version.version}")
|
2019-09-16 00:31:48 +00:00
|
|
|
machine.start()
|
2019-09-15 03:04:57 +00:00
|
|
|
}
|