First commit of the Intel8080 processor core. Passes diagnostics. Runs at ~50% speed of unmanaged code.

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2019-02-28 00:06:35 +00:00
parent 12969dbef6
commit 9a1d5cc762
22 changed files with 5437 additions and 0 deletions

View File

@ -15,6 +15,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z80", "Z80\Z80.csproj", "{C
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z80.Test", "Z80\Z80.Test\Z80.Test.csproj", "{F749BEAE-8903-400B-875C-1220ADCFEF08}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z80.Test", "Z80\Z80.Test\Z80.Test.csproj", "{F749BEAE-8903-400B-875C-1220ADCFEF08}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Intel8080", "Intel8080\Intel8080.csproj", "{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Intel8080.Test", "Intel8080\Intel8080.Test\Intel8080.Test.csproj", "{B09091A2-43A6-4729-9EE2-047895ECAF30}"
EndProject
Global Global
GlobalSection(Performance) = preSolution GlobalSection(Performance) = preSolution
HasPerformanceSessions = true HasPerformanceSessions = true
@ -100,6 +104,30 @@ Global
{F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|x64.Build.0 = 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.ActiveCfg = Release|Any CPU
{F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|x86.Build.0 = Release|Any CPU {F749BEAE-8903-400B-875C-1220ADCFEF08}.Release|x86.Build.0 = Release|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Debug|x64.ActiveCfg = Debug|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Debug|x64.Build.0 = Debug|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Debug|x86.ActiveCfg = Debug|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Debug|x86.Build.0 = Debug|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Release|Any CPU.Build.0 = Release|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Release|x64.ActiveCfg = Release|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Release|x64.Build.0 = Release|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Release|x86.ActiveCfg = Release|Any CPU
{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}.Release|x86.Build.0 = Release|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Debug|x64.ActiveCfg = Debug|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Debug|x64.Build.0 = Debug|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Debug|x86.ActiveCfg = Debug|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Debug|x86.Build.0 = Debug|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|Any CPU.Build.0 = Release|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|x64.ActiveCfg = Release|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|x64.Build.0 = Release|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|x86.ActiveCfg = Release|Any CPU
{B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

480
Intel8080/Disassembler.cs Normal file
View File

@ -0,0 +1,480 @@
// <copyright file="Disassembler.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
public class Disassembler
{
public Disassembler(Bus bus) => this.Bus = bus;
public Bus Bus { get; }
public static string AsFlag(byte value, StatusBits flag, string represents, string off = "-") => (value & (byte)flag) != 0 ? represents : off;
public static string AsFlags(byte value) =>
AsFlag(value, StatusBits.SF, "S")
+ AsFlag(value, StatusBits.ZF, "Z")
+ AsFlag(value, (StatusBits)Bits.Bit5, "1", "0")
+ AsFlag(value, StatusBits.AC, "A")
+ AsFlag(value, (StatusBits)Bits.Bit3, "1", "0")
+ AsFlag(value, StatusBits.PF, "P")
+ AsFlag(value, (StatusBits)Bits.Bit1, "1", "0")
+ AsFlag(value, StatusBits.CF, "C");
public static string State(Intel8080 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;
return
$"PC={pc.Word:x4} SP={sp.Word:x4} "
+ $"A={a:x2} F={AsFlags(f)} "
+ $"B={b:x2} C={c:x2} "
+ $"D={d:x2} E={e:x2} "
+ $"H={h:x2} L={l:x2}";
}
public string Disassemble(Intel8080 cpu) => this.Disassemble(cpu, cpu.PC.Word);
private static string CC(int flag)
{
switch (flag)
{
case 0:
return "NZ";
case 1:
return "Z";
case 2:
return "NC";
case 3:
return "C";
case 4:
return "PO";
case 5:
return "PE";
case 6:
return "P";
case 7:
return "M";
}
throw new System.ArgumentOutOfRangeException(nameof(flag));
}
private static string ALU(int which)
{
switch (which)
{
case 0: // ADD A,n
return "ADD";
case 1: // ADC
return "ADC";
case 2: // SUB n
return "SUB";
case 3: // SBC A,n
return "SBB";
case 4: // AND n
return "ANA";
case 5: // XOR n
return "XRA";
case 6: // OR n
return "ORA";
case 7: // CP n
return "CMP";
}
throw new System.ArgumentOutOfRangeException(nameof(which));
}
private static string ALU2(int which)
{
switch (which)
{
case 0: // ADD A,n
return "ADI";
case 1: // ADC
return "ACI";
case 2: // SUB n
return "SUI";
case 3: // SBC A,n
return "SBI";
case 4: // AND n
return "ANI";
case 5: // XOR n
return "XRI";
case 6: // OR n
return "ORI";
case 7: // CP n
return "CPI";
}
throw new System.ArgumentOutOfRangeException(nameof(which));
}
private string Disassemble(Intel8080 cpu, ushort pc)
{
var opCode = this.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 = this.Bus.Peek((ushort)(pc + 1));
var absolute = cpu.PeekWord((ushort)(pc + 1)).Word;
var displacement = (sbyte)immediate;
var relative = pc + displacement + 2;
var indexedImmediate = this.Bus.Peek((ushort)(pc + 1));
var dumpCount = 0;
var output = $"{opCode:x2}";
var specification = string.Empty;
output += Disassemble(ref specification, ref dumpCount, x, y, z, p, q);
for (var i = 0; i < dumpCount; ++i)
{
output += $"{this.Bus.Peek((ushort)(pc + i + 1)):x2}";
}
output += '\t';
output += string.Format(specification, (int)immediate, (int)absolute, relative, (int)displacement, indexedImmediate);
return output;
}
private static string Disassemble(ref string specification, ref int dumpCount, int x, int y, int z, int p, int q)
{
var output = string.Empty;
switch (x)
{
case 0:
switch (z)
{
case 0: // Relative jumps and assorted ops
switch (y)
{
case 0: // NOP
specification = "NOP";
break;
case 1: // EX AF AF'
break;
case 2: // DJNZ d
break;
case 3: // JR d
break;
default: // JR cc,d
break;
}
break;
case 1: // 16-bit load immediate/add
switch (q)
{
case 0: // LD rp,nn
specification = "LXI " + RP(p) + ",{1:X4}H";
dumpCount += 2;
break;
case 1: // ADD HL,rp
specification = $"DAD {RP(p)}";
break;
}
break;
case 2: // Indirect loading
switch (q)
{
case 0:
switch (p)
{
case 0: // LD (BC),A
specification = "STAX B";
break;
case 1: // LD (DE),A
specification = "STAX D";
break;
case 2: // LD (nn),HL
specification = "SHLD {1:X4}H";
dumpCount += 2;
break;
case 3: // LD (nn),A
specification = "STA {1:X4}H";
dumpCount += 2;
break;
}
break;
case 1:
switch (p)
{
case 0: // LD A,(BC)
specification = "LDAX B";
break;
case 1: // LD A,(DE)
specification = "LDAX D";
break;
case 2: // LD HL,(nn)
specification = "LHLD {1:X4}H";
dumpCount += 2;
break;
case 3: // LD A,(nn)
specification = "LDA {1:X4}H";
dumpCount += 2;
break;
}
break;
}
break;
case 3: // 16-bit INC/DEC
switch (q)
{
case 0: // INC rp
specification = $"INX {RP(p)}";
break;
case 1: // DEC rp
specification = $"DCX {RP(p)}";
break;
}
break;
case 4: // 8-bit INC
specification = $"INR {R(y)}";
break;
case 5: // 8-bit DEC
specification = $"DCR {R(y)}";
break;
case 6: // 8-bit load immediate
specification = $"MVI {R(y)}" + ",{0:X2}H";
dumpCount++;
break;
case 7: // Assorted operations on accumulator/flags
switch (y)
{
case 0:
specification = "RLC";
break;
case 1:
specification = "RRC";
break;
case 2:
specification = "RAL";
break;
case 3:
specification = "RAR";
break;
case 4:
specification = "DAA";
break;
case 5:
specification = "CMA";
break;
case 6:
specification = "STC";
break;
case 7:
specification = "CMC";
break;
}
break;
}
break;
case 1: // 8-bit loading
specification = z == 6 && y == 6 ? "HLT" : $"MOV {R(y)},{R(z)}";
break;
case 2: // Operate on accumulator and register/memory location
specification = $"{ALU(y)} {R(z)}";
break;
case 3:
switch (z)
{
case 0: // Conditional return
specification = $"R{CC(y)}";
break;
case 1: // POP & various ops
switch (q)
{
case 0: // POP rp2[p]
specification = $"POP {RP2(p)}";
break;
case 1:
switch (p)
{
case 0: // RET
specification = "RET";
break;
case 1: // EXX
break;
case 2: // JP (HL)
specification = "PCHL";
break;
case 3: // LD SP,HL
specification = "SPHL";
break;
}
break;
}
break;
case 2: // Conditional jump
specification = $"J{CC(y)}" + " {1:X4}H";
dumpCount += 2;
break;
case 3: // Assorted operations
switch (y)
{
case 0: // JP nn
specification = "JMP {1:X4}H";
dumpCount += 2;
break;
case 1: // CB prefix
break;
case 2: // OUT (n),A
specification = "OUT {0:X2}H";
dumpCount++;
break;
case 3: // IN A,(n)
specification = "IN {0:X2}H";
dumpCount++;
break;
case 4: // EX (SP),HL
specification = "XHTL";
break;
case 5: // EX DE,HL
specification = "XCHG";
break;
case 6: // DI
specification = "DI";
break;
case 7: // EI
specification = "EI";
break;
}
break;
case 4: // Conditional call: CALL cc[y], nn
specification = $"C{CC(y)}" + " {1:X4}H";
dumpCount += 2;
break;
case 5: // PUSH & various ops
switch (q)
{
case 0: // PUSH rp2[p]
specification = $"PUSH {RP2(p)}";
break;
case 1:
switch (p)
{
case 0: // CALL nn
specification = "CALL {1:X4}H";
dumpCount += 2;
break;
case 1: // DD prefix
break;
case 2: // ED prefix
break;
case 3: // FD prefix
break;
}
break;
}
break;
case 6: // Operate on accumulator and immediate operand: alu[y] n
specification = ALU2(y) + " {0:X2}H";
dumpCount++;
break;
case 7: // Restart: RST y * 8
specification = $"RST {y * 8:X2}";
break;
}
break;
}
return output;
}
private static string RP(int rp)
{
switch (rp)
{
case 0:
return "B";
case 1:
return "D";
case 2:
return "H";
case 3:
return "SP";
}
throw new System.ArgumentOutOfRangeException(nameof(rp));
}
private static string RP2(int rp)
{
switch (rp)
{
case 0:
return "B";
case 1:
return "D";
case 2:
return "H";
case 3:
return "PSW";
}
throw new System.ArgumentOutOfRangeException(nameof(rp));
}
private static string R(int r)
{
switch (r)
{
case 0:
return "B";
case 1:
return "C";
case 2:
return "D";
case 3:
return "E";
case 4:
return "H";
case 5:
return "L";
case 6:
return "M";
case 7:
return "A";
}
throw new System.ArgumentOutOfRangeException(nameof(r));
}
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@ -0,0 +1,106 @@
// <copyright file="Board.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Intel8080.Test
{
using EightBit;
internal class Board : Bus
{
private readonly Configuration configuration;
private readonly Ram ram;
private readonly InputOutput ports;
private readonly Disassembler disassembler;
private readonly MemoryMapping mapping;
private int warmstartCount = 0;
public Board(Configuration configuration)
{
this.configuration = configuration;
this.ram = new Ram(0x10000);
this.ports = new InputOutput();
this.CPU = new Intel8080(this, this.ports);
this.disassembler = new Disassembler(this);
this.mapping = new MemoryMapping(this.ram, 0x0000, (ushort)Mask.Mask16, AccessLevel.ReadWrite);
}
public Intel8080 CPU { get; }
public override void RaisePOWER()
{
base.RaisePOWER();
this.CPU.RaisePOWER();
this.CPU.RaiseRESET();
this.CPU.RaiseINT();
}
public override void LowerPOWER()
{
this.CPU.LowerPOWER();
base.LowerPOWER();
}
public override void Initialize()
{
var programPath = this.configuration.RomDirectory + "/" + this.configuration.Program;
var loadAddress = this.configuration.LoadAddress;
this.ram.Load(programPath, loadAddress.Word);
this.CPU.LoweredHALT += this.CPU_LoweredHALT;
this.CPU.ExecutingInstruction += this.CPU_ExecutingInstruction_CPM;
if (this.configuration.DebugMode)
{
this.CPU.ExecutingInstruction += this.CPU_ExecutingInstruction_Debug;
}
this.Poke(0, 0xc3); // JMP
this.CPU.PokeWord(1, this.configuration.StartAddress);
this.Poke(5, 0xc9); // ret
}
public override MemoryMapping Mapping(ushort absolute) => this.mapping;
private void BDOS()
{
switch (this.CPU.C)
{
case 0x2:
System.Console.Out.Write((char)this.CPU.E);
break;
case 0x9:
for (var i = this.CPU.DE.Word; this.Peek(i) != '$'; ++i)
{
System.Console.Out.Write((char)this.Peek(i));
}
break;
}
}
private void CPU_ExecutingInstruction_CPM(object sender, System.EventArgs e)
{
switch (this.CPU.PC.Word)
{
case 0x0: // CP/M warm start
if (++this.warmstartCount == 2)
{
this.LowerPOWER();
}
break;
case 0x5: // BDOS
this.BDOS();
break;
default:
break;
}
}
private void CPU_LoweredHALT(object sender, System.EventArgs e) => this.LowerPOWER();
private void CPU_ExecutingInstruction_Debug(object sender, System.EventArgs e) => System.Console.Error.WriteLine($"{EightBit.Disassembler.State(this.CPU)}\t{this.disassembler.Disassemble(this.CPU)}");
}
}

View File

@ -0,0 +1,25 @@
// <copyright file="Configuration.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Intel8080.Test
{
using EightBit;
internal class Configuration
{
public Configuration()
{
}
public bool DebugMode { get; set; } = false;
public Register16 LoadAddress { get; } = new Register16(0x100);
public Register16 StartAddress { get; } = new Register16(0x100);
public string RomDirectory { get; } = "roms";
public string Program { get; } = "8080EX1.COM";
}
}

View File

@ -0,0 +1,68 @@
<?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>{B09091A2-43A6-4729-9EE2-047895ECAF30}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Intel8080.Test</RootNamespace>
<AssemblyName>Intel8080.Test</AssemblyName>
<TargetFrameworkVersion>v4.7.2</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>
<Prefer32Bit>false</Prefer32Bit>
</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>
<Prefer32Bit>false</Prefer32Bit>
</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="Board.cs" />
<Compile Include="Configuration.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestHarness.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="..\Intel8080.csproj">
<Project>{75ae8d08-4ea0-4b73-84e8-9c0ba694aa6a}</Project>
<Name>Intel8080</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,24 @@
// <copyright file="Program.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Intel8080.Test
{
public static class Program
{
static void Main(string[] args)
{
var configuration = new Configuration();
#if DEBUG
configuration.DebugMode = true;
#endif
//configuration.DebugMode = true;
using (var harness = new TestHarness(configuration))
{
harness.Run();
}
}
}
}

View 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("Intel8080.Test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Intel8080.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("b09091a2-43a6-4729-9ee2-047895ecaf30")]
// 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")]

View File

@ -0,0 +1,56 @@
// <copyright file="TestHarness.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Intel8080.Test
{
using System;
using System.Diagnostics;
internal class TestHarness : IDisposable
{
private readonly Stopwatch timer = new Stopwatch();
private readonly Board board;
private long totalCycles = 0;
private bool disposed = false;
public TestHarness(Configuration configuration) => this.board = new Board(configuration);
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
public void Run()
{
this.board.Initialize();
this.board.RaisePOWER();
var cpu = this.board.CPU;
this.timer.Start();
while (cpu.Powered)
{
this.totalCycles += cpu.Step();
}
this.timer.Stop();
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
System.Console.Out.WriteLine($"\n\nGuest cycles = {this.totalCycles}");
System.Console.Out.WriteLine($"Seconds = {this.timer.ElapsedMilliseconds / 1000.0}");
}
this.disposed = true;
}
}
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,291 @@
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.
;******************************************************************************
;
; Modified by Ian Bartholomew to run a preliminary test on an 8080 CPU
;
; Assemble using M80
;
;******************************************************************************
.8080
aseg
org 100h
start: mvi a,1 ; test simple compares and z/nz jumps
cpi 2
jz 0
cpi 1
jnz 0
jmp lab0
hlt ; emergency exit
db 0ffh
lab0: call lab2 ; does a simple call work?
lab1: jmp 0 ; fail
lab2: pop h ; check return address
mov a,h
cpi high lab1
jz lab3
jmp 0
lab3: mov a,l
cpi low lab1
jz lab4
jmp 0
; test presence and uniqueness of all machine registers
; (except ir)
lab4: lxi sp,regs1
pop psw
pop b
pop d
pop h
lxi sp,regs2+8
push h
push d
push b
push psw
v defl 0
rept 8
lda regs2+v/2
v defl v+2
cpi v
jnz 0
endm
; test access to memory via (hl)
lxi h,hlval
mov a,m
cpi 0a5h
jnz 0
lxi h,hlval+1
mov a,m
cpi 03ch
jnz 0
; test unconditional return
lxi sp,stack
lxi h,reta
push h
ret
jmp 0
; test instructions needed for hex output
reta: mvi a,0ffh
ani 0fh
cpi 0fh
jnz 0
mvi a,05ah
ani 0fh
cpi 0ah
jnz 0
rrc
cpi 05h
jnz 0
rrc
cpi 82h
jnz 0
rrc
cpi 41h
jnz 0
rrc
cpi 0a0h
jnz 0
lxi h,01234h
push h
pop b
mov a,b
cpi 12h
jnz 0
mov a,c
cpi 34h
jnz 0
; from now on we can report errors by displaying an address
; test conditional call, ret, jp, jr
tcond macro flag,pcond,ncond,rel
lxi h,&flag
push h
pop psw
c&pcond lab1&pcond
jmp error
lab1&pcond: pop h
lxi h,0d7h xor &flag
push h
pop psw
c&ncond lab2&pcond
jmp error
lab2&pcond: pop h
lxi h,lab3&pcond
push h
lxi h,&flag
push h
pop psw
r&pcond
call error
lab3&pcond: lxi h,lab4&pcond
push h
lxi h,0d7h xor &flag
push h
pop psw
r&ncond
call error
lab4&pcond: lxi h,&flag
push h
pop psw
j&pcond lab5&pcond
call error
lab5&pcond: lxi h,0d7h xor &flag
push h
pop psw
j&ncond lab6&pcond
call error
lab6&pcond:
endm
tcond 1,c,nc,1
tcond 4,pe,po,0
tcond 040h,z,nz,1
tcond 080h,m,p,0
; test indirect jumps
lxi h,lab7
pchl
call error
; djnz (and (partially) inc a, inc hl)
lab7: mvi a,0a5h
mvi b,4
lab8: rrc
dcr b
jnz lab8
cpi 05ah
cnz error
mvi b,16
lab9: inr a
dcr b
jnz lab9
cpi 06ah
cnz error
mvi b,0
lxi h,0
lab10: inx h
dcr b
jnz lab10
mov a,h
cpi 1
cnz error
mov a,l
cpi 0
cnz error
allok: lxi d,okmsg
mvi c,9
call 5
jmp 0
okmsg: db '8080 Preliminary tests complete$'
; display address at top of stack and exit
error: pop b
mvi h,high hextab
mov a,b
rrc
rrc
rrc
rrc
ani 15
mov l,a
mov a,m
call conout
mov a,b
ani 15
mov l,a
mov a,m
call conout
mov a,c
rrc
rrc
rrc
rrc
ani 15
mov l,a
mov a,m
call conout
mov a,c
ani 15
mov l,a
mov a,m
call conout
mvi a,13
call conout
mvi a,10
call conout
jmp 0
conout: push psw
push b
push d
push h
mvi c,2
mov e,a
call 5
pop h
pop d
pop b
pop psw
ret
v defl 0
regs1: rept 8
v defl v+2
db v
endm
regs2: ds 8,0
hlval: db 0a5h,03ch
; skip to next page boundary
org (($+255)/256)*256
hextab: db '0123456789abcdef'
ds 240
stack equ $
end start

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,805 @@
;***********************************************************************
; MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC VERSION 1.0 (C) 1980
;***********************************************************************
; Load into virtual altair with: ALTAIR L=TEST.HEX
; Then press F2 to view screen, and 'G' to execute the test.
;
;DONATED TO THE "SIG/M" CP/M USER'S GROUP BY:
;KELLY SMITH, MICROCOSM ASSOCIATES
;3055 WACO AVENUE
;SIMI VALLEY, CALIFORNIA, 93065
;(805) 527-9321 (MODEM, CP/M-NET (TM))
;(805) 527-0518 (VERBAL)
;
CPU 8080
ORG 00100H
LXI H, LOLZ
CALL MSG
JMP CPU ;JUMP TO 8080 CPU DIAGNOSTIC
;
LOLZ: DB "MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC VERSION 1.0 (C) 1980", 0dh, 0ah, 24h
;
BDOS EQU 00005H ;BDOS ENTRY TO CP/M
WBOOT: JMP 0
;
;MESSAGE OUTPUT ROUTINE
;
MSG: MOV A,M ; Get data
CPI '$' ; End?
RZ
CALL PCHAR ; Output
INX H ; Next
JMP MSG ; Do all
;
;
;CHARACTER OUTPUT ROUTINE
;
PCHAR: PUSH PSW
PUSH D
PUSH H
MOV E,A
MVI C,2
CALL BDOS
POP H
POP D
POP PSW
RET
;
;
;
BYTEO: PUSH PSW
CALL BYTO1
MOV E,A
CALL PCHAR
POP PSW
CALL BYTO2
MOV E,A
JMP PCHAR
BYTO1: RRC
RRC
RRC
RRC
BYTO2: ANI 0FH
CPI 0AH
JM BYTO3
ADI 7
BYTO3: ADI 30H
RET
;
;
;
;************************************************************
; MESSAGE TABLE FOR OPERATIONAL CPU TEST
;************************************************************
;
OKCPU: DB 0DH,0AH
DB "CPU IS OPERATIONAL$"
;
NGCPU: DB 0DH,0AH
DB " CPU HAS FAILED! ERROR EXIT=$"
;
;
;
;************************************************************
; 8080/8085 CPU TEST/DIAGNOSTIC
;************************************************************
;
;NOTE: (1) PROGRAM ASSUMES "CALL",AND "LXI SP" INSTRUCTIONS WORK!
;
; (2) INSTRUCTIONS NOT TESTED ARE "HLT","DI","EI",
; AND "RST 0" THRU "RST 7"
;
;
;
;TEST JUMP INSTRUCTIONS AND FLAGS
;
CPU: LXI SP,STACK ;SET THE STACK POINTER
ANI 0 ;INITIALIZE A REG. AND CLEAR ALL FLAGS
JZ J010 ;TEST "JZ"
CALL CPUER
J010: JNC J020 ;TEST "JNC"
CALL CPUER
J020: JPE J030 ;TEST "JPE"
CALL CPUER
J030: JP J040 ;TEST "JP"
CALL CPUER
J040: JNZ J050 ;TEST "JNZ"
JC J050 ;TEST "JC"
JPO J050 ;TEST "JPO"
JM J050 ;TEST "JM"
JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL!
J050: CALL CPUER
J060: ADI 6 ;A=6,C=0,P=1,S=0,Z=0
JNZ J070 ;TEST "JNZ"
CALL CPUER
J070: JC J080 ;TEST "JC"
JPO J080 ;TEST "JPO"
JP J090 ;TEST "JP"
J080: CALL CPUER
J090: ADI 070H ;A=76H,C=0,P=0,S=0,Z=0
JPO J100 ;TEST "JPO"
CALL CPUER
J100: JM J110 ;TEST "JM"
JZ J110 ;TEST "JZ"
JNC J120 ;TEST "JNC"
J110: CALL CPUER
J120: ADI 081H ;A=F7H,C=0,P=0,S=1,Z=0
JM J130 ;TEST "JM"
CALL CPUER
J130: JZ J140 ;TEST "JZ"
JC J140 ;TEST "JC"
JPO J150 ;TEST "JPO"
J140: CALL CPUER
J150: ADI 0FEH ;A=F5H,C=1,P=1,S=1,Z=0
JC J160 ;TEST "JC"
CALL CPUER
J160: JZ J170 ;TEST "JZ"
JPO J170 ;TEST "JPO"
JM AIMM ;TEST "JM"
J170: CALL CPUER
;
;
;
;TEST ACCUMULATOR IMMEDIATE INSTRUCTIONS
;
AIMM: CPI 0 ;A=F5H,C=0,Z=0
JC CPIE ;TEST "CPI" FOR RE-SET CARRY
JZ CPIE ;TEST "CPI" FOR RE-SET ZERO
CPI 0F5H ;A=F5H,C=0,Z=1
JC CPIE ;TEST "CPI" FOR RE-SET CARRY ("ADI")
JNZ CPIE ;TEST "CPI" FOR RE-SET ZERO
CPI 0FFH ;A=F5H,C=1,Z=0
JZ CPIE ;TEST "CPI" FOR RE-SET ZERO
JC ACII ;TEST "CPI" FOR SET CARRY
CPIE: CALL CPUER
ACII: ACI 00AH ;A=F5H+0AH+CARRY(1)=0,C=1
ACI 00AH ;A=0+0AH+CARRY(0)=0BH,C=0
CPI 00BH
JZ SUII ;TEST "ACI"
CALL CPUER
SUII: SUI 00CH ;A=FFH,C=0
SUI 00FH ;A=F0H,C=1
CPI 0F0H
JZ SBII ;TEST "SUI"
CALL CPUER
SBII: SBI 0F1H ;A=F0H-0F1H-CARRY(0)=FFH,C=1
SBI 00EH ;A=FFH-OEH-CARRY(1)=F0H,C=0
CPI 0F0H
JZ ANII ;TEST "SBI"
CALL CPUER
ANII: ANI 055H ;A=F0H<AND>55H=50H,C=0,P=1,S=0,Z=0
CPI 050H
JZ ORII ;TEST "ANI"
CALL CPUER
ORII: ORI 03AH ;A=50H<OR>3AH=7AH,C=0,P=0,S=0,Z=0
CPI 07AH
JZ XRII ;TEST "ORI"
CALL CPUER
XRII: XRI 00FH ;A=7AH<XOR>0FH=75H,C=0,P=0,S=0,Z=0
CPI 075H
JZ C010 ;TEST "XRI"
CALL CPUER
;
;
;
;TEST CALLS AND RETURNS
;
C010: ANI 000H ;A=0,C=0,P=1,S=0,Z=1
CC CPUER ;TEST "CC"
CPO CPUER ;TEST "CPO"
CM CPUER ;TEST "CM"
CNZ CPUER ;TEST "CNZ"
CPI 000H
JZ C020 ;A=0,C=0,P=0,S=0,Z=1
CALL CPUER
C020: SUI 077H ;A=89H,C=1,P=0,S=1,Z=0
CNC CPUER ;TEST "CNC"
CPE CPUER ;TEST "CPE"
CP CPUER ;TEST "CP"
CZ CPUER ;TEST "CZ"
CPI 089H
JZ C030 ;TEST FOR "CALLS" TAKING BRANCH
CALL CPUER
C030: ANI 0FFH ;SET FLAGS BACK!
CPO CPOI ;TEST "CPO"
CPI 0D9H
JZ MOVI ;TEST "CALL" SEQUENCE SUCCESS
CALL CPUER
CPOI: RPE ;TEST "RPE"
ADI 010H ;A=99H,C=0,P=0,S=1,Z=0
CPE CPEI ;TEST "CPE"
ADI 002H ;A=D9H,C=0,P=0,S=1,Z=0
RPO ;TEST "RPO"
CALL CPUER
CPEI: RPO ;TEST "RPO"
ADI 020H ;A=B9H,C=0,P=0,S=1,Z=0
CM CMI ;TEST "CM"
ADI 004H ;A=D7H,C=0,P=1,S=1,Z=0
RPE ;TEST "RPE"
CALL CPUER
CMI: RP ;TEST "RP"
ADI 080H ;A=39H,C=1,P=1,S=0,Z=0
CP TCPI ;TEST "CP"
ADI 080H ;A=D3H,C=0,P=0,S=1,Z=0
RM ;TEST "RM"
CALL CPUER
TCPI: RM ;TEST "RM"
ADI 040H ;A=79H,C=0,P=0,S=0,Z=0
CNC CNCI ;TEST "CNC"
ADI 040H ;A=53H,C=0,P=1,S=0,Z=0
RP ;TEST "RP"
CALL CPUER
CNCI: RC ;TEST "RC"
ADI 08FH ;A=08H,C=1,P=0,S=0,Z=0
CC CCI ;TEST "CC"
SUI 002H ;A=13H,C=0,P=0,S=0,Z=0
RNC ;TEST "RNC"
CALL CPUER
CCI: RNC ;TEST "RNC"
ADI 0F7H ;A=FFH,C=0,P=1,S=1,Z=0
CNZ CNZI ;TEST "CNZ"
ADI 0FEH ;A=15H,C=1,P=0,S=0,Z=0
RC ;TEST "RC"
CALL CPUER
CNZI: RZ ;TEST "RZ"
ADI 001H ;A=00H,C=1,P=1,S=0,Z=1
CZ CZI ;TEST "CZ"
ADI 0D0H ;A=17H,C=1,P=1,S=0,Z=0
RNZ ;TEST "RNZ"
CALL CPUER
CZI: RNZ ;TEST "RNZ"
ADI 047H ;A=47H,C=0,P=1,S=0,Z=0
CPI 047H ;A=47H,C=0,P=1,S=0,Z=1
RZ ;TEST "RZ"
CALL CPUER
;
;
;
;TEST "MOV","INR",AND "DCR" INSTRUCTIONS
;
MOVI: MVI A,077H
INR A
MOV B,A
INR B
MOV C,B
DCR C
MOV D,C
MOV E,D
MOV H,E
MOV L,H
MOV A,L ;TEST "MOV" A,L,H,E,D,C,B,A
DCR A
MOV C,A
MOV E,C
MOV L,E
MOV B,L
MOV D,B
MOV H,D
MOV A,H ;TEST "MOV" A,H,D,B,L,E,C,A
MOV D,A
INR D
MOV L,D
MOV C,L
INR C
MOV H,C
MOV B,H
DCR B
MOV E,B
MOV A,E ;TEST "MOV" A,E,B,H,C,L,D,A
MOV E,A
INR E
MOV B,E
MOV H,B
INR H
MOV C,H
MOV L,C
MOV D,L
DCR D
MOV A,D ;TEST "MOV" A,D,L,C,H,B,E,A
MOV H,A
DCR H
MOV D,H
MOV B,D
MOV L,B
INR L
MOV E,L
DCR E
MOV C,E
MOV A,C ;TEST "MOV" A,C,E,L,B,D,H,A
MOV L,A
DCR L
MOV H,L
MOV E,H
MOV D,E
MOV C,D
MOV B,C
MOV A,B
CPI 077H
CNZ CPUER ;TEST "MOV" A,B,C,D,E,H,L,A
;
;
;
;TEST ARITHMETIC AND LOGIC INSTRUCTIONS
;
XRA A
MVI B,001H
MVI C,003H
MVI D,007H
MVI E,00FH
MVI H,01FH
MVI L,03FH
ADD B
ADD C
ADD D
ADD E
ADD H
ADD L
ADD A
CPI 0F0H
CNZ CPUER ;TEST "ADD" B,C,D,E,H,L,A
SUB B
SUB C
SUB D
SUB E
SUB H
SUB L
CPI 078H
CNZ CPUER ;TEST "SUB" B,C,D,E,H,L
SUB A
CNZ CPUER ;TEST "SUB" A
MVI A,080H
ADD A
MVI B,001H
MVI C,002H
MVI D,003H
MVI E,004H
MVI H,005H
MVI L,006H
ADC B
MVI B,080H
ADD B
ADD B
ADC C
ADD B
ADD B
ADC D
ADD B
ADD B
ADC E
ADD B
ADD B
ADC H
ADD B
ADD B
ADC L
ADD B
ADD B
ADC A
CPI 037H
CNZ CPUER ;TEST "ADC" B,C,D,E,H,L,A
MVI A,080H
ADD A
MVI B,001H
SBB B
MVI B,0FFH
ADD B
SBB C
ADD B
SBB D
ADD B
SBB E
ADD B
SBB H
ADD B
SBB L
CPI 0E0H
CNZ CPUER ;TEST "SBB" B,C,D,E,H,L
MVI A,080H
ADD A
SBB A
CPI 0FFH
CNZ CPUER ;TEST "SBB" A
MVI A,0FFH
MVI B,0FEH
MVI C,0FCH
MVI D,0EFH
MVI E,07FH
MVI H,0F4H
MVI L,0BFH
ANA A
ANA C
ANA D
ANA E
ANA H
ANA L
ANA A
CPI 024H
CNZ CPUER ;TEST "ANA" B,C,D,E,H,L,A
XRA A
MVI B,001H
MVI C,002H
MVI D,004H
MVI E,008H
MVI H,010H
MVI L,020H
ORA B
ORA C
ORA D
ORA E
ORA H
ORA L
ORA A
CPI 03FH
CNZ CPUER ;TEST "ORA" B,C,D,E,H,L,A
MVI A,000H
MVI H,08FH
MVI L,04FH
XRA B
XRA C
XRA D
XRA E
XRA H
XRA L
CPI 0CFH
CNZ CPUER ;TEST "XRA" B,C,D,E,H,L
XRA A
CNZ CPUER ;TEST "XRA" A
MVI B,044H
MVI C,045H
MVI D,046H
MVI E,047H
MVI H,(TEMP0/0FFH) ;HIGH BYTE OF TEST MEMORY LOCATION
MVI L,(TEMP0&0FFH) ;LOW BYTE OF TEST MEMORY LOCATION
MOV M,B
MVI B,000H
MOV B,M
MVI A,044H
CMP B
CNZ CPUER ;TEST "MOV" M,B AND B,M
MOV M,D
MVI D,000H
MOV D,M
MVI A,046H
CMP D
CNZ CPUER ;TEST "MOV" M,D AND D,M
MOV M,E
MVI E,000H
MOV E,M
MVI A,047H
CMP E
CNZ CPUER ;TEST "MOV" M,E AND E,M
MOV M,H
MVI H,(TEMP0/0FFH)
MVI L,(TEMP0&0FFH)
MOV H,M
MVI A,(TEMP0/0FFH)
CMP H
CNZ CPUER ;TEST "MOV" M,H AND H,M
MOV M,L
MVI H,(TEMP0/0FFH)
MVI L,(TEMP0&0FFH)
MOV L,M
MVI A,(TEMP0&0FFH)
CMP L
CNZ CPUER ;TEST "MOV" M,L AND L,M
MVI H,(TEMP0/0FFH)
MVI L,(TEMP0&0FFH)
MVI A,032H
MOV M,A
CMP M
CNZ CPUER ;TEST "MOV" M,A
ADD M
CPI 064H
CNZ CPUER ;TEST "ADD" M
XRA A
MOV A,M
CPI 032H
CNZ CPUER ;TEST "MOV" A,M
MVI H,(TEMP0/0FFH)
MVI L,(TEMP0&0FFH)
MOV A,M
SUB M
CNZ CPUER ;TEST "SUB" M
MVI A,080H
ADD A
ADC M
CPI 033H
CNZ CPUER ;TEST "ADC" M
MVI A,080H
ADD A
SBB M
CPI 0CDH
CNZ CPUER ;TEST "SBB" M
ANA M
CNZ CPUER ;TEST "ANA" M
MVI A,025H
ORA M
CPI 037H
CNZ CPUER ;TEST "ORA" M
XRA M
CPI 005H
CNZ CPUER ;TEST "XRA" M
MVI M,055H
INR M
DCR M
ADD M
CPI 05AH
CNZ CPUER ;TEST "INR","DCR",AND "MVI" M
LXI B,12FFH
LXI D,12FFH
LXI H,12FFH
INX B
INX D
INX H
MVI A,013H
CMP B
CNZ CPUER ;TEST "LXI" AND "INX" B
CMP D
CNZ CPUER ;TEST "LXI" AND "INX" D
CMP H
CNZ CPUER ;TEST "LXI" AND "INX" H
MVI A,000H
CMP C
CNZ CPUER ;TEST "LXI" AND "INX" B
CMP E
CNZ CPUER ;TEST "LXI" AND "INX" D
CMP L
CNZ CPUER ;TEST "LXI" AND "INX" H
DCX B
DCX D
DCX H
MVI A,012H
CMP B
CNZ CPUER ;TEST "DCX" B
CMP D
CNZ CPUER ;TEST "DCX" D
CMP H
CNZ CPUER ;TEST "DCX" H
MVI A,0FFH
CMP C
CNZ CPUER ;TEST "DCX" B
CMP E
CNZ CPUER ;TEST "DCX" D
CMP L
CNZ CPUER ;TEST "DCX" H
STA TEMP0
XRA A
LDA TEMP0
CPI 0FFH
CNZ CPUER ;TEST "LDA" AND "STA"
LHLD TEMPP
SHLD TEMP0
LDA TEMPP
MOV B,A
LDA TEMP0
CMP B
CNZ CPUER ;TEST "LHLD" AND "SHLD"
LDA TEMPP+1
MOV B,A
LDA TEMP0+1
CMP B
CNZ CPUER ;TEST "LHLD" AND "SHLD"
MVI A,0AAH
STA TEMP0
MOV B,H
MOV C,L
XRA A
LDAX B
CPI 0AAH
CNZ CPUER ;TEST "LDAX" B
INR A
STAX B
LDA TEMP0
CPI 0ABH
CNZ CPUER ;TEST "STAX" B
MVI A,077H
STA TEMP0
LHLD TEMPP
LXI D,00000H
XCHG
XRA A
LDAX D
CPI 077H
CNZ CPUER ;TEST "LDAX" D AND "XCHG"
XRA A
ADD H
ADD L
CNZ CPUER ;TEST "XCHG"
MVI A,0CCH
STAX D
LDA TEMP0
CPI 0CCH
STAX D
LDA TEMP0
CPI 0CCH
CNZ CPUER ;TEST "STAX" D
LXI H,07777H
DAD H
MVI A,0EEH
CMP H
CNZ CPUER ;TEST "DAD" H
CMP L
CNZ CPUER ;TEST "DAD" H
LXI H,05555H
LXI B,0FFFFH
DAD B
MVI A,055H
CNC CPUER ;TEST "DAD" B
CMP H
CNZ CPUER ;TEST "DAD" B
MVI A,054H
CMP L
CNZ CPUER ;TEST "DAD" B
LXI H,0AAAAH
LXI D,03333H
DAD D
MVI A,0DDH
CMP H
CNZ CPUER ;TEST "DAD" D
CMP L
CNZ CPUER ;TEST "DAD" B
STC
CNC CPUER ;TEST "STC"
CMC
CC CPUER ;TEST "CMC
MVI A,0AAH
CMA
CPI 055H
CNZ CPUER ;TEST "CMA"
ORA A ;RE-SET AUXILIARY CARRY
DAA
CPI 055H
CNZ CPUER ;TEST "DAA"
MVI A,088H
ADD A
DAA
CPI 076H
CNZ CPUER ;TEST "DAA"
XRA A
MVI A,0AAH
DAA
CNC CPUER ;TEST "DAA"
CPI 010H
CNZ CPUER ;TEST "DAA"
XRA A
MVI A,09AH
DAA
CNC CPUER ;TEST "DAA"
CNZ CPUER ;TEST "DAA"
STC
MVI A,042H
RLC
CC CPUER ;TEST "RLC" FOR RE-SET CARRY
RLC
CNC CPUER ;TEST "RLC" FOR SET CARRY
CPI 009H
CNZ CPUER ;TEST "RLC" FOR ROTATION
RRC
CNC CPUER ;TEST "RRC" FOR SET CARRY
RRC
CPI 042H
CNZ CPUER ;TEST "RRC" FOR ROTATION
RAL
RAL
CNC CPUER ;TEST "RAL" FOR SET CARRY
CPI 008H
CNZ CPUER ;TEST "RAL" FOR ROTATION
RAR
RAR
CC CPUER ;TEST "RAR" FOR RE-SET CARRY
CPI 002H
CNZ CPUER ;TEST "RAR" FOR ROTATION
LXI B,01234H
LXI D,0AAAAH
LXI H,05555H
XRA A
PUSH B
PUSH D
PUSH H
PUSH PSW
LXI B,00000H
LXI D,00000H
LXI H,00000H
MVI A,0C0H
ADI 0F0H
POP PSW
POP H
POP D
POP B
CC CPUER ;TEST "PUSH PSW" AND "POP PSW"
CNZ CPUER ;TEST "PUSH PSW" AND "POP PSW"
CPO CPUER ;TEST "PUSH PSW" AND "POP PSW"
CM CPUER ;TEST "PUSH PSW" AND "POP PSW"
MVI A,012H
CMP B
CNZ CPUER ;TEST "PUSH B" AND "POP B"
MVI A,034H
CMP C
CNZ CPUER ;TEST "PUSH B" AND "POP B"
MVI A,0AAH
CMP D
CNZ CPUER ;TEST "PUSH D" AND "POP D"
CMP E
CNZ CPUER ;TEST "PUSH D" AND "POP D"
MVI A,055H
CMP H
CNZ CPUER ;TEST "PUSH H" AND "POP H"
CMP L
CNZ CPUER ;TEST "PUSH H" AND "POP H"
LXI H,00000H
DAD SP
SHLD SAVSTK ;SAVE THE "OLD" STACK-POINTER!
LXI SP,TEMP4
DCX SP
DCX SP
INX SP
DCX SP
MVI A,055H
STA TEMP2
CMA
STA TEMP3
POP B
CMP B
CNZ CPUER ;TEST "LXI","DAD","INX",AND "DCX" SP
CMA
CMP C
CNZ CPUER ;TEST "LXI","DAD","INX", AND "DCX" SP
LXI H,TEMP4
SPHL
LXI H,07733H
DCX SP
DCX SP
XTHL
LDA TEMP3
CPI 077H
CNZ CPUER ;TEST "SPHL" AND "XTHL"
LDA TEMP2
CPI 033H
CNZ CPUER ;TEST "SPHL" AND "XTHL"
MVI A,055H
CMP L
CNZ CPUER ;TEST "SPHL" AND "XTHL"
CMA
CMP H
CNZ CPUER ;TEST "SPHL" AND "XTHL"
LHLD SAVSTK ;RESTORE THE "OLD" STACK-POINTER
SPHL
LXI H,CPUOK
PCHL ;TEST "PCHL"
;
;
;
CPUER: LXI H,NGCPU ;OUTPUT "CPU HAS FAILED ERROR EXIT=" TO CONSOLE
CALL MSG
XTHL
MOV A,H
CALL BYTEO ;SHOW ERROR EXIT ADDRESS HIGH BYTE
MOV A,L
CALL BYTEO ;SHOW ERROR EXIT ADDRESS LOW BYTE
JMP WBOOT ;EXIT TO CP/M WARM BOOT
;
;
;
CPUOK: LXI H,OKCPU ;OUTPUT "CPU IS OPERATIONAL" TO CONSOLE
CALL MSG
JMP WBOOT ;EXIT TO CP/M WARM BOOT
;
;
;
TEMPP: DW TEMP0 ;POINTER USED TO TEST "LHLD","SHLD",
; AND "LDAX" INSTRUCTIONS
;
TEMP0: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
TEMP1: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
TEMP2 DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
TEMP3: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
TEMP4: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS
SAVSTK: DS 2 ;TEMPORARY STACK-POINTER STORAGE LOCATION
;
;
;
STACK EQU TEMPP+256 ;DE-BUG STACK POINTER STORAGE AREA
;
END

Binary file not shown.

822
Intel8080/Intel8080.cs Normal file
View File

@ -0,0 +1,822 @@
// <copyright file="Intel8080.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System;
public class Intel8080 : IntelProcessor
{
private readonly Register16 af = new Register16();
private readonly Register16 intermediate = new Register16();
private readonly InputOutput ports;
private bool interruptEnable = false;
public Intel8080(Bus bus, InputOutput ports)
: base(bus) => this.ports = ports;
public event EventHandler<EventArgs> ExecutingInstruction;
public event EventHandler<EventArgs> ExecutedInstruction;
public override Register16 AF
{
get
{
this.af.Low = (byte)((this.af.Low | (byte)Bits.Bit1) & (int)~(Bits.Bit5 | Bits.Bit3));
return this.af;
}
}
public override Register16 BC { get; } = new Register16((int)Mask.Mask16);
public override Register16 DE { get; } = new Register16((int)Mask.Mask16);
public override Register16 HL { get; } = new Register16((int)Mask.Mask16);
public override int Execute()
{
var decoded = this.GetDecodedOpCode(this.OpCode);
var x = decoded.X;
var y = decoded.Y;
var z = decoded.Z;
var p = decoded.P;
var q = decoded.Q;
this.Execute(x, y, z, p, q);
return this.Cycles;
}
public override int Step()
{
this.ResetCycles();
this.OnExecutingInstruction();
if (this.Powered)
{
if (this.RESET().Lowered())
{
this.HandleRESET();
}
else if (this.INT().Lowered())
{
this.HandleINT();
}
else if (this.Halted)
{
this.Execute(0); // NOP
}
else
{
this.Execute(this.FetchByte());
}
}
this.OnExecutedInstruction();
return this.Cycles;
}
protected virtual void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty);
protected virtual void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
protected override void HandleRESET()
{
base.HandleRESET();
this.DisableInterrupts();
this.Tick(3);
}
protected override void HandleINT()
{
base.HandleINT();
this.RaiseHALT();
if (this.interruptEnable)
{
this.DisableInterrupts();
this.Execute(this.Bus.Data);
this.Tick(3);
}
}
private static byte SetFlag(byte f, StatusBits flag) => SetFlag(f, (byte)flag);
private static byte SetFlag(byte f, StatusBits flag, int condition) => SetFlag(f, (byte)flag, condition);
private static byte SetFlag(byte f, StatusBits flag, bool condition) => SetFlag(f, (byte)flag, condition);
private static byte ClearFlag(byte f, StatusBits flag) => ClearFlag(f, (byte)flag);
private static byte ClearFlag(byte f, StatusBits flag, int condition) => ClearFlag(f, (byte)flag, condition);
private static byte AdjustSign(byte input, byte value) => SetFlag(input, StatusBits.SF, value & (byte)StatusBits.SF);
private static byte AdjustZero(byte input, byte value) => ClearFlag(input, StatusBits.ZF, value);
private static byte AdjustParity(byte input, byte value) => SetFlag(input, StatusBits.PF, EvenParity(value));
private static byte AdjustSZ(byte input, byte value)
{
input = AdjustSign(input, value);
return AdjustZero(input, value);
}
private static byte AdjustSZP(byte input, byte value)
{
input = AdjustSZ(input, value);
return AdjustParity(input, value);
}
private static byte AdjustAuxiliaryCarryAdd(byte input, byte before, byte value, int calculation) => SetFlag(input, StatusBits.AC, CalculateHalfCarryAdd(before, value, calculation));
private static byte AdjustAuxiliaryCarrySub(byte input, byte before, byte value, int calculation) => ClearFlag(input, StatusBits.AC, CalculateHalfCarrySub(before, value, calculation));
private void DisableInterrupts() => this.interruptEnable = false;
private void EnableInterrupts() => this.interruptEnable = true;
private byte R(int r)
{
switch (r)
{
case 0:
return this.B;
case 1:
return this.C;
case 2:
return this.D;
case 3:
return this.E;
case 4:
return this.H;
case 5:
return this.L;
case 6:
return this.BusRead(this.HL.Word);
case 7:
return this.A;
default:
throw new ArgumentOutOfRangeException(nameof(r));
}
}
private void R(int r, byte value)
{
switch (r)
{
case 0:
this.B = value;
break;
case 1:
this.C = value;
break;
case 2:
this.D = value;
break;
case 3:
this.E = value;
break;
case 4:
this.H = value;
break;
case 5:
this.L = value;
break;
case 6:
this.BusWrite(this.HL.Word, value);
break;
case 7:
this.A = value;
break;
default:
throw new ArgumentOutOfRangeException(nameof(r));
}
}
private Register16 RP(int rp)
{
switch (rp)
{
case 0:
return this.BC;
case 1:
return this.DE;
case 2:
return this.HL;
case 3:
return this.SP;
default:
throw new ArgumentOutOfRangeException(nameof(rp));
}
}
private Register16 RP2(int rp)
{
switch (rp)
{
case 0:
return this.BC;
case 1:
return this.DE;
case 2:
return this.HL;
case 3:
return this.AF;
default:
throw new ArgumentOutOfRangeException(nameof(rp));
}
}
private void Execute(int x, int y, int z, int p, int q)
{
switch (x)
{
case 0:
switch (z)
{
case 0: // Relative jumps and assorted ops
switch (y)
{
case 0: // NOP
this.Tick(4);
break;
}
break;
case 1: // 16-bit load immediate/add
switch (q)
{
case 0: // LD rp,nn
this.RP(p).Word = this.FetchWord().Word;
this.Tick(10);
break;
case 1: // ADD HL,rp
this.Add(this.RP(p));
this.Tick(11);
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break;
case 2: // Indirect loading
switch (q)
{
case 0:
switch (p)
{
case 0: // LD (BC),A
this.BusWrite(this.BC, this.A);
this.Tick(7);
break;
case 1: // LD (DE),A
this.BusWrite(this.DE, this.A);
this.Tick(7);
break;
case 2: // LD (nn),HL
this.Bus.Address.Word = this.FetchWord().Word;
this.SetWord(this.HL);
this.Tick(16);
break;
case 3: // LD (nn),A
this.Bus.Address.Word = this.FetchWord().Word;
this.BusWrite(this.A);
this.Tick(13);
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break;
case 1:
switch (p)
{
case 0: // LD A,(BC)
this.A = this.BusRead(this.BC);
this.Tick(7);
break;
case 1: // LD A,(DE)
this.A = this.BusRead(this.DE);
this.Tick(7);
break;
case 2: // LD HL,(nn)
this.Bus.Address.Word = this.FetchWord().Word;
this.HL.Word = this.GetWord().Word;
this.Tick(16);
break;
case 3: // LD A,(nn)
this.Bus.Address.Word = this.FetchWord().Word;
this.A = this.BusRead();
this.Tick(13);
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break;
case 3: // 16-bit INC/DEC
switch (q)
{
case 0: // INC rp
++this.RP(p).Word;
break;
case 1: // DEC rp
--this.RP(p).Word;
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
this.Tick(6);
break;
case 4: // 8-bit INC
this.R(y, this.Increment(this.R(y)));
this.Tick(4);
break;
case 5: // 8-bit DEC
this.R(y, this.Decrement(this.R(y)));
this.Tick(4);
if (y == 6)
{
this.Tick(7);
}
break;
case 6: // 8-bit load immediate
this.R(y, this.FetchByte());
this.Tick(7);
if (y == 6)
{
this.Tick(3);
}
break;
case 7: // Assorted operations on accumulator/flags
switch (y)
{
case 0:
this.A = this.RLC(this.A);
break;
case 1:
this.A = this.RRC(this.A);
break;
case 2:
this.A = this.RL(this.A);
break;
case 3:
this.A = this.RR(this.A);
break;
case 4:
this.DAA();
break;
case 5:
this.CMA();
break;
case 6:
this.STC();
break;
case 7:
this.CMC();
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
this.Tick(4);
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break;
case 1: // 8-bit loading
if (z == 6 && y == 6) // Exception (replaces LD (HL), (HL))
{
this.Halt();
}
else
{
this.R(y, this.R(z));
if ((y == 6) || (z == 6)) // M operations
{
this.Tick(3);
}
}
this.Tick(4);
break;
case 2: // Operate on accumulator and register/memory location
switch (y)
{
case 0: // ADD A,r
this.Add(this.R(z));
break;
case 1: // ADC A,r
this.ADC(this.R(z));
break;
case 2: // SUB r
this.SUB(this.R(z));
break;
case 3: // SBC A,r
this.SBB(this.R(z));
break;
case 4: // AND r
this.AndR(this.R(z));
break;
case 5: // XOR r
this.XorR(this.R(z));
break;
case 6: // OR r
this.OrR(this.R(z));
break;
case 7: // CP r
this.Compare(this.R(z));
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
this.Tick(4);
if (z == 6)
{
this.Tick(3);
}
break;
case 3:
switch (z)
{
case 0: // Conditional return
if (this.ReturnConditionalFlag(y))
{
this.Tick(6);
}
this.Tick(5);
break;
case 1: // POP & various ops
switch (q)
{
case 0: // POP rp2[p]
this.RP2(p).Word = this.PopWord().Word;
this.Tick(10);
break;
case 1:
switch (p)
{
case 0: // RET
this.Return();
this.Tick(10);
break;
case 2: // JP HL
this.Jump(this.HL);
this.Tick(4);
break;
case 3: // LD SP,HL
this.SP.Word = this.HL.Word;
this.Tick(4);
break;
}
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break;
case 2: // Conditional jump
this.JumpConditionalFlag(y);
this.Tick(10);
break;
case 3: // Assorted operations
switch (y)
{
case 0: // JP nn
this.Jump(this.FetchWord());
this.Tick(10);
break;
case 2: // OUT (n),A
this.WritePort(this.FetchByte());
this.Tick(11);
break;
case 3: // IN A,(n)
this.A = this.ReadPort(this.FetchByte());
this.Tick(11);
break;
case 4: // EX (SP),HL
this.XHTL();
this.Tick(19);
break;
case 5: // EX DE,HL
(this.DE.Word, this.HL.Word) = (this.HL.Word, this.DE.Word);
this.Tick(4);
break;
case 6: // DI
this.DisableInterrupts();
this.Tick(4);
break;
case 7: // EI
this.EnableInterrupts();
this.Tick(4);
break;
}
break;
case 4: // Conditional call: CALL cc[y], nn
if (this.CallConditionalFlag(y))
{
this.Tick(7);
}
this.Tick(10);
break;
case 5: // PUSH & various ops
switch (q)
{
case 0: // PUSH rp2[p]
this.PushWord(this.RP2(p));
this.Tick(11);
break;
case 1:
switch (p)
{
case 0: // CALL nn
this.Call(this.FetchWord());
this.Tick(17);
break;
}
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break;
case 6: // Operate on accumulator and immediate operand: alu[y] n
switch (y)
{
case 0: // ADD A,n
this.Add(this.FetchByte());
break;
case 1: // ADC A,n
this.ADC(this.FetchByte());
break;
case 2: // SUB n
this.SUB(this.FetchByte());
break;
case 3: // SBC A,n
this.SBB(this.FetchByte());
break;
case 4: // AND n
this.AndR(this.FetchByte());
break;
case 5: // XOR n
this.XorR(this.FetchByte());
break;
case 6: // OR n
this.OrR(this.FetchByte());
break;
case 7: // CP n
this.Compare(this.FetchByte());
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
this.Tick(7);
break;
case 7: // Restart: RST y * 8
this.Restart((byte)(y << 3));
this.Tick(11);
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break;
}
}
private byte Increment(byte operand)
{
this.F = AdjustSZP(this.F, ++operand);
this.F = ClearFlag(this.F, StatusBits.AC, LowNibble(operand));
return operand;
}
private byte Decrement(byte operand)
{
this.F = AdjustSZP(this.F, --operand);
this.F = SetFlag(this.F, StatusBits.AC, LowNibble(operand) != (byte)Mask.Mask4);
return operand;
}
private bool JumpConditionalFlag(int flag)
{
switch (flag)
{
case 0: // NZ
return this.JumpConditional((this.F & (byte)StatusBits.ZF) == 0);
case 1: // Z
return this.JumpConditional((this.F & (byte)StatusBits.ZF) != 0);
case 2: // NC
return this.JumpConditional((this.F & (byte)StatusBits.CF) == 0);
case 3: // C
return this.JumpConditional((this.F & (byte)StatusBits.CF) != 0);
case 4: // PO
return this.JumpConditional((this.F & (byte)StatusBits.PF) == 0);
case 5: // PE
return this.JumpConditional((this.F & (byte)StatusBits.PF) != 0);
case 6: // P
return this.JumpConditional((this.F & (byte)StatusBits.SF) == 0);
case 7: // M
return this.JumpConditional((this.F & (byte)StatusBits.SF) != 0);
default:
throw new ArgumentOutOfRangeException(nameof(flag));
}
}
private bool ReturnConditionalFlag(int flag)
{
switch (flag)
{
case 0: // NZ
return this.ReturnConditional((this.F & (byte)StatusBits.ZF) == 0);
case 1: // Z
return this.ReturnConditional((this.F & (byte)StatusBits.ZF) != 0);
case 2: // NC
return this.ReturnConditional((this.F & (byte)StatusBits.CF) == 0);
case 3: // C
return this.ReturnConditional((this.F & (byte)StatusBits.CF) != 0);
case 4: // PO
return this.ReturnConditional((this.F & (byte)StatusBits.PF) == 0);
case 5: // PE
return this.ReturnConditional((this.F & (byte)StatusBits.PF) != 0);
case 6: // P
return this.ReturnConditional((this.F & (byte)StatusBits.SF) == 0);
case 7: // M
return this.ReturnConditional((this.F & (byte)StatusBits.SF) != 0);
default:
throw new ArgumentOutOfRangeException(nameof(flag));
}
}
private bool CallConditionalFlag(int flag)
{
switch (flag)
{
case 0: // NZ
return this.CallConditional((this.F & (byte)StatusBits.ZF) == 0);
case 1: // Z
return this.CallConditional((this.F & (byte)StatusBits.ZF) != 0);
case 2: // NC
return this.CallConditional((this.F & (byte)StatusBits.CF) == 0);
case 3: // C
return this.CallConditional((this.F & (byte)StatusBits.CF) != 0);
case 4: // PO
return this.CallConditional((this.F & (byte)StatusBits.PF) == 0);
case 5: // PE
return this.CallConditional((this.F & (byte)StatusBits.PF) != 0);
case 6: // P
return this.CallConditional((this.F & (byte)StatusBits.SF) == 0);
case 7: // M
return this.CallConditional((this.F & (byte)StatusBits.SF) != 0);
default:
throw new ArgumentOutOfRangeException(nameof(flag));
}
}
private void Add(Register16 value)
{
var result = this.HL.Word + value.Word;
this.HL.Word = (ushort)result;
this.F = SetFlag(this.F, StatusBits.CF, result & (int)Bits.Bit16);
}
private void Add(byte value, int carry = 0)
{
this.intermediate.Word = (ushort)(this.A + value + carry);
this.F = AdjustAuxiliaryCarryAdd(this.F, this.A, value, this.intermediate.Low);
this.A = this.intermediate.Low;
this.F = SetFlag(this.F, StatusBits.CF, this.intermediate.High & (byte)StatusBits.CF);
this.F = AdjustSZP(this.F, this.A);
}
private void ADC(byte value) => this.Add(value, this.F & (byte)StatusBits.CF);
private byte Subtract(byte operand, byte value, int carry = 0)
{
this.intermediate.Word = (ushort)(operand - value - carry);
this.F = AdjustAuxiliaryCarrySub(this.F, operand, value, this.intermediate.Word);
var result = this.intermediate.Low;
this.F = SetFlag(this.F, StatusBits.CF, this.intermediate.High & (byte)StatusBits.CF);
this.F = AdjustSZP(this.F, result);
return result;
}
private void SUB(byte value, int carry = 0) => this.A = this.Subtract(this.A, value, carry);
private void SBB(byte value) => this.SUB(value, this.F & (byte)StatusBits.CF);
private void AndR(byte value)
{
this.F = SetFlag(this.F, StatusBits.AC, (this.A | value) & (int)Bits.Bit3);
this.F = ClearFlag(this.F, StatusBits.CF);
this.F = AdjustSZP(this.F, this.A &= value);
}
private void XorR(byte value)
{
this.F = ClearFlag(this.F, StatusBits.AC | StatusBits.CF);
this.F = AdjustSZP(this.F, this.A ^= value);
}
private void OrR(byte value)
{
this.F = ClearFlag(this.F, StatusBits.AC | StatusBits.CF);
this.F = AdjustSZP(this.F, this.A |= value);
}
private void Compare(byte value) => this.Subtract(this.A, value);
private byte RLC(byte operand)
{
var carry = operand & (byte)Bits.Bit7;
this.F = SetFlag(this.F, StatusBits.CF, carry);
return (byte)((operand << 1) | (carry >> 7));
}
private byte RRC(byte operand)
{
var carry = operand & (byte)Bits.Bit0;
this.F = SetFlag(this.F, StatusBits.CF, carry);
return (byte)((operand >> 1) | (carry << 7));
}
private byte RL(byte operand)
{
var carry = this.F & (byte)StatusBits.CF;
this.F = SetFlag(this.F, StatusBits.CF, operand & (byte)Bits.Bit7);
return (byte)((operand << 1) | carry);
}
private byte RR(byte operand)
{
var carry = this.F & (byte)StatusBits.CF;
this.F = SetFlag(this.F, StatusBits.CF, operand & (byte)Bits.Bit0);
return (byte)((operand >> 1) | (carry << 7));
}
private void DAA()
{
var before = this.A;
var carry = (this.F & (byte)StatusBits.CF) != 0;
byte addition = 0;
if (((this.F & (byte)StatusBits.AC) != 0) || (LowNibble(before) > (byte)9))
{
addition = 0x6;
}
if (((this.F & (byte)StatusBits.CF) != 0) || HighNibble(before) > 9 || (HighNibble(before) >= 9 && LowNibble(before) > 9))
{
addition |= 0x60;
carry = true;
}
this.Add(addition);
this.F = SetFlag(this.F, StatusBits.CF, carry);
}
private void CMA() => this.A = (byte)~this.A;
private void STC() => this.F = SetFlag(this.F, StatusBits.CF);
private void CMC() => this.F = ClearFlag(this.F, StatusBits.CF, this.F & (byte)StatusBits.CF);
private void XHTL()
{
this.MEMPTR.Low = this.BusRead(this.SP);
this.BusWrite(this.L);
this.L = this.MEMPTR.Low;
++this.Bus.Address.Word;
this.MEMPTR.High = this.BusRead();
this.BusWrite(this.H);
this.H = this.MEMPTR.High;
}
private void WritePort(byte port)
{
this.Bus.Address.Word = new Register16(port, this.A).Word;
this.Bus.Data = this.A;
this.WritePort();
}
private void WritePort() => this.ports.Write(this.Bus.Address.Low, this.Bus.Data);
private byte ReadPort(byte port)
{
this.Bus.Address.Word = new Register16(port, this.A).Word;
return this.ReadPort();
}
private byte ReadPort() => this.Bus.Data = this.ports.Read(this.Bus.Address.Low);
}
}

View File

@ -0,0 +1,57 @@
<?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>{75AE8D08-4EA0-4B73-84E8-9C0BA694AA6A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EightBit</RootNamespace>
<AssemblyName>Intel8080</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</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="Disassembler.cs" />
<Compile Include="Intel8080.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StatusBits.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EightBit\EightBit.csproj">
<Project>{6ebf8857-62a3-4ef4-af21-c1844031d7e4}</Project>
<Name>EightBit</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View 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("Intel8080")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Intel8080")]
[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("75ae8d08-4ea0-4b73-84e8-9c0ba694aa6a")]
// 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")]

27
Intel8080/StatusBits.cs Normal file
View File

@ -0,0 +1,27 @@
// <copyright file="StatusBits.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace EightBit
{
using System;
[Flags]
public enum StatusBits
{
// Negative
SF = Bits.Bit7,
// Zero
ZF = Bits.Bit6,
// Half carry
AC = Bits.Bit4,
// Parity
PF = Bits.Bit2,
// Carry
CF = Bits.Bit0,
}
}