EightBitNet/Z80/Z80.Test/Board.cs

116 lines
3.5 KiB
C#
Raw Normal View History

// <copyright file="Board.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
namespace Z80.Test
{
using System.Text;
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 Z80(this, this.ports);
this.disassembler = new Disassembler(this);
this.mapping = new MemoryMapping(this.ram, 0x0000, (ushort)Mask.Mask16, AccessLevel.ReadWrite);
}
public Z80 CPU { get; }
public override void RaisePOWER()
{
base.RaisePOWER();
this.CPU.RaisePOWER();
this.CPU.RaiseRESET();
this.CPU.RaiseINT();
this.CPU.RaiseNMI();
}
public override void LowerPOWER()
{
this.CPU.LowerPOWER();
base.LowerPOWER();
}
public override void Initialize()
{
var programFilename = this.configuration.Program;
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 (CPU.C)
{
case 0x2:
System.Console.Out.Write(CPU.E.ToString());
break;
case 0x9:
for (ushort i = CPU.DE.Word; Peek(i) != '$'; ++i)
{
System.Console.Out.Write((char)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
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)}");
}
}
}