diff --git a/M6502/M6502.Test/Board.cs b/M6502/M6502.Test/Board.cs index 8a06f26..2611501 100644 --- a/M6502/M6502.Test/Board.cs +++ b/M6502/M6502.Test/Board.cs @@ -16,6 +16,11 @@ namespace M6502.Test private readonly MemoryMapping mapping; private ushort oldPC; + private int cyclesPolled; + + private char key; + private bool keyHandled; + private bool keyAvailable; public Board(Configuration configuration) { @@ -56,18 +61,70 @@ namespace M6502.Test if (this.configuration.DebugMode) { - this.CPU.ExecutingInstruction += this.CPU_ExecutingInstruction; + this.CPU.ExecutingInstruction += this.CPU_ExecutingInstruction_Debugging; + } + + if (!this.configuration.BreakOnRead) + { + this.CPU.ExecutedInstruction += this.CPU_ExecutedInstruction_Polling; } this.CPU.ExecutedInstruction += this.CPU_ExecutedInstruction; + this.CPU.Bus.WrittenByte += this.Bus_WrittenByte; + this.CPU.Bus.ReadingByte += this.Bus_ReadingByte; + this.CPU.Bus.ReadByte += this.Bus_ReadByte; + this.Poke(0x00, 0x4c); this.CPU.PokeWord(0x01, this.configuration.StartAddress); } public override MemoryMapping Mapping(ushort absolute) => this.mapping; - private void CPU_ExecutedInstruction(object sender, System.EventArgs e) + private void Bus_ReadingByte(object? sender, EventArgs e) + { + var address = this.CPU.Bus.Address; + if (address == this.configuration.InputAddress) + { + var ready = this.keyAvailable && !this.keyHandled; + if (ready && (this.CPU.Bus.Peek(address) == 0)) + { + this.CPU.Bus.Poke(address, (byte)this.key); + this.keyHandled = true; + } + } + } + + private void Bus_ReadByte(object? sender, EventArgs e) + { + var address = this.CPU.Bus.Address; + if (address == this.configuration.InputAddress) + { + if (this.configuration.BreakOnRead) + { + this.LowerPOWER(); + } + else + { + if (this.keyHandled) + { + this.CPU.Bus.Poke(address, 0); + this.keyAvailable = false; + } + } + } + } + + private void Bus_WrittenByte(object? sender, EventArgs e) + { + if (this.CPU.Bus.Address == this.configuration.OutputAddress) + { + var contents = this.CPU.Bus.Peek(this.CPU.Bus.Address); + Console.Out.Write((char)contents); + } + } + + private void CPU_ExecutedInstruction(object? sender, EventArgs e) { var pc = this.CPU.PC.Word; if (this.oldPC != pc) @@ -84,7 +141,30 @@ namespace M6502.Test } } - private void CPU_ExecutingInstruction(object sender, System.EventArgs e) + private void CPU_ExecutedInstruction_Polling(object? sender, EventArgs e) + { + var cycles = this.CPU.Cycles; + this.cyclesPolled += cycles; + System.Diagnostics.Debug.Assert(cycles > 0, "Invalid pollingcycle count"); + if (this.cyclesPolled > this.configuration.PollingTickInterval) + { + this.cyclesPolled = 0; + this.PollHostKeyboard(); + } + } + + private void PollHostKeyboard() + { + if (Console.KeyAvailable) + { + var key = Console.ReadKey(true); + this.key = key.KeyChar; + this.keyAvailable = true; + this.keyHandled = false; + } + } + + private void CPU_ExecutingInstruction_Debugging(object? sender, EventArgs e) { var address = this.CPU.PC.Word; diff --git a/M6502/M6502.Test/Configuration.cs b/M6502/M6502.Test/Configuration.cs index e81deb2..f135c77 100644 --- a/M6502/M6502.Test/Configuration.cs +++ b/M6502/M6502.Test/Configuration.cs @@ -14,10 +14,18 @@ namespace M6502.Test public bool DebugMode { get; set; } = false; + public bool BreakOnRead { get; } = true; + public Register16 LoadAddress { get; } = new Register16(0x400); public Register16 StartAddress { get; } = new Register16(0x400); + public Register16 InputAddress { get; } = new Register16(0xf004); + + public Register16 OutputAddress { get; } = new Register16(0xf001); + + public int PollingTickInterval { get; } = 10000000; + public string RomDirectory { get; } = "roms"; public string Program { get; } = "6502_functional_test.bin"; diff --git a/M6502/M6502.Test/roms/6502_functional_test.a65 b/M6502/M6502.Test/roms/6502_functional_test.a65 index 8653dc6..8730384 100644 --- a/M6502/M6502.Test/roms/6502_functional_test.a65 +++ b/M6502/M6502.Test/roms/6502_functional_test.a65 @@ -117,7 +117,7 @@ disable_selfmod = 0 ;report errors through I/O channel (0=use standard self trap loops, 1=include ;report.i65 as I/O channel, add 3.5 kB) -report = 0 +report = 1 ;RAM integrity test option. Checks for undesired RAM writes. ;set lowest non RAM or RAM mirror address page (-1=disable, 0=64k, $40=16k) diff --git a/M6502/M6502.Test/roms/6502_functional_test.bin b/M6502/M6502.Test/roms/6502_functional_test.bin index ec727f7..cada378 100644 Binary files a/M6502/M6502.Test/roms/6502_functional_test.bin and b/M6502/M6502.Test/roms/6502_functional_test.bin differ