Learn Multi platform 6309 Assembly Programming...
With Secret stuff!
The 6809 was pretty good... and
Hitachi decided they wanted to make their own version - the 6309!
However, they decided they could do better, and added a ton of
extra commands and registers to the chip!... the 6309 has an extra
2 eight bit registers, for a total of 32 bits!
Rather strangely they forgot to tell anyone, and it was much later
that anyone found out about all the extra functionality!
If
you
want to learn 6309 get the 6309
cheatsheet It contains all the 6809 and 6309 opcodes.
We'll be using
Macroassembler AS for our assembly in these tutorials... VASM is
an assembler which supports rarer CPU's like 6309 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 6309 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 6309 is an 8-Bit processor with a 16 bit Address bus!... it has two 8
bit accumulators, 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 6309 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!!!
6309 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 6309 Registers
Compared to the 6502, the 6309 is seriously powerful - and even gives the
Z80 something to think about!
8 Bit
16 Bit
24 Bit
32 Bit
Use cases
accumulator A
A
8 Bit Accumulator
accumulator B
B
8 Bit Accumulator
accumulator E
E
accumulator F
F
16-Bit Accumulator D
A
B
A+B combined to make a 16 bit Double
accumulator
16-Bit Accumulator W
E
F
E+F combined to make a 16 bit Word
accumulator
32-Bit Accumulator Q
A
B
E
F
A+B+E+F combined to make a 32 bit Quad
accumulator
Condition Code Register
CCR
Flags
Mode Register
MD
Zero Register (fixed)
0
/ Z
Transfer Value
V
Fixed Value... accessible via TFR only
survives reset!
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 6309
MD:0I------FN
CC:EFHINZVC
Name
Meaning
0
/0
Division By Zero
I
IL
Illegal instruction Exception
F
FM
FIRQ pushes all registers (1=on)
N
NM
Native mode (1=on)
E
Entire Flag
Regular/Fast Interrupt flag
F
FIRQ Mask
Fast Interrupt Flag
H
Half Carry
Bit 3/4 carry for BCD
I
IRQ Mask
Interrupt Flag
N
Negative
Z
Zero
V
oVerflow
C
Carry
note E and F cannot be pushed with PSHS ...
you must use PSHSW and PULSW (W=E+F)
The Direct page is like the 6502 Zero Page, however
it does not need to be at zero!
We can load A with a value, then TFR A,DP to set the direct
page... we need to tell the assembler where the direct page is,
otherwise some commands may malfunction, we do this with ASSUME
dpr:$xx - this is called SETDP on some assemblers
Like the 68000, the 6309 is BIG
ENDIAN... this means a 16 bit pair stored to an address like $6000
will save the high byte to $6000, and the low byte to $6001
Special Memory addresses on the 6309
Unlike the 6502, The 6309 has full 16 bit Stack pointers, U and S....
the 'Zero Page' (AKA Direct Page) can also be re positioned
Like the 6502, there are a variety of
'Interrupt Vectors' with fixed addresses...
Address
Vector
(Address)
Registers
Auto-pushed onto stack
$FFF2
SWi 3
Vector
D,X,Y,U,DP,CC
$FFF4
SWI 2
Vector
D,X,Y,U,DP,CC
$FFF6
FIRQ Vector
CC (E
flag cleared)
$FFF8
IRQ Vector
D,X,Y,U,DP,CC
$FFFA
SWI 1
Vector
D,X,Y,U,DP,CC
$FFFC
NMI Vector
D,X,Y,U,DP,CC
$FFFE
RESET
Vector
NA
The 6309 Addressing Modes
The 6502 has 11 different addrssing modes... many have no comparable
equivalent on the Z80
Inherent Addressing
Commands that don't take a parameter
ABX
Register 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
offset,R
label,pcr
,R+
,-R
[]
Indexed Addressing: Zero Offset
Just use the address in the register
LDA ,Y
LDA 0,Y
LDA Y
Indexed Addressing: 5 bit offset
-16 to +15 offset
LDA -1,Y
Indexed Addressing: Constant offset from base register
8 / 16 bit offset from X,Y,U,S ... Can be negative or positive
LDA 1000,Y
Indexed Addressing: 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+
ADDA ,X++
AutoDecrement
Subtract 1 or 2 from the register
ADDA ,-X
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
Hints
Saving a byte on return:
Rather than returning, if your last command is a pop, just pop the PC with
your other registers:
PULS B , X , PC
Addresses, Numbers and Hex... 6309 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
Missing Commands!
Commands we don't have, but might want!
DEX/DEY/INX/INY
Tfr X,D ;replace X with Y if required
DecB ;or IncB as required
Tfr D,X ;replace X with Y if required
CLC
AndCC #%11111110
SEC
OrCC #%00000001
DeX
LEAX -1,X
Lesson
1 - Getting started with 6309 Lets learn the basics of using 6309... We'll take a look at
the new registers, and some of the new commands.
The 6809 devtools
support 6309
6309_Lesson_1.asm
6309 supports
everything 6809 does... so we'll only cover the new stuff here!
If you don't know 6809 yet, please see these
tutorials!
New Registers!
The 6809's two 8 bit registers have been doubled!
As well as the old A and B, we now have E and F!
Of course, The 16 bit D register is still made up of A+B, but we
now have another 16 bit pair known as W
W is made up of E+F
All 4 8 bit registers are combined in some cases to make one 32
bit quad, known as Q
Q is made up of A+B+E+F
There are a few more weird and wonderful registers!
0 (or z in asw) is a hardwired zero, we can use it as a substitute
for a regsiter, to get a zero value, or 'discard' the result of a
command.
V is a 16 bit register referred to as the 'Transfer Value'. We
can't set it directly like E and F, but we can move values into
it. Also, strangely, it keeps its value after a reboot!
The final register is MD - the MoDe register. We can turn on bit 0
to enable Native 6309 mode, though we can use all the new commands
without doing so!. Turning on native mode alters the way the
interrupts work.
Here are the results.
Commands using the
new registers like E and F often take an extra byte than the
ones using A and B.
You should still prioritize the original registers where you
can, and just use the new ones as an alternative to the zero
page, or to reduce push pops.
Many of the previous maths commands can now be used with the new
registers.
We can use Clear, Inc and Dec... and these now even work with the
D register.
The new registers also work with ADD and SUB
Here are the results.
We have new ADDR and SUBR commands, which will add and subtract
one register from/to another. The destination is on the right.
ADCR and SBCR provide similar functions, but add and subtract the
carry as well
Unfortunately we dont have a 32 bit add or subtract command which
works with Q, but we can use the 16 bit commands to effect a 32
bit add or subtract via the carry.
Here are the results
Lesson
2 - Shifts, Compares and logical ops The 6309 adds lots of new commands, and adds new supported
registers to old ones... lets see what we can do now!
The 6809 devtools
support 6309
6309_Lesson_2.asm
Rotation and shifts
We now have 16 bit rotate
and shift commands, which work with the D and W registers.
ROR and ROL shift between the
16 bits of the register, plus the carry as a 17th bit
We do not, however, have any that work with the 32 bit Q
Here are the results
We have new logical shift commands for unsigned 16 bit numbers.
We now have LSRD and LSRW
Strangely, while we have a LSLD, we do not have
a LSLW, however "ADDR W,W" will add W to itself giving the same
effect.
Here are the results
We have new Arithmetic shift commands for signed 16 bit numbers.
We now have ASRD and ASRW
Strangely, while we have a ASLD, we do not have
a ASLW, however "ADDR W,W" will add W to itself giving the same
effect.
Here are the results
Tests and compares
We have TST and CMP commands for the new 8 and 16 bit registers.
These commands work the same as usual.
TST will set the Zero and Negative flags based on the contents of
a register.
CMP will set the flags like a subtraction, but will not change the
tested register.
Unfortunately these commands cannot work with the 32 bit Q
register.
Here are the results
Logical Operations
We have some new logical operations!
EOR, AND and OR now can work with the 16 bit D register (but not
the W one)
We now also have commands which work with register to register
values. The first specified register will be processed with the
second, and the result stored in the second register.
Here are the results
We have some new commands which perform an operation with an
Immediate value and the address in a register + an offset,
changing the byte at the effective address.
EIM will Eor an Immediate with Memory
AIM will And an Immediate with Memory
OIM will Or an Immediate with Memory
TIM will Test an Immediate with Memory - setting the flags like
logical operation AND
Here are the results.
More Maths Operations
We have a few other useful commands which perform Bit operations
SEXW will Sign EXtend 16 bit W into a 32 bit value Q (effectively
filling D with the top bit of W)
NEGD will negate the 16 bit D register - however there is no
command to negate the W register.
We also have a COMplement command, which will flip the bits of a
register, this works on all the 8 and 16 bit registers, but the 32
bit Q cannot be flipped in a single command
Here are the results
Lesson
3 - More new commands! Lets take a look at the last of the new 6309 commands.
The 6809 devtools
support 6309
6309_Lesson_3.asm
Push and Pull Commands
The PSH and PUL commands do
not work with the new E and F registers (and by implication W)
The only way to backup and restore these registers via the stack
are using the 4 new commands.
PSHSW will Push W onto the S stack. PULSW will Pull W off the S stack.
PSHUW will Push W onto the U stack. PULUW will Pull W off the U stack.
Here are the results
Bulk transfer commands
The 6309 adds some impressive new bulk transfer commands...
these give functions like LDIR on the Z80, or MVN on the 65816.
The TFM command allows us to transfer from one register to
another, with a variety of Increment and Decrement options (4 in
total)
TFM r1+,r2+ will copy W bytes from the address in r1 to the
address in r2, incrementing both after each byte.
TFM r1-,r2- will copy W bytes from the address in r1 to the
address in r2, decrementing both after each byte.
Here are the results!
We copied 4 bytes to the right, then 4 bytes to the left.
We have two more slightly strange options
TFM r1+,r2 will copy W bytes from the address in r1 to the
address in r2, incrementing only the source after each byte
TFM r1,r2+ will copy W bytes from the address in r1 to the
address in r2, incrementing only the destination after each byte
These could be usedful for transferring a block of data to, or
from, a memory mapped hardware port.
Here are the results, first we transferred 89,AB,CD,EF to $7104
(leaving only EF visible)
Then we transferred 89 four times.
Multiplication and Division
We have a new 16/32 bit
Multiply command!
MULD will multiply D by either an immediate or memory
value - alas we can't multiply by the w register.
DIVQ is the opposite, this divides the 32 bit
value in Q by the specified value, putting the whole number result
in W, and the remainder in D
DIVD is the opposite of the original MUL
command, this divides the 16 bit value in D, putting the whole
number result in B and the remainder in A
Here is the results!
ASW seems to not assembly the DIVD command
correctly, it seems to store the immediate value as a 16 bit
value, causing the command to end up as 4 bytes, rather than the
apparently correct 3.
Bit Test and Set
There are a set of special new commands for bit manipulation on
the 6309:
LDBT Load Memory Bit into Register Bit
STBT Store value of a Register Bit into Memory
BAND Logically AND Register Bit with Memory Bit
BOR Logically OR Memory Bit with Register Bit
BEOR Exclusive-OR Register Bit with Memory Bit
BITD Bit Test Accumulator D with Memory Word
Value
BIEOR Exclusively-OR Register Bit with Inverted
Memory Bit
BIOR Logically OR Register Bit with Inverted
Memory Bit
These have an odd format:
CMD Reg.Bit, Address.Bit
Where Reg and Address are the source/destination (Depending on the
command), and Bit is the source and destination bit numbers (0-7)
Unfortunately, it seems they are not emulated
properly - the 3 register options A,B,CC are mixed
up (I think the assembler is doing them right), so we won't
be covering them in detail here.