diff --git a/EightBit/Bus.cs b/EightBit/Bus.cs index 18b9243..963d28a 100644 --- a/EightBit/Bus.cs +++ b/EightBit/Bus.cs @@ -66,8 +66,8 @@ namespace EightBit public void Write() { this.OnWritingByte(); - var data = this.Data; // N.B. Don't join these two lines together: the - this.Reference() = data; // data bus integrity is lost, due to evaluation order! + var value = this.Data; // N.B. Don't join these two lines together: the + this.Reference() = value; // data bus integrity is lost, due to evaluation order! this.OnWrittenByte(); } diff --git a/Z80/Disassembler.cs b/Z80/Disassembler.cs index be00702..8df4f24 100644 --- a/Z80/Disassembler.cs +++ b/Z80/Disassembler.cs @@ -4,6 +4,8 @@ namespace EightBit { + using System; + public class Disassembler { private bool prefixCB = false; @@ -29,6 +31,11 @@ namespace EightBit public static string State(Z80 cpu) { + if (cpu == null) + { + throw new ArgumentNullException(nameof(cpu)); + } + var pc = cpu.PC; var sp = cpu.SP; @@ -68,59 +75,40 @@ namespace EightBit public string Disassemble(Z80 cpu) { + if (cpu == null) + { + throw new ArgumentNullException(nameof(cpu)); + } + this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false; return this.Disassemble(cpu, cpu.PC.Word); } - private static string CC(int flag) + private static string CC(int flag) => flag switch { - switch (flag) - { - case 0: - return "NZ"; - case 1: - return "Z"; - case 2: - return "NC"; - case 3: - return "C"; - case 4: - return "PO"; - case 5: - return "PE"; - case 6: - return "P"; - case 7: - return "M"; - } + 0 => "NZ", + 1 => "Z", + 2 => "NC", + 3 => "C", + 4 => "PO", + 5 => "PE", + 6 => "P", + 7 => "M", + _ => throw new System.ArgumentOutOfRangeException(nameof(flag)), + }; - throw new System.ArgumentOutOfRangeException(nameof(flag)); - } - - private static string ALU(int which) + private static string ALU(int which) => which switch { - switch (which) - { - case 0: // ADD A,n - return "ADD"; - case 1: // ADC - return "ADC"; - case 2: // SUB n - return "SUB"; - case 3: // SBC A,n - return "SBC"; - case 4: // AND n - return "AND"; - case 5: // XOR n - return "XOR"; - case 6: // OR n - return "OR"; - case 7: // CP n - return "CP"; - } - - throw new System.ArgumentOutOfRangeException(nameof(which)); - } + 0 => "ADD", + 1 => "ADC", + 2 => "SUB", + 3 => "SBC", + 4 => "AND", + 5 => "XOR", + 6 => "OR", + 7 => "CP", + _ => throw new System.ArgumentOutOfRangeException(nameof(which)), + }; private string Disassemble(Z80 cpu, ushort pc) { @@ -152,7 +140,7 @@ namespace EightBit } else if (this.prefixED) { - output += this.DisassembleED(cpu, pc, ref specification, ref dumpCount, x, y, z, p, q); + output += this.DisassembleED(ref specification, ref dumpCount, x, y, z, p, q); } else { @@ -231,7 +219,7 @@ namespace EightBit return output; } - private string DisassembleED(Z80 cpu, ushort pc, ref string specification, ref int dumpCount, int x, int y, int z, int p, int q) + private string DisassembleED(ref string specification, ref int dumpCount, int x, int y, int z, int p, int q) { var output = string.Empty; switch (x) @@ -272,15 +260,11 @@ namespace EightBit specification = "NEG"; break; case 5: // Return from interrupt - switch (y) + specification = y switch { - case 1: - specification = "RETI"; - break; - default: - specification = "RETN"; - break; - } + 1 => "RETI", + _ => "RETN", + }; break; case 6: // Set interrupt mode switch (y) @@ -572,15 +556,7 @@ namespace EightBit break; case 1: // 8-bit loading - if (z == 6 && y == 6) - { - specification = "HALT"; // Exception (replaces LD (HL), (HL)) - } - else - { - specification = $"LD {this.R(y)},{this.R(z)}"; - } - + specification = z == 6 && y == 6 ? "HALT" : $"LD {this.R(y)},{this.R(z)}"; break; case 2: // Operate on accumulator and register/memory location specification = $"{ALU(y)} A,{this.R(z)}"; diff --git a/Z80/RefreshRegister.cs b/Z80/RefreshRegister.cs index 317ba39..4de82dd 100644 --- a/Z80/RefreshRegister.cs +++ b/Z80/RefreshRegister.cs @@ -4,7 +4,7 @@ namespace EightBit { - public struct RefreshRegister + public struct RefreshRegister : System.IEquatable { private readonly byte high; private byte variable; @@ -37,17 +37,10 @@ namespace EightBit public byte ToByte() => ToByte(this); - public override bool Equals(object obj) - { - if (!(obj is RefreshRegister)) - { - return false; - } - - var rhs = (RefreshRegister)obj; - return rhs.high == this.high && rhs.variable == this.variable; - } + public override bool Equals(object obj) => obj is RefreshRegister ? this.Equals((RefreshRegister)obj) : false; public override int GetHashCode() => this.high + this.variable; + + public bool Equals(RefreshRegister other) => other.high == this.high && other.variable == this.variable; } } diff --git a/Z80/Z80.cs b/Z80/Z80.cs index 32163f8..81c9ed7 100644 --- a/Z80/Z80.cs +++ b/Z80/Z80.cs @@ -28,6 +28,7 @@ namespace EightBit private bool prefixCB = false; private bool prefixDD = false; private bool prefixED = false; + private bool prefixFD = false; private PinLevel nmiLine = PinLevel.Low; private PinLevel m1Line = PinLevel.Low; @@ -351,7 +352,7 @@ namespace EightBit this.OnExecutingInstruction(); if (this.Powered) { - this.displaced = this.prefixCB = this.prefixDD = this.prefixED = false; + this.displaced = this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false; var handled = false; if (this.RESET.Lowered()) { @@ -423,7 +424,7 @@ namespace EightBit this.AF.Word = this.IX.Word = this.IY.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16; - this.prefixCB = this.prefixDD = this.prefixED = false; + this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false; base.OnRaisedPOWER(); } @@ -630,80 +631,38 @@ namespace EightBit private void EnableInterrupts() => this.IFF1 = this.IFF2 = true; - private Register16 HL2() + private Register16 HL2() => this.prefixDD ? this.IX : this.prefixFD ? this.IY : this.HL; + + private Register16 RP(int rp) => rp switch { - if (!this.displaced) - { - return this.HL; - } + 0 => this.BC, + 1 => this.DE, + 2 => this.HL2(), + 3 => this.SP, + _ => throw new ArgumentOutOfRangeException(nameof(rp)), + }; - if (this.prefixDD) - { - return this.IX; - } - - // Must be FD prefix - return this.IY; - } - - private Register16 RP(int rp) + private Register16 RP2(int rp) => rp switch { - switch (rp) - { - case 0: - return this.BC; - case 1: - return this.DE; - case 2: - return this.HL2(); - case 3: - return this.SP; - default: - throw new ArgumentOutOfRangeException(nameof(rp)); - } - } + 0 => this.BC, + 1 => this.DE, + 2 => this.HL2(), + 3 => this.AF, + _ => throw new ArgumentOutOfRangeException(nameof(rp)), + }; - private Register16 RP2(int rp) + private byte R(int r) => r switch { - switch (rp) - { - case 0: - return this.BC; - case 1: - return this.DE; - case 2: - return this.HL2(); - case 3: - return this.AF; - default: - throw new ArgumentOutOfRangeException(nameof(rp)); - } - } - - private byte R(int r) - { - switch (r) - { - case 0: - return this.B; - case 1: - return this.C; - case 2: - return this.D; - case 3: - return this.E; - case 4: - return this.HL2().High; - case 5: - return this.HL2().Low; - case 6: - return this.BusRead(this.displaced ? this.DisplacedAddress : this.HL.Word); - case 7: - return this.A; - default: - throw new ArgumentOutOfRangeException(nameof(r)); - } - } + 0 => this.B, + 1 => this.C, + 2 => this.D, + 3 => this.E, + 4 => this.HL2().High, + 5 => this.HL2().Low, + 6 => this.BusRead(this.displaced ? this.DisplacedAddress : this.HL.Word), + 7 => this.A, + _ => throw new ArgumentOutOfRangeException(nameof(r)), + }; private void R(int r, byte value) { @@ -792,36 +751,18 @@ namespace EightBit switch (x) { case 0: // rot[y] r[z] - switch (y) + operand = y switch { - case 0: - operand = this.RLC(operand); - break; - case 1: - operand = this.RRC(operand); - break; - case 2: - operand = this.RL(operand); - break; - case 3: - operand = this.RR(operand); - break; - case 4: - operand = this.SLA(operand); - break; - case 5: - operand = this.SRA(operand); - break; - case 6: - operand = this.SLL(operand); - break; - case 7: - operand = this.SRL(operand); - break; - default: - throw new NotSupportedException("Invalid operation mode"); - } - + 0 => this.RLC(operand), + 1 => this.RRC(operand), + 2 => this.RL(operand), + 3 => this.RR(operand), + 4 => this.SLA(operand), + 5 => this.SRA(operand), + 6 => this.SLL(operand), + 7 => this.SRL(operand), + _ => throw new NotSupportedException("Invalid operation mode"), + }; this.F = AdjustSZP(this.F, operand); break; case 1: // BIT y, r[z] @@ -841,11 +782,7 @@ namespace EightBit if (update) { this.Tick(); - if (!this.displaced) - { - this.R(z, operand); - } - else + if (this.displaced) { this.BusWrite(operand); if (!memoryZ) @@ -853,6 +790,10 @@ namespace EightBit this.R2(z, operand); } } + else + { + this.R(z, operand); + } } } @@ -885,18 +826,12 @@ namespace EightBit this.WritePort(); break; case 2: // 16-bit add/subtract with carry - switch (q) + this.HL2().Word = q switch { - case 0: // SBC HL, rp[p] - this.HL2().Word = this.SBC(this.HL2(), this.RP(p)); - break; - case 1: // ADC HL, rp[p] - this.HL2().Word = this.ADC(this.HL2(), this.RP(p)); - break; - default: - throw new NotSupportedException("Invalid operation mode"); - } - + 0 => this.SBC(this.HL2(), this.RP(p)), // SBC HL, rp[p] + 1 => this.ADC(this.HL2(), this.RP(p)), // ADC HL, rp[p] + _ => throw new NotSupportedException("Invalid operation mode"), + }; break; case 3: // Retrieve/store register pair from/to immediate address this.Bus.Address.Word = this.FetchWord().Word; @@ -1412,13 +1347,10 @@ namespace EightBit break; case 2: { // Operate on accumulator and register/memory location - if (memoryZ) + if (memoryZ && this.displaced) { - if (this.displaced) - { - this.FetchDisplacement(); - this.Tick(5); - } + this.FetchDisplacement(); + this.Tick(5); } var value = this.R(z); @@ -1563,7 +1495,7 @@ namespace EightBit this.Execute(this.FetchInitialOpCode()); break; case 3: // FD prefix - this.displaced = true; + this.displaced = this.prefixFD = true; this.Execute(this.FetchInitialOpCode()); break; default: