The 6502 and 65C02 have one eight bit accumulator. The 65C816 has three.
What, you say? It's true...sort of. The 65C816 can have two 8 bit accumulators and a 16 bit accumulator—three accumulators
en toto!
Like the 65C02, the 65C816 has an A-accumulator, which I will refer to as
.A to avoid having to type a lot. The '816 also has a B-accumulator, aka
.B, a design feature that Bill Mensch, Jr. evidently borrowed from the Motorola 6800. Both accumulators are 8 bits wide, just like the lone accumulator in the 65C02. How these accumulators appear to the rest of the system depends on the state of the status register's
m bit.
When
m is
1, which is the default state after power-on or reset, an instruction such as
LDA $1234 will load an 8 bit value from
$1234 into
.A, just like the 65C02—the load will have no effect on
.B. Setting
m to
0 will cause the 65C816 to gang
.B to
.A, creating a new 16-bit wide accumulator that is referred to as
.C. In this case,
LDA $1234 will cause the byte at
$1234—the least significant byte or LSB—to be loaded into
.A and the byte at
$1235—the most significant byte or MSB—to be loaded into
.B, resulting in a 16 bit load. An extra clock cycle is used to load the MSB, which is characteristic of all 16 bit loads and stores.
Similarly, when the accumulator is set to 16 bits, instructions that act directly on it, such as
ASL or
DEC, act on all 16 bits. For example, consider the following:
Code:
rep #%00100000 ;16 bit accumulator & memory
lda #%0000000010000000 ;$0080
asl a ;left shift a bit
sta $1234 ;save result
When the above is executed the value
$00 will be stored at
$1234 and
$01 will be stored at
$1235, as the
ASL A instruction shifted all 16 bits.
Also, consider the following:
Code:
rep #%00100000 ;16 bit accumulator & memory
lda #$0000 ;16 bit load
dec a ;decrement accumulator
When the above is executed
.C will contain
$FFFF.
You may well be wondering what happens if the
m bit is changed to
1 after a 16 bit load. The accumulator reverts to being an 8 bit register, now referred to as
.A, but
.B is not affected and retains whatever was in the MSB of the value in
.C. For example:
Code:
rep #%00100000 ;16 bit accumulator & memory
lda #$BBAA ;load .C with $BBAA
sep #%00100000 ;8 bit accumulator & memory
When the above is executed,
.A will contain
$AA and despite the accumulator having been changed to 8 bits,
.B will contain
$BB. Hence your program can perform 16 bit loads, but act on the data 8 bits at a time, as is often required during I/O operations.
Even though
.B is "hidden" when
m is
1, it is still accessible by using the
XBA (e
Xchange
B with
A) instruction. Viewed logically,
XBA makes an internal copy of
.B, writes
.A into
.B and then writes the internal copy of
.B into
.A. As with all other instructions that load the accumulator,
XBA will affect the
N and
Z bits in the status register. Hence the value that was in
.B when
XBA is executed is what will set or clear
N and
Z.
XBA can be used whether the accumulator is 8 or 16 bits wide. In the latter case,
XBA can be used to reverse the endianess of a word stored in memory, e.g.:
Code:
rep #%00100000 ;16 bit accumulator & memory
lda #$1234 ;random 16 bit number
sta $5678 ;store it
...do other stuff
lda $5678 ;load $1234 into .C
xba ;swap bytes &...
sta $5678 ;save
When the above is executed,
$5678 will contain
$12 and
$5679 will contain
$34.
This 16 bit business also applies to read-modify-write (R-M-W) instructions, such as
INC $1234, or
ROL $89AB, when the
m bit is
0. For example, consider this contrived code:
Code:
rep #%00100000 ;16 bit accumulator & memory
lda #$7fff
sta $1234
inc $1234
When the above is executed,
$1234 will contain
$00 and
$1235 will contain
$80, since the
INCrement instruction acted on a word, not a byte. Needless to say, be careful if you use a R-M-W instruction on a chip register, as you may inadvertently change an adjacent register if
m is
0.
Similarly, using
BIT on memory when
m is
0 causes bits 14 and 15 to correspond to the
V and
N status register bits, respectively, not bits 6 and 7, as would be the case when
m is
1. Also,
BIT immediate takes a 16 bit operand, e.g.,
BIT #%0011000000000000.
There are a few instructions that will ignore the
m bit and generate a 16 bit transfer in all cases. They are:
- TCD: copies .C to DP (the 16 bit direct page register).
- TCS: copies to .C to SP (the 16 bit stack pointer).
- TDC: copies DP to .C.
- TSC: copies SP to .C.
TDC and
TSC can be sneaky, as they will overwrite
.B even though
m is
1.
Needless to say, you can easily introduce a bug if you forget about this behavior.