From 175069d6bf17876e97397023abc5309088041d2d Mon Sep 17 00:00:00 2001 From: Adrian Conlon <98398945+AdrianConlon@users.noreply.github.com> Date: Fri, 2 May 2025 20:18:04 +0100 Subject: [PATCH] More Z80 timing fixes --- Z80/Z80.HarteTest/Checker.cs | 22 ++++++++++++++++-- Z80/Z80.HarteTest/Test.cs | 2 +- Z80/Z80.cs | 43 ++++++++++++++++++++++-------------- 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/Z80/Z80.HarteTest/Checker.cs b/Z80/Z80.HarteTest/Checker.cs index a0b3c36..cfc791a 100644 --- a/Z80/Z80.HarteTest/Checker.cs +++ b/Z80/Z80.HarteTest/Checker.cs @@ -333,10 +333,10 @@ private void InitialiseState(Test test) { var initial = test.Initial ?? throw new InvalidOperationException("Test cannot have an invalid initial state"); - this.InitialiseState(initial); + this.InitialiseState(initial, test.AvailablePorts()); } - private void InitialiseState(State state) + private void InitialiseState(State state, IEnumerable ports) { var runner = this.Runner; var cpu = runner.CPU; @@ -390,6 +390,24 @@ var value = (byte)entry[1]; runner.Poke(address, value); } + + foreach (var port in ports) + { + var address = new Register16(port.Address).Low; + var value = port.Value; + if (port.Type == "r") + { + cpu.Ports.WriteInputPort(address, value); + } + else if (port.Type == "w") + { + cpu.Ports.WriteOutputPort(address, value); + } + else + { + throw new InvalidOperationException($"Unknown port action type: {port.Type}"); + } + } } private void AddActualCycle(EightBit.Register16 address, byte value, string action) => this.AddActualCycle(address.Word, value, action); diff --git a/Z80/Z80.HarteTest/Test.cs b/Z80/Z80.HarteTest/Test.cs index 5016881..44b4442 100644 --- a/Z80/Z80.HarteTest/Test.cs +++ b/Z80/Z80.HarteTest/Test.cs @@ -29,7 +29,7 @@ { if (this.Ports is null) { - throw new InvalidOperationException("Ports have not been initialised"); + yield break; } foreach (var port in this.Ports) diff --git a/Z80/Z80.cs b/Z80/Z80.cs index 9e2484e..f5651be 100644 --- a/Z80/Z80.cs +++ b/Z80/Z80.cs @@ -19,6 +19,8 @@ namespace Z80 private readonly InputOutput _ports; + public InputOutput Ports => this._ports; + private readonly Register16[] _accumulatorFlags = [new Register16(), new Register16()]; private readonly Register16[][] _registers = [ @@ -504,8 +506,16 @@ namespace Z80 var returned = base.MemoryRead(); this.RaiseRD(); this.RaiseMREQ(); - if (this.M1.Raised()) + if (this.M1.Lowered()) + { + this.Bus.Address.Assign(this.REFRESH, this.IV); + this.LowerRFSH(); this.Tick(); + this.LowerMREQ(); + this.RaiseMREQ(); + this.RaiseRFSH(); + } + this.Tick(); return returned; } @@ -1509,6 +1519,7 @@ namespace Z80 break; case 3: // LD SP,HL this.SP.Assign(this.HL2()); + this.Tick(2); break; default: throw new NotSupportedException("Invalid operation mode"); @@ -1695,15 +1706,6 @@ namespace Z80 this.LowerM1(); var returned = this.MemoryRead(this.PC); this.RaiseM1(); - - this.Bus.Address.Assign(this.REFRESH, this.IV); - this.LowerRFSH(); - this.Tick(); - this.LowerMREQ(); - this.RaiseMREQ(); - this.RaiseRFSH(); - this.Tick(); - return returned; } @@ -1766,9 +1768,9 @@ namespace Z80 protected sealed override bool ReturnConditionalFlag(int flag) { var condition = this.ConvertCondition(flag); + this.Tick(); if (condition) { - this.Tick(); this.Return(); } return condition; @@ -2029,11 +2031,18 @@ namespace Z80 ++this.Bus.Address.Word; this.MEMPTR.High = this.MemoryRead(); this.Tick(); - this.MemoryWrite(exchange.High); - exchange.High = this.MEMPTR.High; --this.Bus.Address.Word; - this.MemoryWrite(exchange.Low); + this.Tick(); + this.Bus.Data = exchange.Low; exchange.Low = this.MEMPTR.Low; + this.MemoryUpdate(1); + this.Tick(); + ++this.Bus.Address.Word; + this.Tick(); + this.Bus.Data = exchange.High; + exchange.High = this.MEMPTR.High; + this.MemoryUpdate(1); + this.Tick(3); } private void BlockCompare(Register16 source, ushort counter) @@ -2265,18 +2274,20 @@ namespace Z80 { this.Bus.Address.Assign(port, this.Bus.Data = this.A); this.MEMPTR.Assign(this.Bus.Address); - ++this.MEMPTR.Low; + ++this.MEMPTR.Word; this.ReadPort(); } private void ReadPort() { - this.Tick(); + this.Tick(2); this.LowerIORQ(); this.LowerRD(); this.Bus.Data = this._ports.Read(this.Bus.Address.Low); + this.Tick(); this.RaiseRD(); this.RaiseIORQ(); + this.Tick(); } } }