diff options
-rw-r--r-- | native/Noddybox.Emulation.EightBit.Z80.Test/Program.cs | 71 | ||||
-rw-r--r-- | native/Noddybox.Emulation.EightBit.Z80.Test/TestMachine.cs | 260 | ||||
-rw-r--r-- | src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs | 45 | ||||
-rw-r--r-- | src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs | 9 | ||||
-rw-r--r-- | src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs | 55 | ||||
-rw-r--r-- | 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 /// </summary>
class Program
{
+ static Queue<string> GetBlock(StreamReader str)
+ {
+ Queue<string> q = new Queue<string>();
+ 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<string> t = GetBlock(test);
+ Queue<string> 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<Register16> Decode(string i)
+ {
+ Queue<Register16> l = new Queue<Register16>();
+
+ 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<string> input, List<string> expected)
+ public bool Run(string name, Queue<string> input, Queue<string> expected)
{
Output(ConsoleColor.Black, ConsoleColor.White, "Running test {0}", name);
+
+ Queue<Register16> 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 @@ -335,6 +335,24 @@ namespace Noddybox.Emulation.EightBit.Z80 }
/// <summary>
+ /// The current state of the IX register pair.
+ /// </summary>
+ public Register16 IX_Register
+ {
+ get { return IX; }
+ set { IX = value; }
+ }
+
+ /// <summary>
+ /// The current state of the IY register pair.
+ /// </summary>
+ public Register16 IY_Register
+ {
+ get { return IY; }
+ set { IY = value; }
+ }
+
+ /// <summary>
/// The current state of the stack pointer.
/// </summary>
public ushort StackPointer
@@ -400,7 +418,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// <summary>
/// The state of the IFF1 register.
/// </summary>
- public bool IFF1_Regsiter
+ public bool IFF1_Register
{
get { return IFF1; }
set { IFF1 = value; }
@@ -409,7 +427,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// <summary>
/// The state of the IFF2 register.
/// </summary>
- 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];
}
/// <summary>
@@ -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];
}
/// <summary>
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.
/// </summary>
public byte Opcode {get; set;}
-
- /// <summary>
- /// The current state of the accumulator.
- /// </summary>
- public byte A {get; set;}
-
- /// <summary>
- /// The current state of the flag register.
- /// </summary>
- public Z80Flags F {get; set;}
-
- /// <summary>
- /// The current state of the BC register pair.
- /// </summary>
- public Register16 BC {get; set;}
-
- /// <summary>
- /// The current state of the DE register pair.
- /// </summary>
- public Register16 DE {get; set;}
-
- /// <summary>
- /// The current state of the HL register pair.
- /// </summary>
- public Register16 HL {get; set;}
-
- /// <summary>
- /// The current state of the stack pointer.
- /// </summary>
- public ushort SP {get; set;}
-
- /// <summary>
- /// The current state of the program counter.
- /// </summary>
- public ushort PC {get; set;}
-
- /// <summary>
- /// The alternate AF' register.
- /// </summary>
- public Register16 AF_ {get; set;}
-
- /// <summary>
- /// The alternate BC' register.
- /// </summary>
- public Register16 BC_ {get; set;}
-
- /// <summary>
- /// The alternate DE' register.
- /// </summary>
- public Register16 DE_ {get; set;}
-
- /// <summary>
- /// The alternate HL' register.
- /// </summary>
- 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 }
}
+ /// <summary>
+ /// Gets the ticks this frame so far.
+ /// </summary>
+ public uint Ticks
+ {
+ get {return frameCount;}
+ }
+
#endregion
#region Public members
|