diff --git a/accum.go b/accum.go index a83fdd5..8db1235 100644 --- a/accum.go +++ b/accum.go @@ -1,5 +1,7 @@ package z80 +// This file includes functions which related to "accumulator" or "ACL" + import "math/bits" func (cpu *CPU) updateFlagArith8(r, a, b uint16, subtract bool) { diff --git a/accum_test.go b/accum_test.go index 0e18cf8..8fe1ce3 100644 --- a/accum_test.go +++ b/accum_test.go @@ -8,6 +8,121 @@ import ( "github.com/google/go-cmp/cmp" ) +const ( + // C is an index for carry flag. + C = 0 + + // N is an index for add/subtract flag. + N = 1 + + // PV is an index for parity/overflow flag. + PV = 2 + + // X3 is reserved index for unused flag. + //X3 = 3 + + // H is an index for half carry flag. + H = 4 + + // X5 is reserved index for unused flag. + //X5 = 5 + + // Z is an index for zero flag. + Z = 6 + + // S is an index for sign flag. + S = 7 +) + +// flagOp provides flag operation. At initial this will keep all bits. +type flagOp struct { + Nand uint8 + Or uint8 +} + +// ApplyOn applies flag operation on uint8 in place. +func (fo flagOp) ApplyOn(v *uint8) { + *v = *v&^fo.Nand | fo.Or +} + +// Keep marks bit-n as keeping. +func (fo flagOp) Keep(n int) flagOp { + var m uint8 = ^(0x01 << n) + fo.Nand &= m + fo.Or &= m + return fo +} + +// Set marks bit-n as being 1. +func (fo flagOp) Set(n int) flagOp { + var b uint8 = 0x01 << n + fo.Nand |= b + fo.Or |= b + return fo +} + +// Reset marks bit-n as being 0. +func (fo flagOp) Reset(n int) flagOp { + var b uint8 = 0x01 << n + fo.Nand |= b + fo.Or &= ^b + return fo +} + +// Put modify bit-n with boolean value. +func (fo flagOp) Put(n int, v bool) flagOp { + if v { + return fo.Set(n) + } + return fo.Reset(n) +} + +func TestFlagOp_ApplyOn(t *testing.T) { + t.Parallel() + for _, c := range []struct { + op flagOp + v []uint8 + exp []uint8 + }{ + {flagOp{0x00, 0x00}, []uint8{0x01, 0x00}, []uint8{0x01, 0x00}}, + {flagOp{0x01, 0x00}, []uint8{0x01, 0x00}, []uint8{0x00, 0x00}}, + {flagOp{0x01, 0x01}, []uint8{0x01, 0x00}, []uint8{0x01, 0x01}}, + // undefined behavior + {flagOp{0x00, 0x01}, []uint8{0x01, 0x00}, []uint8{0x01, 0x01}}, + + {flagOp{0x00, 0x00}, []uint8{0x10, 0x00}, []uint8{0x10, 0x00}}, + {flagOp{0x10, 0x00}, []uint8{0x10, 0x00}, []uint8{0x00, 0x00}}, + {flagOp{0x10, 0x10}, []uint8{0x10, 0x00}, []uint8{0x10, 0x10}}, + // undefined behavior + {flagOp{0x00, 0x10}, []uint8{0x10, 0x00}, []uint8{0x10, 0x10}}, + + {flagOp{0x00, 0x00}, []uint8{0x11}, []uint8{0x11}}, + { + flagOp{0x11, 0x00}, + []uint8{0x11, 0x10, 0x01, 0x00}, + []uint8{0x00, 0x00, 0x00, 0x00}, + }, + { + flagOp{0x11, 0x11}, + []uint8{0x11, 0x10, 0x01, 0x00}, + []uint8{0x11, 0x11, 0x11, 0x11}, + }, + // undefined behavior + { + flagOp{0x00, 0x11}, + []uint8{0x11, 0x10, 0x01, 0x00}, + []uint8{0x11, 0x11, 0x11, 0x11}, + }, + } { + for i, v := range c.v { + c.op.ApplyOn(&v) + if v != c.exp[i] { + t.Fatalf("failed %#v.ApplyOn(0x%02x): expect=0x%02x actual=0x%02x", c.op, c.v[i], c.exp[i], v) + } + } + } +} + func carry2n(c bool) int { if c { return 1 diff --git a/flag_test.go b/flag_test.go deleted file mode 100644 index f43f35f..0000000 --- a/flag_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package z80 - -import "testing" - -const ( - // C is an index for carry flag. - C = 0 - - // N is an index for add/subtract flag. - N = 1 - - // PV is an index for parity/overflow flag. - PV = 2 - - // X3 is reserved index for unused flag. - //X3 = 3 - - // H is an index for half carry flag. - H = 4 - - // X5 is reserved index for unused flag. - //X5 = 5 - - // Z is an index for zero flag. - Z = 6 - - // S is an index for sign flag. - S = 7 -) - -// flagOp provides flag operation. At initial this will keep all bits. -type flagOp struct { - Nand uint8 - Or uint8 -} - -// ApplyOn applies flag operation on uint8 in place. -func (fo flagOp) ApplyOn(v *uint8) { - *v = *v&^fo.Nand | fo.Or -} - -// Keep marks bit-n as keeping. -func (fo flagOp) Keep(n int) flagOp { - var m uint8 = ^(0x01 << n) - fo.Nand &= m - fo.Or &= m - return fo -} - -// Set marks bit-n as being 1. -func (fo flagOp) Set(n int) flagOp { - var b uint8 = 0x01 << n - fo.Nand |= b - fo.Or |= b - return fo -} - -// Reset marks bit-n as being 0. -func (fo flagOp) Reset(n int) flagOp { - var b uint8 = 0x01 << n - fo.Nand |= b - fo.Or &= ^b - return fo -} - -// Put modify bit-n with boolean value. -func (fo flagOp) Put(n int, v bool) flagOp { - if v { - return fo.Set(n) - } - return fo.Reset(n) -} - -func TestFlagOp_ApplyOn(t *testing.T) { - t.Parallel() - for _, c := range []struct { - op flagOp - v []uint8 - exp []uint8 - }{ - {flagOp{0x00, 0x00}, []uint8{0x01, 0x00}, []uint8{0x01, 0x00}}, - {flagOp{0x01, 0x00}, []uint8{0x01, 0x00}, []uint8{0x00, 0x00}}, - {flagOp{0x01, 0x01}, []uint8{0x01, 0x00}, []uint8{0x01, 0x01}}, - // undefined behavior - {flagOp{0x00, 0x01}, []uint8{0x01, 0x00}, []uint8{0x01, 0x01}}, - - {flagOp{0x00, 0x00}, []uint8{0x10, 0x00}, []uint8{0x10, 0x00}}, - {flagOp{0x10, 0x00}, []uint8{0x10, 0x00}, []uint8{0x00, 0x00}}, - {flagOp{0x10, 0x10}, []uint8{0x10, 0x00}, []uint8{0x10, 0x10}}, - // undefined behavior - {flagOp{0x00, 0x10}, []uint8{0x10, 0x00}, []uint8{0x10, 0x10}}, - - {flagOp{0x00, 0x00}, []uint8{0x11}, []uint8{0x11}}, - { - flagOp{0x11, 0x00}, - []uint8{0x11, 0x10, 0x01, 0x00}, - []uint8{0x00, 0x00, 0x00, 0x00}, - }, - { - flagOp{0x11, 0x11}, - []uint8{0x11, 0x10, 0x01, 0x00}, - []uint8{0x11, 0x11, 0x11, 0x11}, - }, - // undefined behavior - { - flagOp{0x00, 0x11}, - []uint8{0x11, 0x10, 0x01, 0x00}, - []uint8{0x11, 0x11, 0x11, 0x11}, - }, - } { - for i, v := range c.v { - c.op.ApplyOn(&v) - if v != c.exp[i] { - t.Fatalf("failed %#v.ApplyOn(0x%02x): expect=0x%02x actual=0x%02x", c.op, c.v[i], c.exp[i], v) - } - } - } -}