Needs tidying a little by full cycle accuracy for 6502 / 65c02

This commit is contained in:
Adrian Conlon committed 2026-05-15 22:02:03 +01:00
1 parent 8f59e79959
commit 6d4d2f22e2
3 files changed
+243 -184

No files matched your search

+29 -20
View File
@@ -14,6 +14,8 @@ namespace M6502
this.RaisedPOWER += this.Core_RaisedPOWER;
}
protected bool ImmediateInstruction { get; private set; }
#region Pin controls
#region NMI pin
@@ -259,7 +261,7 @@ namespace M6502
#region Processor state helpers
protected int InterruptMasked => this.P & (byte)StatusBits.IF;
protected int DecimalMasked => this.P & (byte)StatusBits.DF;
protected int Denary => this.P & (byte)StatusBits.DF;
protected int Negative => NegativeTest(this.P);
protected int Zero => ZeroTest(this.P);
protected int Overflow => OverflowTest(this.P);
@@ -340,7 +342,6 @@ namespace M6502
case 0x18: this.SwallowRead(); this.CLC(); break; // CLC (implied)
case 0x19: this.AbsoluteY(); this.ORA(); break; // ORA (absolute, Y)
case 0x1d: this.AbsoluteX(); this.ORA(); break; // ORA (absolute, X)
case 0x1e: this.AbsoluteXAddress(); this.FixupRead(); this.ASL(); break; // ASL (absolute, X)
case 0x20: this.JSR(); break; // JSR (absolute)
case 0x21: this.IndexedIndirectX(); this.AND(); break; // AND (indexed indirect X)
@@ -361,7 +362,6 @@ namespace M6502
case 0x38: this.SwallowRead(); this.SEC(); break; // SEC (implied)
case 0x39: this.AbsoluteY(); this.AND(); break; // AND (absolute, Y)
case 0x3d: this.AbsoluteX(); this.AND(); break; // AND (absolute, X)
case 0x3e: this.AbsoluteXAddress(); this.FixupRead(); this.ROL(); break; // ROL (absolute, X)
case 0x40: this.SwallowRead(); this.RTI(); break; // RTI (implied)
case 0x41: this.IndexedIndirectX(); this.EOR(); break; // EOR (indexed indirect X)
@@ -383,7 +383,6 @@ namespace M6502
case 0x58: this.SwallowRead(); this.CLI(); break; // CLI (implied)
case 0x59: this.AbsoluteY(); this.EOR(); break; // EOR (absolute, Y)
case 0x5d: this.AbsoluteX(); this.EOR(); break; // EOR (absolute, X)
case 0x5e: this.AbsoluteXAddress(); this.FixupRead(); this.LSR(); break; // LSR (absolute, X)
case 0x60: this.SwallowRead(); this.RTS(); break; // RTS (implied)
case 0x61: this.IndexedIndirectX(); this.ADC(); break; // ADC (indexed indirect X)
@@ -403,7 +402,6 @@ namespace M6502
case 0x78: this.SwallowRead(); this.SEI(); break; // SEI (implied)
case 0x79: this.AbsoluteY(); this.ADC(); break; // ADC (absolute, Y)
case 0x7d: this.AbsoluteX(); this.ADC(); break; // ADC (absolute, X)
case 0x7e: this.AbsoluteXAddress(); this.FixupRead(); this.ROR(); break; // ROR (absolute, X)
case 0x81: this.IndexedIndirectXAddress(); this.STA(); break; // STA (indexed indirect X)
case 0x82: this.Immediate(); NOP(); break; // *NOP (immediate)
@@ -514,6 +512,7 @@ namespace M6502
if (this.RDY.Raised())
{
this.ImmediateInstruction = false;
this.OpCode = this.FetchInstruction();
if (this.RESET.Lowered())
{
@@ -709,7 +708,11 @@ namespace M6502
#region Address and read
protected void Immediate() => this.FetchByte();
protected void Immediate()
{
this.ImmediateInstruction = true;
this.FetchByte();
}
protected void Absolute()
{
@@ -908,26 +911,26 @@ namespace M6502
this.SetFlag(StatusBits.VF, NegativeTest((byte)((operand ^ data) & (operand ^ intermediate))));
}
protected void SBC()
protected virtual void SBC()
{
var operand = this.A;
this.A = this.SUB(operand, CarryTest((byte)~this.P));
this.AdjustOverflowSubtract(operand);
this.AdjustNZ(this.Intermediate.Low);
this.ResetFlag(StatusBits.CF, this.Intermediate.High);
this.PostSUB(operand);
//this.AdjustOverflowSubtract(operand);
//this.ResetFlag(StatusBits.CF, this.Intermediate.High);
}
private byte SUB(byte operand, int borrow) => this.DecimalMasked != 0 ? this.DecimalSUB(operand, borrow) : this.BinarySUB(operand, borrow);
private byte SUB(byte operand, int borrow) => this.Denary != 0 ? this.DecimalSUB(operand, borrow) : this.BinarySUB(operand, borrow);
protected byte BinarySUB(byte operand, int borrow = 0)
protected virtual byte BinarySUB(byte operand, int borrow = 0)
{
var data = this.Bus.Data;
this.Intermediate.Word = (ushort)(operand - data - borrow);
return this.Intermediate.Low;
}
private byte DecimalSUB(byte operand, int borrow)
protected virtual byte DecimalSUB(byte operand, int borrow)
{
this.BinarySUB(operand, borrow);
@@ -949,6 +952,12 @@ namespace M6502
return (byte)(PromoteNibble(high) | LowNibble(low));
}
protected virtual void PostSUB(byte operand)
{
this.AdjustOverflowSubtract(operand);
this.ResetFlag(StatusBits.CF, this.Intermediate.High);
}
#endregion
#region Addition
@@ -960,11 +969,11 @@ namespace M6502
this.SetFlag(StatusBits.VF, NegativeTest((byte)(~(operand ^ data) & (operand ^ intermediate))));
}
protected void ADC() => this.ADC(this.Bus.Data);
protected virtual void ADC() => this.ADC(this.Bus.Data);
protected void ADC(byte data) => this.A = this.DecimalMasked != 0 ? this.DecimalADC(data) : this.BinaryADC(data);
protected void ADC(byte data) => this.A = this.Denary != 0 ? this.DecimalADC(data) : this.BinaryADC(data);
private byte BinaryADC(byte data)
protected virtual byte BinaryADC(byte data)
{
var operand = this.A;
this.Intermediate.Word = (ushort)(operand + data + this.Carry);
@@ -972,12 +981,10 @@ namespace M6502
this.AdjustOverflowAdd(operand);
this.SetFlag(StatusBits.CF, CarryTest(this.Intermediate.High));
this.AdjustNZ(this.Intermediate.Low);
return this.Intermediate.Low;
}
private byte DecimalADC(byte data)
protected virtual byte DecimalADC(byte data)
{
var operand = this.A;
@@ -1025,11 +1032,13 @@ namespace M6502
protected void EOR(byte data) => this.A = this.Through(this.A ^ data);
protected void BitSet(byte mask) => this.AdjustZero((byte)(this.A & mask));
protected void BIT()
{
var data = this.Bus.Data;
this.SetFlag(StatusBits.VF, OverflowTest(data));
this.AdjustZero((byte)(this.A & data));
this.BitSet(data);
this.AdjustNegative(data);
}
+31 -1
View File
@@ -35,6 +35,7 @@ namespace M6502
case 0x1a: this.SwallowRead(); NOP(); break; // *NOP (implied)
case 0x1b: this.AbsoluteYAddress(); this.FixupRead(); this.SLO(); break; // *SLO (absolute, Y)
case 0x1c: this.AbsoluteXAddress(); this.MaybeFixupRead(); NOP(); break; // *NOP (absolute, X)
case 0x1e: this.AbsoluteXAddress(); this.FixupRead(); this.ASL(); break; // ASL (absolute, X)
case 0x1f: this.AbsoluteXAddress(); this.FixupRead(); this.SLO(); break; // *SLO (absolute, X)
case 0x22: this.SwallowRead(); this.JAM(); break; // *JAM
@@ -50,6 +51,7 @@ namespace M6502
case 0x3a: this.SwallowRead(); NOP(); break; // *NOP (implied)
case 0x3b: this.AbsoluteYAddress(); this.FixupRead(); this.RLA(); break; // *RLA (absolute, Y)
case 0x3c: this.AbsoluteXAddress(); this.MaybeFixupRead(); NOP(); break; // *NOP (absolute, X)
case 0x3e: this.AbsoluteXAddress(); this.FixupRead(); this.ROL(); break; // ROL (absolute, X)
case 0x3f: this.AbsoluteXAddress(); this.FixupRead(); this.RLA(); break; // *RLA (absolute, X)
case 0x42: this.SwallowRead(); this.JAM(); break; // *JAM
@@ -64,6 +66,7 @@ namespace M6502
case 0x5a: this.SwallowRead(); NOP(); break; // *NOP (implied)
case 0x5b: this.AbsoluteYAddress(); this.FixupRead(); this.SRE(); break; // *SRE (absolute, Y)
case 0x5c: this.AbsoluteXAddress(); this.MaybeFixupRead(); NOP(); break; // *NOP (absolute, X)
case 0x5e: this.AbsoluteXAddress(); this.FixupRead(); this.LSR(); break; // LSR (absolute, X)
case 0x5f: this.AbsoluteXAddress(); this.FixupRead(); this.SRE(); break; // *SRE (absolute, X)
case 0x62: this.SwallowRead(); this.JAM(); break; // *JAM
@@ -80,6 +83,7 @@ namespace M6502
case 0x7a: this.SwallowRead(); NOP(); break; // *NOP (implied)
case 0x7b: this.AbsoluteYAddress(); this.FixupRead(); this.RRA(); break; // *RRA (absolute, Y)
case 0x7c: this.AbsoluteXAddress(); this.MaybeFixupRead(); NOP(); break; // *NOP (absolute, X)
case 0x7e: this.AbsoluteXAddress(); this.FixupRead(); this.ROR(); break; // ROR (absolute, X)
case 0x7f: this.AbsoluteXAddress(); this.FixupRead(); this.RRA(); break; // *RRA (absolute, X)
case 0x80: this.FetchByte(); NOP(); break; // *NOP (immediate)
@@ -186,7 +190,7 @@ namespace M6502
private void ARR()
{
var value = this.Bus.Data;
if (this.DecimalMasked != 0)
if (this.Denary != 0)
this.ARR_d(value);
else
this.ARR_b(value);
@@ -335,6 +339,32 @@ namespace M6502
#endregion
#region Processor variations
protected override byte BinaryADC(byte data)
{
var returned = base.BinaryADC(data);
this.AdjustNZ(returned);
return returned;
}
protected override byte BinarySUB(byte operand, int borrow = 0)
{
var returned = base.BinarySUB(operand, borrow);
this.AdjustNZ(this.Intermediate.Low);
return returned;
}
protected override byte DecimalSUB(byte operand, int borrow)
{
var returned = base.DecimalSUB(operand, borrow);
this.AdjustNZ(this.Intermediate.Low);
return returned;
}
#endregion
#endregion
}
}
+183 -163
View File
@@ -1,4 +1,4 @@
// <copyright file="WDC65C02.cs" company="Adrian Conlon">
// <copyright file="WDC65C02.cs" company="Adrian Conlon">
// Copyright (c) Adrian Conlon. All rights reserved.
// </copyright>
@@ -41,6 +41,20 @@ namespace M6502
#endregion
#region Cycle wastage
private void SwallowFixup() => this.MemoryRead(this.lastFetchAddress);
private void SwallowSpin(int ticks = 1)
{
for (int i = 0; i < ticks; i++)
{
this.MemoryRead();
}
}
#endregion
#region Core instruction dispatching
protected override bool MaybeExecute()
@@ -53,125 +67,96 @@ namespace M6502
var cycles = this.Cycles;
switch (this.OpCode)
{
case 0x02: this.SwallowFetch(); break; // NOP
case 0x03: break; // null
case 0x04: this.ZeroPage(); this.TSB(); break; // TSB zp
case 0x07: this.ZeroPage(); this.RMB0(); break; // RMB0 zp
case 0x0b: break; // null
case 0x0c: this.Absolute(); this.TSB(); break; // TSB a
case 0x0f: this.ZeroPage(); this.BBR0(); break; // BBR0 r
case 0x02: this.SwallowFetch(); NOP(); break; // NOP (implied)
case 0x04: this.ZeroPage(); this.TSB(); break; // TSB (zero page)
case 0x07: this.ZeroPage(); this.RMB0(); break; // RMB0 (zero page)
case 0x0c: this.Absolute(); this.TSB(); break; // TSB (absolute)
case 0x0f: this.ZeroPage(); this.BBR0(); break; // BBR0 (zero page)
case 0x12: this.ZeroPageIndirect(); this.ORA(); break; // ORA (zp),y
case 0x13: break; // null
case 0x14: this.ZeroPage(); this.TRB(); break; // TRB zp
case 0x17: this.ZeroPage(); this.RMB1(); break; // RMB1 zp
case 0x1a: this.INCA(); break; // INC A
case 0x1b: break; // null
case 0x1c: this.Absolute(); this.TRB(); break; // TRB a
//case 0x1e: this.AbsoluteX(); this.ASL(); break; // ???
case 0x1f: this.ZeroPage(); this.BBR1(); break; // BBR1 r
case 0x12: this.ZeroPageIndirect(); this.ORA(); break; // ORA (zero page indirect)
case 0x14: this.ZeroPage(); this.TRB(); break; // TRB (zero page)
case 0x17: this.ZeroPage(); this.RMB1(); break; // RMB1 (zero page)
case 0x1a: this.SwallowRead(); this.INCA(); break; // INC A (implied)
case 0x1c: this.Absolute(); this.TRB(); break; // TRB (absolute)
case 0x1e: this.AbsoluteX(); this.ASL(); break; // ASL (absolute, X)
case 0x1f: this.ZeroPage(); this.BBR1(); break; // BBR1 (zero page)
case 0x22: this.SwallowFetch(); break; // NOP
case 0x23: break; // null
case 0x27: this.ZeroPage(); this.RMB2(); break; // RMB2 zp
case 0x2b: break; // null
case 0x2f: this.ZeroPage(); this.BBR2(); break; // BBR2 r
case 0x22: this.SwallowFetch(); NOP(); break; // NOP (implied)
case 0x27: this.ZeroPage(); this.RMB2(); break; // RMB2 (zero page)
case 0x2f: this.ZeroPage(); this.BBR2(); break; // BBR2 (zero page)
case 0x32: this.ZeroPageIndirect(); this.AND(); break; // AND (zp)
case 0x33: break; // null
case 0x34: ZeroPageX(); this.BIT(); break; // BIT zp,x
case 0x37: this.ZeroPage(); this.RMB3(); break; // RMB3 zp
case 0x3a: this.DECA(); break; // DEC A
case 0x3b: break; // null
case 0x3c: AbsoluteX(); BIT(); break; // BIT abs,x
//case 0x3e: break;// ????
case 0x3f: this.ZeroPage(); this.BBR3(); break; // BBR3 r
case 0x32: this.ZeroPageIndirect(); this.AND(); break; // AND (zero page indirect)
case 0x34: this.ZeroPageX(); this.BIT(); break; // BIT (zero page, X)
case 0x37: this.ZeroPage(); this.RMB3(); break; // RMB3 (zero page)
case 0x3a: this.SwallowRead(); this.DECA(); break; // DEC A (implied)
case 0x3c: this.AbsoluteX(); this.BIT(); break; // BIT (absolute, X)
case 0x3e: this.AbsoluteX(); this.ROL(); break; // ROL (absolute, X)
case 0x3f: this.ZeroPage(); this.BBR3(); break; // BBR3 (zero page)
case 0x42: this.SwallowFetch(); break; // NOP
case 0x43: break; // null
case 0x47: this.ZeroPage(); this.RMB4(); break; // RMB4 zp
case 0x4b: break; // null
case 0x4f: this.ZeroPage(); this.BBR4(); break; // BBR4 r
case 0x42: this.SwallowFetch(); NOP(); break; // NOP (implied)
case 0x47: this.ZeroPage(); this.RMB4(); break; // RMB4 (zero page)
case 0x4f: this.ZeroPage(); this.BBR4(); break; // BBR4 (zero page)
case 0x52: this.ZeroPageIndirect(); this.EOR(); break; // EOR (zp)
case 0x53: break; // null
case 0x54: this.ZeroPageX(); break; // zp,x NOP
case 0x57: this.ZeroPage(); this.RMB5(); break; // RMB5 zp
case 0x5a: this.PHY(); break; // PHY s
case 0x5b: break; // null
case 0x5c: this.SwallowFetch(); this.SwallowRead(); this.SwallowFetch(); break; // ???
//case 0x5e: break;// ????
case 0x5f: this.ZeroPage(); this.BBR5(); break; // BBR5 r
case 0x52: this.ZeroPageIndirect(); this.EOR(); break; // EOR (zero page indirect)
case 0x54: this.ZeroPageX(); NOP(); break; // NOP (zero page, X)
case 0x57: this.ZeroPage(); this.RMB5(); break; // RMB5 (zero page)
case 0x5a: this.SwallowRead(); this.PHY(); break; // PHY (implied)
case 0x5c: this.AbsoluteAddress(); this.SwallowFixup(); NOP(); break; // NOP (absolute)
case 0x5e: this.AbsoluteX(); this.LSR(); break; // LSR (absolute, X)
case 0x5f: this.ZeroPage(); this.BBR5(); break; // BBR5 (zero page)
case 0x62: this.SwallowFetch(); break; // *NOP
case 0x63: break; // null
case 0x64: this.ZeroPageAddress(); this.STZ(); break; // STZ zp
case 0x67: this.ZeroPage(); this.RMB6(); break; // RMB6 zp
case 0x6b: break; // null
case 0x6f: this.ZeroPage(); this.BBR6(); break; // BBR6 r
case 0x62: this.SwallowFetch(); NOP(); break; // NOP (implied)
case 0x64: this.ZeroPageAddress(); this.STZ(); break; // STZ (zero page)
case 0x67: this.ZeroPage(); this.RMB6(); break; // RMB6 (zero page)
case 0x6f: this.ZeroPage(); this.BBR6(); break; // BBR6 (zero page)
case 0x72: this.ZeroPageIndirect(); this.ADC(); break; // ADC (zp)
case 0x73: break; // null
case 0x74: this.ZeroPageXAddress(); this.STZ(); break; // STZ zp,x
case 0x77: this.ZeroPage(); this.RMB7(); break; // RMB7 zp
case 0x7a: this.PLY(); break; // PLY s
case 0x7b: break; // null
case 0x7c: this.AbsoluteXAddress(); this.JumpIndirect(); break; // JMP (a,x)
case 0x7f: this.ZeroPage(); this.BBR7(); break; // BBR7 r
case 0x72: this.ZeroPageIndirect(); this.ADC(); break; // ADC (zero page indirect)
case 0x74: this.ZeroPageXAddress(); this.STZ(); break; // STZ (zero page, X)
case 0x77: this.ZeroPage(); this.RMB7(); break; // RMB7 (zero page)
case 0x7a: this.SwallowRead(); this.PLY(); break; // PLY (implied)
case 0x7c: this.AbsoluteXIndirectAddress(); JMP(); break; // JMP (absolute, X indirect)
case 0x7e: this.AbsoluteX(); this.ROR(); break; // ROR (absolute, X)
case 0x7f: this.ZeroPage(); this.BBR7(); break; // BBR7 (zero page)
case 0x80: this.BRA(); break; // BRA r
case 0x83: break; // null
case 0x87: this.ZeroPage(); this.SMB0(); break; // SMB0 zp
case 0x89: this.Immediate(); this.BIT_immediate(); break; // BIT # (TBC)
case 0x8b: break; // null
case 0x8f: this.ZeroPage(); this.BBS0(); break; // BBS0 r
case 0x80: this.Immediate(); this.BRA(); break; // BRA (immediate)
case 0x87: this.ZeroPage(); this.SMB0(); break; // SMB0 (zero page)
case 0x89: this.Immediate(); this.BIT_immediate(); break; // BIT (immediate)
case 0x8f: this.ZeroPage(); this.BBS0(); break; // BBS0 (zero page)
case 0x92: this.ZeroPageIndirectAddress(); this.STA(); break; // STA (zp)
case 0x93: break; // null
case 0x97: this.ZeroPage(); this.SMB1(); break; // SMB1 zp
case 0x9b: break; // null
case 0x9c: this.AbsoluteAddress(); this.STZ(); break; // STZ a
case 0x9e: this.AbsoluteXAddress(); this.Fixup(); this.STZ(); break; // STZ a,x
case 0x9f: this.ZeroPage(); this.BBS1(); break; // BBS1 r
case 0x92: this.ZeroPageIndirectAddress(); this.STA(); break; // STA (zero page indirect)
case 0x97: this.ZeroPage(); this.SMB1(); break; // SMB1 (zero page)
case 0x9c: this.AbsoluteAddress(); this.STZ(); break; // STZ (absolute)
case 0x9e: this.AbsoluteXAddress(); this.Fixup(); this.STZ(); break; // STZ (absolute, X)
case 0x9f: this.ZeroPage(); this.BBS1(); break; // BBS1 (zero page)
case 0xa3: break; // null
case 0xa7: this.ZeroPage(); this.SMB2(); break; // SMB2 zp
case 0xab: break; // null
case 0xaf: this.ZeroPage(); this.BBS2(); break; // BBS2 r
case 0xa7: this.ZeroPage(); this.SMB2(); break; // SMB2 (zero page)
case 0xaf: this.ZeroPage(); this.BBS2(); break; // BBS2 (zero page)
case 0xb2: this.ZeroPageIndirect(); this.LDA(); break; // LDA (zp)
case 0xb3: break; // null
case 0xb7: this.ZeroPage(); this.SMB3(); break; // SMB3 zp
case 0xbb: break; // null
case 0xbf: this.ZeroPage(); this.BBS3(); break; // BBS3 r
case 0xb2: this.ZeroPageIndirect(); this.LDA(); break; // LDA (zero page indirect)
case 0xb7: this.ZeroPage(); this.SMB3(); break; // SMB3 (zero page)
case 0xbf: this.ZeroPage(); this.BBS3(); break; // BBS3 (zero page)
case 0xc3: break; // null
case 0xc7: this.ZeroPage(); this.SMB4(); break; // SMB4 zp
case 0xcb: this.WAI(); break; // WAI i
case 0xcf: this.ZeroPage(); this.BBS4(); break; // BBS4 r
case 0xc7: this.ZeroPage(); this.SMB4(); break; // SMB4 (zero page)
case 0xcb: this.SwallowRead(); this.WAI(); break; // WAI (implied)
case 0xcf: this.ZeroPage(); this.BBS4(); break; // BBS4 (zero page)
case 0xd2: this.ZeroPageIndirect(); this.CMP(); break; // CMP (zp)
case 0xd3: break; // null
case 0xd4: this.ZeroPageX(); break; // zp,x NOP
case 0xd7: this.ZeroPage(); this.SMB5(); break; // SMB5 zp
case 0xda: this.PHX(); break; // PHX s
case 0xdb: this.STP(); break; // STP i
case 0xdc: this.Absolute(); break; // null
case 0xdf: this.ZeroPage(); this.BBS5(); break; // BBS5 r
case 0xd2: this.ZeroPageIndirect(); this.CMP(); break; // CMP (zero page indirect)
case 0xd4: this.ZeroPageX(); NOP(); break; // NOP (zero page, X)
case 0xd7: this.ZeroPage(); this.SMB5(); break; // SMB5 (zero page)
case 0xda: this.SwallowRead(); this.PHX(); break; // PHX (implied)
case 0xdb: this.SwallowRead(); this.STP(); break; // STP (implied)
case 0xdc: this.AbsoluteAddress(); this.SwallowFixup(); NOP(); break; // NOP (absolute)
case 0xdf: this.ZeroPage(); this.BBS5(); break; // BBS5 (zero page)
case 0xe3: break; // null
case 0xe7: this.ZeroPage(); this.SMB6(); break; // SMB6 zp
case 0xeb: break; // null
case 0xef: this.ZeroPage(); this.BBS6(); break; // BBS6 r
case 0xe7: this.ZeroPage(); this.SMB6(); break; // SMB6 (zero page)
case 0xef: this.ZeroPage(); this.BBS6(); break; // BBS6 (zero page)
case 0xf2: this.ZeroPageIndirect(); this.SBC(); break; // SBC (zp)
case 0xf3: break; // null
case 0xf4: this.ZeroPageX(); break; // zp,x NOP
case 0xf7: this.ZeroPage(); this.SMB7(); break; // SMB7 zp
case 0xfa: this.PLX(); break; // PLX s
case 0xfb: break; // null
case 0xfc: break; // null
case 0xff: this.ZeroPage(); this.BBS7(); break; // BBS7 r
case 0xf2: this.ZeroPageIndirect(); this.SBC(); break; // SBC (zero page indirect)
case 0xf4: this.ZeroPageX(); NOP(); break; // NOP (zero page, X)
case 0xf7: this.ZeroPage(); this.SMB7(); break; // SMB7 (zero page)
case 0xfa: this.SwallowRead(); this.PLX(); break; // PLX (implied)
case 0xfc: this.AbsoluteAddress(); this.SwallowFixup(); NOP(); break; // NOP (absolute)
case 0xff: this.ZeroPage(); this.BBS7(); break; // BBS7 (zero page)
}
return cycles != this.Cycles;
@@ -207,7 +192,7 @@ namespace M6502
protected override void ModifyWrite(byte data)
{
// The read will have already taken place...
this.MemoryRead(); // Modify cycle (Change from MOS6502)
this.SwallowSpin(); // Modify cycle (Change from MOS6502)
this.MemoryWrite(data); // Write cycle
}
@@ -228,7 +213,7 @@ namespace M6502
protected override void Fixup()
{
var fixingLow = this.Bus.Address.Low;
this.MemoryRead(this.lastFetchAddress);
this.SwallowFixup();
this.Bus.Address.Assign(fixingLow, this.FixedPage);
}
@@ -262,6 +247,17 @@ namespace M6502
this.GetAddress();
}
private void AbsoluteXIndirectAddress()
{
var current = this.PC.Word;
this.AbsoluteXAddress();
this.Bus.Address.Word = current;
this.SwallowSpin();
this.Bus.Address.Assign(this.Intermediate);
this.GetInto(this.Intermediate);
this.Bus.Address.Assign(this.Intermediate);
}
#endregion
#region Address and read
@@ -276,91 +272,122 @@ namespace M6502
#endregion
private void BIT_immediate()
#region Processor variations
protected override byte BinaryADC(byte data)
{
this.AdjustZero((byte)(this.A & this.Bus.Data));
var returned = base.BinaryADC(data);
this.AdjustNZ(returned);
return returned;
}
private void INCA()
protected override byte DecimalADC(byte data)
{
this.SwallowRead();
this.A = this.INC(this.A);
var returned = base.DecimalADC(data);
this.AdjustNZ(returned);
if (this.ImmediateInstruction)
{
this.MemoryRead(0x7f, 0x00);
}
else
{
this.SwallowSpin();
}
return returned;
}
private void DECA()
protected override void SBC()
{
this.SwallowRead();
this.A = this.DEC(this.A);
base.SBC();
if (this.Denary != 0)
{
this.AdjustNZ(this.A);
if (this.ImmediateInstruction)
this.MemoryRead(0x00, 0x00);
else
this.SwallowSpin();
}
}
private void PHX()
protected override byte BinarySUB(byte operand, int borrow = 0)
{
this.SwallowRead();
this.Push(this.X);
var returned = base.BinarySUB(operand, borrow);
this.AdjustNZ(this.Intermediate.Low);
return returned;
}
protected override byte DecimalSUB(byte operand, int borrow)
{
base.BinarySUB(operand, borrow);
var data = this.Bus.Data;
var result = this.Intermediate.Low;
var loBorrow = (LowNibble(operand) < LowNibble(data) + borrow) ? 1 : 0;
if (loBorrow != 0)
{
result -= 6;
}
if (HighNibble(operand) < HighNibble(data) + loBorrow)
{
result -= 0x60;
}
return result;
}
#endregion
private void BIT_immediate() => this.BitSet(this.Bus.Data);
private void INCA() => this.A = this.INC(this.A);
private void DECA() => this.A = this.DEC(this.A);
private void PHX() => this.Push(this.X);
private void PLX()
{
this.SwallowRead();
this.SwallowPop();
this.X = this.Through(this.Pop());
}
private void PHY()
{
this.SwallowRead();
this.Push(this.Y);
}
private void PHY() => this.Push(this.Y);
private void PLY()
{
this.SwallowRead();
this.SwallowPop();
this.Y = this.Through(this.Pop());
}
private void JumpIndirect()
{
this.Bus.Address.Assign(this.Intermediate);
this.GetAddressPaged();
this.JMP();
}
private void BRA() => this.Branch(true);
private void WAI()
{
this.SwallowRead();
this.Waiting = true;
}
private void WAI() => this.Waiting = true;
private void STP()
{
this.SwallowRead();
this.Stopped = true;
}
private void STP() => this.Stopped = true;
private void STZ() => this.MemoryWrite(0);
private void RMB0() => this.RMB(Bit(0));
private void RMB1() => this.RMB(Bit(1));
private void RMB2() => this.RMB(Bit(2));
private void RMB3() => this.RMB(Bit(3));
private void RMB4() => this.RMB(Bit(4));
private void RMB5() => this.RMB(Bit(5));
private void RMB6() => this.RMB(Bit(6));
private void RMB7() => this.RMB(Bit(7));
private void RMB(byte flag)
{
this.MemoryRead();
this.SwallowSpin();
this.Bus.Data &= (byte)~flag;
this.MemoryWrite();
}
@@ -383,13 +410,14 @@ namespace M6502
private void SMB(byte flag)
{
this.MemoryRead();
this.SwallowSpin();
this.Bus.Data |= flag;
this.MemoryWrite();
}
private void BranchBit(bool condition)
{
this.SwallowSpin();
this.FetchByte();
if (condition)
{
@@ -420,11 +448,7 @@ namespace M6502
private void BBS7() => this.BBS(Bit(7));
private void BBS(byte flag)
{
this.MemoryRead();
this.BranchBit((this.Bus.Data & flag) != 0);
}
private void BBS(byte flag) => this.BranchBit((this.Bus.Data & flag) != 0);
private void BBR0() => this.BBR(Bit(0));
private void BBR1() => this.BBR(Bit(1));
@@ -435,21 +459,17 @@ namespace M6502
private void BBR6() => this.BBR(Bit(6));
private void BBR7() => this.BBR(Bit(7));
private void BBR(byte flag)
{
this.MemoryRead();
this.BranchBit((this.Bus.Data & flag) == 0);
}
private void BBR(byte flag) => this.BranchBit((this.Bus.Data & flag) == 0);
private void TSB()
{
this.AdjustZero((byte)(this.A & this.Bus.Data));
this.BitSet(this.Bus.Data);
this.ModifyWrite((byte)(this.A | this.Bus.Data));
}
private void TRB()
{
this.AdjustZero((byte)(this.A & this.Bus.Data));
this.BitSet(this.Bus.Data);
this.ModifyWrite((byte)(~this.A & this.Bus.Data));
}
}