Apply .net 9 analysis

This commit is contained in:
Adrian Conlon
2024-10-12 10:20:29 +01:00
parent a3fd5b055a
commit 515c679e68
20 changed files with 1095 additions and 1118 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,9 @@
namespace M6502 namespace M6502
{ {
using EightBit;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using EightBit;
public class Disassembler(Bus bus, Core processor, Symbols.Parser symbols) public class Disassembler(Bus bus, Core processor, Symbols.Parser symbols)
{ {
@@ -35,16 +35,16 @@ namespace M6502
public string Disassemble(ushort current) public string Disassemble(ushort current)
{ {
address = current; this.address = current;
var output = new StringBuilder(); var output = new StringBuilder();
var cell = bus.Peek(current); var cell = this.bus.Peek(current);
output.Append(DumpByteValue(cell)); output.Append(DumpByteValue(cell));
output.Append(' '); output.Append(' ');
var next = bus.Peek((ushort)(current + 1)); var next = this.bus.Peek((ushort)(current + 1));
var relative = (ushort)(current + 2 + (sbyte)next); var relative = (ushort)(current + 2 + (sbyte)next);
var aaa = (cell & 0b11100000) >> 5; var aaa = (cell & 0b11100000) >> 5;
@@ -60,28 +60,28 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b000: // BRK case 0b000: // BRK
output.Append(Disassemble_Implied("BRK")); output.Append(this.Disassemble_Implied("BRK"));
break; break;
case 0b001: // DOP/NOP (0x04) case 0b001: // DOP/NOP (0x04)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b010: // PHP case 0b010: // PHP
output.Append(Disassemble_Implied("PHP")); output.Append(this.Disassemble_Implied("PHP"));
break; break;
case 0b011: // TOP/NOP (0b00001100, 0x0c) case 0b011: // TOP/NOP (0b00001100, 0x0c)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b100: // BPL case 0b100: // BPL
output.Append(Disassemble_Relative("BPL", relative)); output.Append(this.Disassemble_Relative("BPL", relative));
break; break;
case 0b101: // DOP/NOP (0x14) case 0b101: // DOP/NOP (0x14)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b110: // CLC case 0b110: // CLC
output.Append(Disassemble_Implied("CLC")); output.Append(this.Disassemble_Implied("CLC"));
break; break;
case 0b111: // TOP/NOP (0b00011100, 0x1c) case 0b111: // TOP/NOP (0b00011100, 0x1c)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
default: default:
throw new InvalidOperationException("Illegal instruction"); throw new InvalidOperationException("Illegal instruction");
@@ -92,25 +92,25 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b000: // JSR case 0b000: // JSR
output.Append(Disassemble_Absolute("JSR")); output.Append(this.Disassemble_Absolute("JSR"));
break; break;
case 0b010: // PLP case 0b010: // PLP
output.Append(Disassemble_Implied("PLP")); output.Append(this.Disassemble_Implied("PLP"));
break; break;
case 0b100: // BMI case 0b100: // BMI
output.Append(Disassemble_Relative("BMI", relative)); output.Append(this.Disassemble_Relative("BMI", relative));
break; break;
case 0b101: // DOP/NOP (0x34) case 0b101: // DOP/NOP (0x34)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b110: // SEC case 0b110: // SEC
output.Append(Disassemble_Implied("SEC")); output.Append(this.Disassemble_Implied("SEC"));
break; break;
case 0b111: // TOP/NOP (0b00111100, 0x3c) case 0b111: // TOP/NOP (0b00111100, 0x3c)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
default: // BIT default: // BIT
output.Append(Disassemble_AM_00(bbb, "BIT")); output.Append(this.Disassemble_AM_00(bbb, "BIT"));
break; break;
} }
@@ -119,28 +119,28 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b000: // RTI case 0b000: // RTI
output.Append(Disassemble_Implied("RTI")); output.Append(this.Disassemble_Implied("RTI"));
break; break;
case 0b001: // DOP/NOP (0x44) case 0b001: // DOP/NOP (0x44)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b010: // PHA case 0b010: // PHA
output.Append(Disassemble_Implied("PHA")); output.Append(this.Disassemble_Implied("PHA"));
break; break;
case 0b011: // JMP case 0b011: // JMP
output.Append(Disassemble_Absolute("JMP")); output.Append(this.Disassemble_Absolute("JMP"));
break; break;
case 0b100: // BVC case 0b100: // BVC
output.Append(Disassemble_Relative("BVC", relative)); output.Append(this.Disassemble_Relative("BVC", relative));
break; break;
case 0b101: // DOP/NOP (0x54) case 0b101: // DOP/NOP (0x54)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b110: // CLI case 0b110: // CLI
output.Append(Disassemble_Implied("CLI")); output.Append(this.Disassemble_Implied("CLI"));
break; break;
case 0b111: // TOP/NOP (0b01011100, 0x5c) case 0b111: // TOP/NOP (0b01011100, 0x5c)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
default: default:
throw new InvalidOperationException("Illegal addressing mode"); throw new InvalidOperationException("Illegal addressing mode");
@@ -151,28 +151,28 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b000: // RTS case 0b000: // RTS
output.Append(Disassemble_Implied("RTS")); output.Append(this.Disassemble_Implied("RTS"));
break; break;
case 0b001: // DOP/NOP (0x64) case 0b001: // DOP/NOP (0x64)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b010: // PLA case 0b010: // PLA
output.Append(Disassemble_Implied("PLA")); output.Append(this.Disassemble_Implied("PLA"));
break; break;
case 0b011: // JMP (abs) case 0b011: // JMP (abs)
output.Append(Disassemble_Indirect("JMP")); output.Append(this.Disassemble_Indirect("JMP"));
break; break;
case 0b100: // BVS case 0b100: // BVS
output.Append(Disassemble_Relative("BVS", relative)); output.Append(this.Disassemble_Relative("BVS", relative));
break; break;
case 0b101: // DOP/NOP (0x74) case 0b101: // DOP/NOP (0x74)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b110: // SEI case 0b110: // SEI
output.Append(Disassemble_Implied("SEI")); output.Append(this.Disassemble_Implied("SEI"));
break; break;
case 0b111: // TOP/NOP (0b01111100, 0x7c) case 0b111: // TOP/NOP (0b01111100, 0x7c)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
default: default:
throw new InvalidOperationException("Illegal addressing mode"); throw new InvalidOperationException("Illegal addressing mode");
@@ -183,19 +183,19 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b000: // DOP/NOP (0x80) case 0b000: // DOP/NOP (0x80)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b010: // DEY case 0b010: // DEY
output.Append(Disassemble_Implied("DEY")); output.Append(this.Disassemble_Implied("DEY"));
break; break;
case 0b100: // BCC case 0b100: // BCC
output.Append(Disassemble_Relative("BCC", relative)); output.Append(this.Disassemble_Relative("BCC", relative));
break; break;
case 0b110: // TYA case 0b110: // TYA
output.Append(Disassemble_Implied("TYA")); output.Append(this.Disassemble_Implied("TYA"));
break; break;
default: // STY default: // STY
output.Append(Disassemble_AM_00(bbb, "STY")); output.Append(this.Disassemble_AM_00(bbb, "STY"));
break; break;
} }
@@ -204,16 +204,16 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: // TAY case 0b010: // TAY
output.Append(Disassemble_Implied("TAY")); output.Append(this.Disassemble_Implied("TAY"));
break; break;
case 0b100: // BCS case 0b100: // BCS
output.Append(Disassemble_Relative("BCS", relative)); output.Append(this.Disassemble_Relative("BCS", relative));
break; break;
case 0b110: // CLV case 0b110: // CLV
output.Append(Disassemble_Implied("CLV")); output.Append(this.Disassemble_Implied("CLV"));
break; break;
default: // LDY default: // LDY
output.Append(Disassemble_AM_00(bbb, "LDY")); output.Append(this.Disassemble_AM_00(bbb, "LDY"));
break; break;
} }
@@ -222,22 +222,22 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: // INY case 0b010: // INY
output.Append(Disassemble_Implied("INY")); output.Append(this.Disassemble_Implied("INY"));
break; break;
case 0b100: // BNE case 0b100: // BNE
output.Append(Disassemble_Relative("BNE", relative)); output.Append(this.Disassemble_Relative("BNE", relative));
break; break;
case 0b101: // DOP/NOP (0xd4) case 0b101: // DOP/NOP (0xd4)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b110: // CLD case 0b110: // CLD
output.Append(Disassemble_Implied("CLD")); output.Append(this.Disassemble_Implied("CLD"));
break; break;
case 0b111: // TOP/NOP (0b11011100, 0xdc) case 0b111: // TOP/NOP (0b11011100, 0xdc)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
default: // CPY default: // CPY
output.Append(Disassemble_AM_00(bbb, "CPY")); output.Append(this.Disassemble_AM_00(bbb, "CPY"));
break; break;
} }
@@ -246,22 +246,22 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: // INX case 0b010: // INX
output.Append(Disassemble_Implied("INX")); output.Append(this.Disassemble_Implied("INX"));
break; break;
case 0b100: // BEQ case 0b100: // BEQ
output.Append(Disassemble_Relative("BEQ", relative)); output.Append(this.Disassemble_Relative("BEQ", relative));
break; break;
case 0b101: // DOP/NOP (0xf4) case 0b101: // DOP/NOP (0xf4)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
case 0b110: // SED case 0b110: // SED
output.Append(Disassemble_Implied("SED")); output.Append(this.Disassemble_Implied("SED"));
break; break;
case 0b111: // TOP/NOP (0b11111100, 0xfc) case 0b111: // TOP/NOP (0b11111100, 0xfc)
output.Append(Disassemble_AM_00(bbb, "*NOP")); output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
break; break;
default: // CPX default: // CPX
output.Append(Disassemble_AM_00(bbb, "CPX")); output.Append(this.Disassemble_AM_00(bbb, "CPX"));
break; break;
} }
@@ -273,28 +273,28 @@ namespace M6502
switch (aaa) switch (aaa)
{ {
case 0b000: // ORA case 0b000: // ORA
output.Append(Disassemble_AM_01(bbb, "ORA")); output.Append(this.Disassemble_AM_01(bbb, "ORA"));
break; break;
case 0b001: // AND case 0b001: // AND
output.Append(Disassemble_AM_01(bbb, "AND")); output.Append(this.Disassemble_AM_01(bbb, "AND"));
break; break;
case 0b010: // EOR case 0b010: // EOR
output.Append(Disassemble_AM_01(bbb, "EOR")); output.Append(this.Disassemble_AM_01(bbb, "EOR"));
break; break;
case 0b011: // ADC case 0b011: // ADC
output.Append(Disassemble_AM_01(bbb, "ADC")); output.Append(this.Disassemble_AM_01(bbb, "ADC"));
break; break;
case 0b100: // STA case 0b100: // STA
output.Append(Disassemble_AM_01(bbb, "STA")); output.Append(this.Disassemble_AM_01(bbb, "STA"));
break; break;
case 0b101: // LDA case 0b101: // LDA
output.Append(Disassemble_AM_01(bbb, "LDA")); output.Append(this.Disassemble_AM_01(bbb, "LDA"));
break; break;
case 0b110: // CMP case 0b110: // CMP
output.Append(Disassemble_AM_01(bbb, "CMP")); output.Append(this.Disassemble_AM_01(bbb, "CMP"));
break; break;
case 0b111: // SBC case 0b111: // SBC
output.Append(Disassemble_AM_01(bbb, "SBC")); output.Append(this.Disassemble_AM_01(bbb, "SBC"));
break; break;
default: default:
throw new InvalidOperationException("Illegal addressing mode"); throw new InvalidOperationException("Illegal addressing mode");
@@ -308,10 +308,10 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b110: // 0x1a case 0b110: // 0x1a
output.Append(Disassemble_Implied("*NOP")); output.Append(this.Disassemble_Implied("*NOP"));
break; break;
default: default:
output.Append(Disassemble_AM_10(bbb, "ASL")); output.Append(this.Disassemble_AM_10(bbb, "ASL"));
break; break;
} }
@@ -320,10 +320,10 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b110: // 0x3a case 0b110: // 0x3a
output.Append(Disassemble_Implied("*NOP")); output.Append(this.Disassemble_Implied("*NOP"));
break; break;
default: default:
output.Append(Disassemble_AM_10(bbb, "ROL")); output.Append(this.Disassemble_AM_10(bbb, "ROL"));
break; break;
} }
@@ -332,10 +332,10 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b110: // 0x5a case 0b110: // 0x5a
output.Append(Disassemble_Implied("*NOP")); output.Append(this.Disassemble_Implied("*NOP"));
break; break;
default: default:
output.Append(Disassemble_AM_10(bbb, "LSR")); output.Append(this.Disassemble_AM_10(bbb, "LSR"));
break; break;
} }
@@ -344,10 +344,10 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b110: // 0x7a case 0b110: // 0x7a
output.Append(Disassemble_Implied("*NOP")); output.Append(this.Disassemble_Implied("*NOP"));
break; break;
default: default:
output.Append(Disassemble_AM_10(bbb, "ROR")); output.Append(this.Disassemble_AM_10(bbb, "ROR"));
break; break;
} }
@@ -356,13 +356,13 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: // TXA case 0b010: // TXA
output.Append(Disassemble_Implied("TXA")); output.Append(this.Disassemble_Implied("TXA"));
break; break;
case 0b110: // TXS case 0b110: // TXS
output.Append(Disassemble_Implied("TXS")); output.Append(this.Disassemble_Implied("TXS"));
break; break;
default: // STX default: // STX
output.Append(Disassemble_AM_10_x(bbb, "STX")); output.Append(this.Disassemble_AM_10_x(bbb, "STX"));
break; break;
} }
@@ -371,13 +371,13 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: // TAX case 0b010: // TAX
output.Append(Disassemble_Implied("TAX")); output.Append(this.Disassemble_Implied("TAX"));
break; break;
case 0b110: // TSX case 0b110: // TSX
output.Append(Disassemble_Implied("TSX")); output.Append(this.Disassemble_Implied("TSX"));
break; break;
default: // LDX default: // LDX
output.Append(Disassemble_AM_10_x(bbb, "LDX")); output.Append(this.Disassemble_AM_10_x(bbb, "LDX"));
break; break;
} }
@@ -386,13 +386,13 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: // DEX case 0b010: // DEX
output.Append(Disassemble_Implied("DEX")); output.Append(this.Disassemble_Implied("DEX"));
break; break;
case 0b110: // 0xda case 0b110: // 0xda
output.Append(Disassemble_Implied("*NOP")); output.Append(this.Disassemble_Implied("*NOP"));
break; break;
default: // DEC default: // DEC
output.Append(Disassemble_AM_10(bbb, "DEC")); output.Append(this.Disassemble_AM_10(bbb, "DEC"));
break; break;
} }
@@ -401,13 +401,13 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: // NOP case 0b010: // NOP
output.Append(Disassemble_Implied("NOP")); output.Append(this.Disassemble_Implied("NOP"));
break; break;
case 0b110: // 0xfa case 0b110: // 0xfa
output.Append(Disassemble_Implied("*NOP")); output.Append(this.Disassemble_Implied("*NOP"));
break; break;
default: // INC default: // INC
output.Append(Disassemble_AM_10(bbb, "INC")); output.Append(this.Disassemble_AM_10(bbb, "INC"));
break; break;
} }
@@ -424,10 +424,10 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: case 0b010:
output.Append(Disassemble_Immediate("*AAC")); output.Append(this.Disassemble_Immediate("*AAC"));
break; break;
default: default:
output.Append(Disassemble_AM_01(bbb, "*SLO")); output.Append(this.Disassemble_AM_01(bbb, "*SLO"));
break; break;
} }
@@ -437,28 +437,28 @@ namespace M6502
switch (bbb) switch (bbb)
{ {
case 0b010: case 0b010:
output.Append(Disassemble_Immediate("*AAC")); output.Append(this.Disassemble_Immediate("*AAC"));
break; break;
default: default:
output.Append(Disassemble_AM_01(bbb, "*RLA")); output.Append(this.Disassemble_AM_01(bbb, "*RLA"));
break; break;
} }
break; break;
case 0b010: case 0b010:
output.Append(Disassemble_AM_01(bbb, "*SRE")); output.Append(this.Disassemble_AM_01(bbb, "*SRE"));
break; break;
case 0b011: case 0b011:
output.Append(Disassemble_AM_01(bbb, "*RRA")); output.Append(this.Disassemble_AM_01(bbb, "*RRA"));
break; break;
case 0b100: case 0b100:
output.Append(Disassemble_AM_11(bbb, "*SAX")); output.Append(this.Disassemble_AM_11(bbb, "*SAX"));
break; break;
case 0b101: case 0b101:
output.Append(Disassemble_AM_11(bbb, "*LAX")); output.Append(this.Disassemble_AM_11(bbb, "*LAX"));
break; break;
case 0b110: case 0b110:
output.Append(Disassemble_AM_11_x(bbb, "*DCP")); output.Append(this.Disassemble_AM_11_x(bbb, "*DCP"));
break; break;
case 0b111: case 0b111:
switch (bbb) switch (bbb)
@@ -470,10 +470,10 @@ namespace M6502
case 0b101: case 0b101:
case 0b110: case 0b110:
case 0b111: case 0b111:
output.Append(Disassemble_AM_01(bbb, "*ISB")); output.Append(this.Disassemble_AM_01(bbb, "*ISB"));
break; break;
case 0b010: case 0b010:
output.Append(Disassemble_AM_11(bbb, "*SBC")); output.Append(this.Disassemble_AM_11(bbb, "*SBC"));
break; break;
default: default:
throw new InvalidOperationException("Impossible addressing mode"); throw new InvalidOperationException("Impossible addressing mode");
@@ -496,27 +496,27 @@ namespace M6502
#region Label conversions #region Label conversions
private string ConvertAddressAt(ushort absolute) => ConvertAddress(GetWord(absolute)); private string ConvertAddressAt(ushort absolute) => this.ConvertAddress(this.GetWord(absolute));
private string ConvertAddress(ushort absolute) => TryGetLabel(absolute, out var label) ? label : "$" + DumpWordValue(absolute); private string ConvertAddress(ushort absolute) => this.TryGetLabel(absolute, out var label) ? label : "$" + DumpWordValue(absolute);
private string ConvertZPAddressAt(ushort absolute) => ConvertZPAddress(GetByte(absolute)); private string ConvertZPAddressAt(ushort absolute) => this.ConvertZPAddress(this.GetByte(absolute));
private string ConvertZPAddress(byte absolute) => TryGetLabel(absolute, out var label) ? label : "$" + DumpByteValue(absolute); private string ConvertZPAddress(byte absolute) => this.TryGetLabel(absolute, out var label) ? label : "$" + DumpByteValue(absolute);
private bool TryGetLabel(ushort absolute, out string name) private bool TryGetLabel(ushort absolute, out string name)
{ {
return symbols.TryGetQualifiedLabelByAddress(absolute, out name); return this.symbols.TryGetQualifiedLabelByAddress(absolute, out name);
} }
private string MaybeGetLabel(ushort absolute) private string MaybeGetLabel(ushort absolute)
{ {
return symbols.MaybeGetQualifiedLabelByAddress(absolute); return this.symbols.MaybeGetQualifiedLabelByAddress(absolute);
} }
private string MaybeGetCodeLabel(ushort absolute) private string MaybeGetCodeLabel(ushort absolute)
{ {
var label = MaybeGetLabel(absolute); var label = this.MaybeGetLabel(absolute);
if (string.IsNullOrEmpty(label)) if (string.IsNullOrEmpty(label))
{ {
return string.Empty; return string.Empty;
@@ -526,7 +526,7 @@ namespace M6502
private string MaybeGetCodeLabel() private string MaybeGetCodeLabel()
{ {
return Pad(MaybeGetCodeLabel(address), 30); return Pad(this.MaybeGetCodeLabel(this.address), 30);
} }
#endregion #endregion
@@ -535,46 +535,46 @@ namespace M6502
private bool TryGetConstant(ushort value, out string name) private bool TryGetConstant(ushort value, out string name)
{ {
return symbols.TryGetQualifiedEquateValue(value, out name); return this.symbols.TryGetQualifiedEquateValue(value, out name);
} }
private string ConvertConstantByte(ushort address) => ConvertConstant(GetByte(address)); private string ConvertConstantByte(ushort address) => this.ConvertConstant(this.GetByte(address));
private string ConvertConstant(byte constant) => TryGetConstant(constant, out var label) ? label : "$" + DumpByteValue(constant); private string ConvertConstant(byte constant) => this.TryGetConstant(constant, out var label) ? label : "$" + DumpByteValue(constant);
#endregion #endregion
#endregion #endregion
private byte GetByte(ushort absolute) => bus.Peek(absolute); private byte GetByte(ushort absolute) => this.bus.Peek(absolute);
private ushort GetWord(ushort absolute) => processor.PeekWord(absolute).Word; private ushort GetWord(ushort absolute) => this.processor.PeekWord(absolute).Word;
private string Dump_Byte(ushort absolute) => DumpByteValue(GetByte(absolute)); private string Dump_Byte(ushort absolute) => DumpByteValue(this.GetByte(absolute));
private string Dump_DByte(ushort absolute) => Dump_Byte(absolute) + " " + Dump_Byte(++absolute); private string Dump_DByte(ushort absolute) => this.Dump_Byte(absolute) + " " + this.Dump_Byte(++absolute);
private string Disassemble_Implied(string instruction) => $"{Pad()}\t{MaybeGetCodeLabel()}" + instruction; private string Disassemble_Implied(string instruction) => $"{Pad()}\t{this.MaybeGetCodeLabel()}" + instruction;
private string Disassemble_Absolute(string instruction) => AM_Absolute_dump() + $"\t{MaybeGetCodeLabel()}" + instruction + " " + AM_Absolute(); private string Disassemble_Absolute(string instruction) => this.AM_Absolute_dump() + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.AM_Absolute();
private string Disassemble_Indirect(string instruction) => AM_Absolute_dump() + $"\t{MaybeGetCodeLabel()}" + instruction + " (" + AM_Absolute() + ")"; private string Disassemble_Indirect(string instruction) => this.AM_Absolute_dump() + $"\t{this.MaybeGetCodeLabel()}" + instruction + " (" + this.AM_Absolute() + ")";
private string Disassemble_Relative(string instruction, ushort absolute) => AM_Immediate_dump() + $"\t{MaybeGetCodeLabel()}" + instruction + " " + ConvertAddress(absolute); private string Disassemble_Relative(string instruction, ushort absolute) => this.AM_Immediate_dump() + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.ConvertAddress(absolute);
private string Disassemble_Immediate(string instruction) => AM_Immediate_dump() + $"\t{MaybeGetCodeLabel()}" + instruction + " " + AM_Immediate(); private string Disassemble_Immediate(string instruction) => this.AM_Immediate_dump() + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.AM_Immediate();
private string Disassemble_AM_00(int bbb, string instruction) => AM_00_dump(bbb) + $"\t{MaybeGetCodeLabel()}" + instruction + " " + AM_00(bbb); private string Disassemble_AM_00(int bbb, string instruction) => this.AM_00_dump(bbb) + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.AM_00(bbb);
private string Disassemble_AM_01(int bbb, string instruction) => AM_01_dump(bbb) + $"\t{MaybeGetCodeLabel()}" + instruction + " " + AM_01(bbb); private string Disassemble_AM_01(int bbb, string instruction) => this.AM_01_dump(bbb) + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.AM_01(bbb);
private string Disassemble_AM_10(int bbb, string instruction) => AM_10_dump(bbb) + $"\t{MaybeGetCodeLabel()}" + instruction + " " + AM_10(bbb); private string Disassemble_AM_10(int bbb, string instruction) => this.AM_10_dump(bbb) + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.AM_10(bbb);
private string Disassemble_AM_10_x(int bbb, string instruction) => AM_10_x_dump(bbb) + $"\t{MaybeGetCodeLabel()}" + instruction + " " + AM_10_x(bbb); private string Disassemble_AM_10_x(int bbb, string instruction) => this.AM_10_x_dump(bbb) + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.AM_10_x(bbb);
private string Disassemble_AM_11(int bbb, string instruction) => AM_11_dump(bbb) + $"\t{MaybeGetCodeLabel()}" + instruction + " " + AM_11(bbb); private string Disassemble_AM_11(int bbb, string instruction) => this.AM_11_dump(bbb) + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.AM_11(bbb);
private string Disassemble_AM_11_x(int bbb, string instruction) => AM_11_x_dump(bbb) + $"\t{MaybeGetCodeLabel()}" + instruction + " " + AM_11_x(bbb); private string Disassemble_AM_11_x(int bbb, string instruction) => this.AM_11_x_dump(bbb) + $"\t{this.MaybeGetCodeLabel()}" + instruction + " " + this.AM_11_x(bbb);
private static string Pad(string? value = null, int limit = 10) private static string Pad(string? value = null, int limit = 10)
@@ -589,179 +589,179 @@ namespace M6502
return value + padding; return value + padding;
} }
private string AM_Immediate_dump() => Pad(Dump_Byte((ushort)(address + 1))); private string AM_Immediate_dump() => Pad(this.Dump_Byte((ushort)(this.address + 1)));
private string AM_Immediate() => "#" + ConvertConstantByte((ushort)(address + 1)); private string AM_Immediate() => "#" + this.ConvertConstantByte((ushort)(this.address + 1));
private string AM_Absolute_dump() => Pad(Dump_DByte((ushort)(address + 1))); private string AM_Absolute_dump() => Pad(this.Dump_DByte((ushort)(this.address + 1)));
private string AM_Absolute() => ConvertAddressAt((ushort)(address + 1)); private string AM_Absolute() => this.ConvertAddressAt((ushort)(this.address + 1));
private string AM_ZeroPage_dump() => Pad(Dump_Byte((ushort)(address + 1))); private string AM_ZeroPage_dump() => Pad(this.Dump_Byte((ushort)(this.address + 1)));
private string AM_ZeroPage() => ConvertZPAddressAt((ushort)(address + 1)); private string AM_ZeroPage() => this.ConvertZPAddressAt((ushort)(this.address + 1));
private string AM_ZeroPageX_dump() => AM_ZeroPage_dump(); private string AM_ZeroPageX_dump() => this.AM_ZeroPage_dump();
private string AM_ZeroPageX() => AM_ZeroPage() + ",X"; private string AM_ZeroPageX() => this.AM_ZeroPage() + ",X";
private string AM_ZeroPageY_dump() => AM_ZeroPage_dump(); private string AM_ZeroPageY_dump() => this.AM_ZeroPage_dump();
private string AM_ZeroPageY() => AM_ZeroPage() + ",Y"; private string AM_ZeroPageY() => this.AM_ZeroPage() + ",Y";
private string AM_AbsoluteX_dump() => AM_Absolute_dump(); private string AM_AbsoluteX_dump() => this.AM_Absolute_dump();
private string AM_AbsoluteX() => AM_Absolute() + ",X"; private string AM_AbsoluteX() => this.AM_Absolute() + ",X";
private string AM_AbsoluteY_dump() => AM_Absolute_dump(); private string AM_AbsoluteY_dump() => this.AM_Absolute_dump();
private string AM_AbsoluteY() => AM_Absolute() + ",Y"; private string AM_AbsoluteY() => this.AM_Absolute() + ",Y";
private string AM_IndexedIndirectX_dump() => AM_ZeroPage_dump(); private string AM_IndexedIndirectX_dump() => this.AM_ZeroPage_dump();
private string AM_IndexedIndirectX() => "(" + ConvertZPAddressAt((ushort)(address + 1)) + ",X)"; private string AM_IndexedIndirectX() => "(" + this.ConvertZPAddressAt((ushort)(this.address + 1)) + ",X)";
private string AM_IndirectIndexedY_dump() => AM_ZeroPage_dump(); private string AM_IndirectIndexedY_dump() => this.AM_ZeroPage_dump();
private string AM_IndirectIndexedY() => "(" + ConvertZPAddressAt((ushort)(address + 1)) + "),Y"; private string AM_IndirectIndexedY() => "(" + this.ConvertZPAddressAt((ushort)(this.address + 1)) + "),Y";
private string AM_00_dump(int bbb) => bbb switch private string AM_00_dump(int bbb) => bbb switch
{ {
0b000 => AM_Immediate_dump(), 0b000 => this.AM_Immediate_dump(),
0b001 => AM_ZeroPage_dump(), 0b001 => this.AM_ZeroPage_dump(),
0b011 => AM_Absolute_dump(), 0b011 => this.AM_Absolute_dump(),
0b101 => AM_ZeroPageX_dump(), 0b101 => this.AM_ZeroPageX_dump(),
0b111 => AM_AbsoluteX_dump(), 0b111 => this.AM_AbsoluteX_dump(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_00(int bbb) => bbb switch private string AM_00(int bbb) => bbb switch
{ {
0b000 => AM_Immediate(), 0b000 => this.AM_Immediate(),
0b001 => AM_ZeroPage(), 0b001 => this.AM_ZeroPage(),
0b011 => AM_Absolute(), 0b011 => this.AM_Absolute(),
0b101 => AM_ZeroPageX(), 0b101 => this.AM_ZeroPageX(),
0b111 => AM_AbsoluteX(), 0b111 => this.AM_AbsoluteX(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_01_dump(int bbb) => bbb switch private string AM_01_dump(int bbb) => bbb switch
{ {
0b000 => AM_IndexedIndirectX_dump(), 0b000 => this.AM_IndexedIndirectX_dump(),
0b001 => AM_ZeroPage_dump(), 0b001 => this.AM_ZeroPage_dump(),
0b010 => AM_Immediate_dump(), 0b010 => this.AM_Immediate_dump(),
0b011 => AM_Absolute_dump(), 0b011 => this.AM_Absolute_dump(),
0b100 => AM_IndirectIndexedY_dump(), 0b100 => this.AM_IndirectIndexedY_dump(),
0b101 => AM_ZeroPageX_dump(), 0b101 => this.AM_ZeroPageX_dump(),
0b110 => AM_AbsoluteY_dump(), 0b110 => this.AM_AbsoluteY_dump(),
0b111 => AM_AbsoluteX_dump(), 0b111 => this.AM_AbsoluteX_dump(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_01(int bbb) => bbb switch private string AM_01(int bbb) => bbb switch
{ {
0b000 => AM_IndexedIndirectX(), 0b000 => this.AM_IndexedIndirectX(),
0b001 => AM_ZeroPage(), 0b001 => this.AM_ZeroPage(),
0b010 => AM_Immediate(), 0b010 => this.AM_Immediate(),
0b011 => AM_Absolute(), 0b011 => this.AM_Absolute(),
0b100 => AM_IndirectIndexedY(), 0b100 => this.AM_IndirectIndexedY(),
0b101 => AM_ZeroPageX(), 0b101 => this.AM_ZeroPageX(),
0b110 => AM_AbsoluteY(), 0b110 => this.AM_AbsoluteY(),
0b111 => AM_AbsoluteX(), 0b111 => this.AM_AbsoluteX(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_10_dump(int bbb) => bbb switch private string AM_10_dump(int bbb) => bbb switch
{ {
0b000 => AM_Immediate_dump(), 0b000 => this.AM_Immediate_dump(),
0b001 => AM_ZeroPage_dump(), 0b001 => this.AM_ZeroPage_dump(),
0b010 => string.Empty, 0b010 => string.Empty,
0b011 => AM_Absolute_dump(), 0b011 => this.AM_Absolute_dump(),
0b101 => AM_ZeroPageX_dump(), 0b101 => this.AM_ZeroPageX_dump(),
0b111 => AM_AbsoluteX_dump(), 0b111 => this.AM_AbsoluteX_dump(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_10(int bbb) => bbb switch private string AM_10(int bbb) => bbb switch
{ {
0b000 => AM_Immediate(), 0b000 => this.AM_Immediate(),
0b001 => AM_ZeroPage(), 0b001 => this.AM_ZeroPage(),
0b010 => "A", 0b010 => "A",
0b011 => AM_Absolute(), 0b011 => this.AM_Absolute(),
0b101 => AM_ZeroPageX(), 0b101 => this.AM_ZeroPageX(),
0b111 => AM_AbsoluteX(), 0b111 => this.AM_AbsoluteX(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_10_x_dump(int bbb) => bbb switch private string AM_10_x_dump(int bbb) => bbb switch
{ {
0b000 => AM_Immediate_dump(), 0b000 => this.AM_Immediate_dump(),
0b001 => AM_ZeroPage_dump(), 0b001 => this.AM_ZeroPage_dump(),
0b010 => string.Empty, 0b010 => string.Empty,
0b011 => AM_Absolute_dump(), 0b011 => this.AM_Absolute_dump(),
0b101 => AM_ZeroPageY_dump(), 0b101 => this.AM_ZeroPageY_dump(),
0b111 => AM_AbsoluteY_dump(), 0b111 => this.AM_AbsoluteY_dump(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_10_x(int bbb) => bbb switch private string AM_10_x(int bbb) => bbb switch
{ {
0b000 => AM_Immediate(), 0b000 => this.AM_Immediate(),
0b001 => AM_ZeroPage(), 0b001 => this.AM_ZeroPage(),
0b010 => "A", 0b010 => "A",
0b011 => AM_Absolute(), 0b011 => this.AM_Absolute(),
0b101 => AM_ZeroPageY(), 0b101 => this.AM_ZeroPageY(),
0b111 => AM_AbsoluteY(), 0b111 => this.AM_AbsoluteY(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_11_dump(int bbb) => bbb switch private string AM_11_dump(int bbb) => bbb switch
{ {
0b000 => AM_IndexedIndirectX_dump(), 0b000 => this.AM_IndexedIndirectX_dump(),
0b001 => AM_ZeroPage_dump(), 0b001 => this.AM_ZeroPage_dump(),
0b010 => AM_Immediate_dump(), 0b010 => this.AM_Immediate_dump(),
0b011 => AM_Absolute_dump(), 0b011 => this.AM_Absolute_dump(),
0b100 => AM_IndirectIndexedY_dump(), 0b100 => this.AM_IndirectIndexedY_dump(),
0b101 => AM_ZeroPageY_dump(), 0b101 => this.AM_ZeroPageY_dump(),
0b111 => AM_AbsoluteY_dump(), 0b111 => this.AM_AbsoluteY_dump(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_11_x_dump(int bbb) => bbb switch private string AM_11_x_dump(int bbb) => bbb switch
{ {
0b000 => AM_IndexedIndirectX_dump(), 0b000 => this.AM_IndexedIndirectX_dump(),
0b001 => AM_ZeroPage_dump(), 0b001 => this.AM_ZeroPage_dump(),
0b010 => AM_Immediate_dump(), 0b010 => this.AM_Immediate_dump(),
0b011 => AM_Absolute_dump(), 0b011 => this.AM_Absolute_dump(),
0b100 => AM_IndirectIndexedY_dump(), 0b100 => this.AM_IndirectIndexedY_dump(),
0b101 => AM_ZeroPageX_dump(), 0b101 => this.AM_ZeroPageX_dump(),
0b110 => AM_AbsoluteY_dump(), 0b110 => this.AM_AbsoluteY_dump(),
0b111 => AM_AbsoluteX_dump(), 0b111 => this.AM_AbsoluteX_dump(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_11(int bbb) => bbb switch private string AM_11(int bbb) => bbb switch
{ {
0b000 => AM_IndexedIndirectX(), 0b000 => this.AM_IndexedIndirectX(),
0b001 => AM_ZeroPage(), 0b001 => this.AM_ZeroPage(),
0b010 => AM_Immediate(), 0b010 => this.AM_Immediate(),
0b011 => AM_Absolute(), 0b011 => this.AM_Absolute(),
0b100 => AM_IndirectIndexedY(), 0b100 => this.AM_IndirectIndexedY(),
0b101 => AM_ZeroPageY(), 0b101 => this.AM_ZeroPageY(),
0b111 => AM_AbsoluteY(), 0b111 => this.AM_AbsoluteY(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
private string AM_11_x(int bbb) => bbb switch private string AM_11_x(int bbb) => bbb switch
{ {
0b000 => AM_IndexedIndirectX(), 0b000 => this.AM_IndexedIndirectX(),
0b001 => AM_ZeroPage(), 0b001 => this.AM_ZeroPage(),
0b010 => AM_Immediate(), 0b010 => this.AM_Immediate(),
0b011 => AM_Absolute(), 0b011 => this.AM_Absolute(),
0b100 => AM_IndirectIndexedY(), 0b100 => this.AM_IndirectIndexedY(),
0b101 => AM_ZeroPageX(), 0b101 => this.AM_ZeroPageX(),
0b110 => AM_AbsoluteY(), 0b110 => this.AM_AbsoluteY(),
0b111 => AM_AbsoluteX(), 0b111 => this.AM_AbsoluteX(),
_ => throw new InvalidOperationException("Illegal addressing mode"), _ => throw new InvalidOperationException("Illegal addressing mode"),
}; };
} }

View File

@@ -16,11 +16,11 @@
public bool Valid { get; private set; } public bool Valid { get; private set; }
public bool Invalid => !Valid; public bool Invalid => !this.Valid;
public bool Unimplemented => Invalid && CycleCountMismatch && (Cycles == 1); public bool Unimplemented => this.Invalid && this.CycleCountMismatch && (this.Cycles == 1);
public bool Implemented => !Unimplemented; public bool Implemented => !this.Unimplemented;
public List<string> Messages { get; } = []; public List<string> Messages { get; } = [];
@@ -28,67 +28,67 @@
public Checker(TestRunner runner) public Checker(TestRunner runner)
{ {
Runner = runner; this.Runner = runner;
Disassembler = new(Runner, (M6502.Core)Runner.CPU, Symbols); this.Disassembler = new(this.Runner, this.Runner.CPU, this.Symbols);
} }
public void Check(Test test) public void Check(Test test)
{ {
var cpu = Runner.CPU; var cpu = this.Runner.CPU;
Reset(); this.Reset();
Runner.RaisePOWER(); this.Runner.RaisePOWER();
InitialiseState(test); this.InitialiseState(test);
var pc = cpu.PC.Word; var pc = cpu.PC.Word;
Cycles = cpu.Step(); this.Cycles = cpu.Step();
Runner.LowerPOWER(); this.Runner.LowerPOWER();
Valid = CheckState(test); this.Valid = this.CheckState(test);
if (Unimplemented) if (this.Unimplemented)
{ {
Messages.Add("Unimplemented"); this.Messages.Add("Unimplemented");
return; return;
} }
Debug.Assert(Implemented); Debug.Assert(this.Implemented);
if (Invalid) if (this.Invalid)
{ {
AddDisassembly(pc); this.AddDisassembly(pc);
var final = test.Final ?? throw new InvalidOperationException("Final test state cannot be null"); var final = test.Final ?? throw new InvalidOperationException("Final test state cannot be null");
Raise("PC", final.PC, cpu.PC.Word); this.Raise("PC", final.PC, cpu.PC.Word);
Raise("S", final.S, cpu.S); this.Raise("S", final.S, cpu.S);
Raise("A", final.A, cpu.A); this.Raise("A", final.A, cpu.A);
Raise("X", final.X, cpu.X); this.Raise("X", final.X, cpu.X);
Raise("Y", final.Y, cpu.Y); this.Raise("Y", final.Y, cpu.Y);
Raise("P", final.P, cpu.P); this.Raise("P", final.P, cpu.P);
if (test.Cycles == null) if (test.Cycles == null)
{ {
throw new InvalidOperationException("test cycles cannot be null"); throw new InvalidOperationException("test cycles cannot be null");
} }
Messages.Add($"Fixed page is: {cpu.FixedPage:X2}"); this.Messages.Add($"Fixed page is: {cpu.FixedPage:X2}");
Messages.Add($"Stepped cycles: {Cycles}, expected events: {test.Cycles.Count}, actual events: {ActualCycles.Count}"); this.Messages.Add($"Stepped cycles: {this.Cycles}, expected events: {test.Cycles.Count}, actual events: {this.ActualCycles.Count}");
DumpCycles("-- Expected cycles", test.AvailableCycles()); this.DumpCycles("-- Expected cycles", test.AvailableCycles());
DumpCycles("-- Actual cycles", ActualCycles); this.DumpCycles("-- Actual cycles", this.ActualCycles);
} }
} }
private void Reset() private void Reset()
{ {
Messages.Clear(); this.Messages.Clear();
ActualCycles.Clear(); this.ActualCycles.Clear();
CycleCountMismatch = false; this.CycleCountMismatch = false;
Cycles = 0; this.Cycles = 0;
Valid = false; this.Valid = false;
} }
private bool Check(string what, ushort expected, ushort actual) private bool Check(string what, ushort expected, ushort actual)
@@ -96,7 +96,7 @@
var success = actual == expected; var success = actual == expected;
if (!success) if (!success)
{ {
Raise(what, expected, actual); this.Raise(what, expected, actual);
} }
return success; return success;
} }
@@ -106,7 +106,7 @@
var success = actual == expected; var success = actual == expected;
if (!success) if (!success)
{ {
Raise(what, expected, actual); this.Raise(what, expected, actual);
} }
return success; return success;
} }
@@ -118,7 +118,7 @@
var success = actual == expected; var success = actual == expected;
if (!success) if (!success)
{ {
Raise(what, expected, actual); this.Raise(what, expected, actual);
} }
return success; return success;
} }
@@ -128,7 +128,7 @@
var success = actual == expected; var success = actual == expected;
if (!success) if (!success)
{ {
Raise($"{what}: {address}", expected, actual); this.Raise($"{what}: {address}", expected, actual);
} }
return success; return success;
} }
@@ -138,32 +138,33 @@
string message; string message;
try try
{ {
message = Disassemble(address); message = this.Disassemble(address);
} }
catch (InvalidOperationException error) catch (InvalidOperationException error)
{ {
message = $"Disassembly problem: {error.Message}"; message = $"Disassembly problem: {error.Message}";
} }
Messages.Add(message); this.Messages.Add(message);
} }
private string Disassemble(ushort address) => Disassembler.Disassemble(address); private string Disassemble(ushort address) => this.Disassembler.Disassemble(address);
private bool CheckState(Test test) private bool CheckState(Test test)
{ {
var cpu = Runner.CPU; var cpu = this.Runner.CPU;
var ram = Runner.RAM; var ram = this.Runner.RAM;
var expectedCycles = test.AvailableCycles(); var expectedCycles = test.AvailableCycles();
var actualCycles = ActualCycles; var actualCycles = this.ActualCycles;
var actualIDX = 0; var actualIDX = 0;
foreach (var expectedCycle in expectedCycles) { foreach (var expectedCycle in expectedCycles)
{
if (actualIDX >= actualCycles.Count) if (actualIDX >= actualCycles.Count)
{ {
CycleCountMismatch = true; this.CycleCountMismatch = true;
return false; // more expected cycles than actual return false; // more expected cycles than actual
} }
@@ -171,40 +172,40 @@
var expectedAddress = expectedCycle.Address; var expectedAddress = expectedCycle.Address;
var actualAddress = actualCycle.Address; var actualAddress = actualCycle.Address;
_ = Check("Cycle address", expectedAddress, actualAddress); _ = this.Check("Cycle address", expectedAddress, actualAddress);
var expectedValue = expectedCycle.Value; var expectedValue = expectedCycle.Value;
var actualValue = actualCycle.Value; var actualValue = actualCycle.Value;
_ = Check("Cycle value", expectedValue, actualValue); _ = this.Check("Cycle value", expectedValue, actualValue);
var expectedAction = expectedCycle.Type; var expectedAction = expectedCycle.Type;
var actualAction = actualCycle.Type; var actualAction = actualCycle.Type;
_ = Check("Cycle action", expectedAction, actualAction); _ = this.Check("Cycle action", expectedAction, actualAction);
} }
if (actualIDX < actualCycles.Count) if (actualIDX < actualCycles.Count)
{ {
CycleCountMismatch = true; this.CycleCountMismatch = true;
return false; // less expected cycles than actual return false; // less expected cycles than actual
} }
if (Messages.Count > 0) if (this.Messages.Count > 0)
{ {
return false; return false;
} }
var final = test.Final ?? throw new InvalidOperationException("Final state cannot be null"); var final = test.Final ?? throw new InvalidOperationException("Final state cannot be null");
var pc_good = Check("PC", final.PC, cpu.PC.Word); var pc_good = this.Check("PC", final.PC, cpu.PC.Word);
var s_good = Check("S", final.S, cpu.S); var s_good = this.Check("S", final.S, cpu.S);
var a_good = Check("A", final.A, cpu.A); var a_good = this.Check("A", final.A, cpu.A);
var x_good = Check("X", final.X, cpu.X); var x_good = this.Check("X", final.X, cpu.X);
var y_good = Check("Y", final.Y, cpu.Y); var y_good = this.Check("Y", final.Y, cpu.Y);
var p_good = Check("P", final.P, cpu.P); var p_good = this.Check("P", final.P, cpu.P);
if (!p_good) if (!p_good)
{ {
Messages.Add($"Expected flags: {Disassembler.DumpFlags(final.P)}"); this.Messages.Add($"Expected flags: {Disassembler.DumpFlags(final.P)}");
Messages.Add($"Actual flags : {Disassembler.DumpFlags(cpu.P)}"); this.Messages.Add($"Actual flags : {Disassembler.DumpFlags(cpu.P)}");
} }
if (final.RAM == null) if (final.RAM == null)
@@ -223,7 +224,7 @@
var address = (ushort)entry[0]; var address = (ushort)entry[0];
var value = (byte)entry[1]; var value = (byte)entry[1];
var ramGood = Check("RAM", address, value, ram.Peek(address)); var ramGood = this.Check("RAM", address, value, ram.Peek(address));
if (!ramGood && !ramProblem) if (!ramGood && !ramProblem)
{ {
ramProblem = true; ramProblem = true;
@@ -236,28 +237,28 @@
&& !ramProblem; && !ramProblem;
} }
private void Raise(string what, ushort expected, ushort actual) => Messages.Add($"{what}: expected: {expected:X4}, actual: {actual:X4}"); private void Raise(string what, ushort expected, ushort actual) => this.Messages.Add($"{what}: expected: {expected:X4}, actual: {actual:X4}");
private void Raise(string what, byte expected, byte actual) => Messages.Add($"{what}: expected: {expected:X2}, actual: {actual:X2}"); private void Raise(string what, byte expected, byte actual) => this.Messages.Add($"{what}: expected: {expected:X2}, actual: {actual:X2}");
private void Raise(string what, string expected, string actual) => Messages.Add($"{what}: expected: {expected}, actual: {actual}"); private void Raise(string what, string expected, string actual) => this.Messages.Add($"{what}: expected: {expected}, actual: {actual}");
public void Initialise() public void Initialise()
{ {
Runner.ReadByte += Runner_ReadByte; this.Runner.ReadByte += this.Runner_ReadByte;
Runner.WrittenByte += Runner_WrittenByte; this.Runner.WrittenByte += this.Runner_WrittenByte;
} }
private void InitialiseState(Test test) private void InitialiseState(Test test)
{ {
var initial = test.Initial ?? throw new InvalidOperationException("Test cannot have an invalid initial state"); var initial = test.Initial ?? throw new InvalidOperationException("Test cannot have an invalid initial state");
InitialiseState(initial); this.InitialiseState(initial);
} }
private void InitialiseState(State state) private void InitialiseState(State state)
{ {
var cpu = Runner.CPU; var cpu = this.Runner.CPU;
var ram = Runner.RAM; var ram = this.Runner.RAM;
cpu.PC.Word = state.PC; cpu.PC.Word = state.PC;
cpu.S = state.S; cpu.S = state.S;
@@ -281,39 +282,39 @@
} }
} }
private void Runner_ReadByte(object? sender, EventArgs e) => AddActualReadCycle(Runner.Address, Runner.Data); private void Runner_ReadByte(object? sender, EventArgs e) => this.AddActualReadCycle(this.Runner.Address, this.Runner.Data);
private void Runner_WrittenByte(object? sender, EventArgs e) => AddActualWriteCycle(Runner.Address, Runner.Data); private void Runner_WrittenByte(object? sender, EventArgs e) => this.AddActualWriteCycle(this.Runner.Address, this.Runner.Data);
private void AddActualReadCycle(EightBit.Register16 address, byte value) => AddActualCycle(address, value, "read"); private void AddActualReadCycle(EightBit.Register16 address, byte value) => this.AddActualCycle(address, value, "read");
private void AddActualWriteCycle(EightBit.Register16 address, byte value) => AddActualCycle(address, value, "write"); private void AddActualWriteCycle(EightBit.Register16 address, byte value) => this.AddActualCycle(address, value, "write");
private void AddActualCycle(EightBit.Register16 address, byte value, string action) => AddActualCycle(address.Word, value, action); private void AddActualCycle(EightBit.Register16 address, byte value, string action) => this.AddActualCycle(address.Word, value, action);
private void AddActualCycle(ushort address, byte value, string action) => ActualCycles.Add(new Cycle(address, value, action)); private void AddActualCycle(ushort address, byte value, string action) => this.ActualCycles.Add(new Cycle(address, value, action));
private void DumpCycle(ushort address, byte value, string? action) private void DumpCycle(ushort address, byte value, string? action)
{ {
ArgumentNullException.ThrowIfNull(action); ArgumentNullException.ThrowIfNull(action);
Messages.Add($"Address: {address:X4}, value: {value:X2}, action: {action}"); this.Messages.Add($"Address: {address:X4}, value: {value:X2}, action: {action}");
} }
private void DumpCycle(Cycle cycle) => DumpCycle(cycle.Address, cycle.Value, cycle.Type); private void DumpCycle(Cycle cycle) => this.DumpCycle(cycle.Address, cycle.Value, cycle.Type);
private void DumpCycles(IEnumerable<Cycle>? cycles) private void DumpCycles(IEnumerable<Cycle>? cycles)
{ {
ArgumentNullException.ThrowIfNull(cycles); ArgumentNullException.ThrowIfNull(cycles);
foreach (var cycle in cycles) foreach (var cycle in cycles)
{ {
DumpCycle(cycle); this.DumpCycle(cycle);
} }
} }
private void DumpCycles(string which, IEnumerable<Cycle>? events) private void DumpCycles(string which, IEnumerable<Cycle>? events)
{ {
Messages.Add(which); this.Messages.Add(which);
DumpCycles(events); this.DumpCycles(events);
} }
} }
} }

View File

@@ -1,6 +1,6 @@
namespace M6502.HarteTest namespace M6502.HarteTest
{ {
public sealed class Cycle internal sealed class Cycle
{ {
public ushort Address { get; set; } public ushort Address { get; set; }
@@ -10,9 +10,9 @@
public Cycle(ushort address, byte value, string type) public Cycle(ushort address, byte value, string type)
{ {
Address = address; this.Address = address;
Value = value; this.Value = value;
Type = type; this.Type = type;
} }
public Cycle(List<object> input) public Cycle(List<object> input)
@@ -24,9 +24,9 @@
throw new ArgumentOutOfRangeException(nameof(input), input, "Cycles can only have three elements"); throw new ArgumentOutOfRangeException(nameof(input), input, "Cycles can only have three elements");
} }
Address = AsElement(input[0]).GetUInt16(); this.Address = AsElement(input[0]).GetUInt16();
Value = AsElement(input[1]).GetByte(); this.Value = AsElement(input[1]).GetByte();
Type = AsElement(input[2]).GetString(); this.Type = AsElement(input[2]).GetString();
} }
private static System.Text.Json.JsonElement AsElement(object part) => (System.Text.Json.JsonElement)part; private static System.Text.Json.JsonElement AsElement(object part) => (System.Text.Json.JsonElement)part;

View File

@@ -1,5 +1,6 @@
namespace M6502.HarteTest namespace M6502.HarteTest
{ {
using System.Runtime.CompilerServices;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
@@ -12,28 +13,28 @@
}; };
private bool _disposed; private bool _disposed;
public string Path { get; set; } = path; public string Path { get; } = path;
private readonly FileStream _stream = File.Open(path, FileMode.Open); private readonly FileStream _stream = File.Open(path, FileMode.Open);
public IAsyncEnumerable<Test?> TestsAsync => JsonSerializer.DeserializeAsyncEnumerable<Test>(_stream, SerializerOptions); public ConfiguredCancelableAsyncEnumerable<Test?> TestsAsync => JsonSerializer.DeserializeAsyncEnumerable<Test>(this._stream, SerializerOptions).ConfigureAwait(false);
private void Dispose(bool disposing) private void Dispose(bool disposing)
{ {
if (!_disposed) if (!this._disposed)
{ {
if (disposing) if (disposing)
{ {
_stream.Dispose(); this._stream.Dispose();
} }
_disposed = true; this._disposed = true;
} }
} }
public void Dispose() public void Dispose()
{ {
Dispose(disposing: true); this.Dispose(disposing: true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
} }

View File

@@ -6,7 +6,7 @@
public IEnumerable<OpcodeTestSuite> OpcodeTests() public IEnumerable<OpcodeTestSuite> OpcodeTests()
{ {
foreach (var filename in Directory.EnumerateFiles(Location, "*.json")) foreach (var filename in Directory.EnumerateFiles(this.Location, "*.json"))
{ {
var fileInformation = new FileInfo(filename); var fileInformation = new FileInfo(filename);
if (fileInformation.Length > 0) if (fileInformation.Length > 0)

View File

@@ -11,7 +11,7 @@ namespace M6502.HarteTest
var directory = @"C:\github\spectrum\libraries\EightBit\modules\65x02\6502\v1"; var directory = @"C:\github\spectrum\libraries\EightBit\modules\65x02\6502\v1";
//var directory = @"C:\github\spectrum\libraries\EightBit\modules\65x02\wdc65c02\v1"; //var directory = @"C:\github\spectrum\libraries\EightBit\modules\65x02\wdc65c02\v1";
await ProcessTestSuiteAsync(directory); await ProcessTestSuiteAsync(directory).ConfigureAwait(false);
} }
private static async Task ProcessTestSuiteAsync(string directory) private static async Task ProcessTestSuiteAsync(string directory)
@@ -33,7 +33,7 @@ namespace M6502.HarteTest
Console.WriteLine($"Processing: {Path.GetFileName(opcode.Path)}"); Console.WriteLine($"Processing: {Path.GetFileName(opcode.Path)}");
List<string?> testNames = []; List<string?> testNames = [];
var tests = opcode.TestsAsync ?? throw new InvalidOperationException("No tests are available"); var tests = opcode.TestsAsync;
await foreach (var test in tests) await foreach (var test in tests)
{ {
if (test == null) if (test == null)
@@ -55,7 +55,7 @@ namespace M6502.HarteTest
// Let's see if we had any successes! // Let's see if we had any successes!
if (testNames.Count > 0) if (testNames.Count > 0)
{ {
Console.WriteLine("**** The follow test variations succeeeded"); Console.WriteLine("**** The follow test variations succeeded");
foreach (var testName in testNames) foreach (var testName in testNames)
{ {
Console.WriteLine($"****** {testName}"); Console.WriteLine($"****** {testName}");

View File

@@ -1,6 +1,6 @@
namespace M6502.HarteTest namespace M6502.HarteTest
{ {
public sealed class State internal sealed class State
{ {
public ushort PC { get; set; } public ushort PC { get; set; }

View File

@@ -1,6 +1,6 @@
namespace M6502.HarteTest namespace M6502.HarteTest
{ {
public sealed class Test internal sealed class Test
{ {
public string? Name { get; set; } public string? Name { get; set; }
@@ -12,12 +12,12 @@
public IEnumerable<Cycle> AvailableCycles() public IEnumerable<Cycle> AvailableCycles()
{ {
if (Cycles == null) if (this.Cycles == null)
{ {
throw new InvalidOperationException("Cycles have not been initialised"); throw new InvalidOperationException("Cycles have not been initialised");
} }
foreach (var cycle in Cycles) foreach (var cycle in this.Cycles)
{ {
yield return new Cycle(cycle); yield return new Cycle(cycle);
} }

View File

@@ -13,8 +13,8 @@
public TestRunner() public TestRunner()
{ {
CPU = new(this); this.CPU = new(this);
_mapping = new(RAM, 0x0000, (ushort)Mask.Sixteen, AccessLevel.ReadWrite); this._mapping = new(this.RAM, 0x0000, (ushort)Mask.Sixteen, AccessLevel.ReadWrite);
} }
public override void Initialize() public override void Initialize()
@@ -23,21 +23,21 @@
public override void LowerPOWER() public override void LowerPOWER()
{ {
CPU.LowerPOWER(); this.CPU.LowerPOWER();
base.LowerPOWER(); base.LowerPOWER();
} }
public override MemoryMapping Mapping(ushort _) => _mapping; public override MemoryMapping Mapping(ushort _) => this._mapping;
public override void RaisePOWER() public override void RaisePOWER()
{ {
base.RaisePOWER(); base.RaisePOWER();
CPU.RaisePOWER(); this.CPU.RaisePOWER();
CPU.RaiseRESET(); this.CPU.RaiseRESET();
CPU.RaiseINT(); this.CPU.RaiseINT();
CPU.RaiseNMI(); this.CPU.RaiseNMI();
CPU.RaiseSO(); this.CPU.RaiseSO();
CPU.RaiseRDY(); this.CPU.RaiseRDY();
} }
} }
} }

View File

@@ -1,7 +1,5 @@
namespace M6502.Symbols namespace M6502.Symbols
{ {
using M6502.Symbols;
// line id = 268, file = 1, line = 60, type = 2, count = 1, span = 286 + 195 // line id = 268, file = 1, line = 60, type = 2, count = 1, span = 286 + 195
[Section("line", "Lines")] [Section("line", "Lines")]
public sealed class Line(Parser container) : IdentifiableSection(container) public sealed class Line(Parser container) : IdentifiableSection(container)

View File

@@ -2,6 +2,7 @@
{ {
// mod id=0,name="sudoku.o",file=0 // mod id=0,name="sudoku.o",file=0
[Section("mod", "Modules")] [Section("mod", "Modules")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "External file format")]
public sealed class Module(Parser container) : NamedSection(container) public sealed class Module(Parser container) : NamedSection(container)
{ {
[SectionReference("file")] [SectionReference("file")]

View File

@@ -124,7 +124,7 @@
public Scope? LookupScopeByAddress(int address) public Scope? LookupScopeByAddress(int address)
{ {
var index = _scopeAddressCache[address] ?? (_scopeAddressCache[address] = this.LocateScopeByAddress(address)); var index = this._scopeAddressCache[address] ?? (this._scopeAddressCache[address] = this.LocateScopeByAddress(address));
return index == -1 ? null : this.AddressableScopes[index.Value]; return index == -1 ? null : this.AddressableScopes[index.Value];
} }
@@ -352,7 +352,7 @@
{ {
if (this._version != null) if (this._version != null)
{ {
throw new InvalidOperationException("Verson object has already been parsed"); throw new InvalidOperationException("Version object has already been parsed");
} }
this._version = new(this); this._version = new(this);
this._version.Parse(BuildDictionary(parts)); this._version.Parse(BuildDictionary(parts));

View File

@@ -26,6 +26,7 @@
public void Build(System.Type type) public void Build(System.Type type)
{ {
ArgumentNullException.ThrowIfNull(type);
var sectionAttributes = type.GetCustomAttributes(typeof(SectionAttribute), true); var sectionAttributes = type.GetCustomAttributes(typeof(SectionAttribute), true);
Debug.Assert(sectionAttributes != null, "No section attributes available"); Debug.Assert(sectionAttributes != null, "No section attributes available");
Debug.Assert(sectionAttributes.Length == 1, "Must be a single section attribute available"); Debug.Assert(sectionAttributes.Length == 1, "Must be a single section attribute available");
@@ -154,7 +155,8 @@
if (attribute is SectionReferenceAttribute) if (attribute is SectionReferenceAttribute)
{ {
this.ReferenceAttributes.Add(key, new Tuple<string, System.Type>(name, originalType)); this.ReferenceAttributes.Add(key, new Tuple<string, System.Type>(name, originalType));
} else if (attribute is SectionReferencesAttribute) }
else if (attribute is SectionReferencesAttribute)
{ {
this.ReferencesAttributes.Add(key, new Tuple<string, System.Type>(name, originalType)); this.ReferencesAttributes.Add(key, new Tuple<string, System.Type>(name, originalType));
} }

View File

@@ -8,8 +8,8 @@
public class Section public class Section
{ {
protected static readonly Dictionary<System.Type, ReflectedSectionProperties> _sectionPropertiesCache = []; protected static readonly Dictionary<System.Type, ReflectedSectionProperties> SectionPropertiesCache = [];
protected static readonly DateTime _unixEpoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); protected static readonly DateTime UnixEpoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
protected readonly Parser _container; protected readonly Parser _container;
@@ -23,7 +23,7 @@
protected static ReflectedSectionProperties GetSectionProperties(System.Type type) protected static ReflectedSectionProperties GetSectionProperties(System.Type type)
{ {
var obtained = _sectionPropertiesCache.TryGetValue(type, out var properties); var obtained = SectionPropertiesCache.TryGetValue(type, out var properties);
Debug.Assert(obtained, $"Section properties for {type.Name} have not been built"); Debug.Assert(obtained, $"Section properties for {type.Name} have not been built");
Debug.Assert(properties != null); Debug.Assert(properties != null);
return properties; return properties;
@@ -35,8 +35,8 @@
{ {
var type = this.GetType(); var type = this.GetType();
var entry = new ReflectedSectionProperties(); var entry = new ReflectedSectionProperties();
Debug.Assert(_sectionPropertiesCache != null); Debug.Assert(SectionPropertiesCache != null);
if (_sectionPropertiesCache.TryAdd(type, entry)) if (SectionPropertiesCache.TryAdd(type, entry))
{ {
entry.Build(type); entry.Build(type);
} }
@@ -44,8 +44,9 @@
public T GetValueT<T>(string key) => this.SectionProperties.GetValueT<T>(this, key); public T GetValueT<T>(string key) => this.SectionProperties.GetValueT<T>(this, key);
public virtual void Parse(Dictionary<string, string> entries) public virtual void Parse(Dictionary<string, string>? entries)
{ {
ArgumentNullException.ThrowIfNull(entries);
this._parsed = entries; this._parsed = entries;
this._container.SectionEntries.Add(this); this._container.SectionEntries.Add(this);
this.ProcessAttributesOfProperties(); this.ProcessAttributesOfProperties();
@@ -129,7 +130,12 @@
} }
} }
protected static string ExtractString(string value) => value.Trim('"'); protected static string ExtractString(string? value)
{
ArgumentNullException.ThrowIfNull(value);
return value.Trim('"');
}
protected static string ExtractEnumeration(string value) => value; protected static string ExtractEnumeration(string value) => value;
private static T ExtractHexValue<T>(string value) where T : INumberBase<T> => T.Parse(value.AsSpan(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); private static T ExtractHexValue<T>(string value) where T : INumberBase<T> => T.Parse(value.AsSpan(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
@@ -139,8 +145,13 @@
protected static long ExtractHexLong(string value) => ExtractHexValue<long>(value); protected static long ExtractHexLong(string value) => ExtractHexValue<long>(value);
protected static int ExtractInteger(string value) => ExtractNumericValue<int>(value); protected static int ExtractInteger(string value) => ExtractNumericValue<int>(value);
protected static long ExtractLong(string value) => ExtractNumericValue<long>(value); protected static long ExtractLong(string value) => ExtractNumericValue<long>(value);
protected static DateTime ExtractDateTime(string value) => _unixEpoch.AddSeconds(ExtractHexLong(value)); protected static DateTime ExtractDateTime(string value) => UnixEpoch.AddSeconds(ExtractHexLong(value));
protected static string[] ExtractCompoundString(string value) => value.Split('+');
protected static string[] ExtractCompoundString(string? value)
{
ArgumentNullException.ThrowIfNull(value);
return value.Split('+');
}
protected static List<int> ExtractCompoundInteger(string value) protected static List<int> ExtractCompoundInteger(string value)
{ {

View File

@@ -4,12 +4,12 @@
namespace M6502.Test namespace M6502.Test
{ {
using EightBit;
using M6502;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using EightBit;
using M6502;
internal class Board : Bus internal class Board : Bus
{ {

View File

@@ -10,7 +10,7 @@ namespace M6502.Test
{ {
public bool DebugMode { get; set; } public bool DebugMode { get; set; }
public bool Profile { get; set; } public bool Profile { get; set; };
// Sudoku // Sudoku
public string Program { get; } = "sudoku.65b"; public string Program { get; } = "sudoku.65b";

View File

@@ -17,125 +17,125 @@ namespace M6502
return true; return true;
} }
var cycles = Cycles; var cycles = this.Cycles;
switch (OpCode) switch (this.OpCode)
{ {
case 0x02: Jam(); break; // *JAM case 0x02: this.Jam(); break; // *JAM
case 0x03: IndexedIndirectXRead(); SLO(); break; // *SLO (indexed indirect X) case 0x03: this.IndexedIndirectXRead(); this.SLO(); break; // *SLO (indexed indirect X)
case 0x04: ZeroPageRead(); break; // *NOP (zero page) case 0x04: this.ZeroPageRead(); break; // *NOP (zero page)
case 0x07: ZeroPageRead(); SLO(); break; // *SLO (zero page) case 0x07: this.ZeroPageRead(); this.SLO(); break; // *SLO (zero page)
case 0x0b: ImmediateRead(); ANC(); break; // *ANC (immediate) case 0x0b: this.ImmediateRead(); this.ANC(); break; // *ANC (immediate)
case 0x0c: AbsoluteRead(); break; // *NOP (absolute) case 0x0c: this.AbsoluteRead(); break; // *NOP (absolute)
case 0x0f: AbsoluteRead(); SLO(); break; // *SLO (absolute) case 0x0f: this.AbsoluteRead(); this.SLO(); break; // *SLO (absolute)
case 0x12: Jam(); break; // *JAM case 0x12: this.Jam(); break; // *JAM
case 0x13: IndirectIndexedYAddress(); FixupRead(); SLO(); break; // *SLO (indirect indexed Y) case 0x13: this.IndirectIndexedYAddress(); this.FixupRead(); this.SLO(); break; // *SLO (indirect indexed Y)
case 0x14: ZeroPageXRead(); break; // *NOP (zero page, X) case 0x14: this.ZeroPageXRead(); break; // *NOP (zero page, X)
case 0x17: ZeroPageXRead(); SLO(); break; // *SLO (zero page, X) case 0x17: this.ZeroPageXRead(); this.SLO(); break; // *SLO (zero page, X)
case 0x1a: SwallowRead(); break; // *NOP (implied) case 0x1a: this.SwallowRead(); break; // *NOP (implied)
case 0x1b: AbsoluteYAddress(); FixupRead(); SLO(); break; // *SLO (absolute, Y) case 0x1b: this.AbsoluteYAddress(); this.FixupRead(); this.SLO(); break; // *SLO (absolute, Y)
case 0x1c: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X) case 0x1c: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
case 0x1f: AbsoluteXAddress(); FixupRead(); SLO(); break; // *SLO (absolute, X) case 0x1f: this.AbsoluteXAddress(); this.FixupRead(); this.SLO(); break; // *SLO (absolute, X)
case 0x22: Jam(); break; // *JAM case 0x22: this.Jam(); break; // *JAM
case 0x23: IndexedIndirectXRead(); RLA(); ; break; // *RLA (indexed indirect X) case 0x23: this.IndexedIndirectXRead(); this.RLA(); ; break; // *RLA (indexed indirect X)
case 0x27: ZeroPageRead(); RLA(); ; break; // *RLA (zero page) case 0x27: this.ZeroPageRead(); this.RLA(); ; break; // *RLA (zero page)
case 0x2b: ImmediateRead(); ANC(); break; // *ANC (immediate) case 0x2b: this.ImmediateRead(); this.ANC(); break; // *ANC (immediate)
case 0x2f: AbsoluteRead(); RLA(); break; // *RLA (absolute) case 0x2f: this.AbsoluteRead(); this.RLA(); break; // *RLA (absolute)
case 0x32: Jam(); break; // *JAM case 0x32: this.Jam(); break; // *JAM
case 0x33: IndirectIndexedYAddress(); FixupRead(); RLA(); break; // *RLA (indirect indexed Y) case 0x33: this.IndirectIndexedYAddress(); this.FixupRead(); this.RLA(); break; // *RLA (indirect indexed Y)
case 0x34: ZeroPageXRead(); break; // *NOP (zero page, X) case 0x34: this.ZeroPageXRead(); break; // *NOP (zero page, X)
case 0x37: ZeroPageXRead(); RLA(); ; break; // *RLA (zero page, X) case 0x37: this.ZeroPageXRead(); this.RLA(); ; break; // *RLA (zero page, X)
case 0x3a: SwallowRead(); break; // *NOP (implied) case 0x3a: this.SwallowRead(); break; // *NOP (implied)
case 0x3b: AbsoluteYAddress(); FixupRead(); RLA(); break; // *RLA (absolute, Y) case 0x3b: this.AbsoluteYAddress(); this.FixupRead(); this.RLA(); break; // *RLA (absolute, Y)
case 0x3c: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X) case 0x3c: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
case 0x3f: AbsoluteXAddress(); FixupRead(); RLA(); break; // *RLA (absolute, X) case 0x3f: this.AbsoluteXAddress(); this.FixupRead(); this.RLA(); break; // *RLA (absolute, X)
case 0x42: Jam(); break; // *JAM case 0x42: this.Jam(); break; // *JAM
case 0x43: IndexedIndirectXRead(); SRE(); break; // *SRE (indexed indirect X) case 0x43: this.IndexedIndirectXRead(); this.SRE(); break; // *SRE (indexed indirect X)
case 0x47: ZeroPageRead(); SRE(); break; // *SRE (zero page) case 0x47: this.ZeroPageRead(); this.SRE(); break; // *SRE (zero page)
case 0x4b: ImmediateRead(); ASR(); break; // *ASR (immediate) case 0x4b: this.ImmediateRead(); this.ASR(); break; // *ASR (immediate)
case 0x4f: AbsoluteRead(); SRE(); break; // *SRE (absolute) case 0x4f: this.AbsoluteRead(); this.SRE(); break; // *SRE (absolute)
case 0x52: Jam(); break; // *JAM case 0x52: this.Jam(); break; // *JAM
case 0x53: IndirectIndexedYAddress(); FixupRead(); SRE(); break; // *SRE (indirect indexed Y) case 0x53: this.IndirectIndexedYAddress(); this.FixupRead(); this.SRE(); break; // *SRE (indirect indexed Y)
case 0x57: ZeroPageXRead(); SRE(); break; // *SRE (zero page, X) case 0x57: this.ZeroPageXRead(); this.SRE(); break; // *SRE (zero page, X)
case 0x5a: SwallowRead(); break; // *NOP (implied) case 0x5a: this.SwallowRead(); break; // *NOP (implied)
case 0x5b: AbsoluteYAddress(); FixupRead(); SRE(); break; // *SRE (absolute, Y) case 0x5b: this.AbsoluteYAddress(); this.FixupRead(); this.SRE(); break; // *SRE (absolute, Y)
case 0x5c: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X) case 0x5c: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
case 0x5f: AbsoluteXAddress(); FixupRead(); SRE(); break; // *SRE (absolute, X) case 0x5f: this.AbsoluteXAddress(); this.FixupRead(); this.SRE(); break; // *SRE (absolute, X)
case 0x62: Jam(); break; // *JAM case 0x62: this.Jam(); break; // *JAM
case 0x63: IndexedIndirectXRead(); RRA(); break; // *RRA (indexed indirect X) case 0x63: this.IndexedIndirectXRead(); this.RRA(); break; // *RRA (indexed indirect X)
case 0x64: ZeroPageRead(); break; // *NOP (zero page) case 0x64: this.ZeroPageRead(); break; // *NOP (zero page)
case 0x67: ZeroPageRead(); RRA(); break; // *RRA (zero page) case 0x67: this.ZeroPageRead(); this.RRA(); break; // *RRA (zero page)
case 0x6b: ImmediateRead(); ARR(); break; // *ARR (immediate) case 0x6b: this.ImmediateRead(); this.ARR(); break; // *ARR (immediate)
case 0x6f: AbsoluteRead(); RRA(); break; // *RRA (absolute) case 0x6f: this.AbsoluteRead(); this.RRA(); break; // *RRA (absolute)
case 0x72: Jam(); break; // *JAM case 0x72: this.Jam(); break; // *JAM
case 0x73: IndirectIndexedYAddress(); FixupRead(); RRA(); break; // *RRA (indirect indexed Y) case 0x73: this.IndirectIndexedYAddress(); this.FixupRead(); this.RRA(); break; // *RRA (indirect indexed Y)
case 0x74: ZeroPageXRead(); break; // *NOP (zero page, X) case 0x74: this.ZeroPageXRead(); break; // *NOP (zero page, X)
case 0x77: ZeroPageXRead(); RRA(); break; // *RRA (zero page, X) case 0x77: this.ZeroPageXRead(); this.RRA(); break; // *RRA (zero page, X)
case 0x7a: SwallowRead(); break; // *NOP (implied) case 0x7a: this.SwallowRead(); break; // *NOP (implied)
case 0x7b: AbsoluteYAddress(); FixupRead(); RRA(); break; // *RRA (absolute, Y) case 0x7b: this.AbsoluteYAddress(); this.FixupRead(); this.RRA(); break; // *RRA (absolute, Y)
case 0x7c: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X) case 0x7c: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
case 0x7f: AbsoluteXAddress(); FixupRead(); RRA(); break; // *RRA (absolute, X) case 0x7f: this.AbsoluteXAddress(); this.FixupRead(); this.RRA(); break; // *RRA (absolute, X)
case 0x80: ImmediateRead(); break; // *NOP (immediate) case 0x80: this.ImmediateRead(); break; // *NOP (immediate)
case 0x83: IndexedIndirectXAddress(); MemoryWrite((byte)(A & X)); break; // *SAX (indexed indirect X) case 0x83: this.IndexedIndirectXAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (indexed indirect X)
case 0x87: ZeroPageAddress(); MemoryWrite((byte)(A & X)); break; // *SAX (zero page) case 0x87: this.ZeroPageAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (zero page)
case 0x89: ImmediateRead(); break; // *NOP (immediate) case 0x89: this.ImmediateRead(); break; // *NOP (immediate)
case 0x8b: ImmediateRead(); ANE(); break; // *ANE (immediate) case 0x8b: this.ImmediateRead(); this.ANE(); break; // *ANE (immediate)
case 0x8f: AbsoluteAddress(); MemoryWrite((byte)(A & X)); break; // *SAX (absolute) case 0x8f: this.AbsoluteAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (absolute)
case 0x92: Jam(); break; // *JAM case 0x92: this.Jam(); break; // *JAM
case 0x93: IndirectIndexedYAddress(); Fixup(); SHA(); break; // *SHA (indirect indexed, Y) case 0x93: this.IndirectIndexedYAddress(); this.Fixup(); this.SHA(); break; // *SHA (indirect indexed, Y)
case 0x97: ZeroPageYAddress(); MemoryWrite((byte)(A & X)); break; // *SAX (zero page, Y) case 0x97: this.ZeroPageYAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (zero page, Y)
case 0x9b: AbsoluteYAddress(); Fixup(); TAS(); break; // *TAS (absolute, Y) case 0x9b: this.AbsoluteYAddress(); this.Fixup(); this.TAS(); break; // *TAS (absolute, Y)
case 0x9c: AbsoluteXAddress(); Fixup(); SYA(); break; // *SYA (absolute, X) case 0x9c: this.AbsoluteXAddress(); this.Fixup(); this.SYA(); break; // *SYA (absolute, X)
case 0x9e: AbsoluteYAddress(); Fixup(); SXA(); break; // *SXA (absolute, Y) case 0x9e: this.AbsoluteYAddress(); this.Fixup(); this.SXA(); break; // *SXA (absolute, Y)
case 0x9f: AbsoluteYAddress(); Fixup(); SHA(); break; // *SHA (absolute, Y) case 0x9f: this.AbsoluteYAddress(); this.Fixup(); this.SHA(); break; // *SHA (absolute, Y)
case 0xa3: IndexedIndirectXRead(); A = X = Through(); break; // *LAX (indexed indirect X) case 0xa3: this.IndexedIndirectXRead(); this.A = this.X = this.Through(); break; // *LAX (indexed indirect X)
case 0xa7: ZeroPageRead(); A = X = Through(); break; // *LAX (zero page) case 0xa7: this.ZeroPageRead(); this.A = this.X = this.Through(); break; // *LAX (zero page)
case 0xab: ImmediateRead(); ATX(); break; // *ATX (immediate) case 0xab: this.ImmediateRead(); this.ATX(); break; // *ATX (immediate)
case 0xaf: AbsoluteRead(); A = X = Through(); break; // *LAX (absolute) case 0xaf: this.AbsoluteRead(); this.A = this.X = this.Through(); break; // *LAX (absolute)
case 0xb2: Jam(); break; // *JAM case 0xb2: this.Jam(); break; // *JAM
case 0xb3: IndirectIndexedYRead(); A = X = Through(); break; // *LAX (indirect indexed Y) case 0xb3: this.IndirectIndexedYRead(); this.A = this.X = this.Through(); break; // *LAX (indirect indexed Y)
case 0xb7: ZeroPageYRead(); A = X = Through(); break; // *LAX (zero page, Y) case 0xb7: this.ZeroPageYRead(); this.A = this.X = this.Through(); break; // *LAX (zero page, Y)
case 0xbb: AbsoluteYAddress(); MaybeFixup(); LAS(); break; // *LAS (absolute, Y) case 0xbb: this.AbsoluteYAddress(); this.MaybeFixup(); this.LAS(); break; // *LAS (absolute, Y)
case 0xbf: AbsoluteYRead(); A = X = Through(); break; // *LAX (absolute, Y) case 0xbf: this.AbsoluteYRead(); this.A = this.X = this.Through(); break; // *LAX (absolute, Y)
case 0xc3: IndexedIndirectXRead(); DCP(); break; // *DCP (indexed indirect X) case 0xc3: this.IndexedIndirectXRead(); this.DCP(); break; // *DCP (indexed indirect X)
case 0xc7: ZeroPageRead(); DCP(); break; // *DCP (zero page) case 0xc7: this.ZeroPageRead(); this.DCP(); break; // *DCP (zero page)
case 0xcb: ImmediateRead(); AXS(); break; // *AXS (immediate) case 0xcb: this.ImmediateRead(); this.AXS(); break; // *AXS (immediate)
case 0xcf: AbsoluteRead(); DCP(); break; // *DCP (absolute) case 0xcf: this.AbsoluteRead(); this.DCP(); break; // *DCP (absolute)
case 0xd2: Jam(); break; // *JAM case 0xd2: this.Jam(); break; // *JAM
case 0xd3: IndirectIndexedYAddress(); FixupRead(); DCP(); break; // *DCP (indirect indexed Y) case 0xd3: this.IndirectIndexedYAddress(); this.FixupRead(); this.DCP(); break; // *DCP (indirect indexed Y)
case 0xd7: ZeroPageXRead(); DCP(); break; // *DCP (zero page, X) case 0xd7: this.ZeroPageXRead(); this.DCP(); break; // *DCP (zero page, X)
case 0xda: SwallowRead(); break; // *NOP (implied) case 0xda: this.SwallowRead(); break; // *NOP (implied)
case 0xdb: AbsoluteYAddress(); FixupRead(); DCP(); break; // *DCP (absolute, Y) case 0xdb: this.AbsoluteYAddress(); this.FixupRead(); this.DCP(); break; // *DCP (absolute, Y)
case 0xdc: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X) case 0xdc: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
case 0xdf: AbsoluteXAddress(); FixupRead(); DCP(); break; // *DCP (absolute, X) case 0xdf: this.AbsoluteXAddress(); this.FixupRead(); this.DCP(); break; // *DCP (absolute, X)
case 0xe3: IndexedIndirectXRead(); ISB(); break; // *ISB (indexed indirect X) case 0xe3: this.IndexedIndirectXRead(); this.ISB(); break; // *ISB (indexed indirect X)
case 0xe7: ZeroPageRead(); ISB(); break; // *ISB (zero page) case 0xe7: this.ZeroPageRead(); this.ISB(); break; // *ISB (zero page)
case 0xeb: ImmediateRead(); SBC(); break; // *SBC (immediate) case 0xeb: this.ImmediateRead(); this.SBC(); break; // *SBC (immediate)
case 0xef: AbsoluteRead(); ISB(); break; // *ISB (absolute) case 0xef: this.AbsoluteRead(); this.ISB(); break; // *ISB (absolute)
case 0xf2: Jam(); break; // *JAM case 0xf2: this.Jam(); break; // *JAM
case 0xf3: IndirectIndexedYAddress(); FixupRead(); ISB(); break; // *ISB (indirect indexed Y) case 0xf3: this.IndirectIndexedYAddress(); this.FixupRead(); this.ISB(); break; // *ISB (indirect indexed Y)
case 0xf7: ZeroPageXRead(); ISB(); break; // *ISB (zero page, X) case 0xf7: this.ZeroPageXRead(); this.ISB(); break; // *ISB (zero page, X)
case 0xfa: SwallowRead(); break; // *NOP (implied) case 0xfa: this.SwallowRead(); break; // *NOP (implied)
case 0xfb: AbsoluteYAddress(); FixupRead(); ISB(); break; // *ISB (absolute, Y) case 0xfb: this.AbsoluteYAddress(); this.FixupRead(); this.ISB(); break; // *ISB (absolute, Y)
case 0xfc: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X) case 0xfc: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
case 0xff: AbsoluteXAddress(); FixupRead(); ISB(); break; // *ISB (absolute, X) case 0xff: this.AbsoluteXAddress(); this.FixupRead(); this.ISB(); break; // *ISB (absolute, X)
} }
return cycles != Cycles; return cycles != this.Cycles;
} }
#endregion #endregion
@@ -145,8 +145,8 @@ namespace M6502
protected override void ModifyWrite(byte data) protected override void ModifyWrite(byte data)
{ {
// The read will have already taken place... // The read will have already taken place...
MemoryWrite(); // Modify cycle this.MemoryWrite(); // Modify cycle
MemoryWrite(data); // Write cycle this.MemoryWrite(data); // Write cycle
} }
#endregion #endregion
@@ -155,22 +155,22 @@ namespace M6502
protected override void IndirectAddress() protected override void IndirectAddress()
{ {
AbsoluteAddress(); this.AbsoluteAddress();
GetAddressPaged(); this.GetAddressPaged();
} }
#region Address page fixup #region Address page fixup
protected override void Fixup() protected override void Fixup()
{ {
MemoryRead(); this.MemoryRead();
Bus.Address.High = FixedPage; this.Bus.Address.High = this.FixedPage;
} }
protected override void FixupBranch(sbyte relative) protected override void FixupBranch(sbyte relative)
{ {
NoteFixedAddress(PC.Word + relative); this.NoteFixedAddress(this.PC.Word + relative);
MaybeFixup(); this.MaybeFixup();
} }
#endregion #endregion
@@ -185,11 +185,11 @@ namespace M6502
private void ARR() private void ARR()
{ {
var value = Bus.Data; var value = this.Bus.Data;
if (DecimalMasked != 0) if (this.DecimalMasked != 0)
ARR_d(value); this.ARR_d(value);
else else
ARR_b(value); this.ARR_b(value);
} }
private void ARR_d(byte value) private void ARR_d(byte value)
@@ -197,26 +197,26 @@ namespace M6502
// With thanks to https://github.com/TomHarte/CLK // With thanks to https://github.com/TomHarte/CLK
// What a very strange instruction ARR is... // What a very strange instruction ARR is...
A &= value; this.A &= value;
var unshiftedA = A; var unshiftedA = this.A;
A = Through(A >> 1 | Carry << 7); this.A = this.Through(this.A >> 1 | this.Carry << 7);
SetFlag(StatusBits.VF, OverflowTest((byte)(A ^ A << 1))); this.SetFlag(StatusBits.VF, OverflowTest((byte)(this.A ^ this.A << 1)));
if (LowerNibble(unshiftedA) + (unshiftedA & 0x1) > 5) if (LowerNibble(unshiftedA) + (unshiftedA & 0x1) > 5)
A = (byte)(LowerNibble((byte)(A + 6)) | HigherNibble(A)); this.A = (byte)(LowerNibble((byte)(this.A + 6)) | HigherNibble(this.A));
SetFlag(StatusBits.CF, HigherNibble(unshiftedA) + (unshiftedA & 0x10) > 0x50); this.SetFlag(StatusBits.CF, HigherNibble(unshiftedA) + (unshiftedA & 0x10) > 0x50);
if (Carry != 0) if (this.Carry != 0)
A += 0x60; this.A += 0x60;
} }
private void ARR_b(byte value) private void ARR_b(byte value)
{ {
A &= value; this.A &= value;
A = Through(A >> 1 | Carry << 7); this.A = this.Through(this.A >> 1 | this.Carry << 7);
SetFlag(StatusBits.CF, OverflowTest(A)); this.SetFlag(StatusBits.CF, OverflowTest(this.A));
SetFlag(StatusBits.VF, OverflowTest((byte)(A ^ A << 1))); this.SetFlag(StatusBits.VF, OverflowTest((byte)(this.A ^ this.A << 1)));
} }
#endregion #endregion
@@ -236,108 +236,108 @@ namespace M6502
//this.MemoryWrite(updated); //this.MemoryWrite(updated);
byte updated; byte updated;
if (Fixed) if (this.Fixed)
{ {
updated = (byte)(data & FixedPage); updated = (byte)(data & this.FixedPage);
Bus.Address.High = updated; this.Bus.Address.High = updated;
} }
else else
{ {
updated = (byte)(data & UnfixedPage); updated = (byte)(data & this.UnfixedPage);
Bus.Address.High = updated; this.Bus.Address.High = updated;
} }
MemoryWrite(updated); this.MemoryWrite(updated);
} }
private void SHA() => StoreFixupEffect((byte)(A & X)); private void SHA() => this.StoreFixupEffect((byte)(this.A & this.X));
private void SYA() => StoreFixupEffect(Y); private void SYA() => this.StoreFixupEffect(this.Y);
private void SXA() => StoreFixupEffect(X); private void SXA() => this.StoreFixupEffect(this.X);
#endregion #endregion
private void ANC() private void ANC()
{ {
AndR(); this.AndR();
SetFlag(StatusBits.CF, NegativeTest(A)); this.SetFlag(StatusBits.CF, NegativeTest(this.A));
} }
private void AXS() private void AXS()
{ {
X = Through(BinarySUB((byte)(A & X))); this.X = this.Through(this.BinarySUB((byte)(this.A & this.X)));
ResetFlag(StatusBits.CF, Intermediate.High); this.ResetFlag(StatusBits.CF, this.Intermediate.High);
} }
private void Jam() private void Jam()
{ {
Bus.Address.Assign(PC); this.Bus.Address.Assign(this.PC);
MemoryRead(); this.MemoryRead();
MemoryRead(0xff, 0xff); this.MemoryRead(0xff, 0xff);
Bus.Address.Low = 0xfe; this.Bus.Address.Low = 0xfe;
MemoryRead(); this.MemoryRead();
MemoryRead(); this.MemoryRead();
Bus.Address.Low = 0xff; this.Bus.Address.Low = 0xff;
MemoryRead(); this.MemoryRead();
MemoryRead(); this.MemoryRead();
MemoryRead(); this.MemoryRead();
MemoryRead(); this.MemoryRead();
MemoryRead(); this.MemoryRead();
MemoryRead(); this.MemoryRead();
} }
private void TAS() private void TAS()
{ {
S = (byte)(A & X); this.S = (byte)(this.A & this.X);
SHA(); this.SHA();
} }
private void LAS() => A = X = S = Through(MemoryRead() & S); private void LAS() => this.A = this.X = this.S = this.Through(this.MemoryRead() & this.S);
private void ANE() => A = Through((A | 0xee) & X & Bus.Data); private void ANE() => this.A = this.Through((this.A | 0xee) & this.X & this.Bus.Data);
private void ATX() => A = X = Through((A | 0xee) & Bus.Data); private void ATX() => this.A = this.X = this.Through((this.A | 0xee) & this.Bus.Data);
private void ASR() private void ASR()
{ {
AndR(); this.AndR();
A = LSR(A); this.A = this.LSR(this.A);
} }
private void ISB() private void ISB()
{ {
ModifyWrite(INC()); this.ModifyWrite(this.INC());
SBC(); this.SBC();
} }
private void RLA() private void RLA()
{ {
ModifyWrite(ROL()); this.ModifyWrite(this.ROL());
AndR(); this.AndR();
} }
private void RRA() private void RRA()
{ {
ModifyWrite(ROR()); this.ModifyWrite(this.ROR());
ADC(); this.ADC();
} }
private void SLO() private void SLO()
{ {
ModifyWrite(ASL()); this.ModifyWrite(this.ASL());
OrR(); this.OrR();
} }
private void SRE() private void SRE()
{ {
ModifyWrite(LSR()); this.ModifyWrite(this.LSR());
EorR(); this.EorR();
} }
private void DCP() private void DCP()
{ {
ModifyWrite(DEC()); this.ModifyWrite(this.DEC());
CMP(A); this.CMP(this.A);
} }
#endregion #endregion

View File

@@ -31,8 +31,8 @@
if (activate) if (activate)
{ {
this.processor.RaisingSYNC += Processor_RaisingSYNC; this.processor.RaisingSYNC += this.Processor_RaisingSYNC;
this.processor.ExecutedInstruction += Processor_ExecutedInstruction; this.processor.ExecutedInstruction += this.Processor_ExecutedInstruction;
} }
} }
@@ -62,147 +62,147 @@
{ {
get get
{ {
Debug.Assert(totalCyclesValid); Debug.Assert(this.totalCyclesValid);
return totalCycles; return this.totalCycles;
} }
private set private set
{ {
Debug.Assert(!totalCyclesValid); Debug.Assert(!this.totalCyclesValid);
totalCycles = value; this.totalCycles = value;
totalCyclesValid = true; this.totalCyclesValid = true;
} }
} }
public void Generate() public void Generate()
{ {
OnStartingOutput(); this.OnStartingOutput();
try try
{ {
EmitProfileInformation(); this.EmitProfileInformation();
} }
finally finally
{ {
OnFinishedOutput(); this.OnFinishedOutput();
} }
} }
private void EmitProfileInformation() private void EmitProfileInformation()
{ {
TotalCycles = instructionCycles.Sum(); this.TotalCycles = this.instructionCycles.Sum();
EmitProfileLineInformation(); this.EmitProfileLineInformation();
EmitProfileScopeInformation(); this.EmitProfileScopeInformation();
EmitProfileInstructionInformation(); this.EmitProfileInstructionInformation();
} }
private void EmitProfileScopeInformation() private void EmitProfileScopeInformation()
{ {
OnStartingScopeOutput(); this.OnStartingScopeOutput();
try try
{ {
foreach (var (id, cycles) in scopeCycles) foreach (var (id, cycles) in this.scopeCycles)
{ {
var symbol = symbols.LookupLabelByID(id); var symbol = this.symbols.LookupLabelByID(id);
Debug.Assert(symbol != null); Debug.Assert(symbol != null);
var available = ExtractCycleDistribution((ushort)symbol.Value, out var _, out var _, out var count); var available = this.ExtractCycleDistribution((ushort)symbol.Value, out var _, out var _, out var count);
Debug.Assert(available); Debug.Assert(available);
OnEmitScope(id, cycles, count); this.OnEmitScope(id, cycles, count);
} }
} }
finally finally
{ {
OnFinishedScopeOutput(); this.OnFinishedScopeOutput();
} }
} }
private void EmitProfileLineInformation() private void EmitProfileLineInformation()
{ {
OnStartingLineOutput(); this.OnStartingLineOutput();
try try
{ {
// For each memory address // For each memory address
for (var i = 0; i < 0x10000; ++i) for (var i = 0; i < 0x10000; ++i)
{ {
var address = (ushort)i; var address = (ushort)i;
var available = ExtractCycleDistribution(address, out var cycleDistributions, out var cycles, out var count); var available = this.ExtractCycleDistribution(address, out var cycleDistributions, out var cycles, out var count);
if (available) if (available)
{ {
// Dump a profile/disassembly line // Dump a profile/disassembly line
var source = disassembler.Disassemble(address); var source = this.disassembler.Disassemble(address);
Debug.Assert(cycleDistributions != null); Debug.Assert(cycleDistributions != null);
OnEmitLine(address, source, cycles, count, cycleDistributions); this.OnEmitLine(address, source, cycles, count, cycleDistributions);
} }
} }
} }
finally finally
{ {
OnFinishedLineOutput(); this.OnFinishedLineOutput();
} }
} }
private void EmitProfileInstructionInformation() private void EmitProfileInstructionInformation()
{ {
OnStartingInstructionOutput(); this.OnStartingInstructionOutput();
try try
{ {
// For each instruction // For each instruction
for (var i = 0; i < 0x100; ++i) for (var i = 0; i < 0x100; ++i)
{ {
// If there are any cycles associated // If there are any cycles associated
var cycles = instructionCycles[i]; var cycles = this.instructionCycles[i];
if (cycles > 0) if (cycles > 0)
{ {
var count = instructionCounts[i]; var count = this.instructionCounts[i];
Debug.Assert(count > 0); Debug.Assert(count > 0);
var instruction = (byte)i; var instruction = (byte)i;
// Emit an instruction event // Emit an instruction event
OnEmitInstruction(instruction, cycles, count); this.OnEmitInstruction(instruction, cycles, count);
} }
} }
} }
finally finally
{ {
OnFinishedInstructionOutput(); this.OnFinishedInstructionOutput();
} }
} }
private void Processor_RaisingSYNC(object? sender, EventArgs e) private void Processor_RaisingSYNC(object? sender, EventArgs e)
{ {
executingAddress = processor.Bus.Address.Word; this.executingAddress = this.processor.Bus.Address.Word;
++instructionCounts[executingInstruction = processor.Bus.Data]; ++this.instructionCounts[this.executingInstruction = this.processor.Bus.Data];
} }
private void Processor_ExecutedInstruction(object? sender, EventArgs e) private void Processor_ExecutedInstruction(object? sender, EventArgs e)
{ {
var cycles = processor.Cycles; var cycles = this.processor.Cycles;
{ {
var addressDistribution = addressCycleDistributions[executingAddress]; var addressDistribution = this.addressCycleDistributions[this.executingAddress];
if (addressDistribution == null) if (addressDistribution == null)
{ {
addressCycleDistributions[executingAddress] = addressDistribution = []; this.addressCycleDistributions[this.executingAddress] = addressDistribution = [];
} }
_ = addressDistribution.TryGetValue(cycles, out var current); _ = addressDistribution.TryGetValue(cycles, out var current);
addressDistribution[cycles] = ++current; addressDistribution[cycles] = ++current;
} }
instructionCycles[executingInstruction] += cycles; this.instructionCycles[this.executingInstruction] += cycles;
{ {
var scope = symbols.LookupScopeByAddress(executingAddress); var scope = this.symbols.LookupScopeByAddress(this.executingAddress);
if (scope != null) if (scope != null)
{ {
var id = scope.ID; var id = scope.ID;
// Current will be initialised to zero, if absent // Current will be initialised to zero, if absent
_ = scopeCycles.TryGetValue(id, out var current); _ = this.scopeCycles.TryGetValue(id, out var current);
scopeCycles[id] = current + cycles; this.scopeCycles[id] = current + cycles;
} }
} }
} }
private bool ExtractCycleDistribution(ushort address, out Dictionary<int, long>? cycleDistribution, out long cycleCount, out long hitCount) private bool ExtractCycleDistribution(ushort address, out Dictionary<int, long>? cycleDistribution, out long cycleCount, out long hitCount)
{ {
cycleDistribution = addressCycleDistributions[address]; cycleDistribution = this.addressCycleDistributions[address];
if (cycleDistribution == null) if (cycleDistribution == null)
{ {
cycleCount = -1; cycleCount = -1;

View File

@@ -13,22 +13,22 @@ namespace M6502
private bool Stopped private bool Stopped
{ {
get => _stopped; set => _stopped = value; get => this._stopped; set => this._stopped = value;
} }
private bool Waiting private bool Waiting
{ {
get => _waiting; set => _waiting = value; get => this._waiting; set => this._waiting = value;
} }
private bool Paused => Stopped || Waiting; private bool Paused => this.Stopped || this.Waiting;
#region Interrupts #region Interrupts
protected override void Interrupt(byte vector, InterruptSource source, InterruptType type) protected override void Interrupt(byte vector, InterruptSource source, InterruptType type)
{ {
base.Interrupt(vector, source, type); base.Interrupt(vector, source, type);
ResetFlag(StatusBits.DF); // Disable decimal mode (Change from MOS6502) this.ResetFlag(StatusBits.DF); // Disable decimal mode (Change from MOS6502)
} }
#endregion #endregion
@@ -42,130 +42,130 @@ namespace M6502
return true; return true;
} }
var cycles = Cycles; var cycles = this.Cycles;
switch (OpCode) switch (this.OpCode)
{ {
case 0x02: SwallowFetch(); break; // NOP case 0x02: this.SwallowFetch(); break; // NOP
case 0x03: break; // null case 0x03: break; // null
case 0x04: ZeroPageRead(); TSB(); break; // TSB zp case 0x04: this.ZeroPageRead(); this.TSB(); break; // TSB zp
case 0x07: ZeroPageRead(); RMB(Bit(0)); break; // RMB0 zp case 0x07: this.ZeroPageRead(); this.RMB(Bit(0)); break; // RMB0 zp
case 0x0b: break; // null case 0x0b: break; // null
case 0x0c: AbsoluteRead(); TSB(); break; // TSB a case 0x0c: this.AbsoluteRead(); this.TSB(); break; // TSB a
case 0x0f: ZeroPageRead(); BBR(Bit(0)); break; // BBR0 r case 0x0f: this.ZeroPageRead(); this.BBR(Bit(0)); break; // BBR0 r
case 0x12: ZeroPageIndirectAddress(); OrR(); break; // ORA (zp),y case 0x12: this.ZeroPageIndirectAddress(); this.OrR(); break; // ORA (zp),y
case 0x13: break; // null case 0x13: break; // null
case 0x14: ZeroPageRead(); TRB(); break; // TRB zp case 0x14: this.ZeroPageRead(); this.TRB(); break; // TRB zp
case 0x17: ZeroPageRead(); RMB(Bit(1)); break; // RMB1 zp case 0x17: this.ZeroPageRead(); this.RMB(Bit(1)); break; // RMB1 zp
case 0x1a: SwallowRead(); A = INC(A); break; // INC A case 0x1a: this.SwallowRead(); this.A = this.INC(this.A); break; // INC A
case 0x1b: break; // null case 0x1b: break; // null
case 0x1c: AbsoluteRead(); TRB(); break; // TRB a case 0x1c: this.AbsoluteRead(); this.TRB(); break; // TRB a
case 0x1f: ZeroPageRead(); BBR(Bit(1)); break; // BBR1 r case 0x1f: this.ZeroPageRead(); this.BBR(Bit(1)); break; // BBR1 r
case 0x22: SwallowFetch(); break; // NOP case 0x22: this.SwallowFetch(); break; // NOP
case 0x23: break; // null case 0x23: break; // null
case 0x27: ZeroPageRead(); RMB(Bit(2)); break; // RMB2 zp case 0x27: this.ZeroPageRead(); this.RMB(Bit(2)); break; // RMB2 zp
case 0x2b: break; // null case 0x2b: break; // null
case 0x2f: ZeroPageRead(); BBR(Bit(2)); break; // BBR2 r case 0x2f: this.ZeroPageRead(); this.BBR(Bit(2)); break; // BBR2 r
case 0x32: ZeroPageIndirectRead(); AndR(); break; // AND (zp) case 0x32: this.ZeroPageIndirectRead(); this.AndR(); break; // AND (zp)
case 0x33: break; // null case 0x33: break; // null
case 0x34: break; // BIT zp,x case 0x34: break; // BIT zp,x
case 0x37: ZeroPageRead(); RMB(Bit(3)); break; // RMB3 zp case 0x37: this.ZeroPageRead(); this.RMB(Bit(3)); break; // RMB3 zp
case 0x3a: SwallowRead(); A = DEC(A); break; // DEC A case 0x3a: this.SwallowRead(); this.A = this.DEC(this.A); break; // DEC A
case 0x3b: break; // null case 0x3b: break; // null
case 0x3c: break; // BIT a,x case 0x3c: break; // BIT a,x
case 0x3f: ZeroPageRead(); BBR(Bit(3)); break; // BBR3 r case 0x3f: this.ZeroPageRead(); this.BBR(Bit(3)); break; // BBR3 r
case 0x42: SwallowFetch(); break; // NOP case 0x42: this.SwallowFetch(); break; // NOP
case 0x43: break; // null case 0x43: break; // null
case 0x47: ZeroPageRead(); RMB(Bit(4)); break; // RMB4 zp case 0x47: this.ZeroPageRead(); this.RMB(Bit(4)); break; // RMB4 zp
case 0x4b: break; // null case 0x4b: break; // null
case 0x4f: ZeroPageRead(); BBR(Bit(4)); break; // BBR4 r case 0x4f: this.ZeroPageRead(); this.BBR(Bit(4)); break; // BBR4 r
case 0x52: ZeroPageIndirectRead(); EorR(); break; // EOR (zp) case 0x52: this.ZeroPageIndirectRead(); this.EorR(); break; // EOR (zp)
case 0x53: break; // null case 0x53: break; // null
case 0x57: ZeroPageRead(); RMB(Bit(5)); break; // RMB5 zp case 0x57: this.ZeroPageRead(); this.RMB(Bit(5)); break; // RMB5 zp
case 0x5a: SwallowRead(); Push(Y); break; // PHY s case 0x5a: this.SwallowRead(); this.Push(this.Y); break; // PHY s
case 0x5b: break; // null case 0x5b: break; // null
case 0x5c: break; // null case 0x5c: break; // null
case 0x5f: ZeroPageRead(); BBR(Bit(5)); break; // BBR5 r case 0x5f: this.ZeroPageRead(); this.BBR(Bit(5)); break; // BBR5 r
case 0x62: SwallowFetch(); break; // *NOP case 0x62: this.SwallowFetch(); break; // *NOP
case 0x63: break; // null case 0x63: break; // null
case 0x64: ZeroPageAddress(); MemoryWrite(0); break; // STZ zp case 0x64: this.ZeroPageAddress(); this.MemoryWrite(0); break; // STZ zp
case 0x67: ZeroPageRead(); RMB(Bit(6)); break; // RMB6 zp case 0x67: this.ZeroPageRead(); this.RMB(Bit(6)); break; // RMB6 zp
case 0x6b: break; // null case 0x6b: break; // null
case 0x6f: ZeroPageRead(); BBR(Bit(6)); break; // BBR6 r case 0x6f: this.ZeroPageRead(); this.BBR(Bit(6)); break; // BBR6 r
case 0x72: ZeroPageIndirectRead(); ADC(); break; // ADC (zp) case 0x72: this.ZeroPageIndirectRead(); this.ADC(); break; // ADC (zp)
case 0x73: break; // null case 0x73: break; // null
case 0x74: ZeroPageXAddress(); MemoryWrite(0); break; // STZ zp,x case 0x74: this.ZeroPageXAddress(); this.MemoryWrite(0); break; // STZ zp,x
case 0x77: ZeroPageRead(); RMB(Bit(7)); break; // RMB7 zp case 0x77: this.ZeroPageRead(); this.RMB(Bit(7)); break; // RMB7 zp
case 0x7a: SwallowRead(); SwallowPop(); Y = Through(Pop()); break; // PLY s case 0x7a: this.SwallowRead(); this.SwallowPop(); this.Y = this.Through(this.Pop()); break; // PLY s
case 0x7b: break; // null case 0x7b: break; // null
case 0x7c: break; // JMP (a,x) case 0x7c: break; // JMP (a,x)
case 0x7f: ZeroPageRead(); BBR(Bit(7)); break; // BBR7 r case 0x7f: this.ZeroPageRead(); this.BBR(Bit(7)); break; // BBR7 r
case 0x80: Branch(true); break; // BRA r case 0x80: this.Branch(true); break; // BRA r
case 0x83: break; // null case 0x83: break; // null
case 0x87: ZeroPageRead(); SMB(Bit(0)); break; // SMB0 zp case 0x87: this.ZeroPageRead(); this.SMB(Bit(0)); break; // SMB0 zp
case 0x89: break; // BIT # (TBC) case 0x89: break; // BIT # (TBC)
case 0x8b: break; // null case 0x8b: break; // null
case 0x8f: ZeroPageRead(); BBS(Bit(0)); break; // BBS0 r case 0x8f: this.ZeroPageRead(); this.BBS(Bit(0)); break; // BBS0 r
case 0x92: ZeroPageIndirectAddress(); MemoryWrite(A); break; // STA (zp) case 0x92: this.ZeroPageIndirectAddress(); this.MemoryWrite(this.A); break; // STA (zp)
case 0x93: break; // null case 0x93: break; // null
case 0x97: ZeroPageRead(); SMB(Bit(1)); break; // SMB1 zp case 0x97: this.ZeroPageRead(); this.SMB(Bit(1)); break; // SMB1 zp
case 0x9b: break; // null case 0x9b: break; // null
case 0x9c: AbsoluteAddress(); MemoryWrite(0); break; // STZ a case 0x9c: this.AbsoluteAddress(); this.MemoryWrite(0); break; // STZ a
case 0x9e: AbsoluteXAddress(); MemoryWrite(0); break; // STZ a,x case 0x9e: this.AbsoluteXAddress(); this.MemoryWrite(0); break; // STZ a,x
case 0x9f: ZeroPageRead(); BBS(Bit(1)); break; // BBS1 r case 0x9f: this.ZeroPageRead(); this.BBS(Bit(1)); break; // BBS1 r
case 0xa3: break; // null case 0xa3: break; // null
case 0xa7: ZeroPageRead(); SMB(Bit(2)); break; // SMB2 zp case 0xa7: this.ZeroPageRead(); this.SMB(Bit(2)); break; // SMB2 zp
case 0xab: break; // null case 0xab: break; // null
case 0xaf: ZeroPageRead(); BBS(Bit(2)); break; // BBS2 r case 0xaf: this.ZeroPageRead(); this.BBS(Bit(2)); break; // BBS2 r
case 0xb2: ZeroPageIndirectRead(); A = Through(); break; // LDA (zp) case 0xb2: this.ZeroPageIndirectRead(); this.A = this.Through(); break; // LDA (zp)
case 0xb3: break; // null case 0xb3: break; // null
case 0xb7: ZeroPageRead(); SMB(Bit(3)); break; // SMB3 zp case 0xb7: this.ZeroPageRead(); this.SMB(Bit(3)); break; // SMB3 zp
case 0xbb: break; // null case 0xbb: break; // null
case 0xbf: ZeroPageRead(); BBS(Bit(3)); break; // BBS3 r case 0xbf: this.ZeroPageRead(); this.BBS(Bit(3)); break; // BBS3 r
case 0xc3: break; // null case 0xc3: break; // null
case 0xc7: ZeroPageRead(); SMB(Bit(4)); break; // SMB4 zp case 0xc7: this.ZeroPageRead(); this.SMB(Bit(4)); break; // SMB4 zp
case 0xcb: SwallowRead(); Waiting = true; break; // WAI i case 0xcb: this.SwallowRead(); this.Waiting = true; break; // WAI i
case 0xcf: ZeroPageRead(); BBS(Bit(4)); break; // BBS4 r case 0xcf: this.ZeroPageRead(); this.BBS(Bit(4)); break; // BBS4 r
case 0xd2: ZeroPageIndirectRead(); CMP(A); break; // CMP (zp) case 0xd2: this.ZeroPageIndirectRead(); this.CMP(this.A); break; // CMP (zp)
case 0xd3: break; // null case 0xd3: break; // null
case 0xd7: ZeroPageRead(); SMB(Bit(5)); break; // SMB5 zp case 0xd7: this.ZeroPageRead(); this.SMB(Bit(5)); break; // SMB5 zp
case 0xda: SwallowRead(); Push(X); break; // PHX s case 0xda: this.SwallowRead(); this.Push(this.X); break; // PHX s
case 0xdb: SwallowRead(); Stopped = true; break; // STP i case 0xdb: this.SwallowRead(); this.Stopped = true; break; // STP i
case 0xdc: SwallowRead(); break; // null case 0xdc: this.SwallowRead(); break; // null
case 0xdf: ZeroPageRead(); BBS(Bit(5)); break; // BBS5 r case 0xdf: this.ZeroPageRead(); this.BBS(Bit(5)); break; // BBS5 r
case 0xe3: break; // null case 0xe3: break; // null
case 0xe7: ZeroPageRead(); SMB(Bit(6)); break; // SMB6 zp case 0xe7: this.ZeroPageRead(); this.SMB(Bit(6)); break; // SMB6 zp
case 0xeb: break; // null case 0xeb: break; // null
case 0xef: ZeroPageRead(); BBS(Bit(6)); break; // BBS6 r case 0xef: this.ZeroPageRead(); this.BBS(Bit(6)); break; // BBS6 r
case 0xf2: ZeroPageIndirectRead(); SBC(); break; // SBC (zp) case 0xf2: this.ZeroPageIndirectRead(); this.SBC(); break; // SBC (zp)
case 0xf3: break; // null case 0xf3: break; // null
case 0xf7: ZeroPageRead(); SMB(Bit(7)); break; // SMB7 zp case 0xf7: this.ZeroPageRead(); this.SMB(Bit(7)); break; // SMB7 zp
case 0xfa: SwallowRead(); SwallowPop(); X = Through(Pop()); break; // PLX s case 0xfa: this.SwallowRead(); this.SwallowPop(); this.X = this.Through(this.Pop()); break; // PLX s
case 0xfb: break; // null case 0xfb: break; // null
case 0xfc: break; // null case 0xfc: break; // null
case 0xff: ZeroPageRead(); BBS(Bit(7)); break; // BBS7 r case 0xff: this.ZeroPageRead(); this.BBS(Bit(7)); break; // BBS7 r
} }
return cycles != Cycles; return cycles != this.Cycles;
} }
public override void PoweredStep() public override void PoweredStep()
{ {
if (!Paused) if (!this.Paused)
{ {
base.PoweredStep(); base.PoweredStep();
} }
@@ -174,19 +174,19 @@ namespace M6502
protected override void OnLoweredRESET() protected override void OnLoweredRESET()
{ {
base.OnLoweredRESET(); base.OnLoweredRESET();
Stopped = Waiting = false; this.Stopped = this.Waiting = false;
} }
protected override void OnLoweredINT() protected override void OnLoweredINT()
{ {
base.OnLoweredINT(); base.OnLoweredINT();
Waiting = false; this.Waiting = false;
} }
protected override void OnLoweredNMI() protected override void OnLoweredNMI()
{ {
base.OnLoweredNMI(); base.OnLoweredNMI();
Waiting = false; this.Waiting = false;
} }
#endregion #endregion
@@ -196,8 +196,8 @@ namespace M6502
protected override void ModifyWrite(byte data) protected override void ModifyWrite(byte data)
{ {
// The read will have already taken place... // The read will have already taken place...
MemoryRead(); // Modify cycle (Change from MOS6502) this.MemoryRead(); // Modify cycle (Change from MOS6502)
MemoryWrite(data); // Write cycle this.MemoryWrite(data); // Write cycle
} }
#endregion #endregion
@@ -210,22 +210,22 @@ namespace M6502
protected override byte FetchByte() protected override byte FetchByte()
{ {
lastFetchAddress.Assign(PC); this.lastFetchAddress.Assign(this.PC);
return base.FetchByte(); return base.FetchByte();
} }
protected override void Fixup() protected override void Fixup()
{ {
var fixingLow = Bus.Address.Low; var fixingLow = this.Bus.Address.Low;
MemoryRead(lastFetchAddress); this.MemoryRead(this.lastFetchAddress);
Bus.Address.Assign(fixingLow, FixedPage); this.Bus.Address.Assign(fixingLow, this.FixedPage);
} }
protected override void FixupBranch(sbyte relative) protected override void FixupBranch(sbyte relative)
{ {
NoteFixedAddress(PC.Word + relative); this.NoteFixedAddress(this.PC.Word + relative);
lastFetchAddress.Assign(Bus.Address); // Effectively negate the use of "lastFetchAddress" for branch fixup usages this.lastFetchAddress.Assign(this.Bus.Address); // Effectively negate the use of "lastFetchAddress" for branch fixup usages
MaybeFixup(); this.MaybeFixup();
} }
#endregion #endregion
@@ -234,20 +234,20 @@ namespace M6502
protected void GetAddress() protected void GetAddress()
{ {
GetWordPaged(); this.GetWordPaged();
if (Bus.Address.Low == 0) if (this.Bus.Address.Low == 0)
{ {
Bus.Address.High++; this.Bus.Address.High++;
} }
Bus.Address.Assign(Intermediate.Low, MemoryRead()); this.Bus.Address.Assign(this.Intermediate.Low, this.MemoryRead());
} }
protected override void IndirectAddress() protected override void IndirectAddress()
{ {
AbsoluteAddress(); this.AbsoluteAddress();
GetAddress(); this.GetAddress();
} }
#endregion #endregion
@@ -256,8 +256,8 @@ namespace M6502
private void ZeroPageIndirectRead() private void ZeroPageIndirectRead()
{ {
ZeroPageIndirectAddress(); this.ZeroPageIndirectAddress();
MemoryRead(); this.MemoryRead();
} }
#endregion #endregion
@@ -266,40 +266,40 @@ namespace M6502
private void RMB(byte flag) private void RMB(byte flag)
{ {
MemoryRead(); this.MemoryRead();
Bus.Data &= (byte)~flag; this.Bus.Data &= (byte)~flag;
MemoryWrite(); this.MemoryWrite();
} }
private void SMB(byte flag) private void SMB(byte flag)
{ {
MemoryRead(); this.MemoryRead();
Bus.Data |= flag; this.Bus.Data |= flag;
MemoryWrite(); this.MemoryWrite();
} }
private void BBS(byte flag) private void BBS(byte flag)
{ {
MemoryRead(); this.MemoryRead();
Branch(Bus.Data & flag); this.Branch(this.Bus.Data & flag);
} }
private void BBR(byte flag) private void BBR(byte flag)
{ {
MemoryRead(); this.MemoryRead();
BranchNot(Bus.Data & flag); this.BranchNot(this.Bus.Data & flag);
} }
private void TSB() private void TSB()
{ {
AdjustZero((byte)(A & Bus.Data)); this.AdjustZero((byte)(this.A & this.Bus.Data));
ModifyWrite((byte)(A | Bus.Data)); this.ModifyWrite((byte)(this.A | this.Bus.Data));
} }
private void TRB() private void TRB()
{ {
AdjustZero((byte)(A & Bus.Data)); this.AdjustZero((byte)(this.A & this.Bus.Data));
ModifyWrite((byte)(~A & Bus.Data)); this.ModifyWrite((byte)(~this.A & this.Bus.Data));
} }
} }
} }