mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2024-06-11 15:29:37 +00:00
Add a .net Fuse test suite for the Z80 core (one "unexpected" result).
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
parent
63ef445a78
commit
9550ed57be
|
@ -30,7 +30,7 @@ namespace Fuse
|
||||||
|
|
||||||
protected virtual void ParseInternalState(string line)
|
protected virtual void ParseInternalState(string line)
|
||||||
{
|
{
|
||||||
var tokens = line.Split(new char[] { ' ', '\t' });
|
var tokens = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
this.ParseInternalState(tokens);
|
this.ParseInternalState(tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace Fuse
|
||||||
|
|
||||||
private bool TryParseLine(string line)
|
private bool TryParseLine(string line)
|
||||||
{
|
{
|
||||||
var split = line.Split(new char[] { ' ', '\t' });
|
var split = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
return this.TryParseLine(split);
|
return this.TryParseLine(split);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Fuse
|
||||||
|
|
||||||
public void Parse(Lines lines)
|
public void Parse(Lines lines)
|
||||||
{
|
{
|
||||||
var success = false;
|
bool success;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
var e = new TestEvent();
|
var e = new TestEvent();
|
||||||
|
|
6
Z80/Z80.FuseTest/App.config
Normal file
6
Z80/Z80.FuseTest/App.config
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
17
Z80/Z80.FuseTest/Program.cs
Normal file
17
Z80/Z80.FuseTest/Program.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// <copyright file="Program.cs" company="Adrian Conlon">
|
||||||
|
// Copyright (c) Adrian Conlon. All rights reserved.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
namespace Fuse
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var suite = new TestSuite("fuse-tests\\tests");
|
||||||
|
suite.Read();
|
||||||
|
suite.Parse();
|
||||||
|
suite.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
Z80/Z80.FuseTest/Properties/AssemblyInfo.cs
Normal file
36
Z80/Z80.FuseTest/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Z80.FuseTest")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("Z80.FuseTest")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("0233ff6c-db1a-4353-8e42-d22717770226")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
32
Z80/Z80.FuseTest/RegisterState.cs
Normal file
32
Z80/Z80.FuseTest/RegisterState.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// <copyright file="RegisterState.cs" company="Adrian Conlon">
|
||||||
|
// Copyright (c) Adrian Conlon. All rights reserved.
|
||||||
|
// </copyright>
|
||||||
|
namespace Fuse
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
public class RegisterState : AbstractRegisterState, IRegisterState
|
||||||
|
{
|
||||||
|
public int I { get; private set; } = -1;
|
||||||
|
|
||||||
|
public int R { get; private set; } = -1;
|
||||||
|
|
||||||
|
public bool IFF1 { get; private set; } = false;
|
||||||
|
|
||||||
|
public bool IFF2 { get; private set; } = false;
|
||||||
|
|
||||||
|
public int IM { get; private set; } = -1;
|
||||||
|
|
||||||
|
protected override void ParseInternalState(string[] tokens)
|
||||||
|
{
|
||||||
|
this.I = Convert.ToInt32(tokens[0], 16);
|
||||||
|
this.R = Convert.ToInt32(tokens[1], 16);
|
||||||
|
this.IFF1 = Convert.ToInt32(tokens[2], CultureInfo.InvariantCulture) == 1;
|
||||||
|
this.IFF2 = Convert.ToInt32(tokens[3], CultureInfo.InvariantCulture) == 1;
|
||||||
|
this.IM = Convert.ToInt32(tokens[4], CultureInfo.InvariantCulture);
|
||||||
|
this.Halted = Convert.ToInt32(tokens[5], CultureInfo.InvariantCulture) == 1;
|
||||||
|
this.TStates = Convert.ToInt32(tokens[6], CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
361
Z80/Z80.FuseTest/TestRunner.cs
Normal file
361
Z80/Z80.FuseTest/TestRunner.cs
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
// <copyright file="TestRunner.cs" company="Adrian Conlon">
|
||||||
|
// Copyright (c) Adrian Conlon. All rights reserved.
|
||||||
|
// </copyright>
|
||||||
|
|
||||||
|
namespace Fuse
|
||||||
|
{
|
||||||
|
public enum Register
|
||||||
|
{
|
||||||
|
AF,
|
||||||
|
BC,
|
||||||
|
DE,
|
||||||
|
HL,
|
||||||
|
AF_,
|
||||||
|
BC_,
|
||||||
|
DE_,
|
||||||
|
HL_,
|
||||||
|
IX,
|
||||||
|
IY,
|
||||||
|
SP,
|
||||||
|
PC,
|
||||||
|
MEMPTR,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestRunner : EightBit.Bus
|
||||||
|
{
|
||||||
|
private readonly Test<RegisterState> test;
|
||||||
|
private readonly Result<RegisterState> result;
|
||||||
|
private readonly EightBit.Ram ram = new EightBit.Ram(0x10000);
|
||||||
|
private readonly EightBit.InputOutput ports = new EightBit.InputOutput();
|
||||||
|
private readonly EightBit.Z80 cpu;
|
||||||
|
|
||||||
|
public TestRunner(Test<RegisterState> test, Result<RegisterState> result)
|
||||||
|
{
|
||||||
|
this.cpu = new EightBit.Z80(this, this.ports);
|
||||||
|
this.test = test;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Failed { get; private set; } = false;
|
||||||
|
|
||||||
|
public bool Unimplemented { get; private set; } = false;
|
||||||
|
|
||||||
|
public override EightBit.MemoryMapping Mapping(ushort address) => new EightBit.MemoryMapping(this.ram, 0, EightBit.Mask.Mask16, EightBit.AccessLevel.ReadWrite);
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
this.RaisePOWER();
|
||||||
|
this.Initialize();
|
||||||
|
var allowedCycles = this.test.RegisterState.TStates;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.cpu.Run(allowedCycles);
|
||||||
|
this.Check();
|
||||||
|
}
|
||||||
|
catch (System.InvalidOperationException error)
|
||||||
|
{
|
||||||
|
this.Unimplemented = true;
|
||||||
|
System.Console.Error.WriteLine($"**** Error: {error.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RaisePOWER()
|
||||||
|
{
|
||||||
|
base.RaisePOWER();
|
||||||
|
this.cpu.RaisePOWER();
|
||||||
|
this.cpu.RaiseRESET();
|
||||||
|
this.cpu.RaiseINT();
|
||||||
|
this.cpu.RaiseNMI();
|
||||||
|
this.InitialiseRegisters();
|
||||||
|
this.InitialiseMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LowerPOWER()
|
||||||
|
{
|
||||||
|
this.cpu.LowerPOWER();
|
||||||
|
base.LowerPOWER();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DumpDifference(string description, byte expected, byte actual)
|
||||||
|
{
|
||||||
|
var output = $"**** {description}, Expected: {expected:x2}, Got {actual:x2}";
|
||||||
|
System.Console.Error.WriteLine(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DumpDifference(string highDescription, string lowDescription, EightBit.Register16 expected, EightBit.Register16 actual)
|
||||||
|
{
|
||||||
|
var expectedHigh = expected.High;
|
||||||
|
var expectedLow = expected.Low;
|
||||||
|
|
||||||
|
var actualHigh = actual.High;
|
||||||
|
var actualLow = actual.Low;
|
||||||
|
|
||||||
|
if (expectedHigh != actualHigh)
|
||||||
|
{
|
||||||
|
DumpDifference(highDescription, actualHigh, expectedHigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedLow != actualLow)
|
||||||
|
{
|
||||||
|
DumpDifference(lowDescription, actualLow, expectedLow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitialiseRegisters()
|
||||||
|
{
|
||||||
|
var testState = this.test.RegisterState;
|
||||||
|
var inputRegisters = testState.Registers;
|
||||||
|
|
||||||
|
this.cpu.AF.Word = inputRegisters[(int)Register.AF_].Word;
|
||||||
|
this.cpu.BC.Word = inputRegisters[(int)Register.BC_].Word;
|
||||||
|
this.cpu.DE.Word = inputRegisters[(int)Register.DE_].Word;
|
||||||
|
this.cpu.HL.Word = inputRegisters[(int)Register.HL_].Word;
|
||||||
|
this.cpu.Exx();
|
||||||
|
this.cpu.ExxAF();
|
||||||
|
this.cpu.AF.Word = inputRegisters[(int)Register.AF].Word;
|
||||||
|
this.cpu.BC.Word = inputRegisters[(int)Register.BC].Word;
|
||||||
|
this.cpu.DE.Word = inputRegisters[(int)Register.DE].Word;
|
||||||
|
this.cpu.HL.Word = inputRegisters[(int)Register.HL].Word;
|
||||||
|
|
||||||
|
this.cpu.IX.Word = inputRegisters[(int)Register.IX].Word;
|
||||||
|
this.cpu.IY.Word = inputRegisters[(int)Register.IY].Word;
|
||||||
|
|
||||||
|
this.cpu.SP.Word = inputRegisters[(int)Register.SP].Word;
|
||||||
|
this.cpu.PC.Word = inputRegisters[(int)Register.PC].Word;
|
||||||
|
|
||||||
|
this.cpu.MEMPTR.Word = inputRegisters[(int)Register.MEMPTR].Word;
|
||||||
|
|
||||||
|
this.cpu.IV = (byte)testState.I;
|
||||||
|
this.cpu.REFRESH = (byte)testState.R;
|
||||||
|
this.cpu.IFF1 = testState.IFF1;
|
||||||
|
this.cpu.IFF2 = testState.IFF2;
|
||||||
|
this.cpu.IM = testState.IM;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitialiseMemory()
|
||||||
|
{
|
||||||
|
foreach (var memoryDatum in this.test.MemoryData)
|
||||||
|
{
|
||||||
|
var address = memoryDatum.Address;
|
||||||
|
foreach (var seed in memoryDatum.Bytes)
|
||||||
|
{
|
||||||
|
this.Poke(address++, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Check()
|
||||||
|
{
|
||||||
|
this.Checkregisters();
|
||||||
|
this.CheckMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Checkregisters()
|
||||||
|
{
|
||||||
|
var expectedState = this.result.RegisterState;
|
||||||
|
var expectedRegisters = expectedState.Registers;
|
||||||
|
|
||||||
|
var af = this.cpu.AF.Word == expectedRegisters[(int)Register.AF].Word;
|
||||||
|
var bc = this.cpu.BC.Word == expectedRegisters[(int)Register.BC].Word;
|
||||||
|
var de = this.cpu.DE.Word == expectedRegisters[(int)Register.DE].Word;
|
||||||
|
var hl = this.cpu.HL.Word == expectedRegisters[(int)Register.HL].Word;
|
||||||
|
|
||||||
|
this.cpu.Exx();
|
||||||
|
this.cpu.ExxAF();
|
||||||
|
|
||||||
|
var af_ = this.cpu.AF.Word == expectedRegisters[(int)Register.AF_].Word;
|
||||||
|
var bc_ = this.cpu.BC.Word == expectedRegisters[(int)Register.BC_].Word;
|
||||||
|
var de_ = this.cpu.DE.Word == expectedRegisters[(int)Register.DE_].Word;
|
||||||
|
var hl_ = this.cpu.HL.Word == expectedRegisters[(int)Register.HL_].Word;
|
||||||
|
|
||||||
|
var ix = this.cpu.IX.Word == expectedRegisters[(int)Register.IX].Word;
|
||||||
|
var iy = this.cpu.IY.Word == expectedRegisters[(int)Register.IY].Word;
|
||||||
|
|
||||||
|
var sp = this.cpu.SP.Word == expectedRegisters[(int)Register.SP].Word;
|
||||||
|
var pc = this.cpu.PC.Word == expectedRegisters[(int)Register.PC].Word;
|
||||||
|
|
||||||
|
var memptr = this.cpu.MEMPTR.Word == expectedRegisters[(int)Register.MEMPTR].Word;
|
||||||
|
|
||||||
|
var iv = this.cpu.IV == expectedState.I;
|
||||||
|
var refresh = this.cpu.REFRESH == expectedState.R;
|
||||||
|
var iff1 = this.cpu.IFF1 == expectedState.IFF1;
|
||||||
|
var iff2 = this.cpu.IFF2 == expectedState.IFF2;
|
||||||
|
var im = this.cpu.IM == expectedState.IM;
|
||||||
|
|
||||||
|
// And back again, so the following works as expected...
|
||||||
|
this.cpu.Exx();
|
||||||
|
this.cpu.ExxAF();
|
||||||
|
|
||||||
|
var success =
|
||||||
|
af && bc && de && hl
|
||||||
|
&& af_ && bc_ && de_ && hl_
|
||||||
|
&& ix && iy
|
||||||
|
&& sp && pc
|
||||||
|
&& iv && refresh
|
||||||
|
&& iff1 && iff2
|
||||||
|
&& im
|
||||||
|
&& memptr;
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
this.Failed = true;
|
||||||
|
System.Console.Error.WriteLine($"**** Failed test (Register): {this.test.Description}");
|
||||||
|
|
||||||
|
if (!af)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.AF];
|
||||||
|
var actualWord = this.cpu.AF;
|
||||||
|
DumpDifference("A", "F", expectedWord, actualWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bc)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.BC];
|
||||||
|
var actualWord = this.cpu.BC;
|
||||||
|
DumpDifference("B", "C", expectedWord, actualWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!de)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.DE];
|
||||||
|
var actualWord = this.cpu.DE;
|
||||||
|
DumpDifference("D", "E", expectedWord, actualWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hl)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.HL];
|
||||||
|
var actualWord = this.cpu.HL;
|
||||||
|
DumpDifference("H", "L", expectedWord, actualWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ix)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.IX];
|
||||||
|
var actualWord = this.cpu.IX;
|
||||||
|
DumpDifference("IXH", "IXL", actualWord, expectedWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iy)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.IY];
|
||||||
|
var actualWord = this.cpu.IY;
|
||||||
|
DumpDifference("IYH", "IYL", actualWord, expectedWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sp)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.SP];
|
||||||
|
var actualWord = this.cpu.SP;
|
||||||
|
DumpDifference("SPH", "SPL", expectedWord, actualWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pc)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.PC];
|
||||||
|
var actualWord = this.cpu.PC;
|
||||||
|
DumpDifference("PCH", "PCL", expectedWord, actualWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memptr)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.MEMPTR];
|
||||||
|
var actualWord = this.cpu.MEMPTR;
|
||||||
|
DumpDifference("MEMPTRH", "MEMPTRL", actualWord, expectedWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cpu.ExxAF();
|
||||||
|
this.cpu.Exx();
|
||||||
|
|
||||||
|
if (!af_)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.AF];
|
||||||
|
var actualWord = this.cpu.AF;
|
||||||
|
DumpDifference("A'", "F'", expectedWord, actualWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bc_)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.BC_];
|
||||||
|
var actualWord = this.cpu.BC;
|
||||||
|
DumpDifference("B'", "C'", actualWord, expectedWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!de_)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.DE_];
|
||||||
|
var actualWord = this.cpu.DE;
|
||||||
|
DumpDifference("D'", "E'", actualWord, expectedWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hl_)
|
||||||
|
{
|
||||||
|
var expectedWord = expectedRegisters[(int)Register.HL_];
|
||||||
|
var actualWord = this.cpu.HL;
|
||||||
|
DumpDifference("H'", "L'", actualWord, expectedWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iv)
|
||||||
|
{
|
||||||
|
var output = $"**** IV, Expected: {expectedState.I:X2}, Got: {this.cpu.IV:X2}";
|
||||||
|
System.Console.Error.WriteLine(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!refresh)
|
||||||
|
{
|
||||||
|
var output = $"**** R, Expected: {expectedState.R:X2}, Got: {this.cpu.REFRESH:X2}";
|
||||||
|
System.Console.Error.WriteLine(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iff1)
|
||||||
|
{
|
||||||
|
var output = $"**** IFF1, Expected: {expectedState.IFF1}, Got: {this.cpu.IFF1}";
|
||||||
|
System.Console.Error.WriteLine(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iff2)
|
||||||
|
{
|
||||||
|
var output = $"**** IFF2, Expected: {expectedState.IFF2}, Got: {this.cpu.IFF2}";
|
||||||
|
System.Console.Error.WriteLine(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!im)
|
||||||
|
{
|
||||||
|
var output = $"**** IM, Expected: {expectedState.IM}, Got: {this.cpu.IM}";
|
||||||
|
System.Console.Error.WriteLine(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckMemory()
|
||||||
|
{
|
||||||
|
var first = true;
|
||||||
|
|
||||||
|
foreach (var memoryDatum in this.result.MemoryData)
|
||||||
|
{
|
||||||
|
var address = memoryDatum.Address;
|
||||||
|
foreach (var expected in memoryDatum.Bytes)
|
||||||
|
{
|
||||||
|
var actual = this.Peek(address);
|
||||||
|
if (expected != actual)
|
||||||
|
{
|
||||||
|
this.Failed = true;
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
System.Console.Error.WriteLine($"**** Failed test (Memory): {this.test.Description}");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Console.Error.WriteLine($"**** Difference: Address: {address:x4} Expected: {expected:x2} Actual: {actual:x2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
++address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
Z80/Z80.FuseTest/TestSuite.cs
Normal file
58
Z80/Z80.FuseTest/TestSuite.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
// <copyright file="TestSuite.cs" company="Adrian Conlon">
|
||||||
|
// Copyright (c) Adrian Conlon. All rights reserved.
|
||||||
|
// </copyright>
|
||||||
|
namespace Fuse
|
||||||
|
{
|
||||||
|
public class TestSuite
|
||||||
|
{
|
||||||
|
private readonly Tests<RegisterState> tests;
|
||||||
|
private readonly Results<RegisterState> results;
|
||||||
|
|
||||||
|
public TestSuite(string path)
|
||||||
|
{
|
||||||
|
this.tests = new Tests<RegisterState>(path + ".in");
|
||||||
|
this.results = new Results<RegisterState>(path + ".expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Read()
|
||||||
|
{
|
||||||
|
this.tests.Read();
|
||||||
|
this.results.Read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Parse()
|
||||||
|
{
|
||||||
|
this.tests.Parse();
|
||||||
|
this.results.Parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
var failedCount = 0;
|
||||||
|
var unimplementedCount = 0;
|
||||||
|
foreach (var test in this.tests.Container)
|
||||||
|
{
|
||||||
|
var key = test.Key;
|
||||||
|
System.Console.Out.WriteLine($"** Checking: {key}");
|
||||||
|
|
||||||
|
var input = test.Value;
|
||||||
|
var result = this.results.Container[key];
|
||||||
|
var runner = new TestRunner(input, result);
|
||||||
|
|
||||||
|
runner.Run();
|
||||||
|
if (runner.Failed)
|
||||||
|
{
|
||||||
|
++failedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runner.Unimplemented)
|
||||||
|
{
|
||||||
|
++unimplementedCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Console.Out.WriteLine($"+++ Failed test count: {failedCount}");
|
||||||
|
System.Console.Out.WriteLine($"+++ Unimplemented test count: {unimplementedCount}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
Z80/Z80.FuseTest/Z80.FuseTest.csproj
Normal file
70
Z80/Z80.FuseTest/Z80.FuseTest.csproj
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{0233FF6C-DB1A-4353-8E42-D22717770226}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>Z80.FuseTest</RootNamespace>
|
||||||
|
<AssemblyName>Z80.FuseTest</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="RegisterState.cs" />
|
||||||
|
<Compile Include="TestRunner.cs" />
|
||||||
|
<Compile Include="TestSuite.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\EightBit\EightBit.csproj">
|
||||||
|
<Project>{6ebf8857-62a3-4ef4-af21-c1844031d7e4}</Project>
|
||||||
|
<Name>EightBit</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\Fuse\Fuse.csproj">
|
||||||
|
<Project>{28e65032-5dff-406f-9385-0ee1422a7f4a}</Project>
|
||||||
|
<Name>Fuse</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\Z80.csproj">
|
||||||
|
<Project>{c00648c1-bac1-4efb-816f-e87c091619d7}</Project>
|
||||||
|
<Name>Z80</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
79
Z80/Z80.FuseTest/fuse-tests/README
Normal file
79
Z80/Z80.FuseTest/fuse-tests/README
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
File formats
|
||||||
|
============
|
||||||
|
|
||||||
|
tests.in
|
||||||
|
--------
|
||||||
|
|
||||||
|
Each test has the format:
|
||||||
|
|
||||||
|
<arbitrary test description>
|
||||||
|
AF BC DE HL AF' BC' DE' HL' IX IY SP PC MEMPTR
|
||||||
|
I R IFF1 IFF2 IM <halted> <tstates>
|
||||||
|
|
||||||
|
<halted> specifies whether the Z80 is halted.
|
||||||
|
<tstates> specifies the number of tstates to run the test for, in
|
||||||
|
decimal; the number actually executed may be higher, as the final
|
||||||
|
instruction is allowed to complete.
|
||||||
|
|
||||||
|
Then followed by lines specifying the initial memory setup. Each has
|
||||||
|
the format:
|
||||||
|
|
||||||
|
<start address> <byte1> <byte2> ... -1
|
||||||
|
|
||||||
|
eg
|
||||||
|
|
||||||
|
1234 56 78 9a -1
|
||||||
|
|
||||||
|
says to put 0x56 at 0x1234, 0x78 at 0x1235 and 0x9a at 0x1236.
|
||||||
|
|
||||||
|
Finally, -1 to end the test. Blank lines may follow before the next test.
|
||||||
|
|
||||||
|
tests.expected
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Each test output starts with the test description, followed by a list
|
||||||
|
of 'events': each has the format
|
||||||
|
|
||||||
|
<time> <type> <address> <data>
|
||||||
|
|
||||||
|
<time> is simply the time at which the event occurs.
|
||||||
|
<type> is one of MR (memory read), MW (memory write), MC (memory
|
||||||
|
contend), PR (port read), PW (port write) or PC (port contend).
|
||||||
|
<address> is the address (or IO port) affected.
|
||||||
|
<data> is the byte written or read. Missing for contentions.
|
||||||
|
|
||||||
|
After that, lines specifying AF, BC etc as for .in files. <tstates>
|
||||||
|
now specifies the final time.
|
||||||
|
|
||||||
|
After that, lines specifying which bits of memory have changed since
|
||||||
|
the initial setup. Same format as for .in files.
|
||||||
|
|
||||||
|
Why some specific tests are here
|
||||||
|
================================
|
||||||
|
|
||||||
|
{02,0a,32}_1,edb[012389ab]_[12],d3_4:
|
||||||
|
check MEMPTR is set correctly after various instructions.
|
||||||
|
|
||||||
|
37_{1,2,3}: check the behaviour of SCF with respect to bits 3 and 5
|
||||||
|
(bug fixed on 20040225).
|
||||||
|
|
||||||
|
cb46_{1,2,3,4,5}: check the correct bits of MEMPTR are copied to bits 3
|
||||||
|
and 5 of the flags register after a BIT n,(HL) instruction.
|
||||||
|
|
||||||
|
cb{4,5,6,7}{7,f}_1: designed to check that bits 3 and 5 are copied to
|
||||||
|
F only for BIT 3,<arg> and BIT 5,<arg> respectively
|
||||||
|
(bug fixed on 20040225).
|
||||||
|
|
||||||
|
However, later research has revealed the bits 3
|
||||||
|
and 5 are copied on all BIT instructions, so these
|
||||||
|
tests are now essentially redundant.
|
||||||
|
|
||||||
|
d{3,b}_{1,2,3}: check for correct port contention on IO in the four
|
||||||
|
relevant states (port high byte in 0x40 to 0x7f or not,
|
||||||
|
port low bit set or reset).
|
||||||
|
|
||||||
|
dd00.in, ddfd00.in: test timings of "extended NOP" opcodes DD 00 and
|
||||||
|
DD FD 00; the extra 00 at the end is to check the
|
||||||
|
next opcode executes at the right time (bug fixed
|
||||||
|
on 20060722).
|
||||||
|
|
18913
Z80/Z80.FuseTest/fuse-tests/tests.expected
Normal file
18913
Z80/Z80.FuseTest/fuse-tests/tests.expected
Normal file
File diff suppressed because it is too large
Load Diff
9153
Z80/Z80.FuseTest/fuse-tests/tests.in
Normal file
9153
Z80/Z80.FuseTest/fuse-tests/tests.in
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user