Parts of the 6502 opcode map are fairly regular, and parts of it aren't. One bit that strikes me as really weird is the decoding of LD_ instructions, in relation to the decoding of other ALU instructions.
Well, for one, LDX
/LDY
do not use the ALU, but more importantly, the way you decode it is a bit off. See below for a more detailed view on the 6500 encoding.
The LDX
/LDY
immediate encoding is fine. The quirk within the transfer instructions is at TYA
which is 98
instead of 88
. And there is no technical reson why it has been done that way. There are similar other encodings, especially around the increment/decrement for the index registers.
6500 Opcode encoding
The format isn't built the way you assume. While the general structure follows a 3-3-2 stucture like
aaa-bbb-tt
reading it requires to start at the end with
tt defining an instruction group
This is even visible the way the decoder hardware is done, as tt is not taken as seperate bits like all others, but turned into 3 lines for the three groups used, thus being the primary differentiation for all decoding.
(To simplify this, lets push group 0 (tt=00
) to the end.)
Group 1 (tt=01
) is the most simple. Here aaa
selects one of 8 instructions (ORA
, AND
, EOR
, ADC
, STA
, LDA
, CMP
, SBC
) and bbb
defines an addressing mode ((ZP,X)
, ZP
, IMM
, ABS
, (ZP),Y
, ZP,X
, ABS,Y
, ABS,X
). Drawing this up(*1) will give a filled table with one empty spot at 89
, where the nonsensical STA IMM
would end up (*2).
Group 2 (tt=10
) uses a similar encoding with aaa
as instruction and bbb
as addressing, just with different opcodes (ASL
, ROL
, LSR
, ROR
, STX
, LDX
, DEC
, INC
) and some addressing rearranged (IMM
replacing (ZP,X)
and ACC
IMM
) or not used (IMM
, ZP
, ACC
, ABS
, na, ZP,X
/ZP,Y
, na, ABS,X
/ABS,Y
). Here the STX A
and LDX A
are occupied exactly by TXA
and TAX
. Similarly, the 'unused' addressing 110
is used with STX
/LDX
to form TXS
and TSX
.
Group 2 is also the point where they started to screw it up, as 9E
, where STX ABS,Y
should be, is left out. And while the logical position for DEC A
is filled by DEX
, and NOP
resides where a INC A
could be (*3).
Group 3 (tt=11
) is the most simple of all, as it doesn't exist :))
Group 0 (tt=00
) finally is where it gets crowded. At first it's much like group 2. The instructions are now (na, BIT
, na, na, STY
, LDY
, CPY
, CPX
) while the general addressing modes are the same as with group 2 plus REL
and FLAG
(IMM
, ZP
, ACC
, ABS
, REL
, ZP,X
, FLAG
, ABS,X
).
So far everything is regular, group 0 holds the remaining instructions as well, sprinkled in in a less than regular way:
Addressing REL
now overwrites (in a table for group 0) the instruction with BRx
and FLAG
with flag manipulation - with the exception, that CLV
ended up where SEV
would be if it existed - and TYA
taking up its space.
Similarly, the stack operations lie diagonally to the encoding - and again TAY
is screwing up the somewhat regular placement of increment/decrement for the index registers.
JMP
does follow the scheme in so far as the 01x.011.00
encoding used the ABS
addressing.
The remaining instructions (BRK
, JSR
, RTI
, RTS
) fall completely out of context. But they show at least some inherent logic, especially when considering that BRK
is internally fed into the decoder also whenever a hardware interrupt occurs.
*1 - Drawing tables on SE sucks - so please use your imagination.
*2 - A hole filled up by the 65C02 with BIT IMM
, since the 'rightful' spot 20
was taken by the irregular JSR
.
*3 - as a result the 65C02 had to put INC A
/DEC A
onto new places.