diff --git a/MC6809/MC6809.UnitTest/SchwotzerArithmeticTests.cs b/MC6809/MC6809.UnitTest/SchwotzerArithmeticTests.cs new file mode 100644 index 0000000..92ade1e --- /dev/null +++ b/MC6809/MC6809.UnitTest/SchwotzerArithmeticTests.cs @@ -0,0 +1,267 @@ +// +// Copyright (c) Adrian Conlon. All rights reserved. +// + +// Test data from W. Schwotzer's MC6809 CPU Emulation Validation suite, +// verified on an SGS Thomson EF6809P processor. + +namespace MC6809.UnitTest +{ + [TestClass] + public class SchwotzerArithmeticTests + { + private readonly Board board = new(); + private readonly MC6809 cpu; + + public SchwotzerArithmeticTests() => this.cpu = this.board.CPU; + + [TestInitialize] + public void Initialise() { this.board.RaisePOWER(); this.cpu.Step(); } + + [TestCleanup] + public void Cleanup() => this.board.LowerPOWER(); + + // ADD (ADDB immediate): checks HNZVC ($2F) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x00, 0x04)] + [DataRow(0x00, 0x01, 0x01, 0x00)] + [DataRow(0x40, 0x40, 0x80, 0x0A)] + [DataRow(0x00, 0x80, 0x80, 0x08)] + [DataRow(0x80, 0x80, 0x00, 0x07)] + [DataRow(0x40, 0x80, 0xC0, 0x08)] + [DataRow(0x7F, 0x7F, 0xFE, 0x2A)] + [DataRow(0x7F, 0x80, 0xFF, 0x08)] + [DataRow(0x80, 0x7F, 0xFF, 0x08)] + [DataRow(0x7F, 0x01, 0x80, 0x2A)] + [DataRow(0x80, 0x01, 0x81, 0x08)] + [DataRow(0x40, 0xC0, 0x00, 0x05)] + [DataRow(0x40, 0xC1, 0x01, 0x01)] + [DataRow(0xFF, 0xFF, 0xFE, 0x29)] + [DataRow(0x81, 0x80, 0x01, 0x03)] + public void TestADDB(int operand, int data, int expected, int flags) + { + this.board.Poke(0, 0xCB); + this.board.Poke(1, (byte)data); + this.cpu.CC = 0; + this.cpu.B = (byte)operand; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.B); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x2F)); + } + + // ADDD (immediate): checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x0000, 0x0000, 0x0000, 0x04)] + [DataRow(0x0000, 0x0001, 0x0001, 0x00)] + [DataRow(0x4000, 0x4000, 0x8000, 0x0A)] + [DataRow(0x0000, 0x8000, 0x8000, 0x08)] + [DataRow(0x8000, 0x8000, 0x0000, 0x07)] + [DataRow(0x4000, 0x8000, 0xC000, 0x08)] + [DataRow(0x7FFF, 0x7FFF, 0xFFFE, 0x0A)] + [DataRow(0x7FFF, 0x8000, 0xFFFF, 0x08)] + [DataRow(0x7FFF, 0x0001, 0x8000, 0x0A)] + [DataRow(0x8000, 0x0001, 0x8001, 0x08)] + [DataRow(0x4000, 0xC000, 0x0000, 0x05)] + [DataRow(0x4000, 0xC001, 0x0001, 0x01)] + [DataRow(0xFFFF, 0xFFFF, 0xFFFE, 0x09)] + [DataRow(0x8001, 0x8000, 0x0001, 0x03)] + public void TestADDD(int operand, int data, int expected, int flags) + { + this.board.Poke(0, 0xC3); + this.board.Poke(1, (byte)(data >> 8)); + this.board.Poke(2, (byte)(data & 0xFF)); + this.cpu.CC = 0; + this.cpu.D.Word = (ushort)operand; + this.cpu.Step(); + Assert.AreEqual((ushort)expected, this.cpu.D.Word); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // ADC (ADCA immediate): carry-in from carryIn; checks HNZVC ($2F) + [DataTestMethod] + [DataRow(0x00, 0, 0x00, 0x00, 0x04)] + [DataRow(0x00, 0, 0x01, 0x01, 0x00)] + [DataRow(0x40, 0, 0x40, 0x80, 0x0A)] + [DataRow(0x00, 0, 0x80, 0x80, 0x08)] + [DataRow(0x80, 0, 0x80, 0x00, 0x07)] + [DataRow(0x40, 0, 0x80, 0xC0, 0x08)] + [DataRow(0x7F, 0, 0x7F, 0xFE, 0x2A)] + [DataRow(0x7F, 0, 0x80, 0xFF, 0x08)] + [DataRow(0x80, 0, 0x7F, 0xFF, 0x08)] + [DataRow(0x7F, 0, 0x01, 0x80, 0x2A)] + [DataRow(0x80, 0, 0x01, 0x81, 0x08)] + [DataRow(0x40, 0, 0xC0, 0x00, 0x05)] + [DataRow(0x40, 0, 0xC1, 0x01, 0x01)] + [DataRow(0xFF, 0, 0xFF, 0xFE, 0x29)] + [DataRow(0x81, 0, 0x80, 0x01, 0x03)] + [DataRow(0x00, 1, 0x00, 0x01, 0x00)] + [DataRow(0x00, 1, 0x01, 0x02, 0x00)] + [DataRow(0x40, 1, 0x40, 0x81, 0x0A)] + [DataRow(0x00, 1, 0x80, 0x81, 0x08)] + [DataRow(0x80, 1, 0x80, 0x01, 0x03)] + [DataRow(0x40, 1, 0x80, 0xC1, 0x08)] + [DataRow(0x7F, 1, 0x7F, 0xFF, 0x2A)] + [DataRow(0x7F, 1, 0x80, 0x00, 0x25)] + [DataRow(0x80, 1, 0x7F, 0x00, 0x25)] + [DataRow(0x7F, 1, 0x01, 0x81, 0x2A)] + [DataRow(0x80, 1, 0x01, 0x82, 0x08)] + [DataRow(0x40, 1, 0xC0, 0x01, 0x01)] + [DataRow(0x40, 1, 0xC1, 0x02, 0x01)] + [DataRow(0xFF, 1, 0xFF, 0xFF, 0x29)] + [DataRow(0x81, 1, 0x80, 0x02, 0x03)] + public void TestADCA(int operand, int carryIn, int data, int expected, int flags) + { + this.board.Poke(0, 0x89); + this.board.Poke(1, (byte)data); + this.cpu.CC = (byte)carryIn; + this.cpu.A = (byte)operand; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x2F)); + } + + // SUB (SUBB immediate): checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x00, 0x04)] + [DataRow(0x00, 0x01, 0xFF, 0x09)] + [DataRow(0x00, 0x7F, 0x81, 0x09)] + [DataRow(0x00, 0x80, 0x80, 0x0B)] + [DataRow(0x00, 0xFF, 0x01, 0x01)] + [DataRow(0x01, 0x00, 0x01, 0x00)] + [DataRow(0x01, 0x7F, 0x82, 0x09)] + [DataRow(0x40, 0x41, 0xFF, 0x09)] + [DataRow(0x40, 0x80, 0xC0, 0x0B)] + [DataRow(0x40, 0xC0, 0x80, 0x0B)] + [DataRow(0x40, 0xC1, 0x7F, 0x01)] + [DataRow(0x7F, 0x00, 0x7F, 0x00)] + [DataRow(0x7F, 0x01, 0x7E, 0x00)] + [DataRow(0x7F, 0x7E, 0x01, 0x00)] + [DataRow(0x7F, 0x7F, 0x00, 0x04)] + [DataRow(0x7F, 0x80, 0xFF, 0x0B)] + [DataRow(0x7F, 0xFF, 0x80, 0x0B)] + [DataRow(0x80, 0x01, 0x7F, 0x02)] + [DataRow(0x80, 0x40, 0x40, 0x02)] + [DataRow(0x80, 0x7F, 0x01, 0x02)] + [DataRow(0x80, 0x80, 0x00, 0x04)] + [DataRow(0x80, 0x81, 0xFF, 0x09)] + [DataRow(0x81, 0x80, 0x01, 0x00)] + [DataRow(0xFF, 0xFF, 0x00, 0x04)] + [DataRow(0xFF, 0xFE, 0x01, 0x00)] + [DataRow(0xFF, 0x00, 0xFF, 0x08)] + public void TestSUBB(int operand, int data, int expected, int flags) + { + this.board.Poke(0, 0xC0); + this.board.Poke(1, (byte)data); + this.cpu.CC = 0; + this.cpu.B = (byte)operand; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.B); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // SUBD (immediate): checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x0000, 0x0000, 0x0000, 0x04)] + [DataRow(0x0000, 0x0001, 0xFFFF, 0x09)] + [DataRow(0x0000, 0x7FFF, 0x8001, 0x09)] + [DataRow(0x0000, 0x8000, 0x8000, 0x0B)] + [DataRow(0x0000, 0xFFFF, 0x0001, 0x01)] + [DataRow(0x0001, 0x0000, 0x0001, 0x00)] + [DataRow(0x0001, 0x7FFF, 0x8002, 0x09)] + [DataRow(0x4000, 0x4001, 0xFFFF, 0x09)] + [DataRow(0x4000, 0x8000, 0xC000, 0x0B)] + [DataRow(0x4000, 0xC000, 0x8000, 0x0B)] + [DataRow(0x4000, 0xC001, 0x7FFF, 0x01)] + [DataRow(0x7FFF, 0x0000, 0x7FFF, 0x00)] + [DataRow(0x7FFF, 0x0001, 0x7FFE, 0x00)] + [DataRow(0x7FFF, 0x7FFE, 0x0001, 0x00)] + [DataRow(0x7FFF, 0x7FFF, 0x0000, 0x04)] + [DataRow(0x7FFF, 0x8000, 0xFFFF, 0x0B)] + [DataRow(0x7FFF, 0xFFFF, 0x8000, 0x0B)] + [DataRow(0x8000, 0x0001, 0x7FFF, 0x02)] + [DataRow(0x8000, 0x4000, 0x4000, 0x02)] + [DataRow(0x8000, 0x7FFF, 0x0001, 0x02)] + [DataRow(0x8000, 0x8000, 0x0000, 0x04)] + [DataRow(0x8000, 0x8001, 0xFFFF, 0x09)] + [DataRow(0x8001, 0x8000, 0x0001, 0x00)] + [DataRow(0xFFFF, 0xFFFF, 0x0000, 0x04)] + [DataRow(0xFFFF, 0xFFFE, 0x0001, 0x00)] + [DataRow(0xFFFF, 0x0000, 0xFFFF, 0x08)] + public void TestSUBD(int operand, int data, int expected, int flags) + { + this.board.Poke(0, 0x83); + this.board.Poke(1, (byte)(data >> 8)); + this.board.Poke(2, (byte)(data & 0xFF)); + this.cpu.CC = 0; + this.cpu.D.Word = (ushort)operand; + this.cpu.Step(); + Assert.AreEqual((ushort)expected, this.cpu.D.Word); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // SBC (SBCA immediate): carry-in from carryIn; checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x00, 0, 0x00, 0x00, 0x04)] + [DataRow(0x00, 0, 0x01, 0xFF, 0x09)] + [DataRow(0x00, 0, 0x7F, 0x81, 0x09)] + [DataRow(0x00, 0, 0x80, 0x80, 0x0B)] + [DataRow(0x00, 0, 0xFF, 0x01, 0x01)] + [DataRow(0x01, 0, 0x00, 0x01, 0x00)] + [DataRow(0x01, 0, 0x7F, 0x82, 0x09)] + [DataRow(0x40, 0, 0x41, 0xFF, 0x09)] + [DataRow(0x40, 0, 0x80, 0xC0, 0x0B)] + [DataRow(0x40, 0, 0xC0, 0x80, 0x0B)] + [DataRow(0x40, 0, 0xC1, 0x7F, 0x01)] + [DataRow(0x7F, 0, 0x00, 0x7F, 0x00)] + [DataRow(0x7F, 0, 0x01, 0x7E, 0x00)] + [DataRow(0x7F, 0, 0x7E, 0x01, 0x00)] + [DataRow(0x7F, 0, 0x7F, 0x00, 0x04)] + [DataRow(0x7F, 0, 0x80, 0xFF, 0x0B)] + [DataRow(0x7F, 0, 0xFF, 0x80, 0x0B)] + [DataRow(0x80, 0, 0x01, 0x7F, 0x02)] + [DataRow(0x80, 0, 0x40, 0x40, 0x02)] + [DataRow(0x80, 0, 0x7F, 0x01, 0x02)] + [DataRow(0x80, 0, 0x80, 0x00, 0x04)] + [DataRow(0x80, 0, 0x81, 0xFF, 0x09)] + [DataRow(0x81, 0, 0x80, 0x01, 0x00)] + [DataRow(0xFF, 0, 0xFF, 0x00, 0x04)] + [DataRow(0xFF, 0, 0xFE, 0x01, 0x00)] + [DataRow(0xFF, 0, 0x00, 0xFF, 0x08)] + [DataRow(0x00, 1, 0x00, 0xFF, 0x09)] + [DataRow(0x00, 1, 0x01, 0xFE, 0x09)] + [DataRow(0x00, 1, 0x7F, 0x80, 0x09)] + [DataRow(0x00, 1, 0x80, 0x7F, 0x01)] + [DataRow(0x00, 1, 0xFF, 0x00, 0x05)] + [DataRow(0x01, 1, 0x00, 0x00, 0x04)] + [DataRow(0x01, 1, 0x7F, 0x81, 0x09)] + [DataRow(0x40, 1, 0x41, 0xFE, 0x09)] + [DataRow(0x40, 1, 0x80, 0xBF, 0x0B)] + [DataRow(0x40, 1, 0xC0, 0x7F, 0x01)] + [DataRow(0x40, 1, 0xC1, 0x7E, 0x01)] + [DataRow(0x7F, 1, 0x00, 0x7E, 0x00)] + [DataRow(0x7F, 1, 0x01, 0x7D, 0x00)] + [DataRow(0x7F, 1, 0x7E, 0x00, 0x04)] + [DataRow(0x7F, 1, 0x7F, 0xFF, 0x09)] + [DataRow(0x7F, 1, 0x80, 0xFE, 0x0B)] + [DataRow(0x7F, 1, 0xFF, 0x7F, 0x01)] + [DataRow(0x80, 1, 0x01, 0x7E, 0x02)] + [DataRow(0x80, 1, 0x40, 0x3F, 0x02)] + [DataRow(0x80, 1, 0x7F, 0x00, 0x06)] + [DataRow(0x80, 1, 0x80, 0xFF, 0x09)] + [DataRow(0x80, 1, 0x81, 0xFE, 0x09)] + [DataRow(0x81, 1, 0x80, 0x00, 0x04)] + [DataRow(0xFF, 1, 0xFF, 0xFF, 0x09)] + [DataRow(0xFF, 1, 0xFE, 0x00, 0x04)] + [DataRow(0xFF, 1, 0x00, 0xFE, 0x08)] + public void TestSBCA(int operand, int carryIn, int data, int expected, int flags) + { + this.board.Poke(0, 0x82); + this.board.Poke(1, (byte)data); + this.cpu.CC = (byte)carryIn; + this.cpu.A = (byte)operand; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + } +} diff --git a/MC6809/MC6809.UnitTest/SchwotzerCompareLoadTests.cs b/MC6809/MC6809.UnitTest/SchwotzerCompareLoadTests.cs new file mode 100644 index 0000000..ccabe07 --- /dev/null +++ b/MC6809/MC6809.UnitTest/SchwotzerCompareLoadTests.cs @@ -0,0 +1,285 @@ +// +// Copyright (c) Adrian Conlon. All rights reserved. +// + +// Test data from W. Schwotzer's MC6809 CPU Emulation Validation suite, +// verified on an SGS Thomson EF6809P processor. + +namespace MC6809.UnitTest +{ + [TestClass] + public class SchwotzerCompareLoadTests + { + private readonly Board board = new(); + private readonly MC6809 cpu; + + public SchwotzerCompareLoadTests() => this.cpu = this.board.CPU; + + [TestInitialize] + public void Initialise() { this.board.RaisePOWER(); this.cpu.Step(); } + + [TestCleanup] + public void Cleanup() => this.board.LowerPOWER(); + + // CMPB immediate ($C1): same data as SUBB but B is not modified; checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x04)] + [DataRow(0x00, 0x01, 0x09)] + [DataRow(0x00, 0x7F, 0x09)] + [DataRow(0x00, 0x80, 0x0B)] + [DataRow(0x00, 0xFF, 0x01)] + [DataRow(0x01, 0x00, 0x00)] + [DataRow(0x01, 0x7F, 0x09)] + [DataRow(0x40, 0x41, 0x09)] + [DataRow(0x40, 0x80, 0x0B)] + [DataRow(0x40, 0xC0, 0x0B)] + [DataRow(0x40, 0xC1, 0x01)] + [DataRow(0x7F, 0x00, 0x00)] + [DataRow(0x7F, 0x01, 0x00)] + [DataRow(0x7F, 0x7E, 0x00)] + [DataRow(0x7F, 0x7F, 0x04)] + [DataRow(0x7F, 0x80, 0x0B)] + [DataRow(0x7F, 0xFF, 0x0B)] + [DataRow(0x80, 0x01, 0x02)] + [DataRow(0x80, 0x40, 0x02)] + [DataRow(0x80, 0x7F, 0x02)] + [DataRow(0x80, 0x80, 0x04)] + [DataRow(0x80, 0x81, 0x09)] + [DataRow(0x81, 0x80, 0x00)] + [DataRow(0xFF, 0xFF, 0x04)] + [DataRow(0xFF, 0xFE, 0x00)] + [DataRow(0xFF, 0x00, 0x08)] + public void TestCMPB(int operand, int data, int flags) + { + this.board.Poke(0, 0xC1); + this.board.Poke(1, (byte)data); + this.cpu.CC = 0; + this.cpu.B = (byte)operand; + this.cpu.Step(); + Assert.AreEqual((byte)operand, this.cpu.B); // B must not be modified + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // CMPD immediate ($10,$83): same data as SUBD but D is not modified; checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x0000, 0x0000, 0x04)] + [DataRow(0x0000, 0x0001, 0x09)] + [DataRow(0x0000, 0x7FFF, 0x09)] + [DataRow(0x0000, 0x8000, 0x0B)] + [DataRow(0x0000, 0xFFFF, 0x01)] + [DataRow(0x0001, 0x0000, 0x00)] + [DataRow(0x0001, 0x7FFF, 0x09)] + [DataRow(0x4000, 0x4001, 0x09)] + [DataRow(0x4000, 0x8000, 0x0B)] + [DataRow(0x4000, 0xC000, 0x0B)] + [DataRow(0x4000, 0xC001, 0x01)] + [DataRow(0x7FFF, 0x0000, 0x00)] + [DataRow(0x7FFF, 0x0001, 0x00)] + [DataRow(0x7FFF, 0x7FFE, 0x00)] + [DataRow(0x7FFF, 0x7FFF, 0x04)] + [DataRow(0x7FFF, 0x8000, 0x0B)] + [DataRow(0x7FFF, 0xFFFF, 0x0B)] + [DataRow(0x8000, 0x0001, 0x02)] + [DataRow(0x8000, 0x4000, 0x02)] + [DataRow(0x8000, 0x7FFF, 0x02)] + [DataRow(0x8000, 0x8000, 0x04)] + [DataRow(0x8000, 0x8001, 0x09)] + [DataRow(0x8001, 0x8000, 0x00)] + [DataRow(0xFFFF, 0xFFFF, 0x04)] + [DataRow(0xFFFF, 0xFFFE, 0x00)] + [DataRow(0xFFFF, 0x0000, 0x08)] + public void TestCMPD(int operand, int data, int flags) + { + this.board.Poke(0, 0x10); + this.board.Poke(1, 0x83); + this.board.Poke(2, (byte)(data >> 8)); + this.board.Poke(3, (byte)(data & 0xFF)); + this.cpu.CC = 0; + this.cpu.D.Word = (ushort)operand; + this.cpu.Step(); + Assert.AreEqual((ushort)operand, this.cpu.D.Word); // D must not be modified + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // LDA immediate ($86): checks NZV ($0E) — V always cleared + [DataTestMethod] + [DataRow(0x00, 0x04)] + [DataRow(0x01, 0x00)] + [DataRow(0x7F, 0x00)] + [DataRow(0x80, 0x08)] + [DataRow(0xFF, 0x08)] + [DataRow(0xAA, 0x08)] + [DataRow(0x55, 0x00)] + [DataRow(0x10, 0x00)] + public void TestLDA(int data, int flags) + { + this.board.Poke(0, 0x86); + this.board.Poke(1, (byte)data); + this.cpu.CC = 0; + this.cpu.A = 0xFF; // pre-load a different value + this.cpu.Step(); + Assert.AreEqual((byte)data, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0E)); + } + + // LDD immediate ($CC): checks NZV ($0E) — V always cleared + [DataTestMethod] + [DataRow(0x0000, 0x04)] + [DataRow(0x0001, 0x00)] + [DataRow(0x7FFF, 0x00)] + [DataRow(0x8000, 0x08)] + [DataRow(0xFFFF, 0x08)] + [DataRow(0xAAAA, 0x08)] + [DataRow(0x5555, 0x00)] + [DataRow(0x1000, 0x00)] + public void TestLDD(int data, int flags) + { + this.board.Poke(0, 0xCC); + this.board.Poke(1, (byte)(data >> 8)); + this.board.Poke(2, (byte)(data & 0xFF)); + this.cpu.CC = 0; + this.cpu.D.Word = 0x1234; // pre-load a different value + this.cpu.Step(); + Assert.AreEqual((ushort)data, this.cpu.D.Word); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0E)); + } + + // STA extended ($B7 addr): store A to memory, checks NZV ($0E) — V always cleared + // Stores to $0100 so it doesn't overwrite the instruction at $0000 + [DataTestMethod] + [DataRow(0x00, 0x04)] + [DataRow(0x01, 0x00)] + [DataRow(0x7F, 0x00)] + [DataRow(0x80, 0x08)] + [DataRow(0xFF, 0x08)] + [DataRow(0xAA, 0x08)] + [DataRow(0x55, 0x00)] + [DataRow(0x10, 0x00)] + public void TestSTA(int data, int flags) + { + this.board.Poke(0, 0xB7); + this.board.Poke(1, 0x01); + this.board.Poke(2, 0x00); + this.cpu.CC = 0; + this.cpu.A = (byte)data; + this.cpu.Step(); + Assert.AreEqual((byte)data, this.board.Peek(0x0100)); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0E)); + } + + // STD extended ($FD addr): store D to memory, checks NZV ($0E) — V always cleared + // Stores to $0100 so it doesn't overwrite the instruction + [DataTestMethod] + [DataRow(0x0000, 0x04)] + [DataRow(0x0001, 0x00)] + [DataRow(0x7FFF, 0x00)] + [DataRow(0x8000, 0x08)] + [DataRow(0xFFFF, 0x08)] + [DataRow(0xAAAA, 0x08)] + [DataRow(0x5555, 0x00)] + [DataRow(0x1000, 0x00)] + public void TestSTD(int data, int flags) + { + this.board.Poke(0, 0xFD); + this.board.Poke(1, 0x01); + this.board.Poke(2, 0x00); + this.cpu.CC = 0; + this.cpu.D.Word = (ushort)data; + this.cpu.Step(); + var stored = (ushort)((this.board.Peek(0x0100) << 8) | this.board.Peek(0x0101)); + Assert.AreEqual((ushort)data, stored); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0E)); + } + + // LEAY ,Y ($31,$A4): load Y with effective address of ,Y (i.e. Y itself); checks Z ($04) + // Z is set if result is zero, cleared otherwise. No other CC flags affected. + [DataTestMethod] + [DataRow(0x0000, 0x04)] + [DataRow(0x0001, 0x00)] + [DataRow(0x7FFF, 0x00)] + [DataRow(0x8000, 0x00)] + [DataRow(0xFFFF, 0x00)] + [DataRow(0x0100, 0x00)] + public void TestLEAY(int yValue, int flags) + { + this.board.Poke(0, 0x31); + this.board.Poke(1, 0xA4); // ,Y (no offset, indirect=0) + this.cpu.CC = 0; + this.cpu.Y.Word = (ushort)yValue; + this.cpu.Step(); + Assert.AreEqual((ushort)yValue, this.cpu.Y.Word); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x04)); + } + + // DAA ($19): decimal adjust A after BCD addition; checks NZC ($0D) + // initialCC encodes H (bit5) and C (bit0) before the instruction + // 64 rows: all combinations of initialCC in {0x00,0x01,0x20,0x21} × A in {0x00..0x0F, plus selected values} + // Data from Schwotzer TBDAA table, hardware-verified on EF6809P + [DataTestMethod] + // initialCC=0x00 (H=0, C=0) + [DataRow(0x00, 0x00, 0x00, 0x04)] + [DataRow(0x00, 0x09, 0x09, 0x00)] + [DataRow(0x00, 0x0A, 0x10, 0x00)] + [DataRow(0x00, 0x0F, 0x15, 0x00)] + [DataRow(0x00, 0x10, 0x10, 0x00)] + [DataRow(0x00, 0x19, 0x19, 0x00)] + [DataRow(0x00, 0x1A, 0x20, 0x00)] + [DataRow(0x00, 0x90, 0x90, 0x08)] + [DataRow(0x00, 0x99, 0x99, 0x08)] + [DataRow(0x00, 0x9A, 0x00, 0x05)] + [DataRow(0x00, 0xA0, 0x00, 0x05)] + [DataRow(0x00, 0xF9, 0x59, 0x01)] + [DataRow(0x00, 0xFF, 0x65, 0x01)] + // initialCC=0x01 (H=0, C=1) + [DataRow(0x01, 0x00, 0x60, 0x01)] + [DataRow(0x01, 0x09, 0x69, 0x01)] + [DataRow(0x01, 0x0A, 0x70, 0x01)] + [DataRow(0x01, 0x0F, 0x75, 0x01)] + [DataRow(0x01, 0x10, 0x70, 0x01)] + [DataRow(0x01, 0x19, 0x79, 0x01)] + [DataRow(0x01, 0x1A, 0x80, 0x09)] + [DataRow(0x01, 0x90, 0xF0, 0x09)] + [DataRow(0x01, 0x99, 0xF9, 0x09)] + [DataRow(0x01, 0x9A, 0x00, 0x05)] + [DataRow(0x01, 0xA0, 0x00, 0x05)] + [DataRow(0x01, 0xF9, 0x59, 0x01)] + [DataRow(0x01, 0xFF, 0x65, 0x01)] + // initialCC=0x20 (H=1, C=0) + [DataRow(0x20, 0x00, 0x06, 0x00)] + [DataRow(0x20, 0x09, 0x0F, 0x00)] + [DataRow(0x20, 0x0A, 0x10, 0x00)] + [DataRow(0x20, 0x0F, 0x15, 0x00)] + [DataRow(0x20, 0x10, 0x16, 0x00)] + [DataRow(0x20, 0x19, 0x1F, 0x00)] + [DataRow(0x20, 0x1A, 0x20, 0x00)] + [DataRow(0x20, 0x90, 0x96, 0x08)] + [DataRow(0x20, 0x99, 0x9F, 0x08)] + [DataRow(0x20, 0x9A, 0x00, 0x05)] + [DataRow(0x20, 0xA0, 0x06, 0x01)] + [DataRow(0x20, 0xF9, 0x5F, 0x01)] + [DataRow(0x20, 0xFF, 0x65, 0x01)] + // initialCC=0x21 (H=1, C=1) + [DataRow(0x21, 0x00, 0x66, 0x01)] + [DataRow(0x21, 0x09, 0x6F, 0x01)] + [DataRow(0x21, 0x0A, 0x70, 0x01)] + [DataRow(0x21, 0x0F, 0x75, 0x01)] + [DataRow(0x21, 0x10, 0x76, 0x01)] + [DataRow(0x21, 0x19, 0x7F, 0x01)] + [DataRow(0x21, 0x1A, 0x80, 0x09)] + [DataRow(0x21, 0x90, 0xF6, 0x09)] + [DataRow(0x21, 0x99, 0xFF, 0x09)] + [DataRow(0x21, 0x9A, 0x00, 0x05)] + [DataRow(0x21, 0xA0, 0x06, 0x01)] + [DataRow(0x21, 0xF9, 0x5F, 0x01)] + [DataRow(0x21, 0xFF, 0x65, 0x01)] + public void TestDAA(int initialCC, int input, int expected, int flags) + { + this.board.Poke(0, 0x19); + this.cpu.CC = (byte)initialCC; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0D)); + } + } +} diff --git a/MC6809/MC6809.UnitTest/SchwotzerShiftTests.cs b/MC6809/MC6809.UnitTest/SchwotzerShiftTests.cs new file mode 100644 index 0000000..d15b612 --- /dev/null +++ b/MC6809/MC6809.UnitTest/SchwotzerShiftTests.cs @@ -0,0 +1,139 @@ +// +// Copyright (c) Adrian Conlon. All rights reserved. +// + +// Test data from W. Schwotzer's MC6809 CPU Emulation Validation suite, +// verified on an SGS Thomson EF6809P processor. +// +// Note: the Schwotzer LSL flag table was demonstrably incorrect on several +// entries (the original LBNE OUTERR for flags was commented out). Result +// values are hardware-verified; expected flags are from the MC6809 spec: +// C = old bit 7, N = result bit 7, Z = result==0, V = old_bit7 XOR old_bit6. + +namespace MC6809.UnitTest +{ + [TestClass] + public class SchwotzerShiftTests + { + private readonly Board board = new(); + private readonly MC6809 cpu; + + public SchwotzerShiftTests() => this.cpu = this.board.CPU; + + [TestInitialize] + public void Initialise() { this.board.RaisePOWER(); this.cpu.Step(); } + + [TestCleanup] + public void Cleanup() => this.board.LowerPOWER(); + + // LSL: result from hardware; flags from MC6809 spec; checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x04)] // C=0 N=0 Z=1 V=0 + [DataRow(0xFF, 0xFE, 0x09)] // C=1 N=1 Z=0 V=0 (bit7^bit6 = 1^1 = 0) + [DataRow(0x7F, 0xFE, 0x0A)] // C=0 N=1 Z=0 V=1 (0^1=1) + [DataRow(0x3F, 0x7E, 0x00)] // C=0 N=0 Z=0 V=0 (0^0=0) + [DataRow(0x1F, 0x3E, 0x00)] + [DataRow(0x0F, 0x1E, 0x00)] + [DataRow(0x07, 0x0E, 0x00)] + [DataRow(0x03, 0x06, 0x00)] + [DataRow(0x01, 0x02, 0x00)] + [DataRow(0x55, 0xAA, 0x0A)] // C=0 N=1 Z=0 V=1 (0^1=1) + [DataRow(0xAA, 0x54, 0x03)] // C=1 N=0 Z=0 V=1 (1^0=1) + [DataRow(0x80, 0x00, 0x07)] // C=1 N=0 Z=1 V=1 (1^0=1) + [DataRow(0x10, 0x20, 0x00)] // C=0 N=0 Z=0 V=0 (0^0=0) + [DataRow(0xC0, 0x80, 0x09)] // C=1 N=1 Z=0 V=0 (1^1=0) + [DataRow(0xE0, 0xC0, 0x09)] + [DataRow(0xF0, 0xE0, 0x09)] + [DataRow(0xF8, 0xF0, 0x09)] + [DataRow(0xFC, 0xF8, 0x09)] + [DataRow(0xFE, 0xFC, 0x09)] + public void TestLSLA(int input, int expected, int flags) + { + this.board.Poke(0, 0x48); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // ROR: carry-in from carryIn parameter; checks NZC ($0D) + [DataTestMethod] + [DataRow(0x00, 0, 0x00, 0x04)] + [DataRow(0x01, 0, 0x00, 0x05)] + [DataRow(0x0F, 0, 0x07, 0x01)] + [DataRow(0x10, 0, 0x08, 0x00)] + [DataRow(0x7F, 0, 0x3F, 0x01)] + [DataRow(0x80, 0, 0x40, 0x00)] + [DataRow(0xFE, 0, 0x7F, 0x00)] + [DataRow(0xFF, 0, 0x7F, 0x01)] + [DataRow(0x00, 1, 0x80, 0x08)] + [DataRow(0x01, 1, 0x80, 0x09)] + [DataRow(0x0F, 1, 0x87, 0x09)] + [DataRow(0x10, 1, 0x88, 0x08)] + [DataRow(0x7F, 1, 0xBF, 0x09)] + [DataRow(0x80, 1, 0xC0, 0x08)] + [DataRow(0xFE, 1, 0xFF, 0x08)] + [DataRow(0xFF, 1, 0xFF, 0x09)] + public void TestRORA(int input, int carryIn, int expected, int flags) + { + this.board.Poke(0, 0x46); + this.cpu.CC = (byte)carryIn; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0D)); + } + + // ROL: carry-in from carryIn parameter; checks NZC ($0D) + [DataTestMethod] + [DataRow(0x00, 0, 0x00, 0x04)] + [DataRow(0x01, 0, 0x02, 0x00)] + [DataRow(0x0F, 0, 0x1E, 0x00)] + [DataRow(0x08, 0, 0x10, 0x00)] + [DataRow(0x7F, 0, 0xFE, 0x08)] + [DataRow(0x80, 0, 0x00, 0x05)] + [DataRow(0xFE, 0, 0xFC, 0x09)] + [DataRow(0xFF, 0, 0xFE, 0x09)] + [DataRow(0x00, 1, 0x01, 0x00)] + [DataRow(0x01, 1, 0x03, 0x00)] + [DataRow(0x0F, 1, 0x1F, 0x00)] + [DataRow(0x08, 1, 0x11, 0x00)] + [DataRow(0x7F, 1, 0xFF, 0x08)] + [DataRow(0x80, 1, 0x01, 0x01)] + [DataRow(0xFE, 1, 0xFD, 0x09)] + [DataRow(0xFF, 1, 0xFF, 0x09)] + public void TestROLA(int input, int carryIn, int expected, int flags) + { + this.board.Poke(0, 0x49); + this.cpu.CC = (byte)carryIn; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0D)); + } + + // BIT: AND without storing result; checks NZV ($0E) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x04)] + [DataRow(0xAA, 0x55, 0x04)] + [DataRow(0xAA, 0xAA, 0x08)] + [DataRow(0x55, 0x55, 0x00)] + [DataRow(0xFF, 0xFF, 0x08)] + [DataRow(0xFF, 0x80, 0x08)] + [DataRow(0x81, 0x80, 0x08)] + [DataRow(0xFF, 0x7F, 0x00)] + [DataRow(0xFF, 0x01, 0x00)] + [DataRow(0xF0, 0x0F, 0x04)] + public void TestBITA(int operand, int data, int flags) + { + this.board.Poke(0, 0x85); + this.board.Poke(1, (byte)data); + this.cpu.CC = 0; + this.cpu.A = (byte)operand; + this.cpu.Step(); + Assert.AreEqual((byte)operand, this.cpu.A); // A must not be modified + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0E)); + } + } +} diff --git a/MC6809/MC6809.UnitTest/SchwotzerUnaryTests.cs b/MC6809/MC6809.UnitTest/SchwotzerUnaryTests.cs new file mode 100644 index 0000000..c3d5a1e --- /dev/null +++ b/MC6809/MC6809.UnitTest/SchwotzerUnaryTests.cs @@ -0,0 +1,249 @@ +// +// Copyright (c) Adrian Conlon. All rights reserved. +// + +// Test data from W. Schwotzer's MC6809 CPU Emulation Validation suite, +// verified on an SGS Thomson EF6809P processor. + +namespace MC6809.UnitTest +{ + [TestClass] + public class SchwotzerUnaryTests + { + private readonly Board board = new(); + private readonly MC6809 cpu; + + public SchwotzerUnaryTests() => this.cpu = this.board.CPU; + + [TestInitialize] + public void Initialise() { this.board.RaisePOWER(); this.cpu.Step(); } + + [TestCleanup] + public void Cleanup() => this.board.LowerPOWER(); + + // NEG: checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x04)] + [DataRow(0x80, 0x80, 0x0B)] + [DataRow(0x01, 0xFF, 0x09)] + [DataRow(0xFF, 0x01, 0x01)] + [DataRow(0x7F, 0x81, 0x09)] + [DataRow(0x81, 0x7F, 0x01)] + [DataRow(0xC0, 0x40, 0x01)] + [DataRow(0x40, 0xC0, 0x09)] + public void TestNEGA(int input, int expected, int flags) + { + this.board.Poke(0, 0x40); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // COM: checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x00, 0xFF, 0x09)] + [DataRow(0xFF, 0x00, 0x05)] + [DataRow(0xF0, 0x0F, 0x01)] + [DataRow(0x0F, 0xF0, 0x09)] + [DataRow(0x55, 0xAA, 0x09)] + [DataRow(0xAA, 0x55, 0x01)] + [DataRow(0x01, 0xFE, 0x09)] + [DataRow(0xFE, 0x01, 0x01)] + [DataRow(0x80, 0x7F, 0x01)] + [DataRow(0x7F, 0x80, 0x09)] + public void TestCOMA(int input, int expected, int flags) + { + this.board.Poke(0, 0x43); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // CLR: checks NZVC ($0F) — always clears to zero, Z=1 + [DataTestMethod] + [DataRow(0x01, 0x04)] + [DataRow(0x00, 0x04)] + [DataRow(0xFF, 0x04)] + [DataRow(0x80, 0x04)] + [DataRow(0x7F, 0x04)] + [DataRow(0x10, 0x04)] + [DataRow(0x0F, 0x04)] + public void TestCLRA(int input, int flags) + { + this.board.Poke(0, 0x4F); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual(0, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // DEC: checks NZV ($0E) + [DataTestMethod] + [DataRow(0x01, 0x00, 0x04)] + [DataRow(0x00, 0xFF, 0x08)] + [DataRow(0xFF, 0xFE, 0x08)] + [DataRow(0x80, 0x7F, 0x02)] + [DataRow(0x7F, 0x7E, 0x00)] + [DataRow(0x10, 0x0F, 0x00)] + [DataRow(0x0F, 0x0E, 0x00)] + public void TestDECA(int input, int expected, int flags) + { + this.board.Poke(0, 0x4A); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0E)); + } + + // INC: checks NZV ($0E) + [DataTestMethod] + [DataRow(0x00, 0x01, 0x00)] + [DataRow(0xFE, 0xFF, 0x08)] + [DataRow(0xFF, 0x00, 0x04)] + [DataRow(0x7F, 0x80, 0x0A)] + [DataRow(0x80, 0x81, 0x08)] + [DataRow(0x0F, 0x10, 0x00)] + [DataRow(0x10, 0x11, 0x00)] + public void TestINCA(int input, int expected, int flags) + { + this.board.Poke(0, 0x4C); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0E)); + } + + // TST: checks NZV ($0E) — does not modify A + [DataTestMethod] + [DataRow(0x00, 0x04)] + [DataRow(0x80, 0x08)] + [DataRow(0x01, 0x00)] + [DataRow(0xFF, 0x08)] + [DataRow(0x7F, 0x00)] + [DataRow(0x81, 0x08)] + [DataRow(0xC0, 0x08)] + [DataRow(0x40, 0x00)] + public void TestTSTA(int input, int flags) + { + this.board.Poke(0, 0x4D); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)input, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0E)); + } + + // LSR: checks NZVC ($0F) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x04)] + [DataRow(0xFF, 0x7F, 0x01)] + [DataRow(0x7F, 0x3F, 0x01)] + [DataRow(0x3F, 0x1F, 0x01)] + [DataRow(0x1F, 0x0F, 0x01)] + [DataRow(0x0F, 0x07, 0x01)] + [DataRow(0x07, 0x03, 0x01)] + [DataRow(0x03, 0x01, 0x01)] + [DataRow(0x01, 0x00, 0x05)] + [DataRow(0x55, 0x2A, 0x01)] + [DataRow(0xAA, 0x55, 0x00)] + [DataRow(0x80, 0x40, 0x00)] + [DataRow(0x10, 0x08, 0x00)] + [DataRow(0xC0, 0x60, 0x00)] + [DataRow(0xE0, 0x70, 0x00)] + [DataRow(0xF0, 0x78, 0x00)] + [DataRow(0xF8, 0x7C, 0x00)] + [DataRow(0xFC, 0x7E, 0x00)] + [DataRow(0xFE, 0x7F, 0x00)] + public void TestLSRA(int input, int expected, int flags) + { + this.board.Poke(0, 0x44); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0F)); + } + + // ASR: checks NZC ($0D) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x04)] + [DataRow(0xFF, 0xFF, 0x09)] + [DataRow(0x7F, 0x3F, 0x01)] + [DataRow(0x3F, 0x1F, 0x01)] + [DataRow(0x1F, 0x0F, 0x01)] + [DataRow(0x0F, 0x07, 0x01)] + [DataRow(0x07, 0x03, 0x01)] + [DataRow(0x03, 0x01, 0x01)] + [DataRow(0x01, 0x00, 0x05)] + [DataRow(0x55, 0x2A, 0x01)] + [DataRow(0xAA, 0xD5, 0x08)] + [DataRow(0x80, 0xC0, 0x08)] + [DataRow(0x10, 0x08, 0x00)] + [DataRow(0xC0, 0xE0, 0x08)] + [DataRow(0xE0, 0xF0, 0x08)] + [DataRow(0xF0, 0xF8, 0x08)] + [DataRow(0xF8, 0xFC, 0x08)] + [DataRow(0xFC, 0xFE, 0x08)] + [DataRow(0xFE, 0xFF, 0x08)] + public void TestASRA(int input, int expected, int flags) + { + this.board.Poke(0, 0x47); + this.cpu.CC = 0; + this.cpu.A = (byte)input; + this.cpu.Step(); + Assert.AreEqual((byte)expected, this.cpu.A); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0D)); + } + + // SEX: input in B, sign-extended into D; checks NZ ($0C) + [DataTestMethod] + [DataRow(0x00, 0x00, 0x00, 0x04)] + [DataRow(0x01, 0x00, 0x01, 0x00)] + [DataRow(0x7F, 0x00, 0x7F, 0x00)] + [DataRow(0x80, 0xFF, 0x80, 0x08)] + [DataRow(0xFF, 0xFF, 0xFF, 0x08)] + public void TestSEX(int inputB, int expectedA, int expectedB, int flags) + { + this.board.Poke(0, 0x1D); + this.cpu.CC = 0; + this.cpu.B = (byte)inputB; + this.cpu.Step(); + Assert.AreEqual((byte)expectedA, this.cpu.A); + Assert.AreEqual((byte)expectedB, this.cpu.B); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x0C)); + } + + // MUL: A × B → D (unsigned); checks ZC ($05) + // C is set if bit 7 of the result's low byte (B) is set + [DataTestMethod] + [DataRow(0x00, 0x00, 0x00, 0x00, 0x04)] + [DataRow(0x80, 0x80, 0x40, 0x00, 0x00)] + [DataRow(0x01, 0xFF, 0x00, 0xFF, 0x01)] + [DataRow(0xFF, 0x01, 0x00, 0xFF, 0x01)] + [DataRow(0x7F, 0x81, 0x3F, 0xFF, 0x01)] + [DataRow(0x81, 0x7F, 0x3F, 0xFF, 0x01)] + [DataRow(0xC0, 0x40, 0x30, 0x00, 0x00)] + [DataRow(0x40, 0xC0, 0x30, 0x00, 0x00)] + [DataRow(0xFF, 0xFF, 0xFE, 0x01, 0x00)] + [DataRow(0x7F, 0x7F, 0x3F, 0x01, 0x00)] + [DataRow(0x01, 0x01, 0x00, 0x01, 0x00)] + public void TestMUL(int inputA, int inputB, int expectedA, int expectedB, int flags) + { + this.board.Poke(0, 0x3D); + this.cpu.CC = 0; + this.cpu.A = (byte)inputA; + this.cpu.B = (byte)inputB; + this.cpu.Step(); + Assert.AreEqual((byte)expectedA, this.cpu.A); + Assert.AreEqual((byte)expectedB, this.cpu.B); + Assert.AreEqual((byte)flags, (byte)(this.cpu.CC & 0x05)); + } + } +} diff --git a/MC6809/MC6809.cs b/MC6809/MC6809.cs index b63969e..c73730d 100644 --- a/MC6809/MC6809.cs +++ b/MC6809/MC6809.cs @@ -2165,17 +2165,27 @@ namespace MC6809 { this.LEA(this.X); this.CC = this.AdjustZero(this.X); + this.SwallowRead(); } private void LEAY() { this.LEA(this.Y); this.CC = this.AdjustZero(this.Y); + this.SwallowRead(); } - private void LEAS() => this.LEA(this.S); + private void LEAS() + { + this.LEA(this.S); + this.SwallowRead(); + } - private void LEAU() => this.LEA(this.U); + private void LEAU() + { + this.LEA(this.U); + this.SwallowRead(); + } private void LEA(Register16 register) => register.Assign(this.EA);