// This file is part of the Noddybox.Emulation C# suite. // // Noddybox.Emulation is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Noddybox.Emulation is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Noddybox.Emulation. If not, see . // // Copyright (c) 2012 Ian Cowburn // using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using Noddybox.Emulation.EightBit.Z80.Disassembler; namespace Noddybox.Emulation.EightBit.Z80.Test { class TestMachine : IMemory, IDevice { private readonly byte[] mem = new byte[0x10000]; private readonly Z80Cpu z80 = new Z80Cpu(); private readonly Z80Disassembler disassembler = new Z80Disassembler(); private readonly Clock clock = new Clock(uint.MaxValue, uint.MaxValue); private void Output(ConsoleColor pen, ConsoleColor paper, string format, params object[] p) { Console.ForegroundColor = pen; Console.BackgroundColor = paper; Console.Write(format, p); Console.ResetColor(); Console.WriteLine(); } 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); return mem[address]; } void IMemory.Write(ushort address, byte value) { // Output(ConsoleColor.Red, ConsoleColor.Black, "Writing {0:X2} to {1:X4}", value, address); mem[address] = value; } byte IDevice.Read(ushort device) { // Output(ConsoleColor.Green, ConsoleColor.DarkGray, "Reading 00 from device {1:X4}", device); Register16 r = new Register16(device); return r.high; } void IDevice.Write(ushort device, byte value) { // Output(ConsoleColor.Red, ConsoleColor.DarkGray, "Writing {0:X2} to device {1:X4}", value, device); } public bool Run(string name, Queue input, Queue expected, bool stop) { Output(ConsoleColor.Black, ConsoleColor.White, "Running test {0}{1}", name, stop ? " - STOPPING FOR DEBUG THIS PASS" : String.Empty); 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); Output(ConsoleColor.Gray, ConsoleColor.Black, z80.ToString()); 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; ushort start = addr; foreach (Register16 b in line) { mem[addr++] = b.low; } while(start < addr) { string a, b, c; start = disassembler.Disassemble(start, out a, out b, out c); Output(ConsoleColor.Yellow, ConsoleColor.Blue, "{0}: {1,-20} ; {2}", a, b, c); } } } if (stop) { Debugger.Break(); } while (clock.Ticks < cyclesToRun) { z80.Step(); } Output(ConsoleColor.White, ConsoleColor.Black, z80.ToString()); bool ok = true; while(expected.Peek().StartsWith(" ")) { // Output(ConsoleColor.DarkGray, ConsoleColor.Black, "Not yet handled - {0}", expected.Dequeue()); 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); z80.Reset(); disassembler.Initialise(this); } } }