diff options
| author | James Barnett <noreply@jamesbarnett.xyz> | 2018-06-28 21:38:42 +0100 |
|---|---|---|
| committer | James Barnett <noreply@jamesbarnett.xyz> | 2018-06-28 21:38:42 +0100 |
| commit | dfbf83a9a42907063aa5b3789f1ce9606de32e84 (patch) | |
| tree | eea8e2232f9f6b8841bcf4a3a740cf895afdd629 | |
| parent | 6f87feb0c835589adcd566323e058a9158860071 (diff) | |
| download | KGB-dfbf83a9a42907063aa5b3789f1ce9606de32e84.tar.xz KGB-dfbf83a9a42907063aa5b3789f1ce9606de32e84.zip | |
Add register flags and set from LDHL SP,n op
| -rw-r--r-- | src/main/kotlin/BitManipulation.kt | 11 | ||||
| -rw-r--r-- | src/main/kotlin/cpu/Registers.kt | 32 | ||||
| -rw-r--r-- | src/main/kotlin/cpu/opcodes/Loads16Bit.kt | 23 | ||||
| -rw-r--r-- | src/test/kotlin/RegisterTest.kt | 54 |
4 files changed, 119 insertions, 1 deletions
diff --git a/src/main/kotlin/BitManipulation.kt b/src/main/kotlin/BitManipulation.kt index b4215e8..b655718 100644 --- a/src/main/kotlin/BitManipulation.kt +++ b/src/main/kotlin/BitManipulation.kt @@ -28,4 +28,15 @@ object BitManipulation { } } + fun isSignedBitNegative(value: Int): Boolean { + return value and (1 shl 7) != 0 + } + + fun getAbsoluteValue(value: Int ): Int{ + return if(isSignedBitNegative(value)) { + 0x0100 - value // 1 00000000 - 1xxxxxx = value, due to 2s compliment + } else { + value + } + } }
\ No newline at end of file diff --git a/src/main/kotlin/cpu/Registers.kt b/src/main/kotlin/cpu/Registers.kt index 70c7f06..54539a8 100644 --- a/src/main/kotlin/cpu/Registers.kt +++ b/src/main/kotlin/cpu/Registers.kt @@ -131,4 +131,36 @@ class Registers { return currentSP } + fun getFlag(flag: Flag): Int { + return (F shr flag.bitPosition) and 0x01 + } + + fun setFlag(flag: Flag) { + F = F or (1 shl flag.bitPosition) + } + + fun clearFlag(flag: Flag) { + F = F and (1 shl flag.bitPosition).inv() + } + + fun setFlagFromBool(flag: Flag, isSet: Boolean) { + if(isSet) { + setFlag(flag) + } + else { + clearFlag(flag) + } + } + + fun clearFlags() { + F = 0x00 + } + + enum class Flag(val bitPosition: Int) { + ZERO(7), + SUBTRACT(6), + HALF_CARRY(5), + CARRY(4), + } + }
\ No newline at end of file diff --git a/src/main/kotlin/cpu/opcodes/Loads16Bit.kt b/src/main/kotlin/cpu/opcodes/Loads16Bit.kt index 671a02d..830f6ab 100644 --- a/src/main/kotlin/cpu/opcodes/Loads16Bit.kt +++ b/src/main/kotlin/cpu/opcodes/Loads16Bit.kt @@ -2,6 +2,7 @@ package cpu.opcodes import cpu.Operation import cpu.Registers +import cpu.Registers.Flag import ram.Ram import BitManipulation as bm @@ -15,7 +16,27 @@ var loads16Bit = mapOf( 0xF9 to Operation("LD SP,HL", 0, 8, {r, _, _ -> r.SP = r.HL}), - 0xF8 to Operation("LDHL SP,n", 1, 12, {r, _, a -> r.HL = (r.SP + a[0])}), // TODO - not sure what the flags should be here + 0xF8 to Operation("LDHL SP,n", 1, 12, {r, _, a -> + + // https://stackoverflow.com/questions/5159603/gbz80-how-does-ld-hl-spe-affect-h-and-c-flags + // the carry flag is set if there's an overflow from the 7th to 8th bit. + // the half carry flag is set if there's an overflow from the 3rd into the 4th bit. + r.clearFlags() + + val absoluteValue = bm.getAbsoluteValue(a[0]) + + if (bm.isSignedBitNegative(a[0])) { + r.setFlagFromBool(Flag.HALF_CARRY, r.SP and 0x0F < absoluteValue and 0x0F) + r.setFlagFromBool(Flag.CARRY,r.SP and 0xFF < absoluteValue) + r.HL = r.SP - absoluteValue + + } else { + r.setFlagFromBool(Flag.HALF_CARRY,(r.SP and 0x0F) + (absoluteValue and 0x0F) > 0x0F) + r.setFlagFromBool(Flag.CARRY,(r.SP and 0xFF) + absoluteValue > 0xFF) + r.HL = r.SP + absoluteValue + } + + }), 0x08 to Operation("LD (nn),SP", 2, 20, {r, m, a -> m.writeByte(bm.argsToWord(a), bm.getLsb(r.SP)) m.writeByte(bm.argsToWord(a) + 1, bm.getMsb(r.SP)) diff --git a/src/test/kotlin/RegisterTest.kt b/src/test/kotlin/RegisterTest.kt index 7b9188c..617d6f7 100644 --- a/src/test/kotlin/RegisterTest.kt +++ b/src/test/kotlin/RegisterTest.kt @@ -1,4 +1,6 @@ + import cpu.Registers +import cpu.Registers.Flag import io.kotlintest.shouldBe import io.kotlintest.shouldThrow import io.kotlintest.specs.StringSpec @@ -124,4 +126,56 @@ class RegisterTest : StringSpec({ reg.PC shouldBe 0xAAFE } + "Test flags" { + val reg = Registers() + + reg.getFlag(Flag.ZERO) shouldBe 0 + reg.getFlag(Flag.SUBTRACT) shouldBe 0 + reg.getFlag(Flag.HALF_CARRY) shouldBe 0 + reg.getFlag(Flag.CARRY) shouldBe 0 + + reg.setFlag(Flag.ZERO) + reg.setFlag(Flag.SUBTRACT) + reg.setFlag(Flag.HALF_CARRY) + reg.setFlag(Flag.CARRY) + + reg.getFlag(Flag.ZERO) shouldBe 1 + reg.getFlag(Flag.SUBTRACT) shouldBe 1 + reg.getFlag(Flag.HALF_CARRY) shouldBe 1 + reg.getFlag(Flag.CARRY) shouldBe 1 + reg.F shouldBe 0xF0 + + reg.clearFlag(Flag.ZERO) + reg.clearFlag(Flag.SUBTRACT) + reg.clearFlag(Flag.HALF_CARRY) + reg.clearFlag(Flag.CARRY) + + reg.getFlag(Flag.ZERO) shouldBe 0 + reg.getFlag(Flag.SUBTRACT) shouldBe 0 + reg.getFlag(Flag.HALF_CARRY) shouldBe 0 + reg.getFlag(Flag.CARRY) shouldBe 0 + reg.F shouldBe 0x00 + + reg.setFlag(Flag.ZERO) + reg.setFlag(Flag.HALF_CARRY) + + reg.getFlag(Flag.ZERO) shouldBe 1 + reg.getFlag(Flag.SUBTRACT) shouldBe 0 + reg.getFlag(Flag.HALF_CARRY) shouldBe 1 + reg.getFlag(Flag.CARRY) shouldBe 0 + reg.F shouldBe 0xA0 // 10100000 + + reg.setFlag(Flag.SUBTRACT) + reg.setFlag(Flag.CARRY) + reg.clearFlag(Flag.ZERO) + reg.clearFlag(Flag.HALF_CARRY) + + reg.getFlag(Flag.ZERO) shouldBe 0 + reg.getFlag(Flag.SUBTRACT) shouldBe 1 + reg.getFlag(Flag.HALF_CARRY) shouldBe 0 + reg.getFlag(Flag.CARRY) shouldBe 1 + reg.F shouldBe 0x50 // 01010000 + + } + })
\ No newline at end of file |