(It occurs to me that adding notes about the 68HC11 and 6809 in here would be
useful, but I want to leave the simpler
comparison of the 6800 and 6801
as it is. So I'm duplicating that here, and adding notes for the 6809 and 68HC11. However, I am not comparing any of these with the 6805 or its descendants here.)
I've described the differences between the 6800 and the 6801 instruction architectures at length in several other posts. (Many of those posts also take up other CPUs.) This is a high-level overview.
**68HC11: I'll note here that, much as the 6801 is object-code upwards compatible with the 6800, the 68HC11 is object-code upwards compatible with the 6801, but with some timing differences.
**6809: The 6809 is not object-code upwards compatible with either, although
it is, to a great degree, assembler source upwards compatible with both, using
macros. It is not upward source code compatible with the 68HC11, needing
hardware divide instructions and direct bit manipulation instructions. (The
bit instructions generally need more than two 6809 instructions to synthesize,
and the divide instructions just take too long to wink at.)
(But I still ignore the built-in ROM, RAM, and peripheral devices in the 6801 here. Those are important, but require separate treatment.)
**68HC11: (The 68CH11 has built-in RAM, ROM,. and peripherals, like the 6801.
**6809: The 6809 does not, and never came in a publicly available version that
did, that I know of.)
First, where the 6800 had two independent 8-bit accumulators, A and B, the
6801 has, in addition, the ability to combine them as a single 16-bit
accumulator (A:B, or D) for several key instructions, load, store, add, and
subtract:
LDD
STD
ADDD
SUBD
HIgh byte is in A, low byte in B.
These are available in the full complement of binary addressing modes that the 6800 provides:
- immediate (16-bit immediate value)
- direct/zero page (addresses 0 to 255)
- indexed (with 8-bit constant offset)
- extended/absolute (addresses 0 to 65536)
Note that there is no separate CMPD. If you really need to compare two 16-bit values, you'll need to go ahead do a destructive compare -- save D in a temporary, if necessary, and use the subtract instruction. (The way the flags work, it's only rarely necessary to do so.)
Be aware that the D register is not an actual additional register. It is simply the concatenation and A and B. If you LDD #$ABCD, A will have $AB in it and B will have $CD in it.
accumulator A:8 | |
accumulator B:8 | |
Index X:16 | |
Stack Pointer SP:16 | |
Program Counter PC:16 | |
Condition Codes CC:8 |
accumulator D (A:B)
accumulator A
accumulator B
|
|
Index X | |
Stack Pointer SP | |
Program Counter PC | |
Condition Codes CC |
**68HC11/6809: Both the 68HC11 and the 6809 include the CMPD instruction, with the full set of addressing modes.
**68HC11: The 68HC11 has an actual additional Y (IY) index register. Other than the additional byte and cycle implied by the prebyte for the IY instructions, it can do essentially anything the IX register can do.
accumulator D:16 (A:B)
accumulator A:8
accumulator B:8
|
|
Index IX:16 | |
Index IY:16 | |
Stack Pointer SP:16 | |
Program Counter PC:16 | |
Condition Codes CC:8 |
**68HC11: Like the 6800/6801, the 68HC11 has only one indexing mode, a constant 8-bit unsigned offset of 0 to 255 from the index register, but it can be used with either IX or IY:
- n,X or n,Y.
**6809: The 6809 adds to the X index and S stack pointer a Y index
register and a U stack pointer, and allows indexed address modes with both
stack pointers. And the indexed addressing modes are significantly improved,
allowing auto-inc/dec, various sizes of signed constant offsets, variable
offset using the accumulators, pushing and popping multiple registers on the U
and S stacks, and memory indirection. (Deep breath.) Oh. I forgot. PC is
indexable, too.
**6809: And the 6809 provides a DP register that serves as the top 8 bits of
address when using the direct page address mode. (Unfortunately, while memory
indirection on an extended address is provided, memory indirection on a
direct-page address is not. Darn.)
accumulator D:16 (A|B)
accumulator A:8
accumulator B:8
|
|
Index X:16 | |
Index Y:16 | |
Indexable Return Stack Pointer S:16 | |
Indexable User Stack Pointer U:16 | |
Indexable Program Counter PC:16 | |
Direct Page Base DP:8 | |
Condition Codes CC:8 |
**6809: Indexing modes for the 6809 for all four indexable registers X, Y, U, and S include
- zero offset,
-
constant signed offset of
- 5 bits (-16 to 15),
- 8 bits (-128 to 127),
- 16 bits (-32768 to 32767),
- 5 bits (-16 to 15),
-
(signed variable) accumulator offset of
- A (-128 to 127),
- B (-128 to 127),
- D (-32768 to 32767),
- auto increment/decrement by 1 or 2,
- constant signed offset from PC of
- 8 bits (-128 to 127),
- 16 bits (-32768 to 32767),
- absolute/extended memory indirect
**6809: In addition to the indexed modes referencing the four index registers, two additional indexed modes are provided via the index post-byte encoding:
- program counter relative, with constant signed offset from PC of
- 8 bits (-128 to 127) or
- 16 bits (-32768 to 32767),
- extended (absolute) memory indirect.
**6809: The index post-byte encoding also provides one level of memory indirection on the result address for all indexed addressing modes except for constant 5-bit offset mode. (However, this does not imply double indirection for the extended memory indirect mode.) Memory indirection allows, for example, popping a pointer off a stack and loading an accumulator from the pointer without using an intermediate index register -- thus
LDX ,U++ ; pop pointer into X
LDA ,X ; use pointer to load A
can be done in one instruction, without using X:
LDA [,U++]
Second, the 6801 has an 8-bit by 8-bit integer multiply,
MUL
which multiplies the A and B accumulators yielding a 16-bit result in the double accumulator D. 16-bit multiplies can be done the traditional bit-by-bit way to save a few bytes, or with four 8-bit MULs and appropriate adding of columns for a much faster result.
**68HC11/6809: Both the 68HC11 and the 6809 have the 8 by 8 multiply, as well.
There is no hardware divide in the 6801. You'll have to move up to 68HC11, 68HC12, 68HC16, 68000, or Coldfire, for that.
**6809: The 6809 does not have a hardware divide, either.
**68HC11: The 68HC11 has both
integer and fractional 16 bit by 16 bit hardware divide.
Third, the 6801 adds two 16-bit shifts, logical shift left and right, accumulator-only:
LSLD (ASLD)
LSRD
**68HC11: These two instructions are present in the 68HC11, as well.
**6809: These two instructions are not present in the 6809.
These were considered key instructions. If you need 16-bit versions of the rest of the accumulator shifts and rotates, they are easy, and not expensive, to synthesize with shift-rotate or shift-shift pairs.
(Note that the 6800/6801 does not provide an arithmetic shift left distinct from the logical shift left. As an exercise for the reader, see if you can make an argument for doing so, and describe the separate behavior the arithmetic shift left should have. Heh. Not sure if I'm kidding or not. Saturation?)
Fourth, the 6801 adds a bit of index math, and push and pop for the index register:
ABX (add B to X, unsigned only)
PSHX
PULX
**68HC11: The 68HC11 adds ABY, PSHY, and PULY. It also, of course, adds increment and decrement Y -- INY/DEY. (But no subtract B from X or Y, darn.)
**6809: The 6809 has two sets of pushes and pops, PSHS/U and PULS/U. Each takes a register list, so you can essentially save or restore the entire processor state on either stack in a single instruction.
**6809/68HC11: There is one important difference between the 6800/6801/68HC11 and the 6809:
**68HC11 The stack in the former is post-decrement push, just as the 6800 stack is, always pointing one byte below the top of stack (next free byte). (TSX, TSY, TXS, and TYS adjust the pointer before moving it to or from the index register, so that indexing has no surprises. But if you save S to memory, then load it to the index register, surprise!)
**6809: The stacks in the 6809 are pre-decrement push, always pointing to the last
element pushed. Never any surprise on the 6809, but you do need to be careful
about this when moving code from the 6800/6801/68HC11 to the 6809.
**6809: The 6809 adds (hang on to your seat again) a load effective address instruction that can load the result address of any indexed addressing mode into any of the four indexable registers other than the PC. Use the LEA instruction to add any signed constant offset to X, Y, U, or S, or to add either 8-bit accumulator or the double accumulator to X, Y, U, or S. PC cannot be used as a destination of LEA, but it can be used as a source, allowing such things as constant tables embedded in fully position-independent code without having to game the return stack to access them. Yes, this seriously makes up for the otherwise limited register set of the 6809. Serious magic.
There is one 6801 instruction (four op-codes for each of the binary addressing modes), and one only, with different semantics from the 6800:
CPX (full results in flags)
On the 6800, you could only depend on the Zero flag after a CPX. (Actually, Negative was also set, and oVerflow, too, but not by rules that were useful.) On the 6801, the Negative, oVerflow, and Carry flags are also set appropriately, so that you can use any conditional branch, not just BEQ/BNE, after a CPX and get meaningful results.
** The 68HC11 adds the CPY instruction, in full addressing modes, with full 16-bit comparison semantics like the 6801 CPX.
** The 6809 adds CMPY, CMPS, and CMPU, in full addressing modes, with full 16-bit comparison semantics. (The CPX mnemonic is
CMPX on the 6809.)
These improve index handling, help support stack frames, etc.
(I am not a fan of stack frames on the return address stack, but the frame pointer pushed on S could as easily be a pointer into a synthesized parameter stack. I think maintaining a synthetic parameter stack is no more expensive than maintaining stack frames in a combined stack on the 6800 or 6801.)
**6809 The 6809 U register can be used as a frame pointer in a combined stack run-time architecture. Alternatively, in a split-stack run-time, it can be pushed to the S stack on routine entry as a frame link.
The 6801 provides an additional op-code for the call instruction, adding the
direct/zero page addressing mode:
JSR (direct page)
This allows the programmer to put short, critical subroutines in the direct page for more efficient calls.
(JMP does not get the additional op-code, which means that inner-interpreter loops for virtual machines do not benefit from allocation in the direct page, same as the 6800.)
*68HC11: The 68HC11 follows the 6801 with regards to JSR and JMP. Only extended and indexed mode for JMP, but direct page mode added for JSR.
**6809: The 6809, on the other hand, adds direct page mode JMP as well as JSR.
**68HC11: The 68HC11 follows the 6800/6801 in not providing direct page mode addressing for unary instructions (increments/decrements, shifts, etc.).
**6809: The 6809, on the other hand, does provide the direct page mode opcodes for all unary instructions. (Unfortunately, it does not provide indirection through the direct page.)
Finally, the 6801 adds a branch never instruction:
BRN
This can be useful as a marker no-op in object code, helpful in debugging, linking, and compiler code generation.
**68HC11: The 68HC11 also includes BRN.
**6809: The 6809 also include BRN.
**6809: The 6809 provides long versions of all branches. This, in addition to allowing PC relative indexing, provides significant support for position independent coding so that modules can be loaded anywhere in memory.
If you want more information than this and my writing seems understandable --
[EDIT 202410061839:] Beginning in February 2024, I have been putting together an assembly language tutorial for the 6800, 6801, 6809, and 68000 in parallel. (I do not include the 68HC11 in it because I don't know of an open source/libre licensed simulator for it.) You can find it in my programming fun blog:
https://joels-programming-fun.blogspot.com/2024/03/alpp-assembly-language-programming.html
You can see something of how these additions improve code in a
post I put up describing 64-bit math on several of the Motorola CPUs:
https://joels-programming-fun.blogspot.com/2020/12/64-bit-addition-on-four-retro-cpus-6800.htmlAlso, I discussed microcontroller (plus 6809) differences in this post:
https://defining-computers.blogspot.com/2021/08/guessing-which-motorola-microcontroller-6801-6805-6811-6809.htmlI have a long rant discussing the differences between the 68HC11 and the 6809, which picks up the 6801 and 68000 along the way:
https://defining-computers.blogspot.com/2018/12/68hc11-is-not-modified-6809-and-what-if.html
And I have this chapter of a novel in process (or suspended animation, not sure which), which gives a bit more of a detailed discussion of the 6800 instruction set architecture, touching on the 6801:
https://joelrees-novels.blogspot.com/2020/02/33209-little-about-6800-and-others.html
Also, with Joe H. Allen's permission, I forked his Exorsim project and added instruction set architecture support for the 6801 to it. You can find source code for a fig-Forth implementation for the 6800 and an implementation (somewhat) optimized to the 6801 in the test source code I include there:
My assembler for 6800/6801 may be useful for assembling the fig-Forth source:
No comments:
Post a Comment