mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2025-01-21 09:29:48 +00:00
Apply .net 9 analysis
This commit is contained in:
parent
a3fd5b055a
commit
515c679e68
891
M6502/Core.cs
891
M6502/Core.cs
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
||||
|
||||
namespace M6502
|
||||
{
|
||||
using EightBit;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using EightBit;
|
||||
|
||||
public class Disassembler(Bus bus, Core processor, Symbols.Parser symbols)
|
||||
{
|
||||
@ -35,16 +35,16 @@ namespace M6502
|
||||
|
||||
public string Disassemble(ushort current)
|
||||
{
|
||||
address = current;
|
||||
this.address = current;
|
||||
|
||||
var output = new StringBuilder();
|
||||
|
||||
var cell = bus.Peek(current);
|
||||
var cell = this.bus.Peek(current);
|
||||
|
||||
output.Append(DumpByteValue(cell));
|
||||
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 aaa = (cell & 0b11100000) >> 5;
|
||||
@ -60,28 +60,28 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b000: // BRK
|
||||
output.Append(Disassemble_Implied("BRK"));
|
||||
output.Append(this.Disassemble_Implied("BRK"));
|
||||
break;
|
||||
case 0b001: // DOP/NOP (0x04)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b010: // PHP
|
||||
output.Append(Disassemble_Implied("PHP"));
|
||||
output.Append(this.Disassemble_Implied("PHP"));
|
||||
break;
|
||||
case 0b011: // TOP/NOP (0b00001100, 0x0c)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b100: // BPL
|
||||
output.Append(Disassemble_Relative("BPL", relative));
|
||||
output.Append(this.Disassemble_Relative("BPL", relative));
|
||||
break;
|
||||
case 0b101: // DOP/NOP (0x14)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b110: // CLC
|
||||
output.Append(Disassemble_Implied("CLC"));
|
||||
output.Append(this.Disassemble_Implied("CLC"));
|
||||
break;
|
||||
case 0b111: // TOP/NOP (0b00011100, 0x1c)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Illegal instruction");
|
||||
@ -92,25 +92,25 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b000: // JSR
|
||||
output.Append(Disassemble_Absolute("JSR"));
|
||||
output.Append(this.Disassemble_Absolute("JSR"));
|
||||
break;
|
||||
case 0b010: // PLP
|
||||
output.Append(Disassemble_Implied("PLP"));
|
||||
output.Append(this.Disassemble_Implied("PLP"));
|
||||
break;
|
||||
case 0b100: // BMI
|
||||
output.Append(Disassemble_Relative("BMI", relative));
|
||||
output.Append(this.Disassemble_Relative("BMI", relative));
|
||||
break;
|
||||
case 0b101: // DOP/NOP (0x34)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b110: // SEC
|
||||
output.Append(Disassemble_Implied("SEC"));
|
||||
output.Append(this.Disassemble_Implied("SEC"));
|
||||
break;
|
||||
case 0b111: // TOP/NOP (0b00111100, 0x3c)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
default: // BIT
|
||||
output.Append(Disassemble_AM_00(bbb, "BIT"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "BIT"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -119,28 +119,28 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b000: // RTI
|
||||
output.Append(Disassemble_Implied("RTI"));
|
||||
output.Append(this.Disassemble_Implied("RTI"));
|
||||
break;
|
||||
case 0b001: // DOP/NOP (0x44)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b010: // PHA
|
||||
output.Append(Disassemble_Implied("PHA"));
|
||||
output.Append(this.Disassemble_Implied("PHA"));
|
||||
break;
|
||||
case 0b011: // JMP
|
||||
output.Append(Disassemble_Absolute("JMP"));
|
||||
output.Append(this.Disassemble_Absolute("JMP"));
|
||||
break;
|
||||
case 0b100: // BVC
|
||||
output.Append(Disassemble_Relative("BVC", relative));
|
||||
output.Append(this.Disassemble_Relative("BVC", relative));
|
||||
break;
|
||||
case 0b101: // DOP/NOP (0x54)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b110: // CLI
|
||||
output.Append(Disassemble_Implied("CLI"));
|
||||
output.Append(this.Disassemble_Implied("CLI"));
|
||||
break;
|
||||
case 0b111: // TOP/NOP (0b01011100, 0x5c)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Illegal addressing mode");
|
||||
@ -151,28 +151,28 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b000: // RTS
|
||||
output.Append(Disassemble_Implied("RTS"));
|
||||
output.Append(this.Disassemble_Implied("RTS"));
|
||||
break;
|
||||
case 0b001: // DOP/NOP (0x64)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b010: // PLA
|
||||
output.Append(Disassemble_Implied("PLA"));
|
||||
output.Append(this.Disassemble_Implied("PLA"));
|
||||
break;
|
||||
case 0b011: // JMP (abs)
|
||||
output.Append(Disassemble_Indirect("JMP"));
|
||||
output.Append(this.Disassemble_Indirect("JMP"));
|
||||
break;
|
||||
case 0b100: // BVS
|
||||
output.Append(Disassemble_Relative("BVS", relative));
|
||||
output.Append(this.Disassemble_Relative("BVS", relative));
|
||||
break;
|
||||
case 0b101: // DOP/NOP (0x74)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b110: // SEI
|
||||
output.Append(Disassemble_Implied("SEI"));
|
||||
output.Append(this.Disassemble_Implied("SEI"));
|
||||
break;
|
||||
case 0b111: // TOP/NOP (0b01111100, 0x7c)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Illegal addressing mode");
|
||||
@ -183,19 +183,19 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b000: // DOP/NOP (0x80)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b010: // DEY
|
||||
output.Append(Disassemble_Implied("DEY"));
|
||||
output.Append(this.Disassemble_Implied("DEY"));
|
||||
break;
|
||||
case 0b100: // BCC
|
||||
output.Append(Disassemble_Relative("BCC", relative));
|
||||
output.Append(this.Disassemble_Relative("BCC", relative));
|
||||
break;
|
||||
case 0b110: // TYA
|
||||
output.Append(Disassemble_Implied("TYA"));
|
||||
output.Append(this.Disassemble_Implied("TYA"));
|
||||
break;
|
||||
default: // STY
|
||||
output.Append(Disassemble_AM_00(bbb, "STY"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "STY"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -204,16 +204,16 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010: // TAY
|
||||
output.Append(Disassemble_Implied("TAY"));
|
||||
output.Append(this.Disassemble_Implied("TAY"));
|
||||
break;
|
||||
case 0b100: // BCS
|
||||
output.Append(Disassemble_Relative("BCS", relative));
|
||||
output.Append(this.Disassemble_Relative("BCS", relative));
|
||||
break;
|
||||
case 0b110: // CLV
|
||||
output.Append(Disassemble_Implied("CLV"));
|
||||
output.Append(this.Disassemble_Implied("CLV"));
|
||||
break;
|
||||
default: // LDY
|
||||
output.Append(Disassemble_AM_00(bbb, "LDY"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "LDY"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -222,22 +222,22 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010: // INY
|
||||
output.Append(Disassemble_Implied("INY"));
|
||||
output.Append(this.Disassemble_Implied("INY"));
|
||||
break;
|
||||
case 0b100: // BNE
|
||||
output.Append(Disassemble_Relative("BNE", relative));
|
||||
output.Append(this.Disassemble_Relative("BNE", relative));
|
||||
break;
|
||||
case 0b101: // DOP/NOP (0xd4)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b110: // CLD
|
||||
output.Append(Disassemble_Implied("CLD"));
|
||||
output.Append(this.Disassemble_Implied("CLD"));
|
||||
break;
|
||||
case 0b111: // TOP/NOP (0b11011100, 0xdc)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
default: // CPY
|
||||
output.Append(Disassemble_AM_00(bbb, "CPY"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "CPY"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -246,22 +246,22 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010: // INX
|
||||
output.Append(Disassemble_Implied("INX"));
|
||||
output.Append(this.Disassemble_Implied("INX"));
|
||||
break;
|
||||
case 0b100: // BEQ
|
||||
output.Append(Disassemble_Relative("BEQ", relative));
|
||||
output.Append(this.Disassemble_Relative("BEQ", relative));
|
||||
break;
|
||||
case 0b101: // DOP/NOP (0xf4)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
case 0b110: // SED
|
||||
output.Append(Disassemble_Implied("SED"));
|
||||
output.Append(this.Disassemble_Implied("SED"));
|
||||
break;
|
||||
case 0b111: // TOP/NOP (0b11111100, 0xfc)
|
||||
output.Append(Disassemble_AM_00(bbb, "*NOP"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "*NOP"));
|
||||
break;
|
||||
default: // CPX
|
||||
output.Append(Disassemble_AM_00(bbb, "CPX"));
|
||||
output.Append(this.Disassemble_AM_00(bbb, "CPX"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -273,28 +273,28 @@ namespace M6502
|
||||
switch (aaa)
|
||||
{
|
||||
case 0b000: // ORA
|
||||
output.Append(Disassemble_AM_01(bbb, "ORA"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "ORA"));
|
||||
break;
|
||||
case 0b001: // AND
|
||||
output.Append(Disassemble_AM_01(bbb, "AND"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "AND"));
|
||||
break;
|
||||
case 0b010: // EOR
|
||||
output.Append(Disassemble_AM_01(bbb, "EOR"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "EOR"));
|
||||
break;
|
||||
case 0b011: // ADC
|
||||
output.Append(Disassemble_AM_01(bbb, "ADC"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "ADC"));
|
||||
break;
|
||||
case 0b100: // STA
|
||||
output.Append(Disassemble_AM_01(bbb, "STA"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "STA"));
|
||||
break;
|
||||
case 0b101: // LDA
|
||||
output.Append(Disassemble_AM_01(bbb, "LDA"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "LDA"));
|
||||
break;
|
||||
case 0b110: // CMP
|
||||
output.Append(Disassemble_AM_01(bbb, "CMP"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "CMP"));
|
||||
break;
|
||||
case 0b111: // SBC
|
||||
output.Append(Disassemble_AM_01(bbb, "SBC"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "SBC"));
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Illegal addressing mode");
|
||||
@ -308,10 +308,10 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b110: // 0x1a
|
||||
output.Append(Disassemble_Implied("*NOP"));
|
||||
output.Append(this.Disassemble_Implied("*NOP"));
|
||||
break;
|
||||
default:
|
||||
output.Append(Disassemble_AM_10(bbb, "ASL"));
|
||||
output.Append(this.Disassemble_AM_10(bbb, "ASL"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -320,10 +320,10 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b110: // 0x3a
|
||||
output.Append(Disassemble_Implied("*NOP"));
|
||||
output.Append(this.Disassemble_Implied("*NOP"));
|
||||
break;
|
||||
default:
|
||||
output.Append(Disassemble_AM_10(bbb, "ROL"));
|
||||
output.Append(this.Disassemble_AM_10(bbb, "ROL"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -332,10 +332,10 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b110: // 0x5a
|
||||
output.Append(Disassemble_Implied("*NOP"));
|
||||
output.Append(this.Disassemble_Implied("*NOP"));
|
||||
break;
|
||||
default:
|
||||
output.Append(Disassemble_AM_10(bbb, "LSR"));
|
||||
output.Append(this.Disassemble_AM_10(bbb, "LSR"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -344,10 +344,10 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b110: // 0x7a
|
||||
output.Append(Disassemble_Implied("*NOP"));
|
||||
output.Append(this.Disassemble_Implied("*NOP"));
|
||||
break;
|
||||
default:
|
||||
output.Append(Disassemble_AM_10(bbb, "ROR"));
|
||||
output.Append(this.Disassemble_AM_10(bbb, "ROR"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -356,13 +356,13 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010: // TXA
|
||||
output.Append(Disassemble_Implied("TXA"));
|
||||
output.Append(this.Disassemble_Implied("TXA"));
|
||||
break;
|
||||
case 0b110: // TXS
|
||||
output.Append(Disassemble_Implied("TXS"));
|
||||
output.Append(this.Disassemble_Implied("TXS"));
|
||||
break;
|
||||
default: // STX
|
||||
output.Append(Disassemble_AM_10_x(bbb, "STX"));
|
||||
output.Append(this.Disassemble_AM_10_x(bbb, "STX"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -371,13 +371,13 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010: // TAX
|
||||
output.Append(Disassemble_Implied("TAX"));
|
||||
output.Append(this.Disassemble_Implied("TAX"));
|
||||
break;
|
||||
case 0b110: // TSX
|
||||
output.Append(Disassemble_Implied("TSX"));
|
||||
output.Append(this.Disassemble_Implied("TSX"));
|
||||
break;
|
||||
default: // LDX
|
||||
output.Append(Disassemble_AM_10_x(bbb, "LDX"));
|
||||
output.Append(this.Disassemble_AM_10_x(bbb, "LDX"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -386,13 +386,13 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010: // DEX
|
||||
output.Append(Disassemble_Implied("DEX"));
|
||||
output.Append(this.Disassemble_Implied("DEX"));
|
||||
break;
|
||||
case 0b110: // 0xda
|
||||
output.Append(Disassemble_Implied("*NOP"));
|
||||
output.Append(this.Disassemble_Implied("*NOP"));
|
||||
break;
|
||||
default: // DEC
|
||||
output.Append(Disassemble_AM_10(bbb, "DEC"));
|
||||
output.Append(this.Disassemble_AM_10(bbb, "DEC"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -401,13 +401,13 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010: // NOP
|
||||
output.Append(Disassemble_Implied("NOP"));
|
||||
output.Append(this.Disassemble_Implied("NOP"));
|
||||
break;
|
||||
case 0b110: // 0xfa
|
||||
output.Append(Disassemble_Implied("*NOP"));
|
||||
output.Append(this.Disassemble_Implied("*NOP"));
|
||||
break;
|
||||
default: // INC
|
||||
output.Append(Disassemble_AM_10(bbb, "INC"));
|
||||
output.Append(this.Disassemble_AM_10(bbb, "INC"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -424,10 +424,10 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010:
|
||||
output.Append(Disassemble_Immediate("*AAC"));
|
||||
output.Append(this.Disassemble_Immediate("*AAC"));
|
||||
break;
|
||||
default:
|
||||
output.Append(Disassemble_AM_01(bbb, "*SLO"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "*SLO"));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -437,28 +437,28 @@ namespace M6502
|
||||
switch (bbb)
|
||||
{
|
||||
case 0b010:
|
||||
output.Append(Disassemble_Immediate("*AAC"));
|
||||
output.Append(this.Disassemble_Immediate("*AAC"));
|
||||
break;
|
||||
default:
|
||||
output.Append(Disassemble_AM_01(bbb, "*RLA"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "*RLA"));
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0b010:
|
||||
output.Append(Disassemble_AM_01(bbb, "*SRE"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "*SRE"));
|
||||
break;
|
||||
case 0b011:
|
||||
output.Append(Disassemble_AM_01(bbb, "*RRA"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "*RRA"));
|
||||
break;
|
||||
case 0b100:
|
||||
output.Append(Disassemble_AM_11(bbb, "*SAX"));
|
||||
output.Append(this.Disassemble_AM_11(bbb, "*SAX"));
|
||||
break;
|
||||
case 0b101:
|
||||
output.Append(Disassemble_AM_11(bbb, "*LAX"));
|
||||
output.Append(this.Disassemble_AM_11(bbb, "*LAX"));
|
||||
break;
|
||||
case 0b110:
|
||||
output.Append(Disassemble_AM_11_x(bbb, "*DCP"));
|
||||
output.Append(this.Disassemble_AM_11_x(bbb, "*DCP"));
|
||||
break;
|
||||
case 0b111:
|
||||
switch (bbb)
|
||||
@ -470,10 +470,10 @@ namespace M6502
|
||||
case 0b101:
|
||||
case 0b110:
|
||||
case 0b111:
|
||||
output.Append(Disassemble_AM_01(bbb, "*ISB"));
|
||||
output.Append(this.Disassemble_AM_01(bbb, "*ISB"));
|
||||
break;
|
||||
case 0b010:
|
||||
output.Append(Disassemble_AM_11(bbb, "*SBC"));
|
||||
output.Append(this.Disassemble_AM_11(bbb, "*SBC"));
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Impossible addressing mode");
|
||||
@ -496,27 +496,27 @@ namespace M6502
|
||||
|
||||
#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)
|
||||
{
|
||||
return symbols.TryGetQualifiedLabelByAddress(absolute, out name);
|
||||
return this.symbols.TryGetQualifiedLabelByAddress(absolute, out name);
|
||||
}
|
||||
|
||||
private string MaybeGetLabel(ushort absolute)
|
||||
{
|
||||
return symbols.MaybeGetQualifiedLabelByAddress(absolute);
|
||||
return this.symbols.MaybeGetQualifiedLabelByAddress(absolute);
|
||||
}
|
||||
|
||||
private string MaybeGetCodeLabel(ushort absolute)
|
||||
{
|
||||
var label = MaybeGetLabel(absolute);
|
||||
var label = this.MaybeGetLabel(absolute);
|
||||
if (string.IsNullOrEmpty(label))
|
||||
{
|
||||
return string.Empty;
|
||||
@ -526,7 +526,7 @@ namespace M6502
|
||||
|
||||
private string MaybeGetCodeLabel()
|
||||
{
|
||||
return Pad(MaybeGetCodeLabel(address), 30);
|
||||
return Pad(this.MaybeGetCodeLabel(this.address), 30);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -535,46 +535,46 @@ namespace M6502
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
@ -589,179 +589,179 @@ namespace M6502
|
||||
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
|
||||
{
|
||||
0b000 => AM_Immediate_dump(),
|
||||
0b001 => AM_ZeroPage_dump(),
|
||||
0b011 => AM_Absolute_dump(),
|
||||
0b101 => AM_ZeroPageX_dump(),
|
||||
0b111 => AM_AbsoluteX_dump(),
|
||||
0b000 => this.AM_Immediate_dump(),
|
||||
0b001 => this.AM_ZeroPage_dump(),
|
||||
0b011 => this.AM_Absolute_dump(),
|
||||
0b101 => this.AM_ZeroPageX_dump(),
|
||||
0b111 => this.AM_AbsoluteX_dump(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_00(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_Immediate(),
|
||||
0b001 => AM_ZeroPage(),
|
||||
0b011 => AM_Absolute(),
|
||||
0b101 => AM_ZeroPageX(),
|
||||
0b111 => AM_AbsoluteX(),
|
||||
0b000 => this.AM_Immediate(),
|
||||
0b001 => this.AM_ZeroPage(),
|
||||
0b011 => this.AM_Absolute(),
|
||||
0b101 => this.AM_ZeroPageX(),
|
||||
0b111 => this.AM_AbsoluteX(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_01_dump(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_IndexedIndirectX_dump(),
|
||||
0b001 => AM_ZeroPage_dump(),
|
||||
0b010 => AM_Immediate_dump(),
|
||||
0b011 => AM_Absolute_dump(),
|
||||
0b100 => AM_IndirectIndexedY_dump(),
|
||||
0b101 => AM_ZeroPageX_dump(),
|
||||
0b110 => AM_AbsoluteY_dump(),
|
||||
0b111 => AM_AbsoluteX_dump(),
|
||||
0b000 => this.AM_IndexedIndirectX_dump(),
|
||||
0b001 => this.AM_ZeroPage_dump(),
|
||||
0b010 => this.AM_Immediate_dump(),
|
||||
0b011 => this.AM_Absolute_dump(),
|
||||
0b100 => this.AM_IndirectIndexedY_dump(),
|
||||
0b101 => this.AM_ZeroPageX_dump(),
|
||||
0b110 => this.AM_AbsoluteY_dump(),
|
||||
0b111 => this.AM_AbsoluteX_dump(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_01(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_IndexedIndirectX(),
|
||||
0b001 => AM_ZeroPage(),
|
||||
0b010 => AM_Immediate(),
|
||||
0b011 => AM_Absolute(),
|
||||
0b100 => AM_IndirectIndexedY(),
|
||||
0b101 => AM_ZeroPageX(),
|
||||
0b110 => AM_AbsoluteY(),
|
||||
0b111 => AM_AbsoluteX(),
|
||||
0b000 => this.AM_IndexedIndirectX(),
|
||||
0b001 => this.AM_ZeroPage(),
|
||||
0b010 => this.AM_Immediate(),
|
||||
0b011 => this.AM_Absolute(),
|
||||
0b100 => this.AM_IndirectIndexedY(),
|
||||
0b101 => this.AM_ZeroPageX(),
|
||||
0b110 => this.AM_AbsoluteY(),
|
||||
0b111 => this.AM_AbsoluteX(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_10_dump(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_Immediate_dump(),
|
||||
0b001 => AM_ZeroPage_dump(),
|
||||
0b000 => this.AM_Immediate_dump(),
|
||||
0b001 => this.AM_ZeroPage_dump(),
|
||||
0b010 => string.Empty,
|
||||
0b011 => AM_Absolute_dump(),
|
||||
0b101 => AM_ZeroPageX_dump(),
|
||||
0b111 => AM_AbsoluteX_dump(),
|
||||
0b011 => this.AM_Absolute_dump(),
|
||||
0b101 => this.AM_ZeroPageX_dump(),
|
||||
0b111 => this.AM_AbsoluteX_dump(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_10(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_Immediate(),
|
||||
0b001 => AM_ZeroPage(),
|
||||
0b000 => this.AM_Immediate(),
|
||||
0b001 => this.AM_ZeroPage(),
|
||||
0b010 => "A",
|
||||
0b011 => AM_Absolute(),
|
||||
0b101 => AM_ZeroPageX(),
|
||||
0b111 => AM_AbsoluteX(),
|
||||
0b011 => this.AM_Absolute(),
|
||||
0b101 => this.AM_ZeroPageX(),
|
||||
0b111 => this.AM_AbsoluteX(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_10_x_dump(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_Immediate_dump(),
|
||||
0b001 => AM_ZeroPage_dump(),
|
||||
0b000 => this.AM_Immediate_dump(),
|
||||
0b001 => this.AM_ZeroPage_dump(),
|
||||
0b010 => string.Empty,
|
||||
0b011 => AM_Absolute_dump(),
|
||||
0b101 => AM_ZeroPageY_dump(),
|
||||
0b111 => AM_AbsoluteY_dump(),
|
||||
0b011 => this.AM_Absolute_dump(),
|
||||
0b101 => this.AM_ZeroPageY_dump(),
|
||||
0b111 => this.AM_AbsoluteY_dump(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_10_x(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_Immediate(),
|
||||
0b001 => AM_ZeroPage(),
|
||||
0b000 => this.AM_Immediate(),
|
||||
0b001 => this.AM_ZeroPage(),
|
||||
0b010 => "A",
|
||||
0b011 => AM_Absolute(),
|
||||
0b101 => AM_ZeroPageY(),
|
||||
0b111 => AM_AbsoluteY(),
|
||||
0b011 => this.AM_Absolute(),
|
||||
0b101 => this.AM_ZeroPageY(),
|
||||
0b111 => this.AM_AbsoluteY(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_11_dump(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_IndexedIndirectX_dump(),
|
||||
0b001 => AM_ZeroPage_dump(),
|
||||
0b010 => AM_Immediate_dump(),
|
||||
0b011 => AM_Absolute_dump(),
|
||||
0b100 => AM_IndirectIndexedY_dump(),
|
||||
0b101 => AM_ZeroPageY_dump(),
|
||||
0b111 => AM_AbsoluteY_dump(),
|
||||
0b000 => this.AM_IndexedIndirectX_dump(),
|
||||
0b001 => this.AM_ZeroPage_dump(),
|
||||
0b010 => this.AM_Immediate_dump(),
|
||||
0b011 => this.AM_Absolute_dump(),
|
||||
0b100 => this.AM_IndirectIndexedY_dump(),
|
||||
0b101 => this.AM_ZeroPageY_dump(),
|
||||
0b111 => this.AM_AbsoluteY_dump(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_11_x_dump(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_IndexedIndirectX_dump(),
|
||||
0b001 => AM_ZeroPage_dump(),
|
||||
0b010 => AM_Immediate_dump(),
|
||||
0b011 => AM_Absolute_dump(),
|
||||
0b100 => AM_IndirectIndexedY_dump(),
|
||||
0b101 => AM_ZeroPageX_dump(),
|
||||
0b110 => AM_AbsoluteY_dump(),
|
||||
0b111 => AM_AbsoluteX_dump(),
|
||||
0b000 => this.AM_IndexedIndirectX_dump(),
|
||||
0b001 => this.AM_ZeroPage_dump(),
|
||||
0b010 => this.AM_Immediate_dump(),
|
||||
0b011 => this.AM_Absolute_dump(),
|
||||
0b100 => this.AM_IndirectIndexedY_dump(),
|
||||
0b101 => this.AM_ZeroPageX_dump(),
|
||||
0b110 => this.AM_AbsoluteY_dump(),
|
||||
0b111 => this.AM_AbsoluteX_dump(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_11(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_IndexedIndirectX(),
|
||||
0b001 => AM_ZeroPage(),
|
||||
0b010 => AM_Immediate(),
|
||||
0b011 => AM_Absolute(),
|
||||
0b100 => AM_IndirectIndexedY(),
|
||||
0b101 => AM_ZeroPageY(),
|
||||
0b111 => AM_AbsoluteY(),
|
||||
0b000 => this.AM_IndexedIndirectX(),
|
||||
0b001 => this.AM_ZeroPage(),
|
||||
0b010 => this.AM_Immediate(),
|
||||
0b011 => this.AM_Absolute(),
|
||||
0b100 => this.AM_IndirectIndexedY(),
|
||||
0b101 => this.AM_ZeroPageY(),
|
||||
0b111 => this.AM_AbsoluteY(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
|
||||
private string AM_11_x(int bbb) => bbb switch
|
||||
{
|
||||
0b000 => AM_IndexedIndirectX(),
|
||||
0b001 => AM_ZeroPage(),
|
||||
0b010 => AM_Immediate(),
|
||||
0b011 => AM_Absolute(),
|
||||
0b100 => AM_IndirectIndexedY(),
|
||||
0b101 => AM_ZeroPageX(),
|
||||
0b110 => AM_AbsoluteY(),
|
||||
0b111 => AM_AbsoluteX(),
|
||||
0b000 => this.AM_IndexedIndirectX(),
|
||||
0b001 => this.AM_ZeroPage(),
|
||||
0b010 => this.AM_Immediate(),
|
||||
0b011 => this.AM_Absolute(),
|
||||
0b100 => this.AM_IndirectIndexedY(),
|
||||
0b101 => this.AM_ZeroPageX(),
|
||||
0b110 => this.AM_AbsoluteY(),
|
||||
0b111 => this.AM_AbsoluteX(),
|
||||
_ => throw new InvalidOperationException("Illegal addressing mode"),
|
||||
};
|
||||
}
|
||||
|
@ -16,11 +16,11 @@
|
||||
|
||||
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; } = [];
|
||||
|
||||
@ -28,67 +28,67 @@
|
||||
|
||||
public Checker(TestRunner runner)
|
||||
{
|
||||
Runner = runner;
|
||||
Disassembler = new(Runner, (M6502.Core)Runner.CPU, Symbols);
|
||||
this.Runner = runner;
|
||||
this.Disassembler = new(this.Runner, this.Runner.CPU, this.Symbols);
|
||||
}
|
||||
|
||||
public void Check(Test test)
|
||||
{
|
||||
var cpu = Runner.CPU;
|
||||
var cpu = this.Runner.CPU;
|
||||
|
||||
Reset();
|
||||
this.Reset();
|
||||
|
||||
Runner.RaisePOWER();
|
||||
InitialiseState(test);
|
||||
this.Runner.RaisePOWER();
|
||||
this.InitialiseState(test);
|
||||
var pc = cpu.PC.Word;
|
||||
|
||||
Cycles = cpu.Step();
|
||||
Runner.LowerPOWER();
|
||||
this.Cycles = cpu.Step();
|
||||
this.Runner.LowerPOWER();
|
||||
|
||||
Valid = CheckState(test);
|
||||
this.Valid = this.CheckState(test);
|
||||
|
||||
if (Unimplemented)
|
||||
if (this.Unimplemented)
|
||||
{
|
||||
Messages.Add("Unimplemented");
|
||||
this.Messages.Add("Unimplemented");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Assert(Implemented);
|
||||
if (Invalid)
|
||||
Debug.Assert(this.Implemented);
|
||||
if (this.Invalid)
|
||||
{
|
||||
AddDisassembly(pc);
|
||||
this.AddDisassembly(pc);
|
||||
|
||||
var final = test.Final ?? throw new InvalidOperationException("Final test state cannot be null");
|
||||
|
||||
Raise("PC", final.PC, cpu.PC.Word);
|
||||
Raise("S", final.S, cpu.S);
|
||||
Raise("A", final.A, cpu.A);
|
||||
Raise("X", final.X, cpu.X);
|
||||
Raise("Y", final.Y, cpu.Y);
|
||||
Raise("P", final.P, cpu.P);
|
||||
this.Raise("PC", final.PC, cpu.PC.Word);
|
||||
this.Raise("S", final.S, cpu.S);
|
||||
this.Raise("A", final.A, cpu.A);
|
||||
this.Raise("X", final.X, cpu.X);
|
||||
this.Raise("Y", final.Y, cpu.Y);
|
||||
this.Raise("P", final.P, cpu.P);
|
||||
|
||||
if (test.Cycles == 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());
|
||||
DumpCycles("-- Actual cycles", ActualCycles);
|
||||
this.DumpCycles("-- Expected cycles", test.AvailableCycles());
|
||||
this.DumpCycles("-- Actual cycles", this.ActualCycles);
|
||||
}
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
Messages.Clear();
|
||||
ActualCycles.Clear();
|
||||
this.Messages.Clear();
|
||||
this.ActualCycles.Clear();
|
||||
|
||||
CycleCountMismatch = false;
|
||||
Cycles = 0;
|
||||
Valid = false;
|
||||
this.CycleCountMismatch = false;
|
||||
this.Cycles = 0;
|
||||
this.Valid = false;
|
||||
}
|
||||
|
||||
private bool Check(string what, ushort expected, ushort actual)
|
||||
@ -96,7 +96,7 @@
|
||||
var success = actual == expected;
|
||||
if (!success)
|
||||
{
|
||||
Raise(what, expected, actual);
|
||||
this.Raise(what, expected, actual);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@ -106,7 +106,7 @@
|
||||
var success = actual == expected;
|
||||
if (!success)
|
||||
{
|
||||
Raise(what, expected, actual);
|
||||
this.Raise(what, expected, actual);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@ -118,7 +118,7 @@
|
||||
var success = actual == expected;
|
||||
if (!success)
|
||||
{
|
||||
Raise(what, expected, actual);
|
||||
this.Raise(what, expected, actual);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@ -128,7 +128,7 @@
|
||||
var success = actual == expected;
|
||||
if (!success)
|
||||
{
|
||||
Raise($"{what}: {address}", expected, actual);
|
||||
this.Raise($"{what}: {address}", expected, actual);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@ -138,32 +138,33 @@
|
||||
string message;
|
||||
try
|
||||
{
|
||||
message = Disassemble(address);
|
||||
message = this.Disassemble(address);
|
||||
}
|
||||
catch (InvalidOperationException error)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var cpu = Runner.CPU;
|
||||
var ram = Runner.RAM;
|
||||
var cpu = this.Runner.CPU;
|
||||
var ram = this.Runner.RAM;
|
||||
|
||||
var expectedCycles = test.AvailableCycles();
|
||||
var actualCycles = ActualCycles;
|
||||
var actualCycles = this.ActualCycles;
|
||||
|
||||
var actualIDX = 0;
|
||||
foreach (var expectedCycle in expectedCycles) {
|
||||
foreach (var expectedCycle in expectedCycles)
|
||||
{
|
||||
|
||||
if (actualIDX >= actualCycles.Count)
|
||||
{
|
||||
CycleCountMismatch = true;
|
||||
this.CycleCountMismatch = true;
|
||||
return false; // more expected cycles than actual
|
||||
}
|
||||
|
||||
@ -171,40 +172,40 @@
|
||||
|
||||
var expectedAddress = expectedCycle.Address;
|
||||
var actualAddress = actualCycle.Address;
|
||||
_ = Check("Cycle address", expectedAddress, actualAddress);
|
||||
_ = this.Check("Cycle address", expectedAddress, actualAddress);
|
||||
|
||||
var expectedValue = expectedCycle.Value;
|
||||
var actualValue = actualCycle.Value;
|
||||
_ = Check("Cycle value", expectedValue, actualValue);
|
||||
_ = this.Check("Cycle value", expectedValue, actualValue);
|
||||
|
||||
var expectedAction = expectedCycle.Type;
|
||||
var actualAction = actualCycle.Type;
|
||||
_ = Check("Cycle action", expectedAction, actualAction);
|
||||
_ = this.Check("Cycle action", expectedAction, actualAction);
|
||||
}
|
||||
|
||||
if (actualIDX < actualCycles.Count)
|
||||
{
|
||||
CycleCountMismatch = true;
|
||||
this.CycleCountMismatch = true;
|
||||
return false; // less expected cycles than actual
|
||||
}
|
||||
|
||||
if (Messages.Count > 0)
|
||||
if (this.Messages.Count > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var final = test.Final ?? throw new InvalidOperationException("Final state cannot be null");
|
||||
var pc_good = Check("PC", final.PC, cpu.PC.Word);
|
||||
var s_good = Check("S", final.S, cpu.S);
|
||||
var a_good = Check("A", final.A, cpu.A);
|
||||
var x_good = Check("X", final.X, cpu.X);
|
||||
var y_good = Check("Y", final.Y, cpu.Y);
|
||||
var p_good = Check("P", final.P, cpu.P);
|
||||
var pc_good = this.Check("PC", final.PC, cpu.PC.Word);
|
||||
var s_good = this.Check("S", final.S, cpu.S);
|
||||
var a_good = this.Check("A", final.A, cpu.A);
|
||||
var x_good = this.Check("X", final.X, cpu.X);
|
||||
var y_good = this.Check("Y", final.Y, cpu.Y);
|
||||
var p_good = this.Check("P", final.P, cpu.P);
|
||||
|
||||
if (!p_good)
|
||||
{
|
||||
Messages.Add($"Expected flags: {Disassembler.DumpFlags(final.P)}");
|
||||
Messages.Add($"Actual flags : {Disassembler.DumpFlags(cpu.P)}");
|
||||
this.Messages.Add($"Expected flags: {Disassembler.DumpFlags(final.P)}");
|
||||
this.Messages.Add($"Actual flags : {Disassembler.DumpFlags(cpu.P)}");
|
||||
}
|
||||
|
||||
if (final.RAM == null)
|
||||
@ -223,7 +224,7 @@
|
||||
var address = (ushort)entry[0];
|
||||
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)
|
||||
{
|
||||
ramProblem = true;
|
||||
@ -236,28 +237,28 @@
|
||||
&& !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()
|
||||
{
|
||||
Runner.ReadByte += Runner_ReadByte;
|
||||
Runner.WrittenByte += Runner_WrittenByte;
|
||||
this.Runner.ReadByte += this.Runner_ReadByte;
|
||||
this.Runner.WrittenByte += this.Runner_WrittenByte;
|
||||
}
|
||||
|
||||
private void InitialiseState(Test test)
|
||||
{
|
||||
var initial = test.Initial ?? throw new InvalidOperationException("Test cannot have an invalid initial state");
|
||||
InitialiseState(initial);
|
||||
this.InitialiseState(initial);
|
||||
}
|
||||
|
||||
private void InitialiseState(State state)
|
||||
{
|
||||
var cpu = Runner.CPU;
|
||||
var ram = Runner.RAM;
|
||||
var cpu = this.Runner.CPU;
|
||||
var ram = this.Runner.RAM;
|
||||
|
||||
cpu.PC.Word = state.PC;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(cycles);
|
||||
foreach (var cycle in cycles)
|
||||
{
|
||||
DumpCycle(cycle);
|
||||
this.DumpCycle(cycle);
|
||||
}
|
||||
}
|
||||
|
||||
private void DumpCycles(string which, IEnumerable<Cycle>? events)
|
||||
{
|
||||
Messages.Add(which);
|
||||
DumpCycles(events);
|
||||
this.Messages.Add(which);
|
||||
this.DumpCycles(events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace M6502.HarteTest
|
||||
{
|
||||
public sealed class Cycle
|
||||
internal sealed class Cycle
|
||||
{
|
||||
public ushort Address { get; set; }
|
||||
|
||||
@ -10,9 +10,9 @@
|
||||
|
||||
public Cycle(ushort address, byte value, string type)
|
||||
{
|
||||
Address = address;
|
||||
Value = value;
|
||||
Type = type;
|
||||
this.Address = address;
|
||||
this.Value = value;
|
||||
this.Type = type;
|
||||
}
|
||||
|
||||
public Cycle(List<object> input)
|
||||
@ -24,9 +24,9 @@
|
||||
throw new ArgumentOutOfRangeException(nameof(input), input, "Cycles can only have three elements");
|
||||
}
|
||||
|
||||
Address = AsElement(input[0]).GetUInt16();
|
||||
Value = AsElement(input[1]).GetByte();
|
||||
Type = AsElement(input[2]).GetString();
|
||||
this.Address = AsElement(input[0]).GetUInt16();
|
||||
this.Value = AsElement(input[1]).GetByte();
|
||||
this.Type = AsElement(input[2]).GetString();
|
||||
}
|
||||
|
||||
private static System.Text.Json.JsonElement AsElement(object part) => (System.Text.Json.JsonElement)part;
|
||||
|
@ -1,5 +1,6 @@
|
||||
namespace M6502.HarteTest
|
||||
{
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
@ -12,28 +13,28 @@
|
||||
};
|
||||
private bool _disposed;
|
||||
|
||||
public string Path { get; set; } = path;
|
||||
public string Path { get; } = path;
|
||||
|
||||
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)
|
||||
{
|
||||
if (!_disposed)
|
||||
if (!this._disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_stream.Dispose();
|
||||
this._stream.Dispose();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
this._disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
this.Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
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);
|
||||
if (fileInformation.Length > 0)
|
||||
|
@ -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\wdc65c02\v1";
|
||||
|
||||
await ProcessTestSuiteAsync(directory);
|
||||
await ProcessTestSuiteAsync(directory).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task ProcessTestSuiteAsync(string directory)
|
||||
@ -33,7 +33,7 @@ namespace M6502.HarteTest
|
||||
Console.WriteLine($"Processing: {Path.GetFileName(opcode.Path)}");
|
||||
|
||||
List<string?> testNames = [];
|
||||
var tests = opcode.TestsAsync ?? throw new InvalidOperationException("No tests are available");
|
||||
var tests = opcode.TestsAsync;
|
||||
await foreach (var test in tests)
|
||||
{
|
||||
if (test == null)
|
||||
@ -55,7 +55,7 @@ namespace M6502.HarteTest
|
||||
// Let's see if we had any successes!
|
||||
if (testNames.Count > 0)
|
||||
{
|
||||
Console.WriteLine("**** The follow test variations succeeeded");
|
||||
Console.WriteLine("**** The follow test variations succeeded");
|
||||
foreach (var testName in testNames)
|
||||
{
|
||||
Console.WriteLine($"****** {testName}");
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace M6502.HarteTest
|
||||
{
|
||||
public sealed class State
|
||||
internal sealed class State
|
||||
{
|
||||
public ushort PC { get; set; }
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace M6502.HarteTest
|
||||
{
|
||||
public sealed class Test
|
||||
internal sealed class Test
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
|
||||
@ -12,12 +12,12 @@
|
||||
|
||||
public IEnumerable<Cycle> AvailableCycles()
|
||||
{
|
||||
if (Cycles == null)
|
||||
if (this.Cycles == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cycles have not been initialised");
|
||||
}
|
||||
|
||||
foreach (var cycle in Cycles)
|
||||
foreach (var cycle in this.Cycles)
|
||||
{
|
||||
yield return new Cycle(cycle);
|
||||
}
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
public TestRunner()
|
||||
{
|
||||
CPU = new(this);
|
||||
_mapping = new(RAM, 0x0000, (ushort)Mask.Sixteen, AccessLevel.ReadWrite);
|
||||
this.CPU = new(this);
|
||||
this._mapping = new(this.RAM, 0x0000, (ushort)Mask.Sixteen, AccessLevel.ReadWrite);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
@ -23,21 +23,21 @@
|
||||
|
||||
public override void LowerPOWER()
|
||||
{
|
||||
CPU.LowerPOWER();
|
||||
this.CPU.LowerPOWER();
|
||||
base.LowerPOWER();
|
||||
}
|
||||
|
||||
public override MemoryMapping Mapping(ushort _) => _mapping;
|
||||
public override MemoryMapping Mapping(ushort _) => this._mapping;
|
||||
|
||||
public override void RaisePOWER()
|
||||
{
|
||||
base.RaisePOWER();
|
||||
CPU.RaisePOWER();
|
||||
CPU.RaiseRESET();
|
||||
CPU.RaiseINT();
|
||||
CPU.RaiseNMI();
|
||||
CPU.RaiseSO();
|
||||
CPU.RaiseRDY();
|
||||
this.CPU.RaisePOWER();
|
||||
this.CPU.RaiseRESET();
|
||||
this.CPU.RaiseINT();
|
||||
this.CPU.RaiseNMI();
|
||||
this.CPU.RaiseSO();
|
||||
this.CPU.RaiseRDY();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
namespace M6502.Symbols
|
||||
{
|
||||
using M6502.Symbols;
|
||||
|
||||
// line id = 268, file = 1, line = 60, type = 2, count = 1, span = 286 + 195
|
||||
[Section("line", "Lines")]
|
||||
public sealed class Line(Parser container) : IdentifiableSection(container)
|
||||
|
@ -2,6 +2,7 @@
|
||||
{
|
||||
// mod id=0,name="sudoku.o",file=0
|
||||
[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)
|
||||
{
|
||||
[SectionReference("file")]
|
||||
|
@ -124,7 +124,7 @@
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
@ -352,7 +352,7 @@
|
||||
{
|
||||
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.Parse(BuildDictionary(parts));
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
public void Build(System.Type type)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(type);
|
||||
var sectionAttributes = type.GetCustomAttributes(typeof(SectionAttribute), true);
|
||||
Debug.Assert(sectionAttributes != null, "No section attributes available");
|
||||
Debug.Assert(sectionAttributes.Length == 1, "Must be a single section attribute available");
|
||||
@ -154,7 +155,8 @@
|
||||
if (attribute is SectionReferenceAttribute)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
public class Section
|
||||
{
|
||||
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 Dictionary<System.Type, ReflectedSectionProperties> SectionPropertiesCache = [];
|
||||
protected static readonly DateTime UnixEpoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
protected readonly Parser _container;
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
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(properties != null);
|
||||
return properties;
|
||||
@ -35,8 +35,8 @@
|
||||
{
|
||||
var type = this.GetType();
|
||||
var entry = new ReflectedSectionProperties();
|
||||
Debug.Assert(_sectionPropertiesCache != null);
|
||||
if (_sectionPropertiesCache.TryAdd(type, entry))
|
||||
Debug.Assert(SectionPropertiesCache != null);
|
||||
if (SectionPropertiesCache.TryAdd(type, entry))
|
||||
{
|
||||
entry.Build(type);
|
||||
}
|
||||
@ -44,8 +44,9 @@
|
||||
|
||||
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._container.SectionEntries.Add(this);
|
||||
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;
|
||||
|
||||
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 int ExtractInteger(string value) => ExtractNumericValue<int>(value);
|
||||
protected static long ExtractLong(string value) => ExtractNumericValue<long>(value);
|
||||
protected static DateTime ExtractDateTime(string value) => _unixEpoch.AddSeconds(ExtractHexLong(value));
|
||||
protected static string[] ExtractCompoundString(string value) => value.Split('+');
|
||||
protected static DateTime ExtractDateTime(string value) => UnixEpoch.AddSeconds(ExtractHexLong(value));
|
||||
|
||||
protected static string[] ExtractCompoundString(string? value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
return value.Split('+');
|
||||
}
|
||||
|
||||
protected static List<int> ExtractCompoundInteger(string value)
|
||||
{
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
namespace M6502.Test
|
||||
{
|
||||
using EightBit;
|
||||
using M6502;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using EightBit;
|
||||
using M6502;
|
||||
|
||||
internal class Board : Bus
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ namespace M6502.Test
|
||||
{
|
||||
public bool DebugMode { get; set; }
|
||||
|
||||
public bool Profile { get; set; }
|
||||
public bool Profile { get; set; };
|
||||
|
||||
// Sudoku
|
||||
public string Program { get; } = "sudoku.65b";
|
||||
|
340
M6502/MOS6502.cs
340
M6502/MOS6502.cs
@ -17,125 +17,125 @@ namespace M6502
|
||||
return true;
|
||||
}
|
||||
|
||||
var cycles = Cycles;
|
||||
switch (OpCode)
|
||||
var cycles = this.Cycles;
|
||||
switch (this.OpCode)
|
||||
{
|
||||
case 0x02: Jam(); break; // *JAM
|
||||
case 0x03: IndexedIndirectXRead(); SLO(); break; // *SLO (indexed indirect X)
|
||||
case 0x04: ZeroPageRead(); break; // *NOP (zero page)
|
||||
case 0x07: ZeroPageRead(); SLO(); break; // *SLO (zero page)
|
||||
case 0x0b: ImmediateRead(); ANC(); break; // *ANC (immediate)
|
||||
case 0x0c: AbsoluteRead(); break; // *NOP (absolute)
|
||||
case 0x0f: AbsoluteRead(); SLO(); break; // *SLO (absolute)
|
||||
case 0x02: this.Jam(); break; // *JAM
|
||||
case 0x03: this.IndexedIndirectXRead(); this.SLO(); break; // *SLO (indexed indirect X)
|
||||
case 0x04: this.ZeroPageRead(); break; // *NOP (zero page)
|
||||
case 0x07: this.ZeroPageRead(); this.SLO(); break; // *SLO (zero page)
|
||||
case 0x0b: this.ImmediateRead(); this.ANC(); break; // *ANC (immediate)
|
||||
case 0x0c: this.AbsoluteRead(); break; // *NOP (absolute)
|
||||
case 0x0f: this.AbsoluteRead(); this.SLO(); break; // *SLO (absolute)
|
||||
|
||||
case 0x12: Jam(); break; // *JAM
|
||||
case 0x13: IndirectIndexedYAddress(); FixupRead(); SLO(); break; // *SLO (indirect indexed Y)
|
||||
case 0x14: ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0x17: ZeroPageXRead(); SLO(); break; // *SLO (zero page, X)
|
||||
case 0x1a: SwallowRead(); break; // *NOP (implied)
|
||||
case 0x1b: AbsoluteYAddress(); FixupRead(); SLO(); break; // *SLO (absolute, Y)
|
||||
case 0x1c: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0x1f: AbsoluteXAddress(); FixupRead(); SLO(); break; // *SLO (absolute, X)
|
||||
case 0x12: this.Jam(); break; // *JAM
|
||||
case 0x13: this.IndirectIndexedYAddress(); this.FixupRead(); this.SLO(); break; // *SLO (indirect indexed Y)
|
||||
case 0x14: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0x17: this.ZeroPageXRead(); this.SLO(); break; // *SLO (zero page, X)
|
||||
case 0x1a: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0x1b: this.AbsoluteYAddress(); this.FixupRead(); this.SLO(); break; // *SLO (absolute, Y)
|
||||
case 0x1c: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0x1f: this.AbsoluteXAddress(); this.FixupRead(); this.SLO(); break; // *SLO (absolute, X)
|
||||
|
||||
case 0x22: Jam(); break; // *JAM
|
||||
case 0x23: IndexedIndirectXRead(); RLA(); ; break; // *RLA (indexed indirect X)
|
||||
case 0x27: ZeroPageRead(); RLA(); ; break; // *RLA (zero page)
|
||||
case 0x2b: ImmediateRead(); ANC(); break; // *ANC (immediate)
|
||||
case 0x2f: AbsoluteRead(); RLA(); break; // *RLA (absolute)
|
||||
case 0x22: this.Jam(); break; // *JAM
|
||||
case 0x23: this.IndexedIndirectXRead(); this.RLA(); ; break; // *RLA (indexed indirect X)
|
||||
case 0x27: this.ZeroPageRead(); this.RLA(); ; break; // *RLA (zero page)
|
||||
case 0x2b: this.ImmediateRead(); this.ANC(); break; // *ANC (immediate)
|
||||
case 0x2f: this.AbsoluteRead(); this.RLA(); break; // *RLA (absolute)
|
||||
|
||||
case 0x32: Jam(); break; // *JAM
|
||||
case 0x33: IndirectIndexedYAddress(); FixupRead(); RLA(); break; // *RLA (indirect indexed Y)
|
||||
case 0x34: ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0x37: ZeroPageXRead(); RLA(); ; break; // *RLA (zero page, X)
|
||||
case 0x3a: SwallowRead(); break; // *NOP (implied)
|
||||
case 0x3b: AbsoluteYAddress(); FixupRead(); RLA(); break; // *RLA (absolute, Y)
|
||||
case 0x3c: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0x3f: AbsoluteXAddress(); FixupRead(); RLA(); break; // *RLA (absolute, X)
|
||||
case 0x32: this.Jam(); break; // *JAM
|
||||
case 0x33: this.IndirectIndexedYAddress(); this.FixupRead(); this.RLA(); break; // *RLA (indirect indexed Y)
|
||||
case 0x34: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0x37: this.ZeroPageXRead(); this.RLA(); ; break; // *RLA (zero page, X)
|
||||
case 0x3a: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0x3b: this.AbsoluteYAddress(); this.FixupRead(); this.RLA(); break; // *RLA (absolute, Y)
|
||||
case 0x3c: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0x3f: this.AbsoluteXAddress(); this.FixupRead(); this.RLA(); break; // *RLA (absolute, X)
|
||||
|
||||
case 0x42: Jam(); break; // *JAM
|
||||
case 0x43: IndexedIndirectXRead(); SRE(); break; // *SRE (indexed indirect X)
|
||||
case 0x47: ZeroPageRead(); SRE(); break; // *SRE (zero page)
|
||||
case 0x4b: ImmediateRead(); ASR(); break; // *ASR (immediate)
|
||||
case 0x4f: AbsoluteRead(); SRE(); break; // *SRE (absolute)
|
||||
case 0x42: this.Jam(); break; // *JAM
|
||||
case 0x43: this.IndexedIndirectXRead(); this.SRE(); break; // *SRE (indexed indirect X)
|
||||
case 0x47: this.ZeroPageRead(); this.SRE(); break; // *SRE (zero page)
|
||||
case 0x4b: this.ImmediateRead(); this.ASR(); break; // *ASR (immediate)
|
||||
case 0x4f: this.AbsoluteRead(); this.SRE(); break; // *SRE (absolute)
|
||||
|
||||
case 0x52: Jam(); break; // *JAM
|
||||
case 0x53: IndirectIndexedYAddress(); FixupRead(); SRE(); break; // *SRE (indirect indexed Y)
|
||||
case 0x57: ZeroPageXRead(); SRE(); break; // *SRE (zero page, X)
|
||||
case 0x5a: SwallowRead(); break; // *NOP (implied)
|
||||
case 0x5b: AbsoluteYAddress(); FixupRead(); SRE(); break; // *SRE (absolute, Y)
|
||||
case 0x5c: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0x5f: AbsoluteXAddress(); FixupRead(); SRE(); break; // *SRE (absolute, X)
|
||||
case 0x52: this.Jam(); break; // *JAM
|
||||
case 0x53: this.IndirectIndexedYAddress(); this.FixupRead(); this.SRE(); break; // *SRE (indirect indexed Y)
|
||||
case 0x57: this.ZeroPageXRead(); this.SRE(); break; // *SRE (zero page, X)
|
||||
case 0x5a: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0x5b: this.AbsoluteYAddress(); this.FixupRead(); this.SRE(); break; // *SRE (absolute, Y)
|
||||
case 0x5c: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0x5f: this.AbsoluteXAddress(); this.FixupRead(); this.SRE(); break; // *SRE (absolute, X)
|
||||
|
||||
case 0x62: Jam(); break; // *JAM
|
||||
case 0x63: IndexedIndirectXRead(); RRA(); break; // *RRA (indexed indirect X)
|
||||
case 0x64: ZeroPageRead(); break; // *NOP (zero page)
|
||||
case 0x67: ZeroPageRead(); RRA(); break; // *RRA (zero page)
|
||||
case 0x6b: ImmediateRead(); ARR(); break; // *ARR (immediate)
|
||||
case 0x6f: AbsoluteRead(); RRA(); break; // *RRA (absolute)
|
||||
case 0x62: this.Jam(); break; // *JAM
|
||||
case 0x63: this.IndexedIndirectXRead(); this.RRA(); break; // *RRA (indexed indirect X)
|
||||
case 0x64: this.ZeroPageRead(); break; // *NOP (zero page)
|
||||
case 0x67: this.ZeroPageRead(); this.RRA(); break; // *RRA (zero page)
|
||||
case 0x6b: this.ImmediateRead(); this.ARR(); break; // *ARR (immediate)
|
||||
case 0x6f: this.AbsoluteRead(); this.RRA(); break; // *RRA (absolute)
|
||||
|
||||
case 0x72: Jam(); break; // *JAM
|
||||
case 0x73: IndirectIndexedYAddress(); FixupRead(); RRA(); break; // *RRA (indirect indexed Y)
|
||||
case 0x74: ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0x77: ZeroPageXRead(); RRA(); break; // *RRA (zero page, X)
|
||||
case 0x7a: SwallowRead(); break; // *NOP (implied)
|
||||
case 0x7b: AbsoluteYAddress(); FixupRead(); RRA(); break; // *RRA (absolute, Y)
|
||||
case 0x7c: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0x7f: AbsoluteXAddress(); FixupRead(); RRA(); break; // *RRA (absolute, X)
|
||||
case 0x72: this.Jam(); break; // *JAM
|
||||
case 0x73: this.IndirectIndexedYAddress(); this.FixupRead(); this.RRA(); break; // *RRA (indirect indexed Y)
|
||||
case 0x74: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0x77: this.ZeroPageXRead(); this.RRA(); break; // *RRA (zero page, X)
|
||||
case 0x7a: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0x7b: this.AbsoluteYAddress(); this.FixupRead(); this.RRA(); break; // *RRA (absolute, Y)
|
||||
case 0x7c: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0x7f: this.AbsoluteXAddress(); this.FixupRead(); this.RRA(); break; // *RRA (absolute, X)
|
||||
|
||||
case 0x80: ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0x83: IndexedIndirectXAddress(); MemoryWrite((byte)(A & X)); break; // *SAX (indexed indirect X)
|
||||
case 0x87: ZeroPageAddress(); MemoryWrite((byte)(A & X)); break; // *SAX (zero page)
|
||||
case 0x89: ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0x8b: ImmediateRead(); ANE(); break; // *ANE (immediate)
|
||||
case 0x8f: AbsoluteAddress(); MemoryWrite((byte)(A & X)); break; // *SAX (absolute)
|
||||
case 0x80: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0x83: this.IndexedIndirectXAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (indexed indirect X)
|
||||
case 0x87: this.ZeroPageAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (zero page)
|
||||
case 0x89: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0x8b: this.ImmediateRead(); this.ANE(); break; // *ANE (immediate)
|
||||
case 0x8f: this.AbsoluteAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (absolute)
|
||||
|
||||
case 0x92: Jam(); break; // *JAM
|
||||
case 0x93: IndirectIndexedYAddress(); Fixup(); SHA(); break; // *SHA (indirect indexed, Y)
|
||||
case 0x97: ZeroPageYAddress(); MemoryWrite((byte)(A & X)); break; // *SAX (zero page, Y)
|
||||
case 0x9b: AbsoluteYAddress(); Fixup(); TAS(); break; // *TAS (absolute, Y)
|
||||
case 0x9c: AbsoluteXAddress(); Fixup(); SYA(); break; // *SYA (absolute, X)
|
||||
case 0x9e: AbsoluteYAddress(); Fixup(); SXA(); break; // *SXA (absolute, Y)
|
||||
case 0x9f: AbsoluteYAddress(); Fixup(); SHA(); break; // *SHA (absolute, Y)
|
||||
case 0x92: this.Jam(); break; // *JAM
|
||||
case 0x93: this.IndirectIndexedYAddress(); this.Fixup(); this.SHA(); break; // *SHA (indirect indexed, Y)
|
||||
case 0x97: this.ZeroPageYAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (zero page, Y)
|
||||
case 0x9b: this.AbsoluteYAddress(); this.Fixup(); this.TAS(); break; // *TAS (absolute, Y)
|
||||
case 0x9c: this.AbsoluteXAddress(); this.Fixup(); this.SYA(); break; // *SYA (absolute, X)
|
||||
case 0x9e: this.AbsoluteYAddress(); this.Fixup(); this.SXA(); break; // *SXA (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 0xa7: ZeroPageRead(); A = X = Through(); break; // *LAX (zero page)
|
||||
case 0xab: ImmediateRead(); ATX(); break; // *ATX (immediate)
|
||||
case 0xaf: AbsoluteRead(); A = X = Through(); break; // *LAX (absolute)
|
||||
case 0xa3: this.IndexedIndirectXRead(); this.A = this.X = this.Through(); break; // *LAX (indexed indirect X)
|
||||
case 0xa7: this.ZeroPageRead(); this.A = this.X = this.Through(); break; // *LAX (zero page)
|
||||
case 0xab: this.ImmediateRead(); this.ATX(); break; // *ATX (immediate)
|
||||
case 0xaf: this.AbsoluteRead(); this.A = this.X = this.Through(); break; // *LAX (absolute)
|
||||
|
||||
case 0xb2: Jam(); break; // *JAM
|
||||
case 0xb3: IndirectIndexedYRead(); A = X = Through(); break; // *LAX (indirect indexed Y)
|
||||
case 0xb7: ZeroPageYRead(); A = X = Through(); break; // *LAX (zero page, Y)
|
||||
case 0xbb: AbsoluteYAddress(); MaybeFixup(); LAS(); break; // *LAS (absolute, Y)
|
||||
case 0xbf: AbsoluteYRead(); A = X = Through(); break; // *LAX (absolute, Y)
|
||||
case 0xb2: this.Jam(); break; // *JAM
|
||||
case 0xb3: this.IndirectIndexedYRead(); this.A = this.X = this.Through(); break; // *LAX (indirect indexed Y)
|
||||
case 0xb7: this.ZeroPageYRead(); this.A = this.X = this.Through(); break; // *LAX (zero page, Y)
|
||||
case 0xbb: this.AbsoluteYAddress(); this.MaybeFixup(); this.LAS(); break; // *LAS (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 0xc7: ZeroPageRead(); DCP(); break; // *DCP (zero page)
|
||||
case 0xcb: ImmediateRead(); AXS(); break; // *AXS (immediate)
|
||||
case 0xcf: AbsoluteRead(); DCP(); break; // *DCP (absolute)
|
||||
case 0xc3: this.IndexedIndirectXRead(); this.DCP(); break; // *DCP (indexed indirect X)
|
||||
case 0xc7: this.ZeroPageRead(); this.DCP(); break; // *DCP (zero page)
|
||||
case 0xcb: this.ImmediateRead(); this.AXS(); break; // *AXS (immediate)
|
||||
case 0xcf: this.AbsoluteRead(); this.DCP(); break; // *DCP (absolute)
|
||||
|
||||
case 0xd2: Jam(); break; // *JAM
|
||||
case 0xd3: IndirectIndexedYAddress(); FixupRead(); DCP(); break; // *DCP (indirect indexed Y)
|
||||
case 0xd7: ZeroPageXRead(); DCP(); break; // *DCP (zero page, X)
|
||||
case 0xda: SwallowRead(); break; // *NOP (implied)
|
||||
case 0xdb: AbsoluteYAddress(); FixupRead(); DCP(); break; // *DCP (absolute, Y)
|
||||
case 0xdc: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0xdf: AbsoluteXAddress(); FixupRead(); DCP(); break; // *DCP (absolute, X)
|
||||
case 0xd2: this.Jam(); break; // *JAM
|
||||
case 0xd3: this.IndirectIndexedYAddress(); this.FixupRead(); this.DCP(); break; // *DCP (indirect indexed Y)
|
||||
case 0xd7: this.ZeroPageXRead(); this.DCP(); break; // *DCP (zero page, X)
|
||||
case 0xda: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0xdb: this.AbsoluteYAddress(); this.FixupRead(); this.DCP(); break; // *DCP (absolute, Y)
|
||||
case 0xdc: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0xdf: this.AbsoluteXAddress(); this.FixupRead(); this.DCP(); break; // *DCP (absolute, X)
|
||||
|
||||
case 0xe3: IndexedIndirectXRead(); ISB(); break; // *ISB (indexed indirect X)
|
||||
case 0xe7: ZeroPageRead(); ISB(); break; // *ISB (zero page)
|
||||
case 0xeb: ImmediateRead(); SBC(); break; // *SBC (immediate)
|
||||
case 0xef: AbsoluteRead(); ISB(); break; // *ISB (absolute)
|
||||
case 0xe3: this.IndexedIndirectXRead(); this.ISB(); break; // *ISB (indexed indirect X)
|
||||
case 0xe7: this.ZeroPageRead(); this.ISB(); break; // *ISB (zero page)
|
||||
case 0xeb: this.ImmediateRead(); this.SBC(); break; // *SBC (immediate)
|
||||
case 0xef: this.AbsoluteRead(); this.ISB(); break; // *ISB (absolute)
|
||||
|
||||
case 0xf2: Jam(); break; // *JAM
|
||||
case 0xf3: IndirectIndexedYAddress(); FixupRead(); ISB(); break; // *ISB (indirect indexed Y)
|
||||
case 0xf7: ZeroPageXRead(); ISB(); break; // *ISB (zero page, X)
|
||||
case 0xfa: SwallowRead(); break; // *NOP (implied)
|
||||
case 0xfb: AbsoluteYAddress(); FixupRead(); ISB(); break; // *ISB (absolute, Y)
|
||||
case 0xfc: AbsoluteXAddress(); MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0xff: AbsoluteXAddress(); FixupRead(); ISB(); break; // *ISB (absolute, X)
|
||||
case 0xf2: this.Jam(); break; // *JAM
|
||||
case 0xf3: this.IndirectIndexedYAddress(); this.FixupRead(); this.ISB(); break; // *ISB (indirect indexed Y)
|
||||
case 0xf7: this.ZeroPageXRead(); this.ISB(); break; // *ISB (zero page, X)
|
||||
case 0xfa: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0xfb: this.AbsoluteYAddress(); this.FixupRead(); this.ISB(); break; // *ISB (absolute, Y)
|
||||
case 0xfc: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0xff: this.AbsoluteXAddress(); this.FixupRead(); this.ISB(); break; // *ISB (absolute, X)
|
||||
}
|
||||
|
||||
return cycles != Cycles;
|
||||
return cycles != this.Cycles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -145,8 +145,8 @@ namespace M6502
|
||||
protected override void ModifyWrite(byte data)
|
||||
{
|
||||
// The read will have already taken place...
|
||||
MemoryWrite(); // Modify cycle
|
||||
MemoryWrite(data); // Write cycle
|
||||
this.MemoryWrite(); // Modify cycle
|
||||
this.MemoryWrite(data); // Write cycle
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -155,22 +155,22 @@ namespace M6502
|
||||
|
||||
protected override void IndirectAddress()
|
||||
{
|
||||
AbsoluteAddress();
|
||||
GetAddressPaged();
|
||||
this.AbsoluteAddress();
|
||||
this.GetAddressPaged();
|
||||
}
|
||||
|
||||
#region Address page fixup
|
||||
|
||||
protected override void Fixup()
|
||||
{
|
||||
MemoryRead();
|
||||
Bus.Address.High = FixedPage;
|
||||
this.MemoryRead();
|
||||
this.Bus.Address.High = this.FixedPage;
|
||||
}
|
||||
|
||||
protected override void FixupBranch(sbyte relative)
|
||||
{
|
||||
NoteFixedAddress(PC.Word + relative);
|
||||
MaybeFixup();
|
||||
this.NoteFixedAddress(this.PC.Word + relative);
|
||||
this.MaybeFixup();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -185,11 +185,11 @@ namespace M6502
|
||||
|
||||
private void ARR()
|
||||
{
|
||||
var value = Bus.Data;
|
||||
if (DecimalMasked != 0)
|
||||
ARR_d(value);
|
||||
var value = this.Bus.Data;
|
||||
if (this.DecimalMasked != 0)
|
||||
this.ARR_d(value);
|
||||
else
|
||||
ARR_b(value);
|
||||
this.ARR_b(value);
|
||||
}
|
||||
|
||||
private void ARR_d(byte value)
|
||||
@ -197,26 +197,26 @@ namespace M6502
|
||||
// With thanks to https://github.com/TomHarte/CLK
|
||||
// What a very strange instruction ARR is...
|
||||
|
||||
A &= value;
|
||||
var unshiftedA = A;
|
||||
A = Through(A >> 1 | Carry << 7);
|
||||
SetFlag(StatusBits.VF, OverflowTest((byte)(A ^ A << 1)));
|
||||
this.A &= value;
|
||||
var unshiftedA = this.A;
|
||||
this.A = this.Through(this.A >> 1 | this.Carry << 7);
|
||||
this.SetFlag(StatusBits.VF, OverflowTest((byte)(this.A ^ this.A << 1)));
|
||||
|
||||
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)
|
||||
A += 0x60;
|
||||
if (this.Carry != 0)
|
||||
this.A += 0x60;
|
||||
}
|
||||
|
||||
private void ARR_b(byte value)
|
||||
{
|
||||
A &= value;
|
||||
A = Through(A >> 1 | Carry << 7);
|
||||
SetFlag(StatusBits.CF, OverflowTest(A));
|
||||
SetFlag(StatusBits.VF, OverflowTest((byte)(A ^ A << 1)));
|
||||
this.A &= value;
|
||||
this.A = this.Through(this.A >> 1 | this.Carry << 7);
|
||||
this.SetFlag(StatusBits.CF, OverflowTest(this.A));
|
||||
this.SetFlag(StatusBits.VF, OverflowTest((byte)(this.A ^ this.A << 1)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -236,108 +236,108 @@ namespace M6502
|
||||
//this.MemoryWrite(updated);
|
||||
|
||||
byte updated;
|
||||
if (Fixed)
|
||||
if (this.Fixed)
|
||||
{
|
||||
updated = (byte)(data & FixedPage);
|
||||
Bus.Address.High = updated;
|
||||
updated = (byte)(data & this.FixedPage);
|
||||
this.Bus.Address.High = updated;
|
||||
}
|
||||
else
|
||||
{
|
||||
updated = (byte)(data & UnfixedPage);
|
||||
Bus.Address.High = updated;
|
||||
updated = (byte)(data & this.UnfixedPage);
|
||||
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
|
||||
|
||||
private void ANC()
|
||||
{
|
||||
AndR();
|
||||
SetFlag(StatusBits.CF, NegativeTest(A));
|
||||
this.AndR();
|
||||
this.SetFlag(StatusBits.CF, NegativeTest(this.A));
|
||||
}
|
||||
|
||||
private void AXS()
|
||||
{
|
||||
X = Through(BinarySUB((byte)(A & X)));
|
||||
ResetFlag(StatusBits.CF, Intermediate.High);
|
||||
this.X = this.Through(this.BinarySUB((byte)(this.A & this.X)));
|
||||
this.ResetFlag(StatusBits.CF, this.Intermediate.High);
|
||||
}
|
||||
|
||||
private void Jam()
|
||||
{
|
||||
Bus.Address.Assign(PC);
|
||||
MemoryRead();
|
||||
MemoryRead(0xff, 0xff);
|
||||
Bus.Address.Low = 0xfe;
|
||||
MemoryRead();
|
||||
MemoryRead();
|
||||
Bus.Address.Low = 0xff;
|
||||
MemoryRead();
|
||||
MemoryRead();
|
||||
MemoryRead();
|
||||
MemoryRead();
|
||||
MemoryRead();
|
||||
MemoryRead();
|
||||
this.Bus.Address.Assign(this.PC);
|
||||
this.MemoryRead();
|
||||
this.MemoryRead(0xff, 0xff);
|
||||
this.Bus.Address.Low = 0xfe;
|
||||
this.MemoryRead();
|
||||
this.MemoryRead();
|
||||
this.Bus.Address.Low = 0xff;
|
||||
this.MemoryRead();
|
||||
this.MemoryRead();
|
||||
this.MemoryRead();
|
||||
this.MemoryRead();
|
||||
this.MemoryRead();
|
||||
this.MemoryRead();
|
||||
}
|
||||
|
||||
private void TAS()
|
||||
{
|
||||
S = (byte)(A & X);
|
||||
SHA();
|
||||
this.S = (byte)(this.A & this.X);
|
||||
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()
|
||||
{
|
||||
AndR();
|
||||
A = LSR(A);
|
||||
this.AndR();
|
||||
this.A = this.LSR(this.A);
|
||||
}
|
||||
|
||||
private void ISB()
|
||||
{
|
||||
ModifyWrite(INC());
|
||||
SBC();
|
||||
this.ModifyWrite(this.INC());
|
||||
this.SBC();
|
||||
}
|
||||
|
||||
private void RLA()
|
||||
{
|
||||
ModifyWrite(ROL());
|
||||
AndR();
|
||||
this.ModifyWrite(this.ROL());
|
||||
this.AndR();
|
||||
}
|
||||
|
||||
private void RRA()
|
||||
{
|
||||
ModifyWrite(ROR());
|
||||
ADC();
|
||||
this.ModifyWrite(this.ROR());
|
||||
this.ADC();
|
||||
}
|
||||
|
||||
private void SLO()
|
||||
{
|
||||
ModifyWrite(ASL());
|
||||
OrR();
|
||||
this.ModifyWrite(this.ASL());
|
||||
this.OrR();
|
||||
}
|
||||
|
||||
private void SRE()
|
||||
{
|
||||
ModifyWrite(LSR());
|
||||
EorR();
|
||||
this.ModifyWrite(this.LSR());
|
||||
this.EorR();
|
||||
}
|
||||
|
||||
private void DCP()
|
||||
{
|
||||
ModifyWrite(DEC());
|
||||
CMP(A);
|
||||
this.ModifyWrite(this.DEC());
|
||||
this.CMP(this.A);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -31,8 +31,8 @@
|
||||
|
||||
if (activate)
|
||||
{
|
||||
this.processor.RaisingSYNC += Processor_RaisingSYNC;
|
||||
this.processor.ExecutedInstruction += Processor_ExecutedInstruction;
|
||||
this.processor.RaisingSYNC += this.Processor_RaisingSYNC;
|
||||
this.processor.ExecutedInstruction += this.Processor_ExecutedInstruction;
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,147 +62,147 @@
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(totalCyclesValid);
|
||||
return totalCycles;
|
||||
Debug.Assert(this.totalCyclesValid);
|
||||
return this.totalCycles;
|
||||
}
|
||||
private set
|
||||
{
|
||||
Debug.Assert(!totalCyclesValid);
|
||||
totalCycles = value;
|
||||
totalCyclesValid = true;
|
||||
Debug.Assert(!this.totalCyclesValid);
|
||||
this.totalCycles = value;
|
||||
this.totalCyclesValid = true;
|
||||
}
|
||||
}
|
||||
public void Generate()
|
||||
{
|
||||
OnStartingOutput();
|
||||
this.OnStartingOutput();
|
||||
try
|
||||
{
|
||||
EmitProfileInformation();
|
||||
this.EmitProfileInformation();
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnFinishedOutput();
|
||||
this.OnFinishedOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitProfileInformation()
|
||||
{
|
||||
TotalCycles = instructionCycles.Sum();
|
||||
this.TotalCycles = this.instructionCycles.Sum();
|
||||
|
||||
EmitProfileLineInformation();
|
||||
EmitProfileScopeInformation();
|
||||
EmitProfileInstructionInformation();
|
||||
this.EmitProfileLineInformation();
|
||||
this.EmitProfileScopeInformation();
|
||||
this.EmitProfileInstructionInformation();
|
||||
}
|
||||
|
||||
private void EmitProfileScopeInformation()
|
||||
{
|
||||
OnStartingScopeOutput();
|
||||
this.OnStartingScopeOutput();
|
||||
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);
|
||||
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);
|
||||
OnEmitScope(id, cycles, count);
|
||||
this.OnEmitScope(id, cycles, count);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnFinishedScopeOutput();
|
||||
this.OnFinishedScopeOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitProfileLineInformation()
|
||||
{
|
||||
OnStartingLineOutput();
|
||||
this.OnStartingLineOutput();
|
||||
try
|
||||
{
|
||||
// For each memory address
|
||||
for (var i = 0; i < 0x10000; ++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)
|
||||
{
|
||||
// Dump a profile/disassembly line
|
||||
var source = disassembler.Disassemble(address);
|
||||
var source = this.disassembler.Disassemble(address);
|
||||
Debug.Assert(cycleDistributions != null);
|
||||
OnEmitLine(address, source, cycles, count, cycleDistributions);
|
||||
this.OnEmitLine(address, source, cycles, count, cycleDistributions);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnFinishedLineOutput();
|
||||
this.OnFinishedLineOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitProfileInstructionInformation()
|
||||
{
|
||||
OnStartingInstructionOutput();
|
||||
this.OnStartingInstructionOutput();
|
||||
try
|
||||
{
|
||||
// For each instruction
|
||||
for (var i = 0; i < 0x100; ++i)
|
||||
{
|
||||
// If there are any cycles associated
|
||||
var cycles = instructionCycles[i];
|
||||
var cycles = this.instructionCycles[i];
|
||||
if (cycles > 0)
|
||||
{
|
||||
var count = instructionCounts[i];
|
||||
var count = this.instructionCounts[i];
|
||||
Debug.Assert(count > 0);
|
||||
var instruction = (byte)i;
|
||||
|
||||
// Emit an instruction event
|
||||
OnEmitInstruction(instruction, cycles, count);
|
||||
this.OnEmitInstruction(instruction, cycles, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnFinishedInstructionOutput();
|
||||
this.OnFinishedInstructionOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private void Processor_RaisingSYNC(object? sender, EventArgs e)
|
||||
{
|
||||
executingAddress = processor.Bus.Address.Word;
|
||||
++instructionCounts[executingInstruction = processor.Bus.Data];
|
||||
this.executingAddress = this.processor.Bus.Address.Word;
|
||||
++this.instructionCounts[this.executingInstruction = this.processor.Bus.Data];
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
addressCycleDistributions[executingAddress] = addressDistribution = [];
|
||||
this.addressCycleDistributions[this.executingAddress] = addressDistribution = [];
|
||||
}
|
||||
_ = addressDistribution.TryGetValue(cycles, out var 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)
|
||||
{
|
||||
var id = scope.ID;
|
||||
// Current will be initialised to zero, if absent
|
||||
_ = scopeCycles.TryGetValue(id, out var current);
|
||||
scopeCycles[id] = current + cycles;
|
||||
_ = this.scopeCycles.TryGetValue(id, out var current);
|
||||
this.scopeCycles[id] = current + cycles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
cycleCount = -1;
|
||||
|
@ -13,22 +13,22 @@ namespace M6502
|
||||
|
||||
private bool Stopped
|
||||
{
|
||||
get => _stopped; set => _stopped = value;
|
||||
get => this._stopped; set => this._stopped = value;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
protected override void Interrupt(byte vector, InterruptSource source, InterruptType 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
|
||||
@ -42,130 +42,130 @@ namespace M6502
|
||||
return true;
|
||||
}
|
||||
|
||||
var cycles = Cycles;
|
||||
switch (OpCode)
|
||||
var cycles = this.Cycles;
|
||||
switch (this.OpCode)
|
||||
{
|
||||
case 0x02: SwallowFetch(); break; // NOP
|
||||
case 0x02: this.SwallowFetch(); break; // NOP
|
||||
case 0x03: break; // null
|
||||
case 0x04: ZeroPageRead(); TSB(); break; // TSB zp
|
||||
case 0x07: ZeroPageRead(); RMB(Bit(0)); break; // RMB0 zp
|
||||
case 0x04: this.ZeroPageRead(); this.TSB(); break; // TSB zp
|
||||
case 0x07: this.ZeroPageRead(); this.RMB(Bit(0)); break; // RMB0 zp
|
||||
case 0x0b: break; // null
|
||||
case 0x0c: AbsoluteRead(); TSB(); break; // TSB a
|
||||
case 0x0f: ZeroPageRead(); BBR(Bit(0)); break; // BBR0 r
|
||||
case 0x0c: this.AbsoluteRead(); this.TSB(); break; // TSB a
|
||||
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 0x14: ZeroPageRead(); TRB(); break; // TRB zp
|
||||
case 0x17: ZeroPageRead(); RMB(Bit(1)); break; // RMB1 zp
|
||||
case 0x1a: SwallowRead(); A = INC(A); break; // INC A
|
||||
case 0x14: this.ZeroPageRead(); this.TRB(); break; // TRB zp
|
||||
case 0x17: this.ZeroPageRead(); this.RMB(Bit(1)); break; // RMB1 zp
|
||||
case 0x1a: this.SwallowRead(); this.A = this.INC(this.A); break; // INC A
|
||||
case 0x1b: break; // null
|
||||
case 0x1c: AbsoluteRead(); TRB(); break; // TRB a
|
||||
case 0x1f: ZeroPageRead(); BBR(Bit(1)); break; // BBR1 r
|
||||
case 0x1c: this.AbsoluteRead(); this.TRB(); break; // TRB a
|
||||
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 0x27: ZeroPageRead(); RMB(Bit(2)); break; // RMB2 zp
|
||||
case 0x27: this.ZeroPageRead(); this.RMB(Bit(2)); break; // RMB2 zp
|
||||
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 0x34: break; // BIT zp,x
|
||||
case 0x37: ZeroPageRead(); RMB(Bit(3)); break; // RMB3 zp
|
||||
case 0x3a: SwallowRead(); A = DEC(A); break; // DEC A
|
||||
case 0x37: this.ZeroPageRead(); this.RMB(Bit(3)); break; // RMB3 zp
|
||||
case 0x3a: this.SwallowRead(); this.A = this.DEC(this.A); break; // DEC A
|
||||
case 0x3b: break; // null
|
||||
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 0x47: ZeroPageRead(); RMB(Bit(4)); break; // RMB4 zp
|
||||
case 0x47: this.ZeroPageRead(); this.RMB(Bit(4)); break; // RMB4 zp
|
||||
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 0x57: ZeroPageRead(); RMB(Bit(5)); break; // RMB5 zp
|
||||
case 0x5a: SwallowRead(); Push(Y); break; // PHY s
|
||||
case 0x57: this.ZeroPageRead(); this.RMB(Bit(5)); break; // RMB5 zp
|
||||
case 0x5a: this.SwallowRead(); this.Push(this.Y); break; // PHY s
|
||||
case 0x5b: 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 0x64: ZeroPageAddress(); MemoryWrite(0); break; // STZ zp
|
||||
case 0x67: ZeroPageRead(); RMB(Bit(6)); break; // RMB6 zp
|
||||
case 0x64: this.ZeroPageAddress(); this.MemoryWrite(0); break; // STZ zp
|
||||
case 0x67: this.ZeroPageRead(); this.RMB(Bit(6)); break; // RMB6 zp
|
||||
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 0x74: ZeroPageXAddress(); MemoryWrite(0); break; // STZ zp,x
|
||||
case 0x77: ZeroPageRead(); RMB(Bit(7)); break; // RMB7 zp
|
||||
case 0x7a: SwallowRead(); SwallowPop(); Y = Through(Pop()); break; // PLY s
|
||||
case 0x74: this.ZeroPageXAddress(); this.MemoryWrite(0); break; // STZ zp,x
|
||||
case 0x77: this.ZeroPageRead(); this.RMB(Bit(7)); break; // RMB7 zp
|
||||
case 0x7a: this.SwallowRead(); this.SwallowPop(); this.Y = this.Through(this.Pop()); break; // PLY s
|
||||
case 0x7b: break; // null
|
||||
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 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 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 0x97: ZeroPageRead(); SMB(Bit(1)); break; // SMB1 zp
|
||||
case 0x97: this.ZeroPageRead(); this.SMB(Bit(1)); break; // SMB1 zp
|
||||
case 0x9b: break; // null
|
||||
case 0x9c: AbsoluteAddress(); MemoryWrite(0); break; // STZ a
|
||||
case 0x9e: AbsoluteXAddress(); MemoryWrite(0); break; // STZ a,x
|
||||
case 0x9f: ZeroPageRead(); BBS(Bit(1)); break; // BBS1 r
|
||||
case 0x9c: this.AbsoluteAddress(); this.MemoryWrite(0); break; // STZ a
|
||||
case 0x9e: this.AbsoluteXAddress(); this.MemoryWrite(0); break; // STZ a,x
|
||||
case 0x9f: this.ZeroPageRead(); this.BBS(Bit(1)); break; // BBS1 r
|
||||
|
||||
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 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 0xb7: ZeroPageRead(); SMB(Bit(3)); break; // SMB3 zp
|
||||
case 0xb7: this.ZeroPageRead(); this.SMB(Bit(3)); break; // SMB3 zp
|
||||
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 0xc7: ZeroPageRead(); SMB(Bit(4)); break; // SMB4 zp
|
||||
case 0xcb: SwallowRead(); Waiting = true; break; // WAI i
|
||||
case 0xcf: ZeroPageRead(); BBS(Bit(4)); break; // BBS4 r
|
||||
case 0xc7: this.ZeroPageRead(); this.SMB(Bit(4)); break; // SMB4 zp
|
||||
case 0xcb: this.SwallowRead(); this.Waiting = true; break; // WAI i
|
||||
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 0xd7: ZeroPageRead(); SMB(Bit(5)); break; // SMB5 zp
|
||||
case 0xda: SwallowRead(); Push(X); break; // PHX s
|
||||
case 0xdb: SwallowRead(); Stopped = true; break; // STP i
|
||||
case 0xdc: SwallowRead(); break; // null
|
||||
case 0xdf: ZeroPageRead(); BBS(Bit(5)); break; // BBS5 r
|
||||
case 0xd7: this.ZeroPageRead(); this.SMB(Bit(5)); break; // SMB5 zp
|
||||
case 0xda: this.SwallowRead(); this.Push(this.X); break; // PHX s
|
||||
case 0xdb: this.SwallowRead(); this.Stopped = true; break; // STP i
|
||||
case 0xdc: this.SwallowRead(); break; // null
|
||||
case 0xdf: this.ZeroPageRead(); this.BBS(Bit(5)); break; // BBS5 r
|
||||
|
||||
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 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 0xf7: ZeroPageRead(); SMB(Bit(7)); break; // SMB7 zp
|
||||
case 0xfa: SwallowRead(); SwallowPop(); X = Through(Pop()); break; // PLX s
|
||||
case 0xf7: this.ZeroPageRead(); this.SMB(Bit(7)); break; // SMB7 zp
|
||||
case 0xfa: this.SwallowRead(); this.SwallowPop(); this.X = this.Through(this.Pop()); break; // PLX s
|
||||
case 0xfb: 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()
|
||||
{
|
||||
if (!Paused)
|
||||
if (!this.Paused)
|
||||
{
|
||||
base.PoweredStep();
|
||||
}
|
||||
@ -174,19 +174,19 @@ namespace M6502
|
||||
protected override void OnLoweredRESET()
|
||||
{
|
||||
base.OnLoweredRESET();
|
||||
Stopped = Waiting = false;
|
||||
this.Stopped = this.Waiting = false;
|
||||
}
|
||||
|
||||
protected override void OnLoweredINT()
|
||||
{
|
||||
base.OnLoweredINT();
|
||||
Waiting = false;
|
||||
this.Waiting = false;
|
||||
}
|
||||
|
||||
protected override void OnLoweredNMI()
|
||||
{
|
||||
base.OnLoweredNMI();
|
||||
Waiting = false;
|
||||
this.Waiting = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -196,8 +196,8 @@ namespace M6502
|
||||
protected override void ModifyWrite(byte data)
|
||||
{
|
||||
// The read will have already taken place...
|
||||
MemoryRead(); // Modify cycle (Change from MOS6502)
|
||||
MemoryWrite(data); // Write cycle
|
||||
this.MemoryRead(); // Modify cycle (Change from MOS6502)
|
||||
this.MemoryWrite(data); // Write cycle
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -210,22 +210,22 @@ namespace M6502
|
||||
|
||||
protected override byte FetchByte()
|
||||
{
|
||||
lastFetchAddress.Assign(PC);
|
||||
this.lastFetchAddress.Assign(this.PC);
|
||||
return base.FetchByte();
|
||||
}
|
||||
|
||||
protected override void Fixup()
|
||||
{
|
||||
var fixingLow = Bus.Address.Low;
|
||||
MemoryRead(lastFetchAddress);
|
||||
Bus.Address.Assign(fixingLow, FixedPage);
|
||||
var fixingLow = this.Bus.Address.Low;
|
||||
this.MemoryRead(this.lastFetchAddress);
|
||||
this.Bus.Address.Assign(fixingLow, this.FixedPage);
|
||||
}
|
||||
|
||||
protected override void FixupBranch(sbyte relative)
|
||||
{
|
||||
NoteFixedAddress(PC.Word + relative);
|
||||
lastFetchAddress.Assign(Bus.Address); // Effectively negate the use of "lastFetchAddress" for branch fixup usages
|
||||
MaybeFixup();
|
||||
this.NoteFixedAddress(this.PC.Word + relative);
|
||||
this.lastFetchAddress.Assign(this.Bus.Address); // Effectively negate the use of "lastFetchAddress" for branch fixup usages
|
||||
this.MaybeFixup();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -234,20 +234,20 @@ namespace M6502
|
||||
|
||||
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()
|
||||
{
|
||||
AbsoluteAddress();
|
||||
GetAddress();
|
||||
this.AbsoluteAddress();
|
||||
this.GetAddress();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -256,8 +256,8 @@ namespace M6502
|
||||
|
||||
private void ZeroPageIndirectRead()
|
||||
{
|
||||
ZeroPageIndirectAddress();
|
||||
MemoryRead();
|
||||
this.ZeroPageIndirectAddress();
|
||||
this.MemoryRead();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -266,40 +266,40 @@ namespace M6502
|
||||
|
||||
private void RMB(byte flag)
|
||||
{
|
||||
MemoryRead();
|
||||
Bus.Data &= (byte)~flag;
|
||||
MemoryWrite();
|
||||
this.MemoryRead();
|
||||
this.Bus.Data &= (byte)~flag;
|
||||
this.MemoryWrite();
|
||||
}
|
||||
|
||||
private void SMB(byte flag)
|
||||
{
|
||||
MemoryRead();
|
||||
Bus.Data |= flag;
|
||||
MemoryWrite();
|
||||
this.MemoryRead();
|
||||
this.Bus.Data |= flag;
|
||||
this.MemoryWrite();
|
||||
}
|
||||
|
||||
private void BBS(byte flag)
|
||||
{
|
||||
MemoryRead();
|
||||
Branch(Bus.Data & flag);
|
||||
this.MemoryRead();
|
||||
this.Branch(this.Bus.Data & flag);
|
||||
}
|
||||
|
||||
private void BBR(byte flag)
|
||||
{
|
||||
MemoryRead();
|
||||
BranchNot(Bus.Data & flag);
|
||||
this.MemoryRead();
|
||||
this.BranchNot(this.Bus.Data & flag);
|
||||
}
|
||||
|
||||
private void TSB()
|
||||
{
|
||||
AdjustZero((byte)(A & Bus.Data));
|
||||
ModifyWrite((byte)(A | Bus.Data));
|
||||
this.AdjustZero((byte)(this.A & this.Bus.Data));
|
||||
this.ModifyWrite((byte)(this.A | this.Bus.Data));
|
||||
}
|
||||
|
||||
private void TRB()
|
||||
{
|
||||
AdjustZero((byte)(A & Bus.Data));
|
||||
ModifyWrite((byte)(~A & Bus.Data));
|
||||
this.AdjustZero((byte)(this.A & this.Bus.Data));
|
||||
this.ModifyWrite((byte)(~this.A & this.Bus.Data));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user