6809 Introduction

        .cr     6809        To load this cross overlay

The Motorola 6809 processor is a very powerful successor of the 6800. Not only does it have more registers, like an extra index register and a user definable stack pointer, but some very powerful addressing modes were added as well. The direct page addressing mode is changed in a way that the direct page can now be located in any memory page you like.
JMP and JSR instructions are now accompanied by LBRA and LBSR instructions, which enable you to write fully relocatable programs. This becomes possible because all jumps and subroutine calls can now be made relative to the current program counter..

Programming Model

The programming model in the picture below shows the most important registers of the 6809 processor. I only include a little summary about the features of the 6809's programming model here. It is not my intention to make the original documentation obsolete, so please refer to the original documentation for further details.

6809 programming model

The 6809 has a very powerful addressing mode called direct page addressing. This way all 256 bytes of any page in memory can be addressed with only 8 bits. These 256 addresses can be considered the "registers" of the 6809!

The Accumulators A and B

The 6809 is equipped with two 8-bit accumulators. Both Accumulators are technically the same and can both be used for a variety of arithmetic operations.
Both Accumulators can be concatenated to form a 16-bit accumulator, called D. Accumulator A becomes the most significant byte of the double accumulator.

The Condition Code Register

The CC register holds all the system flags. In some 6809 literature the CC register is sometimes called CCR. Most flags reflect the status of the machine after mathematical or logical instructions. Other flags are set or cleared under program control.

The CC register contains 8 system flags:

Bit 7EEntire Flag
Bit 6FFIRQ mask Flag
Bit 5HHalf Carry Flag
Bit 4IIRQ Flag
Bit 3NNegative sign Flag
Bit 2ZZero Flag
Bit 1VOverflow Flag
Bit 0CCarry Flag

IRQ interrupts are disabled when the I bit is set.
FIRQ interrupts are disabled when the F bit is set.
When the E Flag is set all internal registers were pushed on the stack, as opposed to only PC and CC in case of a FIRQ. The stacked E bit is used by the RTI instruction to determine what is to be pulled from the stack.

The Index registers X and Y

Both index registers can be used to indirectly point to data in many different ways. The X and Y registers are identical to each other.
Using index registers as data pointers almost always involves incrementing or decrementing the index register after or before data fetching. Therefore the 6809 allows auto increment or decrement together with indexed addressing modes.

Please refer to the 6809 opcode test file for all possible indexed notations understood by the SB-Assembler.

The Stack Pointers S and U

The 6809 is equipped with 2 stack pointers. S is the system stack pointer and is always used to save return addresses during subroutine and interrupt calls. This register is sometimes called SP. The system stack may also be used for other purposes, exactly like with most other microprocessors.
The user stack pointer U is somewhat special. In some 6809 literature it is also called US. It can be used to push data onto and pull data from it, just like with the system stack. However it can never be used to store subroutine or interrupt return addresses.
As a bonus both stack pointers can be used as extra index registers having the same capabilities as the X and Y registers.

Both stack pointers are 16-bits wide, so the stacks can be located anywhere in RAM memory. Both stacks grow down in memory when data is pushed to them.

There is a large difference between the stack pointers of the 6809 and the stack pointer of the 6800. On the 6800 the stack pointer always points to the first available stack location. But on the 6809 the stack pointer points to the top of the stack.
This means that the stack pointer points to last byte that was saved (if there was one).
Pushing a byte to the stack on a 6809 is done by decrementing the stack pointer first and then the data is stored at the location pointed to by the stack pointer in use.

Words are pushed with their LSB first. Subroutine calls and interrupts push the return address on the stack. This is the address of the instruction that has to be executed when the subroutine or interrupt is completed.

NMI, IRQ and SWI Interrupts save all registers on the stack. The order in which all data is pushed is shown below:


It goes without saying that the pull order is just the other way around!

FIRQ interrupts have higher priority than IRQ interrupts and are called "fast" because only the PC and CC are pushed on the stack. It's the programmer's responsibility to save and restore all other affected registers. The push order for FIRQ is: PCL, PCH, CC.

The Program Counter

The program counter PC is normally incremented after fetching each instruction or operand byte during program execution. The only way you can change this behaviour is with the jump, subroutine and return instructions. Also interrupts can change the program counter's value.


SB-Assembler Version 3 can show you the cycle times of each instruction when the TON list flag is switched on. The numbers presented are the number of clock pulses the processor needs to execute the instruction.

System Vectors

System Vectors don't have anything to do with the SB-Assembler in particular, but I've included them here anyway for easy reference.


Reserved Words

The SB-Assembler 6809 cross overlay has a few reserved words. All reserved words are register names. It is not very likely though that you will run into trouble if you use any of the reserved words as label names. But it is always better to be safe than sorry, so why use them when you have so many alternatives to choose from.

