From 5714798756d8f774b8747f6bf8b7722e96170d73 Mon Sep 17 00:00:00 2001 From: Adrian Conlon Date: Tue, 19 Feb 2019 00:56:16 +0000 Subject: [PATCH] Lots of stylecop encouraged changes. Signed-off-by: Adrian Conlon --- EightBit/EightBit.UnitTest/ChipUnitTest.cs | 24 +-- Z80/RefreshRegister.cs | 12 +- Z80/RegisterIndex.cs | 13 ++ Z80/Z80.cs | 189 +++++++++++++++------ 4 files changed, 171 insertions(+), 67 deletions(-) create mode 100644 Z80/RegisterIndex.cs diff --git a/EightBit/EightBit.UnitTest/ChipUnitTest.cs b/EightBit/EightBit.UnitTest/ChipUnitTest.cs index 103ed69..7832a72 100644 --- a/EightBit/EightBit.UnitTest/ChipUnitTest.cs +++ b/EightBit/EightBit.UnitTest/ChipUnitTest.cs @@ -13,7 +13,7 @@ namespace UnitTestEightBit [TestMethod] public void TestLowByte() { - ushort input = 0xf00f; + const ushort input = 0xf00f; byte low = Chip.LowByte(input); Assert.AreEqual(0xf, low); } @@ -21,7 +21,7 @@ namespace UnitTestEightBit [TestMethod] public void TestHighByte() { - ushort input = 0xf00f; + const ushort input = 0xf00f; byte high = Chip.HighByte(input); Assert.AreEqual(0xf0, high); } @@ -109,7 +109,7 @@ namespace UnitTestEightBit [TestMethod] public void TestLowerPart() { - ushort input = 0xf00f; + const ushort input = 0xf00f; ushort lower = Chip.LowerPart(input); Assert.AreEqual(0xf, lower); } @@ -117,7 +117,7 @@ namespace UnitTestEightBit [TestMethod] public void TestHigherPart() { - ushort input = 0xf00f; + const ushort input = 0xf00f; ushort higher = Chip.HigherPart(input); Assert.AreEqual(0xf000, higher); } @@ -125,7 +125,7 @@ namespace UnitTestEightBit [TestMethod] public void TestDemoteByte() { - ushort input = 0xf00f; + const ushort input = 0xf00f; byte demoted = Chip.DemoteByte(input); Assert.AreEqual(0xf0, demoted); } @@ -133,7 +133,7 @@ namespace UnitTestEightBit [TestMethod] public void TestPromoteByte() { - byte input = 0xf0; + const byte input = 0xf0; ushort promoted = Chip.PromoteByte(input); Assert.AreEqual(0xf000, promoted); } @@ -141,7 +141,7 @@ namespace UnitTestEightBit [TestMethod] public void TestLowNibble() { - byte input = 0xab; + const byte input = 0xab; int nibble = Chip.LowNibble(input); Assert.AreEqual(0xb, nibble); } @@ -149,7 +149,7 @@ namespace UnitTestEightBit [TestMethod] public void TestHighNibble() { - byte input = 0xab; + const byte input = 0xab; int nibble = Chip.HighNibble(input); Assert.AreEqual(0xa, nibble); } @@ -157,7 +157,7 @@ namespace UnitTestEightBit [TestMethod] public void TestDemoteNibble() { - byte input = 0xab; + const byte input = 0xab; int nibble = Chip.DemoteNibble(input); Assert.AreEqual(0xa, nibble); } @@ -165,7 +165,7 @@ namespace UnitTestEightBit [TestMethod] public void TestPromoteNibble() { - byte input = 0xab; + const byte input = 0xab; int nibble = Chip.PromoteNibble(input); Assert.AreEqual(0xb0, nibble); } @@ -173,7 +173,7 @@ namespace UnitTestEightBit [TestMethod] public void TestHigherNibble() { - byte input = 0xab; + const byte input = 0xab; int nibble = Chip.HigherNibble(input); Assert.AreEqual(0xa0, nibble); } @@ -181,7 +181,7 @@ namespace UnitTestEightBit [TestMethod] public void TestLowerNibble() { - byte input = 0xab; + const byte input = 0xab; int nibble = Chip.LowerNibble(input); Assert.AreEqual(0xb, nibble); } diff --git a/Z80/RefreshRegister.cs b/Z80/RefreshRegister.cs index 5159a65..255a85d 100644 --- a/Z80/RefreshRegister.cs +++ b/Z80/RefreshRegister.cs @@ -21,6 +21,12 @@ return FromByte(input); } + public static RefreshRegister operator ++(RefreshRegister value) => Increment(value); + + public static bool operator ==(RefreshRegister left, RefreshRegister right) => left.Equals(right); + + public static bool operator !=(RefreshRegister left, RefreshRegister right) => !(left == right); + public static byte ToByte(RefreshRegister input) { return (byte)((input.high << 7) | input.variable); @@ -31,12 +37,6 @@ return new RefreshRegister(input); } - public static RefreshRegister operator ++(RefreshRegister value) => Increment(value); - - public static bool operator ==(RefreshRegister left, RefreshRegister right) => left.Equals(right); - - public static bool operator !=(RefreshRegister left, RefreshRegister right) => !(left == right); - public static RefreshRegister Increment(RefreshRegister value) { ++value.variable; diff --git a/Z80/RegisterIndex.cs b/Z80/RegisterIndex.cs new file mode 100644 index 0000000..dac3314 --- /dev/null +++ b/Z80/RegisterIndex.cs @@ -0,0 +1,13 @@ +// +// Copyright (c) Adrian Conlon. All rights reserved. +// + +namespace EightBit +{ + public enum RegisterIndex + { + IndexBC, + IndexDE, + IndexHL, + } +} diff --git a/Z80/Z80.cs b/Z80/Z80.cs index 99d20ce..dd704f1 100644 --- a/Z80/Z80.cs +++ b/Z80/Z80.cs @@ -8,10 +8,11 @@ namespace EightBit public class Z80 : IntelProcessor { - public enum RegisterIndex { IndexBC, IndexDE, IndexHL }; - private readonly InputOutput ports; + private readonly Register16[] accumulatorFlags = new Register16[2]; + private readonly Register16[,] registers = new Register16[2, 3]; + private RefreshRegister refresh = new RefreshRegister(0x7f); private bool prefixCB = false; @@ -22,10 +23,8 @@ namespace EightBit private PinLevel nmiLine = PinLevel.Low; private PinLevel m1Line = PinLevel.Low; - private readonly Register16[] accumulatorFlags = new Register16[2]; private int accumulatorFlagsSet = 0; - private readonly Register16[,] registers = new Register16[2,3]; private int registerSet = 0; private Register16 ix = new Register16(0xffff); @@ -73,7 +72,7 @@ namespace EightBit get { var returned = (this.prefixDD ? this.IX() : this.IY()).Word + this.displacement; - return MEMPTR().Word = (ushort)returned; + return this.MEMPTR().Word = (ushort)returned; } } @@ -177,9 +176,13 @@ namespace EightBit if (prefixed) { if (this.prefixCB) + { this.ExecuteCB(x, y, z); + } else if (this.prefixED) + { this.ExecuteED(x, y, z, p, q); + } } else { @@ -218,6 +221,7 @@ namespace EightBit this.Execute(this.FetchByte()); } } + this.OnExecutedInstruction(); return this.Cycles; } @@ -258,7 +262,7 @@ namespace EightBit this.DisableInterrupts(); switch (this.IM) { - case 0: // i8080 equivalent + case 0: // i8080 equivalent this.Execute(this.Bus.Data); break; case 1: @@ -266,7 +270,7 @@ namespace EightBit this.Tick(13); break; case 2: - this.Call(this.MEMPTR() = new Register16(this.Bus.Data, IV)); + this.Call(this.MEMPTR() = new Register16(this.Bus.Data, this.IV)); this.Tick(19); break; default: @@ -310,7 +314,7 @@ namespace EightBit private static byte AdjustSZP(byte input, byte value) { - AdjustSZ(input, value); + input = AdjustSZ(input, value); return AdjustParity(input, value); } @@ -364,6 +368,16 @@ namespace EightBit return AdjustOverflowSub(input, before & (byte)StatusBits.SF, value & (byte)StatusBits.SF, calculation & (byte)StatusBits.SF); } + private static byte RES(int n, byte operand) + { + return (byte)(operand & ~(1 << n)); + } + + private static byte SET(int n, byte operand) + { + return (byte)(operand | (1 << n)); + } + private void DisableInterrupts() => this.IFF1 = this.IFF2 = false; private void EnableInterrupts() => this.IFF1 = this.IFF2 = true; @@ -502,7 +516,7 @@ namespace EightBit this.Bus.Write(this.HL(), value); break; case 7: - A() = value; + this.A() = value; break; default: throw new ArgumentOutOfRangeException(nameof(r)); @@ -515,11 +529,11 @@ namespace EightBit var memoryZ = z == 6; var indirect = (!this.displaced && memoryZ) || this.displaced; var direct = !indirect; - var operand = !this.displaced ? R(z) : Bus.Read(this.DisplacedAddress); + var operand = !this.displaced ? this.R(z) : this.Bus.Read(this.DisplacedAddress); var update = x != 1; // BIT does not update switch (x) { - case 0: // rot[y] r[z] + case 0: // rot[y] r[z] switch (y) { case 0: @@ -549,6 +563,7 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + this.F() = AdjustSZP(this.F(), operand); this.Tick(8); break; @@ -564,6 +579,7 @@ namespace EightBit this.F() = AdjustXY(this.F(), this.MEMPTR().High); this.Tick(4); } + break; case 2: // RES y, r[z] this.Tick(8); @@ -576,6 +592,7 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + if (update) { if (!this.displaced) @@ -612,8 +629,11 @@ namespace EightBit this.MEMPTR() = this.Bus.Address() = this.BC(); this.MEMPTR()++; this.ReadPort(); - if (y != 6) // IN r[y],(C) - this.R(y, this.Bus.Data); + if (y != 6) + { + this.R(y, this.Bus.Data); // IN r[y],(C) + } + this.F() = AdjustSZPXY(this.F(), this.Bus.Data); this.F() = ClearFlag(this.F(), StatusBits.NF | StatusBits.HC); this.Tick(12); @@ -621,10 +641,15 @@ namespace EightBit case 1: // Output to port with 16-bit address this.MEMPTR() = this.Bus.Address() = this.BC(); this.MEMPTR()++; - if (y != 6) // OUT (C),r[y] - this.Bus.Data = R(y); - else // OUT (C),0 - this.Bus.Data = 0; + if (y != 6) + { + this.Bus.Data = this.R(y); // OUT (C),r[y] + } + else + { + this.Bus.Data = 0; // OUT (C),0 + } + this.WritePort(); this.Tick(12); break; @@ -640,6 +665,7 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + this.Tick(15); break; case 3: // Retrieve/store register pair from/to immediate address @@ -655,6 +681,7 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + this.Tick(20); break; case 4: // Negate accumulator @@ -671,6 +698,7 @@ namespace EightBit this.RetN(); // RETN break; } + this.Tick(14); break; case 6: // Set interrupt mode @@ -693,6 +721,7 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + this.Tick(8); break; case 7: // Assorted ops @@ -709,13 +738,13 @@ namespace EightBit case 2: // LD A,I this.F() = AdjustSZXY(this.F(), this.A() = this.IV); this.F() = ClearFlag(this.F(), StatusBits.NF | StatusBits.HC); - this.F() = SetFlag(this.F(), StatusBits.PF, IFF2); + this.F() = SetFlag(this.F(), StatusBits.PF, this.IFF2); this.Tick(9); break; case 3: // LD A,R - this.F() = AdjustSZXY(this.F(), this.A() = REFRESH()); + this.F() = AdjustSZXY(this.F(), this.A() = this.REFRESH()); this.F() = ClearFlag(this.F(), StatusBits.NF | StatusBits.HC); - this.F() = SetFlag(this.F(), StatusBits.PF, IFF2); + this.F() = SetFlag(this.F(), StatusBits.PF, this.IFF2); this.Tick(9); break; case 4: // RRD @@ -733,10 +762,12 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + break; default: throw new NotSupportedException("Invalid operation mode"); } + break; case 2: switch (z) @@ -757,6 +788,7 @@ namespace EightBit --this.PC(); this.Tick(5); } + break; case 7: // LDDR if (this.LDDR()) @@ -765,8 +797,10 @@ namespace EightBit --this.PC(); this.Tick(5); } + break; } + break; case 1: // CP switch (y) @@ -784,6 +818,7 @@ namespace EightBit --this.PC(); this.Tick(5); } + break; case 7: // CPDR if (this.CPDR()) @@ -796,8 +831,10 @@ namespace EightBit { this.MEMPTR().Word = (ushort)(this.PC().Word - 2); } + break; } + break; case 2: // IN switch (y) @@ -814,6 +851,7 @@ namespace EightBit this.PC().Word -= 2; this.Tick(5); } + break; case 7: // INDR if (this.INDR()) @@ -821,8 +859,10 @@ namespace EightBit this.PC().Word -= 2; this.Tick(5); } + break; } + break; case 3: // OUT switch (y) @@ -839,6 +879,7 @@ namespace EightBit this.PC().Word -= 2; this.Tick(5); } + break; case 7: // OTDR if (this.OTDR()) @@ -846,10 +887,13 @@ namespace EightBit this.PC().Word -= 2; this.Tick(5); } + break; } + break; } + this.Tick(16); break; } @@ -876,7 +920,10 @@ namespace EightBit break; case 2: // DJNZ d if (this.JumpRelativeConditional(--this.B() != 0)) + { this.Tick(5); + } + this.Tick(8); break; case 3: // JR d @@ -888,12 +935,16 @@ namespace EightBit case 6: case 7: if (this.JumpRelativeConditionalFlag(y - 4)) + { this.Tick(5); + } + this.Tick(5); break; default: throw new NotSupportedException("Invalid operation mode"); } + break; case 1: // 16-bit load immediate/add switch (q) @@ -909,6 +960,7 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + break; case 2: // Indirect loading switch (q) @@ -945,6 +997,7 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + break; case 1: switch (p) @@ -975,10 +1028,12 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + break; default: throw new NotSupportedException("Invalid operation mode"); } + break; case 3: // 16-bit INC/DEC switch (q) @@ -992,11 +1047,15 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + this.Tick(6); break; case 4: // 8-bit INC if (this.displaced && memoryY) + { this.FetchDisplacement(); + } + this.R(y, this.Increment(this.R(y))); this.Tick(4); break; @@ -1005,8 +1064,11 @@ namespace EightBit { this.Tick(7); if (this.displaced) + { this.FetchDisplacement(); + } } + this.R(y, this.Decrement(this.R(y))); this.Tick(4); break; @@ -1015,8 +1077,11 @@ namespace EightBit { this.Tick(3); if (this.displaced) + { this.FetchDisplacement(); + } } + this.R(y, this.FetchByte()); // LD r,n this.Tick(7); break; @@ -1050,11 +1115,13 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + this.Tick(4); break; default: throw new NotSupportedException("Invalid operation mode"); } + break; case 1: // 8-bit loading if (!(memoryZ && memoryY)) @@ -1063,7 +1130,10 @@ namespace EightBit if (this.displaced) { if (memoryZ || memoryY) + { this.FetchDisplacement(); + } + if (memoryZ) { switch (y) @@ -1078,6 +1148,7 @@ namespace EightBit break; } } + if (memoryY) { switch (z) @@ -1093,15 +1164,23 @@ namespace EightBit } } } + if (normal) + { this.R(y, this.R(z)); - if (memoryY || memoryZ) // M operations + } + + // M operations + if (memoryY || memoryZ) + { this.Tick(3); + } } else - { // Exception (replaces LD (HL), (HL)) - this.Halt(); + { + this.Halt(); // Exception (replaces LD (HL), (HL)) } + this.Tick(4); break; case 2: @@ -1110,9 +1189,12 @@ namespace EightBit { this.Tick(3); if (this.displaced) + { this.FetchDisplacement(); + } } - var value = R(z); + + var value = this.R(z); switch (y) { case 0: // ADD A,r @@ -1142,15 +1224,20 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + this.Tick(4); break; } + case 3: switch (z) { case 0: // Conditional return if (this.ReturnConditionalFlag(y)) + { this.Tick(6); + } + this.Tick(5); break; case 1: // POP & various ops @@ -1182,10 +1269,12 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + break; default: throw new NotSupportedException("Invalid operation mode"); } + break; case 2: // Conditional jump this.JumpConditionalFlag(y); @@ -1201,7 +1290,10 @@ namespace EightBit case 1: // CB prefix this.prefixCB = true; if (this.displaced) + { this.FetchDisplacement(); + } + this.LowerM1(); this.Execute(this.FetchByte()); break; @@ -1232,10 +1324,14 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + break; case 4: // Conditional call: CALL cc[y], nn if (this.CallConditionalFlag(y)) + { this.Tick(7); + } + this.Tick(10); break; case 5: // PUSH & various ops @@ -1270,10 +1366,12 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + break; default: throw new NotSupportedException("Invalid operation mode"); } + break; case 6: { // Operate on accumulator and immediate operand: alu[y] n @@ -1307,9 +1405,11 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + this.Tick(7); break; } + case 7: // Restart: RST y * 8 this.Restart((byte)(y << 3)); this.Tick(11); @@ -1317,6 +1417,7 @@ namespace EightBit default: throw new NotSupportedException("Invalid operation mode"); } + break; } } @@ -1475,7 +1576,7 @@ namespace EightBit var valueNegative = value.High & (byte)StatusBits.SF; var result = this.MEMPTR().Word - value.Word - (this.F() & (byte)StatusBits.CF); - HL2().Word = (ushort)result; + this.HL2().Word = (ushort)result; var afterNegative = this.HL2().High & (byte)StatusBits.SF; @@ -1541,15 +1642,15 @@ namespace EightBit this.F() = AdjustSZXY(this.F(), this.A() = result.Low); } - private void ADC(byte value) => Add(value, this.F() & (byte)StatusBits.CF); + private void ADC(byte value) => this.Add(value, this.F() & (byte)StatusBits.CF); private void SUB(byte value, int carry = 0) { - this.A() = Subtract(this.A(), value, carry); + this.A() = this.Subtract(this.A(), value, carry); this.F() = AdjustXY(this.F(), this.A()); } - private void SBC(byte value) => SUB(value, this.F() & (byte)StatusBits.CF); + private void SBC(byte value) => this.SUB(value, this.F() & (byte)StatusBits.CF); private void AndR(byte value) { @@ -1572,7 +1673,7 @@ namespace EightBit private void Compare(byte value) { - this.F() = Subtract(this.A(), value); + this.F() = this.Subtract(this.A(), value); this.F() = AdjustXY(this.F(), value); } @@ -1662,21 +1763,11 @@ namespace EightBit this.F() = ClearFlag(this.F(), StatusBits.PF, discarded); } - private static byte RES(int n, byte operand) - { - return (byte)(operand & ~(1 << n)); - } - - private static byte SET(int n, byte operand) - { - return (byte)(operand | (1 << n)); - } - private void DAA() { var updated = this.A(); - var lowAdjust = ((this.F() & (byte)StatusBits.HC) != 0) || (LowNibble(A()) > 9); + var lowAdjust = ((this.F() & (byte)StatusBits.HC) != 0) || (LowNibble(this.A()) > 9); var highAdjust = ((this.F() & (byte)StatusBits.CF) != 0) || (this.A() > 0x99); if ((this.F() & (byte)StatusBits.NF) != 0) @@ -1768,7 +1859,7 @@ namespace EightBit private bool CPIR() { this.CPI(); - return ((this.F() & (byte)StatusBits.PF) != 0) && ((this.F() & (byte)StatusBits.ZF) == 0); // See CPI + return ((this.F() & (byte)StatusBits.PF) != 0) && ((this.F() & (byte)StatusBits.ZF) == 0); // See CPI } private void CPD() @@ -1780,7 +1871,7 @@ namespace EightBit private bool CPDR() { this.CPD(); - return ((this.F() & (byte)StatusBits.PF) != 0) && ((this.F() & (byte)StatusBits.ZF) == 0); // See CPD + return ((this.F() & (byte)StatusBits.PF) != 0) && ((this.F() & (byte)StatusBits.ZF) == 0); // See CPD } private void BlockLoad(Register16 source, Register16 destination, Register16 counter) @@ -1790,7 +1881,7 @@ namespace EightBit var xy = this.A() + value; this.F() = SetFlag(this.F(), StatusBits.XF, xy & (int)Bits.Bit3); this.F() = SetFlag(this.F(), StatusBits.YF, xy & (int)Bits.Bit1); - F() = ClearFlag(this.F(), StatusBits.NF | StatusBits.HC); + this.F() = ClearFlag(this.F(), StatusBits.NF | StatusBits.HC); this.F() = SetFlag(this.F(), StatusBits.PF, --counter.Word); } @@ -1802,7 +1893,7 @@ namespace EightBit private bool LDIR() { this.LDI(); - return (this.F() & (byte)StatusBits.PF) != 0; // See LDI + return (this.F() & (byte)StatusBits.PF) != 0; // See LDI } private void LDD() @@ -1813,7 +1904,7 @@ namespace EightBit private bool LDDR() { this.LDD(); - return (this.F() & (byte)StatusBits.PF) == 0; // See LDD + return (this.F() & (byte)StatusBits.PF) == 0; // See LDD } private void BlockIn(Register16 source, Register16 destination) @@ -1834,7 +1925,7 @@ namespace EightBit private bool INIR() { this.INI(); - return (this.F() & (byte)StatusBits.ZF) == 0; // See INI + return (this.F() & (byte)StatusBits.ZF) == 0; // See INI } private void IND() @@ -1846,7 +1937,7 @@ namespace EightBit private bool INDR() { this.IND(); - return (this.F() & (byte)StatusBits.ZF) == 0; // See IND + return (this.F() & (byte)StatusBits.ZF) == 0; // See IND } private void BlockOut(Register16 source, Register16 destination) @@ -1870,7 +1961,7 @@ namespace EightBit private bool OTIR() { this.OUTI(); - return (this.F() & (byte)StatusBits.ZF) == 0; // See OUTI + return (this.F() & (byte)StatusBits.ZF) == 0; // See OUTI } private void OUTD() @@ -1882,7 +1973,7 @@ namespace EightBit private bool OTDR() { this.OUTD(); - return (this.F() & (byte)StatusBits.ZF) == 0; // See OUTD + return (this.F() & (byte)StatusBits.ZF) == 0; // See OUTD } private void NEG()