return to Choose a Color Scheme: Dark
Print Mode

Learn Multi platform 6809 Assembly Programming... 8 bit resurrection!

This page is Under Construction.... 'Learn 6809 is planned for 2020'

The 6800 was too expensive for the mainstream, and it had many of its features cut, and was released as the 6502...  it's second accumulator gone, it's command set cut back - and everyone forgot about the 6800....

But the 6800 came back - as the 6809... with new previously unheardof powers!... armed with twin stack pointers , 16 bit Stack,X and Y registers- 16 bit capabilities and advanced addressing modes and even a MULTiply command (unheard of in most 8 bits)... the 6809 is the 'missing link' between  the 6502 and the 68000!

Powering the Dragon 32, the FM-7 machines - and more significantly the Vectrex... Lets see what the 6809 can do!


If you want to learn 6809 get the Cheatsheet! it has all the 6809 commands, It will give you a quick reference when you're stuck or confused, which will probably happen a lot in the early days!

We'll be using Macroassembler AS for our assembly in these tutorials... VASM is an assembler which supports rarer CPU's like 6809 and 65816 and many more, and also supports multiple syntax schemes...

You can get the source and documentation for AS from the official website HERE

What is the 6809 and what are 8 'bits' You can skip this if you know about binary and Hex (This is a copy of the same section in the Z80 tutorial)
The 6809 is an 8-Bit processor with a 16 bit Address bus!... it has two 8 bit accumulatrors, A and B, that can be combined to make up one 16 bit accumulator D (AB)
What's 8 bit... well, one 'Bit' can be 1 or 0
four bits make a Nibble (0-15)
two nibbles (8 bits) make a byte (0-255)
two bytes (16 bits) make a word (0-65535)

And what is 65535? well that's 64 kilobytes ... in computers Kilo is 1024, because four bytes is 1024 bytes
64 kilobytes is the amount of memory a basic 8-bit system can access

the 6809 is 8 bit so it's best at numbers less than 256... it can do numbers up to 65535 too more slowly... and really big numbers will be much harder to do! - we can design our game round small numbers so these limits aren't a problem.

You probably think 64 kilobytes doesn't sound much when a small game now takes 8 gigabytes, but that's 'cos modern games are sloppy, inefficient,  fat and lazy - like the basement dwelling losers who wrote them!!!
6809 code is small, fast, and super efficient - with ASM you can do things in 1k that will amaze you!

Numbers in Assembly can be represented in different ways.
A 'Nibble' (half a byte) can be represented as Binary (0000-1111) , Decimal (0-15) or  Hexadecimal (0-F)... unfortunately, you'll need to learn all three for programming!

Also a letter can be a number... Capital 'A'  is stored in the computer as number 65!

Think of Hexadecimal as being the number system invented by someone wit h 15 fingers, ABCDEF are just numbers above 9!
Decimal is just the same, it only has 1 and 0.

In this guide, Binary will shown with a % symbol... eg %11001100 ... hexadecimal will be shown with & eg.. &FF.

Assemblers will use a symbol to denote a hexadecimal number, some use $FF or #FF or even 0x, but this guide uses & - as this is how hexadecimal is represented in CPC basic
All the code in this tutorial is designed for compiling with WinApe's assembler - if you're using something else you may need to change a few things!
But remember, whatever compiler you use, while the text based source code may need to be slightly different, the compiled "BYTES' will be the same!
Decimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 255
Binary 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111   11111111
Hexadecimal 0 1 2 3 4 5 6 7 8 9 A B C D E F   FF

Another way to think of binary is think what each digit is 'Worth' ... each digit in a number has it's own value... lets take a look at %11001100 in detail and add up it's total

Bit position 7 6 5 4 3 2 1 0
Digit Value (D) 128 64 32 16 8 4 2 1
Our number (N) 1 1 0 0 1 1 0 0
D x N 128 64 0 0 8 4 0 0
128+64+8+4= 204            So %11001100 = 204 !

If a binary number is small, it may be shown as %11 ... this is the same as %00000011
Also notice in the chart above, each bit has a number, the bit on the far right is no 0, and the far left is 7... don't worry about it now, but you will need it one day!

If you ever get confused, look at Windows Calculator, Switch to 'Programmer Mode' and  it has binary and Hexadecimal view, so you can change numbers from one form to another!
If you're an Excel fan, Look up the functions DEC2BIN and DEC2HEX... Excel has all the commands to you need to convert one thing to the other!

But wait! I said a Byte could go from 0-255 before, well what happens if you add 1 to 255? Well it overflows, and goes back to 0!...  The same happens if we add 2 to 254... if we add 2 to 255, we will end up with 1
this is actually usefull, as if we want to subtract a number, we can use this to work out what number to add to get the effect we want

Negative number -1 -2 -3 -5 -10 -20 -50 -254 -255
Equivalent Byte value 255 254 253 251 246 236 206 2 1
Equivalent Hex Byte Value FF FE FD FB F6 EC CE 2 1

All these number types can be confusing, but don't worry! Your Assembler will do the work for you!
You can type %11111111 ,  &FF , 255  or  -1  ... but the assembler knows these are all the same thing! Type whatever you prefer in your ode and the assembler will work out what that means and put the right data in the compiled code!

The 6809 Registers
Compared to the 6502, , the 6809 is seriously powerful - and even gives the Z80 something to think about!

The Z80 has Accumulator, 3 pairs of 8 bit regsiters (BC,DE,HL), usable for 16 bit maths and 2 16-bit  indirect registers (IX,IY), it also has a 16 bit Stack pointer, and there are 'Shadow Regsiters' for special purposes

