8

I'm looking at gianlucag/mos6502 and Mike Chambers' fake6502. They have observable differences in the way that they read the reset vector.

Rubbermallet reads the $fffc first, and then $fffd. I'm inclined to think that's what the real deal does too. But the gianlucag emulator seems to read the vector in the opposite order. Do we know what the truth is here? Is there variation in what the real hardware does?

1
  • It's looking as though the bug boils down to a line of code which a compiler is free to do in any order it likes. Commented Sep 20, 2022 at 13:29

2 Answers 2

15

Synertek 6502 datasheet diagrams show a read on $FFFC first and $FFFD last.

MOS datasheets talk about fetching all the vectors in the lower address first, then higher address after.

The MCS6500 Microcomputer Family Programming Manual lists the bus cycles as reading $FFFC on 6th cycle and $FFFD on 7th cycle.

4
  • 2
    No doubt about it that a "real" MOS/Synertek/Rockwell 6502 reads any of the NMI, IRQ, or RESET vectors low-byte first. It has to do with the PC register that has an increment function but not a decrement. Since the 6502 is little-endian it makes no sense to add the decrementer hardware just to read the vectors high-byte first.
    – jwh20
    Commented Sep 19, 2022 at 16:39
  • 1
    Having circuitry to "jam" an address bit high or low would not require the use of an ALU or incrementer. Indeed, if the 6502 had omitted the bottom bit of SP and required that all push and pop instructions operate on a pair of bytes, with the lower address being ODD, operations to push and pop a register could both be accommodated without wasted steps (if the stack pointer is set for address 1100 000x, a push could store to 11000000 while the ALU computes address 1011 111x, and then store to 1011 1111, while a pop could load 11000001 while the ALU computes 1100 001x, and then load 11000010.
    – supercat
    Commented Sep 19, 2022 at 16:58
  • 1
    According to analysis made on Visual 6502, it does not even seem to be PC that is used to load PC, so the PC incrementer may not be relevant. The first load would invalidate PC. The FFFC and FFFD sequence is confirmed from multiple sources about the internal operation.
    – Justme
    Commented Sep 19, 2022 at 18:09
  • @Justme It isn't needed at all, as the vector addresses are set via precharge and pulling of all lines that need to be zero.
    – Raffzahn
    Commented Sep 19, 2022 at 19:58
9

Do we know what the truth is here?

Yes, it's always low first.

While not having a manual page of it's own, the behaviour is well described in Appendix A Summary of Single Cycle Operation of the MCS6500 Family Hardware Manual. Section A.5.4 Break Operation -- (Hardware Interrupt) - BRK (Page A-11) describes the fetch for all vectors step by step:

Manual section

Being set there makes it a fundamental behaviour of all 6500 hardware compatible CPU. It also explicit mentions that this sequence being the same for BRK and all hardware interrupts (*1).

Is there variation in what the real hardware does?

No.

The addressing is entirely handled by applying constant values to the address bus. This is quite visible - as so often - when looking at Hanson's 6502 diagram:

  • ADH(0..7) preset to %1111.1111 (Green)
    • 0/ADH0 and 0/AHD(1-7) inactive (dashed Light Green)
  • ADL(3..7) preset to %1111.1xxx (Dark Blue)
  • ADL(1,2) set to vector, encoded by 0/ADL1 and 0/ADL2 (*2) (Light Blue)
  • ADL(0) set according to sequence (Light Blue)
    • 0/ADL0 active during the first fetch
    • 0/ADL0 inactive during the second fetch

Hanson's 6502 diagram with markings for address generation and vector fetch

(Taken from a cleaned up version on his site)

This also shows that, other than often assumed, the sequence is not mandated due the PC being used for addressing or it needing to be loaded in that sequence. Either vector byte could have been accessed first and loaded independent from the other:

  • Low half from the data bus via IDL and ADL into PCLS (Red)
  • High half from the data bus via IDL and ADH into PCHS (Orange)

*1 - Which is BTW where the manuals explicit hints that any interrupt is a forced just BRK ... with different addresses.

*2 - A part that always puzzled me, as that means the hardware could have supported a 4th vector, allowing to separate between INT and BRK by vector, saving the need to look at the BRK flag when an interrupt occurs.

1
  • 3
    Re footnote 2: that part has also always puzzled me, since having reset be $FFF8, NMI $FFFA, IRQ $FFFC, and BRK be $FFFE would seem easier and better than having to route the logic necessary to push the "B flag" bit.
    – supercat
    Commented Sep 19, 2022 at 20:08

You must log in to answer this question.

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