From 788b8cc4dd404a826ce881c020ee6ca0388a5975 Mon Sep 17 00:00:00 2001 From: Ian C Date: Thu, 1 Mar 2012 00:02:07 +0000 Subject: Initial working version of test suite. Fixed INC8 and DEC8 with results. --- .../Program.cs | 71 +++++- .../TestMachine.cs | 260 ++++++++++++++++++++- src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs | 45 ++-- .../Z80CpuBaseOpcodes.cs | 9 +- .../Z80CpuEventArgs.cs | 55 ----- src/Noddybox.Emulation/Clock.cs | 8 + 6 files changed, 363 insertions(+), 85 deletions(-) diff --git a/native/Noddybox.Emulation.EightBit.Z80.Test/Program.cs b/native/Noddybox.Emulation.EightBit.Z80.Test/Program.cs index 0f2a19d..43dab10 100644 --- a/native/Noddybox.Emulation.EightBit.Z80.Test/Program.cs +++ b/native/Noddybox.Emulation.EightBit.Z80.Test/Program.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.IO; namespace Noddybox.Emulation.EightBit.Z80.Test { @@ -28,9 +29,77 @@ namespace Noddybox.Emulation.EightBit.Z80.Test /// class Program { + static Queue GetBlock(StreamReader str) + { + Queue q = new Queue(); + bool process = false; + + while(!str.EndOfStream) + { + string s = str.ReadLine(); + + if (process) + { + if (s.Trim().Length == 0) + { + return q; + } + + q.Enqueue(s); + } + else + { + if (s.Trim().Length > 0) + { + process = true; + q.Enqueue(s); + } + } + } + + return q; + } + static void Main(string[] args) { - new TestMachine("Test", null, null); + try + { + StreamReader test = new StreamReader("tests.in"); + StreamReader expected = new StreamReader("tests.expected"); + + while(!test.EndOfStream) + { + Queue t = GetBlock(test); + Queue e = GetBlock(expected); + + if (t.Count > 0) + { + if (t.Peek() != e.Peek()) + { + throw new Exception(String.Format("Test name {0}, expected name {1}", t.Peek(), e.Peek())); + } + + TestMachine m = new TestMachine(); + e.Dequeue(); + + if (!m.Run(t.Dequeue(), t, e)) + { + Console.ReadKey(true); + } + } + } + + test.Close(); + expected.Close(); + } + catch (Exception e) + { + while (e != null) + { + Console.WriteLine("**** {0}: {1}", e.GetType(), e.Message); + e = e.InnerException; + } + } } } } diff --git a/native/Noddybox.Emulation.EightBit.Z80.Test/TestMachine.cs b/native/Noddybox.Emulation.EightBit.Z80.Test/TestMachine.cs index 09e868b..b5d7810 100644 --- a/native/Noddybox.Emulation.EightBit.Z80.Test/TestMachine.cs +++ b/native/Noddybox.Emulation.EightBit.Z80.Test/TestMachine.cs @@ -26,7 +26,7 @@ namespace Noddybox.Emulation.EightBit.Z80.Test { private readonly byte[] mem = new byte[0x10000]; private readonly Z80Cpu z80 = new Z80Cpu(); - private readonly Clock clock = new Clock(100000, 50); + private readonly Clock clock = new Clock(uint.MaxValue, uint.MaxValue); private void Output(ConsoleColor pen, ConsoleColor paper, string format, params object[] p) { @@ -36,6 +36,21 @@ namespace Noddybox.Emulation.EightBit.Z80.Test Console.ResetColor(); } + private Queue Decode(string i) + { + Queue l = new Queue(); + + foreach (string s in i.Split(new char[] {' ', '\t'}, StringSplitOptions.RemoveEmptyEntries)) + { + if (s != "-1") + { + l.Enqueue(new Register16(UInt16.Parse(s, System.Globalization.NumberStyles.HexNumber))); + } + } + + return l; + } + byte IMemory.Read(ushort address) { Output(ConsoleColor.Green, ConsoleColor.Black, "Reading {0:X2} from {1:X4}", mem[address], address); @@ -59,9 +74,250 @@ namespace Noddybox.Emulation.EightBit.Z80.Test Output(ConsoleColor.Red, ConsoleColor.DarkGray, "Writing {0:X2} to device {1:X4}", value, device); } - public TestMachine(string name, List input, List expected) + public bool Run(string name, Queue input, Queue expected) { Output(ConsoleColor.Black, ConsoleColor.White, "Running test {0}", name); + + Queue line = Decode(input.Dequeue()); + Register16 r = line.Dequeue(); + + z80.Acummulator = r.high; + z80.StatusFlags = (Z80Flags)r.low; + + z80.BC_Register = line.Dequeue(); + z80.DE_Register = line.Dequeue(); + z80.HL_Register = line.Dequeue(); + + z80.AF_Alternate = line.Dequeue(); + z80.BC_Alternate = line.Dequeue(); + z80.DE_Alternate = line.Dequeue(); + z80.HL_Alternate = line.Dequeue(); + + z80.IX_Register = line.Dequeue(); + z80.IY_Register = line.Dequeue(); + z80.StackPointer = line.Dequeue().reg; + z80.ProgramCounter = line.Dequeue().reg; + + line = Decode(input.Dequeue()); + + z80.InterruptVector = line.Dequeue().low; + z80.Refresh = line.Dequeue().low; + z80.IFF1_Register = (line.Dequeue().reg != 0); + z80.IFF2_Register = (line.Dequeue().reg != 0); + z80.IM_Register = line.Dequeue().low; + z80.HaltLine = (line.Dequeue().reg != 0); + + int cyclesToRun = Convert.ToInt32(line.Dequeue().reg.ToString("X")); + + while(input.Count > 0) + { + line = Decode(input.Dequeue()); + + if (line.Count > 1) + { + ushort addr = line.Dequeue().reg; + + foreach (Register16 b in line) + { + mem[addr++] = b.low; + } + } + } + + while(clock.Ticks < cyclesToRun) + { + z80.Step(); + } + + bool ok = true; + + while(expected.Peek().StartsWith(" ")) + { + Output(ConsoleColor.DarkGray, ConsoleColor.Black, "Not yet handled - {0}", expected.Dequeue()); + } + + line = Decode(expected.Dequeue()); + + r = line.Dequeue(); + if (r.high != z80.Acummulator) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in A, got {1:X}", r.high, z80.Acummulator); + ok = false; + } + + if ((Z80Flags)r.low != z80.StatusFlags) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0} in F, got {1}", (Z80Flags)r.low, z80.StatusFlags); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.BC_Register.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in BC, got {1:X}", r.reg, z80.BC_Register.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.DE_Register.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in DE, got {1:X}", r.reg, z80.DE_Register.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.HL_Register.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in HL, got {1:X}", r.reg, z80.HL_Register.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.AF_Alternate.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in AF', got {1:X}", r.reg, z80.AF_Alternate.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.BC_Alternate.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in BC', got {1:X}", r.reg, z80.BC_Alternate.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.DE_Alternate.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in DE', got {1:X}", r.reg, z80.DE_Alternate.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.HL_Alternate.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in HL', got {1:X}", r.reg, z80.HL_Alternate.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.IX_Register.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in IX, got {1:X}", r.reg, z80.IX_Register.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.IY_Register.reg) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in IY, got {1:X}", r.reg, z80.IY_Register.reg); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.StackPointer) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in SP, got {1:X}", r.reg, z80.StackPointer); + ok = false; + } + + r = line.Dequeue(); + if (r.reg != z80.ProgramCounter) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in PC, got {1:X}", r.reg, z80.ProgramCounter); + ok = false; + } + + line = Decode(expected.Dequeue()); + + r = line.Dequeue(); + if (r.low != z80.InterruptVector) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in I, got {1:X}", r.low, z80.InterruptVector); + ok = false; + } + + r = line.Dequeue(); + if (r.low != z80.Refresh) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in R, got {1:X}", r.low, z80.Refresh); + ok = false; + } + + r = line.Dequeue(); + if ((r.reg != 0) != z80.IFF1_Register) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0} in IFF1, got {1}", (r.reg != 0), z80.IFF1_Register); + ok = false; + } + + r = line.Dequeue(); + if ((r.reg != 0) != z80.IFF2_Register) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0} in IFF2, got {1}", (r.reg != 0), z80.IFF2_Register); + ok = false; + } + + r = line.Dequeue(); + if (r.low != z80.IM_Register) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} in IM, got {1:X}", r.low, z80.IM_Register); + ok = false; + } + + r = line.Dequeue(); + if ((r.reg != 0) != z80.HaltLine) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0} in HALT, got {1}", (r.reg != 0), z80.HaltLine); + ok = false; + } + + int cyclesToTest = Convert.ToInt32(line.Dequeue().reg.ToString("X")); + + if (cyclesToTest != clock.Ticks) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0} cycles, got {1}", cyclesToTest, clock.Ticks); + ok = false; + } + + while (expected.Count > 0) + { + line = Decode(expected.Dequeue()); + + if (line.Count > 1) + { + ushort addr = line.Dequeue().reg; + + foreach (Register16 b in line) + { + if (mem[addr] != b.low) + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Expected {0:X} at location {1:X}, got {2:X}", b.low, addr, mem[addr]); + ok = false; + } + + addr++; + } + } + } + + if (ok) + { + Output(ConsoleColor.Yellow, ConsoleColor.Black, "Test passed"); + } + else + { + Output(ConsoleColor.Red, ConsoleColor.Black, "Test FAILED"); + } + + Console.WriteLine(); + + return ok; + } + + public TestMachine() + { + z80.Initialise(this, this, clock); } } } diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs index 676a1b1..a2e6fed 100644 --- a/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs +++ b/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs @@ -334,6 +334,24 @@ namespace Noddybox.Emulation.EightBit.Z80 set { HL = value; } } + /// + /// The current state of the IX register pair. + /// + public Register16 IX_Register + { + get { return IX; } + set { IX = value; } + } + + /// + /// The current state of the IY register pair. + /// + public Register16 IY_Register + { + get { return IY; } + set { IY = value; } + } + /// /// The current state of the stack pointer. /// @@ -400,7 +418,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// /// The state of the IFF1 register. /// - public bool IFF1_Regsiter + public bool IFF1_Register { get { return IFF1; } set { IFF1 = value; } @@ -409,7 +427,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// /// The state of the IFF2 register. /// - public bool IFF2_Regsiter + public bool IFF2_Register { get { return IFF2; } set { IFF2 = value; } @@ -490,17 +508,6 @@ namespace Noddybox.Emulation.EightBit.Z80 Z80CpuEventArgs e = new Z80CpuEventArgs { Opcode = opcode, - A = this.A, - F = this.F, - BC = this.BC, - DE = this.DE, - HL = this.HL, - SP = this.SP, - PC = this.PC, - AF_ = this.AF_, - BC_ = this.BC_, - DE_ = this.DE_, - HL_ = this.HL_ }; switch(type) @@ -513,18 +520,6 @@ namespace Noddybox.Emulation.EightBit.Z80 OnEDNopEvent(e); break; } - - A = e.A; - F = e.F; - BC = e.BC; - DE = e.DE; - HL = e.HL; - SP = e.SP; - PC = e.PC; - AF_ = e.AF_; - BC_ = e.BC_; - DE_ = e.DE_; - HL_ = e.HL_; } #endregion diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs index 389ba41..24f8093 100644 --- a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs +++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs @@ -369,7 +369,7 @@ namespace Noddybox.Emulation.EightBit.Z80 { reg++; - F = Z80Flags.Carry; + F &= Z80Flags.Carry; if (reg == 0x80) { @@ -380,6 +380,8 @@ namespace Noddybox.Emulation.EightBit.Z80 { F |= Z80Flags.HalfCarry; } + + F |= SZtable[reg] | H35table[reg]; } /// @@ -390,7 +392,8 @@ namespace Noddybox.Emulation.EightBit.Z80 { reg--; - F = Z80Flags.Carry | Z80Flags.Neg; + F &= Z80Flags.Carry; + F |= Z80Flags.Neg; if (reg == 0x7f) { @@ -401,6 +404,8 @@ namespace Noddybox.Emulation.EightBit.Z80 { F |= Z80Flags.HalfCarry; } + + F |= SZtable[reg] | H35table[reg]; } /// diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs index fb0173a..84edfa1 100644 --- a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs +++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs @@ -28,60 +28,5 @@ namespace Noddybox.Emulation.EightBit.Z80 /// The opcode that was executed to trigger the event. /// public byte Opcode {get; set;} - - /// - /// The current state of the accumulator. - /// - public byte A {get; set;} - - /// - /// The current state of the flag register. - /// - public Z80Flags F {get; set;} - - /// - /// The current state of the BC register pair. - /// - public Register16 BC {get; set;} - - /// - /// The current state of the DE register pair. - /// - public Register16 DE {get; set;} - - /// - /// The current state of the HL register pair. - /// - public Register16 HL {get; set;} - - /// - /// The current state of the stack pointer. - /// - public ushort SP {get; set;} - - /// - /// The current state of the program counter. - /// - public ushort PC {get; set;} - - /// - /// The alternate AF' register. - /// - public Register16 AF_ {get; set;} - - /// - /// The alternate BC' register. - /// - public Register16 BC_ {get; set;} - - /// - /// The alternate DE' register. - /// - public Register16 DE_ {get; set;} - - /// - /// The alternate HL' register. - /// - public Register16 HL_ {get; set;} } } diff --git a/src/Noddybox.Emulation/Clock.cs b/src/Noddybox.Emulation/Clock.cs index 72a2cc8..379287e 100644 --- a/src/Noddybox.Emulation/Clock.cs +++ b/src/Noddybox.Emulation/Clock.cs @@ -57,6 +57,14 @@ namespace Noddybox.Emulation } } + /// + /// Gets the ticks this frame so far. + /// + public uint Ticks + { + get {return frameCount;} + } + #endregion #region Public members -- cgit v1.2.3