diff --git a/EightBit.sln b/EightBit.sln
index a86ef49..05c6526 100644
--- a/EightBit.sln
+++ b/EightBit.sln
@@ -13,7 +13,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M6502.Test", "M6502\M6502.T
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z80", "Z80\Z80.csproj", "{C00648C1-BAC1-4EFB-816F-E87C091619D7}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z80.Test", "Z80\Z80.Test\Z80.Test.csproj", "{F749BEAE-8903-400B-875C-1220ADCFEF08}"
+EndProject
Global
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
@@ -83,6 +88,18 @@ Global
{C00648C1-BAC1-4EFB-816F-E87C091619D7}.Release|x64.Build.0 = Release|Any CPU
{C00648C1-BAC1-4EFB-816F-E87C091619D7}.Release|x86.ActiveCfg = Release|Any CPU
{C00648C1-BAC1-4EFB-816F-E87C091619D7}.Release|x86.Build.0 = Release|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Debug|x64.Build.0 = Debug|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Debug|x86.Build.0 = Debug|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|x64.ActiveCfg = Release|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|x64.Build.0 = Release|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|x86.ActiveCfg = Release|Any CPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/EightBit/EightBit.UnitTest/EightBit.UnitTest.csproj b/EightBit/EightBit.UnitTest/EightBit.UnitTest.csproj
index 38ebbba..682b05d 100644
--- a/EightBit/EightBit.UnitTest/EightBit.UnitTest.csproj
+++ b/EightBit/EightBit.UnitTest/EightBit.UnitTest.csproj
@@ -1,6 +1,6 @@
-
+
Debug
@@ -39,13 +39,16 @@
prompt
4
AllRules.ruleset
+ true
- ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
+ ..\..\packages\MSTest.TestFramework.2.0.0-beta2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
+ True
- ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
+ ..\..\packages\MSTest.TestFramework.2.0.0-beta2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
+ True
@@ -65,8 +68,6 @@
-
-
@@ -74,8 +75,8 @@
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
+
+
-
+
\ No newline at end of file
diff --git a/EightBit/EightBit.UnitTest/packages.config b/EightBit/EightBit.UnitTest/packages.config
index 7c9f59f..7d27efe 100644
--- a/EightBit/EightBit.UnitTest/packages.config
+++ b/EightBit/EightBit.UnitTest/packages.config
@@ -1,7 +1,7 @@
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/EightBit/EightBit.csproj b/EightBit/EightBit.csproj
index cfe641d..6f89051 100644
--- a/EightBit/EightBit.csproj
+++ b/EightBit/EightBit.csproj
@@ -33,7 +33,8 @@
4
latest
AllRules.ruleset
- false
+ true
+ true
true
@@ -75,12 +76,14 @@
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/EightBit/packages.config b/EightBit/packages.config
index 4e0d690..45f05d8 100644
--- a/EightBit/packages.config
+++ b/EightBit/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/M6502/M6502.Test/M6502.Test.csproj b/M6502/M6502.Test/M6502.Test.csproj
index 0888262..27a96ea 100644
--- a/M6502/M6502.Test/M6502.Test.csproj
+++ b/M6502/M6502.Test/M6502.Test.csproj
@@ -34,6 +34,7 @@
prompt
4
AllRules.ruleset
+ true
@@ -54,10 +55,8 @@
-
- Designer
-
+
@@ -70,8 +69,8 @@
-
-
+
+
\ No newline at end of file
diff --git a/M6502/M6502.Test/packages.config b/M6502/M6502.Test/packages.config
index 4e0d690..45f05d8 100644
--- a/M6502/M6502.Test/packages.config
+++ b/M6502/M6502.Test/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/M6502/M6502.csproj b/M6502/M6502.csproj
index fb1b3d8..af2c924 100644
--- a/M6502/M6502.csproj
+++ b/M6502/M6502.csproj
@@ -34,6 +34,7 @@
4
latest
AllRules.ruleset
+ true
@@ -60,12 +61,14 @@
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/M6502/packages.config b/M6502/packages.config
index 4e0d690..45f05d8 100644
--- a/M6502/packages.config
+++ b/M6502/packages.config
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/Z80/Disassembly.cs b/Z80/Disassembly.cs
new file mode 100644
index 0000000..cf78080
--- /dev/null
+++ b/Z80/Disassembly.cs
@@ -0,0 +1,215 @@
+namespace Z80
+{
+ using EightBit;
+ using System.Text;
+
+ public class Disassembly
+ {
+ private bool prefixCB = false;
+ private bool prefixDD = false;
+ private bool prefixED = false;
+ private bool prefixFD = false;
+ private readonly Bus bus;
+
+ public Disassembly(Bus bus)
+ {
+ this.bus = bus;
+ }
+
+ public Bus Bus => this.bus;
+
+ public static string State(Z80 cpu)
+ {
+ var pc = cpu.PC();
+ var sp = cpu.SP();
+
+ var a = cpu.A();
+ var f = cpu.F();
+
+ var b = cpu.B();
+ var c = cpu.C();
+
+ var d = cpu.D();
+ var e = cpu.E();
+
+ var h = cpu.H();
+ var l = cpu.L();
+
+ var i = cpu.IV;
+ var r = cpu.REFRESH();
+
+ var im = cpu.IM;
+
+ return
+ $"PC={pc} SP={sp} "
+ + $"A={AsHex(a)} F={AsFlags(f)} "
+ + $"B={AsHex(b)} C={AsHex(c)} "
+ + $"D={AsHex(d)} E={AsHex(e)} "
+ + $"H={AsHex(h)} L={AsHex(l)} "
+ + $"I={AsHex(i)} R={AsHex(r)} "
+ + $"IM={im}";
+ }
+
+ public string Disassemble(Z80 cpu)
+ {
+ this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
+ return Disassemble(cpu, cpu.PC().Word);
+ }
+
+ public static string flag(byte value, int flag, string represents)
+ {
+ return "";
+ }
+
+ public static string AsFlags(byte value)
+ {
+ return "";
+ }
+
+ public static string AsHex(byte value)
+ {
+ return "";
+ }
+
+ public static string AsHex(ushort value)
+ {
+ return "";
+ }
+
+ public static string AsBinary(byte value)
+ {
+ return "";
+ }
+
+ public static string AsDecimal(byte value)
+ {
+ return "";
+ }
+
+ public static string AsInvalid(byte value)
+ {
+ return "";
+ }
+
+ private string Disassemble(Z80 cpu, ushort pc)
+ {
+ var opCode = Bus.Peek(pc);
+
+ var decoded = cpu.GetDecodedOpCode(opCode);
+
+ var x = decoded.X;
+ var y = decoded.Y;
+ var z = decoded.Z;
+
+ var p = decoded.P;
+ var q = decoded.Q;
+
+ var immediate = Bus.Peek((ushort)(pc + 1));
+ var absolute = cpu.PeekWord((ushort)(pc + 1)).Word;
+ var displacement = (sbyte)immediate;
+ var relative = pc + displacement + 2;
+ var indexedImmediate = Bus.Peek((ushort)(pc + 1));
+
+ var dumpCount = 0;
+
+ var output = $"{AsHex(opCode)}";
+
+ var specification = "";
+
+ if (this.prefixCB)
+ output += this.DisassembleCB(
+ cpu, pc,
+ specification, ref dumpCount,
+ x, y, z, p, q);
+ else if (this.prefixED)
+ output += this.DisassembleED(
+ cpu, pc,
+ specification, ref dumpCount,
+ x, y, z, p, q);
+ else
+ output += this.DisassembleOther(
+ cpu, pc,
+ specification, ref dumpCount,
+ x, y, z, p, q);
+
+ for (int i = 0; i < dumpCount; ++i)
+ output += $"{AsHex(this.Bus.Peek((ushort)(pc + i + 1)))}";
+
+ var outputFormatSpecification = !this.prefixDD;
+ if (this.prefixDD)
+ {
+ if (opCode != 0xdd)
+ {
+ outputFormatSpecification = true;
+ }
+ }
+
+ if (outputFormatSpecification)
+ {
+ output += '\t';
+ //m_formatter.parse(specification);
+ //output << m_formatter % (int)immediate % (int)absolute % relative % (int)displacement % indexedImmediate;
+ }
+
+ return output;
+ }
+
+ private string DisassembleCB(
+ Z80 cpu,
+ ushort pc,
+ string specification,
+ ref int dumpCount,
+ int x, int y, int z,
+ int p, int q)
+ {
+ return "";
+ }
+
+ private string DisassembleED(
+ Z80 cpu,
+ ushort pc,
+ string specification,
+ ref int dumpCount,
+ int x, int y, int z,
+ int p, int q)
+ {
+ return "";
+ }
+
+ private string DisassembleOther(
+ Z80 cpu,
+ ushort pc,
+ string specification,
+ ref int dumpCount,
+ int x, int y, int z,
+ int p, int q)
+ {
+ return "";
+ }
+
+ private string RP(int rp)
+ {
+ return "";
+ }
+
+ private string RP2(int rp)
+ {
+ return "";
+ }
+
+ private string R(int r)
+ {
+ return "";
+ }
+
+ private static string CC(int flag)
+ {
+ return "";
+ }
+
+ private static string ALU(int which)
+ {
+ return "";
+ }
+ }
+}
diff --git a/Z80/Properties/AssemblyInfo.cs b/Z80/Properties/AssemblyInfo.cs
index 6aede72..475493f 100644
--- a/Z80/Properties/AssemblyInfo.cs
+++ b/Z80/Properties/AssemblyInfo.cs
@@ -1,4 +1,8 @@
-using System.Reflection;
+//
+// Copyright (c) Adrian Conlon. All rights reserved.
+//
+
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/Z80/Settings.StyleCop b/Z80/Settings.StyleCop
new file mode 100644
index 0000000..348ed88
--- /dev/null
+++ b/Z80/Settings.StyleCop
@@ -0,0 +1,222 @@
+
+
+ en-GB
+
+
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+ False
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Z80/Z80.Test/Board.cs b/Z80/Z80.Test/Board.cs
new file mode 100644
index 0000000..4263854
--- /dev/null
+++ b/Z80/Z80.Test/Board.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Z80.Test
+{
+ class Board
+ {
+ }
+}
diff --git a/Z80/Z80.Test/Configuration.cs b/Z80/Z80.Test/Configuration.cs
new file mode 100644
index 0000000..9fdccce
--- /dev/null
+++ b/Z80/Z80.Test/Configuration.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Z80.Test
+{
+ class Configuration
+ {
+ }
+}
diff --git a/Z80/Z80.Test/Program.cs b/Z80/Z80.Test/Program.cs
new file mode 100644
index 0000000..cc85882
--- /dev/null
+++ b/Z80/Z80.Test/Program.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Z80.Test
+{
+ class Program
+ {
+ }
+}
diff --git a/Z80/Z80.Test/Properties/AssemblyInfo.cs b/Z80/Z80.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..cf8cfb2
--- /dev/null
+++ b/Z80/Z80.Test/Properties/AssemblyInfo.cs
@@ -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.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Z80.Test")]
+[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("f749beae-8903-400b-875c-1220adcfef08")]
+
+// 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")]
diff --git a/Z80/Z80.Test/TestHarness.cs b/Z80/Z80.Test/TestHarness.cs
new file mode 100644
index 0000000..8d7d2db
--- /dev/null
+++ b/Z80/Z80.Test/TestHarness.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Z80.Test
+{
+ class TestHarness
+ {
+ }
+}
diff --git a/Z80/Z80.Test/Z80.Test.csproj b/Z80/Z80.Test/Z80.Test.csproj
new file mode 100644
index 0000000..5074f2d
--- /dev/null
+++ b/Z80/Z80.Test/Z80.Test.csproj
@@ -0,0 +1,55 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {F749BEAE-8903-400B-875C-1220ADCFEF08}
+ Library
+ Properties
+ Z80.Test
+ Z80.Test
+ v4.7.2
+ 512
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Z80/Z80.Test/packages.config b/Z80/Z80.Test/packages.config
new file mode 100644
index 0000000..45f05d8
--- /dev/null
+++ b/Z80/Z80.Test/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Z80/Z80.Test/roms/CPUTEST.COM b/Z80/Z80.Test/roms/CPUTEST.COM
new file mode 100644
index 0000000..dd535a4
Binary files /dev/null and b/Z80/Z80.Test/roms/CPUTEST.COM differ
diff --git a/Z80/Z80.Test/roms/prelim.com b/Z80/Z80.Test/roms/prelim.com
new file mode 100644
index 0000000..e5c82b5
Binary files /dev/null and b/Z80/Z80.Test/roms/prelim.com differ
diff --git a/Z80/Z80.Test/roms/prelim.z80 b/Z80/Z80.Test/roms/prelim.z80
new file mode 100644
index 0000000..7dc0fd3
--- /dev/null
+++ b/Z80/Z80.Test/roms/prelim.z80
@@ -0,0 +1,343 @@
+ .title 'Preliminary Z80 tests'
+
+; prelim.z80 - Preliminary Z80 tests
+; Copyright (C) 1994 Frank D. Cringle
+;
+; This program 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 2
+; of the License, or (at your option) any later version.
+;
+; This program 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 this program; if not, write to the Free Software
+; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+; These tests have two goals. To start with, we assume the worst and
+; successively test the instructions needed to continue testing.
+; Then we try to test all instructions which cannot be handled by
+; zexlax - the crc-based instruction exerciser.
+
+; Initially errors are 'reported' by jumping to 0. This should reboot
+; cp/m, so if the program terminates without any output one of the
+; early tests failed. Later errors are reported by outputting an
+; address via the bdos conout routine. The address can be located in
+; a listing of this program.
+
+; If the program runs to completion it displays a suitable message.
+
+ aseg
+ org 100h
+
+start: ld a,1 ; test simple compares and z/nz jumps
+ cp 2
+ jp z,0
+ cp 1
+ jp nz,0
+ jp lab0
+ halt ; emergency exit
+ db 0ffh
+
+lab0: call lab2 ; does a simple call work?
+lab1: jp 0 ; fail
+
+lab2: pop hl ; check return address
+ ld a,h
+ cp high lab1
+ jp z,lab3
+ jp 0
+lab3: ld a,l
+ cp low lab1
+ jp z,lab4
+ jp 0
+
+; test presence and uniqueness of all machine registers
+; (except ir)
+lab4: ld sp,regs1
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ex af,af'
+ exx
+ pop af
+ pop bc
+ pop de
+ pop hl
+ pop ix
+ pop iy
+ ld sp,regs2+20
+ push iy
+ push ix
+ push hl
+ push de
+ push bc
+ push af
+ ex af,af'
+ exx
+ push hl
+ push de
+ push bc
+ push af
+
+v: set 0
+ rept 20
+ ld a,(regs2+v/2)
+v: set v+2
+ cp v
+ jp nz,0
+ endm
+
+; test access to memory via (hl)
+ ld hl,hlval
+ ld a,(hl)
+ cp 0a5h
+ jp nz,0
+ ld hl,hlval+1
+ ld a,(hl)
+ cp 03ch
+ jp nz,0
+
+; test unconditional return
+ ld sp,stack
+ ld hl,reta
+ push hl
+ ret
+ jp 0
+
+; test instructions needed for hex output
+reta: ld a,255
+ and a,15
+ cp 15
+ jp nz,0
+ ld a,05ah
+ and 15
+ cp 00ah
+ jp nz,0
+ rrca
+ cp 005h
+ jp nz,0
+ rrca
+ cp 082h
+ jp nz,0
+ rrca
+ cp 041h
+ jp nz,0
+ rrca
+ cp 0a0h
+ jp nz,0
+ ld hl,01234h
+ push hl
+ pop bc
+ ld a,b
+ cp 012h
+ jp nz,0
+ ld a,c
+ cp 034h
+ jp nz,0
+
+; from now on we can report errors by displaying an address
+
+; test conditional call, ret, jp, jr
+tcond: macro flag,pcond,ncond,rel
+ ld hl,&flag
+ push hl
+ pop af
+ call &pcond,lab1&pcond
+ jp error
+lab1&pcond: pop hl
+ ld hl,0d7h xor &flag
+ push hl
+ pop af
+ call &ncond,lab2&pcond
+ jp error
+lab2&pcond: pop hl
+ ld hl,lab3&pcond
+ push hl
+ ld hl,&flag
+ push hl
+ pop af
+ ret &pcond
+ call error
+lab3&pcond: ld hl,lab4&pcond
+ push hl
+ ld hl,0d7h xor &flag
+ push hl
+ pop af
+ ret &ncond
+ call error
+lab4&pcond: ld hl,&flag
+ push hl
+ pop af
+ jp &pcond,lab5&pcond
+ call error
+lab5&pcond: ld hl,0d7h xor &flag
+ push hl
+ pop af
+ jp &ncond,lab6&pcond
+ call error
+lab6&pcond:
+ if &rel
+ ld hl,&flag
+ push hl
+ pop af
+ jr &pcond,lab7&pcond
+ call error
+lab7&pcond: ld hl,0d7h xor &flag
+ push hl
+ pop af
+ jr &ncond,lab8&pcond
+ call error
+lab8&pcond:
+ endif
+ endm
+
+ tcond 1,c,nc,1
+ tcond 4,pe,po,0
+ tcond 040h,z,nz,1
+ tcond 080h,m,p,0
+
+; test indirect jumps
+ ld hl,lab5
+ jp (hl)
+ call error
+lab5: ld hl,lab6
+ push hl
+ pop ix
+ jp (ix)
+ call error
+lab6: ld hl,lab7
+ push hl
+ pop iy
+ jp (iy)
+ call error
+
+; djnz (and (partially) inc a, inc hl)
+lab7: ld a,0a5h
+ ld b,4
+lab8: rrca
+ djnz lab8
+ cp 05ah
+ call nz,error
+ ld b,16
+lab9: inc a
+ djnz lab9
+ cp 06ah
+ call nz,error
+ ld b,0
+ ld hl,0
+lab10: inc hl
+ djnz lab10
+ ld a,h
+ cp 1
+ call nz,error
+ ld a,l
+ cp 0
+ call nz,error
+
+; relative addressing
+reladr: macro r
+ ld &r,hlval
+ ld a,(&r)
+ cp 0a5h
+ call nz,error
+ ld a,(&r+1)
+ cp 03ch
+ call nz,error
+ inc &r
+ ld a,(&r-1)
+ cp 0a5h
+ call nz,error
+ ld &r,hlval-126
+ ld a,(&r+127)
+ cp 03ch
+ call nz,error
+ ld &r,hlval+128
+ ld a,(&r-128)
+ cp 0a5h
+ call nz,error
+ endm
+
+ reladr ix
+ reladr iy
+
+allok: ld de,okmsg
+ ld c,9
+ call 5
+ jp 0
+
+okmsg: db 'Preliminary tests complete$'
+
+
+; display address at top of stack and exit
+error: pop bc
+ ld h,high hextab
+ ld a,b
+ rrca
+ rrca
+ rrca
+ rrca
+ and 15
+ ld l,a
+ ld a,(hl)
+ call conout
+ ld a,b
+ and 15
+ ld l,a
+ ld a,(hl)
+ call conout
+ ld a,c
+ rrca
+ rrca
+ rrca
+ rrca
+ and 15
+ ld l,a
+ ld a,(hl)
+ call conout
+ ld a,c
+ and 15
+ ld l,a
+ ld a,(hl)
+ call conout
+ ld a,13
+ call conout
+ ld a,10
+ call conout
+ jp 0
+
+conout: push af
+ push bc
+ push de
+ push hl
+ ld c,2
+ ld e,a
+ call 5
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+v: set 0
+regs1: rept 20
+v: set v+2
+ db v
+ endm
+
+regs2: ds 20,0
+
+hlval: db 0a5h,03ch
+
+; skip to next page boundary
+ org (($+255)/256)*256
+hextab: db '0123456789abcdef'
+ ds 240
+stack: equ $
+
+ end
diff --git a/Z80/Z80.Test/roms/zexall.com b/Z80/Z80.Test/roms/zexall.com
new file mode 100644
index 0000000..fa0e6ff
Binary files /dev/null and b/Z80/Z80.Test/roms/zexall.com differ
diff --git a/Z80/Z80.Test/roms/zexdoc.com b/Z80/Z80.Test/roms/zexdoc.com
new file mode 100644
index 0000000..5cfd531
Binary files /dev/null and b/Z80/Z80.Test/roms/zexdoc.com differ
diff --git a/Z80/Z80.Test/roms/zexdoc.z80 b/Z80/Z80.Test/roms/zexdoc.z80
new file mode 100644
index 0000000..2a56c84
--- /dev/null
+++ b/Z80/Z80.Test/roms/zexdoc.z80
@@ -0,0 +1,1546 @@
+ .title 'Z80 instruction set exerciser'
+
+; zexlax.z80 - Z80 instruction set exerciser
+; Copyright (C) 1994 Frank D. Cringle
+;
+; This program 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 2
+; of the License, or (at your option) any later version.
+;
+; This program 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 this program; if not, write to the Free Software
+; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ aseg
+ org 100h
+
+ jp start
+
+; machine state before test (needs to be at predictably constant address)
+msbt: ds 14
+spbt: ds 2
+
+; For the purposes of this test program, the machine state consists of:
+; a 2 byte memory operand, followed by
+; the registers iy,ix,hl,de,bc,af,sp
+; for a total of 16 bytes.
+
+; The program tests instructions (or groups of similar instructions)
+; by cycling through a sequence of machine states, executing the test
+; instruction for each one and running a 32-bit crc over the resulting
+; machine states. At the end of the sequence the crc is compared to
+; an expected value that was found empirically on a real Z80.
+
+; A test case is defined by a descriptor which consists of:
+; a flag mask byte,
+; the base case,
+; the incement vector,
+; the shift vector,
+; the expected crc,
+; a short descriptive message.
+;
+; The flag mask byte is used to prevent undefined flag bits from
+; influencing the results. Documented flags are as per Mostek Z80
+; Technical Manual.
+;
+; The next three parts of the descriptor are 20 byte vectors
+; corresponding to a 4 byte instruction and a 16 byte machine state.
+; The first part is the base case, which is the first test case of
+; the sequence. This base is then modified according to the next 2
+; vectors. Each 1 bit in the increment vector specifies a bit to be
+; cycled in the form of a binary counter. For instance, if the byte
+; corresponding to the accumulator is set to 0ffh in the increment
+; vector, the test will be repeated for all 256 values of the
+; accumulator. Note that 1 bits don't have to be contiguous. The
+; number of test cases 'caused' by the increment vector is equal to
+; 2^(number of 1 bits). The shift vector is similar, but specifies a
+; set of bits in the test case that are to be successively inverted.
+; Thus the shift vector 'causes' a number of test cases equal to the
+; number of 1 bits in it.
+
+; The total number of test cases is the product of those caused by the
+; counter and shift vectors and can easily become unweildy. Each
+; individual test case can take a few milliseconds to execute, due to
+; the overhead of test setup and crc calculation, so test design is a
+; compromise between coverage and execution time.
+
+; This program is designed to detect differences between
+; implementations and is not ideal for diagnosing the causes of any
+; discrepancies. However, provided a reference implementation (or
+; real system) is available, a failing test case can be isolated by
+; hand using a binary search of the test space.
+
+
+start: ld hl,(6)
+ ld sp,hl
+ ld de,msg1
+ ld c,9
+ call bdos
+
+ ld hl,tests ; first test case
+loop: ld a,(hl) ; end of list ?
+ inc hl
+ or (hl)
+ jp z,done
+ dec hl
+ call stt
+ jp loop
+
+done: ld de,msg2
+ ld c,9
+ call bdos
+ jp 0 ; warm boot
+
+tests:
+ dw adc16
+ dw add16
+ dw add16x
+ dw add16y
+ dw alu8i
+ dw alu8r
+ dw alu8rx
+ dw alu8x
+ dw bitx
+ dw bitz80
+ dw cpd1
+ dw cpi1
+ dw daa
+ dw inca
+ dw incb
+ dw incbc
+ dw incc
+ dw incd
+ dw incde
+ dw ince
+ dw inch
+ dw inchl
+ dw incix
+ dw inciy
+ dw incl
+ dw incm
+ dw incsp
+ dw incx
+ dw incxh
+ dw incxl
+ dw incyh
+ dw incyl
+ dw ld161
+ dw ld162
+ dw ld163
+ dw ld164
+ dw ld165
+ dw ld166
+ dw ld167
+ dw ld168
+ dw ld16im
+ dw ld16ix
+ dw ld8bd
+ dw ld8im
+ dw ld8imx
+ dw ld8ix1
+ dw ld8ix2
+ dw ld8ix3
+ dw ld8ixy
+ dw ld8rr
+ dw ld8rrx
+ dw lda
+ dw ldd1
+ dw ldd2
+ dw ldi1
+ dw ldi2
+ dw neg
+ dw rld
+ dw rot8080
+ dw rotxy
+ dw rotz80
+ dw srz80
+ dw srzx
+ dw st8ix1
+ dw st8ix2
+ dw st8ix3
+ dw stabd
+ dw 0
+
+tstr: macro insn,memop,iy,ix,hl,de,bc,flags,acc,sp
+ local lab
+&lab: db insn
+ ds &lab+4-$,0
+ dw &memop,&iy,&ix,&hl,&de,&bc
+ db &flags
+ db &acc
+ dw &sp
+ if $-&lab ne 20
+ error 'missing parameter'
+ endif
+ endm
+
+tmsg: macro m
+ local lab
+&lab: db m
+ if $ ge &lab+30
+ error 'message too long'
+ else
+ ds &lab+30-$,'.'
+ endif
+ db '$'
+ endm
+
+; hl, (38,912 cycles)
+adc16: db 0c7h ; flag mask
+ tstr <0edh,042h>,0832ch,04f88h,0f22bh,0b339h,07e1fh,01563h,0d3h,089h,0465eh
+ tstr <0,038h>,0,0,0,0f821h,0,0,0,0,0 ; (1024 cycles)
+ tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles)
+ db 0f8h,0b4h,0eah,0a9h ; expected crc
+ tmsg ' hl,'
+
+; add hl, (19,456 cycles)
+add16: db 0c7h ; flag mask
+ tstr 9,0c4a5h,0c4c7h,0d226h,0a050h,058eah,08566h,0c6h,0deh,09bc9h
+ tstr 030h,0,0,0,0f821h,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles)
+ db 089h,0fdh,0b6h,035h ; expected crc
+ tmsg 'add hl,'
+
+; add ix, (19,456 cycles)
+add16x: db 0c7h ; flag mask
+ tstr <0ddh,9>,0ddach,0c294h,0635bh,033d3h,06a76h,0fa20h,094h,068h,036f5h
+ tstr <0,030h>,0,0,0f821h,0,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,-1,0,-1,-1,0d7h,0,-1 ; (38 cycles)
+ db 0c1h,033h,079h,00bh ; expected crc
+ tmsg 'add ix,'
+
+; add iy, (19,456 cycles)
+add16y: db 0c7h ; flag mask
+ tstr <0fdh,9>,0c7c2h,0f407h,051c1h,03e96h,00bf4h,0510fh,092h,01eh,071eah
+ tstr <0,030h>,0,0f821h,0,0,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,-1,0,0,-1,-1,0d7h,0,-1 ; (38 cycles)
+ db 0e8h,081h,07bh,09eh ; expected crc
+ tmsg 'add iy,'
+
+; aluop a,nn (28,672 cycles)
+alu8i: db 0d7h ; flag mask
+ tstr 0c6h,09140h,07e3ch,07a67h,0df6dh,05b61h,00b29h,010h,066h,085b2h
+ tstr 038h,0,0,0,0,0,0,0,-1,0 ; (2048 cycles)
+ tstr <0,-1>,0,0,0,0,0,0,0d7h,0,0 ; (14 cycles)
+ db 048h,079h,093h,060h ; expected crc
+ tmsg 'aluop a,nn'
+
+; aluop a, (753,664 cycles)
+alu8r: db 0d7h ; flag mask
+ tstr 080h,0c53eh,0573ah,04c4dh,msbt,0e309h,0a666h,0d0h,03bh,0adbbh
+ tstr 03fh,0,0,0,0,0,0,0,-1,0 ; (16,384 cycles)
+ tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles)
+ db 0feh,043h,0b0h,016h ; expected crc
+ tmsg 'aluop a,'
+
+; aluop a, (376,832 cycles)
+alu8rx: db 0d7h ; flag mask
+ tstr <0ddh,084h>,0d6f7h,0c76eh,0accfh,02847h,022ddh,0c035h,0c5h,038h,0234bh
+ tstr <020h,039h>,0,0,0,0,0,0,0,-1,0 ; (8,192 cycles)
+ tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles)
+ db 0a4h,002h,06dh,05ah ; expected crc
+ tmsg 'aluop a,'
+
+; aluop a,(+1) (229,376 cycles)
+alu8x: db 0d7h ; flag mask
+ tstr <0ddh,086h,1>,090b7h,msbt-1,msbt-1,032fdh,0406eh,0c1dch,045h,06eh,0e5fah
+ tstr <020h,038h>,0,1,1,0,0,0,0,-1,0 ; (16,384 cycles)
+ tstr 0,0ffh,0,0,0,0,0,0d7h,0,0 ; (14 cycles)
+ db 0e8h,049h,067h,06eh ; expected crc
+ tmsg 'aluop a,(+1)'
+
+; bit n,(+1) (2048 cycles)
+bitx: db 053h ; flag mask
+ tstr <0ddh,0cbh,1,046h>,02075h,msbt-1,msbt-1,03cfch,0a79ah,03d74h,051h,027h,0ca14h
+ tstr <020h,0,0,038h>,0,0,0,0,0,0,053h,0,0 ; (256 cycles)
+ tstr 0,0ffh,0,0,0,0,0,0,0,0 ; (8 cycles)
+ db 0a8h,0eeh,008h,067h ; expected crc
+ tmsg 'bit n,(+1)'
+
+; bit n, (49,152 cycles)
+bitz80: db 053h ; flag mask
+ tstr <0cbh,040h>,03ef1h,09dfch,07acch,msbt,0be61h,07a86h,050h,024h,01998h
+ tstr <0,03fh>,0,0,0,0,0,0,053h,0,0 ; (1024 cycles)
+ tstr 0,0ffh,0,0,0,-1,-1,0,-1,0 ; (48 cycles)
+ db 07bh,055h,0e6h,0c8h ; expected crc
+ tmsg 'bit n,'
+
+; cpd (1) (6144 cycles)
+cpd1: db 0d7h ; flag mask
+ tstr <0edh,0a9h>,0c7b6h,072b4h,018f6h,msbt+17,08dbdh,1,0c0h,030h,094a3h
+ tstr <0,010h>,0,0,0,0,0,010,0,-1,0 ; (1024 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0a8h,07eh,06ch,0fah ; expected crc
+ tmsg 'cpd'
+
+; cpi (1) (6144 cycles)
+cpi1: db 0d7h ; flag mask
+ tstr <0edh,0a1h>,04d48h,0af4ah,0906bh,msbt,04e71h,1,093h,06ah,0907ch
+ tstr <0,010h>,0,0,0,0,0,010,0,-1,0 ; (1024 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 006h,0deh,0b3h,056h ; expected crc
+ tmsg 'cpi'
+
+;
+daa: db 0d7h ; flag mask
+ tstr 027h,02141h,009fah,01d60h,0a559h,08d5bh,09079h,004h,08eh,0299dh
+ tstr 018h,0,0,0,0,0,0,0d7h,-1,0 ; (65,536 cycles)
+ tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle)
+ db 09bh,04bh,0a6h,075h ; expected crc
+ tmsg ''
+
+; a (3072 cycles)
+inca: db 0d7h ; flag mask
+ tstr 03ch,04adfh,0d5d8h,0e598h,08a2bh,0a7b0h,0431bh,044h,05ah,0d030h
+ tstr 001h,0,0,0,0,0,0,0,-1,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0d1h,088h,015h,0a4h ; expected crc
+ tmsg ' a'
+
+; b (3072 cycles)
+incb: db 0d7h ; flag mask
+ tstr 004h,0d623h,0432dh,07a61h,08180h,05a86h,01e85h,086h,058h,09bbbh
+ tstr 001h,0,0,0,0,0,0ff00h,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 05fh,068h,022h,064h ; expected crc
+ tmsg ' b'
+
+; bc (1536 cycles)
+incbc: db 0d7h ; flag mask
+ tstr 003h,0cd97h,044abh,08dc9h,0e3e3h,011cch,0e8a4h,002h,049h,02a4dh
+ tstr 008h,0,0,0,0,0,0f821h,0,0,0 ; (256 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0d2h,0aeh,03bh,0ech ; expected crc
+ tmsg ' bc'
+
+; c (3072 cycles)
+incc: db 0d7h ; flag mask
+ tstr 00ch,0d789h,00935h,0055bh,09f85h,08b27h,0d208h,095h,005h,00660h
+ tstr 001h,0,0,0,0,0,0ffh,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0c2h,084h,055h,04ch ; expected crc
+ tmsg ' c'
+
+; d (3072 cycles)
+incd: db 0d7h ; flag mask
+ tstr 014h,0a0eah,05fbah,065fbh,0981ch,038cch,0debch,043h,05ch,003bdh
+ tstr 001h,0,0,0,0,0ff00h,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 045h,023h,0deh,010h ; expected crc
+ tmsg ' d'
+
+; de (1536 cycles)
+incde: db 0d7h ; flag mask
+ tstr 013h,0342eh,0131dh,028c9h,00acah,09967h,03a2eh,092h,0f6h,09d54h
+ tstr 008h,0,0,0,0,0f821h,0,0,0,0 ; (256 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0aeh,0c6h,0d4h,02ch ; expected crc
+ tmsg ' de'
+
+; e (3072 cycles)
+ince: db 0d7h ; flag mask
+ tstr 01ch,0602fh,04c0dh,02402h,0e2f5h,0a0f4h,0a10ah,013h,032h,05925h
+ tstr 001h,0,0,0,0,0ffh,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0e1h,075h,0afh,0cch ; expected crc
+ tmsg ' e'
+
+; h (3072 cycles)
+inch: db 0d7h ; flag mask
+ tstr 024h,01506h,0f2ebh,0e8ddh,0262bh,011a6h,0bc1ah,017h,006h,02818h
+ tstr 001h,0,0,0,0ff00h,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 01ch,0edh,084h,07dh ; expected crc
+ tmsg ' h'
+
+; hl (1536 cycles)
+inchl: db 0d7h ; flag mask
+ tstr 023h,0c3f4h,007a5h,01b6dh,04f04h,0e2c2h,0822ah,057h,0e0h,0c3e1h
+ tstr 008h,0,0,0,0f821h,0,0,0,0,0 ; (256 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0fch,00dh,06dh,04ah ; expected crc
+ tmsg ' hl'
+
+; ix (1536 cycles)
+incix: db 0d7h ; flag mask
+ tstr <0ddh,023h>,0bc3ch,00d9bh,0e081h,0adfdh,09a7fh,096e5h,013h,085h,00be2h
+ tstr <0,8>,0,0,0f821h,0,0,0,0,0,0 ; (256 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0a5h,04dh,0beh,031h ; expected crc
+ tmsg ' ix'
+
+; iy (1536 cycles)
+inciy: db 0d7h ; flag mask
+ tstr <0fdh,023h>,09402h,0637ah,03182h,0c65ah,0b2e9h,0abb4h,016h,0f2h,06d05h
+ tstr <0,8>,0,0f821h,0,0,0,0,0,0,0 ; (256 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 050h,05dh,051h,0a3h ; expected crc
+ tmsg ' iy'
+
+; l (3072 cycles)
+incl: db 0d7h ; flag mask
+ tstr 02ch,08031h,0a520h,04356h,0b409h,0f4c1h,0dfa2h,0d1h,03ch,03ea2h
+ tstr 001h,0,0,0,0ffh,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 056h,0cdh,006h,0f3h ; expected crc
+ tmsg ' l'
+
+; (hl) (3072 cycles)
+incm: db 0d7h ; flag mask
+ tstr 034h,0b856h,00c7ch,0e53eh,msbt,0877eh,0da58h,015h,05ch,01f37h
+ tstr 001h,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0b8h,03ah,0dch,0efh ; expected crc
+ tmsg ' (hl)'
+
+; sp (1536 cycles)
+incsp: db 0d7h ; flag mask
+ tstr 033h,0346fh,0d482h,0d169h,0deb6h,0a494h,0f476h,053h,002h,0855bh
+ tstr 008h,0,0,0,0,0,0,0,0,0f821h ; (256 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 05dh,0ach,0d5h,027h ; expected crc
+ tmsg ' sp'
+
+; (+1) (6144 cycles)
+incx: db 0d7h ; flag mask
+ tstr <0ddh,034h,1>,0fa6eh,msbt-1,msbt-1,02c28h,08894h,05057h,016h,033h,0286fh
+ tstr <020h,1>,0ffh,0,0,0,0,0,0,0,0 ; (1024 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 020h,058h,014h,070h ; expected crc
+ tmsg ' (+1)'
+
+; ixh (3072 cycles)
+incxh: db 0d7h ; flag mask
+ tstr <0ddh,024h>,0b838h,0316ch,0c6d4h,03e01h,08358h,015b4h,081h,0deh,04259h
+ tstr <0,1>,0,0ff00h,0,0,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 06fh,046h,036h,062h ; expected crc
+ tmsg ' ixh'
+
+; ixl (3072 cycles)
+incxl: db 0d7h ; flag mask
+ tstr <0ddh,02ch>,04d14h,07460h,076d4h,006e7h,032a2h,0213ch,0d6h,0d7h,099a5h
+ tstr <0,1>,0,0ffh,0,0,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 002h,07bh,0efh,02ch ; expected crc
+ tmsg ' ixl'
+
+; iyh (3072 cycles)
+incyh: db 0d7h ; flag mask
+ tstr <0ddh,024h>,02836h,09f6fh,09116h,061b9h,082cbh,0e219h,092h,073h,0a98ch
+ tstr <0,1>,0ff00h,0,0,0,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 02dh,096h,06ch,0f3h ; expected crc
+ tmsg ' iyh'
+
+; iyl (3072 cycles)
+incyl: db 0d7h ; flag mask
+ tstr <0ddh,02ch>,0d7c6h,062d5h,0a09eh,07039h,03e7eh,09f12h,090h,0d9h,0220fh
+ tstr <0,1>,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 0fbh,0cbh,0bah,095h ; expected crc
+ tmsg ' iyl'
+
+; ld ,(nnnn) (32 cycles)
+ld161: db 0d7h ; flag mask
+ tstr <0edh,04bh,low msbt,high msbt>,0f9a8h,0f559h,093a4h,0f5edh,06f96h,0d968h,086h,0e6h,04bd8h
+ tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 04dh,045h,0a9h,0ach ; expected crc
+ tmsg 'ld ,(nnnn)'
+
+; ld hl,(nnnn) (16 cycles)
+ld162: db 0d7h ; flag mask
+ tstr <02ah,low msbt,high msbt>,09863h,07830h,02077h,0b1feh,0b9fah,0abb8h,004h,006h,06015h
+ tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle)
+ tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 05fh,097h,024h,087h ; expected crc
+ tmsg 'ld hl,(nnnn)'
+
+; ld sp,(nnnn) (16 cycles)
+ld163: db 0d7h ; flag mask
+ tstr <0edh,07bh,low msbt,high msbt>,08dfch,057d7h,02161h,0ca18h,0c185h,027dah,083h,01eh,0f460h
+ tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycles)
+ tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 07ah,0ceh,0a1h,01bh ; expected crc
+ tmsg 'ld sp,(nnnn)'
+
+; ld ,(nnnn) (32 cycles)
+ld164: db 0d7h ; flag mask
+ tstr <0ddh,02ah,low msbt,high msbt>,0ded7h,0a6fah,0f780h,0244ch,087deh,0bcc2h,016h,063h,04c96h
+ tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 085h,08bh,0f1h,06dh ; expected crc
+ tmsg 'ld ,(nnnn)'
+
+; ld (nnnn), (64 cycles)
+ld165: db 0d7h ; flag mask
+ tstr <0edh,043h,low msbt,high msbt>,01f98h,0844dh,0e8ach,0c9edh,0c95dh,08f61h,080h,03fh,0c7bfh
+ tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,0,0,0,0,-1,-1,0,0,0 ; (32 cycles)
+ db 064h,01eh,087h,015h ; expected crc
+ tmsg 'ld (nnnn),'
+
+; ld (nnnn),hl (16 cycles)
+ld166: db 0d7h ; flag mask
+ tstr <022h,low msbt,high msbt>,0d003h,07772h,07f53h,03f72h,064eah,0e180h,010h,02dh,035e9h
+ tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle)
+ tstr 0,0,0,0,-1,0,0,0,0,0 ; (16 cycles)
+ db 0a3h,060h,08bh,047h ; expected crc
+ tmsg 'ld (nnnn),hl'
+
+; ld (nnnn),sp (16 cycles)
+ld167: db 0d7h ; flag mask
+ tstr <0edh,073h,low msbt,high msbt>,0c0dch,0d1d6h,0ed5ah,0f356h,0afdah,06ca7h,044h,09fh,03f0ah
+ tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle)
+ tstr 0,0,0,0,0,0,0,0,0,-1 ; (16 cycles)
+ db 016h,058h,05fh,0d7h ; expected crc
+ tmsg 'ld (nnnn),sp'
+
+; ld (nnnn), (64 cycles)
+ld168: db 0d7h ; flag mask
+ tstr <0ddh,022h,low msbt,high msbt>,06cc3h,00d91h,06900h,08ef8h,0e3d6h,0c3f7h,0c6h,0d9h,0c2dfh
+ tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,0,-1,-1,0,0,0,0,0,0 ; (32 cycles)
+ db 0bah,010h,02ah,06bh ; expected crc
+ tmsg 'ld (nnnn),'
+
+; ld ,nnnn (64 cycles)
+ld16im: db 0d7h ; flag mask
+ tstr 1,05c1ch,02d46h,08eb9h,06078h,074b1h,0b30eh,046h,0d1h,030cch
+ tstr 030h,0,0,0,0,0,0,0,0,0 ; (4 cycles)
+ tstr <0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 0deh,039h,019h,069h ; expected crc
+ tmsg 'ld ,nnnn'
+
+; ld ,nnnn (32 cycles)
+ld16ix: db 0d7h ; flag mask
+ tstr <0ddh,021h>,087e8h,02006h,0bd12h,0b69bh,07253h,0a1e5h,051h,013h,0f1bdh
+ tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr <0,0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 022h,07dh,0d5h,025h ; expected crc
+ tmsg 'ld ,nnnn'
+
+; ld a,<(bc),(de)> (44 cycles)
+ld8bd: db 0d7h ; flag mask
+ tstr 00ah,0b3a8h,01d2ah,07f8eh,042ach,msbt,msbt,0c6h,0b1h,0ef8eh
+ tstr 010h,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles)
+ db 0b0h,081h,089h,035h ; expected crc
+ tmsg 'ld a,<(bc),(de)>'
+
+; ld ,nn (64 cycles)
+ld8im: db 0d7h ; flag mask
+ tstr 6,0c407h,0f49dh,0d13dh,00339h,0de89h,07455h,053h,0c0h,05509h
+ tstr 038h,0,0,0,0,0,0,0,0,0 ; (8 cycles)
+ tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles)
+ db 0f1h,0dah,0b5h,056h ; expected crc
+ tmsg 'ld ,nn'
+
+; ld (+1),nn (32 cycles)
+ld8imx: db 0d7h ; flag mask
+ tstr <0ddh,036h,1>,01b45h,msbt-1,msbt-1,0d5c1h,061c7h,0bdc4h,0c0h,085h,0cd16h
+ tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr <0,0,0,-1>,0,0,0,0,0,0,0,-1,0 ; (16 cycles)
+ db 026h,0dbh,047h,07eh ; expected crc
+ tmsg 'ld (+1),nn'
+
+; ld ,(+1) (512 cycles)
+ld8ix1: db 0d7h ; flag mask
+ tstr <0ddh,046h,1>,0d016h,msbt-1,msbt-1,04260h,07f39h,00404h,097h,04ah,0d085h
+ tstr <020h,018h>,0,1,1,0,0,0,0,0,0 ; (32 cycles)
+ tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 0cch,011h,006h,0a8h ; expected crc
+ tmsg 'ld ,(+1)'
+
+; ld ,(+1) (256 cycles)
+ld8ix2: db 0d7h ; flag mask
+ tstr <0ddh,066h,1>,084e0h,msbt-1,msbt-1,09c52h,0a799h,049b6h,093h,000h,0eeadh
+ tstr <020h,008h>,0,1,1,0,0,0,0,0,0 ; (16 cycles)
+ tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 0fah,02ah,04dh,003h ; expected crc
+ tmsg 'ld ,(+1)'
+
+; ld a,(+1) (128 cycles)
+ld8ix3: db 0d7h ; flag mask
+ tstr <0ddh,07eh,1>,0d8b6h,msbt-1,msbt-1,0c612h,0df07h,09cd0h,043h,0a6h,0a0e5h
+ tstr 020h,0,1,1,0,0,0,0,0,0 ; (8 cycles)
+ tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles)
+ db 0a5h,0e9h,0ach,064h ; expected crc
+ tmsg 'ld a,(+1)'
+
+; ld ,nn (32 cycles)
+ld8ixy: db 0d7h ; flag mask
+ tstr <0ddh,026h>,03c53h,04640h,0e179h,07711h,0c107h,01afah,081h,0adh,05d9bh
+ tstr <020h,8>,0,0,0,0,0,0,0,0,0 ; (4 cycles)
+ tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles)
+ db 024h,0e8h,082h,08bh ; expected crc
+ tmsg 'ld ,nn'
+
+; ld , (3456 cycles)
+ld8rr: db 0d7h ; flag mask
+ tstr 040h,072a4h,0a024h,061ach,msbt,082c7h,0718fh,097h,08fh,0ef8eh
+ tstr 03fh,0,0,0,0,0,0,0,0,0 ; (64 cycles)
+ tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles)
+ db 074h,04bh,001h,018h ; expected crc
+ tmsg 'ld ,'
+
+; ld , (6912 cycles)
+ld8rrx: db 0d7h ; flag mask
+ tstr <0ddh,040h>,0bcc5h,msbt,msbt,msbt,02fc2h,098c0h,083h,01fh,03bcdh
+ tstr <020h,03fh>,0,0,0,0,0,0,0,0,0 ; (128 cycles)
+ tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles)
+ db 047h,08bh,0a3h,06bh ; expected crc
+ tmsg 'ld ,'
+
+; ld a,(nnnn) / ld (nnnn),a (44 cycles)
+lda: db 0d7h ; flag mask
+ tstr <032h,low msbt,high msbt>,0fd68h,0f4ech,044a0h,0b543h,00653h,0cdbah,0d2h,04fh,01fd8h
+ tstr 008h,0,0,0,0,0,0,0,0,0 ; (2 cycle)
+ tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles)
+ db 0c9h,026h,02dh,0e5h ; expected crc
+ tmsg 'ld a,(nnnn) / ld (nnnn),a'
+
+; ldd (1) (44 cycles)
+ldd1: db 0d7h ; flag mask
+ tstr <0edh,0a8h>,09852h,068fah,066a1h,msbt+3,msbt+1,1,0c1h,068h,020b7h
+ tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles)
+ db 094h,0f4h,027h,069h ; expected crc
+ tmsg 'ldd (1)'
+
+; ldd (2) (44 cycles)
+ldd2: db 0d7h ; flag mask
+ tstr <0edh,0a8h>,0f12eh,0eb2ah,0d5bah,msbt+3,msbt+1,2,047h,0ffh,0fbe4h
+ tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles)
+ db 05ah,090h,07eh,0d4h ; expected crc
+ tmsg 'ldd (2)'
+
+; ldi (1) (44 cycles)
+ldi1: db 0d7h ; flag mask
+ tstr <0edh,0a0h>,0fe30h,003cdh,06058h,msbt+2,msbt,1,004h,060h,02688h
+ tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles)
+ db 09ah,0bdh,0f6h,0b5h ; expected crc
+ tmsg 'ldi (1)'
+
+; ldi (2) (44 cycles)
+ldi2: db 0d7h ; flag mask
+ tstr <0edh,0a0h>,04aceh,0c26eh,0b188h,msbt+2,msbt,2,014h,02dh,0a39fh
+ tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles)
+ tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles)
+ db 0ebh,059h,089h,01bh ; expected crc
+ tmsg 'ldi (2)'
+
+; neg (16,384 cycles)
+neg: db 0d7h ; flag mask
+ tstr <0edh,044h>,038a2h,05f6bh,0d934h,057e4h,0d2d6h,04642h,043h,05ah,009cch
+ tstr 0,0,0,0,0,0,0,0d7h,-1,0 ; (16,384 cycles)
+ tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle)
+ db 06ah,03ch,03bh,0bdh ; expected crc
+ tmsg 'neg'
+
+; (7168 cycles)
+rld: db 0d7h ; flag mask
+ tstr <0edh,067h>,091cbh,0c48bh,0fa62h,msbt,0e720h,0b479h,040h,006h,08ae2h
+ tstr <0,8>,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,-1,0 ; (14 cycles)
+ db 095h,05bh,0a3h,026h ; expected crc
+ tmsg ''
+
+; (6144 cycles)
+rot8080: db 0d7h ; flag mask
+ tstr 7,0cb92h,06d43h,00a90h,0c284h,00c53h,0f50eh,091h,0ebh,040fch
+ tstr 018h,0,0,0,0,0,0,0,-1,0 ; (1024 cycles)
+ tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles)
+ db 025h,013h,030h,0aeh ; expected crc
+ tmsg ''
+
+; shift/rotate (+1) (416 cycles)
+rotxy: db 0d7h ; flag mask
+ tstr <0ddh,0cbh,1,6>,0ddafh,msbt-1,msbt-1,0ff3ch,0dbf6h,094f4h,082h,080h,061d9h
+ tstr <020h,0,0,038h>,0,0,0,0,0,0,080h,0,0 ; (32 cycles)
+ tstr 0,0ffh,0,0,0,0,0,057h,0,0 ; (13 cycles)
+ db 071h,03ah,0cdh,081h ; expected crc
+ tmsg 'shf/rot (+1)'
+
+; shift/rotate (6784 cycles)
+rotz80: db 0d7h ; flag mask
+ tstr 0cbh,0ccebh,05d4ah,0e007h,msbt,01395h,030eeh,043h,078h,03dadh
+ tstr <0,03fh>,0,0,0,0,0,0,080h,0,0 ; (128 cycles)
+ tstr 0,0ffh,0,0,0,-1,-1,057h,-1,0 ; (53 cycles)
+ db 0ebh,060h,04dh,058h ; expected crc
+ tmsg 'shf/rot '
+
+; n, (7936 cycles)
+srz80: db 0d7h ; flag mask
+ tstr <0cbh,080h>,02cd5h,097abh,039ffh,msbt,0d14bh,06ab2h,053h,027h,0b538h
+ tstr <0,07fh>,0,0,0,0,0,0,0,0,0 ; (128 cycles)
+ tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (62 cycles)
+ db 08bh,057h,0f0h,008h ; expected crc
+ tmsg ' n,'
+
+; n,(+1) (1792 cycles)
+srzx: db 0d7h ; flag mask
+ tstr <0ddh,0cbh,1,086h>,0fb44h,msbt-1,msbt-1,0ba09h,068beh,032d8h,010h,05eh,0a867h
+ tstr <020h,0,0,078h>,0,0,0,0,0,0,0,0,0 ; (128 cycles)
+ tstr 0,0ffh,0,0,0,0,0,0d7h,0,0 ;(14 cycles)
+ db 0cch,063h,0f9h,08ah ; expected crc
+ tmsg ' n,(+1)'
+
+; ld (+1), (1024 cycles)
+st8ix1: db 0d7h ; flag mask
+ tstr <0ddh,070h,1>,0270dh,msbt-1,msbt-1,0b73ah,0887bh,099eeh,086h,070h,0ca07h
+ tstr <020h,003h>,0,1,1,0,0,0,0,0,0 ; (32 cycles)
+ tstr 0,0,0,0,0,-1,-1,0,0,0 ; (32 cycles)
+ db 004h,062h,06ah,0bfh ; expected crc
+ tmsg 'ld (+1),'
+
+; ld (+1), (256 cycles)
+st8ix2: db 0d7h ; flag mask
+ tstr <0ddh,074h,1>,0b664h,msbt-1,msbt-1,0e8ach,0b5f5h,0aafeh,012h,010h,09566h
+ tstr <020h,001h>,0,1,1,0,0,0,0,0,0 ; (16 cycles)
+ tstr 0,0,0,0,-1,0,0,0,0,0 ; (32 cycles)
+ db 06ah,01ah,088h,031h ; expected crc
+ tmsg 'ld (+1),'
+
+; ld (+1),a (64 cycles)
+st8ix3: db 0d7h ; flag mask
+ tstr <0ddh,077h,1>,067afh,msbt-1,msbt-1,04f13h,00644h,0bcd7h,050h,0ach,05fafh
+ tstr 020h,0,1,1,0,0,0,0,0,0 ; (8 cycles)
+ tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles)
+ db 0cch,0beh,05ah,096h ; expected crc
+ tmsg 'ld (+1),a'
+
+; ld (),a (96 cycles)
+stabd: db 0d7h ; flag mask
+ tstr 2,00c3bh,0b592h,06cffh,0959eh,msbt,msbt+1,0c1h,021h,0bde7h
+ tstr 018h,0,0,0,0,0,0,0,0,0 ; (4 cycles)
+ tstr 0,-1,0,0,0,0,0,0,-1,0 ; (24 cycles)
+ db 07ah,04ch,011h,04fh ; expected crc
+ tmsg 'ld (),a'
+
+; start test pointed to by (hl)
+stt: push hl
+ ld a,(hl) ; get pointer to test
+ inc hl
+ ld h,(hl)
+ ld l,a
+ ld a,(hl) ; flag mask
+ ld (flgmsk+1),a
+ inc hl
+ push hl
+ ld de,20
+ add hl,de ; point to incmask
+ ld de,counter
+ call initmask
+ pop hl
+ push hl
+ ld de,20+20
+ add hl,de ; point to scanmask
+ ld de,shifter
+ call initmask
+ ld hl,shifter
+ ld (hl),1 ; first bit
+ pop hl
+ push hl
+ ld de,iut ; copy initial instruction under test
+ ld bc,4
+ ldir
+ ld de,msbt ; copy initial machine state
+ ld bc,16
+ ldir
+ ld de,20+20+4 ; skip incmask, scanmask and expcrc
+ add hl,de
+ ex de,hl
+ ld c,9
+ call bdos ; show test name
+ call initcrc ; initialise crc
+; test loop
+tlp: ld a,(iut)
+ cp 076h ; pragmatically avoid halt intructions
+ jp z,tlp2
+ and a,0dfh
+ cp 0ddh
+ jp nz,tlp1
+ ld a,(iut+1)
+ cp 076h
+tlp1: call nz,test ; execute the test instruction
+tlp2: call count ; increment the counter
+ call nz,shift ; shift the scan bit
+ pop hl ; pointer to test case
+ jp z,tlp3 ; done if shift returned NZ
+ ld de,20+20+20
+ add hl,de ; point to expected crc
+ call cmpcrc
+ ld de,okmsg
+ jp z,tlpok
+ ld de,ermsg1
+ ld c,9
+ call bdos
+ call phex8
+ ld de,ermsg2
+ ld c,9
+ call bdos
+ ld hl,crcval
+ call phex8
+ ld de,crlf
+tlpok: ld c,9
+ call bdos
+ pop hl
+ inc hl
+ inc hl
+ ret
+
+tlp3: push hl
+ ld a,1 ; initialise count and shift scanners
+ ld (cntbit),a
+ ld (shfbit),a
+ ld hl,counter
+ ld (cntbyt),hl
+ ld hl,shifter
+ ld (shfbyt),hl
+
+ ld b,4 ; bytes in iut field
+ pop hl ; pointer to test case
+ push hl
+ ld de,iut
+ call setup ; setup iut
+ ld b,16 ; bytes in machine state
+ ld de,msbt
+ call setup ; setup machine state
+ jp tlp
+
+; setup a field of the test case
+; b = number of bytes
+; hl = pointer to base case
+; de = destination
+setup: call subyte
+ inc hl
+ dec b
+ jp nz,setup
+ ret
+
+subyte: push bc
+ push de
+ push hl
+ ld c,(hl) ; get base byte
+ ld de,20
+ add hl,de ; point to incmask
+ ld a,(hl)
+ cp 0
+ jp z,subshf
+ ld b,8 ; 8 bits
+subclp: rrca
+ push af
+ ld a,0
+ call c,nxtcbit ; get next counter bit if mask bit was set
+ xor c ; flip bit if counter bit was set
+ rrca
+ ld c,a
+ pop af
+ dec b
+ jp nz,subclp
+ ld b,8
+subshf: ld de,20
+ add hl,de ; point to shift mask
+ ld a,(hl)
+ cp 0
+ jp z,substr
+ ld b,8 ; 8 bits
+sbshf1: rrca
+ push af
+ ld a,0
+ call c,nxtsbit ; get next shifter bit if mask bit was set
+ xor c ; flip bit if shifter bit was set
+ rrca
+ ld c,a
+ pop af
+ dec b
+ jp nz,sbshf1
+substr: pop hl
+ pop de
+ ld a,c
+ ld (de),a ; mangled byte to destination
+ inc de
+ pop bc
+ ret
+
+; get next counter bit in low bit of a
+cntbit: ds 1
+cntbyt: ds 2
+
+nxtcbit: push bc
+ push hl
+ ld hl,(cntbyt)
+ ld b,(hl)
+ ld hl,cntbit
+ ld a,(hl)
+ ld c,a
+ rlca
+ ld (hl),a
+ cp a,1
+ jp nz,ncb1
+ ld hl,(cntbyt)
+ inc hl
+ ld (cntbyt),hl
+ncb1: ld a,b
+ and c
+ pop hl
+ pop bc
+ ret z
+ ld a,1
+ ret
+
+; get next shifter bit in low bit of a
+shfbit: ds 1
+shfbyt: ds 2
+
+nxtsbit: push bc
+ push hl
+ ld hl,(shfbyt)
+ ld b,(hl)
+ ld hl,shfbit
+ ld a,(hl)
+ ld c,a
+ rlca
+ ld (hl),a
+ cp a,1
+ jp nz,nsb1
+ ld hl,(shfbyt)
+ inc hl
+ ld (shfbyt),hl
+nsb1: ld a,b
+ and c
+ pop hl
+ pop bc
+ ret z
+ ld a,1
+ ret
+
+
+; clear memory at hl, bc bytes
+clrmem: push af
+ push bc
+ push de
+ push hl
+ ld (hl),0
+ ld d,h
+ ld e,l
+ inc de
+ dec bc
+ ldir
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+; initialise counter or shifter
+; de = pointer to work area for counter or shifter
+; hl = pointer to mask
+initmask:
+ push de
+ ex de,hl
+ ld bc,20+20
+ call clrmem ; clear work area
+ ex de,hl
+ ld b,20 ; byte counter
+ ld c,1 ; first bit
+ ld d,0 ; bit counter
+imlp: ld e,(hl)
+imlp1: ld a,e
+ and a,c
+ jp z,imlp2
+ inc d
+imlp2: ld a,c
+ rlca
+ ld c,a
+ cp a,1
+ jp nz,imlp1
+ inc hl
+ dec b
+ jp nz,imlp
+; got number of 1-bits in mask in reg d
+ ld a,d
+ and 0f8h
+ rrca
+ rrca
+ rrca ; divide by 8 (get byte offset)
+ ld l,a
+ ld h,0
+ ld a,d
+ and a,7 ; bit offset
+ inc a
+ ld b,a
+ ld a,080h
+imlp3: rlca
+ dec b
+ jp nz,imlp3
+ pop de
+ add hl,de
+ ld de,20
+ add hl,de
+ ld (hl),a
+ ret
+
+; multi-byte counter
+count: push bc
+ push de
+ push hl
+ ld hl,counter ; 20 byte counter starts here
+ ld de,20 ; somewhere in here is the stop bit
+ ex de,hl
+ add hl,de
+ ex de,hl
+cntlp: inc (hl)
+ ld a,(hl)
+ cp 0
+ jp z,cntlp1 ; overflow to next byte
+ ld b,a
+ ld a,(de)
+ and a,b ; test for terminal value
+ jp z,cntend
+ ld (hl),0 ; reset to zero
+cntend: pop bc
+ pop de
+ pop hl
+ ret
+
+cntlp1: inc hl
+ inc de
+ jp cntlp
+
+
+; multi-byte shifter
+shift: push bc
+ push de
+ push hl
+ ld hl,shifter ; 20 byte shift register starts here
+ ld de,20 ; somewhere in here is the stop bit
+ ex de,hl
+ add hl,de
+ ex de,hl
+shflp: ld a,(hl)
+ or a
+ jp z,shflp1
+ ld b,a
+ ld a,(de)
+ and b
+ jp nz,shlpe
+ ld a,b
+ rlca
+ cp a,1
+ jp nz,shflp2
+ ld (hl),0
+ inc hl
+ inc de
+shflp2: ld (hl),a
+ xor a ; set Z
+shlpe: pop hl
+ pop de
+ pop bc
+ ret
+shflp1: inc hl
+ inc de
+ jp shflp
+
+counter: ds 2*20
+shifter: ds 2*20
+
+; test harness
+test: push af
+ push bc
+ push de
+ push hl
+ if 0
+ ld de,crlf
+ ld c,9
+ call bdos
+ ld hl,iut
+ ld b,4
+ call hexstr
+ ld e,' '
+ ld c,2
+ call bdos
+ ld b,16
+ ld hl,msbt
+ call hexstr
+ endif
+ di ; disable interrupts
+ ld (spsav),sp ; save stack pointer
+ ld sp,msbt+2 ; point to test-case machine state
+ pop iy ; and load all regs
+ pop ix
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ld sp,(spbt)
+iut: ds 4 ; max 4 byte instruction under test
+ ld (spat),sp ; save stack pointer
+ ld sp,spat
+ push af ; save other registers
+ push bc
+ push de
+ push hl
+ push ix
+ push iy
+ ld sp,(spsav) ; restore stack pointer
+ ei ; enable interrupts
+ ld hl,(msbt) ; copy memory operand
+ ld (msat),hl
+ ld hl,flgsat ; flags after test
+ ld a,(hl)
+flgmsk: and a,0d7h ; mask-out irrelevant bits (self-modified code!)
+ ld (hl),a
+ ld b,16 ; total of 16 bytes of state
+ ld de,msat
+ ld hl,crcval
+tcrc: ld a,(de)
+ inc de
+ call updcrc ; accumulate crc of this test case
+ dec b
+ jp nz,tcrc
+ if 0
+ ld e,' '
+ ld c,2
+ call bdos
+ ld hl,crcval
+ call phex8
+ ld de,crlf
+ ld c,9
+ call bdos
+ ld hl,msat
+ ld b,16
+ call hexstr
+ ld de,crlf
+ ld c,9
+ call bdos
+ endif
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+; machine state after test
+msat: ds 14 ; memop,iy,ix,hl,de,bc,af
+spat: ds 2 ; stack pointer after test
+flgsat: equ spat-2 ; flags
+
+spsav: ds 2 ; saved stack pointer
+
+; display hex string (pointer in hl, byte count in b)
+hexstr: ld a,(hl)
+ call phex2
+ inc hl
+ dec b
+ jp nz,hexstr
+ ret
+
+; display hex
+; display the big-endian 32-bit value pointed to by hl
+phex8: push af
+ push bc
+ push hl
+ ld b,4
+ph8lp: ld a,(hl)
+ call phex2
+ inc hl
+ dec b
+ jp nz,ph8lp
+ pop hl
+ pop bc
+ pop af
+ ret
+
+; display byte in a
+phex2: push af
+ rrca
+ rrca
+ rrca
+ rrca
+ call phex1
+ pop af
+; fall through
+
+; display low nibble in a
+phex1: push af
+ push bc
+ push de
+ push hl
+ and a,0fh
+ cp a,10
+ jp c,ph11
+ add a,'a'-'9'-1
+ph11: add a,'0'
+ ld e,a
+ ld c,2
+ call bdos
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+bdos push af
+ push bc
+ push de
+ push hl
+ call 5
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+msg1: db 'Z80 instruction exerciser',10,13,'$'
+msg2: db 'Tests complete$'
+okmsg: db ' OK',10,13,'$'
+ermsg1: db ' ERROR **** crc expected:$'
+ermsg2: db ' found:$'
+crlf: db 10,13,'$'
+
+; compare crc
+; hl points to value to compare to crcval
+cmpcrc: push bc
+ push de
+ push hl
+ ld de,crcval
+ ld b,4
+cclp: ld a,(de)
+ cp a,(hl)
+ jp nz,cce
+ inc hl
+ inc de
+ dec b
+ jp nz,cclp
+cce: pop hl
+ pop de
+ pop bc
+ ret
+
+; 32-bit crc routine
+; entry: a contains next byte, hl points to crc
+; exit: crc updated
+updcrc: push af
+ push bc
+ push de
+ push hl
+ push hl
+ ld de,3
+ add hl,de ; point to low byte of old crc
+ xor a,(hl) ; xor with new byte
+ ld l,a
+ ld h,0
+ add hl,hl ; use result as index into table of 4 byte entries
+ add hl,hl
+ ex de,hl
+ ld hl,crctab
+ add hl,de ; point to selected entry in crctab
+ ex de,hl
+ pop hl
+ ld bc,4 ; c = byte count, b = accumulator
+crclp: ld a,(de)
+ xor a,b
+ ld b,(hl)
+ ld (hl),a
+ inc de
+ inc hl
+ dec c
+ jp nz,crclp
+ if 0
+ ld hl,crcval
+ call phex8
+ ld de,crlf
+ ld c,9
+ call bdos
+ endif
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+initcrc:push af
+ push bc
+ push hl
+ ld hl,crcval
+ ld a,0ffh
+ ld b,4
+icrclp: ld (hl),a
+ inc hl
+ dec b
+ jp nz,icrclp
+ pop hl
+ pop bc
+ pop af
+ ret
+
+crcval ds 4
+
+crctab: db 000h,000h,000h,000h
+ db 077h,007h,030h,096h
+ db 0eeh,00eh,061h,02ch
+ db 099h,009h,051h,0bah
+ db 007h,06dh,0c4h,019h
+ db 070h,06ah,0f4h,08fh
+ db 0e9h,063h,0a5h,035h
+ db 09eh,064h,095h,0a3h
+ db 00eh,0dbh,088h,032h
+ db 079h,0dch,0b8h,0a4h
+ db 0e0h,0d5h,0e9h,01eh
+ db 097h,0d2h,0d9h,088h
+ db 009h,0b6h,04ch,02bh
+ db 07eh,0b1h,07ch,0bdh
+ db 0e7h,0b8h,02dh,007h
+ db 090h,0bfh,01dh,091h
+ db 01dh,0b7h,010h,064h
+ db 06ah,0b0h,020h,0f2h
+ db 0f3h,0b9h,071h,048h
+ db 084h,0beh,041h,0deh
+ db 01ah,0dah,0d4h,07dh
+ db 06dh,0ddh,0e4h,0ebh
+ db 0f4h,0d4h,0b5h,051h
+ db 083h,0d3h,085h,0c7h
+ db 013h,06ch,098h,056h
+ db 064h,06bh,0a8h,0c0h
+ db 0fdh,062h,0f9h,07ah
+ db 08ah,065h,0c9h,0ech
+ db 014h,001h,05ch,04fh
+ db 063h,006h,06ch,0d9h
+ db 0fah,00fh,03dh,063h
+ db 08dh,008h,00dh,0f5h
+ db 03bh,06eh,020h,0c8h
+ db 04ch,069h,010h,05eh
+ db 0d5h,060h,041h,0e4h
+ db 0a2h,067h,071h,072h
+ db 03ch,003h,0e4h,0d1h
+ db 04bh,004h,0d4h,047h
+ db 0d2h,00dh,085h,0fdh
+ db 0a5h,00ah,0b5h,06bh
+ db 035h,0b5h,0a8h,0fah
+ db 042h,0b2h,098h,06ch
+ db 0dbh,0bbh,0c9h,0d6h
+ db 0ach,0bch,0f9h,040h
+ db 032h,0d8h,06ch,0e3h
+ db 045h,0dfh,05ch,075h
+ db 0dch,0d6h,00dh,0cfh
+ db 0abh,0d1h,03dh,059h
+ db 026h,0d9h,030h,0ach
+ db 051h,0deh,000h,03ah
+ db 0c8h,0d7h,051h,080h
+ db 0bfh,0d0h,061h,016h
+ db 021h,0b4h,0f4h,0b5h
+ db 056h,0b3h,0c4h,023h
+ db 0cfh,0bah,095h,099h
+ db 0b8h,0bdh,0a5h,00fh
+ db 028h,002h,0b8h,09eh
+ db 05fh,005h,088h,008h
+ db 0c6h,00ch,0d9h,0b2h
+ db 0b1h,00bh,0e9h,024h
+ db 02fh,06fh,07ch,087h
+ db 058h,068h,04ch,011h
+ db 0c1h,061h,01dh,0abh
+ db 0b6h,066h,02dh,03dh
+ db 076h,0dch,041h,090h
+ db 001h,0dbh,071h,006h
+ db 098h,0d2h,020h,0bch
+ db 0efh,0d5h,010h,02ah
+ db 071h,0b1h,085h,089h
+ db 006h,0b6h,0b5h,01fh
+ db 09fh,0bfh,0e4h,0a5h
+ db 0e8h,0b8h,0d4h,033h
+ db 078h,007h,0c9h,0a2h
+ db 00fh,000h,0f9h,034h
+ db 096h,009h,0a8h,08eh
+ db 0e1h,00eh,098h,018h
+ db 07fh,06ah,00dh,0bbh
+ db 008h,06dh,03dh,02dh
+ db 091h,064h,06ch,097h
+ db 0e6h,063h,05ch,001h
+ db 06bh,06bh,051h,0f4h
+ db 01ch,06ch,061h,062h
+ db 085h,065h,030h,0d8h
+ db 0f2h,062h,000h,04eh
+ db 06ch,006h,095h,0edh
+ db 01bh,001h,0a5h,07bh
+ db 082h,008h,0f4h,0c1h
+ db 0f5h,00fh,0c4h,057h
+ db 065h,0b0h,0d9h,0c6h
+ db 012h,0b7h,0e9h,050h
+ db 08bh,0beh,0b8h,0eah
+ db 0fch,0b9h,088h,07ch
+ db 062h,0ddh,01dh,0dfh
+ db 015h,0dah,02dh,049h
+ db 08ch,0d3h,07ch,0f3h
+ db 0fbh,0d4h,04ch,065h
+ db 04dh,0b2h,061h,058h
+ db 03ah,0b5h,051h,0ceh
+ db 0a3h,0bch,000h,074h
+ db 0d4h,0bbh,030h,0e2h
+ db 04ah,0dfh,0a5h,041h
+ db 03dh,0d8h,095h,0d7h
+ db 0a4h,0d1h,0c4h,06dh
+ db 0d3h,0d6h,0f4h,0fbh
+ db 043h,069h,0e9h,06ah
+ db 034h,06eh,0d9h,0fch
+ db 0adh,067h,088h,046h
+ db 0dah,060h,0b8h,0d0h
+ db 044h,004h,02dh,073h
+ db 033h,003h,01dh,0e5h
+ db 0aah,00ah,04ch,05fh
+ db 0ddh,00dh,07ch,0c9h
+ db 050h,005h,071h,03ch
+ db 027h,002h,041h,0aah
+ db 0beh,00bh,010h,010h
+ db 0c9h,00ch,020h,086h
+ db 057h,068h,0b5h,025h
+ db 020h,06fh,085h,0b3h
+ db 0b9h,066h,0d4h,009h
+ db 0ceh,061h,0e4h,09fh
+ db 05eh,0deh,0f9h,00eh
+ db 029h,0d9h,0c9h,098h
+ db 0b0h,0d0h,098h,022h
+ db 0c7h,0d7h,0a8h,0b4h
+ db 059h,0b3h,03dh,017h
+ db 02eh,0b4h,00dh,081h
+ db 0b7h,0bdh,05ch,03bh
+ db 0c0h,0bah,06ch,0adh
+ db 0edh,0b8h,083h,020h
+ db 09ah,0bfh,0b3h,0b6h
+ db 003h,0b6h,0e2h,00ch
+ db 074h,0b1h,0d2h,09ah
+ db 0eah,0d5h,047h,039h
+ db 09dh,0d2h,077h,0afh
+ db 004h,0dbh,026h,015h
+ db 073h,0dch,016h,083h
+ db 0e3h,063h,00bh,012h
+ db 094h,064h,03bh,084h
+ db 00dh,06dh,06ah,03eh
+ db 07ah,06ah,05ah,0a8h
+ db 0e4h,00eh,0cfh,00bh
+ db 093h,009h,0ffh,09dh
+ db 00ah,000h,0aeh,027h
+ db 07dh,007h,09eh,0b1h
+ db 0f0h,00fh,093h,044h
+ db 087h,008h,0a3h,0d2h
+ db 01eh,001h,0f2h,068h
+ db 069h,006h,0c2h,0feh
+ db 0f7h,062h,057h,05dh
+ db 080h,065h,067h,0cbh
+ db 019h,06ch,036h,071h
+ db 06eh,06bh,006h,0e7h
+ db 0feh,0d4h,01bh,076h
+ db 089h,0d3h,02bh,0e0h
+ db 010h,0dah,07ah,05ah
+ db 067h,0ddh,04ah,0cch
+ db 0f9h,0b9h,0dfh,06fh
+ db 08eh,0beh,0efh,0f9h
+ db 017h,0b7h,0beh,043h
+ db 060h,0b0h,08eh,0d5h
+ db 0d6h,0d6h,0a3h,0e8h
+ db 0a1h,0d1h,093h,07eh
+ db 038h,0d8h,0c2h,0c4h
+ db 04fh,0dfh,0f2h,052h
+ db 0d1h,0bbh,067h,0f1h
+ db 0a6h,0bch,057h,067h
+ db 03fh,0b5h,006h,0ddh
+ db 048h,0b2h,036h,04bh
+ db 0d8h,00dh,02bh,0dah
+ db 0afh,00ah,01bh,04ch
+ db 036h,003h,04ah,0f6h
+ db 041h,004h,07ah,060h
+ db 0dfh,060h,0efh,0c3h
+ db 0a8h,067h,0dfh,055h
+ db 031h,06eh,08eh,0efh
+ db 046h,069h,0beh,079h
+ db 0cbh,061h,0b3h,08ch
+ db 0bch,066h,083h,01ah
+ db 025h,06fh,0d2h,0a0h
+ db 052h,068h,0e2h,036h
+ db 0cch,00ch,077h,095h
+ db 0bbh,00bh,047h,003h
+ db 022h,002h,016h,0b9h
+ db 055h,005h,026h,02fh
+ db 0c5h,0bah,03bh,0beh
+ db 0b2h,0bdh,00bh,028h
+ db 02bh,0b4h,05ah,092h
+ db 05ch,0b3h,06ah,004h
+ db 0c2h,0d7h,0ffh,0a7h
+ db 0b5h,0d0h,0cfh,031h
+ db 02ch,0d9h,09eh,08bh
+ db 05bh,0deh,0aeh,01dh
+ db 09bh,064h,0c2h,0b0h
+ db 0ech,063h,0f2h,026h
+ db 075h,06ah,0a3h,09ch
+ db 002h,06dh,093h,00ah
+ db 09ch,009h,006h,0a9h
+ db 0ebh,00eh,036h,03fh
+ db 072h,007h,067h,085h
+ db 005h,000h,057h,013h
+ db 095h,0bfh,04ah,082h
+ db 0e2h,0b8h,07ah,014h
+ db 07bh,0b1h,02bh,0aeh
+ db 00ch,0b6h,01bh,038h
+ db 092h,0d2h,08eh,09bh
+ db 0e5h,0d5h,0beh,00dh
+ db 07ch,0dch,0efh,0b7h
+ db 00bh,0dbh,0dfh,021h
+ db 086h,0d3h,0d2h,0d4h
+ db 0f1h,0d4h,0e2h,042h
+ db 068h,0ddh,0b3h,0f8h
+ db 01fh,0dah,083h,06eh
+ db 081h,0beh,016h,0cdh
+ db 0f6h,0b9h,026h,05bh
+ db 06fh,0b0h,077h,0e1h
+ db 018h,0b7h,047h,077h
+ db 088h,008h,05ah,0e6h
+ db 0ffh,00fh,06ah,070h
+ db 066h,006h,03bh,0cah
+ db 011h,001h,00bh,05ch
+ db 08fh,065h,09eh,0ffh
+ db 0f8h,062h,0aeh,069h
+ db 061h,06bh,0ffh,0d3h
+ db 016h,06ch,0cfh,045h
+ db 0a0h,00ah,0e2h,078h
+ db 0d7h,00dh,0d2h,0eeh
+ db 04eh,004h,083h,054h
+ db 039h,003h,0b3h,0c2h
+ db 0a7h,067h,026h,061h
+ db 0d0h,060h,016h,0f7h
+ db 049h,069h,047h,04dh
+ db 03eh,06eh,077h,0dbh
+ db 0aeh,0d1h,06ah,04ah
+ db 0d9h,0d6h,05ah,0dch
+ db 040h,0dfh,00bh,066h
+ db 037h,0d8h,03bh,0f0h
+ db 0a9h,0bch,0aeh,053h
+ db 0deh,0bbh,09eh,0c5h
+ db 047h,0b2h,0cfh,07fh
+ db 030h,0b5h,0ffh,0e9h
+ db 0bdh,0bdh,0f2h,01ch
+ db 0cah,0bah,0c2h,08ah
+ db 053h,0b3h,093h,030h
+ db 024h,0b4h,0a3h,0a6h
+ db 0bah,0d0h,036h,005h
+ db 0cdh,0d7h,006h,093h
+ db 054h,0deh,057h,029h
+ db 023h,0d9h,067h,0bfh
+ db 0b3h,066h,07ah,02eh
+ db 0c4h,061h,04ah,0b8h
+ db 05dh,068h,01bh,002h
+ db 02ah,06fh,02bh,094h
+ db 0b4h,00bh,0beh,037h
+ db 0c3h,00ch,08eh,0a1h
+ db 05ah,005h,0dfh,01bh
+ db 02dh,002h,0efh,08dh
+
diff --git a/Z80/Z80.csproj b/Z80/Z80.csproj
index f42552e..045785c 100644
--- a/Z80/Z80.csproj
+++ b/Z80/Z80.csproj
@@ -31,6 +31,7 @@
4
latest
AllRules.ruleset
+ true
@@ -43,7 +44,9 @@
+
+
@@ -54,5 +57,15 @@
EightBit
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Z80/packages.config b/Z80/packages.config
new file mode 100644
index 0000000..45f05d8
--- /dev/null
+++ b/Z80/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Z80/stylecop.json b/Z80/stylecop.json
new file mode 100644
index 0000000..3af08b4
--- /dev/null
+++ b/Z80/stylecop.json
@@ -0,0 +1,19 @@
+{
+ // ACTION REQUIRED: This file was automatically added to your project, but it
+ // will not take effect until additional steps are taken to enable it. See the
+ // following page for additional information:
+ //
+ // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md
+
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "documentInterfaces": false,
+ "documentExposedElements": false,
+ "documentInternalElements": false,
+ "documentPrivateElements": false,
+ "documentPrivateFields": false,
+ "companyName": "Adrian Conlon"
+ }
+ }
+}