From 910313f176ef7f754eca0ec4cfa20851ca7a7fdc Mon Sep 17 00:00:00 2001 From: TomCh Date: Tue, 15 Oct 2024 21:26:38 +0100 Subject: [PATCH] Fix edge-case for 6522 Timer write (#1333, PR #1334) Refactor GetOpcodeCyclesForRead()/Write() to make then consistent & consolidate common code. --- source/6522.cpp | 211 ++++++++++++++++++++++++------------------------ source/6522.h | 1 + 2 files changed, 105 insertions(+), 107 deletions(-) diff --git a/source/6522.cpp b/source/6522.cpp index d4c0674e..c1712670 100644 --- a/source/6522.cpp +++ b/source/6522.cpp @@ -411,9 +411,8 @@ BYTE SY6522::Read(BYTE nReg) // TODO: RMW opcodes: dec,inc,asl,lsr,rol,ror (abs16 & abs16,x) + 65C02 trb,tsb (abs16) UINT SY6522::GetOpcodeCyclesForRead(BYTE reg) { - UINT opcodeCycles = 0; - BYTE opcode = 0; - bool abs16 = false; + UINT zpOpcodeCycles = 0, opcodeCycles = 0; + BYTE zpOpcode = 0, opcode = 0; // these double-up as flags to indicate validity bool abs16x = false; bool abs16y = false; bool indx = false; @@ -422,172 +421,173 @@ UINT SY6522::GetOpcodeCyclesForRead(BYTE reg) const BYTE opcodeMinus3 = mem[(::regs.pc - 3) & 0xffff]; const BYTE opcodeMinus2 = mem[(::regs.pc - 2) & 0xffff]; + // Check 2-byte opcodes if (((opcodeMinus2 & 0x0f) == 0x01) && ((opcodeMinus2 & 0x10) == 0x00)) // ora (zp,x), and (zp,x), ..., sbc (zp,x) { // NB. this is for read, so don't need to exclude 0x81 / sta (zp,x) - opcodeCycles = 6; - opcode = opcodeMinus2; + zpOpcodeCycles = 6; + zpOpcode = opcodeMinus2; indx = true; } else if (((opcodeMinus2 & 0x0f) == 0x01) && ((opcodeMinus2 & 0x10) == 0x10)) // ora (zp),y, and (zp),y, ..., sbc (zp),y { // NB. this is for read, so don't need to exclude 0x91 / sta (zp),y - opcodeCycles = 5; - opcode = opcodeMinus2; + zpOpcodeCycles = 5; + zpOpcode = opcodeMinus2; indy = true; } else if (((opcodeMinus2 & 0x0f) == 0x02) && ((opcodeMinus2 & 0x10) == 0x10) && GetMainCpu() == CPU_65C02) // ora (zp), and (zp), ..., sbc (zp) : 65C02-only { // NB. this is for read, so don't need to exclude 0x92 / sta (zp) - opcodeCycles = 5; - opcode = opcodeMinus2; + zpOpcodeCycles = 5; + zpOpcode = opcodeMinus2; } - else - { - if ((((opcodeMinus3 & 0x0f) == 0x0D) && ((opcodeMinus3 & 0x10) == 0x00)) || // ora abs16, and abs16, ..., sbc abs16 - (opcodeMinus3 == 0x2C) || // bit abs16 - (opcodeMinus3 == 0xAC) || // ldy abs16 - (opcodeMinus3 == 0xAE) || // ldx abs16 - (opcodeMinus3 == 0xCC) || // cpy abs16 - (opcodeMinus3 == 0xEC)) // cpx abs16 - { - } - else if ((opcodeMinus3 == 0xBC) || // ldy abs16,x - ((opcodeMinus3 == 0x3C) && GetMainCpu() == CPU_65C02)) // bit abs16,x : 65C02-only - { - abs16x = true; - } - else if ((opcodeMinus3 == 0xBE)) // ldx abs16,y - { - abs16y = true; - } - else if ((opcodeMinus3 & 0x10) == 0x10) - { - if ((opcodeMinus3 & 0x0f) == 0x0D) // ora abs16,x, and abs16,x, ..., sbc abs16,x - abs16x = true; - else if ((opcodeMinus3 & 0x0f) == 0x09) // ora abs16,y, and abs16,y, ..., sbc abs16,y - abs16y = true; - } - else - { - _ASSERT(0); - opcodeCycles = 0; - return 0; - } + // Check 3-byte opcodes + if ((((opcodeMinus3 & 0x0f) == 0x0D) && ((opcodeMinus3 & 0x10) == 0x00)) || // ora abs16, and abs16, ..., sbc abs16 + (opcodeMinus3 == 0x2C) || // bit abs16 + (opcodeMinus3 == 0xAC) || // ldy abs16 + (opcodeMinus3 == 0xAE) || // ldx abs16 + (opcodeMinus3 == 0xCC) || // cpy abs16 + (opcodeMinus3 == 0xEC)) // cpx abs16 + { opcodeCycles = 4; opcode = opcodeMinus3; - abs16 = true; + } + else if ((opcodeMinus3 == 0xBC) || // ldy abs16,x + ((opcodeMinus3 == 0x3C) && GetMainCpu() == CPU_65C02)) // bit abs16,x : 65C02-only + { + opcodeCycles = 4; + opcode = opcodeMinus3; + abs16x = true; + } + else if ((opcodeMinus3 == 0xBE)) // ldx abs16,y + { + opcodeCycles = 4; + opcode = opcodeMinus3; + abs16y = true; + } + else if ((opcodeMinus3 & 0x10) == 0x10) + { + if ((opcodeMinus3 & 0x0f) == 0x0D) // ora abs16,x, and abs16,x, ..., sbc abs16,x + { + opcodeCycles = 4; + opcode = opcodeMinus3; + abs16x = true; + } + else if ((opcodeMinus3 & 0x0f) == 0x09) // ora abs16,y, and abs16,y, ..., sbc abs16,y + { + opcodeCycles = 4; + opcode = opcodeMinus3; + abs16y = true; + } } // - WORD addr16 = 0; - - if (!abs16) - { - BYTE zp = mem[(::regs.pc - 1) & 0xffff]; - if (indx) zp += ::regs.x; - addr16 = (mem[zp] | (mem[(zp + 1) & 0xff] << 8)); - if (indy) addr16 += ::regs.y; - } - else - { - addr16 = mem[(::regs.pc - 2) & 0xffff] | (mem[(::regs.pc - 1) & 0xffff] << 8); - if (abs16y) addr16 += ::regs.y; - if (abs16x) addr16 += ::regs.x; - } - - // Check we've reverse looked-up the 6502 opcode correctly - if ((addr16 & 0xF80F) != (0xC000 + reg)) + if (!opcode && !zpOpcode) // Unsupported opcode { _ASSERT(0); return 0; } - return opcodeCycles; + return GetOpcodeCycles(reg, zpOpcodeCycles, opcodeCycles, zpOpcode, opcode, abs16x, abs16y, indx, indy); } // TODO: RMW opcodes: dec,inc,asl,lsr,rol,ror (abs16 & abs16,x) + 65C02 trb,tsb (abs16) UINT SY6522::GetOpcodeCyclesForWrite(BYTE reg) { UINT zpOpcodeCycles = 0, opcodeCycles = 0; - BYTE zpOpcode = 0, opcode = 0; - bool isZP = false, isAbs16 = false; + BYTE zpOpcode = 0, opcode = 0; // these double-up as flags to indicate validity + bool abs16x = false; + bool abs16y = false; + bool indx = false; + bool indy = false; const BYTE opcodeMinus3 = mem[(::regs.pc - 3) & 0xffff]; const BYTE opcodeMinus2 = mem[(::regs.pc - 2) & 0xffff]; - if ((opcodeMinus3 == 0x8C) || // sty abs16 - (opcodeMinus3 == 0x8D) || // sta abs16 - (opcodeMinus3 == 0x8E)) // stx abs16 - { // Eg. FT demos: CHIP, MADEF, MAD2 - opcodeCycles = 4; - opcode = opcodeMinus3; - isAbs16 = true; - } - else if ((opcodeMinus3 == 0x99) || // sta abs16,y - (opcodeMinus3 == 0x9D)) // sta abs16,x - { // Eg. Paleotronic microTracker demo - opcodeCycles = 5; - opcode = opcodeMinus3; - isAbs16 = true; - } - else if (opcodeMinus3 == 0x9C && GetMainCpu() == CPU_65C02) // stz abs16 : 65C02-only - { - opcodeCycles = 4; - opcode = opcodeMinus3; - isAbs16 = true; - } - else if (opcodeMinus3 == 0x9E && GetMainCpu() == CPU_65C02) // stz abs16,x : 65C02-only - { - opcodeCycles = 5; - opcode = opcodeMinus3; - isAbs16 = true; - } - - if (opcodeMinus2 == 0x81) // sta (zp,x) + // Check 2-byte opcodes + if (opcodeMinus2 == 0x81) // sta (zp,x) { zpOpcodeCycles = 6; zpOpcode = opcodeMinus2; - isZP = true; + indx = true; } else if (opcodeMinus2 == 0x91) // sta (zp),y { // Eg. FT demos: OMT, PLS zpOpcodeCycles = 6; zpOpcode = opcodeMinus2; - isZP = true; + indy = true; } else if (opcodeMinus2 == 0x92 && GetMainCpu() == CPU_65C02) // sta (zp) : 65C02-only { zpOpcodeCycles = 5; zpOpcode = opcodeMinus2; - isZP = true; } - if (!isAbs16 && !isZP) // Unsupported opcode + // Check 3-byte opcodes + if ((opcodeMinus3 == 0x8C) || // sty abs16 + (opcodeMinus3 == 0x8D) || // sta abs16 + (opcodeMinus3 == 0x8E)) // stx abs16 + { // Eg. FT demos: CHIP, MADEF, MAD2 + opcodeCycles = 4; + opcode = opcodeMinus3; + } + else if (opcodeMinus3 == 0x99) // sta abs16,y + { + opcodeCycles = 5; + opcode = opcodeMinus3; + abs16y = true; + } + else if (opcodeMinus3 == 0x9D) // sta abs16,x + { // Eg. Paleotronic microTracker demo + opcodeCycles = 5; + opcode = opcodeMinus3; + abs16x = true; + } + else if (opcodeMinus3 == 0x9C && GetMainCpu() == CPU_65C02) // stz abs16 : 65C02-only + { + opcodeCycles = 4; + opcode = opcodeMinus3; + } + else if (opcodeMinus3 == 0x9E && GetMainCpu() == CPU_65C02) // stz abs16,x : 65C02-only + { + opcodeCycles = 5; + opcode = opcodeMinus3; + abs16x = true; + } + + // + + if (!opcode && !zpOpcode) // Unsupported opcode { _ASSERT(0); return 0; } - // + return GetOpcodeCycles(reg, zpOpcodeCycles, opcodeCycles, zpOpcode, opcode, abs16x, abs16y, indx, indy); +} +UINT SY6522::GetOpcodeCycles(BYTE reg, UINT zpOpcodeCycles, UINT opcodeCycles, + BYTE zpOpcode, BYTE opcode, + bool abs16x, bool abs16y, bool indx, bool indy) +{ WORD zpAddr16 = 0, addr16 = 0; - if (isZP) + if (zpOpcode) { BYTE zp = mem[(::regs.pc - 1) & 0xffff]; - if (zpOpcode == 0x81) zp += ::regs.x; + if (indx) zp += ::regs.x; zpAddr16 = (mem[zp] | (mem[(zp + 1) & 0xff] << 8)); - if (zpOpcode == 0x91) zpAddr16 += ::regs.y; + if (indy) zpAddr16 += ::regs.y; } - if (isAbs16) + if (opcode) { addr16 = mem[(::regs.pc - 2) & 0xffff] | (mem[(::regs.pc - 1) & 0xffff] << 8); - if (opcode == 0x99) addr16 += ::regs.y; - if (opcode == 0x9D || opcode == 0x9E) addr16 += ::regs.x; + if (abs16y) addr16 += ::regs.y; + if (abs16x) addr16 += ::regs.x; } // Check we've reverse looked-up the 6502 opcode correctly @@ -601,10 +601,7 @@ UINT SY6522::GetOpcodeCyclesForWrite(BYTE reg) return 0; } - if (isZpAddrValid && !isAbs16AddrValid) - opcodeCycles = zpOpcodeCycles; - - return opcodeCycles; + return isZpAddrValid ? zpOpcodeCycles : opcodeCycles; } //============================================================================= diff --git a/source/6522.h b/source/6522.h index 529a037b..b0091182 100644 --- a/source/6522.h +++ b/source/6522.h @@ -97,6 +97,7 @@ private: UINT GetOpcodeCyclesForRead(BYTE reg); UINT GetOpcodeCyclesForWrite(BYTE reg); + UINT GetOpcodeCycles(BYTE reg, UINT zpOpcodeCycles, UINT opcodeCycles, BYTE zpOpcode, BYTE opcode, bool abs16x, bool abs16y, bool indx, bool indy); void StartTimer2(void); void StartTimer1_LoadStateV1(void);