Page crossings during indexing were the cause of some rare but nasty headaches on the NMOS '02, so it may seem counterintuitive that floobydust's indexing problem was
solved by invoking a page crossing.
The explanation involves fixes that were applied when the 'C02 was designed.
The 'C02 fix for page crossings during indexing successfully achieved a certain defined goal. But the designers missed the opportunity to fix a related and more obscure issue.
At issue are address modes such as abs,X abs,Y and (ind),Y which take a 16-bit base address and add to it an 8-bit index. The 16-bit result is available immediately if the lowbyte addition generates no carry. Otherwise an extra cycle is required, and what's immediately available is only a partially formed address -- one whose lowbyte is correct but whose highbyte needs to be incremented. Sometimes mysteriously referred to as an "invalid address," a partially formed address is actually entirely predictable. It's simply the intended address minus $100. And the cycle in which it appears is like a wait state, a delay inserted before the final cycle.
Unfortunately, an NMOS '02 will put the PFA on the address bus during the wait state. That means your program can, when indexing, inadvertently touch whatever is $100 below the intended address. If there's an I/O device there its internal status may be altered -- hence the nasty headaches! As bugs go, this one is especially bad because the cause and effect are entirely unrelated. (You could waste a lot of time believing the bug was in the I/O routine.
)
AFAICT the 'C02 never places a PFA on the address bus. Instead (as loosely described in the doc) there's some sort of mechanism that places the Program Counter on the bus during any cycle which, on an NMOS '02, would have a PFA. IOW the fix can be said to achieve a goal of no PFA's. Instead the 'C02 harmlessly does a spurious read of the last instruction byte.
What apparently got overlooked is the case of an indexed STA. With STA -- a write operation -- the wait state aka extra cycle is no longer conditional. It's always included (and is always a read), whether or not the lowbyte addition produces a carry. This makes possible something which otherwise never happens
(except as noted in the ps) : an extra indexing cycle during which the complete address is already present.
Ideally that same mechanism would kick in and place the Program Counter on the bus. But that's where the 'C02 fix falls short. The mechanism only kicks in if there's a carry. With no carry, the complete address is allowed to appear on the bus, resulting in a spurious read from the same address which will be written in the following cycle.
Who knows; maybe the designers said, "Heck, it's not a PFA, so we don't need to do anything about it." Or maybe there's a solid reason they weren't able to take action. But, as floobydust discovered, a spurious read can cause trouble even when it doesn't involve a PFA / "invalid" address. And coaxing the mechanism to kick in is a viable workaround.
-- Jeff
ps: discussed
here is another incomplete 'C02 fix, first brought to our attention by dclxvi. Again there may be an extra indexing cycle during which the complete address is already present, and again the mechanism's response depends on the presence or absence of a carry:
Quote:
Without a page crossing the extra cycle appears anyway, and the address is the same as that during the following cycle when the RMW actually commences. [...] With a page crossing there will be an extra cycle, during which PC appears on the address bus