Skip to content

Commit

Permalink
Implement, Subtract with borrow, And, Or, Xor
Browse files Browse the repository at this point in the history
  • Loading branch information
mcribbs committed Dec 31, 2024
1 parent d8be9f5 commit 3aaba6c
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 24 deletions.
42 changes: 21 additions & 21 deletions src/main/scala/CPU.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,34 +98,34 @@ class CPU(ram: Memory):
case (0,0, 0,1,0, 1,0,0) => i.SUI // SUI
case (1,0, 0,1,0, _,_,_) => i.SUr(sss) // SUs

case (1,0, 0,1,1, 1,1,1) => ??? // SBM
case (0,0, 0,1,1, 1,0,0) => ??? // SBI
case (1,0, 0,1,1, _,_,_) => ??? // SBs
case (1,0, 0,1,1, 1,1,1) => i.SBM // SBM
case (0,0, 0,1,1, 1,0,0) => i.SBI // SBI
case (1,0, 0,1,1, _,_,_) => i.SBr(sss) // SBs

case (1,0, 1,0,0, 1,1,1) => ??? // NDM
case (0,0, 1,0,0, 1,0,0) => ??? // NDI
case (1,0, 1,0,0, _,_,_) => ??? // NDs
case (1,0, 1,0,0, 1,1,1) => i.NDM // NDM
case (0,0, 1,0,0, 1,0,0) => i.NDI // NDI
case (1,0, 1,0,0, _,_,_) => i.NDr(sss) // NDs

case (1,0, 1,0,1, 1,1,1) => ??? // XRM
case (0,0, 1,0,1, 1,0,0) => ??? // XRI
case (1,0, 1,0,1, _,_,_) => ??? // XRs
case (1,0, 1,0,1, 1,1,1) => i.XRM // XRM
case (0,0, 1,0,1, 1,0,0) => i.XRI // XRI
case (1,0, 1,0,1, _,_,_) => i.XRr(sss) // XRs

case (1,0, 1,1,0, 1,1,1) => ??? // ORM
case (0,0, 1,1,0, 1,0,0) => ??? // ORI
case (1,0, 1,1,0, _,_,_) => ??? // ORs
case (1,0, 1,1,0, 1,1,1) => i.ORM // ORM
case (0,0, 1,1,0, 1,0,0) => i.ORI // ORI
case (1,0, 1,1,0, _,_,_) => i.ORr(sss) // ORs

case (1,0, 1,1,1, 1,1,1) => ??? // CPM
case (0,0, 1,1,1, 1,0,0) => ??? // CPI
case (1,0, 1,1,1, _,_,_) => ??? // CPs
case (1,0, 1,1,1, 1,1,1) => ??? // CPM
case (0,0, 1,1,1, 1,0,0) => ??? // CPI
case (1,0, 1,1,1, _,_,_) => ??? // CPs

case (0,0, _,_,_, 0,0,0) => i.INr(ddd) // INd
case (0,0, _,_,_, 0,0,1) => i.DCr(ddd) // DCd
case (0,0, _,_,_, 0,0,0) => i.INr(ddd) // INd
case (0,0, _,_,_, 0,0,1) => i.DCr(ddd) // DCd

// Rotate group
case (0,0, 0,0,0, 0,1,0) => ??? // RLC
case (0,0, 0,0,1, 0,1,0) => ??? // RRC
case (0,0, 0,1,0, 0,1,0) => ??? // RAL
case (0,0, 0,1,1, 0,1,0) => ??? // RAR
case (0,0, 0,0,0, 0,1,0) => ??? // RLC
case (0,0, 0,0,1, 0,1,0) => ??? // RRC
case (0,0, 0,1,0, 0,1,0) => ??? // RAL
case (0,0, 0,1,1, 0,1,0) => ??? // RAR
}
t2
}
22 changes: 21 additions & 1 deletion src/main/scala/Instructions.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package net.mcribbs.s8008

import spire.math.UByte
import spire.math.UByte

class Instructions(state: CPUState):

Expand Down Expand Up @@ -69,6 +69,21 @@ class Instructions(state: CPUState):
def SUI: CPUState = doALU(ADDRESSING_MODE.I, Register.A, subtract)
def SUr(s: Register): CPUState = doALU(ADDRESSING_MODE.R, s, subtract)

def SBM: CPUState = doALU(ADDRESSING_MODE.M, Register.A, subtractWithBorrow)
def SBI: CPUState = doALU(ADDRESSING_MODE.I, Register.A, subtractWithBorrow)
def SBr(s: Register): CPUState = doALU(ADDRESSING_MODE.R, s, subtractWithBorrow)

def NDM: CPUState = doALU(ADDRESSING_MODE.M, Register.A, (a, b) => (a & b, false))
def NDI: CPUState = doALU(ADDRESSING_MODE.I, Register.A, (a, b) => (a & b, false))
def NDr(s: Register): CPUState = doALU(ADDRESSING_MODE.R, s, (a, b) => (a & b, false))

def XRM: CPUState = doALU(ADDRESSING_MODE.M, Register.A, (a, b) => (a ^ b, false))
def XRI: CPUState = doALU(ADDRESSING_MODE.I, Register.A, (a, b) => (a ^ b, false))
def XRr(s: Register): CPUState = doALU(ADDRESSING_MODE.R, s, (a, b) => (a ^ b, false))

def ORM: CPUState = doALU(ADDRESSING_MODE.M, Register.A, (a, b) => (a | b, false))
def ORI: CPUState = doALU(ADDRESSING_MODE.I, Register.A, (a, b) => (a | b, false))
def ORr(s: Register): CPUState = doALU(ADDRESSING_MODE.R, s, (a, b) => (a | b, false))

