Skip to content
Switch branches/tags
This branch is up to date with master.

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

F9DASM - 6800/6801/6802/6803/6808/6809 / 6301/6303/6309 Disassembler

Copyright (c) 2000 Arto Salmi
Parts Copyright (c) 2001-2020 Hermann Seib
Parts Copyright (c) 2013 Colin Bourassa
Parts Copyright (c) 2014-2015 Rainer Buchty

Based on Arto Salmi's C core that can be found somewhere on the 'net (last address known to me was, I built a complete 6800/6809/6309 disassembler that can handle input files in a variety of formats (Intel Hex / Motorola S09 / Flex9 Binary / Binary). Since disassembly without guidance produces measly results, it can load information files with quite a lot of directives, too.

I taylored the original to my taste by working through the source code; since F9DASM has reached a level of complexity that doesn't really lend itself to following the "Use the Source, Luke!" principle if you just want to disassemble a little 6809 program, I've added this documentation. Have fun!

Hermann Seib, 2015


f9dasm, hex2bin and mot2bin are command line tools written in fairly generic C that should compile on a wide range of systems.

For Microsoft Visual Studio, .dsp, .dsw (Visual Studio 6), .sln, and .vcproj files are provided.

A Makefile is provided for Linux systems; this may also work on other systems using GNU Make. You'll need to make sure you have the appropriate development packages (make, gcc, etc.) installed. This was tested on Debian 9.


f9dasm [-option]* [filename]

Command Line Options

-offset address
When disassembling a binary file, the default load address is 0, since the binary file does not contain any clues; using this option forces F9DASM to load the file at the specified address.
-begin address
start disassembly address (address has to be given in hex format)
Default is the first referenced address in the file.
-end address
end disassembly address (address has to be given in hex format)
Normally, this is defined either through the file size or its contents, if it has an embedded END addres. This option allows to override the implicit end address.
-out filename
normally, f9dasm streams to standard output; this option forces it to write to the specified file instead.
if disabled, suppresses the address field output for clean assembler source files (default is enabled)
disables or enables hex dump output (default is enabled).
While analyzing a file, the hex dump can be quite helpful; if you want to generate a clean assembler source file, you can disable it.
-x, -6309
puts disassembler in 6309 mode (default is 6809).
-6800, -6802, -6808
puts disassembler in 6800/6802/6808 mode (default is 6809).
-6801, -6803
puts disassembler in 6801/6803 mode (default is 6809).
-6301, -6303
puts disassembler in 6301/6303 mode (default is 6809).
using this flag, the disassembler tries to convert swi2 to the corresponding OS/9 calls.
-info filename
filename gives an information file which contains additional hints for the disassembler. See the Info File section below.
Passing the file name help displays help for the information file.
-cchar char
char is the character to be used as comment delimiter.
Default is ;, but not all assemblers can use this.
-cchar * would switch the comment delimiter to *, for example, which might be better if a TSC-compatible assembler is used.
using this flag, the disassembler uses the standardized FLEX labels for a defined range of addresses.
using this flag, the disassembler outputs various "convenience" mnemonics (like, for example, CLRD instead of CLRA followed by CLRB).
Default is on, but not all assemblers support this, so f9dasm can be forced to stick to the base set of mnemonics.
f9dasm's companion, A09, can of course handle them :-)
can be used to output values in decimal notation (by default it's hexadecimal).
can be used to enable or disable the output of comments (which can be provided in an info file, see below).
Normally, comments are enabled.
can be used to enable or disable output of the ASCII equivalent to code/data.
Default is to output ASCII
can be used to enable or disable the use of FCC to define data (instead of FCB or FDB)
Default is to use FCC
omit indexed-mode operands of $00 (default)
do not omit indexed-mode operands of $00
This only works for 6800-based code; in 6809-based code, omitting the zero is encoded differently.
using this flag, the assembler outputs forced direct (<) or extended (>) addressing markers where this is necessary to ensure an exact reproduction.
This is based on the TSC Assembler's syntax, which is not necessarily universal, so it can be turned off.
-ldchar char
char is the character to be used as label delimiter.
Default is nothing, but not all assemblers can use this; some need a colon, for example.
-ldchar : can be used to switch the label delimiter to : in this case.
outputs an abbreviated version of this documentation.

Info File

Using the -info filename option, you can give f9dasm additional information about the layout of the processed file.

Normally, f9dasm will try to interpret everything as code; it doesn't try to find out which areas contain code and which areas contain data, or the format of the data. Using an info file, you can give it detailed instructions how to process the file, add comments, insert additional stuff, and so on.

The info file is a simple text file, which contains one instruction per line.
The instructions are case-insensitive.
Addresses need to be given in hexadecimal notation. Anything following an asterisk (*) is interpreted as a comment.

The info file can contain the following instructions:

file filename [baseaddr]
This instructs f9dasm to load the given file at the given address.
Can be used instead of the command line parameter for the file name; this can, for example, be useful if you want to generate a listing for a bunch of small EPROMs that cover a continuous memory area.
option option [value]
option is one of the options listed above, just without the leading hyphen (-).
code addr[-addr]
defines the given address (range) as containing code.
data addr[-addr]
defines the given address (range) as containing data instead of code.
f9dasm will try to decipher ASCII strings in the area and display them in the best possible format.
bin[ary] addr[-addr]
char addr[-addr]
dec[imal] addr[-addr]
hex[adecimal] addr[-addr]
defines the output format used for the given data range.
This can also be used for constants in the code area; if, for example, f9dasm outputs the following line of code:
        LDA     #$D6                     *C115: 86 D6
and you know pretty well that this is a binary bit mask, you can force it to display the data in a nicer format by giving the instruction bin c116 (note that the address of the constant byte is given, not the address of the instruction!). This results in the modified output
        LDA     #%11010110               *C115: 86 D6
which may be easier to read (depending on your mental approach to assembler programming :-).
Note that char and bin can not be used for word areas (see below).
word addr[-addr]
defines that the area consists of words (i.e., 2-byte entities, high byte first) instead of single bytes.
const addr[-addr]
defines the data in the given range as constants.
Normally, if f9dasm can interpret the data as addresses, it will; and if there's a label defined for this address, it will display the label instead of the original value.
unused addr[-addr]
defines the given address range as unused.
This can be useful if an area in the loaded file is known to be empty; there's no need to put it into the generated assembler source.
rmb addr[-addr]
defines the given address range as reserved, but not initialized to defined values.
label addr name
sets a label at the given address.
Note that f9dasm doesn't restrict the length of the label, nor does it enforce a given range of characters (except for * and zero bytes - these terminate the name). This may conflict with the assembler of your choice, so choose the labels withg caution.
used[label] addr [name]
forces the given address used.
Normally, f9dasm would only emit a label definition in the form of an EQU statement if the label is really used in the code.
unlabel addr[-addr]
removes defined labels in the given address range.
This is mainly useful if you use a set of info files (see the include instruction below) and want to remove label definitions from an earlier info file.
insert addr[-addr] text
This instruction adds the given text to the text lines which are displayed before a given (range of) address(es).
In contrast to a comment, there's no comment character written before the text, which allows to insert any assembler statement or pseudo-op.
comment addr[-addr] text
appends a comment to the lines displayed before a given address (range).
lcomment addr[-addr] text
appends a line comment to the lines displayed before a given address (range).
A line comment is displayed as a comment to the right of the instruction.
If more than one line comment is given, they are displayed on separate lines, but all to the right of the instruction.
prepend addr[-addr] text
This instruction prepends the given text to the text lines which are displayed before a given (range of) address(es).
This is mainly useful if you use a set of info files (see the include instruction below) and want to add additional text from a later info file before text lines from an earlier info file.
prepcomm addr[-addr] text
Same as prepend (see above), but it prepends a comment instead of a normal text line.
preplcom[ment] addr[-addr] text
prepends a line comment to the lines displayed before a given address (range).
uncomment addr[-addr]
removes insert and comment lines from the given address range.
This is mainly useful if you use a set of info files (see the include instruction below) and want to remove comments from an earlier info file so that you can replace them.
unlcomment addr[-addr]
removes line comments from the given address range.
This is mainly useful if you use a set of info files (see the include instruction below) and want to remove line comments from an earlier info file.
include filename
includes the given info file.
setdp [addr[-addr]] dp-content
uses the specified direct page (if the specified processor can do that - 6800 and its derivates implicitly uses Direct Page 0).
To allow usage with programs that repeatedly change the direct page, an address range can be given.
If only the start address is given, the range is assumed to start there and go up to the end of the address range.
If no address is given, the global direct page is changed.
Any value between 00 and FF sets the direct page (0 is the default); values outside this range disable direct page processing by forcing f9dasm to emit a
line which 6809 assemblers normally interpret as "don't use direct page addressing".
Only the last global setdp statement is used.
unsetdp [addr[-addr]]
removes setdp effects from the given range or, if no range is given, sets the global direct page back to the default.
rel[ative] addr[-addr] baseaddr
This can be used to make instructions with indexed addressing easier to read.
unrel[ative] addr[-addr]
cancels the effect of relative instructions.
remap addr[-addr] offset
This is a tricky instruction that only makes sense in very special situations; imagine, for example, that you already have an elaborate info file for a specific EPROM - and then you get another EPROM that contains nearly the same stuff, just with one or two instructions added or missing.
You could, of course, adapt all instructions in your info file to the new address layout.
Would you? I wouldn't.
In this case, it's easier to prepend a remap instruction that tells f9dasm to "shift" the following addresses in the info file some bytes.
phase addr[-addr] [+|-]phase
Sometimes, an EPROM can contain data that are mapped to a different location; in this case, all jump targets etc. inside that area are incorrect, i.e., "out of phase". The phase instruction tells F9DASM to disassemble that area as if it was starting at the address given in phase.
Using this instruction embeds PHASE/DEPHASE pseudo-ops in the generated source code, so an Assembler that can process these pseudo-ops is required (the mighty AS can do it, and my A09 can do it since V1.30, too).
This deals with one part of the problem - data inside phased areas are disassembled correctly. But to reference them correctly from outside the phased area requires additional, relative phase statements.
Relative phase statements are made by adding a + or - before phase (which in this case is a relative value).
Attention: a relative phase statement can only be set inside a phased area; so, if relative phasing is required, all areas in the disassembled module that use it have to be put into a phased area, even the "un-phased" ones, like:
phase 8000-ffff 8000
and relative phases have to be defined after the phase area definition.
If your Assembler of choice can't handle phasing, all you can do is to cut the binary in slices, use the -offset command line option to disassemble them, and merge the generated assembler source files by hand.
cvec[tor] addr[-addr]
defines a code vector area (a table of code addresses).
Works like word addr[-addr], but also defines code labels for the addresses if necessary
dvec[tor] addr[-addr]
defines a data vector area (a table of data addresses).
Works like word addr[-addr], but also defines data labels for the addresses if necessary
patch addr[-addr] hex [hex]*
Can be used to patch bytes in a loaded file. Using this feature, modified versions of a file can be created automatically.
A09 can be used to emit patch instructions instead of listings to make it easier to develop a modified version of a program.
patchw addr[-addr] word [word]*
Can be used to patch words (i.e., 2-byte entities) in a loaded file.
Terminates processing of this info file at once.

Note: wherever text requires leading blanks or tabs, it isn't possible to simply put them into the instruction, as f9dasm would discard them. For these cases, simply prepend a '\' (backslash) to the text, like, for example, in insert 0 \ OPT H63 so that f9dasm knows where text really starts. Despite the similarity, f9dasm doesn't know the range of "C" escape characters; a '\' simply means "Ignore this backslash, but make sure the next character is part of the text". If you need to have a * as part of the text, it is mandatory to write it as \*; f9dasm would otherwise assume the line ends at the *, which starts the comment part.


6800/6801/6809/6309 Disassembler




No releases published


No packages published