mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2024-12-23 17:31:33 +00:00
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:
parent
12969dbef6
commit
9a1d5cc762
28
EightBit.sln
28
EightBit.sln
@ -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
480
Intel8080/Disassembler.cs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
Intel8080/Intel8080.Test/App.config
Normal file
6
Intel8080/Intel8080.Test/App.config
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
106
Intel8080/Intel8080.Test/Board.cs
Normal file
106
Intel8080/Intel8080.Test/Board.cs
Normal 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)}");
|
||||||
|
}
|
||||||
|
}
|
25
Intel8080/Intel8080.Test/Configuration.cs
Normal file
25
Intel8080/Intel8080.Test/Configuration.cs
Normal 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";
|
||||||
|
}
|
||||||
|
}
|
68
Intel8080/Intel8080.Test/Intel8080.Test.csproj
Normal file
68
Intel8080/Intel8080.Test/Intel8080.Test.csproj
Normal 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>
|
24
Intel8080/Intel8080.Test/Program.cs
Normal file
24
Intel8080/Intel8080.Test/Program.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
Intel8080/Intel8080.Test/Properties/AssemblyInfo.cs
Normal file
36
Intel8080/Intel8080.Test/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("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")]
|
56
Intel8080/Intel8080.Test/TestHarness.cs
Normal file
56
Intel8080/Intel8080.Test/TestHarness.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
Intel8080/Intel8080.Test/roms/8080EX1.COM
Normal file
BIN
Intel8080/Intel8080.Test/roms/8080EX1.COM
Normal file
Binary file not shown.
1286
Intel8080/Intel8080.Test/roms/8080EX1.MAC
Normal file
1286
Intel8080/Intel8080.Test/roms/8080EX1.MAC
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Intel8080/Intel8080.Test/roms/8080EXER.COM
Normal file
BIN
Intel8080/Intel8080.Test/roms/8080EXER.COM
Normal file
Binary file not shown.
BIN
Intel8080/Intel8080.Test/roms/8080PRE.COM
Normal file
BIN
Intel8080/Intel8080.Test/roms/8080PRE.COM
Normal file
Binary file not shown.
291
Intel8080/Intel8080.Test/roms/8080PRE.MAC
Normal file
291
Intel8080/Intel8080.Test/roms/8080PRE.MAC
Normal 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
|
||||||
|
|
1284
Intel8080/Intel8080.Test/roms/8085EXER.MAC
Normal file
1284
Intel8080/Intel8080.Test/roms/8085EXER.MAC
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Intel8080/Intel8080.Test/roms/CPUTEST.COM
Normal file
BIN
Intel8080/Intel8080.Test/roms/CPUTEST.COM
Normal file
Binary file not shown.
805
Intel8080/Intel8080.Test/roms/TEST.ASM
Normal file
805
Intel8080/Intel8080.Test/roms/TEST.ASM
Normal 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
|
||||||
|
|
BIN
Intel8080/Intel8080.Test/roms/TEST.COM
Normal file
BIN
Intel8080/Intel8080.Test/roms/TEST.COM
Normal file
Binary file not shown.
822
Intel8080/Intel8080.cs
Normal file
822
Intel8080/Intel8080.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
57
Intel8080/Intel8080.csproj
Normal file
57
Intel8080/Intel8080.csproj
Normal 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>
|
36
Intel8080/Properties/AssemblyInfo.cs
Normal file
36
Intel8080/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("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
27
Intel8080/StatusBits.cs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user