6

As everyone knows, the 6502 has many many undefined opcodes. One of these is RRA, which essentially performs both ROR and ADC.

From what I understand of hardware (really not much) and the explanation in this document, the example program:

rra $02 

should:

  1. read from the location $02,
  2. write its contents back while it does the shift and addition.
  3. write the rotated value, while latching the result of the addition into the accumulator

But here's the example run in Visual6502.

0 0000 67 1 0000 aa 00 00 fd nv‑BdIZc 0 0000 67 1 0000 aa 00 00 fd nv‑BdIZc 1 0001 02 1 0001 aa 00 00 fd nv‑BdIZc 1 0001 02 1 0001 aa 00 00 fd nv‑BdIZc 2 0002 20 1 0002 aa 00 00 fd nv‑BdIZc 2 0002 20 1 0002 aa 00 00 fd nv‑BdIZc 3 0002 20 0 0002 aa 00 00 fd nv‑BdIZc 3 0002 20 0 0002 aa 00 00 fd nv‑BdIZc 4 0002 20 0 0002 aa 00 00 fd nv‑BdIzc 4 0002 10 0 0002 aa 00 00 fd nv‑BdIzc 

So my concern is that the accumulator did not change. Trying a few different values shows that the Carry flag changes as though a ROR happened.

I'm inclined to trust the Visual6502 implementation, but on the other hand, all the documents, software, emulators and everything that attest to the behaviour of the RRA opcode can't all be wrong, can they? So the document I linked to up there is quite C64-centric. Have I discovered that the Visual6502 reproduces a variant that is different from the NMOS thing in the C64 and NES?

1
  • 3
    Keep the overlapping nature of fetch and execution in mind. Thus one needs to take the (whole) first cycle of the next instruction as well into account. Commented Apr 12, 2021 at 14:04

2 Answers 2

12

Look further down in the print-out. The A register shows as updated after the first byte fetch of that next instruction.

Starting with the bytes 67 02 20 10, which seem to be what you had:

cycle ab db rw Fetch pc a x y s p 0 0000 67 1 unknown 0000 aa 00 00 fd nv‑BdIZc 0 0000 67 1 unknown 0000 aa 00 00 fd nv‑BdIZc 1 0001 02 1 0001 aa 00 00 fd nv‑BdIZc 1 0001 02 1 0001 aa 00 00 fd nv‑BdIZc 2 0002 20 1 0002 aa 00 00 fd nv‑BdIZc 2 0002 20 1 0002 aa 00 00 fd nv‑BdIZc 3 0002 20 0 0002 aa 00 00 fd nv‑BdIZc 3 0002 20 0 0002 aa 00 00 fd nv‑BdIZc 4 0002 20 0 0002 aa 00 00 fd nv‑BdIzc 4 0002 10 0 0002 aa 00 00 fd nv‑BdIzc 5 0002 10 1 BPL 0002 aa 00 00 fd nv‑BdIzc 5 0002 10 1 BPL 0002 aa 00 00 fd nv‑BdIzc 6 0003 10 1 0003 ba 00 00 fd Nv‑BdIzc 6 0003 10 1 0003 ba 00 00 fd Nv‑BdIzc 

Note that that's also the point where the N flag becomes set, even though the BPL has already started fetching. Since this is an effect from the previous instruction, the branch is not taken.


These results are as seen for separate ROR and ADC, with input 66 04 65 04 20 10 (offsets adjusted to point at the 20):

cycle ab db rw Fetch pc a x y s p 0 0000 66 1 ROR zp 0000 aa 00 00 fd nv‑BdIZc 0 0000 66 1 ROR zp 0000 aa 00 00 fd nv‑BdIZc 1 0001 04 1 0001 aa 00 00 fd nv‑BdIZc 1 0001 04 1 0001 aa 00 00 fd nv‑BdIZc 2 0004 20 1 0002 aa 00 00 fd nv‑BdIZc 2 0004 20 1 0002 aa 00 00 fd nv‑BdIZc 3 0004 20 0 0002 aa 00 00 fd nv‑BdIZc 3 0004 20 0 0002 aa 00 00 fd nv‑BdIZc 4 0004 20 0 0002 aa 00 00 fd nv‑BdIzc 4 0004 10 0 0002 aa 00 00 fd nv‑BdIzc 5 0002 65 1 ADC zp 0002 aa 00 00 fd nv‑BdIzc 5 0002 65 1 ADC zp 0002 aa 00 00 fd nv‑BdIzc 6 0003 04 1 0003 aa 00 00 fd nv‑BdIzc 6 0003 04 1 0003 aa 00 00 fd nv‑BdIzc 7 0004 10 1 0004 aa 00 00 fd nv‑BdIzc 7 0004 10 1 0004 aa 00 00 fd nv‑BdIzc 8 0004 10 1 BPL 0004 aa 00 00 fd nv‑BdIzc 8 0004 10 1 BPL 0004 aa 00 00 fd nv‑BdIzc 9 0005 10 1 0005 ba 00 00 fd Nv‑BdIzc 9 0005 10 1 0005 ba 00 00 fd Nv‑BdIzc 
6

Although it's often convenient to think of each instruction as starting with an opcode fetch, it's more accurate to think of each instruction's execution as starting on the cycle after its opcode is fetched, and extending through the fetch of the following opcode. If one considers an instruction like ADC #12, there's no way the processor can even begin to perform the addition until after it has fetched the operand byte, and there's almost no time between that and the start of the next instruction fetch. Thus, instructions whose last step is to update a register will generally perform that last step during the fetch of the following opcode byte.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.