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
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z80.Test", "Z80\Z80.Test\Z80.Test.csproj", "{F749BEAE-8903-400B-875C-1220ADCFEF08}"
|
||||
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
|
||||
GlobalSection(Performance) = preSolution
|
||||
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|x86.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
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