I am building a W65C02S based computer for fun, and I try to build basically all the tools myself. Including the assembler (yes, I know they exist, I just want to make everything from scratch myself, for fun).

When working on the JSR opcode (absolute addressing mode), I find that before it puts the program counter on the stack, it reads one byte off the stack first (program counter is set to 80 2e at this point, the stack pointer is 01b6):

READ  address:   80 2e   data:   20   JSR   ; Read the opcode
READ  address:   80 2f   data:   14   14    ; Read the LO byte of operand
READ  address:   01 b6   data:   74   't'   ; Read the stack (why?!)
WRITE address:   01 b6   data:   80   ---   ; Write HI byte of PC
WRITE address:   01 b5   data:   30   '0'   ; Write LO byte of PC
READ  address:   80 30   data:   80   80    ; Read HI byte of operand
READ  address:   80 14   data:   8d   STA   ; Read opcode at `80 14` (the JSR operand)

It works OK, but what it the reason it reads from the stack first?

(To explain the table: this is from my own tool. I am using an Arduino to look at the data and address buses to see what is happening there. It is a hardware CPU running only my own code.)

  • Maybe it is because your tracker is reading the data and address bus to detect and save any change. By this way it may read data during the transition of the control bus (R/W for instance).since your tracker board is faster than 6502 try to add timestamps or save also the control bus status. Commented Feb 13, 2021 at 20:57
  • @PaulGhobril the tracker reads on every clock pulse. And this happens only at this point in the code. Commented Feb 13, 2021 at 21:11
  • 2
    The WDC instruction timing chart confirms your observation and labels it an internal operation (and mentions the original 6502 is in a different order). Since it has to read or write something every cycle, the easiest option would be PC+1 again, or S. Commented Feb 13, 2021 at 21:12
  • but are you going to build the tools to build the assembler yourself too? if not that's cheating. Commented Feb 13, 2021 at 22:09
  • @BartFriederichs Erm ... please not another half ass assembler. If you have to do, either be super minimalistic and stay with the original cross assembler syntax (might be implemented in less than a KiB of code) of go for a full fledged real one (read ASSEMBF), worthwhile the time spent.
    – Raffzahn
    Commented Feb 13, 2021 at 22:13

1 Answer 1


[This question is kind of duplicate to


It's one of the 'dead' or internal cycles of a 6500. On a WDC65C02 they are externally all turned into 'harmless' read cycles.


Unlike other CPUs the 6500 series has not pure internal cycles without memory access, but each and every cycle will as well be a memory cycle. Whenever internal operation can not overlap with with a needed memory cycle, a dummy access is inserted. Usually with the last address used.

  • On NMOS it depends on what the next (intended) cycle would be, read or write.

  • On CMOS this was changed that the internal cycle would always be a read.

This behaviour will be as well seen on RMW instructions and all inserted carry processing cycles on page crossings.

The Finer Details

The detailed working are described on page 107 of the 1976 MCS6500 Microcomputer Family Programming Manual:

enter image description here

Notable here is that cycle 3 stores the just read ADL, the low byte of the target address, which then gets overwritten in cycle 4 by PCL. This is of course like the NMOS version works.

As mentioned, when the CMOS version was designed one goal was to remove all unintended write operations (*1). In this case the third cycle writing ADL was replaced by a dummy read.

P.S.: If you're starting from scratch, it might be a good start to first read both 1976 manuals end to end :)

*1 - While it doesn't really matter when looking at RAM, unintended writes may screw the workings of I/O ports. The 6500 being mainly meant as an embedded CPU family this counts an important improvement.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .