18

Most emulators store the number of cycles a particular instruction takes in an array, and then adds any conditional cycles if needed (when crossing page boundaries, for example).

I'm wondering if there is a way to procedurally determine the number of cycles an instruction will take based solely on addressing mode and memory reads/writes.

To give an example, I've noticed that all instructions that use immediate or relative addressing take 2 cycles.

All zero-page instructions take 3 cycles, plus an additional 2 cycles if altering memory in-place.

All indexed zero-page instructions take 4 cycles, plus an additional 2 cycles if altering memory in-place.

...And so on.

So, is there some fully documented, procedural way of determining the number of cycles for an instruction like the above? Are there exceptions that would break determinism in such a formula?

  • 2
    If you want to really know why each instruction takes as many cycles as they do, you could read up on how the 6502 processor actually works. For a start you could read this article and look at this table of the ROM. tl;dr The processor itself also has a table that determines which operations each instruction causes to happen, and therefore also the cycle count. – Matti Virkkunen Dec 21 '16 at 12:08
19

To a certain extent you can guess the number of cycles by counting the number of memory accesses.

A 2-byte instruction will take a minimum of 2 cycles because you need to read 2 bytes. If the instruction needs to read or write a data byte add another cycle. For example, a zero-page read is a 2-byte instruction, but in addition to reading the instruction bytes you also need to read 1 byte from zero page, totaling 3.

Crossing a page boundary requires an extra cycle because the high byte of the address needs to be incremented due to the carry from the lower byte (it's actually the carry that causes the extra cycle).

A read-modify-write instruction requires 3 extra cycles (1 cycle to read, 1 cycle to modify the data, and 1 cycle to write the new value to memory).

Some instructions are hard to guess at this way because some cycles are used for operations internal to the CPU (e.g. the extra cycle for crossing a page boundary). And you have to have a pretty good idea of how the CPU works internally; specifically which operations can be done in parallel and which must be done in sequence. If an instruction takes one cycle more than you think it should, chances are good that there was an internal operation that couldn't be done in parallel in 1 cycle, and had to be done in 2 cycles. If an instruction takes fewer cycles than you thought, chances are good it was able to do 2 steps in parallel.

In the end, because there will be exceptions due to mysterious/unknown CPU design choices, it is usually simpler to just look up the total delay in a table.

3

You are correct that instructions of the same form follow the same pattern. Alas, I forget my original documentation sources now (perhaps this?), but these days I tend to use my emulator code as a reference. :-/ For instance, not counting the initial instruction opcode fetch (which is identical for all instructions), 2-byte-long 4-cycle zp,Y instructions always go like this. You can see the ldx variant referencing that code here.

All instructions read or write at every cycle, and sometimes the intermediate reads are at strange addresses: for instance, STA ADDR,X instructions will read from ADDR+X, but without the carry applied to the high byte, before getting the final address correct for the write.

If you really want to be sure you got your reads and writes correct, my suggestion is that you run Klaus Dorman's excellent test suite, and compare every cycle's reads and writes with the transistor-level simulation of the 6502: there are versions in (at least) Javascript, C, and Go. You can see my test that does that here. After that, you can be reasonably sure that you got most of the details right. :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.