The 6502 is very different, it has an 8 bit Accumulator, two 8 bit  indirect registers (X,Y)  and an 8 bit stack pointer... it also has a 16 bit Program Counter... it has no Shadow Registers

8 Bit 16 Bit Use cases
accumulator A A 8 Bit Accumulator
accumulator B B 8 Bit Accumulator
16-Bit Accumulator  D A B A+B combined to make a 16 bit accumulator
Condition Code Register CCR Flags
Indirect X X Indirect Register
Indirect Y Y Indirect Register
User Stack Pointer U User Stack
Hardware Stack  Pointer  S Stack 
Program Counter PC Running Command
Direct Page DP Zero page is relocatable on 6809

    Flags: NV-BDIZC
Name Meaning
N Negative 1=Negative
V Overflow 1=True
- unused
B BRK command
D Decimal mode 1=True
I IRQ disable 1=Disable
Z Zero 1=Result Zero
C Carry 1=Carry

At a glance this may make the 6502 seem significantly inferior to the Z80, however the 6502 has some tricks up it's sleeve!... Where as the fastest command on the Z80 takes 4 ticks, on the 6502 it takes only 1... and the 6502 makes up for it's lack of registers with superior addressing modes!

Special Memory addresses on the 6809
Unlike the 6502, The 6809 has full 16 bit Stack pointers, U and S.... the 'Zero Page' (AKA Direct Page) can also be repositioned

The 6809 Addressing Modes
The 6502 has 11 different addrssing modes... many have no comparable equivalent on the Z80

Inherant Addressing Commands that don't take a parameter ABX
Regsiter Addressing Commands that only use register TFR A,DP
Immediate Addressing Direct Address of command ADDA #$10
ADDD #$1000
Direct Page addressing Read from DP (zero page ADDA $10
Extended Direct addressing Read from an address ADDA $1234
Extended Indirect Addressing Read from the address specified... then get the value from that address ADDA [$1234]
Indexed Addressing Uses a 2nd setting byte - allows for Autoinc ,R
Zero Offset Just use the address in the register LDA ,Y
5 bit offset -16 to +15 offset LDA -1,Y
Consant offset from base register 8 / 16 bit offset from X,Y,U,S ... Can be negative or positive LDA 1000,Y
Constant Offset From PC 8 / 16 bit offset from PC LDA $10,PC
Program counter relative PCR is like PC, but is calculated by the assembler ADDA label,PCR
Indirect with constant offset from base register Load from the address in the register + offset LDA [1,X]
Accumulator offset from Base register Add accumulator (A/B/D) to a X,Y,U,S (not PC) LDA B,Y
Indirect Accumulator offset from Base register Load from the address made up of a X,Y,U,S Plus the accumulator LD [B,Y]
AutoIncrement Add 1 or 2 to the register ADDA ,X+
AutoDecrement Subtract 1 or 2 from the register ADDA ,-X
Indirect AutoIncrement Load from the address in Register, then add 1 or 2 ADDA [,X+]
ADDA [,X++]
Indirect AutoDecrement Subtract 1 or 2 then Load from the address in Register ADDA [,-X]
ADDA [,--X]
Program relative Offset to PC BRA label

Saving a byte on return:

Rather than returning, if your last command is a pop, just pop the PC with your other registers:

Mode Description Sample Command Z80 Equivalent effective result
Implied / Inherant A command that needs no paprameters SEC SEC  (set carry) SCF
Relative A command which uses the program counter PC with and offset nn (-128 to +127) BEQ #$nn BEQ [label] (branch if equal) JR Z,[label]
Accumulator A command which uses the Accumulator as the parameter ROL ROL (ROtate bits Left) RLCA
Immediate A command which takes a byte nn as a parameter ADC #$nn ADC #1 ADC 1 &nn
Absolute Take a parameter from a two byte memory address $nnnn LDA $nnnn LDA $2000 LD a,(&2000) (&nnnn)
Absolute Indexed Take a parameter from a two byte memory address $nnnn+X (or Y) LDA $nnnn,X LDA $2000,X (&nnnn+X)
Zero Page Take a parameter from the zero page address $00nn ADC $nn ADC $32 (&00nn)
Zero Page Indexed Takes a parameter from memory address $00nn+X ADC $nn,X ADC $32,X (&00nn+X)
Indirect Take a parameter from pointer at address $nnnn...
if $nnnn contains $1234 the parameter would come from the address at $1234
JMP ($1000) LD HL,(&1000)
indirect ZP The 65c02 has an extra feature, where it can read from an unindexed Zero page LDA ($80) ((&00nn))
Pre Indexed (Indirect,X) Take a paramenter from pointer at address $nnnn+X
if $nnnn contains $1234, and X contained 4  the parameter would come from the address at $1238
ADC ($nn,X) ADC ($32,X) ((&00nn+X))
Postindexed  (Indirect),Y Take pointer from address $nnnn, add Y... get the parameter from the result
if $nnnn contains $1234, and Y contained 4, the address would be read from $1234... then 4 would be added... and the parameter would be read from ther resulting address
ADC ($nn),Y ADC ($32),Y ((&00nn)+Y)
Addresses, Numbers and Hex... 6809 notification
We'll be using VASM for our assembler, but most other 6502 assemblers use the same formats... however coming from Z80, they can be a little confusing, so lets make it clear which is which!
Prefix Example Z80 equivalent   Meaning
# #16384 16384 Decimal Number
#% #%00001111 %00001111 Binary Number
#$ #$4000 &4000 Hexadecimal number
#' #'a 'a' ascii value
12345 (16384) decimal memory address
$ $4000 (&4000) Hexadecimal memory address

Learn Assembly for the Greatest Classic Processors:  Z80 - 6502 - 68000
Visit to get my games and their source code! | Support me on patreon