diff --git a/EightBit.sln b/EightBit.sln index 6a5a730..132f285 100644 --- a/EightBit.sln +++ b/EightBit.sln @@ -19,10 +19,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Intel8080", "Intel8080\Inte EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Intel8080.Test", "Intel8080\Intel8080.Test\Intel8080.Test.csproj", "{B09091A2-43A6-4729-9EE2-047895ECAF30}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MC6809", "MC6809\MC6809.csproj", "{3A63972B-AB50-4A01-8A10-0D2165580FAD}" +EndProject Global - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 @@ -128,6 +127,18 @@ Global {B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|x64.Build.0 = Release|Any CPU {B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|x86.ActiveCfg = Release|Any CPU {B09091A2-43A6-4729-9EE2-047895ECAF30}.Release|x86.Build.0 = Release|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Debug|x64.ActiveCfg = Debug|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Debug|x64.Build.0 = Debug|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Debug|x86.ActiveCfg = Debug|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Debug|x86.Build.0 = Debug|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Release|Any CPU.Build.0 = Release|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Release|x64.ActiveCfg = Release|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Release|x64.Build.0 = Release|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Release|x86.ActiveCfg = Release|Any CPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -135,4 +146,7 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E120AD0F-5939-4F8B-B454-7920E565FA7E} EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/EightBit/Processor.cs b/EightBit/Processor.cs index a9fa486..4bbd5ff 100644 --- a/EightBit/Processor.cs +++ b/EightBit/Processor.cs @@ -35,6 +35,15 @@ namespace EightBit protected byte OpCode { get; set; } + // http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend + public static sbyte SignExtend(int b, byte x) + { + var m = (byte)(1 << (b - 1)); // mask can be pre-computed if b is fixed + x = (byte)(x & ((1 << b) - 1)); // (Skip this if bits in x above position b are already zero.) + var result = (x ^ m) - m; + return (sbyte)result; + } + public ref PinLevel RESET() => ref this.resetLine; public ref PinLevel INT() => ref this.intLine; @@ -178,12 +187,16 @@ namespace EightBit return this.GetWord(); } + protected Register16 GetWord(Register16 address) => this.GetWord(address.Word); + protected void SetWord(ushort address, Register16 value) { this.Bus.Address.Word = address; this.SetWord(value); } + protected void SetWord(Register16 address, Register16 value) => this.SetWord(address.Word, value); + protected void Jump(ushort destination) => this.PC.Word = destination; protected void Call(ushort destination) diff --git a/EightBit/Register16.cs b/EightBit/Register16.cs index a5e26b4..358596d 100644 --- a/EightBit/Register16.cs +++ b/EightBit/Register16.cs @@ -5,11 +5,13 @@ namespace EightBit { using System.Diagnostics; - using System.Runtime.InteropServices; [DebuggerDisplay("Word = {Word}")] public class Register16 { + private byte low; + private byte high; + public Register16(byte low, byte high) { this.Low = low; @@ -32,6 +34,11 @@ namespace EightBit { } + public Register16(uint value) + : this((ushort)value) + { + } + public Register16(byte low) : this(low, 0) { @@ -54,9 +61,9 @@ namespace EightBit } } - public byte Low { get; set; } + public ref byte Low => ref this.low; - public byte High { get; set; } + public ref byte High => ref this.high; public static Register16 operator ++(Register16 value) => Increment(value); diff --git a/MC6809/MC6809.cs b/MC6809/MC6809.cs new file mode 100644 index 0000000..94e5203 --- /dev/null +++ b/MC6809/MC6809.cs @@ -0,0 +1,1583 @@ +namespace EightBit +{ + using System; + + // Uses some information from: + // http://www.cpu-world.com/Arch/6809.html + + // |---------------|-----------------------------------| + // | MPU State | | + // |_______________| MPU State Definition | + // | BA | BS | | + // |_______|_______|___________________________________| + // | 0 | 0 | Normal (running) | + // | 0 | 1 | Interrupt or RESET Acknowledge | + // | 1 | 0 | SYNC Acknowledge | + // | 1 | 1 | HALT Acknowledge | + // |-------|-------|-----------------------------------| + + public sealed class MC6809 : BigEndianProcessor + { + private const byte RESETvector = 0xfe; // RESET vector + private const byte NMIvector = 0xfc; // NMI vector + private const byte SWIvector = 0xfa; // SWI vector + private const byte IRQvector = 0xf8; // IRQ vector + private const byte FIRQvector = 0xf6; // FIRQ vector + private const byte SWI2vector = 0xf4; // SWI2 vector + private const byte SWI3vector = 0xf2; // SWI3 vector + private const byte RESERVEDvector = 0xf0; // RESERVED vector + + private readonly Register16 d = new Register16(); + private readonly Register16 x = new Register16(); + private readonly Register16 y = new Register16(); + private readonly Register16 u = new Register16(); + private readonly Register16 s = new Register16(); + + private byte cc = 0; + private byte dp = 0; + + private PinLevel nmiLine = PinLevel.Low; + private PinLevel firqLine = PinLevel.Low; + private PinLevel haltLine = PinLevel.Low; + private PinLevel baLine = PinLevel.Low; + private PinLevel bsLine = PinLevel.Low; + + private bool prefix10 = false; + private bool prefix11 = false; + + public MC6809(Bus bus) + : base(bus) + { + } + + public event EventHandler ExecutingInstruction; + + public event EventHandler ExecutedInstruction; + + public event EventHandler RaisingNMI; + + public event EventHandler RaisedNMI; + + public event EventHandler LoweringNMI; + + public event EventHandler LoweredNMI; + + public event EventHandler RaisingFIRQ; + + public event EventHandler RaisedFIRQ; + + public event EventHandler LoweringFIRQ; + + public event EventHandler LoweredFIRQ; + + public event EventHandler RaisingHALT; + + public event EventHandler RaisedHALT; + + public event EventHandler LoweringHALT; + + public event EventHandler LoweredHALT; + + public event EventHandler RaisingBA; + + public event EventHandler RaisedBA; + + public event EventHandler LoweringBA; + + public event EventHandler LoweredBA; + + public event EventHandler RaisingBS; + + public event EventHandler RaisedBS; + + public event EventHandler LoweringBS; + + public event EventHandler LoweredBS; + + public Register16 D => this.d; + + public ref byte A => ref this.D.High; + + public ref byte B => ref this.D.Low; + + public Register16 X => this.x; + + public Register16 Y => this.y; + + public Register16 U => this.u; + + public Register16 S => this.s; + + public ref byte DP => ref this.dp; + + public ref byte CC => ref this.cc; + + public bool Halted => this.HALT().Lowered(); + + private int EntireRegisterSet => this.CC & (byte)StatusBits.EF; + + private int FastInterruptMasked => this.CC & (byte)StatusBits.FF; + + private int HalfCarry => this.CC & (byte)StatusBits.HF; + + private int InterruptMasked => this.CC & (byte)StatusBits.IF; + + private int Negative => this.CC & (byte)StatusBits.NF; + + private int Zero => this.CC & (byte)StatusBits.ZF; + + private int Overflow => this.CC & (byte)StatusBits.VF; + + private int Carry => this.CC & (byte)StatusBits.CF; + + private bool LS => (this.Carry != 0) || (this.Zero != 0); // (C OR Z) + + private bool HI => !this.LS; // !(C OR Z) + + private bool LT => ((this.Negative >> 3) ^ (this.Overflow >> 3)) != 0; // (N XOR V) + + private bool GE => !this.LT; // !(N XOR V) + + private bool LE => (this.Zero != 0) || this.LT; // (Z OR (N XOR V)) + + private bool GT => !this.LE; // !(Z OR (N XOR V)) + + public ref PinLevel NMI() => ref this.nmiLine; + + public ref PinLevel FIRQ() => ref this.firqLine; + + public ref PinLevel HALT() => ref this.haltLine; + + public ref PinLevel BA() => ref this.baLine; + + public ref PinLevel BS() => ref this.bsLine; + + public void Halt() + { + --this.PC.Word; + this.LowerHALT(); + } + + public void Proceed() + { + ++this.PC.Word; + this.RaiseHALT(); + } + + public override int Step() + { + this.ResetCycles(); + this.OnExecutingInstruction(); + if (this.Powered) + { + this.prefix10 = this.prefix11 = false; + if (this.Halted) + { + this.HandleHALT(); + } + else if (this.RESET().Lowered()) + { + this.HandleRESET(); + } + else if (this.NMI().Lowered()) + { + this.HandleNMI(); + } + else if (this.FIRQ().Lowered() && (this.FastInterruptMasked == 0)) + { + this.HandleFIRQ(); + } + else if (this.INT().Lowered() && (this.InterruptMasked == 0)) + { + this.HandleINT(); + } + else + { + this.Execute(this.FetchByte()); + } + } + + this.OnExecutedInstruction(); + return this.Cycles; + } + + public override int Execute() + { + this.LowerBA(); + this.LowerBS(); + var prefixed = this.prefix10 || this.prefix11; + var unprefixed = !prefixed; + if (unprefixed) + { + this.ExecuteUnprefixed(); + } + else + { + if (this.prefix10) + { + this.Execute10(); + } + else + { + this.Execute11(); + } + } + + return this.Cycles; + } + + public override void RaisePOWER() + { + base.RaisePOWER(); + this.LowerBA(); + this.LowerBS(); + } + + public void RaiseNMI() + { + this.OnRaisingNMI(); + this.NMI().Raise(); + this.OnRaisedNMI(); + } + + public void LowerNMI() + { + this.OnLoweringNMI(); + this.NMI().Lower(); + this.OnLoweredNMI(); + } + + public void RaiseFIRQ() + { + this.OnRaisingFIRQ(); + this.FIRQ().Raise(); + this.OnRaisedFIRQ(); + } + + public void LowerFIRQ() + { + this.OnLoweringFIRQ(); + this.FIRQ().Lower(); + this.OnLoweredFIRQ(); + } + + public void RaiseHALT() + { + this.OnRaisingHALT(); + this.HALT().Raise(); + this.OnRaisedHALT(); + } + + public void LowerHALT() + { + this.OnLoweringHALT(); + this.HALT().Lower(); + this.OnLoweredHALT(); + } + + public void RaiseBA() + { + this.OnRaisingBA(); + this.BA().Raise(); + this.OnRaisedBA(); + } + + public void LowerBA() + { + this.OnLoweringBA(); + this.BA().Lower(); + this.OnLoweredBA(); + } + + public void RaiseBS() + { + this.OnRaisingBS(); + this.BS().Raise(); + this.OnRaisedBS(); + } + + public void LowerBS() + { + this.OnLoweringBS(); + this.BS().Lower(); + this.OnLoweredBS(); + } + + protected override void HandleRESET() + { + base.HandleRESET(); + this.RaiseNMI(); + this.LowerBA(); + this.RaiseBS(); + this.DP = 0; + SetFlag(this.CC, StatusBits.IF); // Disable IRQ + SetFlag(this.CC, StatusBits.FF); // Disable FIRQ + this.Jump(this.GetWordPaged(0xff, RESETvector)); + this.Tick(10); + } + + protected override void HandleINT() + { + base.HandleINT(); + this.LowerBA(); + this.RaiseBS(); + this.SaveEntireRegisterState(); + SetFlag(this.CC, StatusBits.IF); // Disable IRQ + this.Jump(this.GetWordPaged(0xff, IRQvector)); + this.Tick(12); + } + + protected override byte Pop() => this.PopS(); + + protected override void Push(byte value) => this.PushS(value); + + + private void HandleHALT() + { + this.RaiseBA(); + this.RaiseBS(); + } + + private void HandleNMI() + { + this.RaiseNMI(); + this.LowerBA(); + this.RaiseBS(); + this.SaveEntireRegisterState(); + SetFlag(this.CC, StatusBits.IF); // Disable IRQ + SetFlag(this.CC, StatusBits.FF); // Disable FIRQ + this.Jump(this.GetWordPaged(0xff, NMIvector)); + this.Tick(12); + } + + private void HandleFIRQ() + { + this.RaiseFIRQ(); + this.LowerBA(); + this.RaiseBS(); + this.SavePartialRegisterState(); + SetFlag(this.CC, StatusBits.IF); // Disable IRQ + SetFlag(this.CC, StatusBits.FF); // Disable FIRQ + this.Jump(this.GetWordPaged(0xff, FIRQvector)); + this.Tick(12); + } + + private void OnRaisingNMI() => this.RaisingNMI?.Invoke(this, EventArgs.Empty); + + private void OnRaisedNMI() => this.RaisedNMI?.Invoke(this, EventArgs.Empty); + + private void OnLoweringNMI() => this.LoweringNMI?.Invoke(this, EventArgs.Empty); + + private void OnLoweredNMI() => this.LoweredNMI?.Invoke(this, EventArgs.Empty); + + private void OnRaisingFIRQ() => this.RaisingFIRQ?.Invoke(this, EventArgs.Empty); + + private void OnRaisedFIRQ() => this.RaisedFIRQ?.Invoke(this, EventArgs.Empty); + + private void OnLoweringFIRQ() => this.LoweringFIRQ?.Invoke(this, EventArgs.Empty); + + private void OnLoweredFIRQ() => this.LoweredFIRQ?.Invoke(this, EventArgs.Empty); + + private void OnRaisingHALT() => this.RaisingHALT?.Invoke(this, EventArgs.Empty); + + private void OnRaisedHALT() => this.RaisedHALT?.Invoke(this, EventArgs.Empty); + + private void OnLoweringHALT() => this.LoweringHALT?.Invoke(this, EventArgs.Empty); + + private void OnLoweredHALT() => this.LoweredHALT?.Invoke(this, EventArgs.Empty); + + private void OnRaisingBA() => this.RaisingBA?.Invoke(this, EventArgs.Empty); + + private void OnRaisedBA() => this.RaisedBA?.Invoke(this, EventArgs.Empty); + + private void OnLoweringBA() => this.LoweringBA?.Invoke(this, EventArgs.Empty); + + private void OnLoweredBA() => this.LoweredBA?.Invoke(this, EventArgs.Empty); + + private void OnRaisingBS() => this.RaisingBS?.Invoke(this, EventArgs.Empty); + + private void OnRaisedBS() => this.RaisedBS?.Invoke(this, EventArgs.Empty); + + private void OnLoweringBS() => this.LoweringBS?.Invoke(this, EventArgs.Empty); + + private void OnLoweredBS() => this.LoweredBS?.Invoke(this, EventArgs.Empty); + + private void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty); + + private void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty); + + private static byte SetFlag(byte f, StatusBits flag) => SetFlag(f, (byte)flag); + + private static byte SetFlag(byte f, StatusBits flag, int condition) => SetFlag(f, (byte)flag, condition); + + private static byte SetFlag(byte f, StatusBits flag, bool condition) => SetFlag(f, (byte)flag, condition); + + private static byte ClearFlag(byte f, StatusBits flag) => ClearFlag(f, (byte)flag); + + private static byte ClearFlag(byte f, StatusBits flag, int condition) => ClearFlag(f, (byte)flag, condition); + + private void Push(Register16 stack, byte value) => this.BusWrite(--stack, value); + + private void PushS(byte value) => this.Push(this.S, value); + + private void PushU(byte value) => this.Push(this.U, value); + + private void PushWord(Register16 stack, Register16 value) + { + this.Push(stack, value.Low); + this.Push(stack, value.High); + } + + private void PushWordS(Register16 value) => this.PushWord(this.S, value); + + private void PushWordU(Register16 value) => this.PushWord(this.U, value); + + private byte Pop(Register16 stack) => this.BusRead(stack++); + + private byte PopS() => this.Pop(this.S); + + private byte PopU() => this.Pop(this.U); + + private Register16 PopWord(Register16 stack) + { + var high = this.Pop(stack); + var low = this.Pop(stack); + return new Register16(low, high); + } + + private Register16 PopWordS() => this.PopWord(this.S); + + private Register16 PopWordU() => this.PopWord(this.U); + + private Register16 RR(int which) + { + switch (which) { + case 0b00: + return this.X; + case 0b01: + return this.Y; + case 0b10: + return this.U; + case 0b11: + return this.S; + default: + throw new ArgumentOutOfRangeException("which", which, "Which does not specify a valid register"); + } + } + + private Register16 Address_relative_byte() => new Register16(this.PC.Word + (sbyte)this.FetchByte()); + + private Register16 Address_relative_word() => new Register16(this.PC.Word + (short)this.FetchWord().Word); + + private Register16 Address_direct() => new Register16(this.FetchByte(), this.DP); + + private Register16 Address_extended() => this.FetchWord(); + + private Register16 Address_indexed() + { + var type = this.FetchByte(); + var r = this.RR((type & (byte)(Bits.Bit6 | Bits.Bit5)) >> 5); + + var address = new Register16(); + if ((type & (byte)Bits.Bit7) != 0) + { + switch (type & (byte)Mask.Mask4) + { + case 0b0000: // ,R+ + this.Tick(2); + address.Word = r++.Word; + break; + case 0b0001: // ,R++ + this.Tick(3); + address.Word = r.Word; + r.Word += 2; + break; + case 0b0010: // ,-R + this.Tick(2); + address.Word = --r.Word; + break; + case 0b0011: // ,--R + this.Tick(3); + r.Word -= 2; + address.Word = r.Word; + break; + case 0b0100: // ,R + address.Word = r.Word; + break; + case 0b0101: // B,R + this.Tick(); + address.Word = (ushort)(r.Word + (sbyte)this.B); + break; + case 0b0110: // A,R + this.Tick(); + address.Word = (ushort)(r.Word + (sbyte)this.A); + break; + case 0b1000: // n,R (eight-bit) + this.Tick(); + address.Word = (ushort)(r.Word + (sbyte)this.FetchByte()); + break; + case 0b1001: // n,R (sixteen-bit) + this.Tick(4); + address.Word = (ushort)(r.Word + (short)this.FetchWord().Word); + break; + case 0b1011: // D,R + this.Tick(4); + address.Word = (ushort)(r.Word + this.D.Word); + break; + case 0b1100: // n,PCR (eight-bit) + this.Tick(); + address.Word = this.Address_relative_byte().Word; + break; + case 0b1101: // n,PCR (sixteen-bit) + this.Tick(2); + address.Word = this.Address_relative_word().Word; + break; + case 0b1111: // [n] + this.Tick(2); + address.Word = this.Address_extended().Word; + break; + default: + throw new InvalidOperationException("Invalid index type"); + } + + var indirect = type & (byte)Bits.Bit4; + if (indirect != 0) + { + this.Tick(3); + address.Word = this.GetWord(address).Word; + } + } + else + { + // EA = ,R + 5-bit offset + this.Tick(); + address = new Register16(r.Word + SignExtend(5, (byte)(type & (byte)Mask.Mask5))); + } + return address; + } + + private byte AM_immediate_byte() => this.FetchByte(); + + private byte AM_direct_byte() => this.BusRead(this.Address_direct()); + + private byte AM_indexed_byte() => this.BusRead(this.Address_indexed()); + + private byte AM_extended_byte() => this.BusRead(this.Address_extended()); + + private Register16 AM_immediate_word() => this.FetchWord(); + + private Register16 AM_direct_word() => this.GetWord(this.Address_direct()); + + private Register16 AM_indexed_word() => this.GetWord(this.Address_indexed()); + + private Register16 AM_extended_word() => this.GetWord(this.Address_extended()); + + private void AdjustZero(byte datum) => ClearFlag(this.CC, StatusBits.ZF, datum); + + private void AdjustZero(ushort datum) => ClearFlag(this.CC, StatusBits.ZF, datum); + + private void AdjustZero(Register16 datum) => this.AdjustZero(datum.Word); + + private void AdjustNegative(byte datum) => SetFlag(this.CC, StatusBits.NF, datum & (byte)Bits.Bit7); + + private void AdjustNegative(ushort datum) => SetFlag(this.CC, StatusBits.NF, datum & (ushort)Bits.Bit15); + + private void AdjustNegative(Register16 datum) => this.AdjustNegative(datum.Word); + + private void AdjustNZ(byte datum) + { + this.AdjustZero(datum); + this.AdjustNegative(datum); + } + + private void AdjustNZ(ushort datum) + { + this.AdjustZero(datum); + this.AdjustNegative(datum); + } + + private void AdjustNZ(Register16 datum) => this.AdjustNZ(datum.Word); + + private void AdjustCarry(ushort datum) => SetFlag(this.CC, StatusBits.CF, datum & (ushort)Bits.Bit8); // 8-bit addition + + private void AdjustCarry(uint datum) => SetFlag(this.CC, StatusBits.CF, (int)(datum & (uint)Bits.Bit16)); // 16-bit addition + + private void AdjustCarry(Register16 datum) => this.AdjustCarry(datum.Word); + + private void AdjustBorrow(ushort datum) => ClearFlag(this.CC, StatusBits.CF, datum & (ushort)Bits.Bit8); // 8-bit subtraction + + private void AdjustBorrow(uint datum) => ClearFlag(this.CC, StatusBits.CF, (int)(datum & (uint)Bits.Bit16)); // 16-bit subtraction + + private void AdjustBorrow(Register16 datum) => this.AdjustBorrow(datum.Word); + + private void AdjustOverflow(byte before, byte data, Register16 after) + { + var lowAfter = after.Low; + var highAfter = after.High; + SetFlag(this.CC, StatusBits.VF, (before ^ data ^ lowAfter ^ (highAfter << 7)) & (int)Bits.Bit7); + } + + private void AdjustOverflow(ushort before, ushort data, uint after) + { + var lowAfter = (ushort)(after & (uint)Mask.Mask16); + var highAfter = (ushort)(after >> 16); + SetFlag(this.CC, StatusBits.VF, (before ^ data ^ lowAfter ^ (highAfter << 15)) & (int)Bits.Bit15); + } + + private void AdjustOverflow(Register16 before, Register16 data, Register16 after) => this.AdjustOverflow(before.Word, data.Word, after.Word); + + private void AdjustHalfCarry(byte before, byte data, byte after) => SetFlag(this.CC, StatusBits.HF, (before ^ data ^ after) & (int)Bits.Bit4); + + private void AdjustAddition(byte before, byte data, Register16 after) + { + var result = after.Low; + this.AdjustNZ(result); + this.AdjustCarry(after); + this.AdjustOverflow(before, data, after); + this.AdjustHalfCarry(before, data, result); + } + + private void AdjustAddition(ushort before, ushort data, uint after) + { + var result = new Register16(after & (uint)Mask.Mask16); + this.AdjustNZ(result); + this.AdjustCarry(after); + this.AdjustOverflow(before, data, after); + } + + private void AdjustAddition(Register16 before, Register16 data, uint after) => this.AdjustAddition(before.Word, data.Word, after); + + private void AdjustSubtraction(byte before, byte data, Register16 after) + { + var result = after.Low; + this.AdjustNZ(result); + this.AdjustCarry(after); + this.AdjustOverflow(before, data, after); + } + + private void AdjustSubtraction(ushort before, ushort data, uint after) + { + var result = new Register16(after & (uint)Mask.Mask16); + this.AdjustNZ(result); + this.AdjustCarry(after); + this.AdjustOverflow(before, data, after); + } + + private void AdjustSubtraction(Register16 before, Register16 data, uint after) => this.AdjustSubtraction(before.Word, data.Word, after); + + private byte Through(byte data) + { + ClearFlag(this.CC, StatusBits.VF); + this.AdjustNZ(data); + return data; + } + + private ushort Through(ushort data) + { + ClearFlag(this.CC, StatusBits.VF); + this.AdjustNZ(data); + return data; + } + + private Register16 Through(Register16 data) + { + ClearFlag(this.CC, StatusBits.VF); + this.AdjustNZ(data); + return data; + } + + private byte LD(byte data) => this.Through(data); + + private ushort LD(ushort data) => this.Through(data); + + private Register16 LD(Register16 data) => this.Through(data); + + private byte ST(byte data) => this.Through(data); + + private ushort ST(ushort data) => this.Through(data); + + private Register16 ST(Register16 data) => this.Through(data); + + private void Jump(Register16 destination) => this.Jump(destination.Word); + + private bool Branch(ushort destination, bool condition) + { + if (condition) + { + this.Jump(destination); + } + + return condition; + } + + private bool Branch(Register16 destination, bool condition) => this.Branch(destination.Word, condition); + + private void Branch(ushort destination, int condition) => this.Branch(destination, condition != 0); + + private void Branch(Register16 destination, int condition) => this.Branch(destination.Word, condition); + + private void BranchShort(bool condition) => this.Branch(this.Address_relative_byte(), condition); + + private void BranchLong(bool condition) + { + if (this.Branch(this.Address_relative_word(), condition)) + { + this.Tick(); + } + } + + private void SaveEntireRegisterState() + { + SetFlag(this.CC, StatusBits.EF); + this.SaveRegisterState(); + } + + private void SavePartialRegisterState() + { + ClearFlag(this.CC, StatusBits.EF); + this.SaveRegisterState(); + } + + private void SaveRegisterState() => this.PSH(this.S, this.EntireRegisterSet != 0 ? (byte)Mask.Mask8 : (byte)0b10000001); + + private void RestoreRegisterState() => this.PUL(this.S, this.EntireRegisterSet != 0 ? (byte)Mask.Mask8 : (byte)0b10000001); + + private ref byte ReferenceTransfer8(int specifier) + { + switch (specifier) + { + case 0b1000: + return ref this.A; + case 0b1001: + return ref this.B; + case 0b1010: + return ref this.CC; + case 0b1011: + return ref this.DP; + default: + throw new ArgumentOutOfRangeException("specifier", specifier, "Invalid specifier"); + } + } + + Register16 ReferenceTransfer16(int specifier) + { + switch (specifier) { + case 0b0000: + return this.D; + case 0b0001: + return this.X; + case 0b0010: + return this.Y; + case 0b0011: + return this.U; + case 0b0100: + return this.S; + case 0b0101: + return this.PC; + default: + throw new ArgumentOutOfRangeException("specifier", specifier, "Invalid specifier"); + } + } + + private void ExecuteUnprefixed() + { + switch (this.OpCode) + { + case 0x10: this.prefix10 = true; this.Execute(this.FetchByte()); break; + case 0x11: this.prefix11 = true; this.Execute(this.FetchByte()); break; + + // ABX + case 0x3a: this.Tick(3); this.X.Word += this.B; break; // ABX (inherent) + + // ADC + case 0x89: this.Tick(2); this.A = this.ADC(this.A, this.AM_immediate_byte()); break; // ADC (ADCA immediate) + case 0x99: this.Tick(4); this.A = this.ADC(this.A, this.AM_direct_byte()); break; // ADC (ADCA direct) + case 0xa9: this.Tick(4); this.A = this.ADC(this.A, this.AM_indexed_byte()); break; // ADC (ADCA indexed) + case 0xb9: this.Tick(4); this.A = this.ADC(this.A, this.AM_extended_byte()); break; // ADC (ADCA extended) + + case 0xc9: this.Tick(2); this.B = this.ADC(this.B, this.AM_immediate_byte()); break; // ADC (ADCB immediate) + case 0xd9: this.Tick(4); this.B = this.ADC(this.B, this.AM_direct_byte()); break; // ADC (ADCB direct) + case 0xe9: this.Tick(4); this.B = this.ADC(this.B, this.AM_indexed_byte()); break; // ADC (ADCB indexed) + case 0xf9: this.Tick(4); this.B = this.ADC(this.B, this.AM_extended_byte()); break; // ADC (ADCB extended) + + // ADD + case 0x8b: this.Tick(2); this.A = this.ADD(this.A, this.AM_immediate_byte()); break; // ADD (ADDA immediate) + case 0x9b: this.Tick(4); this.A = this.ADD(this.A, this.AM_direct_byte()); break; // ADD (ADDA direct) + case 0xab: this.Tick(4); this.A = this.ADD(this.A, this.AM_indexed_byte()); break; // ADD (ADDA indexed) + case 0xbb: this.Tick(5); this.A = this.ADD(this.A, this.AM_extended_byte()); break; // ADD (ADDA extended) + + case 0xcb: this.Tick(2); this.B = this.ADD(this.B, this.AM_immediate_byte()); break; // ADD (ADDB immediate) + case 0xdb: this.Tick(4); this.B = this.ADD(this.B, this.AM_direct_byte()); break; // ADD (ADDB direct) + case 0xeb: this.Tick(4); this.B = this.ADD(this.B, this.AM_indexed_byte()); break; // ADD (ADDB indexed) + case 0xfb: this.Tick(5); this.B = this.ADD(this.B, this.AM_extended_byte()); break; // ADD (ADDB extended) + + case 0xc3: this.Tick(4); this.D.Word = this.ADD(this.D, this.AM_immediate_word()).Word; break; // ADD (ADDD immediate) + case 0xd3: this.Tick(6); this.D.Word = this.ADD(this.D, this.AM_direct_word()).Word; break; // ADD (ADDD direct) + case 0xe3: this.Tick(6); this.D.Word = this.ADD(this.D, this.AM_indexed_word()).Word; break; // ADD (ADDD indexed) + case 0xf3: this.Tick(7); this.D.Word = this.ADD(this.D, this.AM_extended_word()).Word; break; // ADD (ADDD extended) + + // AND + case 0x84: this.Tick(2); this.A = this.AndR(this.A, this.AM_immediate_byte()); break; // AND (ANDA immediate) + case 0x94: this.Tick(4); this.A = this.AndR(this.A, this.AM_direct_byte()); break; // AND (ANDA direct) + case 0xa4: this.Tick(4); this.A = this.AndR(this.A, this.AM_indexed_byte()); break; // AND (ANDA indexed) + case 0xb4: this.Tick(5); this.A = this.AndR(this.A, this.AM_extended_byte()); break; // AND (ANDA extended) + + case 0xc4: this.Tick(2); this.B = this.AndR(this.B, this.AM_immediate_byte()); break; // AND (ANDB immediate) + case 0xd4: this.Tick(4); this.B = this.AndR(this.B, this.AM_direct_byte()); break; // AND (ANDB direct) + case 0xe4: this.Tick(4); this.B = this.AndR(this.B, this.AM_indexed_byte()); break; // AND (ANDB indexed) + case 0xf4: this.Tick(5); this.B = this.AndR(this.B, this.AM_extended_byte()); break; // AND (ANDB extended) + + case 0x1c: this.Tick(3); this.CC &= this.AM_immediate_byte(); break; // AND (ANDCC immediate) + + // ASL/LSL + case 0x08: this.Tick(6); this.BusWrite(this.ASL(this.AM_direct_byte())); break; // ASL (direct) + case 0x48: this.Tick(2); this.A = this.ASL(this.A); break; // ASL (ASLA inherent) + case 0x58: this.Tick(2); this.B = this.ASL(this.B); break; // ASL (ASLB inherent) + case 0x68: this.Tick(6); this.BusWrite(this.ASL(this.AM_indexed_byte())); break; // ASL (indexed) + case 0x78: this.Tick(7); this.BusWrite(this.ASL(this.AM_extended_byte())); break; // ASL (extended) + + // ASR + case 0x07: this.Tick(6); this.BusWrite(this.ASR(this.AM_direct_byte())); break; // ASR (direct) + case 0x47: this.Tick(2); this.A = this.ASR(this.A); break; // ASR (ASRA inherent) + case 0x57: this.Tick(2); this.B = this.ASR(this.B); break; // ASR (ASRB inherent) + case 0x67: this.Tick(6); this.BusWrite(this.ASR(this.AM_indexed_byte())); break; // ASR (indexed) + case 0x77: this.Tick(7); this.BusWrite(this.ASR(this.AM_extended_byte())); break; // ASR (extended) + + // BIT + case 0x85: this.Tick(2); this.BIT(this.A, this.AM_immediate_byte()); break; // BIT (BITA immediate) + case 0x95: this.Tick(4); this.BIT(this.A, this.AM_direct_byte()); break; // BIT (BITA direct) + case 0xa5: this.Tick(4); this.BIT(this.A, this.AM_indexed_byte()); break; // BIT (BITA indexed) + case 0xb5: this.Tick(5); this.BIT(this.A, this.AM_extended_byte()); break; // BIT (BITA extended) + + case 0xc5: this.Tick(2); this.BIT(this.B, this.AM_immediate_byte()); break; // BIT (BITB immediate) + case 0xd5: this.Tick(4); this.BIT(this.B, this.AM_direct_byte()); break; // BIT (BITB direct) + case 0xe5: this.Tick(4); this.BIT(this.B, this.AM_indexed_byte()); break; // BIT (BITB indexed) + case 0xf5: this.Tick(5); this.BIT(this.B, this.AM_extended_byte()); break; // BIT (BITB extended) + + // CLR + case 0x0f: this.Tick(6); this.BusWrite(this.Address_direct(), this.CLR()); break; // CLR (direct) + case 0x4f: this.Tick(2); this.A = this.CLR(); break; // CLR (CLRA implied) + case 0x5f: this.Tick(2); this.B = this.CLR(); break; // CLR (CLRB implied) + case 0x6f: this.Tick(6); this.BusWrite(this.Address_indexed(), this.CLR()); break; // CLR (indexed) + case 0x7f: this.Tick(7); this.BusWrite(this.Address_extended(), this.CLR()); break; // CLR (extended) + + // CMP + + // CMPA + case 0x81: this.Tick(2); this.CMP(this.A, this.AM_immediate_byte()); break; // CMP (CMPA, immediate) + case 0x91: this.Tick(4); this.CMP(this.A, this.AM_direct_byte()); break; // CMP (CMPA, direct) + case 0xa1: this.Tick(4); this.CMP(this.A, this.AM_indexed_byte()); break; // CMP (CMPA, indexed) + case 0xb1: this.Tick(5); this.CMP(this.A, this.AM_extended_byte()); break; // CMP (CMPA, extended) + + // CMPB + case 0xc1: this.Tick(2); this.CMP(this.B, this.AM_immediate_byte()); break; // CMP (CMPB, immediate) + case 0xd1: this.Tick(4); this.CMP(this.B, this.AM_direct_byte()); break; // CMP (CMPB, direct) + case 0xe1: this.Tick(4); this.CMP(this.B, this.AM_indexed_byte()); break; // CMP (CMPB, indexed) + case 0xf1: this.Tick(5); this.CMP(this.B, this.AM_extended_byte()); break; // CMP (CMPB, extended) + + // CMPX + case 0x8c: this.Tick(4); this.CMP(this.X, this.AM_immediate_word()); break; // CMP (CMPX, immediate) + case 0x9c: this.Tick(6); this.CMP(this.X, this.AM_direct_word()); break; // CMP (CMPX, direct) + case 0xac: this.Tick(6); this.CMP(this.X, this.AM_indexed_word()); break; // CMP (CMPX, indexed) + case 0xbc: this.Tick(7); this.CMP(this.X, this.AM_extended_word()); break; // CMP (CMPX, extended) + + // COM + case 0x03: this.Tick(6); this.BusWrite(this.COM(this.AM_direct_byte())); break; // COM (direct) + case 0x43: this.Tick(2); this.A = this.COM(this.A); break; // COM (COMA inherent) + case 0x53: this.Tick(2); this.B = this.COM(this.B); break; // COM (COMB inherent) + case 0x63: this.Tick(6); this.BusWrite(this.COM(this.AM_indexed_byte())); break; // COM (indexed) + case 0x73: this.Tick(7); this.BusWrite(this.COM(this.AM_extended_byte())); break; // COM (extended) + + // CWAI + case 0x3c: this.Tick(11); this.CWAI(this.AM_direct_byte()); break; // CWAI (direct) + + // DAA + case 0x19: this.Tick(2); this.A = this.DA(this.A); break; // DAA (inherent) + + // DEC + case 0x0a: this.Tick(6); this.BusWrite(this.DEC(this.AM_direct_byte())); break; // DEC (direct) + case 0x4a: this.Tick(2); this.A = this.DEC(this.A); break; // DEC (DECA inherent) + case 0x5a: this.Tick(2); this.B = this.DEC(this.B); break; // DEC (DECB inherent) + case 0x6a: this.Tick(6); this.BusWrite(this.DEC(this.AM_indexed_byte())); break; // DEC (indexed) + case 0x7a: this.Tick(7); this.BusWrite(this.DEC(this.AM_extended_byte())); break; // DEC (extended) + + // EOR + + // EORA + case 0x88: this.Tick(2); this.A = this.EorR(this.A, this.AM_immediate_byte()); break; // EOR (EORA immediate) + case 0x98: this.Tick(4); this.A = this.EorR(this.A, this.AM_direct_byte()); break; // EOR (EORA direct) + case 0xa8: this.Tick(4); this.A = this.EorR(this.A, this.AM_indexed_byte()); break; // EOR (EORA indexed) + case 0xb8: this.Tick(5); this.A = this.EorR(this.A, this.AM_extended_byte()); break; // EOR (EORA extended) + + // EORB + case 0xc8: this.Tick(2); this.B = this.EorR(this.B, this.AM_immediate_byte()); break; // EOR (EORB immediate) + case 0xd8: this.Tick(4); this.B = this.EorR(this.B, this.AM_direct_byte()); break; // EOR (EORB direct) + case 0xe8: this.Tick(4); this.B = this.EorR(this.B, this.AM_indexed_byte()); break; // EOR (EORB indexed) + case 0xf8: this.Tick(5); this.B = this.EorR(this.B, this.AM_extended_byte()); break; // EOR (EORB extended) + + // EXG + case 0x1e: this.Tick(8); this.EXG(this.AM_immediate_byte()); break; // EXG (R1,R2 immediate) + + // INC + case 0x0c: this.Tick(6); this.BusWrite(this.INC(this.AM_direct_byte())); break; // INC (direct) + case 0x4c: this.Tick(2); this.A = this.INC(this.A); break; // INC (INCA inherent) + case 0x5c: this.Tick(2); this.B = this.INC(this.B); break; // INC (INCB inherent) + case 0x6c: this.Tick(6); this.BusWrite(this.INC(this.AM_indexed_byte())); break; // INC (indexed) + case 0x7c: this.Tick(7); this.BusWrite(this.INC(this.AM_extended_byte())); break; // INC (extended) + + // JMP + case 0x0e: this.Tick(6); this.Jump(this.Address_direct()); break; // JMP (direct) + case 0x6e: this.Tick(6); this.Jump(this.Address_indexed()); break; // JMP (indexed) + case 0x7e: this.Tick(7); this.Jump(this.Address_extended()); break; // JMP (extended) + + // JSR + case 0x9d: this.Tick(6); this.JSR(this.Address_direct()); break; // JSR (direct) + case 0xad: this.Tick(6); this.JSR(this.Address_indexed()); break; // JSR (indexed) + case 0xbd: this.Tick(7); this.JSR(this.Address_extended()); break; // JSR (extended) + + // LD + + // LDA + case 0x86: this.Tick(2); this.A = this.LD(this.AM_immediate_byte()); break; // LD (LDA immediate) + case 0x96: this.Tick(4); this.A = this.LD(this.AM_direct_byte()); break; // LD (LDA direct) + case 0xa6: this.Tick(4); this.A = this.LD(this.AM_indexed_byte()); break; // LD (LDA indexed) + case 0xb6: this.Tick(5); this.A = this.LD(this.AM_extended_byte()); break; // LD (LDA extended) + + // LDB + case 0xc6: this.Tick(2); this.B = this.LD(this.AM_immediate_byte()); break; // LD (LDB immediate) + case 0xd6: this.Tick(4); this.B = this.LD(this.AM_direct_byte()); break; // LD (LDB direct) + case 0xe6: this.Tick(4); this.B = this.LD(this.AM_indexed_byte()); break; // LD (LDB indexed) + case 0xf6: this.Tick(5); this.B = this.LD(this.AM_extended_byte()); break; // LD (LDB extended) + + // LDD + case 0xcc: this.Tick(3); this.D.Word = this.LD(this.AM_immediate_word()).Word; break; // LD (LDD immediate) + case 0xdc: this.Tick(5); this.D.Word = this.LD(this.AM_direct_word()).Word; break; // LD (LDD direct) + case 0xec: this.Tick(5); this.D.Word = this.LD(this.AM_indexed_word()).Word; break; // LD (LDD indexed) + case 0xfc: this.Tick(6); this.D.Word = this.LD(this.AM_extended_word()).Word; break; // LD (LDD extended) + + // LDU + case 0xce: this.Tick(3); this.U.Word = this.LD(this.AM_immediate_word()).Word; break; // LD (LDU immediate) + case 0xde: this.Tick(5); this.U.Word = this.LD(this.AM_direct_word()).Word; break; // LD (LDU direct) + case 0xee: this.Tick(5); this.U.Word = this.LD(this.AM_indexed_word()).Word; break; // LD (LDU indexed) + case 0xfe: this.Tick(6); this.U.Word = this.LD(this.AM_extended_word()).Word; break; // LD (LDU extended) + + // LDX + case 0x8e: this.Tick(3); this.X.Word = this.LD(this.AM_immediate_word()).Word; break; // LD (LDX immediate) + case 0x9e: this.Tick(5); this.X.Word = this.LD(this.AM_direct_word()).Word; break; // LD (LDX direct) + case 0xae: this.Tick(5); this.X.Word = this.LD(this.AM_indexed_word()).Word; break; // LD (LDX indexed) + case 0xbe: this.Tick(6); this.X.Word = this.LD(this.AM_extended_word()).Word; break; // LD (LDX extended) + + // LEA + case 0x30: this.Tick(4); this.AdjustZero(this.X.Word = this.Address_indexed().Word); break; // LEA (LEAX indexed) + case 0x31: this.Tick(4); this.AdjustZero(this.Y.Word = this.Address_indexed().Word); break; // LEA (LEAY indexed) + case 0x32: this.Tick(4); this.S.Word = this.Address_indexed().Word; break; // LEA (LEAS indexed) + case 0x33: this.Tick(4); this.U.Word = this.Address_indexed().Word; break; // LEA (LEAU indexed) + + // LSR + case 0x04: this.Tick(6); this.BusWrite(this.LSR(this.AM_direct_byte())); break; // LSR (direct) + case 0x44: this.Tick(2); this.A = this.LSR(this.A); break; // LSR (LSRA inherent) + case 0x54: this.Tick(2); this.B = this.LSR(this.B); break; // LSR (LSRB inherent) + case 0x64: this.Tick(6); this.BusWrite(this.LSR(this.AM_indexed_byte())); break; // LSR (indexed) + case 0x74: this.Tick(7); this.BusWrite(this.LSR(this.AM_extended_byte())); break; // LSR (extended) + + // MUL + case 0x3d: this.Tick(11); this.D.Word = this.MUL(this.A, this.B).Word; break; // MUL (inherent) + + // NEG + case 0x00: this.Tick(6); this.BusWrite(this.NEG(this.AM_direct_byte())); break; // NEG (direct) + case 0x40: this.Tick(2); this.A = this.NEG(this.A); break; // NEG (NEGA, inherent) + case 0x50: this.Tick(2); this.B = this.NEG(this.B); break; // NEG (NEGB, inherent) + case 0x60: this.Tick(6); this.BusWrite(this.NEG(this.AM_indexed_byte())); break; // NEG (indexed) + case 0x70: this.Tick(7); this.BusWrite(this.NEG(this.AM_extended_byte())); break; // NEG (extended) + + // NOP + case 0x12: this.Tick(2); break; // NOP (inherent) + + // OR + + // ORA + case 0x8a: this.Tick(2); this.A = this.OrR(this.A, this.AM_immediate_byte()); break; // OR (ORA immediate) + case 0x9a: this.Tick(4); this.A = this.OrR(this.A, this.AM_direct_byte()); break; // OR (ORA direct) + case 0xaa: this.Tick(4); this.A = this.OrR(this.A, this.AM_indexed_byte()); break; // OR (ORA indexed) + case 0xba: this.Tick(5); this.A = this.OrR(this.A, this.AM_extended_byte()); break; // OR (ORA extended) + + // ORB + case 0xca: this.Tick(2); this.B = this.OrR(this.B, this.AM_immediate_byte()); break; // OR (ORB immediate) + case 0xda: this.Tick(4); this.B = this.OrR(this.B, this.AM_direct_byte()); break; // OR (ORB direct) + case 0xea: this.Tick(4); this.B = this.OrR(this.B, this.AM_indexed_byte()); break; // OR (ORB indexed) + case 0xfa: this.Tick(5); this.B = this.OrR(this.B, this.AM_extended_byte()); break; // OR (ORB extended) + + // ORCC + case 0x1a: this.Tick(3); this.CC |= this.AM_immediate_byte(); break; // OR (ORCC immediate) + + // PSH + case 0x34: this.Tick(5); this.PSH(this.S, this.AM_immediate_byte()); break; // PSH (PSHS immediate) + case 0x36: this.Tick(5); this.PSH(this.U, this.AM_immediate_byte()); break; // PSH (PSHU immediate) + + // PUL + case 0x35: this.Tick(5); this.PUL(this.S, this.AM_immediate_byte()); break; // PUL (PULS immediate) + case 0x37: this.Tick(5); this.PUL(this.U, this.AM_immediate_byte()); break; // PUL (PULU immediate) + + // ROL + case 0x09: this.Tick(6); this.BusWrite(this.ROL(this.AM_direct_byte())); break; // ROL (direct) + case 0x49: this.Tick(2); this.A = this.ROL(this.A); break; // ROL (ROLA inherent) + case 0x59: this.Tick(2); this.B = this.ROL(this.B); break; // ROL (ROLB inherent) + case 0x69: this.Tick(6); this.BusWrite(this.ROL(this.AM_indexed_byte())); break; // ROL (indexed) + case 0x79: this.Tick(7); this.BusWrite(this.ROL(this.AM_extended_byte())); break; // ROL (extended) + + // ROR + case 0x06: this.Tick(6); this.BusWrite(this.ROR(this.AM_direct_byte())); break; // ROR (direct) + case 0x46: this.Tick(2); this.A = this.ROR(this.A); break; // ROR (RORA inherent) + case 0x56: this.Tick(2); this.B = this.ROR(this.B); break; // ROR (RORB inherent) + case 0x66: this.Tick(6); this.BusWrite(this.ROR(this.AM_indexed_byte())); break; // ROR (indexed) + case 0x76: this.Tick(7); this.BusWrite(this.ROR(this.AM_extended_byte())); break; // ROR (extended) + + // RTI + case 0x3B: this.Tick(6); this.RTI(); break; // RTI (inherent) + + // RTS + case 0x39: this.Tick(5); this.RTS(); break; // RTS (inherent) + + // SBC + + // SBCA + case 0x82: this.Tick(4); this.A = this.SBC(this.A, this.AM_immediate_byte()); break; // SBC (SBCA immediate) + case 0x92: this.Tick(4); this.A = this.SBC(this.A, this.AM_direct_byte()); break; // SBC (SBCA direct) + case 0xa2: this.Tick(4); this.A = this.SBC(this.A, this.AM_indexed_byte()); break; // SBC (SBCA indexed) + case 0xb2: this.Tick(5); this.A = this.SBC(this.A, this.AM_extended_byte()); break; // SBC (SBCB extended) + + // SBCB + case 0xc2: this.Tick(4); this.B = this.SBC(this.B, this.AM_immediate_byte()); break; // SBC (SBCB immediate) + case 0xd2: this.Tick(4); this.B = this.SBC(this.B, this.AM_direct_byte()); break; // SBC (SBCB direct) + case 0xe2: this.Tick(4); this.B = this.SBC(this.B, this.AM_indexed_byte()); break; // SBC (SBCB indexed) + case 0xf2: this.Tick(5); this.B = this.SBC(this.B, this.AM_extended_byte()); break; // SBC (SBCB extended) + + // SEX + case 0x1d: this.Tick(2); this.A = this.SEX(this.B); break; // SEX (inherent) + + // ST + + // STA + case 0x97: this.Tick(4); this.BusWrite(this.Address_direct(), this.ST(this.A)); break; // ST (STA direct) + case 0xa7: this.Tick(4); this.BusWrite(this.Address_indexed(), this.ST(this.A)); break; // ST (STA indexed) + case 0xb7: this.Tick(5); this.BusWrite(this.Address_extended(), this.ST(this.A)); break; // ST (STA extended) + + // STB + case 0xd7: this.Tick(4); this.BusWrite(this.Address_direct(), this.ST(this.B)); break; // ST (STB direct) + case 0xe7: this.Tick(4); this.BusWrite(this.Address_indexed(), this.ST(this.B)); break; // ST (STB indexed) + case 0xf7: this.Tick(5); this.BusWrite(this.Address_extended(), this.ST(this.B)); break; // ST (STB extended) + + // STD + case 0xdd: this.Tick(5); this.SetWord(this.Address_direct(), this.ST(this.D)); break; // ST (STD direct) + case 0xed: this.Tick(5); this.SetWord(this.Address_indexed(), this.ST(this.D)); break; // ST (STD indexed) + case 0xfd: this.Tick(6); this.SetWord(this.Address_extended(), this.ST(this.D)); break; // ST (STD extended) + + // STU + case 0xdf: this.Tick(5); this.SetWord(this.Address_direct(), this.ST(this.U)); break; // ST (STU direct) + case 0xef: this.Tick(5); this.SetWord(this.Address_indexed(), this.ST(this.U)); break; // ST (STU indexed) + case 0xff: this.Tick(6); this.SetWord(this.Address_extended(), this.ST(this.U)); break; // ST (STU extended) + + // STX + case 0x9f: this.Tick(5); this.SetWord(this.Address_direct(), this.ST(this.X)); break; // ST (STX direct) + case 0xaf: this.Tick(5); this.SetWord(this.Address_indexed(), this.ST(this.X)); break; // ST (STX indexed) + case 0xbf: this.Tick(6); this.SetWord(this.Address_extended(), this.ST(this.X)); break; // ST (STX extended) + + // SUB + + // SUBA + case 0x80: this.Tick(2); this.A = this.SUB(this.A, this.AM_immediate_byte()); break; // SUB (SUBA immediate) + case 0x90: this.Tick(4); this.A = this.SUB(this.A, this.AM_direct_byte()); break; // SUB (SUBA direct) + case 0xa0: this.Tick(4); this.A = this.SUB(this.A, this.AM_indexed_byte()); break; // SUB (SUBA indexed) + case 0xb0: this.Tick(5); this.A = this.SUB(this.A, this.AM_extended_byte()); break; // SUB (SUBA extended) + + // SUBB + case 0xc0: this.Tick(2); this.B = this.SUB(this.B, this.AM_immediate_byte()); break; // SUB (SUBB immediate) + case 0xd0: this.Tick(4); this.B = this.SUB(this.B, this.AM_direct_byte()); break; // SUB (SUBB direct) + case 0xe0: this.Tick(4); this.B = this.SUB(this.B, this.AM_indexed_byte()); break; // SUB (SUBB indexed) + case 0xf0: this.Tick(5); this.B = this.SUB(this.B, this.AM_extended_byte()); break; // SUB (SUBB extended) + + // SUBD + case 0x83: this.Tick(4); this.D.Word = this.SUB(this.D, this.AM_immediate_word()).Word; break; // SUB (SUBD immediate) + case 0x93: this.Tick(6); this.D.Word = this.SUB(this.D, this.AM_direct_word()).Word; break; // SUB (SUBD direct) + case 0xa3: this.Tick(6); this.D.Word = this.SUB(this.D, this.AM_indexed_word()).Word; break; // SUB (SUBD indexed) + case 0xb3: this.Tick(7); this.D.Word = this.SUB(this.D, this.AM_extended_word()).Word; break; // SUB (SUBD extended) + + // SWI + case 0x3f: this.Tick(10); this.SWI(); break; // SWI (inherent) + + // SYNC + case 0x13: this.Tick(4); this.Halt(); break; // SYNC (inherent) + + // TFR + case 0x1f: this.Tick(6); this.TFR(this.AM_immediate_byte()); break; // TFR (immediate) + + // TST + case 0x0d: this.Tick(6); this.TST(this.AM_direct_byte()); break; // TST (direct) + case 0x4d: this.Tick(2); this.TST(this.A); break; // TST (TSTA inherent) + case 0x5d: this.Tick(2); this.TST(this.B); break; // TST (TSTB inherent) + case 0x6d: this.Tick(6); this.TST(this.AM_indexed_byte()); break; // TST (indexed) + case 0x7d: this.Tick(7); this.TST(this.AM_extended_byte()); break; // TST (extended) + + // Branching + + case 0x16: this.Tick(5); this.Jump(this.Address_relative_word()); break; // BRA (LBRA relative) + case 0x17: this.Tick(9); this.JSR(this.Address_relative_word()); break; // BSR (LBSR relative) + case 0x20: this.Tick(3); this.Jump(this.Address_relative_byte()); break; // BRA (relative) + case 0x21: this.Tick(3); this.Address_relative_byte(); break; // BRN (relative) + case 0x22: this.Tick(3); this.BranchShort(this.HI); break; // BHI (relative) + case 0x23: this.Tick(3); this.BranchShort(this.LS); break; // BLS (relative) + case 0x24: this.Tick(3); this.BranchShort(this.Carry == 0); break; // BCC (relative) + case 0x25: this.Tick(3); this.BranchShort(this.Carry != 0); break; // BCS (relative) + case 0x26: this.Tick(3); this.BranchShort(this.Zero == 0); break; // BNE (relative) + case 0x27: this.Tick(3); this.BranchShort(this.Zero != 0); break; // BEQ (relative) + case 0x28: this.Tick(3); this.BranchShort(this.Overflow == 0); break; // BVC (relative) + case 0x29: this.Tick(3); this.BranchShort(this.Overflow != 0); break; // BVS (relative) + case 0x2a: this.Tick(3); this.BranchShort(this.Negative == 0); break; // BPL (relative) + case 0x2b: this.Tick(3); this.BranchShort(this.Negative != 0); break; // BMI (relative) + case 0x2c: this.Tick(3); this.BranchShort(this.GE); break; // BGE (relative) + case 0x2d: this.Tick(3); this.BranchShort(this.LT); break; // BLT (relative) + case 0x2e: this.Tick(3); this.BranchShort(this.GT); break; // BGT (relative) + case 0x2f: this.Tick(3); this.BranchShort(this.LE); break; // BLE (relative) + + case 0x8d: this.Tick(7); this.JSR(this.Address_relative_byte()); break; // BSR (relative) + + default: + throw new InvalidOperationException("Unknown op-code"); + } + } + + private void Execute10() + { + switch (this.OpCode) + { + + // CMP + + // CMPD + case 0x83: this.Tick(5); this.CMP(this.D, this.AM_immediate_word()); break; // CMP (CMPD, immediate) + case 0x93: this.Tick(7); this.CMP(this.D, this.AM_direct_word()); break; // CMP (CMPD, direct) + case 0xa3: this.Tick(7); this.CMP(this.D, this.AM_indexed_word()); break; // CMP (CMPD, indexed) + case 0xb3: this.Tick(8); this.CMP(this.D, this.AM_extended_word()); break; // CMP (CMPD, extended) + + // CMPY + case 0x8c: this.Tick(5); this.CMP(this.Y, this.AM_immediate_word()); break; // CMP (CMPY, immediate) + case 0x9c: this.Tick(7); this.CMP(this.Y, this.AM_direct_word()); break; // CMP (CMPY, direct) + case 0xac: this.Tick(7); this.CMP(this.Y, this.AM_indexed_word()); break; // CMP (CMPY, indexed) + case 0xbc: this.Tick(8); this.CMP(this.Y, this.AM_extended_word()); break; // CMP (CMPY, extended) + + // LD + + // LDS + case 0xce: this.Tick(4); this.S.Word = this.LD(this.AM_immediate_word()).Word; break; // LD (LDS immediate) + case 0xde: this.Tick(6); this.S.Word = this.LD(this.AM_direct_word()).Word; break; // LD (LDS direct) + case 0xee: this.Tick(6); this.S.Word = this.LD(this.AM_indexed_word()).Word; break; // LD (LDS indexed) + case 0xfe: this.Tick(7); this.S.Word = this.LD(this.AM_extended_word()).Word; break; // LD (LDS extended) + + // LDY + case 0x8e: this.Tick(4); this.Y.Word = this.LD(this.AM_immediate_word()).Word; break; // LD (LDY immediate) + case 0x9e: this.Tick(6); this.Y.Word = this.LD(this.AM_direct_word()).Word; break; // LD (LDY direct) + case 0xae: this.Tick(6); this.Y.Word = this.LD(this.AM_indexed_word()).Word; break; // LD (LDY indexed) + case 0xbe: this.Tick(7); this.Y.Word = this.LD(this.AM_extended_word()).Word; break; // LD (LDY extended) + + // Branching + + case 0x21: this.Tick(5); this.Address_relative_word(); break; // BRN (LBRN relative) + case 0x22: this.Tick(5); this.BranchLong(this.HI); break; // BHI (LBHI relative) + case 0x23: this.Tick(5); this.BranchLong(this.LS); break; // BLS (LBLS relative) + case 0x24: this.Tick(5); this.BranchLong(this.Carry == 0); break; // BCC (LBCC relative) + case 0x25: this.Tick(5); this.BranchLong(this.Carry != 0); break; // BCS (LBCS relative) + case 0x26: this.Tick(5); this.BranchLong(this.Zero == 0); break; // BNE (LBNE relative) + case 0x27: this.Tick(5); this.BranchLong(this.Zero != 0); break; // BEQ (LBEQ relative) + case 0x28: this.Tick(5); this.BranchLong(this.Overflow == 0); break; // BVC (LBVC relative) + case 0x29: this.Tick(5); this.BranchLong(this.Overflow != 0); break; // BVS (LBVS relative) + case 0x2a: this.Tick(5); this.BranchLong(this.Negative == 0); break; // BPL (LBPL relative) + case 0x2b: this.Tick(5); this.BranchLong(this.Negative != 0); break; // BMI (LBMI relative) + case 0x2c: this.Tick(5); this.BranchLong(this.GE); break; // BGE (LBGE relative) + case 0x2d: this.Tick(5); this.BranchLong(this.LT); break; // BLT (LBLT relative) + case 0x2e: this.Tick(5); this.BranchLong(this.GT); break; // BGT (LBGT relative) + case 0x2f: this.Tick(5); this.BranchLong(this.LE); break; // BLE (LBLE relative) + + // STS + case 0xdf: this.Tick(6); this.SetWord(this.Address_direct(), this.ST(this.S)); break; // ST (STS direct) + case 0xef: this.Tick(6); this.SetWord(this.Address_indexed(), this.ST(this.S)); break; // ST (STS indexed) + case 0xff: this.Tick(7); this.SetWord(this.Address_extended(), this.ST(this.S)); break; // ST (STS extended) + + // STY + case 0x9f: this.Tick(6); this.SetWord(this.Address_direct(), this.ST(this.Y)); break; // ST (STY direct) + case 0xaf: this.Tick(6); this.SetWord(this.Address_indexed(), this.ST(this.Y)); break; // ST (STY indexed) + case 0xbf: this.Tick(7); this.SetWord(this.Address_extended(), this.ST(this.Y)); break; // ST (STY extended) + + // SWI + case 0x3f: this.Tick(11); this.SWI2(); break; // SWI (SWI2 inherent) + + default: + throw new InvalidOperationException("Unknown 10 prefixed op-code"); + } + } + + private void Execute11() + { + switch (this.OpCode) + { + + // CMP + + // CMPU + case 0x83: this.Tick(5); this.CMP(this.U, this.AM_immediate_word()); break; // CMP (CMPU, immediate) + case 0x93: this.Tick(7); this.CMP(this.U, this.AM_direct_word()); break; // CMP (CMPU, direct) + case 0xa3: this.Tick(7); this.CMP(this.U, this.AM_indexed_word()); break; // CMP (CMPU, indexed) + case 0xb3: this.Tick(8); this.CMP(this.U, this.AM_extended_word()); break; // CMP (CMPU, extended) + + // CMPS + case 0x8c: this.Tick(5); this.CMP(this.S, this.AM_immediate_word()); break; // CMP (CMPS, immediate) + case 0x9c: this.Tick(7); this.CMP(this.S, this.AM_direct_word()); break; // CMP (CMPS, direct) + case 0xac: this.Tick(7); this.CMP(this.S, this.AM_indexed_word()); break; // CMP (CMPS, indexed) + case 0xbc: this.Tick(8); this.CMP(this.S, this.AM_extended_word()); break; // CMP (CMPS, extended) + + // SWI + case 0x3f: this.Tick(11); this.SWI3(); break; // SWI (SWI3 inherent) + + default: + throw new InvalidOperationException("Unknown 11 prefixed op-code"); + } + } + + private byte ADC(byte operand, byte data) => this.ADD(operand, data, (byte)this.Carry); + + private byte ADD(byte operand, byte data, byte carry = 0) + { + var addition = new Register16(operand + data + carry); + this.AdjustAddition(operand, data, addition); + return addition.Low; + } + + private Register16 ADD(Register16 operand, Register16 data) + { + var addition = (uint)(operand.Word + data.Word); + this.AdjustAddition(operand, data, addition); + return new Register16(addition & (uint)Mask.Mask16); + } + + private byte AndR(byte operand, byte data) => this.Through((byte)(operand & data)); + + private byte ASL(byte operand) + { + SetFlag(this.CC, StatusBits.CF, operand & (byte)Bits.Bit7); + this.AdjustNZ(operand <<= 1); + var overflow = this.Carry ^ (this.Negative >> 3); + SetFlag(this.CC, StatusBits.VF, overflow); + return operand; + } + + private byte ASR(byte operand) + { + SetFlag(this.CC, StatusBits.CF, operand & (byte)Bits.Bit0); + var result = (byte)((operand >> 1) | (int)Bits.Bit7); + this.AdjustNZ(result); + return result; + } + + private void BIT(byte operand, byte data) => this.AndR(operand, data); + + private byte CLR() + { + ClearFlag(this.CC, StatusBits.CF); + return this.Through((byte)0U); + } + + private void CMP(byte operand, byte data) => this.SUB(operand, data); + + private void CMP(Register16 operand, Register16 data) => this.SUB(operand, data); + + private byte COM(byte operand) + { + SetFlag(this.CC, StatusBits.CF); + return this.Through((byte)~operand); + } + + private void CWAI(byte data) + { + this.CC &= data; + this.SaveEntireRegisterState(); + this.Halt(); + } + + private byte DA(byte operand) + { + SetFlag(this.CC, StatusBits.CF, operand > 0x99); + + var lowAdjust = (this.HalfCarry != 0) || (Chip.LowNibble(operand) > 9); + var highAdjust = (this.Carry != 0) || (operand > 0x99); + + if (lowAdjust) + { + operand += 6; + } + + if (highAdjust) + { + operand += 0x60; + } + + return this.Through(operand); + } + + private byte DEC(byte operand) + { + var subtraction = new Register16(operand - 1); + var result = subtraction.Low; + this.AdjustNZ(result); + this.AdjustOverflow(operand, 1, subtraction); + return result; + } + + private byte EorR(byte operand, byte data) => this.Through((byte)(operand ^ data)); + + private void EXG(byte data) + { + var specifier1 = Chip.HighNibble(data); + var specifier2 = Chip.LowNibble(data); + + var type8 = (specifier1 & (int)Bits.Bit3) == 0; // 8 bit exchange? + + if (type8) + { + ref var register1 = ref this.ReferenceTransfer8(specifier1); + ref var register2 = ref this.ReferenceTransfer8(specifier2); + (register1, register2) = (register2, register1); + } + else + { + var register1 = this.ReferenceTransfer16(specifier1); + var register2 = this.ReferenceTransfer16(specifier2); + (register1, register2) = (register2, register1); + } + } + + private byte INC(byte operand) + { + const register16_t addition = operand + 1; + const auto result = addition.low; + adjustNZ(result); + adjustOverflow(operand, 1, addition); + adjustHalfCarry(operand, 1, result); + return result; + } + + private void JSR(ushort address) => this.Call(address); + + private void JSR(Register16 address) => this.JSR(address.Word); + + private byte LSR(byte operand) + { + setFlag(CC(), CF, operand & Bit0); + adjustNZ(operand >>= 1); + return operand; + } + + private Register16 MUL(byte first, byte second) + { + const register16_t result = first * second; + adjustZero(result); + setFlag(CC(), CF, result.low & Bit7); + return result; + } + + private byte NEG(byte operand) + { + setFlag(CC(), VF, operand == Bit7); + const register16_t result = 0 - operand; + operand = result.low; + adjustNZ(operand); + adjustCarry(result); + return operand; + } + + private byte OrR(byte operand, byte data) => this.Through((byte)(operand | data)); + + private void PSH(Register16 stack, byte data) + { + if ((data & (byte)Bits.Bit7) != 0) + { + this.Tick(2); + this.PushWord(stack, this.PC); + } + + if ((data & (byte)Bits.Bit6) != 0) + { + this.Tick(2); + // Pushing to the S stack means we must be pushing U + this.PushWord(stack, object.ReferenceEquals(stack, this.S) ? this.U : this.S); + } + + if ((data & (byte)Bits.Bit5) != 0) + { + this.Tick(2); + this.PushWord(stack, this.Y); + } + + if ((data & (byte)Bits.Bit4) != 0) + { + this.Tick(2); + this.PushWord(stack, this.X); + } + + if ((data & (byte)Bits.Bit3) != 0) + { + this.Tick(); + this.Push(stack, this.DP); + } + + if ((data & (byte)Bits.Bit2) != 0) + { + this.Tick(); + this.Push(stack, this.B); + } + + if ((data & (byte)Bits.Bit1) != 0) + { + this.Tick(); + this.Push(stack, this.A); + } + + if ((data & (byte)Bits.Bit0) != 0) + { + this.Tick(); + this.Push(stack, this.CC); + } + } + + private void PUL(Register16 stack, byte data) + { + if ((data & (byte)Bits.Bit0) != 0) + { + this.Tick(); + this.CC = this.Pop(stack); + } + + if ((data & (byte)Bits.Bit1) != 0) + { + this.Tick(); + this.A = this.Pop(stack); + } + + if ((data & (byte)Bits.Bit2) != 0) + { + this.Tick(); + this.B = this.Pop(stack); + } + + if ((data & (byte)Bits.Bit3) != 0) + { + this.Tick(); + this.DP = this.Pop(stack); + } + + if ((data & (byte)Bits.Bit4) != 0) + { + this.Tick(2); + this.X.Word = this.PopWord(stack).Word; + } + + if ((data & (byte)Bits.Bit5) != 0) + { + this.Tick(2); + this.Y.Word = this.PopWord(stack).Word; + } + + if ((data & (byte)Bits.Bit6) != 0) + { + this.Tick(2); + // Pulling from the S stack means we must be pulling U + (object.ReferenceEquals(stack, this.S) ? this.U : this.S).Word = this.PopWord(stack).Word; + } + + if ((data & (byte)Bits.Bit7) != 0) + { + this.Tick(2); + this.PC.Word = this.PopWord(stack).Word; + } + } + + private byte ROL(byte operand) + { + const auto carryIn = carry(); + setFlag(CC(), CF, operand & Bit7); + setFlag(CC(), VF, ((operand & Bit7) >> 7) ^ ((operand & Bit6) >> 6)); + const uint8_t result = (operand << 1) | carryIn; + adjustNZ(result); + return result; + } + + private byte ROR(byte operand) + { + const auto carryIn = carry(); + setFlag(CC(), CF, operand & Bit0); + const uint8_t result = (operand >> 1) | (carryIn << 7); + adjustNZ(result); + return result; + } + + private void RTI() => this.RestoreRegisterState(); + + private void RTS() => this.Return(); + + private byte SBC(byte operand, byte data) => this.SUB(operand, data, (byte)this.Carry); + + private byte SUB(byte operand, byte data, byte carry = 0) + { + const register16_t subtraction = operand - data - carry; + adjustSubtraction(operand, data, subtraction); + return subtraction.low; + } + + private Register16 SUB(Register16 operand, Register16 data) + { + const uint32_t subtraction = operand.word - data.word; + adjustSubtraction(operand, data, subtraction); + return subtraction & Mask16; + } + + private byte SEX(byte from) + { + adjustNZ(from); + return from & Bit7 ? Mask8 : 0; + } + + private void SWI() + { + saveEntireRegisterState(); + setFlag(CC(), IF); // Disable IRQ + setFlag(CC(), FF); // Disable FIRQ + jump(getWordPaged(0xff, SWIvector)); + } + + private void SWI2() + { + saveEntireRegisterState(); + jump(getWordPaged(0xff, SWI2vector)); + } + + private void SWI3() + { + saveEntireRegisterState(); + jump(getWordPaged(0xff, SWI3vector)); + } + + private void TFR(byte data) + { + const auto reg1 = highNibble(data); + const auto reg2 = lowNibble(data); + + const bool type8 = !!(reg1 & Bit3); // 8 bit transfer? + ASSUME(type8 == !!(reg2 & Bit3)); // Regardless, the register transfer must be equivalent + + if (type8) + referenceTransfer8(reg2) = referenceTransfer8(reg1); + else + referenceTransfer16(reg2) = referenceTransfer16(reg1); + } + + private void TST(byte data) => this.CMP(data, 0); + } +} \ No newline at end of file diff --git a/MC6809/MC6809.csproj b/MC6809/MC6809.csproj new file mode 100644 index 0000000..9a58b11 --- /dev/null +++ b/MC6809/MC6809.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {3A63972B-AB50-4A01-8A10-0D2165580FAD} + Library + Properties + EightBit + MC6809 + v4.7.2 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + latest + + + + + + + + + + + + + + + + + + + + + + + + + {6ebf8857-62a3-4ef4-af21-c1844031d7e4} + EightBit + + + + \ No newline at end of file diff --git a/MC6809/Properties/AssemblyInfo.cs b/MC6809/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0a6b684 --- /dev/null +++ b/MC6809/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MC6809")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MC6809")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3a63972b-ab50-4a01-8a10-0d2165580fad")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MC6809/StatusBits.cs b/MC6809/StatusBits.cs new file mode 100644 index 0000000..a01465f --- /dev/null +++ b/MC6809/StatusBits.cs @@ -0,0 +1,48 @@ +// +// Copyright (c) Adrian Conlon. All rights reserved. +// + +namespace EightBit +{ + using System; + + [Flags] + public enum StatusBits : byte + { + // Entire flag: set if the complete machine state was saved in the stack. + // If this bit is not set then only program counter and condition code + // registers were saved in the stack. This bit is used by interrupt + // handling routines only. + // The bit is cleared by fast interrupts, and set by all other interrupts. + EF = Bits.Bit7, + + // Fast interrupt mask: set if the FIRQ interrupt is disabled. + FF = Bits.Bit6, + + // Half carry: set if there was a carry from bit 3 to bit 4 of the result + // during the last add operation. + HF = Bits.Bit5, + + // Interrupt mask: set if the IRQ interrupt is disabled. + IF = Bits.Bit4, + + // Negative: set if the most significant bit of the result is set. + // This bit can be set not only by arithmetic and logical operations, + // but also by load / store operations. + NF = Bits.Bit3, + + // Zero: set if the result is zero. Like the N bit, this bit can be + // set not only by arithmetic and logical operations, but also + // by load / store operations. + ZF = Bits.Bit2, + + // Overflow: set if there was an overflow during last result calculation. + // Logical, load and store operations clear this bit. + VF = Bits.Bit1, + + // Carry: set if there was a carry from the bit 7 during last add + // operation, or if there was a borrow from last subtract operation, + // or if bit 7 of the A register was set during last MUL operation. + CF = Bits.Bit0, + } +} diff --git a/MC6809/packages.config b/MC6809/packages.config new file mode 100644 index 0000000..c7973f9 --- /dev/null +++ b/MC6809/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/MC6809/stylecop.json b/MC6809/stylecop.json new file mode 100644 index 0000000..3af08b4 --- /dev/null +++ b/MC6809/stylecop.json @@ -0,0 +1,19 @@ +{ + // ACTION REQUIRED: This file was automatically added to your project, but it + // will not take effect until additional steps are taken to enable it. See the + // following page for additional information: + // + // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md + + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "documentInterfaces": false, + "documentExposedElements": false, + "documentInternalElements": false, + "documentPrivateElements": false, + "documentPrivateFields": false, + "companyName": "Adrian Conlon" + } + } +}