From 0f2a69509ba58812bed07dc75005c2d08f9db001 Mon Sep 17 00:00:00 2001 From: Adrian Conlon Date: Thu, 31 Oct 2019 23:01:47 +0000 Subject: [PATCH] Sync (as far as possible) with unmanaged C++ emulators. Signed-off-by: Adrian Conlon --- M6502/M6502.cs | 43 ++++++ MC6809/MC6809.cs | 52 +++++++ Z80/Disassembler.cs | 33 +++++ Z80/Z80.cs | 336 ++++++++++++++++++++++++++++++++------------ 4 files changed, 373 insertions(+), 91 deletions(-) diff --git a/M6502/M6502.cs b/M6502/M6502.cs index 09bea47..5476633 100644 --- a/M6502/M6502.cs +++ b/M6502/M6502.cs @@ -23,6 +23,7 @@ namespace EightBit private PinLevel soLine = PinLevel.Low; private PinLevel syncLine = PinLevel.Low; private PinLevel rdyLine = PinLevel.Low; + private PinLevel rwLine = PinLevel.Low; public M6502(Bus bus) : base(bus) @@ -65,6 +66,14 @@ namespace EightBit public event EventHandler LoweredRDY; + public event EventHandler RaisingRW; + + public event EventHandler RaisedRW; + + public event EventHandler LoweringRW; + + public event EventHandler LoweredRW; + public ref PinLevel NMI => ref this.nmiLine; public ref PinLevel SO => ref this.soLine; @@ -73,6 +82,8 @@ namespace EightBit public ref PinLevel RDY => ref this.rdyLine; + public ref PinLevel RW => ref this.rwLine; + public byte X { get; set; } = 0; public byte Y { get; set; } = 0; @@ -155,6 +166,26 @@ namespace EightBit } } + public virtual void RaiseRW() + { + if (this.RW.Lowered()) + { + this.OnRaisingRW(); + this.RW.Raise(); + this.OnRaisedRW(); + } + } + + public virtual void LowerRW() + { + if (this.RW.Raised()) + { + this.OnLoweringRW(); + this.RW.Lower(); + this.OnLoweredRW(); + } + } + public override int Execute() { this.RaiseSYNC(); // Instruction fetch has now completed @@ -451,6 +482,7 @@ namespace EightBit if (this.RDY.Raised()) { this.LowerSYNC(); // Instruction fetch beginning + this.RaiseRW(); this.OpCode = this.Bus.Read(this.PC.Word++); // can't use fetchByte if (this.RESET.Lowered()) { @@ -509,6 +541,14 @@ namespace EightBit protected virtual void OnLoweredRDY() => this.LoweredRDY?.Invoke(this, EventArgs.Empty); + protected virtual void OnRaisingRW() => this.RaisingRW?.Invoke(this, EventArgs.Empty); + + protected virtual void OnRaisedRW() => this.RaisedRW?.Invoke(this, EventArgs.Empty); + + protected virtual void OnLoweringRW() => this.LoweringRW?.Invoke(this, EventArgs.Empty); + + protected virtual void OnLoweredRW() => this.LoweredRW?.Invoke(this, EventArgs.Empty); + protected override void OnRaisedPOWER() { this.X = (byte)Bits.Bit7; @@ -517,6 +557,7 @@ namespace EightBit this.P = (byte)StatusBits.RF; this.S = (byte)Mask.Mask8; this.LowerSYNC(); + this.LowerRW(); base.OnRaisedPOWER(); } @@ -555,12 +596,14 @@ namespace EightBit protected override sealed void BusWrite() { this.Tick(); + this.LowerRW(); base.BusWrite(); } protected override sealed byte BusRead() { this.Tick(); + this.RaiseRW(); return base.BusRead(); } diff --git a/MC6809/MC6809.cs b/MC6809/MC6809.cs index 4463ad2..50f30a0 100644 --- a/MC6809/MC6809.cs +++ b/MC6809/MC6809.cs @@ -36,6 +36,7 @@ private PinLevel haltLine = PinLevel.Low; private PinLevel baLine = PinLevel.Low; private PinLevel bsLine = PinLevel.Low; + private PinLevel rwLine = PinLevel.Low; private bool prefix10 = false; private bool prefix11 = false; @@ -89,6 +90,14 @@ public event EventHandler LoweredBS; + public event EventHandler RaisingRW; + + public event EventHandler RaisedRW; + + public event EventHandler LoweringRW; + + public event EventHandler LoweredRW; + public Register16 D { get; } = new Register16(); public ref byte A => ref this.D.High; @@ -147,6 +156,8 @@ public ref PinLevel BS => ref this.bsLine; + public ref PinLevel RW => ref this.rwLine; + public void Halt() { --this.PC.Word; @@ -321,10 +332,31 @@ } } + public void RaiseRW() + { + if (this.RW.Lowered()) + { + this.OnRaisingRW(); + this.RW.Raise(); + this.OnRaisedRW(); + } + } + + public void LowerRW() + { + if (this.RW.Raised()) + { + this.OnLoweringRW(); + this.RW.Lower(); + this.OnLoweredRW(); + } + } + protected override void OnRaisedPOWER() { this.LowerBA(); this.LowerBS(); + this.LowerRW(); base.OnRaisedPOWER(); } @@ -356,6 +388,18 @@ protected override void Push(byte value) => this.PushS(value); + protected override void BusWrite() + { + this.LowerRW(); + base.BusWrite(); + } + + protected override byte BusRead() + { + this.RaiseRW(); + return base.BusRead(); + } + private void HandleHALT() { this.RaiseBA(); @@ -426,6 +470,14 @@ private void OnLoweredBS() => this.LoweredBS?.Invoke(this, EventArgs.Empty); + private void OnRaisingRW() => this.RaisingRW?.Invoke(this, EventArgs.Empty); + + private void OnRaisedRW() => this.RaisedRW?.Invoke(this, EventArgs.Empty); + + private void OnLoweringRW() => this.LoweringRW?.Invoke(this, EventArgs.Empty); + + private void OnLoweredRW() => this.LoweredRW?.Invoke(this, EventArgs.Empty); + private void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty); private void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty); diff --git a/Z80/Disassembler.cs b/Z80/Disassembler.cs index ffd1843..f504289 100644 --- a/Z80/Disassembler.cs +++ b/Z80/Disassembler.cs @@ -266,6 +266,39 @@ namespace EightBit dumpCount += 2; break; + case 4: // Negate accumulator + specification = "NEG"; + break; + case 5: // Return from interrupt + switch (y) + { + case 1: + specification = "RETI"; + break; + default: + specification = "RETN"; + break; + } + break; + case 6: // Set interrupt mode + switch (y) + { + case 0: + case 1: + case 4: + case 5: + specification = "IM 0"; + break; + case 2: + case 6: + specification = "IM 1"; + break; + case 3: + case 7: + specification = "IM 2"; + break; + } + break; case 7: switch (y) { diff --git a/Z80/Z80.cs b/Z80/Z80.cs index 9ad960d..8491854 100644 --- a/Z80/Z80.cs +++ b/Z80/Z80.cs @@ -31,6 +31,9 @@ namespace EightBit private PinLevel nmiLine = PinLevel.Low; private PinLevel m1Line = PinLevel.Low; + private PinLevel iorqLine = PinLevel.Low; + private PinLevel rdLine = PinLevel.Low; + private PinLevel wrLine = PinLevel.Low; private int accumulatorFlagsSet = 0; @@ -61,6 +64,30 @@ namespace EightBit public event EventHandler LoweredM1; + 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; } = 0; @@ -95,6 +122,12 @@ namespace EightBit public ref PinLevel M1 => ref this.m1Line; + public ref PinLevel IORQ => ref this.iorqLine; + + public ref PinLevel RD => ref this.rdLine; + + public ref PinLevel WR => ref this.wrLine; + private ushort DisplacedAddress { get @@ -148,13 +181,69 @@ namespace EightBit } } + 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(); + } + } + + 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(); + } + } + + 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 int Execute() { - if (!(this.prefixCB && this.displaced)) - { - ++this.REFRESH; - this.RaiseM1(); - } + this.RaiseM1(); var decoded = this.GetDecodedOpCode(this.OpCode); @@ -165,17 +254,13 @@ namespace EightBit var p = decoded.P; var q = decoded.Q; - var prefixed = this.prefixCB || this.prefixED; - if (prefixed) + if (this.prefixCB) { - if (this.prefixCB) - { - this.ExecuteCB(x, y, z); - } - else if (this.prefixED) - { - this.ExecuteED(x, y, z, p, q); - } + this.ExecuteCB(x, y, z); + } + else if (this.prefixED) + { + this.ExecuteED(x, y, z, p, q); } else { @@ -192,7 +277,6 @@ namespace EightBit if (this.Powered) { this.displaced = this.prefixCB = this.prefixDD = this.prefixED = false; - this.LowerM1(); var handled = false; if (this.RESET.Lowered()) { @@ -219,6 +303,7 @@ namespace EightBit if (!handled) { + this.LowerM1(); this.Execute(this.FetchByte()); } } @@ -230,6 +315,9 @@ namespace EightBit protected override void OnRaisedPOWER() { this.RaiseM1(); + this.RaiseIORQ(); + this.RaiseRD(); + this.RaiseWR(); this.DisableInterrupts(); this.IM = 0; @@ -265,7 +353,50 @@ namespace EightBit protected virtual void OnLoweringM1() => this.LoweringM1?.Invoke(this, EventArgs.Empty); - protected virtual void OnLoweredM1() => this.LoweredM1?.Invoke(this, EventArgs.Empty); + protected virtual void OnLoweredM1() + { + ++this.REFRESH; + this.LoweredM1?.Invoke(this, EventArgs.Empty); + } + + protected virtual void OnLoweringIORQ() => this.LoweringIORQ?.Invoke(this, EventArgs.Empty); + + protected virtual void OnLoweredIORQ() => this.LoweredIORQ?.Invoke(this, EventArgs.Empty); + + protected virtual void OnRaisingIORQ() => this.RaisingIORQ?.Invoke(this, EventArgs.Empty); + + protected virtual void OnRaisedIORQ() => this.RaisedIORQ?.Invoke(this, EventArgs.Empty); + + protected virtual void OnLoweringRD() => this.LoweringRD?.Invoke(this, EventArgs.Empty); + + protected virtual void OnLoweredRD() => this.LoweredRD?.Invoke(this, EventArgs.Empty); + + protected virtual void OnRaisingRD() => this.RaisingRD?.Invoke(this, EventArgs.Empty); + + protected virtual void OnRaisedRD() => this.RaisedRD?.Invoke(this, EventArgs.Empty); + + protected virtual void OnLoweringWR() => this.LoweringWR?.Invoke(this, EventArgs.Empty); + + protected virtual void OnLoweredWR() => this.LoweredWR?.Invoke(this, EventArgs.Empty); + + protected virtual void OnRaisingWR() => this.RaisingWR?.Invoke(this, EventArgs.Empty); + + protected virtual void OnRaisedWR() => this.RaisedWR?.Invoke(this, EventArgs.Empty); + + protected override void BusWrite() + { + this.LowerWR(); + base.BusWrite(); + this.RaiseWR(); + } + + protected override byte BusRead() + { + this.LowerRD(); + var returned = base.BusRead(); + this.RaiseRD(); + return returned; + } protected override void HandleRESET() { @@ -277,18 +408,23 @@ namespace EightBit protected override void HandleINT() { base.HandleINT(); + this.LowerM1(); + this.LowerIORQ(); + var data = this.Bus.Data; + this.RaiseIORQ(); + this.RaiseM1(); this.DisableInterrupts(); switch (this.IM) { case 0: // i8080 equivalent - this.Execute(this.Bus.Data); + this.Execute(data); break; case 1: this.Restart(7 << 3); this.Tick(13); break; case 2: - this.Call(this.MEMPTR.Word = new Register16(this.Bus.Data, this.IV).Word); + this.Call(this.MEMPTR.Word = new Register16(data, this.IV).Word); this.Tick(19); break; default: @@ -639,10 +775,10 @@ namespace EightBit switch (q) { case 0: // SBC HL, rp[p] - this.SBC(this.RP(p)); + this.HL2().Word = this.SBC(this.HL2(), this.RP(p)); break; case 1: // ADC HL, rp[p] - this.ADC(this.RP(p)); + this.HL2().Word = this.ADC(this.HL2(), this.RP(p)); break; default: throw new NotSupportedException("Invalid operation mode"); @@ -894,6 +1030,11 @@ namespace EightBit switch (y) { case 0: // NOP + if (this.prefixDD) + { + this.Tick(4); + } + this.Tick(4); break; case 1: // EX AF AF' @@ -936,7 +1077,7 @@ namespace EightBit this.Tick(10); break; case 1: // ADD HL,rp - this.Add(this.RP(p)); + this.HL2().Word = this.Add(this.HL2(), this.RP(p)); this.Tick(11); break; default: @@ -1180,16 +1321,16 @@ namespace EightBit switch (y) { case 0: // ADD A,r - this.Add(value); + this.A = this.Add(this.A, value); break; case 1: // ADC A,r - this.ADC(value); + this.A = this.ADC(this.A, value); break; case 2: // SUB r - this.SUB(value); + this.A = this.SUB(this.A, value); break; case 3: // SBC A,r - this.SBC(value); + this.A = this.SBC(this.A, value); break; case 4: // AND r this.AndR(value); @@ -1275,8 +1416,11 @@ namespace EightBit { this.FetchDisplacement(); } + else + { + this.LowerM1(); + } - this.LowerM1(); this.Execute(this.FetchByte()); break; case 2: // OUT (n),A @@ -1361,16 +1505,16 @@ namespace EightBit switch (y) { case 0: // ADD A,n - this.Add(operand); + this.A = this.Add(this.A, operand); break; case 1: // ADC A,n - this.ADC(operand); + this.A = this.ADC(this.A, operand); break; case 2: // SUB n - this.SUB(operand); + this.A = this.SUB(this.A, operand); break; case 3: // SBC A,n - this.SBC(operand); + this.A = this.SBC(this.A, operand); break; case 4: // AND n this.AndR(operand); @@ -1409,6 +1553,9 @@ namespace EightBit this.RaiseNMI(); this.RaiseHALT(); this.IFF1 = false; + this.LowerM1(); + var discarded = this.Bus.Data; + this.RaiseM1(); this.Restart(0x66); this.Tick(13); } @@ -1550,92 +1697,84 @@ namespace EightBit } } - private void SBC(Register16 value) + private ushort SBC(Register16 operand, Register16 value) { - var hl2 = this.HL2(); - this.MEMPTR.Word = hl2.Word; + var subtraction = operand.Word - value.Word - (this.F & (byte)StatusBits.CF); + this.intermediate.Word = (ushort)subtraction; - var beforeNegative = this.MEMPTR.High & (byte)StatusBits.SF; - var valueNegative = value.High & (byte)StatusBits.SF; - - var result = this.MEMPTR.Word - value.Word - (this.F & (byte)StatusBits.CF); - hl2.Word = (ushort)result; - - var afterNegative = hl2.High & (byte)StatusBits.SF; - - this.F = SetBit(this.F, StatusBits.SF, afterNegative); - this.F = ClearBit(this.F, StatusBits.ZF, hl2.Word); - this.F = AdjustHalfCarrySub(this.F, this.MEMPTR.High, value.High, hl2.High); - this.F = AdjustOverflowSub(this.F, beforeNegative, valueNegative, afterNegative); this.F = SetBit(this.F, StatusBits.NF); - this.F = SetBit(this.F, StatusBits.CF, result & (int)Bits.Bit16); - this.F = AdjustXY(this.F, hl2.High); + this.F = ClearBit(this.F, StatusBits.ZF, this.intermediate.Word); + this.F = SetBit(this.F, StatusBits.CF, subtraction & (int)Bits.Bit16); + this.F = AdjustHalfCarrySub(this.F, operand.High, value.High, this.intermediate.High); + this.F = AdjustXY(this.F, this.intermediate.High); - ++this.MEMPTR.Word; - } - - private void ADC(Register16 value) - { - var hl2 = this.HL2(); - this.MEMPTR.Word = hl2.Word; - - var beforeNegative = this.MEMPTR.High & (byte)StatusBits.SF; + var beforeNegative = operand.High & (byte)StatusBits.SF; var valueNegative = value.High & (byte)StatusBits.SF; - - var result = this.MEMPTR.Word + value.Word + (this.F & (byte)StatusBits.CF); - hl2.Word = (ushort)result; - - var afterNegative = hl2.High & (byte)StatusBits.SF; + var afterNegative = this.intermediate.High & (byte)StatusBits.SF; + + this.F = SetBit(this.F, StatusBits.SF, afterNegative); + this.F = AdjustOverflowSub(this.F, beforeNegative, valueNegative, afterNegative); + + this.MEMPTR.Word = (ushort)(operand.Word + 1); + + return this.intermediate.Word; + } + + private ushort ADC(Register16 operand ,Register16 value) + { + this.Add(operand, value, this.F & (byte)StatusBits.CF); // Leaves result in intermediate anyway + this.F = ClearBit(this.F, StatusBits.ZF, this.intermediate.Word); + + var beforeNegative = operand.High & (byte)StatusBits.SF; + var valueNegative = value.High & (byte)StatusBits.SF; + var afterNegative = this.intermediate.High & (byte)StatusBits.SF; this.F = SetBit(this.F, StatusBits.SF, afterNegative); - this.F = ClearBit(this.F, StatusBits.ZF, hl2.Word); - this.F = AdjustHalfCarryAdd(this.F, this.MEMPTR.High, value.High, hl2.High); this.F = AdjustOverflowAdd(this.F, beforeNegative, valueNegative, afterNegative); - this.F = ClearBit(this.F, StatusBits.NF); - this.F = SetBit(this.F, StatusBits.CF, result & (int)Bits.Bit16); - this.F = AdjustXY(this.F, hl2.High); - ++this.MEMPTR.Word; + return this.intermediate.Word; } - private void Add(Register16 value) + private ushort Add(Register16 operand, Register16 value, int carry = 0) { - var hl2 = this.HL2(); - this.MEMPTR.Word = hl2.Word; - - var result = this.MEMPTR.Word + value.Word; - - hl2.Word = (ushort)result; + var addition = operand.Word + value.Word + carry; + this.intermediate.Word = (ushort)addition; this.F = ClearBit(this.F, StatusBits.NF); - this.F = SetBit(this.F, StatusBits.CF, result & (int)Bits.Bit16); - this.F = AdjustHalfCarryAdd(this.F, this.MEMPTR.High, value.High, hl2.High); - this.F = AdjustXY(this.F, hl2.High); + this.F = SetBit(this.F, StatusBits.CF, addition & (int)Bits.Bit16); + this.F = AdjustHalfCarryAdd(this.F, operand.High, value.High, this.intermediate.High); + this.F = AdjustXY(this.F, this.intermediate.High); - ++this.MEMPTR.Word; + this.MEMPTR.Word = (ushort)(operand.Word + 1); + + return this.intermediate.Word; } - private void Add(byte value, int carry = 0) + private byte Add(byte operand, byte value, int carry = 0) { - this.intermediate.Word = (ushort)(this.A + value + carry); + this.intermediate.Word = (ushort)(operand + value + carry); + var result = this.intermediate.Low; - this.F = AdjustHalfCarryAdd(this.F, this.A, value, this.intermediate.Low); - this.F = AdjustOverflowAdd(this.F, this.A, value, this.intermediate.Low); + this.F = AdjustHalfCarryAdd(this.F, operand, value, result); + this.F = AdjustOverflowAdd(this.F, operand, value, result); this.F = ClearBit(this.F, StatusBits.NF); this.F = SetBit(this.F, StatusBits.CF, this.intermediate.High & (byte)StatusBits.CF); - this.F = AdjustSZXY(this.F, this.A = this.intermediate.Low); + this.F = AdjustSZXY(this.F, result); + + return result; } - private void ADC(byte value) => this.Add(value, this.F & (byte)StatusBits.CF); + private byte ADC(byte operand, byte value) => this.Add(operand, value, this.F & (byte)StatusBits.CF); - private void SUB(byte value, int carry = 0) + private byte SUB(byte operand, byte value, int carry = 0) { - this.A = this.Subtract(this.A, value, carry); - this.F = AdjustXY(this.F, this.A); + var subtraction = this.Subtract(operand, value, carry); + this.F = AdjustXY(this.F, subtraction); + return subtraction; } - private void SBC(byte value) => this.SUB(value, this.F & (byte)StatusBits.CF); + private byte SBC(byte operand, byte value) => this.SUB(operand, value, this.F & (byte)StatusBits.CF); private void AndR(byte value) { @@ -2002,7 +2141,14 @@ namespace EightBit ++this.MEMPTR.Low; } - private void WritePort() => this.ports.Write(this.Bus.Address.Low, this.Bus.Data); + private void WritePort() + { + this.LowerIORQ(); + this.LowerWR(); + this.ports.Write(this.Bus.Address.Low, this.Bus.Data); + this.RaiseWR(); + this.RaiseIORQ(); + } private byte ReadPort(byte port) { @@ -2011,6 +2157,14 @@ namespace EightBit return this.ReadPort(); } - private byte ReadPort() => this.Bus.Data = this.ports.Read(this.Bus.Address.Low); + private byte ReadPort() + { + this.LowerIORQ(); + this.LowerRD(); + var returned = this.Bus.Data = this.ports.Read(this.Bus.Address.Low); + this.RaiseRD(); + this.RaiseIORQ(); + return returned; + } } }