private def add(a: UByte, b: UByte): (UByte, Boolean) =
val c = a + b
Expand All @@ -85,6 +100,11 @@ class Instructions(state: CPUState):
val carry = (c > a) && (c > b)
(c, carry)

private def subtractWithBorrow(a: UByte, b: UByte): (UByte, Boolean) =
val c = a - b - UByte(state.flags.carry.compare(false))
val carry = (c > a) && (c > b)
(c, carry)

private def doALU(mode: ADDRESSING_MODE, source: Register, f: (UByte, UByte) => (UByte, Boolean)): CPUState =
val (data: UByte, s: CPUState) = mode match {
case ADDRESSING_MODE.M => (state.ram.readByte(state.registers.HL), state.incrementPC)
Expand Down
207 changes: 205 additions & 2 deletions src/test/scala/ArithmeticGroupInstructionsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class ArithmeticGroupInstructionsTest extends AnyWordSpec {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x87))
.writeByte(0x0001, UByte(0x05))
val cpu = new CPU(ram)
val test = cpu.state.toString
cpu.state = cpu.state.withRegister(Register.A, UByte(0xFF))
.withRegister(Register.H, UByte(0x00)).withRegister(Register.L, UByte(0x01))
val state = cpu.step
Expand Down Expand Up @@ -111,7 +110,6 @@ class ArithmeticGroupInstructionsTest extends AnyWordSpec {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x97))
.writeByte(0x0001, UByte(0x05))
val cpu = new CPU(ram)
val test = cpu.state.toString
cpu.state = cpu.state.withRegister(Register.A, UByte(0xFF))
.withRegister(Register.H, UByte(0x00)).withRegister(Register.L, UByte(0x01))
val state = cpu.step
Expand Down Expand Up @@ -156,6 +154,211 @@ class ArithmeticGroupInstructionsTest extends AnyWordSpec {
}
}

"SBM" should {
"Add the content of memory register M to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x9F))
.writeByte(0x0001, UByte(0x05))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0xFF))
.withRegister(Register.H, UByte(0x00)).withRegister(Register.L, UByte(0x01))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0xF9))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(state.flags.sign)
assert(state.flags.parity)
// TODO more flag tests
}
}

"SBI" should {
"Add the content of data B...B to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x1C))
.writeByte(0x0001, UByte(0x05))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0xFF))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0xF9))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(state.flags.sign)
assert(state.flags.parity)
// TODO more flag tests
}
}

"SBr" should {
"Add the content of index register r and carry flag to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x99))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0xFF)).withRegister(Register.B, UByte(0x05))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0xF9))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(state.flags.sign)
assert(state.flags.parity)
// TODO more flag tests

}
}

"NDM" should {
"Add the content of memory register M to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0xA7))
.writeByte(0x0001, UByte(0x0D))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C))
.withRegister(Register.H, UByte(0x00)).withRegister(Register.L, UByte(0x01))
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x0C))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(state.flags.parity)
// TODO more flag tests
}
}

"NDI" should {
"Add the content of data B...B to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x24))
.writeByte(0x0001, UByte(0x0D))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x0C))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(state.flags.parity)
// TODO more flag tests
}
}

"NDr" should {
"Add the content of index register r and carry flag to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0xA1))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C)).withRegister(Register.B, UByte(0x0D))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x0C))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(state.flags.parity)
// TODO more flag tests

}
}

"XRM" should {
"Add the content of memory register M to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0xAF))
.writeByte(0x0001, UByte(0x0D))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C))
.withRegister(Register.H, UByte(0x00)).withRegister(Register.L, UByte(0x01))
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x31))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(!state.flags.parity)
// TODO more flag tests
}
}

"XRI" should {
"Add the content of data B...B to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x2C))
.writeByte(0x0001, UByte(0x0D))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x31))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(!state.flags.parity)
// TODO more flag tests
}
}

"XRr" should {
"Add the content of index register r and carry flag to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0xA9))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C)).withRegister(Register.B, UByte(0x0D))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x31))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(!state.flags.parity)
// TODO more flag tests

}
}

"ORM" should {
"Add the content of memory register M to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0xB7))
.writeByte(0x0001, UByte(0x0D))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C))
.withRegister(Register.H, UByte(0x00)).withRegister(Register.L, UByte(0x01))
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x3D))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(!state.flags.parity)
// TODO more flag tests
}
}

"ORI" should {
"Add the content of data B...B to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x34))
.writeByte(0x0001, UByte(0x0D))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x3D))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(!state.flags.parity)
// TODO more flag tests
}
}

"ORr" should {
"Add the content of index register r and carry flag to the accumulator and properly set the flags" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0xB1))
val cpu = new CPU(ram)
cpu.state = cpu.state.withRegister(Register.A, UByte(0x3C)).withRegister(Register.B, UByte(0x0D))
.withFlag(Flag.C, true)
val state = cpu.step
assert(state.getRegister(Register.A) == UByte(0x3D))
assert(!state.flags.carry)
assert(!state.flags.zero)
assert(!state.flags.sign)
assert(!state.flags.parity)
// TODO more flag tests

}
}

"INr" should {
"increment the contents of register r and set ZSP" in {
val ram = Memory(new Array[UByte](Memory.MAX_MEMORY)).writeByte(0x0000, UByte(0x08))
Expand Down

0 comments on commit 3aaba6c

Please sign in to comment.