From bc8352f96a207c97c1ca5b1fa10632a554032c8f Mon Sep 17 00:00:00 2001 From: Adrian Conlon <98398945+AdrianConlon@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:18:36 +0100 Subject: [PATCH] Start implementing W65C02 as a derived MOS6502 core. --- M6502/M6502.cs | 37 ++++++++++++++++++ M6502/M6502Core.cs | 50 +++++++----------------- M6502/W65C02.cs | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 35 deletions(-) create mode 100644 M6502/W65C02.cs diff --git a/M6502/M6502.cs b/M6502/M6502.cs index 4151fd3..7d7d486 100644 --- a/M6502/M6502.cs +++ b/M6502/M6502.cs @@ -145,6 +145,43 @@ namespace EightBit #endregion + #region Bus/Memory Access + + protected override void ModifyWrite(byte data) + { + // The read will have already taken place... + this.MemoryWrite(); // Modify cycle + this.MemoryWrite(data); // Write cycle + } + + #endregion + + #region Addressing modes + + protected override void IndirectAddress() + { + this.AbsoluteAddress(); + this.GetAddressPaged(); + } + + #region Address page fixup + + protected override void Fixup() + { + this.MemoryRead(); + this.Bus.Address.High = this.FixedPage; + } + + protected override void FixupBranch(sbyte relative) + { + this.NoteFixedAddress(this.PC.Word + relative); + this.MaybeFixup(); + } + + #endregion + + #endregion + #region Instruction implementations #region Undocumented instructions diff --git a/M6502/M6502Core.cs b/M6502/M6502Core.cs index bdcd1bc..f7adf9d 100644 --- a/M6502/M6502Core.cs +++ b/M6502/M6502Core.cs @@ -1,10 +1,10 @@ -// +// // Copyright (c) Adrian Conlon. All rights reserved. // namespace EightBit { - public class M6502Core(Bus bus) : LittleEndianProcessor(bus) + public abstract class M6502Core(Bus bus) : LittleEndianProcessor(bus) { #region Instruction execution events @@ -215,11 +215,11 @@ namespace EightBit private const byte RSTvector = 0xfc; // RST vector private const byte NMIvector = 0xfa; // NMI vector - enum InterruptSource { hardware, software }; + protected enum InterruptSource { hardware, software }; - enum InterruptType { reset, non_reset }; + protected enum InterruptType { reset, non_reset }; - private void Interrupt(byte vector, InterruptSource source = InterruptSource.hardware, InterruptType type = InterruptType.non_reset) + protected virtual void Interrupt(byte vector, InterruptSource source = InterruptSource.hardware, InterruptType type = InterruptType.non_reset) { if (type == InterruptType.reset) { @@ -615,12 +615,7 @@ namespace EightBit base.BusWrite(); } - protected void ModifyWrite(byte data) - { - // The read will have already taken place... - this.MemoryWrite(); - this.MemoryWrite(data); - } + protected abstract void ModifyWrite(byte data); #endregion @@ -659,19 +654,12 @@ namespace EightBit #region Address page fixup - private byte unfixedPage; private byte fixedPage; - public byte UnfixedPage - { - get => this.unfixedPage; - private set => this.unfixedPage = value; - } - public byte FixedPage { get => this.fixedPage; - private set => this.fixedPage = value; + protected set => this.fixedPage = value; } protected void MaybeFixup() @@ -682,12 +670,7 @@ namespace EightBit } } - protected void Fixup() - { - this.MemoryRead(); - this.UnfixedPage = this.Bus.Address.High; - this.Bus.Address.High = this.FixedPage; - } + protected abstract void Fixup(); protected void MaybeFixupRead() { @@ -705,19 +688,19 @@ namespace EightBit #region Address resolution - private void NoteFixedAddress(int address) + protected void NoteFixedAddress(int address) { this.NoteFixedAddress((ushort)address); } - private void NoteFixedAddress(ushort address) + protected void NoteFixedAddress(ushort address) { this.Intermediate.Word = address; this.FixedPage = this.Intermediate.High; this.Bus.Address.Low = this.Intermediate.Low; } - private void GetAddressPaged() + protected void GetAddressPaged() { this.GetWordPaged(); this.Bus.Address.Assign(this.Intermediate); @@ -742,11 +725,7 @@ namespace EightBit this.GetAddressPaged(); } - protected void IndirectAddress() - { - this.AbsoluteAddress(); - this.GetAddressPaged(); - } + protected abstract void IndirectAddress(); protected void ZeroPageWithIndexAddress(byte index) { @@ -855,12 +834,13 @@ namespace EightBit { var relative = (sbyte)this.Bus.Data; this.SwallowRead(); - this.NoteFixedAddress(this.PC.Word + relative); - this.MaybeFixup(); + this.FixupBranch(relative); this.Jump(this.Bus.Address); } } + protected abstract void FixupBranch(sbyte relative); + #endregion #region Data flag adjustment diff --git a/M6502/W65C02.cs b/M6502/W65C02.cs new file mode 100644 index 0000000..eaeae33 --- /dev/null +++ b/M6502/W65C02.cs @@ -0,0 +1,97 @@ +// +// Copyright (c) Adrian Conlon. All rights reserved. +// + +namespace EightBit +{ + public class W65C02(Bus bus) : M6502Core(bus) + { + #region Interrupts + + protected override void Interrupt(byte vector, InterruptSource source, InterruptType type) + { + base.Interrupt(vector, source, type); + this.ResetFlag(StatusBits.DF); // Disable decimal mode (Change from M6502) + } + + #endregion + + #region Core instruction dispatching + + protected override bool MaybeExecute() + { + if (base.MaybeExecute()) + { + return true; + } + + return false; + } + + #endregion + + #region Bus/Memory Access + + protected override void ModifyWrite(byte data) + { + // The read will have already taken place... + this.MemoryRead(); // Modify cycle (Change from M6502) + this.MemoryWrite(data); // Write cycle + } + + #endregion + + #region Addressing modes + + #region Address page fixup + + private readonly Register16 lastFetchAddress = new(); + + protected override byte FetchByte() + { + this.lastFetchAddress.Assign(this.PC); + return base.FetchByte(); + } + + protected override void Fixup() + { + var fixingLow = this.Bus.Address.Low; + this.MemoryRead(this.lastFetchAddress); + this.Bus.Address.Assign(fixingLow, this.FixedPage); + } + + protected override void FixupBranch(sbyte relative) + { + this.NoteFixedAddress(this.PC.Word + relative); + this.lastFetchAddress.Assign(this.Bus.Address); // Effectively negate the use of "lastFetchAddress" for branch fixup usages + this.MaybeFixup(); + } + + #endregion + + #region Address resolution + + protected void GetAddress() + { + this.GetWordPaged(); + + if (this.Bus.Address.Low == 0) + { + this.Bus.Address.High++; + } + + this.Bus.Address.High = this.MemoryRead(); + this.Bus.Address.Low = this.Intermediate.Low; + } + + protected override void IndirectAddress() + { + this.AbsoluteAddress(); + this.GetAddress(); + } + + #endregion + + #endregion + } +} \ No newline at end of file