aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Barnett <noreply@jamesbarnett.xyz>2018-07-21 19:46:20 +0100
committerJames Barnett <noreply@jamesbarnett.xyz>2018-07-21 19:46:20 +0100
commitc6a953d722b1fdc27a9db6f78f00c52fe43a7222 (patch)
tree6efab06c40d0bd3c26876ca2b40f2f0f20b2def2
parent2861f2db6f918c48019c1ac3f91bf6a407452493 (diff)
downloadKGB-c6a953d722b1fdc27a9db6f78f00c52fe43a7222.tar.xz
KGB-c6a953d722b1fdc27a9db6f78f00c52fe43a7222.zip
Add ability to step through CPU execution of boot rom
-rw-r--r--src/main/kotlin/cpu/Cpu.kt61
-rw-r--r--src/main/kotlin/gui/CpuRegisterWindow.kt2
-rw-r--r--src/main/kotlin/gui/RunControlWindow.kt46
-rw-r--r--src/main/kotlin/gui/WindowContainer.kt6
-rw-r--r--src/main/kotlin/ram/Ram.kt7
-rw-r--r--src/main/resources/roms/boot-rom.gbbin0 -> 256 bytes
6 files changed, 121 insertions, 1 deletions
diff --git a/src/main/kotlin/cpu/Cpu.kt b/src/main/kotlin/cpu/Cpu.kt
index 91150c4..f474dbb 100644
--- a/src/main/kotlin/cpu/Cpu.kt
+++ b/src/main/kotlin/cpu/Cpu.kt
@@ -2,12 +2,16 @@ package cpu
import cpu.opcodes.*
import ram.Ram
+import kotlin.concurrent.thread
class Cpu {
val registers = Registers()
val ram = Ram()
+ var currentOp: Operation? = null
+ var nextOp: Operation? = null
+
var standardOpcodes: Map<Int, Operation>
var extendedOpcodes: Map<Int, Operation>
init {
@@ -33,4 +37,61 @@ class Cpu {
}
+ fun loadRom(rom: ByteArray) {
+ ram.load(rom)
+ }
+
+ fun executeNextInstruction() {
+
+ val (op, opArgs) = getNextOp()
+ op.command.invoke(registers, ram, opArgs)
+
+ currentOp = op
+ nextOp = peekNextOp()
+ }
+
+ fun run() {
+ thread {
+ while(true) {
+ executeNextInstruction()
+ }
+ }
+
+ }
+
+ private fun getNextOp(): Pair<Operation, IntArray> {
+
+ var addr = registers.PC
+ val startByte = ram.readByte(addr)
+ val op: Operation
+
+ op = if(startByte == 0xCB) {
+ extendedOpcodes[ram.readByte(++addr)]!!
+ } else {
+ standardOpcodes[startByte]!!
+ }
+
+ val opLength = op.length
+ val opArgs = IntArray(opLength)
+
+ IntRange(0, opLength -1).forEach {i ->
+ opArgs[i] = ram.readByte(++addr)
+ }
+
+ registers.PC = ++addr
+
+ return Pair(op, opArgs)
+ }
+
+
+ private fun peekNextOp(): Operation {
+
+ val startByte = ram.readByte(registers.PC)
+ return if(startByte == 0xCB) {
+ extendedOpcodes[ram.readByte(registers.PC + 1)]!!
+ } else {
+ standardOpcodes[startByte]!!
+ }
+ }
+
} \ No newline at end of file
diff --git a/src/main/kotlin/gui/CpuRegisterWindow.kt b/src/main/kotlin/gui/CpuRegisterWindow.kt
index 0de7ad6..618d298 100644
--- a/src/main/kotlin/gui/CpuRegisterWindow.kt
+++ b/src/main/kotlin/gui/CpuRegisterWindow.kt
@@ -7,7 +7,7 @@ import imgui.ImGui
fun paintCpuRegisterWindow(registers: Registers) {
with(ImGui) {
- setNextWindowSize(Vec2(200, 300), Cond.FirstUseEver)
+ setNextWindowSize(Vec2(200, 250), Cond.FirstUseEver)
setNextWindowPos(Vec2(20, 150), Cond.FirstUseEver)
begin("CPU state")
diff --git a/src/main/kotlin/gui/RunControlWindow.kt b/src/main/kotlin/gui/RunControlWindow.kt
new file mode 100644
index 0000000..8ffc764
--- /dev/null
+++ b/src/main/kotlin/gui/RunControlWindow.kt
@@ -0,0 +1,46 @@
+package gui
+
+import cpu.Cpu
+import glm_.vec2.Vec2
+import imgui.Cond
+import imgui.ImGui
+
+fun paintRunControlWindow(cpu: Cpu) {
+ with(ImGui) {
+
+ setNextWindowPos(Vec2(20, 410), Cond.FirstUseEver)
+ begin("Run control")
+
+ text("Current op:")
+ separator()
+ if(cpu.currentOp != null) {
+ text(cpu.currentOp!!.name)
+ }
+ else {
+ text("None")
+ }
+
+ newLine()
+
+ text("Next op:")
+ separator()
+ if(cpu.nextOp != null) {
+ text(cpu.nextOp!!.name)
+ }
+ else {
+ text("None")
+ }
+
+ newLine()
+
+ text("Control:")
+ separator()
+
+
+ if(button("Step")) {
+ cpu.executeNextInstruction()
+ }
+
+ end()
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/gui/WindowContainer.kt b/src/main/kotlin/gui/WindowContainer.kt
index 5e101b7..4d58c18 100644
--- a/src/main/kotlin/gui/WindowContainer.kt
+++ b/src/main/kotlin/gui/WindowContainer.kt
@@ -10,6 +10,7 @@ import imgui.impl.LwjglGL3
import org.lwjgl.opengl.GL11
import uno.glfw.GlfwWindow
import uno.glfw.glfw
+import java.io.File
class WindowContainer {
@@ -18,6 +19,10 @@ class WindowContainer {
init {
glfw.init("3.2")
cpu = Cpu()
+ val file = File("src/main/resources/roms/boot-rom.gb")
+ val rom = file.readBytes()
+ cpu.loadRom(rom)
+ //cpu.run()
}
val window = GlfwWindow(1280, 720, "KGB - KotlinGameBoy").apply {
@@ -52,6 +57,7 @@ class WindowContainer {
paintDebugWindow()
paintEmulationOutputWindow()
paintCpuRegisterWindow(cpu.registers)
+ paintRunControlWindow(cpu)
}
gln.glViewport(window.framebufferSize)
diff --git a/src/main/kotlin/ram/Ram.kt b/src/main/kotlin/ram/Ram.kt
index 93336a7..7614040 100644
--- a/src/main/kotlin/ram/Ram.kt
+++ b/src/main/kotlin/ram/Ram.kt
@@ -13,4 +13,11 @@ class Ram {
ram[address] = data
}
+ fun load(rom: ByteArray) {
+
+ rom.forEachIndexed{i, b ->
+ ram[i] = b.toInt() and 0xFF
+ }
+ }
+
} \ No newline at end of file
diff --git a/src/main/resources/roms/boot-rom.gb b/src/main/resources/roms/boot-rom.gb
new file mode 100644
index 0000000..afa0ee4
--- /dev/null
+++ b/src/main/resources/roms/boot-rom.gb
Binary files differ