Quote:
The stream of one-cycle NOPs is uninterruptible! It behaves just as if it was a one big multibyte instruction!
Did anyone spotted this behavior before?
Yes, and I should update my
post which you quoted. (Oh, and I see Ed, too, searched and found it -- thanks, Ed!)
Quote:
Do anyone have any idea why it is so? Is one cycle too little for interrupt machinery to kick in?
I have a theory that to me seems satisfactory. It's maybe best to start by looking at another question. Back when the CMOS '02 (ie, 65
C02) was being developed, one of the goals was to render all undefined opcodes into NOP's.
Why that was a goal is a question in itself.
It's certainly true that, for NMOS '02, users had figured out what the undefined aka illegal opcodes did and then, despite the weirdness of those ops' behavior, proceeded to use them in programs. Evidently WDC (developer of the new, CMOS CPU) perceived this as undesirable, probably because there was a threat that the wonky, NMOS undefined op's could become a de facto standard -- and such a standard would prevent the undefined opcodes from being more gainfully deployed in future as new, approved (and non-wonky!) instructions. The 'C02 did introduce some new instructions, but not enough to fill the entire opcode map. And somebody in management apparently decided the remaining undefined opcodes must be turned into NOP's in order that they would have zero appeal for hacking. (They failed to completely eliminate the appeal. I and others hacked the new, so-called NOP's anyway. But that's another story!
)
With management's decision made, it then became someone's job to alter the new CPU's logic in a way that rendered all undefined opcodes as NOP's. And that someone said, "I'm lazy. What's the easiest way to approach this?" (Of course I'm theorizing now.)
One easy thing is to detect opcodes in the $_3 and $_B columns of the map. Late in the cycle during which an opcode is fetched (ie, SYNC is high), the value fetched is examined and a determination is made during the few remaining nanoseconds. If the opcode fetched is from column $_3 or $_B then
the added logic evidently says, "OK, what we have to do in the next cycle is fetch a new opcode!"... even though the present cycle has already fetched a new opcode. To be clear, this is different than other instructions. Even the official NOP ($EA) needs to enter the pipeline and get executed, and the pipeline requires two cycles minimum. But opcodes in the $_3 and $_B columns seemingly do not enter the pipeline. They just generate a hiccup which causes the chip to forget that an opcode has already been fetched. It's a clever solution, given that it requires minimal logic and yet it fixes all 32 of the undefined opcodes in columns $_3 and $_B. (The first C02's didn't have STP and WAI.) I'm guessing that the remaining undefined opcodes (those
not in columns $_3 and $_B) were quite a lot more trouble to neuter. But those in columns $_3 and $_B were low-hanging fruit.
One side effect of the induced hiccup is that an interrupt sequence can't commence. This means, as you say, laoo, that the $_3/$_B instruction(s)
and the normal instruction which follows become "atomic" -- a single, uninterruptable entity. I confirmed this by experiment, as did you.
For me it's good news, because I have a history of
using hardware to hack undefined opcodes, and one very powerful tactic is to use a $_3/$_B opcode as a prefix to alter the following instruction. But things get complicated if an interrupt causes the prefix to become separated from the op it's intended to affect! I'm pleased that that threat is eliminated by the induced hiccup I just described.
For your purposes, laoo, perhaps this
very simple Clock Stretching circuit would offer a solution.
-- Jeff
eta: my bad, the first 'C02 cpus had 64 single-cycle NOP's, not 32. Opcodes in columns $_3, $_7, $_B and $_F all were single-cycle NOP's. I tend to overlook this as my first 'C02 was a Rockwell device which, like later WDC C02's, has bit-oriented instructions in columns $_7 and $_F.