From fc1ad39a8dbe3d0c5ae8395cf3fda37d2b13b523 Mon Sep 17 00:00:00 2001 From: Adrian Conlon Date: Mon, 11 May 2026 22:27:30 +0100 Subject: [PATCH] Add half-carry tests --- MC6809/MC6809.UnitTest/AddTests.cs | 26 ++++++++++++++++++++++++++ MC6809/MC6809.UnitTest/DecTests.cs | 24 ++++++++++++++++++++++++ MC6809/MC6809.UnitTest/IncTests.cs | 24 ++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/MC6809/MC6809.UnitTest/AddTests.cs b/MC6809/MC6809.UnitTest/AddTests.cs index 47f5596..692eb83 100644 --- a/MC6809/MC6809.UnitTest/AddTests.cs +++ b/MC6809/MC6809.UnitTest/AddTests.cs @@ -59,6 +59,32 @@ namespace MC6809.UnitTest Assert.AreEqual(2, this.cpu.Cycles); } + // 0x08 + 0x08 = 0x10: carry out of low nibble sets H + [TestMethod] + public void TestImmediateADDA_half_carry_set() + { + this.board.Poke(0, 0x8b); + this.board.Poke(1, 0x08); + this.cpu.CC = 0; + this.cpu.A = 0x08; + this.cpu.Step(); + Assert.AreEqual(0x10, this.cpu.A); + Assert.IsTrue(this.cpu.HalfCarry); + } + + // 0x01 + 0x01 = 0x02: no carry out of low nibble, H clear + [TestMethod] + public void TestImmediateADDA_half_carry_clear() + { + this.board.Poke(0, 0x8b); + this.board.Poke(1, 0x01); + this.cpu.CC = 0; + this.cpu.A = 0x01; + this.cpu.Step(); + Assert.AreEqual(0x02, this.cpu.A); + Assert.IsFalse(this.cpu.HalfCarry); + } + // The overflow (V) bit indicates signed two’s complement overflow, which occurs when the // sign bit differs from the carry bit after an arithmetic operation. // A=0x03 + 0xFF becomes 0x02 diff --git a/MC6809/MC6809.UnitTest/DecTests.cs b/MC6809/MC6809.UnitTest/DecTests.cs index b0ece2d..0ff5aae 100644 --- a/MC6809/MC6809.UnitTest/DecTests.cs +++ b/MC6809/MC6809.UnitTest/DecTests.cs @@ -69,5 +69,29 @@ namespace MC6809.UnitTest Assert.IsTrue(this.cpu.Negative); Assert.AreEqual(2, this.cpu.Cycles); } + + // DEC does not affect H: H=1 before must be H=1 after + [TestMethod] + public void TestInherentDECA_preserves_half_carry_set() + { + this.board.Poke(0, 0x4a); + this.cpu.CC = (byte)StatusBits.HF; + this.cpu.A = 0x10; + this.cpu.Step(); + Assert.AreEqual(0x0f, this.cpu.A); + Assert.IsTrue(this.cpu.HalfCarry); + } + + // DEC does not affect H: H=0 before must be H=0 after + [TestMethod] + public void TestInherentDECA_preserves_half_carry_clear() + { + this.board.Poke(0, 0x4a); + this.cpu.CC = 0; + this.cpu.A = 0x10; + this.cpu.Step(); + Assert.AreEqual(0x0f, this.cpu.A); + Assert.IsFalse(this.cpu.HalfCarry); + } } } diff --git a/MC6809/MC6809.UnitTest/IncTests.cs b/MC6809/MC6809.UnitTest/IncTests.cs index da1d69a..d323444 100644 --- a/MC6809/MC6809.UnitTest/IncTests.cs +++ b/MC6809/MC6809.UnitTest/IncTests.cs @@ -67,5 +67,29 @@ namespace MC6809.UnitTest Assert.IsFalse(this.cpu.Carry); Assert.AreEqual(2, this.cpu.Cycles); } + + // INC does not affect H: H=1 before must be H=1 after + [TestMethod] + public void TestInherentINCA_preserves_half_carry_set() + { + this.board.Poke(0, 0x4c); + this.cpu.CC = (byte)StatusBits.HF; + this.cpu.A = 0x01; + this.cpu.Step(); + Assert.AreEqual(0x02, this.cpu.A); + Assert.IsTrue(this.cpu.HalfCarry); + } + + // INC does not affect H: a nibble-crossing increment must not set H=1 + [TestMethod] + public void TestInherentINCA_preserves_half_carry_clear() + { + this.board.Poke(0, 0x4c); + this.cpu.CC = 0; + this.cpu.A = 0x0f; + this.cpu.Step(); + Assert.AreEqual(0x10, this.cpu.A); + Assert.IsFalse(this.cpu.HalfCarry); + } } }