A09
A Morotola 6809 assembler. There are many like it, but this is mine.
Install / Use
/learn @spc476/A09README
A Motorola 6809 Assembler
This is a standard, two-pass assembler that understands (as far as I can tell) most of the standard pseudo operations that other 6809 assemblers understand, plus a few others that I find handy.
NOTE: You will need to downlaod and install the following libraries to use the program:
https://github.com/spc476/CGILib
https://github.com/spc476/mc6809
Labels are restricted to 63 charaters in length, which I think is larger than most other 6809 assemblers. I also support a type of 'local' label that is easier to show than explain:
random pshs x,d
ldd #-1
.smaller_mask cmpd ,s
blo .got_mask
lsra
rorb
bra .smaller_mask
.got_mask lslb
rolb
orb #1
std 2,s
.generate ldd lfsr
lsra
rorb
bcc .nofeedback
eora #$B4
eora #$00
.nofeedback std lfsr
anda 2,s
andb 3,s
cmpd ,s
bhi .generate
leas 4,s
rts
Labels that start with '.' are considered 'local' to a previous label not starting with a '.'. Internally, the assembler will translate the these labels:
.smaller_mask
.got_mask
.generate
.nofeedback
to
random.smaller_mask
random.got_mask
random.generate
random.nofeedback
The total length of a label, plus a 'local' label, must not exceed 63 chararacters, but I feel that such a feature, along with the generous limit for label length, can make for more readable code. One more example:
clear_bytes clra
.loop sta ,x+
decb
bne .loop
rts
clear_words stb ,-s
clra
clrb
.loop std ,x++
dec ,s
bne .loop
rts
The four labels defined are:
clear_bytes
clear_bytes.loop
clear_words
clear_words.loop
The two instances of '.loop' do not interfere, nor are considered duplicate labels, due to the internal expansion.
Expressions can be prefixed with '>' to force a 16-bit value; with '<' to force an 8-bit value, or '<<' to force a 5-bit value (useful for the index addressing mode).
foo equ $01
lda foo ; knows to use direct (8-bit) address
lda >foo ; force extended (16-bit) address
lda bar ; used extended, beause of forward reference
lda <bar ; force use of direct address
lda foo,x ; uses 5-bit offset because value is known
lda <foo,x ; force use of 8-bit offset
lda >foo,x ; force use of 16-bit offset
lda bar,x ; uses 16-bit offset because of forward reference
lda <<bar,x ; force 5-bit offset
lda <bar,x ; force 8-bit offset
bar equ $02
And here's the generated machine code for the above code:
1 | foo equ $01
2 |
0000: 96 01 3 | lda foo 0002: B6 0001 4 | lda >foo 0005: B6 0002 5 | lda bar 0008: 96 02 6 | lda <bar 000A: A6 01 7 | lda foo,x 000C: A6 8801 8 | lda <foo,x 000F: A6 890001 9 | lda >foo,x 0013: A6 890002 10 | lda bar,x 0017: A6 02 11 | lda <<bar,x 0019: A6 8802 12 | lda <bar,x 13 | 14 | bar equ $02
And the warnings the assembler generated from the above code:
example.a:5: warning: W0005: address could be 8-bits, maybe use '<'?
example.a:10: warning: W0006: offset could be 5-bits, maybe use '<<'?
(The reason we can't just apply those transformations is due to speed considerations, and complexity---each such change requires another pass, and that would lead a more complex assembler.)
Numbers can be specified in decimal, octal (leading '&'), binary (leading '%') and hexadecimal (leading '$'). The use of an underscore ('_') within numbers can be used to separate groups. Some examples:
122 decimal
12_123 decimal
%10101010 binary
%10_101_110 binary
&34 octal
&23_44 octal
$FF hexadecimal
$F_ff_3 hexadecimal
There is a special form of value for use with the ANDCC, ORCC and CWAI instructions. Instead of an immediate value, like:
ORCC #$50 ; disable interrupts
ANDCC #$AF ; enable interrupts
CWAI #$AF ; enable interrupts and wait
ORCC #$01 ; set carry flag
ANDCC #$FE ; reset carry flag
you can specify a "flag set", as:
ORCC {FI}
ANDCC {FI}
CWAI {FI}
ORCC {C}
ANDCC {C}
This form will construct the appropriate values for the instructions. The flags are:
C carry
V overflow
Z zero
N negative
I interrupt
H half-carry
F fast interrupt
E entire state
There is a special form of value for use with the PSHS/PULS/PSHU/PULU instructions. Instead of a list of registers, you can specify no registers at all:
PSHS -
PULU -
This generates an operand byte of 0. This can be useful if you need a 5-cycle NOP instruction.
The assembler also supports a wide range of operators. Unary operators include:
>n Force n to be 16 bits
<n Force n to be 8 bits
<<n Force n to be 5 bits (signed)
-n Negate n
~n 2s complement n
+n n
n! Factorial n (floating point values only)
And binary operators include (grouped by highest to lowest, left to right assiciative unless indicated otherwise):
a ** b a to the b power (right to left associative)
a * b a * b
a / b a / b
a % b a mod b
a + b a add b
a - b a sub b
a << b a shift left b bits
a >> b a shift right b bits
a & b a bitwise and b
a ^ b a bitwise exclusive or b
a | b a bitwise or b
a :: b a * 256 + b (a MSB of word, b LSB of word) (int values only)
a <> b a not equal to b
a < b a less than b
a <= b a less than or equal to b
a = b a equal to b
a >= b a greater than or equal to b
a > b a greater than b
a && b a logical and b
a || b a logical or b
The list of supported pseudo operations---if label "Non-standard", it's a non-standard pesudo operation for most 6809 assemblers.
.ASSERT expr [, "explanation" ]
(Non-standard) Assert a condition when running tests;
otherwise ignored. If the expression is true, nothing
happens; if the expression is false, the test fails, a
dianostic message is printed, and the assembly procedure
stops. This can appear outside of a unit test.
.ENDTST
(Non-standard) End a unit test; ignored when not running
tests.
.FLOAT float-expr [, float-expr ... ]
(Non-standard) Format a floating point number; default
format except when using the rsdos or basic formats. This
will format a 32-bit IEEE-754 floating point number, which
can be used with the MC6839. For the rsdos and basic
formats, this will generate the Color Basic floating point
format (40 bits). There may be some differences with a
value generated from Color Basic itself, but may be "close
enough" to be useful. The format can be changed with the
.OPT * REAL directive.
.FLOATD float-expr [, float-expr ... ]
(Non-standard) Format a double length floating point number
when using IEEE-754 floats. For the rsdos and basic
formats, this will generate the same value as .FLOAT, but
generate a warning.
.NOTEST
(Non-standard) All text up to a .ENDTST directive is
ignored. This is an easy way to disable a test without
removing it.
.OPT set option data...
(Non-standard) Supply an option from within the source code
instead of the command line. The following options are
always available:
.OPT * DISABLE <warning>
Disable the given warning (see list below).
Note that W0002, W0014, W0015 and W0016
cannot be disabled with this directive given
the nature of when they happen. W0002 can
be disabled with the ".OPT * USES <label>"
directive; the others mentioned above only
happen when using the test backend.
All warnings are enabled by default.
.OPT * ENABLE <warning>
Enable a given warning. Note that upon
program startup, all warnings are enabled by
default. This is typically used to
re-enable a warning after being disabled.
.OPT * USES <label>
Mark a label as being used. This is used to
supress W0002 warnings.
.OPT * OBJ ('TRUE' | 'FALSE')
Enable or disable the generation of object
code. This option is used to define
variables for the direct page without
actually generating data in the output file.
Symbols, however, are defined.
Default value is TRUE.
.OPT * REAL ('IEEE' | 'MSFP' | 'LBFP' )
Generate floating point values per the
IEEE-754 ('IEEE') format, the Microsoft
('MSFP') floating point format, or the
format used by Lennart Benschop's floating
point routines.
Default value depends upon backend.
.OPT * CT
Generate a total cycle count in the listing
file.
.OPT * CC
Clear the total cycle count in the listing
file.
The following options are only used when running tests. The
following options can appear inside or outside a .TEST
directive unless otherwise specified. If specified inside a
.TEST directive, they only take effect when the test is run.
.OPT TEST ORG <address>
Set the starting address for assembling test
cases. This directive can ONLY appear
outside of a .TEST directive, given the
nature of the assembler.
Default value is $E000.
.OPT TEST POKE <address>,<byte>
Write the byte value to the address in the
virtual memory for the 6809 emulator.
.OPT TEST POKEW <address>,<word>
Write the word (16-bit value) to the address
in the virtual memory for the 6809 emulator.
.OPT TEST PROT <prot>,<address>[,<end-address>]
Enable memory permissions for the given
address(es). The permissions allowed are:
r allow reads
w allow writes
x allow execution
t trace execution and writes
n remove any protections
The first four can be all be used; 'n' is
used to remove any existing protections on a
memory location.
.OPT TEST PROT r,$400 ; ro of $400
.OPT TEST PROT rw,foo ; rw @ foo
.OPT TEST P
