// // Copyright (c) Adrian Conlon. All rights reserved. // namespace EightBit { using System; // Uses some information from: // http://www.cpu-world.com/Arch/6809.html // http://atjs.mbnet.fi/mc6809/Information/6809.htm /* |---------------|-----------------------------------| | 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 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 PinLevel rwLine = 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 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; public ref byte B => ref this.D.Low; public Register16 X { get; } = new Register16(); public Register16 Y { get; } = new Register16(); public Register16 U { get; } = new Register16(); public Register16 S { get; } = new Register16(); public ref byte DP => ref this.dp; public ref byte CC => ref this.cc; public bool Halted => this.HALT.Lowered(); 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 ref PinLevel RW => ref this.rwLine; public int EntireRegisterSet => this.CC & (byte)StatusBits.EF; public int FastInterruptMasked => this.CC & (byte)StatusBits.FF; public int HalfCarry => this.CC & (byte)StatusBits.HF; public int InterruptMasked => this.CC & (byte)StatusBits.IF; public int Negative => this.CC & (byte)StatusBits.NF; public int Zero => this.CC & (byte)StatusBits.ZF; public int Overflow => this.CC & (byte)StatusBits.VF; public 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 >> 1)) != 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 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 void 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(); } } } public void RaiseNMI() { if (this.NMI.Lowered()) { this.OnRaisingNMI(); this.NMI.Raise(); this.OnRaisedNMI(); } } public void LowerNMI() { if (this.NMI.Raised()) { this.OnLoweringNMI(); this.NMI.Lower(); this.OnLoweredNMI(); } } public void RaiseFIRQ() { if (this.FIRQ.Lowered()) { this.OnRaisingFIRQ(); this.FIRQ.Raise(); this.OnRaisedFIRQ(); } } public void LowerFIRQ() { if (this.FIRQ.Raised()) { this.OnLoweringFIRQ(); this.FIRQ.Lower(); this.OnLoweredFIRQ(); } } public void RaiseHALT() { if (this.HALT.Lowered()) { this.OnRaisingHALT(); this.HALT.Raise(); this.OnRaisedHALT(); } } public void LowerHALT() { if (this.HALT.Raised()) { this.OnLoweringHALT(); this.HALT.Lower(); this.OnLoweredHALT(); } } public void RaiseBA() { if (this.BA.Lowered()) { this.OnRaisingBA(); this.BA.Raise(); this.OnRaisedBA(); } } public void LowerBA() { if (this.BA.Raised()) { this.OnLoweringBA(); this.BA.Lower(); this.OnLoweredBA(); } } public void RaiseBS() { if (this.BS.Lowered()) { this.OnRaisingBS(); this.BS.Raise(); this.OnRaisedBS(); } } public void LowerBS() { if (this.BS.Raised()) { this.OnLoweringBS(); this.BS.Lower(); this.OnLoweredBS(); } } 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(); } protected override void HandleRESET() { base.HandleRESET(); this.RaiseNMI(); this.LowerBA(); this.RaiseBS(); this.DP = 0; this.CC = SetBit(this.CC, StatusBits.IF); // Disable IRQ this.CC = SetBit(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(); this.CC = SetBit(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); protected override void BusWrite() { this.LowerRW(); base.BusWrite(); } protected override byte BusRead() { this.RaiseRW(); return base.BusRead(); } private static byte SetBit(byte f, StatusBits flag) => SetBit(f, (byte)flag); private static byte SetBit(byte f, StatusBits flag, int condition) => SetBit(f, (byte)flag, condition); private static byte SetBit(byte f, StatusBits flag, bool condition) => SetBit(f, (byte)flag, condition); private static byte ClearBit(byte f, StatusBits flag) => ClearBit(f, (byte)flag); private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition); private void HandleHALT() { this.RaiseBA(); this.RaiseBS(); } private void HandleNMI() { this.RaiseNMI(); this.LowerBA(); this.RaiseBS(); this.SaveEntireRegisterState(); this.CC = SetBit(this.CC, StatusBits.IF); // Disable IRQ this.CC = SetBit(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(); this.CC = SetBit(this.CC, StatusBits.IF); // Disable IRQ this.CC = SetBit(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 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); private void Push(Register16 stack, byte value) => this.MemoryWrite(--stack.Word, value); private void PushS(byte value) => this.Push(this.S, value); private void PushWord(Register16 stack, Register16 value) { this.Push(stack, value.Low); this.Push(stack, value.High); } private byte Pop(Register16 stack) => this.MemoryRead(stack.Word++); private byte PopS() => this.Pop(this.S); private Register16 PopWord(Register16 stack) { var high = this.Pop(stack); var low = this.Pop(stack); return new Register16(low, high); } 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(nameof(which), which, "Which does not specify a valid register"); } } private Register16 Address_relative_byte() { var offset = (sbyte)this.FetchByte(); return new Register16(this.PC.Word + offset); } private Register16 Address_relative_word() { var offset = (short)this.FetchWord().Word; return new Register16(this.PC.Word + offset); } 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.Four) { 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.Word = new Register16(r.Word + SignExtend(5, (byte)(type & (byte)Mask.Five))).Word; } return address; } private byte AM_immediate_byte() => this.FetchByte(); private byte AM_direct_byte() => this.MemoryRead(this.Address_direct()); private byte AM_indexed_byte() => this.MemoryRead(this.Address_indexed()); private byte AM_extended_byte() => this.MemoryRead(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 byte AdjustZero(byte datum) => ClearBit(this.CC, StatusBits.ZF, datum); private byte AdjustZero(ushort datum) => ClearBit(this.CC, StatusBits.ZF, datum); private byte AdjustZero(Register16 datum) => this.AdjustZero(datum.Word); private byte AdjustNegative(byte datum) => SetBit(this.CC, StatusBits.NF, datum & (byte)Bits.Bit7); private byte AdjustNegative(ushort datum) => SetBit(this.CC, StatusBits.NF, datum & (ushort)Bits.Bit15); private byte AdjustNZ(byte datum) { this.CC = this.AdjustZero(datum); return this.AdjustNegative(datum); } private byte AdjustNZ(ushort datum) { this.CC = this.AdjustZero(datum); return this.AdjustNegative(datum); } private byte AdjustNZ(Register16 datum) => this.AdjustNZ(datum.Word); private byte AdjustCarry(ushort datum) => SetBit(this.CC, StatusBits.CF, datum & (ushort)Bits.Bit8); // 8-bit addition private byte AdjustCarry(uint datum) => SetBit(this.CC, StatusBits.CF, (int)(datum & (uint)Bits.Bit16)); // 16-bit addition private byte AdjustCarry(Register16 datum) => this.AdjustCarry(datum.Word); private byte AdjustOverflow(byte before, byte data, Register16 after) { var lowAfter = after.Low; var highAfter = after.High; return SetBit(this.CC, StatusBits.VF, (before ^ data ^ lowAfter ^ (highAfter << 7)) & (int)Bits.Bit7); } private byte AdjustOverflow(ushort before, ushort data, uint after) { var lowAfter = (ushort)(after & (uint)Mask.Sixteen); var highAfter = (ushort)(after >> 16); return SetBit(this.CC, StatusBits.VF, (before ^ data ^ lowAfter ^ (highAfter << 15)) & (int)Bits.Bit15); } private byte AdjustHalfCarry(byte before, byte data, byte after) => SetBit(this.CC, StatusBits.HF, (before ^ data ^ after) & (int)Bits.Bit4); private byte AdjustAddition(byte before, byte data, Register16 after) { var result = after.Low; this.CC = this.AdjustNZ(result); this.CC = this.AdjustCarry(after); this.CC = this.AdjustOverflow(before, data, after); return this.AdjustHalfCarry(before, data, result); } private byte AdjustAddition(ushort before, ushort data, uint after) { var result = new Register16(after & (uint)Mask.Sixteen); this.CC = this.AdjustNZ(result); this.CC = this.AdjustCarry(after); return this.AdjustOverflow(before, data, after); } private byte AdjustAddition(Register16 before, Register16 data, uint after) => this.AdjustAddition(before.Word, data.Word, after); private byte AdjustSubtraction(byte before, byte data, Register16 after) { var result = after.Low; this.CC = this.AdjustNZ(result); this.CC = this.AdjustCarry(after); return this.AdjustOverflow(before, data, after); } private byte AdjustSubtraction(ushort before, ushort data, uint after) { var result = new Register16(after & (uint)Mask.Sixteen); this.CC = this.AdjustNZ(result); this.CC = this.AdjustCarry(after); return this.AdjustOverflow(before, data, after); } private byte AdjustSubtraction(Register16 before, Register16 data, uint after) => this.AdjustSubtraction(before.Word, data.Word, after); private byte Through(byte data) { this.CC = ClearBit(this.CC, StatusBits.VF); this.CC = this.AdjustNZ(data); return data; } private Register16 Through(Register16 data) { this.CC = ClearBit(this.CC, StatusBits.VF); this.CC = this.AdjustNZ(data); return data; } private byte LD(byte data) => this.Through(data); private Register16 LD(Register16 data) => this.Through(data); private byte ST(byte 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 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() { this.CC = SetBit(this.CC, StatusBits.EF); this.SaveRegisterState(); } private void SavePartialRegisterState() { this.CC = ClearBit(this.CC, StatusBits.EF); this.SaveRegisterState(); } private void SaveRegisterState() => this.PSH(this.S, this.EntireRegisterSet != 0 ? (byte)Mask.Eight : (byte)0b10000001); private void RestoreRegisterState() => this.PUL(this.S, this.EntireRegisterSet != 0 ? (byte)Mask.Eight : (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(nameof(specifier), specifier, "Invalid specifier"); } } private 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(nameof(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.MemoryWrite(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.MemoryWrite(this.ASL(this.AM_indexed_byte())); break; // ASL (indexed) case 0x78: this.Tick(7); this.MemoryWrite(this.ASL(this.AM_extended_byte())); break; // ASL (extended) // ASR case 0x07: this.Tick(6); this.MemoryWrite(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.MemoryWrite(this.ASR(this.AM_indexed_byte())); break; // ASR (indexed) case 0x77: this.Tick(7); this.MemoryWrite(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.MemoryWrite(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.MemoryWrite(this.Address_indexed(), this.CLR()); break; // CLR (indexed) case 0x7f: this.Tick(7); this.MemoryWrite(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.MemoryWrite(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.MemoryWrite(this.COM(this.AM_indexed_byte())); break; // COM (indexed) case 0x73: this.Tick(7); this.MemoryWrite(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.MemoryWrite(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.MemoryWrite(this.DEC(this.AM_indexed_byte())); break; // DEC (indexed) case 0x7a: this.Tick(7); this.MemoryWrite(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.MemoryWrite(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.MemoryWrite(this.INC(this.AM_indexed_byte())); break; // INC (indexed) case 0x7c: this.Tick(7); this.MemoryWrite(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.CC = this.AdjustZero(this.X.Word = this.Address_indexed().Word); break; // LEA (LEAX indexed) case 0x31: this.Tick(4); this.CC = 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.MemoryWrite(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.MemoryWrite(this.LSR(this.AM_indexed_byte())); break; // LSR (indexed) case 0x74: this.Tick(7); this.MemoryWrite(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.MemoryWrite(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.MemoryWrite(this.NEG(this.AM_indexed_byte())); break; // NEG (indexed) case 0x70: this.Tick(7); this.MemoryWrite(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.MemoryWrite(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.MemoryWrite(this.ROL(this.AM_indexed_byte())); break; // ROL (indexed) case 0x79: this.Tick(7); this.MemoryWrite(this.ROL(this.AM_extended_byte())); break; // ROL (extended) // ROR case 0x06: this.Tick(6); this.MemoryWrite(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.MemoryWrite(this.ROR(this.AM_indexed_byte())); break; // ROR (indexed) case 0x76: this.Tick(7); this.MemoryWrite(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.MemoryWrite(this.Address_direct(), this.ST(this.A)); break; // ST (STA direct) case 0xa7: this.Tick(4); this.MemoryWrite(this.Address_indexed(), this.ST(this.A)); break; // ST (STA indexed) case 0xb7: this.Tick(5); this.MemoryWrite(this.Address_extended(), this.ST(this.A)); break; // ST (STA extended) // STB case 0xd7: this.Tick(4); this.MemoryWrite(this.Address_direct(), this.ST(this.B)); break; // ST (STB direct) case 0xe7: this.Tick(4); this.MemoryWrite(this.Address_indexed(), this.ST(this.B)); break; // ST (STB indexed) case 0xf7: this.Tick(5); this.MemoryWrite(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.CC = this.AdjustAddition(operand, data, addition); return addition.Low; } private Register16 ADD(Register16 operand, Register16 data) { var addition = (uint)(operand.Word + data.Word); this.CC = this.AdjustAddition(operand, data, addition); return new Register16(addition & (uint)Mask.Sixteen); } private byte AndR(byte operand, byte data) => this.Through((byte)(operand & data)); private byte ASL(byte operand) { this.CC = SetBit(this.CC, StatusBits.CF, operand & (byte)Bits.Bit7); this.CC = this.AdjustNZ(operand <<= 1); var overflow = this.Carry ^ (this.Negative >> 3); this.CC = SetBit(this.CC, StatusBits.VF, overflow); return operand; } private byte ASR(byte operand) { this.CC = SetBit(this.CC, StatusBits.CF, operand & (byte)Bits.Bit0); var result = (byte)((operand >> 1) | (int)Bits.Bit7); this.CC = this.AdjustNZ(result); return result; } private void BIT(byte operand, byte data) => this.AndR(operand, data); private byte CLR() { this.CC = ClearBit(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) { this.CC = SetBit(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) { this.CC = SetBit(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.CC = this.AdjustNZ(result); this.CC = 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 leftSpecifier = Chip.HighNibble(data); var leftType = leftSpecifier & (int)Bits.Bit3; var rightSpecifier = Chip.LowNibble(data); var rightType = rightSpecifier & (int)Bits.Bit3; if (leftType == 0) { var leftRegister = this.ReferenceTransfer16(leftSpecifier); if (rightType == 0) { var rightRegister = this.ReferenceTransfer16(rightSpecifier); (leftRegister.Word, rightRegister.Word) = (rightRegister.Word, leftRegister.Word); } else { ref var rightRegister = ref this.ReferenceTransfer8(rightSpecifier); (leftRegister.Low, rightRegister) = (rightRegister, leftRegister.Low); leftRegister.High = (byte)Mask.Eight; } } else { ref var leftRegister = ref this.ReferenceTransfer8(leftSpecifier); if (rightType == 0) { var rightRegister = this.ReferenceTransfer16(rightSpecifier); (leftRegister, rightRegister.Low) = (rightRegister.Low, leftRegister); rightRegister.High =(byte)Mask.Eight; } else { ref var rightRegister = ref this.ReferenceTransfer8(rightSpecifier); (leftRegister, rightRegister) = (rightRegister, leftRegister); } } } private byte INC(byte operand) { var addition = new Register16(operand + 1); var result = addition.Low; this.CC = this.AdjustNZ(result); this.CC = this.AdjustOverflow(operand, 1, addition); this.CC = this.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) { this.CC = SetBit(this.CC, StatusBits.CF, operand & (byte)Bits.Bit0); this.CC = this.AdjustNZ(operand >>= 1); return operand; } private Register16 MUL(byte first, byte second) { var result = new Register16(first * second); this.CC = this.AdjustZero(result); this.CC = SetBit(this.CC, StatusBits.CF, result.Low & (byte)Bits.Bit7); return result; } private byte NEG(byte operand) { this.CC = SetBit(this.CC, StatusBits.VF, operand == (byte)Bits.Bit7); var result = new Register16(0 - operand); operand = result.Low; this.CC = this.AdjustNZ(operand); this.CC = this.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) { var carryIn = this.Carry; this.CC = SetBit(this.CC, StatusBits.CF, operand & (byte)Bits.Bit7); this.CC = SetBit(this.CC, StatusBits.VF, ((operand & (byte)Bits.Bit7) >> 7) ^ ((operand & (byte)Bits.Bit6) >> 6)); var result = (byte)((operand << 1) | carryIn); this.CC = this.AdjustNZ(result); return result; } private byte ROR(byte operand) { var carryIn = this.Carry; this.CC = SetBit(this.CC, StatusBits.CF, operand & (byte)Bits.Bit0); var result = (byte)((operand >> 1) | (carryIn << 7)); this.CC = this.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) { var subtraction = new Register16(operand - data - carry); this.CC = this.AdjustSubtraction(operand, data, subtraction); return subtraction.Low; } private Register16 SUB(Register16 operand, Register16 data) { var subtraction = (uint)(operand.Word - data.Word); this.CC = this.AdjustSubtraction(operand, data, subtraction); return new Register16(subtraction & (uint)Mask.Sixteen); } private byte SEX(byte from) { this.CC = this.AdjustNZ(from); return (from & (byte)Bits.Bit7) != 0 ? (byte)Mask.Eight : (byte)0; } private void SWI() { this.SaveEntireRegisterState(); this.CC = SetBit(this.CC, StatusBits.IF); // Disable IRQ this.CC = SetBit(this.CC, StatusBits.FF); // Disable FIRQ this.Jump(this.GetWordPaged(0xff, SWIvector)); } private void SWI2() { this.SaveEntireRegisterState(); this.Jump(this.GetWordPaged(0xff, SWI2vector)); } private void SWI3() { this.SaveEntireRegisterState(); this.Jump(this.GetWordPaged(0xff, SWI3vector)); } private void TFR(byte data) { var sourceSpecifier = Chip.HighNibble(data); var sourceType = sourceSpecifier & (int)Bits.Bit3; var destinationSpecifier = Chip.LowNibble(data); var destinationType = destinationSpecifier & (int)Bits.Bit3; if (sourceType == 0) { var sourceRegister = this.ReferenceTransfer16(sourceSpecifier); if (destinationType == 0) { var destinationRegister = this.ReferenceTransfer16(destinationSpecifier); destinationRegister.Word = sourceRegister.Word; } else { ref var destinationRegister = ref this.ReferenceTransfer8(destinationSpecifier); destinationRegister = sourceRegister.Low; } } else { ref var sourceRegister = ref this.ReferenceTransfer8(sourceSpecifier); if (destinationType == 0) { var destinationRegister = this.ReferenceTransfer16(destinationSpecifier); destinationRegister.Low = sourceRegister; destinationRegister.High = (byte)Mask.Eight; } else { ref var destinationRegister = ref this.ReferenceTransfer8(destinationSpecifier); destinationRegister = sourceRegister; } } } private void TST(byte data) => this.CMP(data, 0); } }