assemblyemulation6502

Best approach to emulating 6502 clock cycles?


I've been working on the CPU for an NES emulator, and I was wondering about what is the best way to manage cycles for multi-cycle instructions.
(Assuming the time delay of a cycle is implemented) I could increment the cycles individually per each step of the instruction, like so:

void EXAMPLE_INSTRUCTION(){
step1();
cycles++;

step2();
cycles++;

step3();
cycles++;
}

Or take the 3 cycles all at once when the instruction finishes, like this:

void EXAMPLE_INSTRUCTION(){
step1();
step2();
step3();

cycles+=3;

Trying to track down which parts of an instruction take a cycle and counting on my hands is getting annoying, and I was wondering if there are any downsides to removing my current implementation of clock cycles in favor of just taking all of the cycles at once before the instruction finishes.


Solution

  • The answer is that it depends.


    If your emulator is not cycle accurate, you can add all the cycles on at once at the end. In fact, you can have a lookup table of the cycle count for each instruction so you don't have to add increment cycles in every single instruction implementation.

    There is a caveat to that approach which is that you need to be aware that not all instructions have constant cycle counts. For example all the branch instructions take:

    So BNE could take 2, 3 or 4 cycles. The approach I took was to keep the base count in a lookup table and add extra cycles in the instruction implementations as required.


    If you want a cycle accurate emulation, you will have to use your first approach because accesses to the data bus should probably occur with an accurate cycle count.

    For example, reading and/or writing to IO registers can trigger external events. Normally you'd expect the read or write to be the last thing that happens during instruction execution but you might want to accurately simulate weird things like incrementing a memory location that happens to be an IO register or accidentally jumping to a location that is an IO register.