The reserved words are:

A, B, CC, CCR, DP, DPR, X, Y, U, US, S, SP, PC, PCR.

Special Features

Stack operation

The 6809 has two stack pointers. One of them is the system stack (S), used to save return addresses and other data. The other one is a user stack (U), which can be used for any purpose, except for storing return addresses.

The 6809 can push or pull all its registers to or from either one of the stacks with just one instruction. The PSHS, PSHU, PULS, or PULU instructions should be followed by a register list, indicating what registers should be pushed or pulled. The order in which the registers are pushed to the stack is fixed, as shown below:

PC, U/S, Y, X, DP, B, A, CC

The SB-Assembler doesn't care in what order you enter the registers to be pushed or pulled. It is the 6809 that determines the pushing order shown above. Only the registers which are mentioned in the parameter list of the PSH or PUL instruction are really saved or restored. You may duplicate particular registers in your list without any error messages from the SB-Assembler. But each register will only be pushed or pulled once per instruction! So don't use PSHS A,A to push the Accumulator A to the stack twice because A will be pushed only once.
Only Version 3 of the SB-Assembler will give you a Repeated register(s) ignored warning if you specify one or more registers more than once. For the rest the behaviour of Version 3 is exactly the same as in Version 2.
All 16-bit registers are pushed to the stack with their low byte first. This will leave the word in memory in big endian model, which is the overall default of the 6809.
Saving accumulator D is in fact the same as saving both accumulators A and B, therefore the instruction PSHS A,B is exactly the same as the instruction PSHS D.
The second register in the list above is U/S. This means that you can either save U or S to the stack. You can save U to the system stack, or S to the user stack. It's no use to save U to the user stack, or S to the system stack.

It goes without saying that the pull order is exactly the reverse order of the push order.

Reading several 6809 programming manuals I came across different syntaxes for the CC and DP registers. Therefore I have included CCR and DPR as alternatives for the CC and DP register names.

Indirect addressing mode

