From d4dc99b45456f40d9fc5d803387705f05f3228ac Mon Sep 17 00:00:00 2001 From: Adrian Conlon <98398945+AdrianConlon@users.noreply.github.com> Date: Sun, 23 Mar 2025 11:08:36 +0000 Subject: [PATCH] Use lambda functions to simplify CPU pin control --- Z80/Z80.cs | 565 +++++++++++++++++++++++++++++------------------------ 1 file changed, 311 insertions(+), 254 deletions(-) diff --git a/Z80/Z80.cs b/Z80/Z80.cs index 0629d69..2afae0f 100644 --- a/Z80/Z80.cs +++ b/Z80/Z80.cs @@ -5,6 +5,8 @@ namespace Z80 { using EightBit; + using System.Diagnostics; + public class Z80(Bus bus, InputOutput ports) : IntelProcessor(bus) { @@ -24,76 +26,12 @@ namespace Z80 private bool _prefixED; private bool _prefixFD; - private PinLevel _nmiLine = PinLevel.Low; - private PinLevel _m1Line = PinLevel.Low; - private PinLevel _rfshLine = PinLevel.Low; - private PinLevel _mreqLine = PinLevel.Low; - private PinLevel _iorqLine = PinLevel.Low; - private PinLevel _rdLine = PinLevel.Low; - private PinLevel _wrLine = PinLevel.Low; - private int _accumulatorFlagsSet; private int _registerSet; private sbyte _displacement; private bool _displaced; - public event EventHandler? RaisingNMI; - - public event EventHandler? RaisedNMI; - - public event EventHandler? LoweringNMI; - - public event EventHandler? LoweredNMI; - - public event EventHandler? RaisingM1; - - public event EventHandler? RaisedM1; - - public event EventHandler? LoweringM1; - - public event EventHandler? LoweredM1; - - public event EventHandler? RaisingRFSH; - - public event EventHandler? RaisedRFSH; - - public event EventHandler? LoweringRFSH; - - public event EventHandler? LoweredRFSH; - - public event EventHandler? RaisingMREQ; - - public event EventHandler? RaisedMREQ; - - public event EventHandler? LoweringMREQ; - - public event EventHandler? LoweredMREQ; - - public event EventHandler? RaisingIORQ; - - public event EventHandler? RaisedIORQ; - - public event EventHandler? LoweringIORQ; - - public event EventHandler? LoweredIORQ; - - public event EventHandler? RaisingRD; - - public event EventHandler? RaisedRD; - - public event EventHandler? LoweringRD; - - public event EventHandler? LoweredRD; - - public event EventHandler? RaisingWR; - - public event EventHandler? RaisedWR; - - public event EventHandler? LoweringWR; - - public event EventHandler? LoweredWR; - public byte IV { get; set; } = 0xff; public int IM { get; set; } @@ -137,24 +75,6 @@ namespace Z80 // bits of the address bus. public ref RefreshRegister REFRESH => ref this._refresh; - public ref PinLevel NMI => ref this._nmiLine; - - public ref PinLevel M1 => ref this._m1Line; - - // ** From the Z80 CPU User Manual - // RFSH.Refresh(output, active Low). RFSH, together with MREQ, indicates that the lower - // seven bits of the system’s address bus can be used as a _refresh address to the system’s - // dynamic memories. - public ref PinLevel RFSH => ref this._rfshLine; - - public ref PinLevel MREQ => ref this._mreqLine; - - public ref PinLevel IORQ => ref this._iorqLine; - - public ref PinLevel RD => ref this._rdLine; - - public ref PinLevel WR => ref this._wrLine; - private void DisplaceAddress() { var displacement = (this._prefixDD ? this.IX : this.IY).Word + this._displacement; @@ -165,153 +85,6 @@ namespace Z80 public void ExxAF() => this._accumulatorFlagsSet ^= 1; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] - public virtual void RaiseNMI() - { - if (this.NMI.Lowered()) - { - this.OnRaisingNMI(); - this.NMI.Raise(); - this.OnRaisedNMI(); - } - } - - public virtual void LowerNMI() - { - if (this.NMI.Raised()) - { - this.OnLoweringNMI(); - this.NMI.Lower(); - this.OnLoweredNMI(); - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] - public virtual void RaiseM1() - { - if (this.M1.Lowered()) - { - this.OnRaisingM1(); - this.M1.Raise(); - this.OnRaisedM1(); - } - } - - public virtual void LowerM1() - { - if (this.M1.Raised()) - { - this.OnLoweringM1(); - this.M1.Lower(); - this.OnLoweredM1(); - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] - public virtual void RaiseRFSH() - { - if (this.RFSH.Lowered()) - { - this.OnRaisingRFSH(); - this.RFSH.Raise(); - this.OnRaisedRFSH(); - } - } - - public virtual void LowerRFSH() - { - if (this.RFSH.Raised()) - { - this.OnLoweringRFSH(); - this.RFSH.Lower(); - this.OnLoweredRFSH(); - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] - public virtual void RaiseMREQ() - { - if (this.MREQ.Lowered()) - { - this.OnRaisingMREQ(); - this.MREQ.Raise(); - this.OnRaisedMREQ(); - } - } - - public virtual void LowerMREQ() - { - if (this.MREQ.Raised()) - { - this.OnLoweringMREQ(); - this.MREQ.Lower(); - this.OnLoweredMREQ(); - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] - public virtual void RaiseIORQ() - { - if (this.IORQ.Lowered()) - { - this.OnRaisingIORQ(); - this.IORQ.Raise(); - this.OnRaisedIORQ(); - } - } - - public virtual void LowerIORQ() - { - if (this.IORQ.Raised()) - { - this.OnLoweringIORQ(); - this.IORQ.Lower(); - this.OnLoweredIORQ(); - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] - public virtual void RaiseRD() - { - if (this.RD.Lowered()) - { - this.OnRaisingRD(); - this.RD.Raise(); - this.OnRaisedRD(); - } - } - - public virtual void LowerRD() - { - if (this.RD.Raised()) - { - this.OnLoweringRD(); - this.RD.Lower(); - this.OnLoweredRD(); - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] - public virtual void RaiseWR() - { - if (this.WR.Lowered()) - { - this.OnRaisingWR(); - this.WR.Raise(); - this.OnRaisedWR(); - } - } - - public virtual void LowerWR() - { - if (this.WR.Raised()) - { - this.OnLoweringWR(); - this.WR.Lower(); - this.OnLoweredWR(); - } - } - public override void Execute() { var decoded = this.GetDecodedOpCode(this.OpCode); @@ -419,6 +192,49 @@ namespace Z80 this._prefixCB = this._prefixDD = this._prefixED = this._prefixFD = false; } + private static void WithPinChange(Func check, Action enter, Action leave, Action task) + { + if (check()) + { + enter(); + try + { + task(); + } + finally + { + leave(); + } + } + } + + private static byte WithPin(Action enter, Action leave, Func task) + { + enter(); + try + { + return task(); + } + finally + { + leave(); + } + } + + #region NMI pin + + public event EventHandler? RaisingNMI; + + public event EventHandler? RaisedNMI; + + public event EventHandler? LoweringNMI; + + public event EventHandler? LoweredNMI; + + private PinLevel _nmiLine = PinLevel.Low; + + public ref PinLevel NMI => ref this._nmiLine; + protected virtual void OnRaisingNMI() => RaisingNMI?.Invoke(this, EventArgs.Empty); protected virtual void OnRaisedNMI() => RaisedNMI?.Invoke(this, EventArgs.Empty); @@ -427,6 +243,43 @@ namespace Z80 protected virtual void OnLoweredNMI() => LoweredNMI?.Invoke(this, EventArgs.Empty); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] + public virtual void RaiseNMI() + { + if (this.NMI.Lowered()) + { + this.OnRaisingNMI(); + this.NMI.Raise(); + this.OnRaisedNMI(); + } + } + + public virtual void LowerNMI() + { + if (this.NMI.Raised()) + { + this.OnLoweringNMI(); + this.NMI.Lower(); + this.OnLoweredNMI(); + } + } + + #endregion + + #region M1 pin + + public event EventHandler? RaisingM1; + + public event EventHandler? RaisedM1; + + public event EventHandler? LoweringM1; + + public event EventHandler? LoweredM1; + + private PinLevel _m1Line = PinLevel.Low; + + public ref PinLevel M1 => ref this._m1Line; + protected virtual void OnRaisingM1() => RaisingM1?.Invoke(this, EventArgs.Empty); protected virtual void OnRaisedM1() @@ -439,6 +292,43 @@ namespace Z80 protected virtual void OnLoweredM1() => LoweredM1?.Invoke(this, EventArgs.Empty); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] + public virtual void RaiseM1() + { + WithPinChange(() => this.M1.Lowered(), this.OnRaisingM1, this.OnRaisedM1, () => this.M1.Raise()); + } + + public virtual void LowerM1() + { + WithPinChange(() => this.M1.Raised(), this.OnLoweringM1, this.OnLoweredM1, () => this.M1.Lower()); + } + + private byte WithM1(Func function) + { + return WithPin(this.LowerM1, this.RaiseM1, function); + } + + #endregion + + #region RFSH pin + + public event EventHandler? RaisingRFSH; + + public event EventHandler? RaisedRFSH; + + public event EventHandler? LoweringRFSH; + + public event EventHandler? LoweredRFSH; + + // ** From the Z80 CPU User Manual + // RFSH.Refresh(output, active Low). RFSH, together with MREQ, indicates that the lower + // seven bits of the system’s address bus can be used as a _refresh address to the system’s + // dynamic memories. + + private PinLevel _rfshLine = PinLevel.Low; + + public ref PinLevel RFSH => ref this._rfshLine; + protected virtual void OnRaisingRFSH() => RaisingRFSH?.Invoke(this, EventArgs.Empty); protected virtual void OnRaisedRFSH() => RaisedRFSH?.Invoke(this, EventArgs.Empty); @@ -447,6 +337,38 @@ namespace Z80 protected virtual void OnLoweredRFSH() => LoweredRFSH?.Invoke(this, EventArgs.Empty); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] + public virtual void RaiseRFSH() + { + WithPinChange(() => this.RFSH.Lowered(), this.OnRaisingRFSH, this.OnRaisedRFSH, () => this.RFSH.Raise()); + } + + public virtual void LowerRFSH() + { + WithPinChange(() => this.RFSH.Raised(), this.OnLoweringRFSH, this.OnLoweredRFSH, () => this.RFSH.Lower()); + } + + private byte WithRFSH(Func function) + { + return WithPin(this.LowerRFSH, this.RaiseRFSH, function); + } + + #endregion + + #region MREQ pin + + public event EventHandler? RaisingMREQ; + + public event EventHandler? RaisedMREQ; + + public event EventHandler? LoweringMREQ; + + public event EventHandler? LoweredMREQ; + + private PinLevel _mreqLine = PinLevel.Low; + + public ref PinLevel MREQ => ref this._mreqLine; + protected virtual void OnLoweringMREQ() => LoweringMREQ?.Invoke(this, EventArgs.Empty); protected virtual void OnLoweredMREQ() => LoweredMREQ?.Invoke(this, EventArgs.Empty); @@ -455,6 +377,38 @@ namespace Z80 protected virtual void OnRaisedMREQ() => RaisedMREQ?.Invoke(this, EventArgs.Empty); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] + public virtual void RaiseMREQ() + { + WithPinChange(() => this.MREQ.Lowered(), this.OnRaisingMREQ, this.OnRaisedMREQ, () => this.MREQ.Raise()); + } + + public virtual void LowerMREQ() + { + WithPinChange(() => this.MREQ.Raised(), this.OnLoweringMREQ, this.OnLoweredMREQ, () => this.MREQ.Lower()); + } + + private byte WithMREQ(Func function) + { + return WithPin(this.LowerMREQ, this.RaiseMREQ, function); + } + + #endregion + + #region IORQ pin + + public event EventHandler? RaisingIORQ; + + public event EventHandler? RaisedIORQ; + + public event EventHandler? LoweringIORQ; + + public event EventHandler? LoweredIORQ; + + private PinLevel _iorqLine = PinLevel.Low; + + public ref PinLevel IORQ => ref this._iorqLine; + protected virtual void OnLoweringIORQ() => LoweringIORQ?.Invoke(this, EventArgs.Empty); protected virtual void OnLoweredIORQ() => LoweredIORQ?.Invoke(this, EventArgs.Empty); @@ -463,6 +417,39 @@ namespace Z80 protected virtual void OnRaisedIORQ() => RaisedIORQ?.Invoke(this, EventArgs.Empty); + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] + public virtual void RaiseIORQ() + { + WithPinChange(() => this.IORQ.Lowered(), this.OnRaisingIORQ, this.OnRaisedIORQ, () => this.IORQ.Raise()); + } + + public virtual void LowerIORQ() + { + WithPinChange(() => this.IORQ.Raised(), this.OnLoweringIORQ, this.OnLoweredIORQ, () => this.IORQ.Lower()); + } + + private byte WithIORQ(Func function) + { + return WithPin(this.LowerIORQ, this.RaiseIORQ, function); + } + + #endregion + + #region RD pin + + public event EventHandler? RaisingRD; + + public event EventHandler? RaisedRD; + + public event EventHandler? LoweringRD; + + public event EventHandler? LoweredRD; + + private PinLevel _rdLine = PinLevel.Low; + + public ref PinLevel RD => ref this._rdLine; + protected virtual void OnLoweringRD() => LoweringRD?.Invoke(this, EventArgs.Empty); protected virtual void OnLoweredRD() => LoweredRD?.Invoke(this, EventArgs.Empty); @@ -471,6 +458,38 @@ namespace Z80 protected virtual void OnRaisedRD() => RaisedRD?.Invoke(this, EventArgs.Empty); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] + public virtual void RaiseRD() + { + WithPinChange(() => this.RD.Lowered(), this.OnRaisingRD, this.OnRaisedRD, () => this.RD.Raise()); + } + + public virtual void LowerRD() + { + WithPinChange(() => this.RD.Raised(), this.OnLoweringRD, this.OnLoweredRD, () => this.RD.Lower()); + } + + private byte WithRD(Func function) + { + return WithPin(this.LowerRD, this.RaiseRD, function); + } + + #endregion + + #region WR pin + + public event EventHandler? RaisingWR; + + public event EventHandler? RaisedWR; + + public event EventHandler? LoweringWR; + + public event EventHandler? LoweredWR; + + private PinLevel _wrLine = PinLevel.Low; + + public ref PinLevel WR => ref this._wrLine; + protected virtual void OnLoweringWR() => LoweringWR?.Invoke(this, EventArgs.Empty); protected virtual void OnLoweredWR() => LoweredWR?.Invoke(this, EventArgs.Empty); @@ -479,25 +498,55 @@ namespace Z80 protected virtual void OnRaisedWR() => RaisedWR?.Invoke(this, EventArgs.Empty); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1030:Use events where appropriate", Justification = "The word 'raise' is used in an electrical sense")] + public virtual void RaiseWR() + { + WithPinChange(() => this.WR.Lowered(), this.OnRaisingWR, this.OnRaisedWR, () => this.WR.Raise()); + } + + public virtual void LowerWR() + { + WithPinChange(() => this.WR.Raised(), this.OnLoweringWR, this.OnLoweredWR, () => this.WR.Lower()); + } + + private byte WithWR(Func function) + { + this.LowerWR(); + try + { + return function(); + } + finally + { + this.RaiseWR(); + } + } + + #endregion + protected override void MemoryWrite() { - this.Tick(3); - this.LowerMREQ(); - this.LowerWR(); - base.MemoryWrite(); - this.RaiseWR(); - this.RaiseMREQ(); + _ = this.WithMREQ(() => + { + return this.WithWR(() => + { + this.Tick(3); + base.MemoryWrite(); + return 0; + }); + }); } protected override byte MemoryRead() { - this.Tick(3); - this.LowerMREQ(); - this.LowerRD(); - var returned = base.MemoryRead(); - this.RaiseRD(); - this.RaiseMREQ(); - return returned; + return this.WithMREQ(() => + { + return this.WithRD(() => + { + this.Tick(3); + return base.MemoryRead(); + }); + }); } protected override void HandleRESET() @@ -512,11 +561,15 @@ namespace Z80 protected override void HandleINT() { base.HandleINT(); - this.LowerM1(); - this.LowerIORQ(); - var data = this.Bus.Data; - this.RaiseIORQ(); - this.RaiseM1(); + + var data = this.WithM1(() => + { + return this.WithIORQ(() => + { + return this.Bus.Data; + }); + }); + this.DisableInterrupts(); this.Tick(5); switch (this.IM) @@ -1670,14 +1723,18 @@ namespace Z80 private byte ReadInitialOpCode() { this.Tick(); - this.LowerM1(); - var returned = this.MemoryRead(this.PC); - this.RaiseM1(); + var returned = this.WithM1(() => + { + return this.MemoryRead(this.PC); + }); this.Bus.Address.Assign(this.REFRESH, this.IV); - this.LowerRFSH(); - this.LowerMREQ(); - this.RaiseMREQ(); - this.RaiseRFSH(); + _ = this.WithRFSH(() => + { + return this.WithMREQ(() => + { + return 0; + }); + }); return returned; }