AxibugEmuOnline/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs

2074 lines
62 KiB
C#
Raw Normal View History

2024-07-25 11:03:58 +08:00
#undef DPCM_SYNCCLOCK
using System;
namespace VirtualNes.Core
2024-07-23 18:31:59 +08:00
{
public class CPU
{
2024-07-25 18:34:52 +08:00
private static int nmicount;
2024-07-25 11:03:58 +08:00
// 6502 status flags
public const byte C_FLAG = 0x01; // 1: Carry
public const byte Z_FLAG = 0x02; // 1: Zero
public const byte I_FLAG = 0x04; // 1: Irq disabled
public const byte D_FLAG = 0x08; // 1: Decimal mode flag (NES unused)
public const byte B_FLAG = 0x10; // 1: Break
public const byte R_FLAG = 0x20; // 1: Reserved (Always 1)
public const byte V_FLAG = 0x40; // 1: Overflow
public const byte N_FLAG = 0x80; // 1: Negative
// Interrupt
public const byte NMI_FLAG = 0x01;
public const byte IRQ_FLAG = 0x02;
public const byte IRQ_FRAMEIRQ = 0x04;
public const byte IRQ_DPCM = 0x08;
public const byte IRQ_MAPPER = 0x10;
public const byte IRQ_MAPPER2 = 0x20;
public const byte IRQ_TRIGGER = 0x40; // one shot(媽IRQ())
public const byte IRQ_TRIGGER2 = 0x80; // one shot(媽IRQ_NotPending())
public static readonly byte IRQ_MASK = unchecked((byte)(~(NMI_FLAG | IRQ_FLAG)));
// Vector
public const ushort NMI_VECTOR = 0xFFFA;
public const ushort RES_VECTOR = 0xFFFC;
public const ushort IRQ_VECTOR = 0xFFFE;
private NES nes;
private bool m_bClockProcess;
private int TOTAL_cycles;
private int DMA_cycles;
private Mapper mapper;
private APU apu;
2024-07-31 17:40:32 +08:00
internal R6502 R = new R6502();
2024-07-25 11:03:58 +08:00
private byte[] ZN_Table = new byte[256];
2024-08-07 17:45:38 +08:00
private ArrayRef<byte> STACK;
2024-07-23 18:31:59 +08:00
public CPU(NES parent)
{
2024-07-25 11:03:58 +08:00
nes = parent;
m_bClockProcess = false;
}
public void Dispose() { }
2024-07-26 17:52:33 +08:00
ushort EA = 0;
ushort ET = 0;
ushort WT = 0;
byte DT = 0;
int exec_cycles = 0;
2024-07-25 11:03:58 +08:00
internal long EXEC(int request_cycles)
{
2024-07-26 17:52:33 +08:00
byte opcode = 0;
int OLD_cycles = TOTAL_cycles;
byte nmi_request = 0, irq_request = 0;
bool bClockProcess = m_bClockProcess;
exec_cycles = 0;
EA = 0;
ET = 0;
WT = 0;
DT = 0;
while (request_cycles > 0)
{
exec_cycles = 0;
if (DMA_cycles > 0)
{
if (request_cycles <= DMA_cycles)
{
DMA_cycles -= request_cycles;
TOTAL_cycles += request_cycles;
mapper.Clock(request_cycles);
#if DPCM_SYNCCLOCK
apu.SyncDPCM(request_cycles);
#endif
if (m_bClockProcess)
{
nes.Clock(request_cycles);
}
goto _execute_exit;
}
else
{
exec_cycles += DMA_cycles;
DMA_cycles = 0;
}
}
nmi_request = irq_request = 0;
opcode = OP6502(R.PC++);
if (R.INT_pending != 0)
{
if ((R.INT_pending & NMI_FLAG) != 0)
{
nmi_request = 0xFF;
byte temp = unchecked((byte)(~NMI_FLAG));
R.INT_pending &= temp;
}
else if ((R.INT_pending & IRQ_MASK) != 0)
{
byte temp = unchecked((byte)(~IRQ_TRIGGER2));
R.INT_pending &= temp;
if (
((R.P & I_FLAG) == 0)
&&
(opcode != 0x40)
)
{
irq_request = 0xFF;
temp = unchecked((byte)(~IRQ_TRIGGER));
R.INT_pending &= temp;
}
}
}
switch (opcode)
{
2024-07-31 17:40:32 +08:00
case 0x69: // ADC #$??
2024-07-26 17:52:33 +08:00
MR_IM(); ADC();
ADD_CYCLE(2);
break;
2024-07-31 17:40:32 +08:00
case 0x65: // ADC $??
2024-07-26 17:52:33 +08:00
MR_ZP(); ADC();
ADD_CYCLE(3);
break;
2024-07-31 17:40:32 +08:00
case 0x75: // ADC $??,X
2024-07-26 17:52:33 +08:00
MR_ZX(); ADC();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0x6D: // ADC $????
2024-07-26 17:52:33 +08:00
MR_AB(); ADC();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0x7D: // ADC $????,X
2024-07-26 17:52:33 +08:00
MR_AX(); ADC(); CHECK_EA();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0x79: // ADC $????,Y
2024-07-26 17:52:33 +08:00
MR_AY(); ADC(); CHECK_EA();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0x61: // ADC ($??,X)
2024-07-26 17:52:33 +08:00
MR_IX(); ADC();
ADD_CYCLE(6);
break;
2024-07-31 17:40:32 +08:00
case 0x71: // ADC ($??),Y
2024-07-26 17:52:33 +08:00
MR_IY(); ADC(); CHECK_EA();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0xE9: // SBC #$??
2024-07-26 17:52:33 +08:00
MR_IM(); SBC();
ADD_CYCLE(2);
break;
2024-07-31 17:40:32 +08:00
case 0xE5: // SBC $??
2024-07-26 17:52:33 +08:00
MR_ZP(); SBC();
ADD_CYCLE(3);
break;
2024-07-31 17:40:32 +08:00
case 0xF5: // SBC $??,X
2024-07-26 17:52:33 +08:00
MR_ZX(); SBC();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0xED: // SBC $????
2024-07-26 17:52:33 +08:00
MR_AB(); SBC();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0xFD: // SBC $????,X
2024-07-26 17:52:33 +08:00
MR_AX(); SBC(); CHECK_EA();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0xF9: // SBC $????,Y
2024-07-26 17:52:33 +08:00
MR_AY(); SBC(); CHECK_EA();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0xE1: // SBC ($??,X)
2024-07-26 17:52:33 +08:00
MR_IX(); SBC();
ADD_CYCLE(6);
break;
2024-07-31 17:40:32 +08:00
case 0xF1: // SBC ($??),Y
2024-07-26 17:52:33 +08:00
MR_IY(); SBC(); CHECK_EA();
ADD_CYCLE(5);
break;
2024-07-31 17:40:32 +08:00
2024-07-26 17:52:33 +08:00
case 0xC6: // DEC $??
MR_ZP(); DEC(); MW_ZP();
ADD_CYCLE(5);
break;
2024-07-31 17:40:32 +08:00
case 0xD6: // DEC $??,X
2024-07-26 17:52:33 +08:00
MR_ZX(); DEC(); MW_ZP();
ADD_CYCLE(6);
break;
case 0xCE: // DEC $????
MR_AB(); DEC(); MW_EA();
ADD_CYCLE(6);
break;
2024-07-31 17:40:32 +08:00
case 0xDE: // DEC $????,X
2024-07-26 17:52:33 +08:00
MR_AX(); DEC(); MW_EA();
ADD_CYCLE(7);
break;
2024-07-31 17:40:32 +08:00
2024-07-26 17:52:33 +08:00
case 0xCA: // DEX
DEX();
ADD_CYCLE(2);
break;
case 0x88: // DEY
DEY();
ADD_CYCLE(2);
break;
2024-07-31 17:40:32 +08:00
2024-07-26 17:52:33 +08:00
case 0xE6: // INC $??
MR_ZP(); INC(); MW_ZP();
ADD_CYCLE(5);
break;
2024-07-31 17:40:32 +08:00
case 0xF6: // INC $??,X
2024-07-26 17:52:33 +08:00
MR_ZX(); INC(); MW_ZP();
ADD_CYCLE(6);
break;
case 0xEE: // INC $????
MR_AB(); INC(); MW_EA();
ADD_CYCLE(6);
break;
2024-07-31 17:40:32 +08:00
case 0xFE: // INC $????,X
2024-07-26 17:52:33 +08:00
MR_AX(); INC(); MW_EA();
ADD_CYCLE(7);
break;
2024-07-31 17:40:32 +08:00
2024-07-26 17:52:33 +08:00
case 0xE8: // INX
INX();
ADD_CYCLE(2);
break;
case 0xC8: // INY
INY();
ADD_CYCLE(2);
break;
2024-07-31 17:40:32 +08:00
2024-07-26 17:52:33 +08:00
case 0x29: // AND #$??
MR_IM(); AND();
ADD_CYCLE(2);
break;
case 0x25: // AND $??
MR_ZP(); AND();
ADD_CYCLE(3);
break;
2024-07-31 17:40:32 +08:00
case 0x35: // AND $??,X
2024-07-26 17:52:33 +08:00
MR_ZX(); AND();
ADD_CYCLE(4);
break;
case 0x2D: // AND $????
MR_AB(); AND();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0x3D: // AND $????,X
2024-07-26 17:52:33 +08:00
MR_AX(); AND(); CHECK_EA();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0x39: // AND $????,Y
2024-07-26 17:52:33 +08:00
MR_AY(); AND(); CHECK_EA();
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
case 0x21: // AND ($??,X)
2024-07-26 17:52:33 +08:00
MR_IX(); AND();
ADD_CYCLE(6);
break;
2024-07-31 17:40:32 +08:00
case 0x31: // AND ($??),Y
2024-07-26 17:52:33 +08:00
MR_IY(); AND(); CHECK_EA();
ADD_CYCLE(5);
break;
2024-07-31 17:40:32 +08:00
2024-07-26 17:52:33 +08:00
case 0x0A: // ASL A
ASL_A();
ADD_CYCLE(2);
break;
case 0x06: // ASL $??
MR_ZP(); ASL(); MW_ZP();
ADD_CYCLE(5);
break;
case 0x16: // ASL $??,X
MR_ZX(); ASL(); MW_ZP();
ADD_CYCLE(6);
break;
case 0x0E: // ASL $????
MR_AB(); ASL(); MW_EA();
ADD_CYCLE(6);
break;
case 0x1E: // ASL $????,X
MR_AX(); ASL(); MW_EA();
ADD_CYCLE(7);
break;
case 0x24: // BIT $??
MR_ZP(); BIT();
ADD_CYCLE(3);
break;
case 0x2C: // BIT $????
MR_AB(); BIT();
ADD_CYCLE(4);
break;
case 0x49: // EOR #$??
MR_IM(); EOR();
ADD_CYCLE(2);
break;
case 0x45: // EOR $??
MR_ZP(); EOR();
ADD_CYCLE(3);
break;
case 0x55: // EOR $??,X
MR_ZX(); EOR();
ADD_CYCLE(4);
break;
case 0x4D: // EOR $????
MR_AB(); EOR();
ADD_CYCLE(4);
break;
case 0x5D: // EOR $????,X
MR_AX(); EOR(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0x59: // EOR $????,Y
MR_AY(); EOR(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0x41: // EOR ($??,X)
MR_IX(); EOR();
ADD_CYCLE(6);
break;
case 0x51: // EOR ($??),Y
MR_IY(); EOR(); CHECK_EA();
ADD_CYCLE(5);
break;
case 0x4A: // LSR A
LSR_A();
ADD_CYCLE(2);
break;
case 0x46: // LSR $??
MR_ZP(); LSR(); MW_ZP();
ADD_CYCLE(5);
break;
case 0x56: // LSR $??,X
MR_ZX(); LSR(); MW_ZP();
ADD_CYCLE(6);
break;
case 0x4E: // LSR $????
MR_AB(); LSR(); MW_EA();
ADD_CYCLE(6);
break;
case 0x5E: // LSR $????,X
MR_AX(); LSR(); MW_EA();
ADD_CYCLE(7);
break;
case 0x09: // ORA #$??
MR_IM(); ORA();
ADD_CYCLE(2);
break;
case 0x05: // ORA $??
MR_ZP(); ORA();
ADD_CYCLE(3);
break;
case 0x15: // ORA $??,X
MR_ZX(); ORA();
ADD_CYCLE(4);
break;
case 0x0D: // ORA $????
MR_AB(); ORA();
ADD_CYCLE(4);
break;
case 0x1D: // ORA $????,X
MR_AX(); ORA(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0x19: // ORA $????,Y
MR_AY(); ORA(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0x01: // ORA ($??,X)
MR_IX(); ORA();
ADD_CYCLE(6);
break;
case 0x11: // ORA ($??),Y
MR_IY(); ORA(); CHECK_EA();
ADD_CYCLE(5);
break;
case 0x2A: // ROL A
ROL_A();
ADD_CYCLE(2);
break;
case 0x26: // ROL $??
MR_ZP(); ROL(); MW_ZP();
ADD_CYCLE(5);
break;
case 0x36: // ROL $??,X
MR_ZX(); ROL(); MW_ZP();
ADD_CYCLE(6);
break;
case 0x2E: // ROL $????
MR_AB(); ROL(); MW_EA();
ADD_CYCLE(6);
break;
case 0x3E: // ROL $????,X
MR_AX(); ROL(); MW_EA();
ADD_CYCLE(7);
break;
case 0x6A: // ROR A
ROR_A();
ADD_CYCLE(2);
break;
case 0x66: // ROR $??
MR_ZP(); ROR(); MW_ZP();
ADD_CYCLE(5);
break;
case 0x76: // ROR $??,X
MR_ZX(); ROR(); MW_ZP();
ADD_CYCLE(6);
break;
case 0x6E: // ROR $????
MR_AB(); ROR(); MW_EA();
ADD_CYCLE(6);
break;
case 0x7E: // ROR $????,X
MR_AX(); ROR(); MW_EA();
ADD_CYCLE(7);
break;
case 0xA9: // LDA #$??
MR_IM(); LDA();
ADD_CYCLE(2);
break;
case 0xA5: // LDA $??
MR_ZP(); LDA();
ADD_CYCLE(3);
break;
case 0xB5: // LDA $??,X
MR_ZX(); LDA();
ADD_CYCLE(4);
break;
case 0xAD: // LDA $????
MR_AB(); LDA();
ADD_CYCLE(4);
break;
case 0xBD: // LDA $????,X
MR_AX(); LDA(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0xB9: // LDA $????,Y
MR_AY(); LDA(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0xA1: // LDA ($??,X)
MR_IX(); LDA();
ADD_CYCLE(6);
break;
case 0xB1: // LDA ($??),Y
MR_IY(); LDA(); CHECK_EA();
ADD_CYCLE(5);
break;
case 0xA2: // LDX #$??
MR_IM(); LDX();
ADD_CYCLE(2);
break;
case 0xA6: // LDX $??
MR_ZP(); LDX();
ADD_CYCLE(3);
break;
case 0xB6: // LDX $??,Y
MR_ZY(); LDX();
ADD_CYCLE(4);
break;
case 0xAE: // LDX $????
MR_AB(); LDX();
ADD_CYCLE(4);
break;
case 0xBE: // LDX $????,Y
MR_AY(); LDX(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0xA0: // LDY #$??
MR_IM(); LDY();
ADD_CYCLE(2);
break;
case 0xA4: // LDY $??
MR_ZP(); LDY();
ADD_CYCLE(3);
break;
case 0xB4: // LDY $??,X
MR_ZX(); LDY();
ADD_CYCLE(4);
break;
case 0xAC: // LDY $????
MR_AB(); LDY();
ADD_CYCLE(4);
break;
case 0xBC: // LDY $????,X
MR_AX(); LDY(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0x85: // STA $??
EA_ZP(); STA(); MW_ZP();
ADD_CYCLE(3);
break;
case 0x95: // STA $??,X
EA_ZX(); STA(); MW_ZP();
ADD_CYCLE(4);
break;
case 0x8D: // STA $????
EA_AB(); STA(); MW_EA();
ADD_CYCLE(4);
break;
case 0x9D: // STA $????,X
EA_AX(); STA(); MW_EA();
ADD_CYCLE(5);
break;
case 0x99: // STA $????,Y
EA_AY(); STA(); MW_EA();
ADD_CYCLE(5);
break;
case 0x81: // STA ($??,X)
EA_IX(); STA(); MW_EA();
ADD_CYCLE(6);
break;
case 0x91: // STA ($??),Y
EA_IY(); STA(); MW_EA();
ADD_CYCLE(6);
break;
case 0x86: // STX $??
EA_ZP(); STX(); MW_ZP();
ADD_CYCLE(3);
break;
case 0x96: // STX $??,Y
EA_ZY(); STX(); MW_ZP();
ADD_CYCLE(4);
break;
case 0x8E: // STX $????
EA_AB(); STX(); MW_EA();
ADD_CYCLE(4);
break;
case 0x84: // STY $??
EA_ZP(); STY(); MW_ZP();
ADD_CYCLE(3);
break;
case 0x94: // STY $??,X
EA_ZX(); STY(); MW_ZP();
ADD_CYCLE(4);
break;
case 0x8C: // STY $????
EA_AB(); STY(); MW_EA();
ADD_CYCLE(4);
break;
case 0xAA: // TAX
TAX();
ADD_CYCLE(2);
break;
case 0x8A: // TXA
TXA();
ADD_CYCLE(2);
break;
case 0xA8: // TAY
TAY();
ADD_CYCLE(2);
break;
case 0x98: // TYA
TYA();
ADD_CYCLE(2);
break;
case 0xBA: // TSX
TSX();
ADD_CYCLE(2);
break;
case 0x9A: // TXS
TXS();
ADD_CYCLE(2);
break;
case 0xC9: // CMP #$??
MR_IM(); CMP_();
ADD_CYCLE(2);
break;
case 0xC5: // CMP $??
MR_ZP(); CMP_();
ADD_CYCLE(3);
break;
case 0xD5: // CMP $??,X
MR_ZX(); CMP_();
ADD_CYCLE(4);
break;
case 0xCD: // CMP $????
MR_AB(); CMP_();
ADD_CYCLE(4);
break;
case 0xDD: // CMP $????,X
MR_AX(); CMP_(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0xD9: // CMP $????,Y
MR_AY(); CMP_(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0xC1: // CMP ($??,X)
MR_IX(); CMP_();
ADD_CYCLE(6);
break;
case 0xD1: // CMP ($??),Y
MR_IY(); CMP_(); CHECK_EA();
ADD_CYCLE(5);
break;
case 0xE0: // CPX #$??
MR_IM(); CPX();
ADD_CYCLE(2);
break;
case 0xE4: // CPX $??
MR_ZP(); CPX();
ADD_CYCLE(3);
break;
case 0xEC: // CPX $????
MR_AB(); CPX();
ADD_CYCLE(4);
break;
case 0xC0: // CPY #$??
MR_IM(); CPY();
ADD_CYCLE(2);
break;
case 0xC4: // CPY $??
MR_ZP(); CPY();
ADD_CYCLE(3);
break;
case 0xCC: // CPY $????
MR_AB(); CPY();
ADD_CYCLE(4);
break;
case 0x90: // BCC
MR_IM(); BCC();
ADD_CYCLE(2);
break;
case 0xB0: // BCS
MR_IM(); BCS();
ADD_CYCLE(2);
break;
case 0xF0: // BEQ
MR_IM(); BEQ();
ADD_CYCLE(2);
break;
case 0x30: // BMI
MR_IM(); BMI();
ADD_CYCLE(2);
break;
case 0xD0: // BNE
MR_IM(); BNE();
ADD_CYCLE(2);
break;
case 0x10: // BPL
MR_IM(); BPL();
ADD_CYCLE(2);
break;
case 0x50: // BVC
MR_IM(); BVC();
ADD_CYCLE(2);
break;
case 0x70: // BVS
MR_IM(); BVS();
ADD_CYCLE(2);
break;
case 0x4C: // JMP $????
JMP();
ADD_CYCLE(3);
break;
case 0x6C: // JMP ($????)
JMP_ID();
ADD_CYCLE(5);
break;
case 0x20: // JSR
JSR();
ADD_CYCLE(6);
break;
case 0x40: // RTI
RTI();
ADD_CYCLE(6);
break;
case 0x60: // RTS
RTS();
ADD_CYCLE(6);
break;
2024-07-31 17:40:32 +08:00
// フラグ制御系
2024-07-26 17:52:33 +08:00
case 0x18: // CLC
CLC();
ADD_CYCLE(2);
break;
case 0xD8: // CLD
CLD();
ADD_CYCLE(2);
break;
case 0x58: // CLI
CLI();
ADD_CYCLE(2);
break;
case 0xB8: // CLV
CLV();
ADD_CYCLE(2);
break;
case 0x38: // SEC
SEC();
ADD_CYCLE(2);
break;
case 0xF8: // SED
SED();
ADD_CYCLE(2);
break;
case 0x78: // SEI
SEI();
ADD_CYCLE(2);
break;
2024-07-31 17:40:32 +08:00
// スタック系
2024-07-26 17:52:33 +08:00
case 0x48: // PHA
PUSH(R.A);
ADD_CYCLE(3);
break;
case 0x08: // PHP
PUSH((byte)(R.P | B_FLAG));
ADD_CYCLE(3);
break;
case 0x68: // PLA (N-----Z-)
R.A = POP();
SET_ZN_FLAG(R.A);
ADD_CYCLE(4);
break;
case 0x28: // PLP
R.P = (byte)(POP() | R_FLAG);
ADD_CYCLE(4);
break;
2024-07-31 17:40:32 +08:00
// その他
2024-07-26 17:52:33 +08:00
case 0x00: // BRK
BRK();
ADD_CYCLE(7);
break;
case 0xEA: // NOP
ADD_CYCLE(2);
break;
2024-07-31 17:40:32 +08:00
// 未公開命令群
2024-07-26 17:52:33 +08:00
case 0x0B: // ANC #$??
case 0x2B: // ANC #$??
MR_IM(); ANC();
ADD_CYCLE(2);
break;
case 0x8B: // ANE #$??
MR_IM(); ANE();
ADD_CYCLE(2);
break;
case 0x6B: // ARR #$??
MR_IM(); ARR();
ADD_CYCLE(2);
break;
case 0x4B: // ASR #$??
MR_IM(); ASR();
ADD_CYCLE(2);
break;
case 0xC7: // DCP $??
MR_ZP(); DCP(); MW_ZP();
ADD_CYCLE(5);
break;
case 0xD7: // DCP $??,X
MR_ZX(); DCP(); MW_ZP();
ADD_CYCLE(6);
break;
case 0xCF: // DCP $????
MR_AB(); DCP(); MW_EA();
ADD_CYCLE(6);
break;
case 0xDF: // DCP $????,X
MR_AX(); DCP(); MW_EA();
ADD_CYCLE(7);
break;
case 0xDB: // DCP $????,Y
MR_AY(); DCP(); MW_EA();
ADD_CYCLE(7);
break;
case 0xC3: // DCP ($??,X)
MR_IX(); DCP(); MW_EA();
ADD_CYCLE(8);
break;
case 0xD3: // DCP ($??),Y
MR_IY(); DCP(); MW_EA();
ADD_CYCLE(8);
break;
case 0xE7: // ISB $??
MR_ZP(); ISB(); MW_ZP();
ADD_CYCLE(5);
break;
case 0xF7: // ISB $??,X
MR_ZX(); ISB(); MW_ZP();
ADD_CYCLE(5);
break;
case 0xEF: // ISB $????
MR_AB(); ISB(); MW_EA();
ADD_CYCLE(5);
break;
case 0xFF: // ISB $????,X
MR_AX(); ISB(); MW_EA();
ADD_CYCLE(5);
break;
case 0xFB: // ISB $????,Y
MR_AY(); ISB(); MW_EA();
ADD_CYCLE(5);
break;
case 0xE3: // ISB ($??,X)
MR_IX(); ISB(); MW_EA();
ADD_CYCLE(5);
break;
case 0xF3: // ISB ($??),Y
MR_IY(); ISB(); MW_EA();
ADD_CYCLE(5);
break;
case 0xBB: // LAS $????,Y
MR_AY(); LAS(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0xA7: // LAX $??
MR_ZP(); LAX();
ADD_CYCLE(3);
break;
case 0xB7: // LAX $??,Y
MR_ZY(); LAX();
ADD_CYCLE(4);
break;
case 0xAF: // LAX $????
MR_AB(); LAX();
ADD_CYCLE(4);
break;
case 0xBF: // LAX $????,Y
MR_AY(); LAX(); CHECK_EA();
ADD_CYCLE(4);
break;
case 0xA3: // LAX ($??,X)
MR_IX(); LAX();
ADD_CYCLE(6);
break;
case 0xB3: // LAX ($??),Y
MR_IY(); LAX(); CHECK_EA();
ADD_CYCLE(5);
break;
case 0xAB: // LXA #$??
MR_IM(); LXA();
ADD_CYCLE(2);
break;
case 0x27: // RLA $??
MR_ZP(); RLA(); MW_ZP();
ADD_CYCLE(5);
break;
case 0x37: // RLA $??,X
MR_ZX(); RLA(); MW_ZP();
ADD_CYCLE(6);
break;
case 0x2F: // RLA $????
MR_AB(); RLA(); MW_EA();
ADD_CYCLE(6);
break;
case 0x3F: // RLA $????,X
MR_AX(); RLA(); MW_EA();
ADD_CYCLE(7);
break;
case 0x3B: // RLA $????,Y
MR_AY(); RLA(); MW_EA();
ADD_CYCLE(7);
break;
case 0x23: // RLA ($??,X)
MR_IX(); RLA(); MW_EA();
ADD_CYCLE(8);
break;
case 0x33: // RLA ($??),Y
MR_IY(); RLA(); MW_EA();
ADD_CYCLE(8);
break;
case 0x67: // RRA $??
MR_ZP(); RRA(); MW_ZP();
ADD_CYCLE(5);
break;
case 0x77: // RRA $??,X
MR_ZX(); RRA(); MW_ZP();
ADD_CYCLE(6);
break;
case 0x6F: // RRA $????
MR_AB(); RRA(); MW_EA();
ADD_CYCLE(6);
break;
case 0x7F: // RRA $????,X
MR_AX(); RRA(); MW_EA();
ADD_CYCLE(7);
break;
case 0x7B: // RRA $????,Y
MR_AY(); RRA(); MW_EA();
ADD_CYCLE(7);
break;
case 0x63: // RRA ($??,X)
MR_IX(); RRA(); MW_EA();
ADD_CYCLE(8);
break;
case 0x73: // RRA ($??),Y
MR_IY(); RRA(); MW_EA();
ADD_CYCLE(8);
break;
case 0x87: // SAX $??
MR_ZP(); SAX(); MW_ZP();
ADD_CYCLE(3);
break;
case 0x97: // SAX $??,Y
MR_ZY(); SAX(); MW_ZP();
ADD_CYCLE(4);
break;
case 0x8F: // SAX $????
MR_AB(); SAX(); MW_EA();
ADD_CYCLE(4);
break;
case 0x83: // SAX ($??,X)
MR_IX(); SAX(); MW_EA();
ADD_CYCLE(6);
break;
case 0xCB: // SBX #$??
MR_IM(); SBX();
ADD_CYCLE(2);
break;
case 0x9F: // SHA $????,Y
MR_AY(); SHA(); MW_EA();
ADD_CYCLE(5);
break;
case 0x93: // SHA ($??),Y
MR_IY(); SHA(); MW_EA();
ADD_CYCLE(6);
break;
case 0x9B: // SHS $????,Y
MR_AY(); SHS(); MW_EA();
ADD_CYCLE(5);
break;
case 0x9E: // SHX $????,Y
MR_AY(); SHX(); MW_EA();
ADD_CYCLE(5);
break;
case 0x9C: // SHY $????,X
MR_AX(); SHY(); MW_EA();
ADD_CYCLE(5);
break;
case 0x07: // SLO $??
MR_ZP(); SLO(); MW_ZP();
ADD_CYCLE(5);
break;
case 0x17: // SLO $??,X
MR_ZX(); SLO(); MW_ZP();
ADD_CYCLE(6);
break;
case 0x0F: // SLO $????
MR_AB(); SLO(); MW_EA();
ADD_CYCLE(6);
break;
case 0x1F: // SLO $????,X
MR_AX(); SLO(); MW_EA();
ADD_CYCLE(7);
break;
case 0x1B: // SLO $????,Y
MR_AY(); SLO(); MW_EA();
ADD_CYCLE(7);
break;
case 0x03: // SLO ($??,X)
MR_IX(); SLO(); MW_EA();
ADD_CYCLE(8);
break;
case 0x13: // SLO ($??),Y
MR_IY(); SLO(); MW_EA();
ADD_CYCLE(8);
break;
case 0x47: // SRE $??
MR_ZP(); SRE(); MW_ZP();
ADD_CYCLE(5);
break;
case 0x57: // SRE $??,X
MR_ZX(); SRE(); MW_ZP();
ADD_CYCLE(6);
break;
case 0x4F: // SRE $????
MR_AB(); SRE(); MW_EA();
ADD_CYCLE(6);
break;
case 0x5F: // SRE $????,X
MR_AX(); SRE(); MW_EA();
ADD_CYCLE(7);
break;
case 0x5B: // SRE $????,Y
MR_AY(); SRE(); MW_EA();
ADD_CYCLE(7);
break;
case 0x43: // SRE ($??,X)
MR_IX(); SRE(); MW_EA();
ADD_CYCLE(8);
break;
case 0x53: // SRE ($??),Y
MR_IY(); SRE(); MW_EA();
ADD_CYCLE(8);
break;
case 0xEB: // SBC #$?? (Unofficial)
MR_IM(); SBC();
ADD_CYCLE(2);
break;
case 0x1A: // NOP (Unofficial)
case 0x3A: // NOP (Unofficial)
case 0x5A: // NOP (Unofficial)
case 0x7A: // NOP (Unofficial)
case 0xDA: // NOP (Unofficial)
case 0xFA: // NOP (Unofficial)
ADD_CYCLE(2);
break;
case 0x80: // DOP (CYCLES 2)
case 0x82: // DOP (CYCLES 2)
case 0x89: // DOP (CYCLES 2)
case 0xC2: // DOP (CYCLES 2)
case 0xE2: // DOP (CYCLES 2)
R.PC++;
ADD_CYCLE(2);
break;
case 0x04: // DOP (CYCLES 3)
case 0x44: // DOP (CYCLES 3)
case 0x64: // DOP (CYCLES 3)
R.PC++;
ADD_CYCLE(3);
break;
case 0x14: // DOP (CYCLES 4)
case 0x34: // DOP (CYCLES 4)
case 0x54: // DOP (CYCLES 4)
case 0x74: // DOP (CYCLES 4)
case 0xD4: // DOP (CYCLES 4)
case 0xF4: // DOP (CYCLES 4)
R.PC++;
ADD_CYCLE(4);
break;
case 0x0C: // TOP
case 0x1C: // TOP
case 0x3C: // TOP
case 0x5C: // TOP
case 0x7C: // TOP
case 0xDC: // TOP
case 0xFC: // TOP
R.PC += 2;
ADD_CYCLE(4);
break;
case 0x02: /* JAM */
case 0x12: /* JAM */
case 0x22: /* JAM */
case 0x32: /* JAM */
case 0x42: /* JAM */
case 0x52: /* JAM */
case 0x62: /* JAM */
case 0x72: /* JAM */
case 0x92: /* JAM */
case 0xB2: /* JAM */
case 0xD2: /* JAM */
case 0xF2: /* JAM */
default:
if (!Supporter.Config.emulator.bIllegalOp)
{
2024-07-31 17:40:32 +08:00
throw new Exception("IllegalOp");
2024-07-26 17:52:33 +08:00
}
else
{
R.PC--;
ADD_CYCLE(4);
}
break;
2024-07-31 17:40:32 +08:00
// default:
// __assume(0);
2024-07-26 17:52:33 +08:00
}
if (nmi_request != 0)
{
_NMI();
}
else
if (irq_request != 0)
{
_IRQ();
}
request_cycles -= exec_cycles;
TOTAL_cycles += exec_cycles;
mapper.Clock(exec_cycles);
#if DPCM_SYNCCLOCK
apu->SyncDPCM( exec_cycles );
#endif
if (bClockProcess)
{
nes.Clock(exec_cycles);
}
}
_execute_exit:
#if !DPCM_SYNCCLOCK
apu.SyncDPCM(TOTAL_cycles - OLD_cycles);
#endif
return TOTAL_cycles - OLD_cycles;
}
private void _IRQ()
{
PUSH((byte)(R.PC >> 8));
PUSH((byte)(R.PC & 0xFF));
CLR_FLAG(B_FLAG);
PUSH(R.P);
SET_FLAG(I_FLAG);
R.PC = RD6502W(IRQ_VECTOR);
exec_cycles += 7;
}
private ushort RD6502W(ushort addr)
{
if (addr < 0x2000)
{
// RAM (Mirror $0800, $1000, $1800)
return BitConverter.ToUInt16(MMU.RAM, addr & 0x07FF);
}
else if (addr < 0x8000)
{
// Others
return (ushort)(nes.Read(addr) + nes.Read((ushort)(addr + 1)) * 0x100);
}
2024-07-30 18:53:36 +08:00
var temp = MMU.CPU_MEM_BANK[addr >> 13];
2024-07-26 17:52:33 +08:00
shortTemp[0] = temp[addr & 0x1FFF];
shortTemp[1] = temp[(addr & 0x1FFF) + 1];
return BitConverter.ToUInt16(shortTemp, 0);
}
private void SET_FLAG(byte V)
{
R.P |= (V);
}
private void CLR_FLAG(byte V)
{
var temp = (byte)(~V);
R.P &= temp;
}
private void _NMI()
{
PUSH((byte)(R.PC >> 8));
PUSH((byte)(R.PC & 0xFF));
CLR_FLAG(B_FLAG);
PUSH(R.P);
SET_FLAG(I_FLAG);
R.PC = RD6502W(NMI_VECTOR);
exec_cycles += 7;
}
private void SRE()
{
TST_FLAG((DT & 0x01) != 0, C_FLAG);
DT >>= 1;
R.A ^= DT;
SET_ZN_FLAG(R.A);
}
private void SLO()
{
TST_FLAG((DT & 0x80) != 0, C_FLAG);
DT <<= 1;
R.A |= DT;
SET_ZN_FLAG(R.A);
}
private void SHY()
{
DT = (byte)(R.Y & ((EA >> 8) + 1));
}
private void SHX()
{
DT = (byte)(R.X & ((EA >> 8) + 1));
}
private void SHS()
{
R.S = (byte)(R.A & R.X);
DT = (byte)(R.S & ((EA >> 8) + 1));
}
private void SHA()
{
DT = (byte)(R.A & R.X & ((EA >> 8) + 1));
}
private void SBX()
{
WT = (ushort)((R.A & R.X) - DT);
TST_FLAG(WT < 0x100, C_FLAG);
R.X = (byte)(WT & 0xFF);
SET_ZN_FLAG(R.X);
}
private void SAX()
{
DT = (byte)(R.A & R.X);
}
private void RRA()
{
if ((R.P & C_FLAG) != 0)
{
TST_FLAG((DT & 0x01) != 0, C_FLAG);
DT = (byte)((DT >> 1) | 0x80);
}
else
{
TST_FLAG((DT & 0x01) != 0, C_FLAG);
DT >>= 1;
}
ADC();
}
private void RLA()
{
if ((R.P & C_FLAG) != 0)
{
TST_FLAG((DT & 0x80) != 0, C_FLAG);
DT = (byte)((DT << 1) | 1);
}
else
{
TST_FLAG((DT & 0x80) != 0, C_FLAG);
DT <<= 1;
}
R.A &= DT;
SET_ZN_FLAG(R.A);
}
private void LXA()
{
R.A = R.X = (byte)((R.A | 0xEE) & DT);
SET_ZN_FLAG(R.A);
}
private void LAX()
{
R.A = DT;
R.X = R.A;
SET_ZN_FLAG(R.A);
}
private void LAS()
{
R.A = R.X = R.S = (byte)(R.S & DT);
SET_ZN_FLAG(R.A);
}
private void ISB()
{
DT++;
SBC();
}
private void DCP()
{
DT--;
CMP_();
}
private void ASR()
{
DT &= R.A;
TST_FLAG((DT & 0x01) != 0, C_FLAG);
R.A = (byte)(DT >> 1);
SET_ZN_FLAG(R.A);
}
private void ARR()
{
DT &= R.A;
R.A = (byte)((DT >> 1) | ((R.P & C_FLAG) << 7));
SET_ZN_FLAG(R.A);
TST_FLAG((R.A & 0x40) != 0, C_FLAG);
TST_FLAG(((R.A >> 6) ^ (R.A >> 5)) != 0, V_FLAG);
}
private void ANE()
{
R.A = (byte)((R.A | 0xEE) & R.X & DT);
SET_ZN_FLAG(R.A);
}
private void ANC()
{
R.A &= DT;
SET_ZN_FLAG(R.A);
TST_FLAG((R.P & N_FLAG) != 0, C_FLAG);
}
private void BRK()
{
R.PC++;
PUSH((byte)(R.PC >> 8));
PUSH((byte)(R.PC & 0xFF));
SET_FLAG(B_FLAG);
PUSH(R.P);
SET_FLAG(I_FLAG);
R.PC = RD6502W(IRQ_VECTOR);
}
private byte POP()
{
return STACK[(++R.S) & 0xFF];
2024-07-26 17:52:33 +08:00
}
private void PUSH(byte V)
{
STACK[(R.S--) & 0xFF] = V;
2024-07-26 17:52:33 +08:00
}
private void SEI()
{
R.P |= I_FLAG;
}
private void SED()
{
R.P |= D_FLAG;
}
private void SEC()
{
R.P |= C_FLAG;
}
private void CLV()
{
var temp = unchecked((byte)(~V_FLAG));
R.P &= temp;
}
private void CLI()
{
var temp = unchecked((byte)(~I_FLAG));
R.P &= temp;
}
private void CLD()
{
var temp = unchecked((byte)(~D_FLAG));
R.P &= temp;
}
private void CLC()
{
var temp = unchecked((byte)(~C_FLAG));
R.P &= temp;
}
private void RTS()
{
R.PC = POP();
R.PC |= (ushort)(POP() * 0x0100);
R.PC++;
}
private void RTI()
{
R.P = (byte)(POP() | R_FLAG);
R.PC = POP();
R.PC |= (ushort)(POP() * 0x0100);
}
private void JSR()
{
EA = OP6502W(R.PC);
R.PC++;
PUSH((byte)(R.PC >> 8));
PUSH((byte)(R.PC & 0xFF));
R.PC = EA;
}
private void JMP_ID()
{
WT = OP6502W(R.PC);
EA = RD6502(WT);
WT = (ushort)((WT & 0xFF00) | ((WT + 1) & 0x00FF));
R.PC = (ushort)(EA + RD6502(WT) * 0x100);
}
private void JMP()
{
R.PC = OP6502W(R.PC);
}
private void BVS()
{
if ((R.P & V_FLAG) != 0)
REL_JUMP();
}
private void REL_JUMP()
{
ET = R.PC;
EA = (ushort)(R.PC + (sbyte)DT);
R.PC = EA;
ADD_CYCLE(1);
CHECK_EA();
}
private void BVC()
{
if ((R.P & V_FLAG) == 0) REL_JUMP();
}
private void BPL()
{
if ((R.P & N_FLAG) == 0) REL_JUMP();
}
private void BNE()
{
if ((R.P & Z_FLAG) == 0) REL_JUMP();
}
private void BMI()
{
if ((R.P & N_FLAG) != 0) REL_JUMP();
}
private void BEQ()
{
if ((R.P & Z_FLAG) != 0) REL_JUMP();
}
private void BCS()
{
if ((R.P & C_FLAG) != 0) REL_JUMP();
}
private void BCC()
{
if ((R.P & C_FLAG) == 0) REL_JUMP();
}
private void CPY()
{
WT = (ushort)(R.Y - DT);
TST_FLAG((WT & 0x8000) == 0, C_FLAG);
SET_ZN_FLAG((byte)WT);
}
private void CPX()
{
WT = (ushort)(R.X - DT);
TST_FLAG((WT & 0x8000) == 0, C_FLAG);
SET_ZN_FLAG((byte)WT);
}
private void CMP_()
{
WT = (ushort)(R.A - DT);
TST_FLAG((WT & 0x8000) == 0, C_FLAG);
SET_ZN_FLAG((byte)WT);
}
private void TXS()
{
R.S = R.X;
}
private void TSX()
{
R.X = R.S; SET_ZN_FLAG(R.X);
}
2024-07-25 11:03:58 +08:00
2024-07-26 17:52:33 +08:00
private void TYA()
{
R.A = R.Y; SET_ZN_FLAG(R.A);
}
2024-07-25 11:03:58 +08:00
2024-07-26 17:52:33 +08:00
private void TAY()
{
R.Y = R.A; SET_ZN_FLAG(R.Y);
}
2024-07-25 11:03:58 +08:00
2024-07-26 17:52:33 +08:00
private void TXA()
{
R.A = R.X; SET_ZN_FLAG(R.A);
}
2024-07-25 11:03:58 +08:00
2024-07-26 17:52:33 +08:00
private void TAX()
{
R.X = R.A; SET_ZN_FLAG(R.X);
}
2024-07-25 11:03:58 +08:00
2024-07-26 17:52:33 +08:00
private void STY()
{
DT = R.Y;
}
2024-07-25 11:03:58 +08:00
2024-07-26 17:52:33 +08:00
private void EA_ZY()
{
DT = OP6502(R.PC++);
EA = (byte)(DT + R.Y);
}
2024-07-25 11:03:58 +08:00
2024-07-26 17:52:33 +08:00
private void STX()
{
DT = R.X;
}
private void EA_IY()
{
DT = OP6502(R.PC++);
ET = ZPRDW(DT);
EA = (ushort)(ET + R.Y);
}
private void EA_IX()
{
DT = OP6502(R.PC++);
EA = ZPRDW(DT + R.X);
}
private void EA_AY()
{
ET = OP6502W(R.PC);
R.PC += 2;
EA = (ushort)(ET + R.Y);
}
private void EA_AX()
{
ET = OP6502W(R.PC);
R.PC += 2;
EA = (ushort)(ET + R.X);
}
private void EA_AB()
{
EA = OP6502W(R.PC);
R.PC += 2;
}
private void EA_ZX()
{
DT = OP6502(R.PC++);
EA = (byte)(DT + R.X);
}
private void STA()
{
DT = R.A;
}
private void EA_ZP()
{
EA = OP6502(R.PC++);
}
private void LDY()
{
R.Y = DT; SET_ZN_FLAG(R.Y);
}
private void MR_ZY()
{
DT = OP6502(R.PC++);
EA = (byte)(DT + R.Y);
DT = ZPRD(EA);
}
private void LDX()
{
R.X = DT; SET_ZN_FLAG(R.X);
}
private void LDA()
{
R.A = DT; SET_ZN_FLAG(R.A);
}
private void ROR()
{
if ((R.P & C_FLAG) != 0)
{
TST_FLAG((DT & 0x01) != 0, C_FLAG);
DT = (byte)((DT >> 1) | 0x80);
2024-07-25 11:03:58 +08:00
}
2024-07-26 17:52:33 +08:00
else
{
TST_FLAG((DT & 0x01) != 0, C_FLAG);
DT >>= 1;
}
SET_ZN_FLAG(DT);
}
private void ROR_A()
{
if ((R.P & C_FLAG) != 0)
{
TST_FLAG((R.A & 0x01) != 0, C_FLAG);
R.A = (byte)((R.A >> 1) | 0x80);
}
else
{
TST_FLAG((R.A & 0x01) != 0, C_FLAG);
R.A >>= 1;
}
SET_ZN_FLAG(R.A);
}
private void ROL()
{
if ((R.P & C_FLAG) != 0)
{
TST_FLAG((DT & 0x80) != 0, C_FLAG);
DT = (byte)((DT << 1) | 0x01);
}
else
{
TST_FLAG((DT & 0x80) != 0, C_FLAG);
DT <<= 1;
}
SET_ZN_FLAG(DT);
}
private void ROL_A()
{
if ((R.P & C_FLAG) != 0)
{
TST_FLAG((R.A & 0x80) != 0, C_FLAG);
R.A = (byte)((R.A << 1) | 0x01);
}
else
{
TST_FLAG((R.A & 0x80) != 0, C_FLAG);
R.A <<= 1;
}
SET_ZN_FLAG(R.A);
}
private void ORA()
{
R.A |= DT;
SET_ZN_FLAG(R.A);
}
private void LSR_A()
{
TST_FLAG((R.A & 0x01) != 0, C_FLAG);
R.A >>= 1;
SET_ZN_FLAG(R.A);
}
private void LSR()
{
TST_FLAG((DT & 0x01) != 0, C_FLAG);
DT >>= 1;
SET_ZN_FLAG(DT);
}
private void EOR()
{
R.A ^= DT;
SET_ZN_FLAG(R.A);
2024-07-25 11:03:58 +08:00
}
internal void SetClockProcess(bool bEnable)
{
m_bClockProcess = bEnable;
}
internal byte OP6502(ushort addr)
{
2024-07-30 18:53:36 +08:00
return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
2024-07-25 11:03:58 +08:00
}
2024-07-26 17:52:33 +08:00
private byte[] shortTemp = new byte[2];
2024-07-25 14:03:52 +08:00
internal ushort OP6502W(ushort addr)
{
var bytePage = MMU.CPU_MEM_BANK[addr >> 13];
2024-07-30 18:53:36 +08:00
var spanByte = bytePage;
2024-07-26 17:52:33 +08:00
shortTemp[0] = spanByte[addr & 0x1FFF];
shortTemp[1] = spanByte[(addr & 0x1FFF) + 1];
return BitConverter.ToUInt16(shortTemp, 0);
2024-07-25 14:03:52 +08:00
}
internal byte RD6502(ushort addr)
{
if (addr < 0x2000)
{
// RAM (Mirror $0800, $1000, $1800)
return MMU.RAM[addr & 0x07FF];
}
else if (addr < 0x8000)
{
// Others
return nes.Read(addr);
}
else
{
// Dummy access
2024-07-30 18:53:36 +08:00
mapper.Read(addr, MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF]);
2024-07-25 14:03:52 +08:00
}
// Quick bank read
2024-07-30 18:53:36 +08:00
return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
2024-07-26 17:52:33 +08:00
}
private void AND()
{
R.A &= DT;
SET_ZN_FLAG(R.A);
2024-07-25 14:03:52 +08:00
}
2024-07-26 17:52:33 +08:00
private void MR_IM()
2024-07-25 11:03:58 +08:00
{
DT = OP6502(R.PC++);
}
2024-07-26 17:52:33 +08:00
private void BIT()
{
TST_FLAG((DT & R.A) == 0, Z_FLAG);
TST_FLAG((DT & 0x80) != 0, N_FLAG);
TST_FLAG((DT & 0x40) != 0, V_FLAG);
}
private void MR_ZP()
2024-07-25 11:03:58 +08:00
{
EA = OP6502(R.PC++);
2024-07-25 18:34:52 +08:00
DT = ZPRD(EA);
2024-07-25 11:03:58 +08:00
}
2024-07-25 18:34:52 +08:00
private byte ZPRD(ushort A)
2024-07-25 11:03:58 +08:00
{
return MMU.RAM[A];
}
2024-07-25 18:34:52 +08:00
private ushort ZPRDW(int A)
{
ushort ram1 = MMU.RAM[A];
ushort ram2 = MMU.RAM[A + 1];
ram2 <<= 8;
return (ushort)(ram1 + ram2);
}
2024-07-26 17:52:33 +08:00
private void ADC()
2024-07-25 11:03:58 +08:00
{
WT = (ushort)(R.A + DT + (R.P & C_FLAG));
2024-07-25 18:34:52 +08:00
TST_FLAG(WT > 0xFF, C_FLAG);
2024-07-25 11:03:58 +08:00
var temp = ((~(R.A ^ DT)) & (R.A ^ WT) & 0x80);
2024-07-25 18:34:52 +08:00
TST_FLAG(temp != 0, V_FLAG);
2024-07-25 11:03:58 +08:00
R.A = (byte)WT;
2024-07-25 18:34:52 +08:00
SET_ZN_FLAG(R.A);
2024-07-25 11:03:58 +08:00
}
2024-07-25 18:34:52 +08:00
private void TST_FLAG(bool F, byte V)
2024-07-25 11:03:58 +08:00
{
byte temp = (byte)~V;
R.P &= temp;
if (F) R.P |= V;
}
2024-07-25 18:34:52 +08:00
private void SET_ZN_FLAG(byte A)
2024-07-25 11:03:58 +08:00
{
byte temp = unchecked((byte)(~(Z_FLAG | N_FLAG)));
R.P &= temp;
R.P |= ZN_Table[A];
}
2024-07-26 17:52:33 +08:00
private void ADD_CYCLE(int V)
2024-07-25 11:03:58 +08:00
{
exec_cycles += V;
}
2024-07-26 17:52:33 +08:00
private void MR_ZX()
2024-07-25 11:03:58 +08:00
{
DT = OP6502(R.PC++);
EA = (ushort)(DT + R.X);
2024-07-25 18:34:52 +08:00
DT = ZPRD(EA);
2024-07-23 18:31:59 +08:00
}
2024-07-25 14:03:52 +08:00
2024-07-26 17:52:33 +08:00
private void MR_AB()
2024-07-25 14:03:52 +08:00
{
EA = OP6502W(R.PC);
R.PC += 2;
DT = RD6502(EA);
}
2024-07-26 17:52:33 +08:00
private void MR_AX()
2024-07-25 18:34:52 +08:00
{
ET = OP6502W(R.PC);
R.PC += 2;
2024-07-31 17:40:32 +08:00
EA = (ushort)(ET + R.X);
2024-07-25 18:34:52 +08:00
DT = RD6502(EA);
}
2024-07-26 17:52:33 +08:00
private void CHECK_EA()
2024-07-25 18:34:52 +08:00
{
2024-07-26 17:52:33 +08:00
if ((ET & 0xFF00) != (EA & 0xFF00)) ADD_CYCLE(1);
2024-07-25 18:34:52 +08:00
}
2024-07-26 17:52:33 +08:00
private void MR_AY()
2024-07-25 18:34:52 +08:00
{
ET = OP6502W(R.PC);
R.PC += 2;
EA = (ushort)(ET + R.Y);
DT = RD6502(EA);
}
2024-07-26 17:52:33 +08:00
private void MR_IX()
2024-07-25 18:34:52 +08:00
{
DT = OP6502(R.PC++);
EA = ZPRDW(DT + R.X);
DT = RD6502(EA);
}
2024-07-26 17:52:33 +08:00
private void MR_IY()
2024-07-25 18:34:52 +08:00
{
DT = OP6502(R.PC++);
ET = ZPRDW(DT);
EA = (ushort)(ET + R.Y);
DT = RD6502(EA);
}
2024-07-26 17:52:33 +08:00
private void ASL_A()
{
TST_FLAG((R.A & 0x80) != 0, C_FLAG);
R.A <<= 1;
SET_ZN_FLAG(R.A);
}
private void ASL()
{
TST_FLAG((DT & 0x80) != 0, C_FLAG);
DT <<= 1;
SET_ZN_FLAG(DT);
}
2024-07-25 18:34:52 +08:00
2024-07-26 17:52:33 +08:00
private void SBC()
2024-07-25 18:34:52 +08:00
{
WT = (ushort)(R.A - DT - (~R.P & C_FLAG));
bool f = ((R.A ^ DT) & (R.A ^ WT) & (0x80)) != 0;
TST_FLAG(f, V_FLAG);
TST_FLAG(WT < 0x100, C_FLAG);
R.A = (byte)WT;
SET_ZN_FLAG(R.A);
}
2024-07-26 17:52:33 +08:00
private void DEC()
2024-07-25 18:34:52 +08:00
{
DT--;
SET_ZN_FLAG(DT);
}
2024-07-26 17:52:33 +08:00
private void DEX()
{
R.X--;
SET_ZN_FLAG(R.X);
}
private void DEY()
{
R.Y--;
SET_ZN_FLAG(R.Y);
}
private void INC()
{
DT++;
SET_ZN_FLAG(DT);
}
private void INX()
{
R.X++;
SET_ZN_FLAG(R.X);
}
private void INY()
{
R.Y++;
SET_ZN_FLAG(R.Y);
}
private void MW_ZP()
2024-07-25 18:34:52 +08:00
{
ZPWR(EA, DT);
}
private void ZPWR(ushort a, byte v)
{
MMU.RAM[a] = v;
}
2024-07-26 17:52:33 +08:00
private void MW_EA()
2024-07-25 18:34:52 +08:00
{
WR6502(EA, DT);
}
2024-07-25 14:03:52 +08:00
internal void ClrIRQ(byte mask)
{
byte temp = (byte)~mask;
2024-07-25 18:34:52 +08:00
R.INT_pending &= temp;
}
internal void WR6502(ushort addr, byte data)
{
if (addr < 0x2000)
{
// RAM (Mirror $0800, $1000, $1800)
MMU.RAM[addr & 0x07FF] = data;
}
else
{
// Others
nes.Write(addr, data);
}
}
internal void NMI()
{
R.INT_pending |= NMI_FLAG;
nmicount = 0;
}
internal void SetIRQ(byte mask)
{
R.INT_pending |= mask;
}
internal int GetTotalCycles()
{
return TOTAL_cycles;
}
internal void DMA(int cycles)
{
DMA_cycles += cycles;
2024-07-25 14:03:52 +08:00
}
2024-07-26 17:52:33 +08:00
internal void Reset()
{
apu = nes.apu;
mapper = nes.mapper;
R.A = 0x00;
R.X = 0x00;
R.Y = 0x00;
R.S = 0xFF;
R.P = Z_FLAG | R_FLAG;
R.PC = RD6502W(RES_VECTOR);
R.INT_pending = 0;
TOTAL_cycles = 0;
DMA_cycles = 0;
// STACK quick access
2024-08-07 17:45:38 +08:00
STACK = new ArrayRef<byte>(MMU.RAM, 0x0100, MMU.RAM.Length - 0x100);
2024-07-26 17:52:33 +08:00
// Zero/Negative FLAG
ZN_Table[0] = Z_FLAG;
for (int i = 1; i < 256; i++)
ZN_Table[i] = (byte)((i & 0x80) != 0 ? N_FLAG : 0);
}
internal void GetContext(ref R6502 r)
{
r = R;
}
2024-08-29 17:20:01 +08:00
internal int GetDmaCycles()
{
return DMA_cycles;
}
2024-07-23 18:31:59 +08:00
}
public enum StatusFlag6502 : int
{
C_FLAG = 0x01,
Z_FLAG = 0x02,
I_FLAG = 0x04,
D_FLAG = 0x08,
B_FLAG = 0x10,
R_FLAG = 0x20,
V_FLAG = 0x40,
N_FLAG = 0x80
}
public enum Interrupt : int
{
NMI_FLAG = 0x01,
IRQ_FLAG = 0x02,
IRQ_FRAMEIRQ = 0x04,
IRQ_DPCM = 0x08,
IRQ_MAPPER = 0x10,
IRQ_MAPPER2 = 0x20,
IRQ_TRIGGER = 0x40,
IRQ_TRIGGER2 = 0x80,
IRQ_MASK = (~(NMI_FLAG | IRQ_FLAG)),
}
public enum Vector : int
{
NMI_VECTOR = 0xFFFA,
RES_VECTOR = 0xFFFC,
IRQ_VECTOR = 0xFFFE
}
2024-07-25 18:34:52 +08:00
public class R6502
2024-07-23 18:31:59 +08:00
{
2024-07-25 11:03:58 +08:00
public ushort PC;
public byte A;
public byte P;
public byte X;
public byte Y;
public byte S;
2024-07-25 18:34:52 +08:00
public byte INT_pending;
2024-07-23 18:31:59 +08:00
}
}