I was looking at some of the unofficial opcodes when I ran across some nice examples of how these are a result of "don't care" states in the 6502 opcode decoder (aka the PLA). This has been examined elsewhere at some depth (e.g.
http://visual6502.org/wiki/index.php?title=6507_Decode_ROM) but a more basic look was helpful to me so I though I would share this. The unofficial LAX is a nice example. On the 6502,
$A4 is LDY <zpg>,
$A5 is LDA <zpg>, and
$A6 is LDX <zpg>,
which indicates the lower two bits of the opcode determine the target register for the load operation, as follows:
00 = Y
01 = A
10 = X
11 = *don't care*
to implement this with some gates, we might write it in boolean terms as:
Y = /OP1 & /OP0
A = OP0
X = OP1
That of course leaves the "11" combination as a "don't care" which, according to the boolean expressions above, triggers a write to both A and X. So we get $A7 = LAX <zpg> (lower two bits = 11 = A and X) which loads both A and X from memory.
There is a nice parallel also in SLO <zpg>. Here, opcode $05 is ORA <zpg>, $06 is ASL <zpg> and $07 is a combination of the two - the unofficial SLO <zpg>, which both shifts memory left and ORs the result with the accumulator. Here is the microcode I use for for ASL:
$05: ASL <zpg>Code:
DPL := *PC; PC += 1
B := *zDP
T := 0 ASL B; SETF(NZC)
*zDP := T
IR := *PC; PC += 1; END
And this is what ORA <zpg> looks like:
$06: ORA <zpg>Code:
DPL := *PC; PC += 1
B := *zDP
A := A OR B; SETF(NZ); IR := *PC; PC += 1; END
Rather neatly, the microcode for SLO performs the ASL and then, on the last step, includes the OR operation from the last line of the ORA sequence, as follows:
$07: SLO <zpg>Code:
DPL := *PC; PC += 1
B := *zDP
T := 0 ASL B; SETF(NZC)
*zDP := T
A := A OR B; SETF(NZ); IR := *PC; PC += 1; END
Once again, the lower two bits of the opcode tell the tale. Looking at the "aaabbbcc" format for the opcode (
http://www.llx.com/~nparker/a2/opcodes.html), ORA belongs to the cc = 01 ALU only opcodes while ASL to RMW ones where cc = 10. In each case, the "aaa" parameter selects the operation. So aaa = 000 refers to ORA if cc = 01 or to ASL if cc = 10. The $07 SLO opcode where cc = 11 triggers both, albeit each at a different cycle of the instruction sequence.
Incidentally, the microcode above for SLO would not work for me because of a change I made earlier to accommodate TSB and TRB in the 65C02 microcode - namely, inhibiting the B data latch on write-cycles. The TSB/TRB microcode needed that to allow the
unmodified value of B, which is latched in cycle 3 below, to survive the store operation in cycle 4:
Code:
1: DPL := *PC; PC += 1
2: B := *zDP
3: B := *zDP; T := A OR B
4: *zDP := T
5: A AND B; SETF(Z); IR := *PC; PC += 1; END
Meanwhile, SLO in the NMOS 6502 microcode requires exactly the opposite. Latching B on the write cycle in this case supplies the
modified value after the ASL operation to the subsequent OR, which is correct.
So, it seems a further change may be necessary to allow both requirements to co-exist, by for example, inhibiting the B data latch on write-operations but only for TRB/TSB opcodes. I can do that simply by latching B on write cycles only when bit 0 of the opcode OP0 = 1 (since TSB and TRB have OP0 = 0 and SLO opcodes have OP0 = 1). Alternatvely, I can use the microcode-select-bits to inhibit the B latch only for the 65C02 microcode. That's probably cleaner, but I should have a closer look at the other unofficial opcodes before going any further. I know some can be done with only microcode changes, but others look a little nasty. We'll see.
Cheers,
Drass.