The normal syntax for the indirect mode is [address]. However the SB-Assembler also accepts the notation (address), which it inherited from its first version on the Apple ][ computer, because the Apple had problems with typing the square brackets.

Indexed addressing modes

The official notation of the indexed addressing mode is offset,X, where offset can be up to a 16-bit signed offset value. However usually the offset value is $00 and that can be written in two different ways in the SB-Assembler:

         LDA    0,X
         LDA    ,X

Both instructions have the same effect and use an offset value of $00.
The SB-Assembler will automatically select the appropriate indexing mode, using no offset, 5-bit signed offset, 8-bit signed offset, or 16-bit signed offset values.

Forced direct page and extended addressing modes

One of the strongest features of the 6809 is its direct page addressing mode. Direct page addressing mode is also called zero page addressing mode on other micro processors because they always use the first 256 bytes of memory space. The 6809 takes this concept even further and allows the direct page to be in any specific memory page by storing the page number in the DP register.
With direct addressing mode you specify a memory location that can be addressed with only one byte (instead of 2 for all other memory locations). This way the 6809 can be seen as a microprocessor with 256 sets of 256 registers each.

The SB-Assembler automatically selects direct addressing mode when that mode is available and the high byte of the address is equal to the value stored in the DP register. After a hardware reset the DP register always contains $00, making the 6809 compatible with the 6800. To enable this automatic selection of the direct page addressing mode, the SB-Assembler must know what the currently expected direct page is. The 6809 specific directive .DP tells the assembler what direct page to use.
We only know for sure that the high byte of the address is equal to the currently set Direct Page if there was no unresolved label used in the expression identifying the address. If a forward referenced label is used in an address expression we automatically assume the worst case situation and opt for extended addressing mode (2 bytes address field).

You may override this automatic selection of addressing mode by preceding the address field with a < or a > symbol.
The < symbol forces the assembler to use direct page addressing mode, even if the address expression contains a forward referenced label.
On the other hand the > symbol will force the assembler to use the extended addressing mode, even if the address could be resolved to a direct address.
As opposed to the 6800 cross overlay, no Out of range error will be reported if you try to force to use the direct addressing mode where the high byte of the address isn't equal to the current direct page. This is because the 6809 can have its direct page located anywhere in memory. So you'll have to be careful to ensure that the DP register is loaded with the correct value whenever yo use forced direct page mode.


8000-                     .DP   0             Direct page = zero page
0010-           LABEL     .EQ   $10           A direct page address
8000-96 10                LDA   LABEL         Appears to be direct page
8002-96 11                LDA   <FORWARD      Clearly a forward referenced label
8004-97 12                STA   $12           Is a direct page address
8006-B7 00 11             STA   >$11          Force extended addressing mode
0011-           FORWARD   .EQ   $11           A direct page address

Forced 8-bit and 16-bit offsets

Only Version 3 of the SB-Assembler will allow forced 8-bit or 16-bit indexed addressing modes. If an offset is preceded with a > symbol the assembler will always use a 16-bit offset, even for 8-bit, 5-bit and 0 offsets. If an offset is preceded with a < symbol the assembler will use an 8-bit offset. However, if the resulting offset doesn't fit in 8-bits, a Out of range error will be generated.
The forced 8-bit offset can be used to force the short addressing mode while using forward referenced labels. Otherwise the worst case 16-bit offset is used if a forward referenced label was used.
You cannot force the offset to be 5-bits or even 0 offset in any way. These offsets can only be used if no forward referenced labels are used in the offset expression.

Register names

Especially the register names for the EXG and TFR instructions are a cause for some confusion if you read some of the available 6809 literature. Therefore I have added some extra register names for the above mentioned instructions in Version 3 of the SB-Assembler. These names are aliases for the more commonly used names of the affected registers.
Register D may also be written as A:B. Register U may be called US, while register S may be called SP. Furthermore CC and CCR are the same, and DP is the same as DPR.

offset,PC addressing mode

One of the great features of the 6809 is its ability to execute position independent code. Especially the Long Branch Jump and Long Branch Subroutine instructions make this possible. However, a program sometimes needs to read some data from memory. Here the Long Branch instructions are of no big help. Fortunately the 6809 understands the offset,PC addressing mode.

There's one little problem though. You'll have to calculate the offset from the current PC to your data yourself. And this is quite tricky.
The offset from the current PC to your data is calculated as: destination - (PC + instruction_length). Here destination is the destination address where the data is to be found (seen from the current location of the code). PC is the address of held the PC register at the beginning of the instruction. But what is the instruction_length? For 8-bit offsets the instruction length is 3 bytes, unless a pre-byte is needed (e.g. for LDY offset,PC) because then the length is 4 bytes. For 16-bit offsets the instruction length is again 1 byte longer.
All in all, quite complicated and error prone if you have to calculate the offset yourself. Therefore the SB-Assembler can do that for you if you use the syntax destination,PCR. Destination is now translated to the correct offset by the assembler for you. The assembler will even choose 8-bit offsets if possible.


8000-A6 8D 00 0B          LDA   COUNT-$-4,PC  Hand calculated offset
8004-17 01 F9             LBSR  PRINT
8007-A6 8D 00 05          LDA   MEAN,PCR      Offset is calculated for you
800B-17 01 F2             LBSR  PRINT
800E-39                   RTS
800F-05           COUNT   .DA   #5            Both forward referenced labels
8010-78           MEAN    .DA   #120           therefore 16-bit offsets used

Compatibility mnemonics

I have added many mnemonics to the 6809 cross assembler to make it source code compatible with the 6800. Some of these instructions don't really have a 6800 equivalent, but are added for convenience, like CLRD or ROLD. Normally the assembler isn't supposed to understand all these instructions, but I have added them here for your convenience. If you don't like them, simply don't use them. And if you like the compatibility mnemonics better than the original 6809 once, feel free to use them instead. But remember, you may run into portability problems if you try to assemble your code in other assemblers. (Can't imagine why you would want to use another assembler though)

Accumulator D compound instructions

Arithmetic shift left D
Arithmetic shift right D
Clear D
Complement D
Logical shift left D
Logical shift right D
Roll left D
Roll right D

Set and Clear instructions

CLCANDCC #$FEClear Carry
CLIFANDCC #$AFClear FIRQ and IRQ flags
CLVANDCC #$FDClear Overflow flag
SECORCC #$01Set Carry flag
SEFORCC #$40Set FIRQ flag
SEIORCC #$10Set IRQ flag
SEIFORCC #$50Set FIRQ and IRQ flags
SEVORCC #$02Set Overflow flag

Increment and decrement instructions

DESLEAS -1,SDecrement S
DEULEAU -1,UDecrement U
DEXLEAX -1,XDecrement X
DEYLEAY -1,YDecrement Y
INSLEAS 1,SIncrement S
INULEAU 1,UIncrement U
INXLEAX 1,XIncrement X
INYLEAY 1,YIncrement Y

Stack instructions

PSHAPSHS APush A to system stack
PSHBPSHS BPush B to system stack
PSHCCPSHS CCPush A to system stack
PSHDPSHS A,BPush B to system stack
PSHDPPSHS DPPush A to system stack
PSHPCPSHS PCPush B to system stack
PSHXPSHS XPush B to system stack
PSHYPSHS YPush B to system stack
PULAPULS APull A from system stack
PULBPULS BPull B from system stack
PULCCPULS CCPull A from system stack
PULDPULS DPull B from system stack
PULDPPULS DPPull A from system stack
PULPCPULS PCPull B from system stack
PULXPULS XPull B from system stack
PULYPULS YPull A from system stack

Please note that PSHU and PULU are not included as compound instructions. This is to avoid confusion with the original PSHU and PULU instructions, which require you to specify the registers to be pushed or pulled.

Transfer and miscellaneous instructions

Add B to A
Compare B with A
Subtract B from A
Transfer A to B and set flags
TAPTFR A,CCTransfer A to CC
Transfer B to A and set flags
TPATFR CC,ATransfer CC to A
TSXTFR S,XTransfer S to X
TXSTFR X,STransfer X to S
WAICWAI #$FFWait for interrupt

Apart from the tables above you can also use the 6800 instructions like LDAA instead of LDA, or STAB instead of STB etc.

Overlay Initialization

Three things are set while initializing the 6809 overlay every time it is loaded by the .CR directive.

  • Big endian model is selected for 16-bit addresses and for the .DA and .DL directives. This means that words or long words are stored with their high byte first.
  • The assumed direct page is set to $00, which reflects the way the 6809 will wake up from reset.
  • The maximum program counter value is set to $FFFF.

.DP     Direct Page


        .DP  expression


The .DP directive is used to tell the SB-Assembler what the currently selected Direct Page is. Knowing this enables the SB-Assembler to automatically select between direct addressing mode and extended addressing mode. The SB-Assembler will use direct addressing mode whenever the address and the instruction both allow it.


The direct page of a 6809 may be located in any memory page, as opposed to the direct page of the 6800 which is fixed to page 0. You must be able to tell the SB-Assembler what the expected direct page is to allow it to select the direct page addressing mode whenever possible. This is done with the .DP directive.
Please note that you only tell the SB-Assembler what memory bank is supposed to be selected. It is the programmer's responsibility to effectively set the 6809's DP register to the proper value to make it really happen! The SB-Assembler has no way of checking this and is therefore unable to warn you about mistakes. So the .DP directive is in no way a substitute for the loading of the DP register to really select the direct page on the processor!
Page 0 is selected when a 6809 comes out of reset and that is also the default expected direct page after loading or reloading the cross overlay.

The expression must evaluate to a value from 0 to 255 and may not contain forward referenced labels. Other values will result in a Out of range error.

The SB-Assembler will automatically select the direct addressing mode whenever it can. This is when the instruction allows it and when the upper byte of the operand address is equal to the value set by the latest .DP instruction.
The destination address must be resolved completely, otherwise the worst case situation is expected and the SB-Assembler will opt for extended addressing mode. So the SB-Assembler will use extended addressing mode if the destination address contains a forward referenced label.

You can force the use of direct addressing mode by preceding the destination address with the < symbol. The direct addressing mode will then be used regardless of forward referenced labels and regardless of the destination address' high byte value.
This differs a little with e.g. the 6800 assembler because on the 6809 the high byte of the address may be any value, not only 0.
You can also force the SB-Assembler to use extended addressing mode by preceding the destination address by the > symbol.


8000-                  .DP    $00         Tell assembler to use DP $00
8000-86 00             LDA    #$00        Tell 6809 to use
8002-1F 8B             TFR    A,DP         direct page $00
8004-96 12             LDA    $12         Use direct mode automatically
8006-B6 12 34          LDA    $1234       Don't use direct mode
8009-                  .DP    $12         Tell assembler to use DP $12
8009-86 12             LDA    #$12        Tell 6809 to use
800B-1F 8B             TFR    A,DP         direct page $12
800D-BC 00 12          LDA    $12         Don't use direct mode
8010-96 34             LDA    $1234       Use direct mode automatically

Please note that the assembler would still generate the same code when the LDA #$12 and TFR A,DP instructions at address $8009 were omitted. But in real life the last program line would point to address $0034 instead of the intended address $1234!

Differences Between Other Assemblers

There are some differences between the SB-Assembler and other assemblers for the 6809 processor. These differences require you to adapt existing source files before they can be assembled by the SB-Assembler. This is not too difficult though, and is the (small) price you have to pay for having a very universal cross assembler.

  • Not all assemblers are as forgiving when it comes to entering register names in the wrong order with push and pull instructions.
  • Not all assemblers will understand all the compatibility instructions.
  • Not all assemblers will understand forced direct page and extended addressing modes.
  • The obvious differences in notation of directives and radixes common to all SB-Assembler crosses.
  • Don't forget that the SB-Assembler does not allow spaces in or between operands. Only Version 3 will allow one space after each comma separating operands in the operand field.