mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-10-31 14:09:43 +00:00
568 lines
25 KiB
Plaintext
568 lines
25 KiB
Plaintext
<appendix id="ref-link">
|
|
<title>Ophis Command Reference</title>
|
|
<section>
|
|
<title>Command Modes</title>
|
|
<para>
|
|
These mostly follow the <emphasis>MOS Technology 6500
|
|
Microprocessor Family Programming Manual</emphasis>, except
|
|
for the Accumulator mode. Accumulator instructions are written
|
|
and interpreted identically to Implied mode instructions.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem><para><emphasis>Implied:</emphasis> <literal>RTS</literal></para></listitem>
|
|
<listitem><para><emphasis>Accumulator:</emphasis> <literal>LSR</literal></para></listitem>
|
|
<listitem><para><emphasis>Immediate:</emphasis> <literal>LDA #$06</literal></para></listitem>
|
|
<listitem><para><emphasis>Zero Page:</emphasis> <literal>LDA $7C</literal></para></listitem>
|
|
<listitem><para><emphasis>Zero Page, X:</emphasis> <literal>LDA $7C,X</literal></para></listitem>
|
|
<listitem><para><emphasis>Zero Page, Y:</emphasis> <literal>LDA $7C,Y</literal></para></listitem>
|
|
<listitem><para><emphasis>Absolute:</emphasis> <literal>LDA $D020</literal></para></listitem>
|
|
<listitem><para><emphasis>Absolute, X:</emphasis> <literal>LDA $D000,X</literal></para></listitem>
|
|
<listitem><para><emphasis>Absolute, Y:</emphasis> <literal>LDA $D000,Y</literal></para></listitem>
|
|
<listitem><para><emphasis>(Zero Page Indirect, X):</emphasis> <literal>LDA ($80, X)</literal></para></listitem>
|
|
<listitem><para><emphasis>(Zero Page Indirect), Y:</emphasis> <literal>LDA ($80), Y</literal></para></listitem>
|
|
<listitem><para><emphasis>(Absolute Indirect):</emphasis> <literal>JMP ($A000)</literal></para></listitem>
|
|
<listitem><para><emphasis>Relative:</emphasis> <literal>BNE loop</literal></para></listitem>
|
|
<listitem><para><emphasis>(Absolute Indirect, X):</emphasis> <literal>JMP ($A000, X)</literal> — Only available with 65C02 extensions</para></listitem>
|
|
<listitem><para><emphasis>(Zero Page Indirect):</emphasis> <literal>LDX ($80)</literal> — Only available with 65C02 extensions</para></listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section>
|
|
<title>Basic arguments</title>
|
|
<para>
|
|
Most arguments are just a number or label. The formats for
|
|
these are below.
|
|
</para>
|
|
<section>
|
|
<title>Numeric types</title>
|
|
<itemizedlist>
|
|
<listitem><para><emphasis>Hex:</emphasis> <literal>$41</literal> (Prefixed with $)</para></listitem>
|
|
<listitem><para><emphasis>Decimal:</emphasis> <literal>65</literal> (No markings)</para></listitem>
|
|
<listitem><para><emphasis>Octal:</emphasis> <literal>0101</literal> (Prefixed with zero)</para></listitem>
|
|
<listitem><para><emphasis>Binary:</emphasis> <literal>%01000001</literal> (Prefixed with %)</para></listitem>
|
|
<listitem><para><emphasis>Character:</emphasis> <literal>'A</literal> (Prefixed with single quote)</para></listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section>
|
|
<title>Label types</title>
|
|
<para>
|
|
Normal labels are simply referred to by name. Anonymous
|
|
labels may be referenced with strings of - or + signs (the
|
|
label <literal>-</literal> refers to the immediate
|
|
previous anonymous label, <literal>--</literal> the
|
|
one before that, etc., while <literal>+</literal>
|
|
refers to the next anonymous label), and the special
|
|
label <literal>^</literal> refers to the program
|
|
counter at the start of the current instruction or directive.
|
|
</para>
|
|
<para>
|
|
Normal labels are <emphasis>defined</emphasis> by
|
|
prefixing a line with the label name and then a colon
|
|
(e.g., <literal>label:</literal>). Anonymous labels
|
|
are defined by prefixing a line with an asterisk
|
|
(e.g., <literal>*</literal>).
|
|
</para>
|
|
<para>
|
|
Temporary labels are only reachable from inside the
|
|
innermost enclosing <literal>.scope</literal>
|
|
statement. They are identical to normal labels in every
|
|
way, except that they start with an underscore.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>String types</title>
|
|
<para>
|
|
Strings are enclosed in double quotation marks. Backslashed
|
|
characters (including backslashes and double quotes) are
|
|
treated literally, so the string <literal>"The man said,
|
|
\"The \\ character is the backslash.\""</literal> produces
|
|
the ASCII sequence for <literal>The man said, "The \
|
|
character is the backslash."</literal>
|
|
</para>
|
|
<para>
|
|
Strings are generally only used as arguments to assembler
|
|
directives—usually for filenames
|
|
(e.g., <literal>.include</literal>) but also for string
|
|
data (in association with <literal>.byte</literal>).
|
|
</para>
|
|
<para>
|
|
It is legal, though unusual, to attempt to pass a string to
|
|
the other data statements. This will produces a series of
|
|
words/dwords where all bytes that aren't least-significant
|
|
are zero. Endianness and size will match what the directive
|
|
itself indicated.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Compound Arguments</title>
|
|
<para>
|
|
Compound arguments may be built up from simple ones, using the
|
|
standard +, -, *, and / operators, which carry the usual
|
|
precedence. Also, the unary operators > and <, which
|
|
bind more tightly than anything else, provide the high and low
|
|
bytes of 16-bit values, respectively.
|
|
</para>
|
|
<para>
|
|
Use brackets [ ] instead of parentheses ( ) when grouping
|
|
arithmetic operations, as the parentheses are needed for the
|
|
indirect addressing modes.
|
|
</para>
|
|
<para>
|
|
Examples:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem><para><literal>$D000</literal> evaluates to $D000</para></listitem>
|
|
<listitem><para><literal>$D000+32</literal> evaluates to $D020</para></listitem>
|
|
<listitem><para><literal>$D000+$20</literal> also evaluates to $D020</para></listitem>
|
|
<listitem><para><literal><$D000+32</literal> evaluates to $20</para></listitem>
|
|
<listitem><para><literal>>$D000+32</literal> evaluates to $F0</para></listitem>
|
|
<listitem><para><literal>>[$D000+32]</literal> evaluates to $D0</para></listitem>
|
|
<listitem><para><literal>>[$D000-275]</literal> evaluates to $CE</para></listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section>
|
|
<title>Memory Model</title>
|
|
<para>
|
|
In order to properly compute the locations of labels and the
|
|
like, Ophis must keep track of where assembled code will
|
|
actually be sitting in memory, and it strives to do this in a
|
|
way that is independent both of the target file and of the
|
|
target machine.
|
|
</para>
|
|
<section>
|
|
<title>Basic PC tracking</title>
|
|
<para>
|
|
The primary technique Ophis uses is <emphasis>program counter
|
|
tracking</emphasis>. As it assembles the code, it keeps
|
|
track of a virtual program counter, and uses that to
|
|
determine where the labels should go.
|
|
</para>
|
|
<para>
|
|
In the absence of an <literal>.org</literal> directive, it
|
|
assumes a starting PC of zero. <literal>.org</literal>
|
|
is a simple directive, setting the PC to the value
|
|
that <literal>.org</literal> specifies. In the simplest
|
|
case, one <literal>.org</literal> directive appears at the
|
|
beginning of the code and sets the location for the rest of
|
|
the code, which is one contiguous block.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Basic Segmentation simulation</title>
|
|
<para>
|
|
However, this isn't always practical. Often one wishes to
|
|
have a region of memory reserved for data without actually
|
|
mapping that memory to the file. On some systems (typically
|
|
cartridge-based systems where ROM and RAM are seperate, and
|
|
the target file only specifies the ROM image) this is
|
|
mandatory. In order to access these variables symbolically,
|
|
it's necessary to put the values into the label lookup
|
|
table.
|
|
</para>
|
|
<para>
|
|
It is possible, but inconvenient, to do this
|
|
with <literal>.alias</literal>, assigning a specific
|
|
memory location to each variable. This requires careful
|
|
coordination through your code, and makes creating reusable
|
|
libraries all but impossible.
|
|
</para>
|
|
<para>
|
|
A better approach is to reserve a section at the beginning
|
|
or end of your program, put an <literal>.org</literal>
|
|
directive in, then use the <literal>.space</literal>
|
|
directive to divide up the data area. This is still a bit
|
|
inconvenient, though, because all variables must be
|
|
assigned all at once. What we'd really like is to keep
|
|
multiple PC counters, one for data and one for code.
|
|
</para>
|
|
<para>
|
|
The <literal>.text</literal>
|
|
and <literal>.data</literal> directives do this. Each
|
|
has its own PC that starts at zero, and you can switch
|
|
between the two at any point without corrupting the other's
|
|
counter. In this way each function can have
|
|
a <literal>.data</literal> section (filled
|
|
with <literal>.space</literal> commands) and
|
|
a <literal>.text</literal> section (that contains the
|
|
actual code). This lets our library routines be almost
|
|
completely self-contained - we can have one source file
|
|
that could be <literal>.included</literal> by multiple
|
|
projects without getting in anything's way.
|
|
</para>
|
|
<para>
|
|
However, any given program may have its own ideas about
|
|
where data and code go, and it's good to ensure with
|
|
a <literal>.checkpc</literal> at the end of your code
|
|
that you haven't accidentally overwritten code with data or
|
|
vice versa. If your <literal>.data</literal>
|
|
segment <emphasis>did</emphasis> start at zero, it's
|
|
probably wise to make sure you aren't smashing the stack,
|
|
too (which is sitting in the region from $0100 to
|
|
$01FF).
|
|
</para>
|
|
<para>
|
|
If you write code with no segment-defining statements in
|
|
it, the default segment
|
|
is <literal>text</literal>.
|
|
</para>
|
|
<para>
|
|
The <literal>data</literal> segment is designed only
|
|
for organizing labels. As such, errors will be flagged if
|
|
you attempt to actually output information into
|
|
a <literal>data</literal> segment.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>General Segmentation Simulation</title>
|
|
<para>
|
|
One text and data segment each is usually sufficient, but
|
|
for the cases where it is not, Ophis allows for user-defined
|
|
segments. Putting a label
|
|
after <literal>.text</literal>
|
|
or <literal>.data</literal> produces a new segment with
|
|
the specified name.
|
|
</para>
|
|
<para>
|
|
Say, for example, that we have access to the RAM at the low
|
|
end of the address space, but want to reserve the zero page
|
|
for truly critical variables, and use the rest of RAM for
|
|
everything else. Let's also assume that this is a 6510
|
|
chip, and locations $00 and $01 are reserved for the I/O
|
|
port. We could start our program off with:
|
|
</para>
|
|
<programlisting>
|
|
.data
|
|
.org $200
|
|
.data zp
|
|
.org $2
|
|
.text
|
|
.org $800
|
|
</programlisting>
|
|
<para>
|
|
And, to be safe, we would probably want to end our code
|
|
with checks to make sure we aren't overwriting anything:
|
|
</para>
|
|
<programlisting>
|
|
.data
|
|
.checkpc $800
|
|
.data zp
|
|
.checkpc $100
|
|
</programlisting>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Macros</title>
|
|
<para>
|
|
Assembly language is a powerful tool—however, there are
|
|
many tasks that need to be done repeatedly, and with
|
|
mind-numbing minor modifications. Ophis includes a facility
|
|
for <emphasis>macros</emphasis> to allow this. Ophis macros
|
|
are very similar in form to function calls in higher level
|
|
languages.
|
|
</para>
|
|
<section>
|
|
<title>Defining Macros</title>
|
|
<para>
|
|
Macros are defined with the <literal>.macro</literal>
|
|
and <literal>.macend</literal> commands. Here's a
|
|
simple one that will clear the screen on a Commodore
|
|
64:
|
|
</para>
|
|
<programlisting>
|
|
.macro clr'screen
|
|
lda #147
|
|
jsr $FFD2
|
|
.macend
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>Invoking Macros</title>
|
|
<para>
|
|
To invoke a macro, either use
|
|
the <literal>.invoke</literal> command or backquote the
|
|
name of the routine. The previous macro may be expanded
|
|
out in either of two ways, at any point in the
|
|
source:
|
|
</para>
|
|
<programlisting>.invoke clr'screen</programlisting>
|
|
<para>or</para>
|
|
<programlisting>`clr'screen</programlisting>
|
|
<para>will work equally well.</para>
|
|
</section>
|
|
<section>
|
|
<title>Passing Arguments to Macros</title>
|
|
<para>
|
|
Macros may take arguments. The arguments to a macro are
|
|
all of the <quote>word</quote> type, though byte values may
|
|
be passed and used as bytes as well. The first argument in
|
|
an invocation is bound to the label
|
|
<literal>_1</literal>, the second
|
|
to <literal>_2</literal>, and so on. Here's a macro
|
|
for storing a 16-bit value into a word pointer:
|
|
</para>
|
|
<programlisting>
|
|
.macro store16 ; `store16 dest, src
|
|
lda #<_2
|
|
sta _1
|
|
lda #>_2
|
|
sta _1+1
|
|
.macend
|
|
</programlisting>
|
|
<para>
|
|
Macro arguments behave, for the most part, as if they were
|
|
defined by <literal>.alias</literal>
|
|
commands <emphasis>in the calling context</emphasis>.
|
|
(They differ in that they will not produce duplicate-label
|
|
errors if those names already exist in the calling scope,
|
|
and in that they disappear after the call is
|
|
completed.)
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Features and Restrictions of the Ophis Macro Model</title>
|
|
<para>
|
|
Unlike most macro systems (which do textual replacement),
|
|
Ophis macros evaluate their arguments and bind them into the
|
|
symbol table as temporary labels. This produces some
|
|
benefits, but it also puts some restrictions on what kinds of
|
|
macros may be defined.
|
|
</para>
|
|
<para>
|
|
The primary benefit of this <quote>expand-via-binding</quote>
|
|
discipline is that there are no surprises in the semantics.
|
|
The expression <literal>_1+1</literal> in the macro above
|
|
will always evaluate to one more than the value that was
|
|
passed as the first argument, even if that first argument is
|
|
some immensely complex expression that an
|
|
expand-via-substitution method may accidentally
|
|
mangle.
|
|
</para>
|
|
<para>
|
|
The primary disadvantage of the expand-via-binding
|
|
discipline is that only fixed numbers of words and bytes
|
|
may be passed. A substitution-based system could define a
|
|
macro including the line <literal>LDA _1</literal> and
|
|
accept as arguments both <literal>$C000</literal>
|
|
(which would put the value of memory location $C000 into
|
|
the accumulator) and <literal>#$40</literal> (which
|
|
would put the immediate value $40 into the accumulator).
|
|
If you <emphasis>really</emphasis> need this kind of
|
|
behavior, a run a C preprocessor over your Ophis source,
|
|
and use <literal>#define</literal> to your heart's
|
|
content.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Assembler directives</title>
|
|
<para>
|
|
Assembler directives are all instructions to the assembler
|
|
that are not actual instructions. Ophis's set of directives
|
|
follow.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>.outfile</literal> <emphasis>filename</emphasis>:
|
|
Sets the filename for the output binary if one has not
|
|
already been set. If no name is ever set, the output will
|
|
be written to <literal>ophis.bin</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.advance</literal> <emphasis>address</emphasis>
|
|
[, <emphasis>filler</emphasis>]: Forces the program
|
|
counter to be <emphasis>address</emphasis>. Unlike
|
|
the <literal>.org</literal>
|
|
directive, <literal>.advance</literal> outputs bytes (the
|
|
value of <emphasis>filler</emphasis>, or zeroes if it is
|
|
unspecified) until the program counter reaches a
|
|
specified address. Attempting
|
|
to <literal>.advance</literal> to a point behind the
|
|
current program counter is an assemble-time error.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.alias</literal> <emphasis>label</emphasis> <emphasis>value</emphasis>:
|
|
The .alias directive assigns an arbitrary value to a
|
|
label. This value may be an arbitrary argument, but
|
|
cannot reference any label that has not already been
|
|
defined (this prevents recursive label
|
|
dependencies).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.byte</literal> <emphasis>arg</emphasis> [
|
|
, <emphasis>arg</emphasis>, ... ]: Specifies a series of
|
|
arguments, which are evaluated, and strings, which are
|
|
included as raw ASCII data. The final results of these
|
|
arguments must be one byte in size. Seperate constants
|
|
are seperated by comments.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.checkpc</literal> <emphasis>address</emphasis>:
|
|
Ensures that the program counter is less than or equal to
|
|
the address specified, and emits an assemble-time error
|
|
if it is not. <emphasis>This produces no code in the
|
|
final binary - it is there to ensure that linking a large
|
|
amount of data together does not overstep memory
|
|
boundaries.</emphasis>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.data</literal> <emphasis>[label]</emphasis>:
|
|
Sets the segment to the segment name specified and
|
|
disallows output. If no label is given, switches to the
|
|
default data segment.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.incbin</literal> <emphasis>filename</emphasis>
|
|
[, <emphasis>offset</emphasis>
|
|
[, <emphasis>length</emphasis>]]: Inserts the contents of
|
|
the file specified as binary data. Use it to include
|
|
graphics information, precompiled code, or other
|
|
non-assembler data. You may also optionally specify an
|
|
index to start including from, or a length to only
|
|
include a subset.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.include</literal> <emphasis>filename</emphasis>:
|
|
Includes the entirety of the file specified at that point
|
|
in the program. Use this to order your final sources, if
|
|
you aren't doing it via the command line.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.org</literal> <emphasis>address</emphasis>:
|
|
Sets the program counter to the address
|
|
specified. <emphasis>This does not emit any code in and
|
|
of itself, nor does it overwrite anything that previously
|
|
existed.</emphasis> If you wish to jump ahead in memory,
|
|
use <literal>.advance</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.require</literal> <emphasis>filename</emphasis>:
|
|
Includes the entirety of the file specified at that point
|
|
in the program. Unlike <literal>.include</literal>,
|
|
however, code included with <literal>.require</literal>
|
|
will only be inserted once.
|
|
The <literal>.require</literal> directive is useful for
|
|
ensuring that certain code libraries are somewhere in the
|
|
final binary. They are also very useful for guaranteeing
|
|
that macro libraries are available.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.space</literal> <emphasis>label</emphasis> <emphasis>size</emphasis>:
|
|
This directive is used to organize global variables. It
|
|
defines the label specified to be at the current location
|
|
of the program counter, and then advances the program
|
|
counter <emphasis>size</emphasis> steps ahead. No actual
|
|
code is produced. This is equivalent to <literal>label:
|
|
.org ^+size</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.text</literal> <emphasis>[label]</emphasis>:
|
|
Sets the segment to the segment name specified and allows
|
|
output. If no label is given, switches to the default
|
|
text segment.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.word</literal> <emphasis>arg</emphasis> [
|
|
, <emphasis>arg</emphasis>, ... ]:
|
|
Like <literal>.byte</literal>, but values are all treated
|
|
as two-byte values and stored low-end first (as is the
|
|
6502's wont). Use this to create jump tables (an
|
|
unadorned label will evaluate to that label's location)
|
|
or otherwise store 16-bit data.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.dword</literal> <emphasis>arg</emphasis> [
|
|
, <emphasis>arg</emphasis>, ...]:
|
|
Like <literal>.word</literal>, but for 32-bit
|
|
values.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.wordbe</literal> <emphasis>arg</emphasis> [
|
|
, <emphasis>arg</emphasis>, ...]:
|
|
Like <literal>.word</literal>, but stores the value in a
|
|
big-endian format (high byte first).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.dwordbe</literal> <emphasis>arg</emphasis> [
|
|
, <emphasis>arg</emphasis>, ...]:
|
|
Like <literal>.dword</literal>, but stores the value high
|
|
byte first.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.scope</literal>: Starts a new scope
|
|
block. Labels that begin with an underscore are only
|
|
reachable from within their innermost
|
|
enclosing <literal>.scope</literal>
|
|
statement.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.scend</literal>: Ends a scope block. Makes the
|
|
temporary labels defined since the
|
|
last <literal>.scope</literal> statement unreachable, and
|
|
permits them to be redefined in a new
|
|
scope.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.macro</literal> <emphasis>name</emphasis>:
|
|
Begins a macro definition block. This is a scope block
|
|
that can be inlined at arbitrary points
|
|
with <literal>.invoke</literal>. Arguments to the macro
|
|
will be bound to temporary labels with names like
|
|
<literal>_1</literal>, <literal>_2</literal>, etc.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.macend</literal>: Ends a macro definition block.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>.invoke</literal> <emphasis>label</emphasis> [<emphasis>argument</emphasis> [,
|
|
<emphasis>argument</emphasis> ...]]: invokes (inlines) the
|
|
specified macro, binding the values of the arguments to the
|
|
ones the macro definition intends to read. A shorthand
|
|
for <literal>.invoke</literal> is the name of the macro to
|
|
invoke, backquoted.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</appendix>
|