SingleStepTests / ProcessorTests

A language-agnostic JSON-encoded instruction-by-instruction test suite for the 8088, 68000, 65816, 65[c]02 and SPC700 that includes bus activity.
188 stars 13 forks source link

6502: JSR Overwriting Instruction #65

Closed pjsoberoi closed 1 year ago

pjsoberoi commented 1 year ago

Thank you for this test suite! I've already found numerous issues in Ghidra (https://github.com/oberoisecurity/ghidra-6502-fixes). I'm trying to debug an issue with /6502/v1/20.json instruction 4044. All other unit tests in 20.json pass.

{ "name": "20 55 13", "initial": { "pc": 379, "s": 125, "a": 158, "x": 137, "y": 52, "p": 230, "ram": [ [379, 32], [380, 85], [381, 19], [341, 173]]}, "final": { "pc": 341, "s": 123, "a": 158, "x": 137, "y": 52, "p": 230, "ram": [ [341, 173], [379, 32], [380, 125], [381, 1]]},
"cycles": [ [379, 32, "read"], [380, 85, "read"], [381, 19, "read"], [381, 1, "write"], [380, 125, "write"], [381, 1, "read"]] },`

From the looks of the unit test we are overwriting the instruction as we are executing it. I'm stumped as to what the correct behavior is here. The unit test says PC should be 341 but Ghidra is claiming 4949. How were your unit tests generated? On real hardware? Are you sure this is the correct behavior?

TomHarte commented 1 year ago

This one has been tested on real hardware, which was found to conform to its documentation — which annoyingly I can't immediately find the primary source for, but which is retained in e.g. https://www.nesdev.org/6502_cpu.txt :

   JSR

        #  address R/W description
       --- ------- --- -------------------------------------------------
        1    PC     R  fetch opcode, increment PC
        2    PC     R  fetch low address byte, increment PC
        3  $0100,S  R  internal operation (predecrement S?)
        4  $0100,S  W  push PCH on stack, decrement S
        5  $0100,S  W  push PCL on stack, decrement S
        6    PC     R  copy low address byte to PCL, fetch high address
                       byte to PCH

So I don't know what Ghidra thinks is going on but the sequence of events in that test is:

  1. read opcode and low byte of destination address;
  2. push current program counter to the stack, which modifies the instruction in-flight;
  3. read high byte of destination address, which is now what was just written to the stack.

I feel like the original WDC specification of the above was in an application note rather than the original data sheet, so I'll keep looking and update if I can find the primary source.

pjsoberoi commented 1 year ago

Thanks, you answered my question. I appreciate it.

TomHarte commented 1 year ago

Such as it helps; I found a contemporary primary source: the Synertek hardware manual on page A-10 (page 174 of the PDF) which indicates the same thing — that 'Fetch high order byte of Subroutine Address' occurs after both of the stack pushes.