Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect timing / CPU cycle emulation for page-crossing opcodes #149

Open
ThorstenBr opened this issue Sep 27, 2020 · 1 comment
Open

Comments

@ThorstenBr
Copy link
Contributor

The 6502 opcodes need an extra cycle when the referenced address crosses a page, e.g.

// with X=0
LDA $FFFC,X

needs 4 cycles, but

// with X=4
LDA $FFFC,X

needs 5 cycles.

The handling of extra cycles is implemented in CPU.cpp, however it's currently not working, since the execution order is incorrect.

The extra cycle handling is implemented in the CHECK_PAGE_CHANGE macro:

#define CHECK_PAGE_CHANGE  if (bSlowerOnPagecross) {          \
             if ((base ^ addr) & 0xFF00)    \
           uExtraCycles=1;        \
         }

This macro is called by the "ABSX", "ABSY", "INDY" macros:
#define ABSX base = *(LPWORD)(mem+regs.pc); addr = base+(WORD)regs.x; regs.pc += 2; CHECK_PAGE_CHANGE;

So, the 'extra cycle' effect is only considered when bSlowerOnPagecross==1. This flag is to be set by the respective opcode. And it is indeed correctly set for LDA:

#define LDA   bSlowerOnPagecross = 1;                \
     regs.a = READ;                \
     SETNZ(regs.a)

However, the LDA macro is only called after the ABSX macro - so ABSX will never add any extra cycles, since the bSlowerOnPagecross flag is set too late:

      case 0xBD:
      ABSX
        LDA
        CYC(4)
        break;

It is the same for all other opcodes. As a result the execution timing is incorrect.

I compared with the original AppleWin sources. AppleWin is correctly emulating the extra cycle for page crossing operations. The whole "bSlowerOnPagecross" logic is absent in the original AppleWin sources. Indeed, it seems removing the bSlowerOnPagecross from CPU.cpp altogether results in proper timing. No idea why the bSlowerOnPagecross was introduced in the first place: it seems the CHECK_PAGE_CHANGE is called for those opcodes anyway, which are indeed affected by the extra page crossing cycle effect in the first place.

@webspacecreations
Copy link

@ThorstenBr is a temporary fix to comment out / remove the if (bSlowerOnPagecross) condition on line 194 (leaving the if ((base ^ addr) & 0xFF00) condition)?

I gather you are officially recommending the removal of all bSlowerOnPagecross = 0|1 statements, but do see that AppleWin sources are using the uExtraCycles flag also in use by LinApple.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants