Initial import of the Ophis 1.0 distribution and supplemental material

This commit is contained in:
Michael C. Martin 2011-08-20 16:33:25 -07:00
parent b78f3c614a
commit 2c8dba2450
99 changed files with 31597 additions and 0 deletions

BIN
doc/a2blink.map Normal file

Binary file not shown.

BIN
doc/a2inverse.map Normal file

Binary file not shown.

BIN
doc/a2normal.map Normal file

Binary file not shown.

12
doc/c64-1.oph Normal file
View File

@ -0,0 +1,12 @@
.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance 2064
.require "kernal.oph"

40
doc/c64-2.oph Normal file
View File

@ -0,0 +1,40 @@
.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance $0810
.require "kernal.oph"
.data zp
.org $0002
.text
.scope
; Cache BASIC's zero page at top of available RAM.
ldx #$7E
* lda $01, x
sta $CF81, x
dex
bne -
jsr _main
; Restore BASIC's zero page and return control.
ldx #$7E
* lda $CF81, x
sta $01, x
dex
bne -
rts
_main:
; Program follows...
.scend

478
doc/docbook/cmdref.sgm Normal file
View File

@ -0,0 +1,478 @@
<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> &mdash; Only available with 65C02 extensions</para></listitem>
<listitem><para><emphasis>(Zero Page Indirect):</emphasis> <literal>LDX ($80)</literal> &mdash; 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&mdash;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 &gt; and &lt;, 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>&lt;$D000+32</literal> evaluates to $20</para></listitem>
<listitem><para><literal>&gt;$D000+32</literal> evaluates to $F0</para></listitem>
<listitem><para><literal>&gt;[$D000+32]</literal> evaluates to $D0</para></listitem>
<listitem><para><literal>&gt;$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&mdash;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 #&lt;_2
sta _1
lda #&gt;_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>.advance</literal> <emphasis>address</emphasis>:
Forces the program counter to
be <emphasis>address</emphasis>. Unlike
the <literal>.org</literal>
directive, <literal>.advance</literal> outputs zeroes 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>: Inserts the
contents of the file specified as binary data. Use it to
include graphics information, precompiled code, or other
non-assembler data.</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.</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>
<para>
The following directives are deprecated, added for
compatibility with the old Perl
assembler <command>P65</command>. Use
the <literal>-d</literal> option to Ophis to enable
them.
</para>
<itemizedlist>
<listitem><para><literal>.ascii</literal>: Equivalent to <literal>.byte</literal>,
which didn't used to be able to handle strings.</para></listitem>
<listitem><para><literal>.code</literal>: Equivalent to <literal>.text</literal>.</para></listitem>
<listitem><para><literal>.segment</literal>: Equivalent to <literal>.text</literal>,
from when there was no distinction between <literal>.text</literal> and
<literal>.data</literal> segments.</para></listitem>
<listitem><para><literal>.address</literal>: Equivalent to
<literal>.word</literal>.</para></listitem>
<listitem><para><literal>.link</literal> <emphasis>filename address</emphasis>: Assembles
the file specified as if it began at the address specified.
This is generally for use in <quote>top-level</quote> files, where there
is not necessarily a one-to-one correspondence between file
position and memory position. This is equivalent to an
<literal>.org</literal> directive followed by an <literal>.include</literal>.
With the introduction of the <literal>.org</literal> directive this one is
less useful (and in most cases, any <literal>.org</literal> statement
you use will actually be at the top of the <literal>.include</literal>d
file).</para></listitem>
</itemizedlist>
</section>
</appendix>

View File

@ -0,0 +1,29 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"
[<!ENTITY part1 SYSTEM "tutor1.sgm">
<!ENTITY part2 SYSTEM "tutor2.sgm">
<!ENTITY part3 SYSTEM "tutor3.sgm">
<!ENTITY part4 SYSTEM "tutor4.sgm">
<!ENTITY part5 SYSTEM "tutor5.sgm">
<!ENTITY part6 SYSTEM "tutor6.sgm">
<!ENTITY part7 SYSTEM "tutor7.sgm">
<!ENTITY samplecode SYSTEM "samplecode.sgm">
<!ENTITY pre1 SYSTEM "preface.sgm">
<!ENTITY cmdref SYSTEM "cmdref.sgm">
]>
<book>
<bookinfo>
<title>Programming with Ophis</title>
<author><firstname>Michael</firstname><surname>Martin</surname></author>
<copyright><year>2006-7</year><holder>Michael Martin</holder></copyright>
</bookinfo>
&pre1;
&part1;
&part2;
&part3;
&part4;
&part5;
&part6;
&part7;
&samplecode;
&cmdref;
</book>

74
doc/docbook/preface.sgm Normal file
View File

@ -0,0 +1,74 @@
<preface>
<title>Preface</title>
<para>
The Ophis project started on a lark back in 2001. My graduate
studies required me to learn Perl and Python, and I'd been playing
around with Commodore 64 emulators in my spare time, so I decided
to learn both languages by writing a simple cross-assembler for
the 6502 chip the C-64 used in both.
</para>
<para>
The Perl version was quickly abandoned, but the Python one slowly
grew in scope and power over the years, and by 2005 was a very
powerful, flexible macro assembler that saw more use than I'd
expect. In 2007 I finally got around to implementing the last few
features I really wanted and polishing it up for general release.
</para>
<para>
Part of that process has been formatting the various little
tutorials and references I'd created into a single, unified
document&mdash;the one you are now reading.
</para>
<section>
<title>Why <quote>Ophis</quote>?</title>
<para>
It's actually a kind of a horrific pun. See, I was using Python
at the time, and one of the things I had been hoping to do with
the assembler was to produce working Apple II
programs. <quote>Ophis</quote> is Greek
for <quote>snake</quote>, and a number of traditions also use it
as the actual <emphasis>name</emphasis> of the serpent in the
Garden of Eden. So, Pythons, snakes, and stories involving
really old Apples all combined to name the assembler.
</para>
</section>
<section>
<title>Getting a copy of Ophis</title>
<para>
If you're reading this as part of the Ophis install, you clearly
already have it. If not, as of this writing the homepage for
the Ophis assembler
is <ulink url="http://hkn.eecs.berkeley.edu/~mcmartin/ophis/"></ulink>. If
this is out-of-date, a Web search on <quote>Ophis 6502
assembler</quote> (without the quotation marks) should yield its
page.
</para>
<para>
Ophis is written entirely in Python and packaged using the
distutils. The default installation script on Unix and Mac OS X
systems should put the files where they need to go. If you are
running it locally, you will need to install
the <literal>Ophis</literal> package somewhere in your Python
package path, and then put the <command>ophis</command> script
somewhere in your path.
</para>
<para>
Windows users that have Python installed can use the same source
distributions that the other operating systems
use; <command>ophis.bat</command> will arrange the environment
variables accordingly and invoke the main script.
</para>
<para>
If you are on Windows and do not have Python installed, a
prepackaged system made with <command>py2exe</command> is also
available. The default Windows installer will use this. In
this case, all you need to do is
have <command>ophis.exe</command> in your path.
</para>
</section>
</preface>

749
doc/docbook/samplecode.sgm Normal file
View File

@ -0,0 +1,749 @@
<appendix>
<title>Example Programs</title>
<para>
This Appendix collects all the programs referred to in the course
of this manual.
</para>
<section id="tutor1-src">
<title id="tutor1-fname"><filename>tutor1.oph</filename></title>
<programlisting>
.word $0801
.org $0801
.word next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
next: .word 0 ; End of program
.advance 2064
ldx #0
loop: lda hello, x
beq done
jsr $ffd2
inx
bne loop
done: rts
hello: .byte "HELLO, WORLD!", 0
</programlisting>
</section>
<section id="tutor2-src">
<title id="tutor2-fname"><filename>tutor2.oph</filename></title>
<programlisting>
.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance 2064
.alias chrout $ffd2
ldx #0
* lda hello, x
beq +
jsr chrout
inx
bne -
* rts
hello: .byte "HELLO, WORLD!", 0
</programlisting>
</section>
<section id="c64-1-src">
<title id="c64-1-fname"><filename>c64-1.oph</filename></title>
<programlisting>
.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance 2064
.require "kernal.oph"
</programlisting>
</section>
<section id="kernal-src">
<title id="kernal-fname"><filename>kernal.oph</filename></title>
<programlisting>
; KERNAL routine aliases (C64)
.alias acptr $ffa5
.alias chkin $ffc6
.alias chkout $ffc9
.alias chrin $ffcf
.alias chrout $ffd2
.alias ciout $ffa8
.alias cint $ff81
.alias clall $ffe7
.alias close $ffc3
.alias clrchn $ffcc
.alias getin $ffe4
.alias iobase $fff3
.alias ioinit $ff84
.alias listen $ffb1
.alias load $ffd5
.alias membot $ff9c
.alias memtop $ff99
.alias open $ffc0
.alias plot $fff0
.alias ramtas $ff87
.alias rdtim $ffde
.alias readst $ffb7
.alias restor $ff8a
.alias save $ffd8
.alias scnkey $ff9f
.alias screen $ffed
.alias second $ff93
.alias setlfs $ffba
.alias setmsg $ff90
.alias setnam $ffbd
.alias settim $ffdb
.alias settmo $ffa2
.alias stop $ffe1
.alias talk $ffb4
.alias tksa $ff96
.alias udtim $ffea
.alias unlsn $ffae
.alias untlk $ffab
.alias vector $ff8d
; Character codes for the colors.
.alias color'0 144
.alias color'1 5
.alias color'2 28
.alias color'3 159
.alias color'4 156
.alias color'5 30
.alias color'6 31
.alias color'7 158
.alias color'8 129
.alias color'9 149
.alias color'10 150
.alias color'11 151
.alias color'12 152
.alias color'13 153
.alias color'14 154
.alias color'15 155
; ...and reverse video
.alias reverse'on 18
.alias reverse'off 146
; ...and character set
.alias upper'case 142
.alias lower'case 14
</programlisting>
</section>
<section id="tutor3-src">
<title id="tutor3-fname"><filename>tutor3.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
</programlisting>
</section>
<section id="tutor4a-src">
<title id="tutor4a-fname"><filename>tutor4a.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts
</programlisting>
</section>
<section id="tutor4b-src">
<title id="tutor4b-fname"><filename>tutor4b.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
lda #lower'case
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "Hello, ",0
hello2: .byte "!", 13, 0
target1: .byte "programmer", 0
target2: .byte "room", 0
target3: .byte "building", 0
target4: .byte "neighborhood", 0
target5: .byte "city", 0
target6: .byte "nation", 0
target7: .byte "world", 0
target8: .byte "Solar System", 0
target9: .byte "Galaxy", 0
target10: .byte "Universe", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts
</programlisting>
</section>
<section id="tutor4c-src">
<title id="tutor4c-fname"><filename>tutor4c.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
lda #lower'case
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
.charmap 'A, "abcdefghijklmnopqrstuvwxyz"
.charmap 'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
hello1: .byte "Hello, ",0
hello2: .byte "!", 13, 0
target1: .byte "programmer", 0
target2: .byte "room", 0
target3: .byte "building", 0
target4: .byte "neighborhood", 0
target5: .byte "city", 0
target6: .byte "nation", 0
target7: .byte "world", 0
target8: .byte "Solar System", 0
target9: .byte "Galaxy", 0
target10: .byte "Universe", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts
</programlisting>
</section>
<section id="tutor5-src">
<title id="tutor5-fname"><filename>tutor5.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.data
.org $C000
.text
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
.checkpc $A000
.data
.checkpc $D000
</programlisting>
</section>
<section id="tutor6-src">
<title id="tutor6-fname"><filename>tutor6.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.data
.org $C000
.space cache 2
.text
.macro print
lda #<_1
ldx #>_1
jsr printstr
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
; Save the zero page locations that PRINTSTR uses.
lda $10
sta cache
lda $11
sta cache+1
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
; Restore the zero page values printstr uses.
lda cache
sta $10
lda cache+1
sta $11
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
printstr:
sta $10
stx $11
ldy #$00
_lp: lda ($10),y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend
.checkpc $A000
.data
.checkpc $D000
</programlisting>
</section>
<section id="c64-2-src">
<title id="c64-2-fname"><filename>c64-2.oph</filename></title>
<programlisting>
.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance $0810
.require "kernal.oph"
.data zp
.org $0002
.text
.scope
; Cache BASIC's zero page at top of available RAM.
ldx #$7E
* lda $01, x
sta $CF81, x
dex
bne -
jsr _main
; Restore BASIC's zero page and return control.
ldx #$7E
* lda $CF81, x
sta $01, x
dex
bne -
rts
_main:
; Program follows...
.scend
</programlisting>
</section>
<section id="tutor7-src">
<title id="tutor7-fname"><filename>tutor7.oph</filename></title>
<programlisting>
.include "c64-2.oph"
.data
.org $C000
.text
.macro print
lda #<_1
ldx #>_1
jsr printstr
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
.data zp
.space _ptr 2
.text
printstr:
sta _ptr
stx _ptr+1
ldy #$00
_lp: lda (_ptr),y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend
.checkpc $A000
.data
.checkpc $D000
.data zp
.checkpc $80
</programlisting>
</section>
</appendix>

315
doc/docbook/tutor1.sgm Normal file
View File

@ -0,0 +1,315 @@
<chapter id="part1">
<title>The basics</title>
<para>
In this first part of the tutorial we will create a
simple <quote>Hello World</quote> program to run on the Commodore
64. This will cover:
<itemizedlist>
<listitem><para>How to make programs run on a Commodore 64</para></listitem>
<listitem><para>Writing simple code with labels</para></listitem>
<listitem><para>Numeric and string data</para></listitem>
<listitem><para>Invoking the assembler</para></listitem>
</itemizedlist>
</para>
<section>
<title>A note on numeric notation</title>
<para>
Throughout these tutorials, I will be using a lot of both
decimal and hexadecimal notation. Hex numbers will have a
dollar sign in front of them. Thus, 100 = $64, and $100 = 256.
</para>
</section>
<section>
<title>Producing Commodore 64 programs</title>
<para>
Commodore 64 programs are stored in
the <filename>PRG</filename> format on disk. Some emulators
(such as CCS64 or VICE) can run <filename>PRG</filename>
programs directly; others need them to be transferred to
a <filename>D64</filename> image first.
</para>
<para>
The <filename>PRG</filename> format is ludicrously simple. It
has two bytes of header data: This is a little-endian number
indicating the starting address. The rest of the file is a
single continuous chunk of data loaded into memory, starting at
that address. BASIC memory starts at memory location 2048, and
that's probably where we'll want to start.
</para>
<para>
Well, not quite. We want our program to be callable from BASIC,
so we should have a BASIC program at the start. We guess the
size of a simple one line BASIC program to be about 16 bytes.
Thus, we start our program at memory location 2064 ($0810), and
the BASIC program looks like this:
</para>
<programlisting>
10 SYS 2064
</programlisting>
<para>
We <userinput>SAVE</userinput> this program to a file, then
study it in a debugger. It's 15 bytes long:
</para>
<screen>
1070:0100 01 08 0C 08 0A 00 9E 20-32 30 36 34 00 00 00
</screen>
<para>
The first two bytes are the memory location: $0801. The rest of
the data breaks down as follows:
</para>
<table frame="all">
<title>BASIC program breakdown</title>
<tgroup cols='2'>
<thead>
<row>
<entry align="center">Memory Locations</entry>
<entry align="center">Value</entry>
</row>
</thead>
<tbody>
<row><entry>$0801-$0802</entry><entry>2-byte pointer to the next line of BASIC code ($080C).</entry></row>
<row><entry>$0803-$0804</entry><entry>2-byte line number ($000A = 10).</entry></row>
<row><entry>$0805</entry><entry>Byte code for the <userinput>SYS</userinput> command.</entry></row>
<row><entry>$0806-$080A</entry><entry>The rest of the line, which is just the string <quote> 2064</quote>.</entry></row>
<row><entry>$080B</entry><entry>Null byte, terminating the line.</entry></row>
<row><entry>$080C-$080D</entry><entry>2-byte pointer to the next line of BASIC code ($0000 = end of program).</entry></row>
</tbody>
</tgroup>
</table>
<para>
That's 13 bytes. We started at 2049, so we need 2 more bytes of
filler to make our code actually start at location 2064. These
17 bytes will give us the file format and the BASIC code we need
to have our machine language program run.
</para>
<para>
These are just bytes&mdash;indistinguishable from any other sort of
data. In Ophis, bytes of data are specified with
the <literal>.byte</literal> command. We'll also have to tell
Ophis what the program counter should be, so that it knows what
values to assign to our labels. The <literal>.org</literal>
(origin) command tells Ophis this. Thus, the Ophis code for our
header and linking info is:
</para>
<programlisting>
.byte $01, $08, $0C, $08, $0A, $00, $9E, $20
.byte $32, $30, $36, $34, $00, $00, $00, $00
.byte $00, $00
.org $0810
</programlisting>
<para>
This gets the job done, but it's completely incomprehensible,
and it only uses two directives&mdash;not very good for a
tutorial. Here's a more complicated, but much clearer, way of
saying the same thing.
</para>
<programlisting>
.word $0801
.org $0801
.word next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
next: .word 0 ; End of program
.advance 2064
</programlisting>
<para>
This code has many advantages over the first.
<itemizedlist>
<listitem><para> It describes better what is actually
happening. The <literal>.word</literal> directive at the
beginning indicates a 16-bit value stored in the typical
65xx way (small byte first). This is followed by
an <literal>.org</literal> statement, so we let the
assembler know right away where everything is supposed to
be.
</para></listitem>
<listitem><para> Instead of hardcoding in the value $080C, we
instead use a label to identify the location it's pointing
to. Ophis will compute the address
of <literal>next</literal> and put that value in as data.
We also describe the line number in decimal since BASIC
line numbers generally <emphasis>are</emphasis> in decimal.
Labels are defined by putting their name, then a colon, as
seen in the definition of <literal>next</literal>.
</para></listitem>
<listitem><para>
Instead of putting in the hex codes for the string part of
the BASIC code, we included the string directly. Each
character in the string becomes one byte.
</para></listitem>
<listitem><para>
Instead of adding the buffer ourselves, we
used <literal>.advance</literal>, which outputs zeros until
the specified address is reached. Attempting
to <literal>.advance</literal> backwards produces an
assemble-time error.
</para></listitem>
<listitem><para>
It has comments that explain what the data are for. The
semicolon is the comment marker; everything from a semicolon
to the end of the line is ignored.
</para></listitem>
</itemizedlist>
</para>
</section>
<section>
<title>Related commands and options</title>
<para>
This code includes constants that are both in decimal and in
hex. It is also possible to specify constants in octal, binary,
or with an ASCII character.
<itemizedlist>
<listitem><para>To specify decimal constants, simply write the number.</para></listitem>
<listitem><para>To specify hexadecimal constants, put a $ in front.</para></listitem>
<listitem><para>To specify octal constants, put a 0 (zero) in front.</para></listitem>
<listitem><para>To specify binary constants, put a % in front.</para></listitem>
<listitem><para>To specify ASCII constants, put an apostrophe in front.</para></listitem>
</itemizedlist>
Example: 65 = $41 = 0101 = %1000001 = 'A
</para>
<para>
There are other commands besides <literal>.byte</literal>
and <literal>.word</literal> to specify data. In particular,
the <literal>.dword</literal> command specifies four-byte values
which some applications will find useful. Also, some linking
formats (such as the <filename>SID</filename> format) have
header data in big-endian (high byte first) format.
The <literal>.wordbe</literal> and <literal>.dwordbe</literal>
directives provide a way to specify multibyte constants in
big-endian formats cleanly.
</para>
</section>
<section>
<title>Writing the actual code</title>
<para>
Now that we have our header information, let's actually write
the <quote>Hello world</quote> program. It's pretty
short&mdash;a simple loop that steps through a hardcoded array
until it reaches a 0 or outputs 256 characters. It then returns
control to BASIC with an <literal>RTS</literal> statement.
</para>
<para>
Each character in the array is passed as an argument to a
subroutine at memory location $FFD2. This is part of the
Commodore 64's BIOS software, which its development
documentation calls the KERNAL. Location $FFD2 prints out the
character corresponding to the character code in the
accumulator.
</para>
<programlisting>
ldx #0
loop: lda hello, x
beq done
jsr $ffd2
inx
bne loop
done: rts
hello: .byte "HELLO, WORLD!", 0
</programlisting>
<para>
The complete, final source is available in
the <xref linkend="tutor1-src" endterm="tutor1-fname"> file.
</para>
</section>
<section>
<title>Assembling the code</title>
<para>
The Ophis assembler is a collection of Python modules,
controlled by a master script. On Windows, this should all
have been combined into an executable
file <command>ophis.exe</command>; on other platforms, the
Ophis modules should be in the library and
the <command>ophis</command> script should be in your path.
Typing <command>ophis</command> with no arguments should give a
summary of available command line options.
</para>
<table frame="all">
<title>Ophis Options</title>
<tgroup cols='2'>
<thead>
<row>
<entry align="center">Option</entry>
<entry align="center">Effect</entry>
</row>
</thead>
<tbody>
<row><entry><option>-6510</option></entry><entry>Allows the 6510 undocumented opcodes as listed in the VICE documentation.</entry></row>
<row><entry><option>-65c02</option></entry><entry>Allows opcodes and addressing modes added by the 65C02.</entry></row>
<row><entry><option>-v 0</option></entry><entry>Quiet operation. Only reports errors.</entry></row>
<row><entry><option>-v 1</option></entry><entry>Default operation. Reports files as they are loaded, and gives statistics on the final output.</entry></row>
<row><entry><option>-v 2</option></entry><entry>Verbose operation. Names each assembler pass as it runs.</entry></row>
<row><entry><option>-v 3</option></entry><entry>Debug operation: Dumps the entire IR after each pass.</entry></row>
<row><entry><option>-v 4</option></entry><entry>Full debug operation: Dumps the entire IR and symbol table after each pass.</entry></row>
</tbody>
</tgroup>
</table>
<para>
The only options Ophis demands are an input file and an output
file. Here's a sample session, assembling the tutorial file
here:
</para>
<screen>
localhost$ ophis tutor1.oph tutor1.prg -v 2
Loading tutor1.oph
Running: Macro definition pass
Running: Macro expansion pass
Running: Label initialization pass
Fixpoint failed, looping back
Running: Label initialization pass
Running: Circularity check pass
Running: Expression checking pass
Running: Easy addressing modes pass
Running: Label Update Pass
Fixpoint failed, looping back
Running: Label Update Pass
Running: Instruction Collapse Pass
Running: Mode Normalization pass
Running: Label Update Pass
Running: Assembler
Assembly complete: 45 bytes output (14 code, 29 data, 2 filler)
</screen>
<para>
If your emulator can run <filename>PRG</filename> files
directly, this file will now run (and
print <computeroutput>HELLO, WORLD!</computeroutput>) as many
times as you type <userinput>RUN</userinput>. Otherwise, use
a <filename>D64</filename> management utility to put
the <filename>PRG</filename> on a <filename>D64</filename>, then
load and run the file off that.
</para>
</section>
</chapter>

107
doc/docbook/tutor2.sgm Normal file
View File

@ -0,0 +1,107 @@
<chapter>
<title>Labels and aliases</title>
<para>
Labels are an important part of your code. However, since each
label must normally be unique, this can lead to <quote>namespace
pollution,</quote> and you'll find yourself going through ever
more contorted constructions to generate unique label names.
Ophis offers two solutions to this: <emphasis>anonymous
labels</emphasis> and <emphasis>temporary labels</emphasis>. This
tutorial will cover both of these facilities, and also introduce
the aliasing mechanism.
</para>
<section>
<title>Temporary labels</title>
<para>
Temporary labels are the easiest to use. If a label begins with
an underscore, it will only be reachable from inside the
innermost enclosing scope. Scopes begin when
a <literal>.scope</literal> statement is encountered. This
produces a new, inner scope if there is another scope in use.
The <literal>.scend</literal> command ends the innermost
currently active scope.
</para>
<para>
We can thus rewrite our header data using temporary labels, thus
allowing the main program to have a label
named <literal>next</literal> if it wants.
</para>
<programlisting>
.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance 2064
</programlisting>
</section>
<section>
<title>Anonymous labels</title>
<para>
Anonymous labels are a way to handle short-ranged branches
without having to come up with names for the then and else
branches, for brief loops, and other such purposes. To define
an anonymous label, use an asterisk. To refer to an anonymous
label, use a series of <literal>+</literal>
or <literal>-</literal> signs. <literal>+</literal> refers to
the next anonymous label, <literal>++</literal> the label
after that, etc. Likewise, <literal>-</literal> is the most
recently defined label, <literal>--</literal> the one before
that, and so on. The main body of the Hello World program
with anonymous labels would be:
</para>
<programlisting>
ldx #0
* lda hello, x
beq +
jsr $ffd2
inx
bne -
* rts
</programlisting>
<para>
It is worth noting that anonymous labels are globally available.
They are not temporary labels, and they ignore scoping
restrictions.
</para>
</section>
<section>
<title>Aliasing</title>
<para>
Rather the reverse of anonymous labels, aliases are names
given to specific memory locations. These make it easier to
keep track of important constants or locations. The KERNAL
routines are a good example of constants that deserve names.
To assign the traditional name <literal>chrout</literal> to
the routine at $FFD2, simply give the directive:
</para>
<programlisting>
.alias chrout $ffd2
</programlisting>
<para>And change the <userinput>jsr</userinput> command
to:</para>
<programlisting>
jsr chrout
</programlisting>
<para>
The final version of the code is in <xref linkend="tutor2-src" endterm="tutor2-fname">. It should
assemble to exactly the same program as <xref linkend="tutor1-src" endterm="tutor1-fname">.
</para>
</section>
</chapter>

160
doc/docbook/tutor3.sgm Normal file
View File

@ -0,0 +1,160 @@
<chapter id="ch3-link">
<title>Headers, Libraries, and Macros</title>
<para>
In this chapter we will split away parts of our <quote>Hello
World</quote> program into reusable header files and libraries.
We will also abstract away our string printing technique into a
macro which may be invoked at will, on arbitrary strings. We will
then multiply the output of our program tenfold.
</para>
<section>
<title>Header files and libraries</title>
<para>
The prelude to our program&mdash;the <filename>PRG</filename>
information and the BASIC program&mdash;are going to be the same
in many, many programs. Thus, we should put them into a header
file to be included later. The <literal>.include</literal>
directive will load a file and insert it as source at the
designated point.
</para>
<para>
A related directive, <literal>.require</literal>, will include
the file as long as it hasn't been included yet elsewhere. It
is useful for ensuring a library is linked in.
</para>
<para>
For pre-assembled code or raw binary data,
the <literal>.incbin</literal> directive lets you include the
contents of a binary file directly in the output. This is handy
for linking in pre-created graphics or sound data.
</para>
<para>
As a sample library, we will expand the definition of
the <literal>chrout</literal> routine to include the standard
names for every KERNAL routine. Our header file will
then <literal>.require</literal> it.
</para>
<para>
We'll also add some convenience aliases for things like reverse
video, color changes, and shifting between upper case/graphics
and mixed case text. We'd feed those to
the <literal>chrout</literal> routine to get their effects.
</para>
<para>
Since there have been no interesting changes to the prelude, and
the KERNAL values are standard, we do not reproduce them here.
(The files in question are <xref linkend="c64-1-src"
endterm="c64-1-fname"> and <xref linkend="kernal-src"
endterm="kernal-fname">.)
</para>
</section>
<section>
<title>Macros</title>
<para>
A macro is a way of expressing a lot of code or data with a
simple shorthand. It's also usually configurable. Traditional
macro systems such as C's <literal>#define</literal> mechanic
use <emphasis>textual replacement</emphasis>: a macro is
expanded before any evaluation or even parsing occurs.
</para>
<para>
In contrast, Ophis's macro system uses a <emphasis>call by
value</emphasis> approach where the arguments to macros are
evaluated to bytes or words before being inserted into the macro
body. This produces effects much closer to those of a
traditional function call. A more detailed discussion of the
tradeoffs may be found in <xref linkend="ref-link">.
</para>
<section>
<title>Macro definitions</title>
<para>
A macro definition is a set of statements between
a <literal>.macro</literal> statement and
a <literal>.macend</literal> statement.
The <literal>.macro</literal> statement also names the macro
being defined.
</para>
<para>
No global or anonymous labels may be defined inside a macro:
temporary labels only persist in the macro expansion itself.
(Each macro body has its own scope.)
</para>
<para>
Arguments to macros are referred to by number: the first is
<literal>_1</literal>, the second <literal>_2</literal>, and so on.
</para>
<para>
Here's a macro that encapsulates the printing routine in our
<quote>Hello World</quote> program, with an argument being the
address of the string to print:
</para>
<programlisting>
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
</programlisting>
</section>
<section>
<title>Macro invocations</title>
<para>
Macros may be invoked in two ways: one that looks like a
directive, and one that looks like an instruction.
</para>
<para>
The most common way to invoke a macro is to backquote the name
of the macro. It is also possible to use
the <literal>.invoke</literal> command. These commands look
like this:
</para>
<programlisting>
`print msg
.invoke print msg
</programlisting>
<para>
Arguments are passed to the macro as a comma-separated list.
They must all be expressions that evaluate to byte or word
values&mdash;a mechanism similar to <literal>.alias</literal>
is used to assign their values to the <literal>_n</literal>
names.
</para>
</section>
</section>
<section>
<title>Example code</title>
<para>
<xref linkend="tutor3-src" endterm="tutor3-fname"> expands our
running example, including the code above and also defining a
new macro <literal>greet</literal> that takes a string argument
and prints a greeting to it. It then greets far too many
targets.
</para>
</section>
</chapter>

110
doc/docbook/tutor4.sgm Normal file
View File

@ -0,0 +1,110 @@
<chapter id="ch4-link">
<title>Character maps</title>
<para>
Now we will close the gap between the Commodore's
version of ASCII and the real one. We'll also add a time-delay
routine to slow down the output. This routine isn't really of
interest to us right now, so we'll add a subroutine
called <literal>delay</literal> that executes 2,560*(accumulator)
<userinput>NOP</userinput>s. By the time the program is finished,
we'll have executed 768,000 no-ops.
</para>
<para>
There actually are better ways of getting a time-delay on the
Commodore 64; we'll deal with those in <xref linkend="ch5-link">.
As a result, there isn't really a lot to discuss here. The later
tutorials will be building off of <xref linkend="tutor4a-src"
endterm="tutor4a-fname">, so you may want to get familiar with
that. Note also the change to the body of
the <literal>greet</literal> macro.
</para>
<para>
On to the topic at hand. Let's change the code to use mixed case.
We defined the <literal>upper'case</literal>
and <literal>lower'case</literal> aliases back
in <xref linkend="ch3-link"> as part of the
standard <xref linkend="kernal-src" endterm="kernal-fname">
header, so we can add this before our invocations of
the <literal>greet</literal> macro:
</para>
<programlisting>
lda #lower'case
jsr chrout
</programlisting>
<para>
And that will put us into mixed case mode. So, now we just need
to redefine the data so that it uses the mixed-case:
</para>
<programlisting>
hello1: .byte "Hello, ",0
hello2: .byte "!", 13, 0
target1: .byte "programmer", 0
target2: .byte "room", 0
target3: .byte "building", 0
target4: .byte "neighborhood", 0
target5: .byte "city", 0
target6: .byte "nation", 0
target7: .byte "world", 0
target8: .byte "Solar System", 0
target9: .byte "Galaxy", 0
target10: .byte "Universe", 0
</programlisting>
<para>
The code that does this is in <xref linkend="tutor4b-src"
endterm="tutor4b-fname">. If you assemble and run it, you will
notice that the output is not what we want. In particular, upper
and lowercase are reversed, so we have messages
like <computeroutput>hELLO, sOLAR sYSTEM!</computeroutput>. For
the specific case of PETSCII, we can just fix our strings, but
that's less of an option if we're writing for the Apple II's
character set, or targeting a game console that puts its letters
in arbitrary locations. We need to remap how strings are turned
into byte values. The <literal>.charmap</literal>
and <literal>.charmapbin</literal> directives do what we need.
</para>
<para>
The <literal>.charmap</literal> directive usually takes two
arguments; a byte (usually in character form) indicating the ASCII
value to start remapping from, and then a string giving the new
values. To do our case-swapping, we write two directives before
defining any string constants:
</para>
<programlisting>
.charmap 'A, "abcdefghijklmnopqrstuvwxyz"
.charmap 'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
</programlisting>
<para>
Note that the <literal>'a</literal> constant in the second
directive refers to the <quote>a</quote> character in the source,
not in the current map.
</para>
<para>
The fixed code is in <xref linkend="tutor4c-src"
endterm="tutor4c-fname">, and will produce the expected results
when run.
</para>
<para>
An alternative is to use a <literal>.charmapbin</literal>
directive to replace the entire character map directly. This
specifies an external file, 256 bytes long, that is loaded in at
that point. A binary character map for the Commodore 64 is
provided with the sample programs
as <filename>petscii.map</filename>. There are also three
files, <filename>a2normal.map</filename>, <filename>a2inverse.map</filename>,
and <filename>a2blink.map</filename> that handle the Apple II's
very nonstandard character encodings.
</para>
</chapter>

157
doc/docbook/tutor5.sgm Normal file
View File

@ -0,0 +1,157 @@
<chapter id="ch5-link">
<title>Local variables and memory segments</title>
<para>
As mentioned in <xref linkend="ch4-link">, there are better ways
to handle waiting than just executing vast numbers of NOPs. The
Commodore 64 KERNAL library includes a <literal>rdtim</literal>
routine that returns the uptime of the machine, in
60<superscript>th</superscript>s of a second, as a 24-bit integer.
The Commodore 64 programmer's guide available online actually has
a bug in it, reversing the significance of the A and Y registers.
The accumulator holds the <emphasis>least</emphasis> significant
byte, not the most.
</para>
<para>
Here's a first shot at a better delay routine:
</para>
<programlisting>
.scope
; data used by the delay routine
_tmp: .byte 0
_target: .byte 0
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
</programlisting>
<para>
This works, but it eats up two bytes of file space that don't
really need to be specified. Also, it's modifying data inside a
program text area, which isn't good if you're assembling to a ROM
chip. (Since the Commodore 64 stores its programs in RAM, it's
not an issue for us here.) A slightly better solution is to
use <literal>.alias</literal> to assign the names to chunks of RAM
somewhere. There's a 4K chunk of RAM from $C000 through $CFFF
between the BASIC ROM and the I/O ROM that should serve our
purposes nicely. We can replace the definitions
of <literal>_tmp</literal> and <literal>_target</literal> with:
</para>
<programlisting>
; data used by the delay routine
.alias _tmp $C000
.alias _target $C001
</programlisting>
<para>
This works better, but now we've just added a major bookkeeping
burden upon ourselves&mdash;we must ensure that no routines step on
each other. What we'd really like are two separate program
counters&mdash;one for the program text, and one for our variable
space.
</para>
<para>
Ophis lets us do this with the <literal>.text</literal>
and <literal>.data</literal> commands.
The <literal>.text</literal> command switches to the program-text
counter, and the <literal>.data</literal> command switches to the
variable-data counter. When Ophis first starts assembling a file,
it starts in <literal>.text</literal> mode.
</para>
<para>
To reserve space for a variable, use the .space command. This
takes the form:
<programlisting>
.space varname size
</programlisting>
which assigns the name <literal>varname</literal> to the current
program counter, then advances the program counter by the amount
specified in <literal>size</literal>. Nothing is output to the
final binary as a result of the <literal>.space</literal> command.
</para>
<para>
You may not put in any commands that produce output into
a <literal>.data</literal> segment. Generally, all you will be
using are <literal>.org</literal> and <literal>.space</literal>
commands. Ophis will not complain if you
use <literal>.space</literal> inside a <literal>.text</literal>
segment, but this is nearly always wrong.
</para>
<para>
The final version of <literal>delay</literal> looks like this:
</para>
<programlisting>
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
</programlisting>
<para>
We're not quite done yet, however, because we have to tell the
data segment where to begin. (If we don't, it starts at 0, which
is usually wrong.) We add a very brief data segment to the top of
our code:
</para>
<programlisting>
.data
.org $C000
.text
</programlisting>
<para>
This will run. However, we also ought to make sure that we aren't
overstepping any boundaries. Our program text shouldn't run into
the BASIC chip at $A000, and our data shouldn't run into the I/O
region at $D000. The <literal>.checkpc</literal> command lets us
assert that the program counter hasn't reached a specific point
yet. We put, at the end of our code:
</para>
<programlisting>
.checkpc $A000
.data
.checkpc $D000
</programlisting>
<para>
The final program is available as <xref linkend="tutor5-src"
endterm="tutor5-fname">. Note that we based this on the
all-uppercase version from the last section, not any of the
charmapped versions.
</para>
</chapter>

118
doc/docbook/tutor6.sgm Normal file
View File

@ -0,0 +1,118 @@
<chapter>
<title>Expressions</title>
<para>
Ophis permits a reasonably rich set of arithmetic operations to be
done at assemble time. So far, all of our arguments and values
have either been constants or label names. In this chapter, we
will modify the <literal>print</literal> macro so that it calls a
subroutine to do the actual printing. This will shrink the final
code size a fair bit.
</para>
<para>
Here's our printing routine. It's fairly straightforward.
</para>
<programlisting>
; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
printstr:
sta $10
stx $11
ldy #$00
_lp: lda ($10), y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend
</programlisting>
<para>
However, now we are faced with the problem of what to do with
the <literal>print</literal> macro. We need to take a 16-bit
value and store it in two 8-bit registers. We can use
the <literal>&lt;</literal> and <literal>&gt;</literal> operators
to take the low or high byte of a word, respectively.
The <literal>print</literal> macro becomes:
</para>
<programlisting>
.macro print
lda #&lt;_1
ldx #&gt;_1
jsr printstr
.macend
</programlisting>
<para>
Also, since BASIC uses the locations $10 and $11, we should really
cache them at the start of the program and restore them at the
end:
</para>
<programlisting>
.data
.org $C000
.space cache 2
.text
; Save the zero page locations that printstr uses.
lda $10
sta cache
lda $11
sta cache+1
; ... main program goes here ...
; Restore the zero page values printstr uses.
lda cache
sta $10
lda cache+1
sta $11
</programlisting>
<para>
Note that we only have to name <literal>cache</literal> once, but
can use addition to refer to any offset from it.
</para>
<para>
Ophis supports following operations, with the following precedence
levels (higher entries bind more tightly):
</para>
<table frame="all">
<title>Ophis Operators</title>
<tgroup cols='2'>
<thead>
<row>
<entry align="center">Operators</entry>
<entry align="center">Description</entry>
</row>
</thead>
<tbody>
<row><entry><literal>[ ]</literal></entry><entry>Parenthesized expressions</entry></row>
<row><entry><literal>&lt; &gt;</literal></entry><entry>Byte selection (low, high)</entry></row>
<row><entry><literal>* /</literal></entry><entry>Multiply, divide</entry></row>
<row><entry><literal>+ -</literal></entry><entry>Add, subtract</entry></row>
<row><entry><literal>| &amp; ^</literal></entry><entry>Bitwise OR, AND, XOR</entry></row>
</tbody>
</tgroup>
</table>
<para>
Note that brackets, not parentheses, are used to group arithmetic
operations. This is because parentheses are used for the indirect
addressing modes, and it makes parsing much easier.
</para>
<para>
The code for this version of the code is
in <xref linkend="tutor6-src" endterm="tutor6-fname">.
</para>
</chapter>

143
doc/docbook/tutor7.sgm Normal file
View File

@ -0,0 +1,143 @@
<chapter>
<title>Advanced Memory Segments</title>
<para>
This is the last section of the Ophis tutorial. By now we've
covered the basics of every command in the assembler; in this
final installment we show the full capabilities of
the <literal>.text</literal> and <literal>.data</literal> commands
as we produce a final set of Commodore 64 header files.
</para>
<section>
<title>The Problem</title>
<para>
Our <literal>print'str</literal> routine
in <xref linkend="tutor6-src" endterm="tutor6-fname"> accesses
memory locations $10 and $11 directly. We'd prefer to have
symbolic names for them. This reprises our concerns back in
<xref linkend="ch5-link"> when we concluded that we wanted two
separate program counters. Now we realize that we really need
three; one for the text, one for the data, and one for the zero
page data. And if we're going to allow three, we really should
allow any number.
</para>
</section>
<section>
<title>The Solution</title>
<para>
The <literal>.data</literal> and <literal>.text</literal>
commands can take a label name after them&mdash;this names a new
segment. We'll define a new segment
called <literal>zp</literal> (for <quote>zero page</quote>) and
have our zero-page variables be placed there. We can't actually
use the default origin of $0000 here either, though, because the
Commodore 64 reserves memory locations 0 and 1 to control its
memory mappers:
</para>
<programlisting>
.data zp
.org $0002
</programlisting>
<para>
Now, actually, the rest of the zero page is reserved too:
locations $02-$7F are used by the BASIC interpreter, and
locations $80-$FF are used by the KERNAL. We don't need the
BASIC interpreter, though, so we can back up all of $02-$7F at
the start of our program and restore it all when we're done:
</para>
<programlisting>
.scope
; Cache BASIC's zero page at top of available RAM.
ldx #$7E
* lda $01, x
sta $CF81, x
dex
bne -
jsr _main
; Restore BASIC's zero page and return control.
ldx #$7E
* lda $CF81, x
sta $01, x
dex
bne -
rts
_main:
; _main points at the start of the real program,
; which is actually outside of this scope
.scend
</programlisting>
<para>
The new, improved header file is <xref linkend="c64-2-src"
endterm="c64-2-fname">.
</para>
<para>
Our <literal>print'str</literal> routine is then rewritten to
declare and use a zero-page variable, like so:
</para>
<programlisting>
; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
.data zp
.space _ptr 2
.text
printstr:
sta _ptr
stx _ptr+1
ldy #$00
_lp: lda (_ptr),y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend
</programlisting>
<para>
Also, we ought to put in an extra check to make sure our
zero-page allocations don't overflow, either:
</para>
<programlisting>
.data zp
.checkpc $80
</programlisting>
<para>
That concludes our tour. The final source file
is <xref linkend="tutor7-src" endterm="tutor7-fname">.
</para>
</section>
<section>
<title>Where to go from here</title>
<para>
This tutorial has touched on everything that the assembler can
do, but it's not really well organized as a
reference. <xref linkend="ref-link"> is a better place to look
up matters of syntax or consult lists of available commands.
</para>
<para>
If you're looking for projects to undertake, the Commodore 64
and Atari 2600 development communities are both very strong, and
the Apple II and NES development communities are still alive and
well as well. There's an annual Minigame Competition that's
always looking for new entries.
</para>
</section>
</chapter>

67
doc/kernal.oph Normal file
View File

@ -0,0 +1,67 @@
; KERNAL routine aliases (C64)
.alias acptr $ffa5
.alias chkin $ffc6
.alias chkout $ffc9
.alias chrin $ffcf
.alias chrout $ffd2
.alias ciout $ffa8
.alias cint $ff81
.alias clall $ffe7
.alias close $ffc3
.alias clrchn $ffcc
.alias getin $ffe4
.alias iobase $fff3
.alias ioinit $ff84
.alias listen $ffb1
.alias load $ffd5
.alias membot $ff9c
.alias memtop $ff99
.alias open $ffc0
.alias plot $fff0
.alias ramtas $ff87
.alias rdtim $ffde
.alias readst $ffb7
.alias restor $ff8a
.alias save $ffd8
.alias scnkey $ff9f
.alias screen $ffed
.alias second $ff93
.alias setlfs $ffba
.alias setmsg $ff90
.alias setnam $ffbd
.alias settim $ffdb
.alias settmo $ffa2
.alias stop $ffe1
.alias talk $ffb4
.alias tksa $ff96
.alias udtim $ffea
.alias unlsn $ffae
.alias untlk $ffab
.alias vector $ff8d
; Character codes for the colors.
.alias color'0 144
.alias color'1 5
.alias color'2 28
.alias color'3 159
.alias color'4 156
.alias color'5 30
.alias color'6 31
.alias color'7 158
.alias color'8 129
.alias color'9 149
.alias color'10 150
.alias color'11 151
.alias color'12 152
.alias color'13 153
.alias color'14 154
.alias color'15 155
; ...and reverse video
.alias reverse'on 18
.alias reverse'off 146
; ...and character set
.alias upper'case 142
.alias lower'case 14

7725
doc/ophismanual.pdf Normal file

File diff suppressed because one or more lines are too long

BIN
doc/petscii.map Normal file

Binary file not shown.

18
doc/tutor1.oph Normal file
View File

@ -0,0 +1,18 @@
.word $0801
.org $0801
.word next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
next: .word 0 ; End of program
.advance 2064
ldx #0
loop: lda hello, x
beq done
jsr $ffd2
inx
bne loop
done: rts
hello: .byte "HELLO, WORLD!", 0

22
doc/tutor2.oph Normal file
View File

@ -0,0 +1,22 @@
.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance 2064
.alias chrout $ffd2
ldx #0
* lda hello, x
beq +
jsr chrout
inx
bne -
* rts
hello: .byte "HELLO, WORLD!", 0

45
doc/tutor3.oph Normal file
View File

@ -0,0 +1,45 @@
.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0

69
doc/tutor4a.oph Normal file
View File

@ -0,0 +1,69 @@
.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts

71
doc/tutor4b.oph Normal file
View File

@ -0,0 +1,71 @@
.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
lda #lower'case
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "Hello, ",0
hello2: .byte "!", 13, 0
target1: .byte "programmer", 0
target2: .byte "room", 0
target3: .byte "building", 0
target4: .byte "neighborhood", 0
target5: .byte "city", 0
target6: .byte "nation", 0
target7: .byte "world", 0
target8: .byte "Solar System", 0
target9: .byte "Galaxy", 0
target10: .byte "Universe", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts

73
doc/tutor4c.oph Normal file
View File

@ -0,0 +1,73 @@
.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
lda #lower'case
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
.charmap 'A, "abcdefghijklmnopqrstuvwxyz"
.charmap 'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
hello1: .byte "Hello, ",0
hello2: .byte "!", 13, 0
target1: .byte "programmer", 0
target2: .byte "room", 0
target3: .byte "building", 0
target4: .byte "neighborhood", 0
target5: .byte "city", 0
target6: .byte "nation", 0
target7: .byte "world", 0
target8: .byte "Solar System", 0
target9: .byte "Galaxy", 0
target10: .byte "Universe", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts

75
doc/tutor5.oph Normal file
View File

@ -0,0 +1,75 @@
.include "c64-1.oph"
.data
.org $C000
.text
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
.checkpc $A000
.data
.checkpc $D000

102
doc/tutor6.oph Normal file
View File

@ -0,0 +1,102 @@
.include "c64-1.oph"
.data
.org $C000
.space cache 2
.text
.macro print
lda #<_1
ldx #>_1
jsr printstr
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
; Save the zero page locations that PRINTSTR uses.
lda $10
sta cache
lda $11
sta cache+1
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
; Restore the zero page values printstr uses.
lda cache
sta $10
lda cache+1
sta $11
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
printstr:
sta $10
stx $11
ldy #$00
_lp: lda ($10),y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend
.checkpc $A000
.data
.checkpc $D000

96
doc/tutor7.oph Normal file
View File

@ -0,0 +1,96 @@
.include "c64-2.oph"
.data
.org $C000
.text
.macro print
lda #<_1
ldx #>_1
jsr printstr
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
.data zp
.space _ptr 2
.text
printstr:
sta _ptr
stx _ptr+1
ldy #$00
_lp: lda (_ptr),y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend
.checkpc $A000
.data
.checkpc $D000
.data zp
.checkpc $80

32
site/index.html Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head><title>The Ophis Assembler</title></head>
<body>
<h1>The Ophis Assembler</h1>
<p>Ophis is a cross-assembler for the 65xx series of chips. It supports the stock 6502 opcodes, the 65c02 extensions, and syntax for the "undocumented opcodes" in the 6510 chip used on the Commodore 64. (Syntax for these opcodes matches those given in the <a href="http://www.viceteam.org">VICE team's documentation</a>.)</p>
<p>Ophis is written in pure Python and should be highly portable.</p>
<p>If you have questions or comments, email me at <i>mcmartin AT gmail DOT com</i>.</p>
<h2>Downloads</h2>
<ul>
<li><a href="Ophis-1.0.tar.gz">Source distribution</a>. For Unix and Mac. Untar, then run "python setup.py install" as root to install. Documentation and sample code is in the tarball but won't be placed anywhere special.</li>
<li><a href="http://hkn.eecs.berkeley.edu/~mcmartin/ophis/Ophis-1.0-win32-installer.exe">Win32 installer</a>. Installs a standalone executable and support libraries. You will need to put the install directory into your PATH to run it conveniently, as it is a commandline program.</li>
</ul>
<h2>Documentation</h2>
<p>The manual <i>Programming with Ophis</i> is distributed with each download. You can also get it alone.</p>
<ul>
<li><a href="ophismanual.pdf">Download the PDF version of <i>Programming with Ophis</i></a></li>
<li><a href="manual/book1.html">Browse <i>Programming with Ophis</i> online</a></li>
</ul>
</body>
</html>

184
site/manual/a454.html Normal file
View File

@ -0,0 +1,184 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Example Programs</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Where to go from here"
HREF="x449.html"><LINK
REL="NEXT"
TITLE="tutor2.oph"
HREF="x461.html"></HEAD
><BODY
CLASS="APPENDIX"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x449.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x461.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="APPENDIX"
><H1
><A
NAME="AEN454"
></A
>Example Programs</H1
><P
> This Appendix collects all the programs referred to in the course
of this manual.
</P
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR1-SRC"
><TT
CLASS="FILENAME"
>tutor1.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.word $0801
.org $0801
.word next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
next: .word 0 ; End of program
.advance 2064
ldx #0
loop: lda hello, x
beq done
jsr $ffd2
inx
bne loop
done: rts
hello: .byte "HELLO, WORLD!", 0</PRE
></TD
></TR
></TABLE
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x449.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x461.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Where to go from here</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor2.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

311
site/manual/a505.html Normal file
View File

@ -0,0 +1,311 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Ophis Command Reference</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="tutor7.oph"
HREF="x501.html"><LINK
REL="NEXT"
TITLE="Basic arguments"
HREF="x572.html"></HEAD
><BODY
CLASS="APPENDIX"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x501.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x572.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="APPENDIX"
><H1
><A
NAME="REF-LINK"
></A
>Ophis Command Reference</H1
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN507"
>Command Modes</A
></H1
><P
> These mostly follow the <I
CLASS="EMPHASIS"
>MOS Technology 6500
Microprocessor Family Programming Manual</I
>, except
for the Accumulator mode. Accumulator instructions are written
and interpreted identically to Implied mode instructions.
</P
><P
></P
><UL
><LI
><P
><I
CLASS="EMPHASIS"
>Implied:</I
> <TT
CLASS="LITERAL"
>RTS</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Accumulator:</I
> <TT
CLASS="LITERAL"
>LSR</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Immediate:</I
> <TT
CLASS="LITERAL"
>LDA #$06</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Zero Page:</I
> <TT
CLASS="LITERAL"
>LDA $7C</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Zero Page, X:</I
> <TT
CLASS="LITERAL"
>LDA $7C,X</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Zero Page, Y:</I
> <TT
CLASS="LITERAL"
>LDA $7C,Y</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Absolute:</I
> <TT
CLASS="LITERAL"
>LDA $D020</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Absolute, X:</I
> <TT
CLASS="LITERAL"
>LDA $D000,X</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Absolute, Y:</I
> <TT
CLASS="LITERAL"
>LDA $D000,Y</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>(Zero Page Indirect, X):</I
> <TT
CLASS="LITERAL"
>LDA ($80, X)</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>(Zero Page Indirect), Y:</I
> <TT
CLASS="LITERAL"
>LDA ($80), Y</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>(Absolute Indirect):</I
> <TT
CLASS="LITERAL"
>JMP ($A000)</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Relative:</I
> <TT
CLASS="LITERAL"
>BNE loop</TT
></P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>(Absolute Indirect, X):</I
> <TT
CLASS="LITERAL"
>JMP ($A000, X)</TT
> &#8212; Only available with 65C02 extensions</P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>(Zero Page Indirect):</I
> <TT
CLASS="LITERAL"
>LDX ($80)</TT
> &#8212; Only available with 65C02 extensions</P
></LI
></UL
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x501.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x572.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor7.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Basic arguments</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

467
site/manual/book1.html Normal file
View File

@ -0,0 +1,467 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Programming with Ophis</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="NEXT"
TITLE="Preface"
HREF="f10.html"></HEAD
><BODY
CLASS="BOOK"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="BOOK"
><A
NAME="AEN1"
></A
><DIV
CLASS="TITLEPAGE"
><H1
CLASS="TITLE"
><A
NAME="AEN2"
>Programming with Ophis</A
></H1
><H3
CLASS="AUTHOR"
><A
NAME="AEN4"
></A
>Michael Martin</H3
><P
CLASS="COPYRIGHT"
>Copyright &copy; 2006-7 Michael Martin</P
><HR></DIV
><DIV
CLASS="TOC"
><DL
><DT
><B
>Table of Contents</B
></DT
><DT
><A
HREF="f10.html"
>Preface</A
></DT
><DD
><DL
><DT
><A
HREF="f10.html#AEN15"
>Why <SPAN
CLASS="QUOTE"
>"Ophis"</SPAN
>?</A
></DT
><DT
><A
HREF="x22.html"
>Getting a copy of Ophis</A
></DT
></DL
></DD
><DT
><A
HREF="c35.html"
>The basics</A
></DT
><DD
><DL
><DT
><A
HREF="c35.html#AEN48"
>A note on numeric notation</A
></DT
><DT
><A
HREF="x51.html"
>Producing Commodore 64 programs</A
></DT
><DT
><A
HREF="x119.html"
>Related commands and options</A
></DT
><DT
><A
HREF="x140.html"
>Writing the actual code</A
></DT
><DT
><A
HREF="x149.html"
>Assembling the code</A
></DT
></DL
></DD
><DT
><A
HREF="c200.html"
>Labels and aliases</A
></DT
><DD
><DL
><DT
><A
HREF="c200.html#AEN206"
>Temporary labels</A
></DT
><DT
><A
HREF="x214.html"
>Anonymous labels</A
></DT
><DT
><A
HREF="x225.html"
>Aliasing</A
></DT
></DL
></DD
><DT
><A
HREF="c236.html"
>Headers, Libraries, and Macros</A
></DT
><DD
><DL
><DT
><A
HREF="c236.html#AEN240"
>Header files and libraries</A
></DT
><DT
><A
HREF="x257.html"
>Macros</A
></DT
><DD
><DL
><DT
><A
HREF="x257.html#AEN265"
>Macro definitions</A
></DT
><DT
><A
HREF="x257.html#AEN278"
>Macro invocations</A
></DT
></DL
></DD
><DT
><A
HREF="x287.html"
>Example code</A
></DT
></DL
></DD
><DT
><A
HREF="c292.html"
>Character maps</A
></DT
><DT
><A
HREF="c329.html"
>Local variables and memory segments</A
></DT
><DT
><A
HREF="c371.html"
>Expressions</A
></DT
><DT
><A
HREF="c419.html"
>Advanced Memory Segments</A
></DT
><DD
><DL
><DT
><A
HREF="c419.html#AEN424"
>The Problem</A
></DT
><DT
><A
HREF="x430.html"
>The Solution</A
></DT
><DT
><A
HREF="x449.html"
>Where to go from here</A
></DT
></DL
></DD
><DT
><A
HREF="a454.html"
>Example Programs</A
></DT
><DD
><DL
><DT
><A
HREF="a454.html#TUTOR1-SRC"
><TT
CLASS="FILENAME"
>tutor1.oph</TT
></A
></DT
><DT
><A
HREF="x461.html"
><TT
CLASS="FILENAME"
>tutor2.oph</TT
></A
></DT
><DT
><A
HREF="x465.html"
><TT
CLASS="FILENAME"
>c64-1.oph</TT
></A
></DT
><DT
><A
HREF="x469.html"
><TT
CLASS="FILENAME"
>kernal.oph</TT
></A
></DT
><DT
><A
HREF="x473.html"
><TT
CLASS="FILENAME"
>tutor3.oph</TT
></A
></DT
><DT
><A
HREF="x477.html"
><TT
CLASS="FILENAME"
>tutor4a.oph</TT
></A
></DT
><DT
><A
HREF="x481.html"
><TT
CLASS="FILENAME"
>tutor4b.oph</TT
></A
></DT
><DT
><A
HREF="x485.html"
><TT
CLASS="FILENAME"
>tutor4c.oph</TT
></A
></DT
><DT
><A
HREF="x489.html"
><TT
CLASS="FILENAME"
>tutor5.oph</TT
></A
></DT
><DT
><A
HREF="x493.html"
><TT
CLASS="FILENAME"
>tutor6.oph</TT
></A
></DT
><DT
><A
HREF="x497.html"
><TT
CLASS="FILENAME"
>c64-2.oph</TT
></A
></DT
><DT
><A
HREF="x501.html"
><TT
CLASS="FILENAME"
>tutor7.oph</TT
></A
></DT
></DL
></DD
><DT
><A
HREF="a505.html"
>Ophis Command Reference</A
></DT
><DD
><DL
><DT
><A
HREF="a505.html#AEN507"
>Command Modes</A
></DT
><DT
><A
HREF="x572.html"
>Basic arguments</A
></DT
><DD
><DL
><DT
><A
HREF="x572.html#AEN575"
>Numeric types</A
></DT
><DT
><A
HREF="x572.html#AEN598"
>Label types</A
></DT
><DT
><A
HREF="x572.html#AEN611"
>String types</A
></DT
></DL
></DD
><DT
><A
HREF="x620.html"
>Compound Arguments</A
></DT
><DT
><A
HREF="x647.html"
>Memory Model</A
></DT
><DD
><DL
><DT
><A
HREF="x647.html#AEN650"
>Basic PC tracking</A
></DT
><DT
><A
HREF="x647.html#AEN659"
>Basic Segmentation simulation</A
></DT
><DT
><A
HREF="x647.html#AEN683"
>General Segmentation Simulation</A
></DT
></DL
></DD
><DT
><A
HREF="x692.html"
>Macros</A
></DT
><DD
><DL
><DT
><A
HREF="x692.html#AEN696"
>Defining Macros</A
></DT
><DT
><A
HREF="x692.html#AEN702"
>Invoking Macros</A
></DT
><DT
><A
HREF="x692.html#AEN710"
>Passing Arguments to Macros</A
></DT
><DT
><A
HREF="x692.html#AEN720"
>Features and Restrictions of the Ophis Macro Model</A
></DT
></DL
></DD
><DT
><A
HREF="x732.html"
>Assembler directives</A
></DT
></DL
></DD
></DL
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="f10.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Preface</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

208
site/manual/c200.html Normal file
View File

@ -0,0 +1,208 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Labels and aliases</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Assembling the code"
HREF="x149.html"><LINK
REL="NEXT"
TITLE="Anonymous labels"
HREF="x214.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x149.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x214.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="AEN200"
></A
>Labels and aliases</H1
><P
> Labels are an important part of your code. However, since each
label must normally be unique, this can lead to <SPAN
CLASS="QUOTE"
>"namespace
pollution,"</SPAN
> and you'll find yourself going through ever
more contorted constructions to generate unique label names.
Ophis offers two solutions to this: <I
CLASS="EMPHASIS"
>anonymous
labels</I
> and <I
CLASS="EMPHASIS"
>temporary labels</I
>. This
tutorial will cover both of these facilities, and also introduce
the aliasing mechanism.
</P
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN206"
>Temporary labels</A
></H1
><P
> Temporary labels are the easiest to use. If a label begins with
an underscore, it will only be reachable from inside the
innermost enclosing scope. Scopes begin when
a <TT
CLASS="LITERAL"
>.scope</TT
> statement is encountered. This
produces a new, inner scope if there is another scope in use.
The <TT
CLASS="LITERAL"
>.scend</TT
> command ends the innermost
currently active scope.
</P
><P
> We can thus rewrite our header data using temporary labels, thus
allowing the main program to have a label
named <TT
CLASS="LITERAL"
>next</TT
> if it wants.
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance 2064</PRE
></TD
></TR
></TABLE
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x149.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x214.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Assembling the code</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Anonymous labels</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

226
site/manual/c236.html Normal file
View File

@ -0,0 +1,226 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Headers, Libraries, and Macros</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Aliasing"
HREF="x225.html"><LINK
REL="NEXT"
TITLE="Macros"
HREF="x257.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x225.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x257.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="CH3-LINK"
></A
>Headers, Libraries, and Macros</H1
><P
> In this chapter we will split away parts of our <SPAN
CLASS="QUOTE"
>"Hello
World"</SPAN
> program into reusable header files and libraries.
We will also abstract away our string printing technique into a
macro which may be invoked at will, on arbitrary strings. We will
then multiply the output of our program tenfold.
</P
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN240"
>Header files and libraries</A
></H1
><P
> The prelude to our program&#8212;the <TT
CLASS="FILENAME"
>PRG</TT
>
information and the BASIC program&#8212;are going to be the same
in many, many programs. Thus, we should put them into a header
file to be included later. The <TT
CLASS="LITERAL"
>.include</TT
>
directive will load a file and insert it as source at the
designated point.
</P
><P
> A related directive, <TT
CLASS="LITERAL"
>.require</TT
>, will include
the file as long as it hasn't been included yet elsewhere. It
is useful for ensuring a library is linked in.
</P
><P
> For pre-assembled code or raw binary data,
the <TT
CLASS="LITERAL"
>.incbin</TT
> directive lets you include the
contents of a binary file directly in the output. This is handy
for linking in pre-created graphics or sound data.
</P
><P
> As a sample library, we will expand the definition of
the <TT
CLASS="LITERAL"
>chrout</TT
> routine to include the standard
names for every KERNAL routine. Our header file will
then <TT
CLASS="LITERAL"
>.require</TT
> it.
</P
><P
> We'll also add some convenience aliases for things like reverse
video, color changes, and shifting between upper case/graphics
and mixed case text. We'd feed those to
the <TT
CLASS="LITERAL"
>chrout</TT
> routine to get their effects.
</P
><P
> Since there have been no interesting changes to the prelude, and
the KERNAL values are standard, we do not reproduce them here.
(The files in question are <A
HREF="x465.html"
><I
><I
>c64-1.oph</I
></I
></A
> and <A
HREF="x469.html"
><I
><I
>kernal.oph</I
></I
></A
>.)
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x225.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x257.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Aliasing</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Macros</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

344
site/manual/c292.html Normal file
View File

@ -0,0 +1,344 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Character maps</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Example code"
HREF="x287.html"><LINK
REL="NEXT"
TITLE="Local variables and memory segments"
HREF="c329.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x287.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c329.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="CH4-LINK"
></A
>Character maps</H1
><P
> Now we will close the gap between the Commodore's
version of ASCII and the real one. We'll also add a time-delay
routine to slow down the output. This routine isn't really of
interest to us right now, so we'll add a subroutine
called <TT
CLASS="LITERAL"
>delay</TT
> that executes 2,560*(accumulator)
<KBD
CLASS="USERINPUT"
>NOP</KBD
>s. By the time the program is finished,
we'll have executed 768,000 no-ops.
</P
><P
> There actually are better ways of getting a time-delay on the
Commodore 64; we'll deal with those in <A
HREF="c329.html"
>the Chapter called <I
>Local variables and memory segments</I
></A
>.
As a result, there isn't really a lot to discuss here. The later
tutorials will be building off of <A
HREF="x477.html"
><I
><I
>tutor4a.oph</I
></I
></A
>, so you may want to get familiar with
that. Note also the change to the body of
the <TT
CLASS="LITERAL"
>greet</TT
> macro.
</P
><P
> On to the topic at hand. Let's change the code to use mixed case.
We defined the <TT
CLASS="LITERAL"
>upper'case</TT
>
and <TT
CLASS="LITERAL"
>lower'case</TT
> aliases back
in <A
HREF="c236.html"
>the Chapter called <I
>Headers, Libraries, and Macros</I
></A
> as part of the
standard <A
HREF="x469.html"
><I
><I
>kernal.oph</I
></I
></A
>
header, so we can add this before our invocations of
the <TT
CLASS="LITERAL"
>greet</TT
> macro:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
> lda #lower'case
jsr chrout</PRE
></TD
></TR
></TABLE
><P
> And that will put us into mixed case mode. So, now we just need
to redefine the data so that it uses the mixed-case:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>hello1: .byte "Hello, ",0
hello2: .byte "!", 13, 0
target1: .byte "programmer", 0
target2: .byte "room", 0
target3: .byte "building", 0
target4: .byte "neighborhood", 0
target5: .byte "city", 0
target6: .byte "nation", 0
target7: .byte "world", 0
target8: .byte "Solar System", 0
target9: .byte "Galaxy", 0
target10: .byte "Universe", 0</PRE
></TD
></TR
></TABLE
><P
> The code that does this is in <A
HREF="x481.html"
><I
><I
>tutor4b.oph</I
></I
></A
>. If you assemble and run it, you will
notice that the output is not what we want. In particular, upper
and lowercase are reversed, so we have messages
like <SAMP
CLASS="COMPUTEROUTPUT"
>hELLO, sOLAR sYSTEM!</SAMP
>. For
the specific case of PETSCII, we can just fix our strings, but
that's less of an option if we're writing for the Apple II's
character set, or targeting a game console that puts its letters
in arbitrary locations. We need to remap how strings are turned
into byte values. The <TT
CLASS="LITERAL"
>.charmap</TT
>
and <TT
CLASS="LITERAL"
>.charmapbin</TT
> directives do what we need.
</P
><P
> The <TT
CLASS="LITERAL"
>.charmap</TT
> directive usually takes two
arguments; a byte (usually in character form) indicating the ASCII
value to start remapping from, and then a string giving the new
values. To do our case-swapping, we write two directives before
defining any string constants:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.charmap 'A, "abcdefghijklmnopqrstuvwxyz"
.charmap 'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"</PRE
></TD
></TR
></TABLE
><P
> Note that the <TT
CLASS="LITERAL"
>'a</TT
> constant in the second
directive refers to the <SPAN
CLASS="QUOTE"
>"a"</SPAN
> character in the source,
not in the current map.
</P
><P
> The fixed code is in <A
HREF="x485.html"
><I
><I
>tutor4c.oph</I
></I
></A
>, and will produce the expected results
when run.
</P
><P
> An alternative is to use a <TT
CLASS="LITERAL"
>.charmapbin</TT
>
directive to replace the entire character map directly. This
specifies an external file, 256 bytes long, that is loaded in at
that point. A binary character map for the Commodore 64 is
provided with the sample programs
as <TT
CLASS="FILENAME"
>petscii.map</TT
>. There are also three
files, <TT
CLASS="FILENAME"
>a2normal.map</TT
>, <TT
CLASS="FILENAME"
>a2inverse.map</TT
>,
and <TT
CLASS="FILENAME"
>a2blink.map</TT
> that handle the Apple II's
very nonstandard character encodings.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x287.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c329.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Example code</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Local variables and memory segments</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

402
site/manual/c329.html Normal file
View File

@ -0,0 +1,402 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Local variables and memory segments</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Character maps"
HREF="c292.html"><LINK
REL="NEXT"
TITLE="Expressions"
HREF="c371.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c292.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c371.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="CH5-LINK"
></A
>Local variables and memory segments</H1
><P
> As mentioned in <A
HREF="c292.html"
>the Chapter called <I
>Character maps</I
></A
>, there are better ways
to handle waiting than just executing vast numbers of NOPs. The
Commodore 64 KERNAL library includes a <TT
CLASS="LITERAL"
>rdtim</TT
>
routine that returns the uptime of the machine, in
60<SUP
>th</SUP
>s of a second, as a 24-bit integer.
The Commodore 64 programmer's guide available online actually has
a bug in it, reversing the significance of the A and Y registers.
The accumulator holds the <I
CLASS="EMPHASIS"
>least</I
> significant
byte, not the most.
</P
><P
> Here's a first shot at a better delay routine:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.scope
; data used by the delay routine
_tmp: .byte 0
_target: .byte 0
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend</PRE
></TD
></TR
></TABLE
><P
> This works, but it eats up two bytes of file space that don't
really need to be specified. Also, it's modifying data inside a
program text area, which isn't good if you're assembling to a ROM
chip. (Since the Commodore 64 stores its programs in RAM, it's
not an issue for us here.) A slightly better solution is to
use <TT
CLASS="LITERAL"
>.alias</TT
> to assign the names to chunks of RAM
somewhere. There's a 4K chunk of RAM from $C000 through $CFFF
between the BASIC ROM and the I/O ROM that should serve our
purposes nicely. We can replace the definitions
of <TT
CLASS="LITERAL"
>_tmp</TT
> and <TT
CLASS="LITERAL"
>_target</TT
> with:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
> ; data used by the delay routine
.alias _tmp $C000
.alias _target $C001</PRE
></TD
></TR
></TABLE
><P
> This works better, but now we've just added a major bookkeeping
burden upon ourselves&#8212;we must ensure that no routines step on
each other. What we'd really like are two separate program
counters&#8212;one for the program text, and one for our variable
space.
</P
><P
> Ophis lets us do this with the <TT
CLASS="LITERAL"
>.text</TT
>
and <TT
CLASS="LITERAL"
>.data</TT
> commands.
The <TT
CLASS="LITERAL"
>.text</TT
> command switches to the program-text
counter, and the <TT
CLASS="LITERAL"
>.data</TT
> command switches to the
variable-data counter. When Ophis first starts assembling a file,
it starts in <TT
CLASS="LITERAL"
>.text</TT
> mode.
</P
><P
> To reserve space for a variable, use the .space command. This
takes the form:
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.space varname size</PRE
></TD
></TR
></TABLE
>
which assigns the name <TT
CLASS="LITERAL"
>varname</TT
> to the current
program counter, then advances the program counter by the amount
specified in <TT
CLASS="LITERAL"
>size</TT
>. Nothing is output to the
final binary as a result of the <TT
CLASS="LITERAL"
>.space</TT
> command.
</P
><P
> You may not put in any commands that produce output into
a <TT
CLASS="LITERAL"
>.data</TT
> segment. Generally, all you will be
using are <TT
CLASS="LITERAL"
>.org</TT
> and <TT
CLASS="LITERAL"
>.space</TT
>
commands. Ophis will not complain if you
use <TT
CLASS="LITERAL"
>.space</TT
> inside a <TT
CLASS="LITERAL"
>.text</TT
>
segment, but this is nearly always wrong.
</P
><P
> The final version of <TT
CLASS="LITERAL"
>delay</TT
> looks like this:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend</PRE
></TD
></TR
></TABLE
><P
> We're not quite done yet, however, because we have to tell the
data segment where to begin. (If we don't, it starts at 0, which
is usually wrong.) We add a very brief data segment to the top of
our code:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.data
.org $C000
.text</PRE
></TD
></TR
></TABLE
><P
> This will run. However, we also ought to make sure that we aren't
overstepping any boundaries. Our program text shouldn't run into
the BASIC chip at $A000, and our data shouldn't run into the I/O
region at $D000. The <TT
CLASS="LITERAL"
>.checkpc</TT
> command lets us
assert that the program counter hasn't reached a specific point
yet. We put, at the end of our code:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.checkpc $A000
.data
.checkpc $D000</PRE
></TD
></TR
></TABLE
><P
> The final program is available as <A
HREF="x489.html"
><I
><I
>tutor5.oph</I
></I
></A
>. Note that we based this on the
all-uppercase version from the last section, not any of the
charmapped versions.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c292.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c371.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Character maps</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Expressions</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

180
site/manual/c35.html Normal file
View File

@ -0,0 +1,180 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>The basics</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Getting a copy of Ophis"
HREF="x22.html"><LINK
REL="NEXT"
TITLE="Producing Commodore 64 programs"
HREF="x51.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x22.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x51.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="PART1"
></A
>The basics</H1
><P
> In this first part of the tutorial we will create a
simple <SPAN
CLASS="QUOTE"
>"Hello World"</SPAN
> program to run on the Commodore
64. This will cover:
<P
></P
><UL
><LI
><P
>How to make programs run on a Commodore 64</P
></LI
><LI
><P
>Writing simple code with labels</P
></LI
><LI
><P
>Numeric and string data</P
></LI
><LI
><P
>Invoking the assembler</P
></LI
></UL
>
</P
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN48"
>A note on numeric notation</A
></H1
><P
> Throughout these tutorials, I will be using a lot of both
decimal and hexadecimal notation. Hex numbers will have a
dollar sign in front of them. Thus, 100 = $64, and $100 = 256.
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x22.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x51.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Getting a copy of Ophis</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Producing Commodore 64 programs</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

348
site/manual/c371.html Normal file
View File

@ -0,0 +1,348 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Expressions</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Local variables and memory segments"
HREF="c329.html"><LINK
REL="NEXT"
TITLE="Advanced Memory Segments"
HREF="c419.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c329.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c419.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="AEN371"
></A
>Expressions</H1
><P
> Ophis permits a reasonably rich set of arithmetic operations to be
done at assemble time. So far, all of our arguments and values
have either been constants or label names. In this chapter, we
will modify the <TT
CLASS="LITERAL"
>print</TT
> macro so that it calls a
subroutine to do the actual printing. This will shrink the final
code size a fair bit.
</P
><P
> Here's our printing routine. It's fairly straightforward.
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
printstr:
sta $10
stx $11
ldy #$00
_lp: lda ($10), y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend</PRE
></TD
></TR
></TABLE
><P
> However, now we are faced with the problem of what to do with
the <TT
CLASS="LITERAL"
>print</TT
> macro. We need to take a 16-bit
value and store it in two 8-bit registers. We can use
the <TT
CLASS="LITERAL"
>&#60;</TT
> and <TT
CLASS="LITERAL"
>&#62;</TT
> operators
to take the low or high byte of a word, respectively.
The <TT
CLASS="LITERAL"
>print</TT
> macro becomes:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.macro print
lda #&#60;_1
ldx #&#62;_1
jsr printstr
.macend</PRE
></TD
></TR
></TABLE
><P
> Also, since BASIC uses the locations $10 and $11, we should really
cache them at the start of the program and restore them at the
end:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.data
.org $C000
.space cache 2
.text
; Save the zero page locations that printstr uses.
lda $10
sta cache
lda $11
sta cache+1
; ... main program goes here ...
; Restore the zero page values printstr uses.
lda cache
sta $10
lda cache+1
sta $11</PRE
></TD
></TR
></TABLE
><P
> Note that we only have to name <TT
CLASS="LITERAL"
>cache</TT
> once, but
can use addition to refer to any offset from it.
</P
><P
> Ophis supports following operations, with the following precedence
levels (higher entries bind more tightly):
</P
><DIV
CLASS="TABLE"
><A
NAME="AEN388"
></A
><P
><B
>Table 1. Ophis Operators</B
></P
><TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
CELLSPACING="0"
CELLPADDING="4"
CLASS="CALSTABLE"
><THEAD
><TR
><TH
ALIGN="CENTER"
>Operators</TH
><TH
ALIGN="CENTER"
>Description</TH
></TR
></THEAD
><TBODY
><TR
><TD
><TT
CLASS="LITERAL"
>[ ]</TT
></TD
><TD
>Parenthesized expressions</TD
></TR
><TR
><TD
><TT
CLASS="LITERAL"
>&#60; &#62;</TT
></TD
><TD
>Byte selection (low, high)</TD
></TR
><TR
><TD
><TT
CLASS="LITERAL"
>* /</TT
></TD
><TD
>Multiply, divide</TD
></TR
><TR
><TD
><TT
CLASS="LITERAL"
>+ -</TT
></TD
><TD
>Add, subtract</TD
></TR
><TR
><TD
><TT
CLASS="LITERAL"
>| &#38; ^</TT
></TD
><TD
>Bitwise OR, AND, XOR</TD
></TR
></TBODY
></TABLE
></DIV
><P
> Note that brackets, not parentheses, are used to group arithmetic
operations. This is because parentheses are used for the indirect
addressing modes, and it makes parsing much easier.
</P
><P
> The code for this version of the code is
in <A
HREF="x493.html"
><I
><I
>tutor6.oph</I
></I
></A
>.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c329.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c419.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Local variables and memory segments</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Advanced Memory Segments</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

184
site/manual/c419.html Normal file
View File

@ -0,0 +1,184 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Advanced Memory Segments</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Expressions"
HREF="c371.html"><LINK
REL="NEXT"
TITLE="The Solution"
HREF="x430.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c371.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x430.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="AEN419"
></A
>Advanced Memory Segments</H1
><P
> This is the last section of the Ophis tutorial. By now we've
covered the basics of every command in the assembler; in this
final installment we show the full capabilities of
the <TT
CLASS="LITERAL"
>.text</TT
> and <TT
CLASS="LITERAL"
>.data</TT
> commands
as we produce a final set of Commodore 64 header files.
</P
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN424"
>The Problem</A
></H1
><P
> Our <TT
CLASS="LITERAL"
>print'str</TT
> routine
in <A
HREF="x493.html"
><I
><I
>tutor6.oph</I
></I
></A
> accesses
memory locations $10 and $11 directly. We'd prefer to have
symbolic names for them. This reprises our concerns back in
<A
HREF="c329.html"
>the Chapter called <I
>Local variables and memory segments</I
></A
> when we concluded that we wanted two
separate program counters. Now we realize that we really need
three; one for the text, one for the data, and one for the zero
page data. And if we're going to allow three, we really should
allow any number.
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c371.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x430.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Expressions</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>The Solution</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

186
site/manual/f10.html Normal file
View File

@ -0,0 +1,186 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Preface</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="NEXT"
TITLE="Getting a copy of Ophis"
HREF="x22.html"></HEAD
><BODY
CLASS="PREFACE"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="book1.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x22.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="PREFACE"
><H1
><A
NAME="AEN10"
></A
>Preface</H1
><P
> The Ophis project started on a lark back in 2001. My graduate
studies required me to learn Perl and Python, and I'd been playing
around with Commodore 64 emulators in my spare time, so I decided
to learn both languages by writing a simple cross-assembler for
the 6502 chip the C-64 used in both.
</P
><P
> The Perl version was quickly abandoned, but the Python one slowly
grew in scope and power over the years, and by 2005 was a very
powerful, flexible macro assembler that saw more use than I'd
expect. In 2007 I finally got around to implementing the last few
features I really wanted and polishing it up for general release.
</P
><P
> Part of that process has been formatting the various little
tutorials and references I'd created into a single, unified
document&#8212;the one you are now reading.
</P
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN15"
>Why <SPAN
CLASS="QUOTE"
>"Ophis"</SPAN
>?</A
></H1
><P
> It's actually a kind of a horrific pun. See, I was using Python
at the time, and one of the things I had been hoping to do with
the assembler was to produce working Apple II
programs. <SPAN
CLASS="QUOTE"
>"Ophis"</SPAN
> is Greek
for <SPAN
CLASS="QUOTE"
>"snake"</SPAN
>, and a number of traditions also use it
as the actual <I
CLASS="EMPHASIS"
>name</I
> of the serpent in the
Garden of Eden. So, Pythons, snakes, and stories involving
really old Apples all combined to name the assembler.
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x22.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Programming with Ophis</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Getting a copy of Ophis</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

206
site/manual/x119.html Normal file
View File

@ -0,0 +1,206 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Related commands and options</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="The basics"
HREF="c35.html"><LINK
REL="PREVIOUS"
TITLE="Producing Commodore 64 programs"
HREF="x51.html"><LINK
REL="NEXT"
TITLE="Writing the actual code"
HREF="x140.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x51.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>The basics</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x140.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN119"
>Related commands and options</A
></H1
><P
> This code includes constants that are both in decimal and in
hex. It is also possible to specify constants in octal, binary,
or with an ASCII character.
<P
></P
><UL
><LI
><P
>To specify decimal constants, simply write the number.</P
></LI
><LI
><P
>To specify hexadecimal constants, put a $ in front.</P
></LI
><LI
><P
>To specify octal constants, put a 0 (zero) in front.</P
></LI
><LI
><P
>To specify binary constants, put a % in front.</P
></LI
><LI
><P
>To specify ASCII constants, put an apostrophe in front.</P
></LI
></UL
>
Example: 65 = $41 = 0101 = %1000001 = 'A
</P
><P
> There are other commands besides <TT
CLASS="LITERAL"
>.byte</TT
>
and <TT
CLASS="LITERAL"
>.word</TT
> to specify data. In particular,
the <TT
CLASS="LITERAL"
>.dword</TT
> command specifies four-byte values
which some applications will find useful. Also, some linking
formats (such as the <TT
CLASS="FILENAME"
>SID</TT
> format) have
header data in big-endian (high byte first) format.
The <TT
CLASS="LITERAL"
>.wordbe</TT
> and <TT
CLASS="LITERAL"
>.dwordbe</TT
>
directives provide a way to specify multibyte constants in
big-endian formats cleanly.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x51.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x140.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Producing Commodore 64 programs</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c35.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Writing the actual code</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

197
site/manual/x140.html Normal file
View File

@ -0,0 +1,197 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Writing the actual code</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="The basics"
HREF="c35.html"><LINK
REL="PREVIOUS"
TITLE="Related commands and options"
HREF="x119.html"><LINK
REL="NEXT"
TITLE="Assembling the code"
HREF="x149.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x119.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>The basics</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x149.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN140"
>Writing the actual code</A
></H1
><P
> Now that we have our header information, let's actually write
the <SPAN
CLASS="QUOTE"
>"Hello world"</SPAN
> program. It's pretty
short&#8212;a simple loop that steps through a hardcoded array
until it reaches a 0 or outputs 256 characters. It then returns
control to BASIC with an <TT
CLASS="LITERAL"
>RTS</TT
> statement.
</P
><P
> Each character in the array is passed as an argument to a
subroutine at memory location $FFD2. This is part of the
Commodore 64's BIOS software, which its development
documentation calls the KERNAL. Location $FFD2 prints out the
character corresponding to the character code in the
accumulator.
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
> ldx #0
loop: lda hello, x
beq done
jsr $ffd2
inx
bne loop
done: rts
hello: .byte "HELLO, WORLD!", 0
</PRE
></TD
></TR
></TABLE
><P
> The complete, final source is available in
the <A
HREF="a454.html#TUTOR1-SRC"
><I
><I
>tutor1.oph</I
></I
></A
> file.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x119.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x149.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Related commands and options</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c35.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Assembling the code</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

317
site/manual/x149.html Normal file
View File

@ -0,0 +1,317 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Assembling the code</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="The basics"
HREF="c35.html"><LINK
REL="PREVIOUS"
TITLE="Writing the actual code"
HREF="x140.html"><LINK
REL="NEXT"
TITLE="Labels and aliases"
HREF="c200.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x140.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>The basics</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c200.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN149"
>Assembling the code</A
></H1
><P
> The Ophis assembler is a collection of Python modules,
controlled by a master script. On Windows, this should all
have been combined into an executable
file <B
CLASS="COMMAND"
>ophis.exe</B
>; on other platforms, the
Ophis modules should be in the library and
the <B
CLASS="COMMAND"
>ophis</B
> script should be in your path.
Typing <B
CLASS="COMMAND"
>ophis</B
> with no arguments should give a
summary of available command line options.
</P
><DIV
CLASS="TABLE"
><A
NAME="AEN155"
></A
><P
><B
>Table 2. Ophis Options</B
></P
><TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
CELLSPACING="0"
CELLPADDING="4"
CLASS="CALSTABLE"
><THEAD
><TR
><TH
ALIGN="CENTER"
>Option</TH
><TH
ALIGN="CENTER"
>Effect</TH
></TR
></THEAD
><TBODY
><TR
><TD
><CODE
CLASS="OPTION"
>-6510</CODE
></TD
><TD
>Allows the 6510 undocumented opcodes as listed in the VICE documentation.</TD
></TR
><TR
><TD
><CODE
CLASS="OPTION"
>-65c02</CODE
></TD
><TD
>Allows opcodes and addressing modes added by the 65C02.</TD
></TR
><TR
><TD
><CODE
CLASS="OPTION"
>-v 0</CODE
></TD
><TD
>Quiet operation. Only reports errors.</TD
></TR
><TR
><TD
><CODE
CLASS="OPTION"
>-v 1</CODE
></TD
><TD
>Default operation. Reports files as they are loaded, and gives statistics on the final output.</TD
></TR
><TR
><TD
><CODE
CLASS="OPTION"
>-v 2</CODE
></TD
><TD
>Verbose operation. Names each assembler pass as it runs.</TD
></TR
><TR
><TD
><CODE
CLASS="OPTION"
>-v 3</CODE
></TD
><TD
>Debug operation: Dumps the entire IR after each pass.</TD
></TR
><TR
><TD
><CODE
CLASS="OPTION"
>-v 4</CODE
></TD
><TD
>Full debug operation: Dumps the entire IR and symbol table after each pass.</TD
></TR
></TBODY
></TABLE
></DIV
><P
> The only options Ophis demands are an input file and an output
file. Here's a sample session, assembling the tutorial file
here:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="SCREEN"
>localhost$ ophis tutor1.oph tutor1.prg -v 2
Loading tutor1.oph
Running: Macro definition pass
Running: Macro expansion pass
Running: Label initialization pass
Fixpoint failed, looping back
Running: Label initialization pass
Running: Circularity check pass
Running: Expression checking pass
Running: Easy addressing modes pass
Running: Label Update Pass
Fixpoint failed, looping back
Running: Label Update Pass
Running: Instruction Collapse Pass
Running: Mode Normalization pass
Running: Label Update Pass
Running: Assembler
Assembly complete: 45 bytes output (14 code, 29 data, 2 filler)
</PRE
></TD
></TR
></TABLE
><P
> If your emulator can run <TT
CLASS="FILENAME"
>PRG</TT
> files
directly, this file will now run (and
print <SAMP
CLASS="COMPUTEROUTPUT"
>HELLO, WORLD!</SAMP
>) as many
times as you type <KBD
CLASS="USERINPUT"
>RUN</KBD
>. Otherwise, use
a <TT
CLASS="FILENAME"
>D64</TT
> management utility to put
the <TT
CLASS="FILENAME"
>PRG</TT
> on a <TT
CLASS="FILENAME"
>D64</TT
>, then
load and run the file off that.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x140.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c200.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Writing the actual code</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c35.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Labels and aliases</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

198
site/manual/x214.html Normal file
View File

@ -0,0 +1,198 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Anonymous labels</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Labels and aliases"
HREF="c200.html"><LINK
REL="PREVIOUS"
TITLE="Labels and aliases"
HREF="c200.html"><LINK
REL="NEXT"
TITLE="Aliasing"
HREF="x225.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c200.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Labels and aliases</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x225.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN214"
>Anonymous labels</A
></H1
><P
> Anonymous labels are a way to handle short-ranged branches
without having to come up with names for the then and else
branches, for brief loops, and other such purposes. To define
an anonymous label, use an asterisk. To refer to an anonymous
label, use a series of <TT
CLASS="LITERAL"
>+</TT
>
or <TT
CLASS="LITERAL"
>-</TT
> signs. <TT
CLASS="LITERAL"
>+</TT
> refers to
the next anonymous label, <TT
CLASS="LITERAL"
>++</TT
> the label
after that, etc. Likewise, <TT
CLASS="LITERAL"
>-</TT
> is the most
recently defined label, <TT
CLASS="LITERAL"
>--</TT
> the one before
that, and so on. The main body of the Hello World program
with anonymous labels would be:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
> ldx #0
* lda hello, x
beq +
jsr $ffd2
inx
bne -
* rts</PRE
></TD
></TR
></TABLE
><P
> It is worth noting that anonymous labels are globally available.
They are not temporary labels, and they ignore scoping
restrictions.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c200.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x225.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Labels and aliases</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c200.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Aliasing</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

197
site/manual/x22.html Normal file
View File

@ -0,0 +1,197 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Getting a copy of Ophis</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Preface"
HREF="f10.html"><LINK
REL="PREVIOUS"
TITLE="Preface"
HREF="f10.html"><LINK
REL="NEXT"
TITLE="The basics"
HREF="c35.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="f10.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Preface</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c35.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN22"
>Getting a copy of Ophis</A
></H1
><P
> If you're reading this as part of the Ophis install, you clearly
already have it. If not, as of this writing the homepage for
the Ophis assembler
is <A
HREF="http://hkn.eecs.berkeley.edu/~mcmartin/ophis/"
TARGET="_top"
>http://hkn.eecs.berkeley.edu/~mcmartin/ophis/</A
>. If
this is out-of-date, a Web search on <SPAN
CLASS="QUOTE"
>"Ophis 6502
assembler"</SPAN
> (without the quotation marks) should yield its
page.
</P
><P
> Ophis is written entirely in Python and packaged using the
distutils. The default installation script on Unix and Mac OS X
systems should put the files where they need to go. If you are
running it locally, you will need to install
the <TT
CLASS="LITERAL"
>Ophis</TT
> package somewhere in your Python
package path, and then put the <B
CLASS="COMMAND"
>ophis</B
> script
somewhere in your path.
</P
><P
> Windows users that have Python installed can use the same source
distributions that the other operating systems
use; <B
CLASS="COMMAND"
>ophis.bat</B
> will arrange the environment
variables accordingly and invoke the main script.
</P
><P
> If you are on Windows and do not have Python installed, a
prepackaged system made with <B
CLASS="COMMAND"
>py2exe</B
> is also
available. The default Windows installer will use this. In
this case, all you need to do is
have <B
CLASS="COMMAND"
>ophis.exe</B
> in your path.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="f10.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c35.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Preface</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="f10.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>The basics</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

203
site/manual/x225.html Normal file
View File

@ -0,0 +1,203 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Aliasing</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Labels and aliases"
HREF="c200.html"><LINK
REL="PREVIOUS"
TITLE="Anonymous labels"
HREF="x214.html"><LINK
REL="NEXT"
TITLE="Headers, Libraries, and Macros"
HREF="c236.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x214.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Labels and aliases</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c236.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN225"
>Aliasing</A
></H1
><P
> Rather the reverse of anonymous labels, aliases are names
given to specific memory locations. These make it easier to
keep track of important constants or locations. The KERNAL
routines are a good example of constants that deserve names.
To assign the traditional name <TT
CLASS="LITERAL"
>chrout</TT
> to
the routine at $FFD2, simply give the directive:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.alias chrout $ffd2</PRE
></TD
></TR
></TABLE
><P
>And change the <KBD
CLASS="USERINPUT"
>jsr</KBD
> command
to:</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
> jsr chrout</PRE
></TD
></TR
></TABLE
><P
> The final version of the code is in <A
HREF="x461.html"
><I
><I
>tutor2.oph</I
></I
></A
>. It should
assemble to exactly the same program as <A
HREF="a454.html#TUTOR1-SRC"
><I
><I
>tutor1.oph</I
></I
></A
>.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x214.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c236.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Anonymous labels</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c200.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Headers, Libraries, and Macros</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

289
site/manual/x257.html Normal file
View File

@ -0,0 +1,289 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Macros</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Headers, Libraries, and Macros"
HREF="c236.html"><LINK
REL="PREVIOUS"
TITLE="Headers, Libraries, and Macros"
HREF="c236.html"><LINK
REL="NEXT"
TITLE="Example code"
HREF="x287.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c236.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Headers, Libraries, and Macros</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x287.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN257"
>Macros</A
></H1
><P
> A macro is a way of expressing a lot of code or data with a
simple shorthand. It's also usually configurable. Traditional
macro systems such as C's <TT
CLASS="LITERAL"
>#define</TT
> mechanic
use <I
CLASS="EMPHASIS"
>textual replacement</I
>: a macro is
expanded before any evaluation or even parsing occurs.
</P
><P
> In contrast, Ophis's macro system uses a <I
CLASS="EMPHASIS"
>call by
value</I
> approach where the arguments to macros are
evaluated to bytes or words before being inserted into the macro
body. This produces effects much closer to those of a
traditional function call. A more detailed discussion of the
tradeoffs may be found in <A
HREF="a505.html"
>the Appendix called <I
>Ophis Command Reference</I
></A
>.
</P
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN265"
>Macro definitions</A
></H2
><P
> A macro definition is a set of statements between
a <TT
CLASS="LITERAL"
>.macro</TT
> statement and
a <TT
CLASS="LITERAL"
>.macend</TT
> statement.
The <TT
CLASS="LITERAL"
>.macro</TT
> statement also names the macro
being defined.
</P
><P
> No global or anonymous labels may be defined inside a macro:
temporary labels only persist in the macro expansion itself.
(Each macro body has its own scope.)
</P
><P
> Arguments to macros are referred to by number: the first is
<TT
CLASS="LITERAL"
>_1</TT
>, the second <TT
CLASS="LITERAL"
>_2</TT
>, and so on.
</P
><P
> Here's a macro that encapsulates the printing routine in our
<SPAN
CLASS="QUOTE"
>"Hello World"</SPAN
> program, with an argument being the
address of the string to print:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN278"
>Macro invocations</A
></H2
><P
> Macros may be invoked in two ways: one that looks like a
directive, and one that looks like an instruction.
</P
><P
> The most common way to invoke a macro is to backquote the name
of the macro. It is also possible to use
the <TT
CLASS="LITERAL"
>.invoke</TT
> command. These commands look
like this:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>`print msg
.invoke print msg</PRE
></TD
></TR
></TABLE
><P
> Arguments are passed to the macro as a comma-separated list.
They must all be expressions that evaluate to byte or word
values&#8212;a mechanism similar to <TT
CLASS="LITERAL"
>.alias</TT
>
is used to assign their values to the <TT
CLASS="LITERAL"
>_n</TT
>
names.
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c236.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x287.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Headers, Libraries, and Macros</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c236.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Example code</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

161
site/manual/x287.html Normal file
View File

@ -0,0 +1,161 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Example code</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Headers, Libraries, and Macros"
HREF="c236.html"><LINK
REL="PREVIOUS"
TITLE="Macros"
HREF="x257.html"><LINK
REL="NEXT"
TITLE="Character maps"
HREF="c292.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x257.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Headers, Libraries, and Macros</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c292.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN287"
>Example code</A
></H1
><P
> <A
HREF="x473.html"
><I
><I
>tutor3.oph</I
></I
></A
> expands our
running example, including the code above and also defining a
new macro <TT
CLASS="LITERAL"
>greet</TT
> that takes a string argument
and prints a greeting to it. It then greets far too many
targets.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x257.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c292.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Macros</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c236.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Character maps</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

295
site/manual/x430.html Normal file
View File

@ -0,0 +1,295 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>The Solution</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Advanced Memory Segments"
HREF="c419.html"><LINK
REL="PREVIOUS"
TITLE="Advanced Memory Segments"
HREF="c419.html"><LINK
REL="NEXT"
TITLE="Where to go from here"
HREF="x449.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c419.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Advanced Memory Segments</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x449.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN430"
>The Solution</A
></H1
><P
> The <TT
CLASS="LITERAL"
>.data</TT
> and <TT
CLASS="LITERAL"
>.text</TT
>
commands can take a label name after them&#8212;this names a new
segment. We'll define a new segment
called <TT
CLASS="LITERAL"
>zp</TT
> (for <SPAN
CLASS="QUOTE"
>"zero page"</SPAN
>) and
have our zero-page variables be placed there. We can't actually
use the default origin of $0000 here either, though, because the
Commodore 64 reserves memory locations 0 and 1 to control its
memory mappers:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.data zp
.org $0002</PRE
></TD
></TR
></TABLE
><P
> Now, actually, the rest of the zero page is reserved too:
locations $02-$7F are used by the BASIC interpreter, and
locations $80-$FF are used by the KERNAL. We don't need the
BASIC interpreter, though, so we can back up all of $02-$7F at
the start of our program and restore it all when we're done:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.scope
; Cache BASIC's zero page at top of available RAM.
ldx #$7E
* lda $01, x
sta $CF81, x
dex
bne -
jsr _main
; Restore BASIC's zero page and return control.
ldx #$7E
* lda $CF81, x
sta $01, x
dex
bne -
rts
_main:
; _main points at the start of the real program,
; which is actually outside of this scope
.scend</PRE
></TD
></TR
></TABLE
><P
> The new, improved header file is <A
HREF="x497.html"
><I
><I
>c64-2.oph</I
></I
></A
>.
</P
><P
> Our <TT
CLASS="LITERAL"
>print'str</TT
> routine is then rewritten to
declare and use a zero-page variable, like so:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
.data zp
.space _ptr 2
.text
printstr:
sta _ptr
stx _ptr+1
ldy #$00
_lp: lda (_ptr),y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend</PRE
></TD
></TR
></TABLE
><P
> Also, we ought to put in an extra check to make sure our
zero-page allocations don't overflow, either:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.data zp
.checkpc $80</PRE
></TD
></TR
></TABLE
><P
> That concludes our tour. The final source file
is <A
HREF="x501.html"
><I
><I
>tutor7.oph</I
></I
></A
>.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c419.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x449.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Advanced Memory Segments</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c419.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Where to go from here</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

162
site/manual/x449.html Normal file
View File

@ -0,0 +1,162 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Where to go from here</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Advanced Memory Segments"
HREF="c419.html"><LINK
REL="PREVIOUS"
TITLE="The Solution"
HREF="x430.html"><LINK
REL="NEXT"
TITLE="Example Programs"
HREF="a454.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x430.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Advanced Memory Segments</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="a454.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN449"
>Where to go from here</A
></H1
><P
> This tutorial has touched on everything that the assembler can
do, but it's not really well organized as a
reference. <A
HREF="a505.html"
>the Appendix called <I
>Ophis Command Reference</I
></A
> is a better place to look
up matters of syntax or consult lists of available commands.
</P
><P
> If you're looking for projects to undertake, the Commodore 64
and Atari 2600 development communities are both very strong, and
the Apple II and NES development communities are still alive and
well as well. There's an annual Minigame Competition that's
always looking for new entries.
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x430.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>The Solution</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c419.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Example Programs</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

183
site/manual/x461.html Normal file
View File

@ -0,0 +1,183 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>tutor2.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="NEXT"
TITLE="c64-1.oph"
HREF="x465.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="a454.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x465.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR2-SRC"
><TT
CLASS="FILENAME"
>tutor2.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance 2064
.alias chrout $ffd2
ldx #0
* lda hello, x
beq +
jsr chrout
inx
bne -
* rts
hello: .byte "HELLO, WORLD!", 0</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x465.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Example Programs</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>c64-1.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

176
site/manual/x465.html Normal file
View File

@ -0,0 +1,176 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>c64-1.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="tutor2.oph"
HREF="x461.html"><LINK
REL="NEXT"
TITLE="kernal.oph"
HREF="x469.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x461.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x469.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="C64-1-SRC"
><TT
CLASS="FILENAME"
>c64-1.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance 2064
.require "kernal.oph"</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x461.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x469.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor2.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>kernal.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

231
site/manual/x469.html Normal file
View File

@ -0,0 +1,231 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>kernal.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="c64-1.oph"
HREF="x465.html"><LINK
REL="NEXT"
TITLE="tutor3.oph"
HREF="x473.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x465.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x473.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="KERNAL-SRC"
><TT
CLASS="FILENAME"
>kernal.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>; KERNAL routine aliases (C64)
.alias acptr $ffa5
.alias chkin $ffc6
.alias chkout $ffc9
.alias chrin $ffcf
.alias chrout $ffd2
.alias ciout $ffa8
.alias cint $ff81
.alias clall $ffe7
.alias close $ffc3
.alias clrchn $ffcc
.alias getin $ffe4
.alias iobase $fff3
.alias ioinit $ff84
.alias listen $ffb1
.alias load $ffd5
.alias membot $ff9c
.alias memtop $ff99
.alias open $ffc0
.alias plot $fff0
.alias ramtas $ff87
.alias rdtim $ffde
.alias readst $ffb7
.alias restor $ff8a
.alias save $ffd8
.alias scnkey $ff9f
.alias screen $ffed
.alias second $ff93
.alias setlfs $ffba
.alias setmsg $ff90
.alias setnam $ffbd
.alias settim $ffdb
.alias settmo $ffa2
.alias stop $ffe1
.alias talk $ffb4
.alias tksa $ff96
.alias udtim $ffea
.alias unlsn $ffae
.alias untlk $ffab
.alias vector $ff8d
; Character codes for the colors.
.alias color'0 144
.alias color'1 5
.alias color'2 28
.alias color'3 159
.alias color'4 156
.alias color'5 30
.alias color'6 31
.alias color'7 158
.alias color'8 129
.alias color'9 149
.alias color'10 150
.alias color'11 151
.alias color'12 152
.alias color'13 153
.alias color'14 154
.alias color'15 155
; ...and reverse video
.alias reverse'on 18
.alias reverse'off 146
; ...and character set
.alias upper'case 142
.alias lower'case 14</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x465.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x473.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>c64-1.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor3.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

209
site/manual/x473.html Normal file
View File

@ -0,0 +1,209 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>tutor3.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="kernal.oph"
HREF="x469.html"><LINK
REL="NEXT"
TITLE="tutor4a.oph"
HREF="x477.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x469.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x477.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR3-SRC"
><TT
CLASS="FILENAME"
>tutor3.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x469.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x477.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>kernal.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor4a.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

230
site/manual/x477.html Normal file
View File

@ -0,0 +1,230 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>tutor4a.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="tutor3.oph"
HREF="x473.html"><LINK
REL="NEXT"
TITLE="tutor4b.oph"
HREF="x481.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x473.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x481.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR4A-SRC"
><TT
CLASS="FILENAME"
>tutor4a.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x473.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x481.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor3.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor4b.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

232
site/manual/x481.html Normal file
View File

@ -0,0 +1,232 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>tutor4b.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="tutor4a.oph"
HREF="x477.html"><LINK
REL="NEXT"
TITLE="tutor4c.oph"
HREF="x485.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x477.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x485.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR4B-SRC"
><TT
CLASS="FILENAME"
>tutor4b.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
lda #lower'case
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "Hello, ",0
hello2: .byte "!", 13, 0
target1: .byte "programmer", 0
target2: .byte "room", 0
target3: .byte "building", 0
target4: .byte "neighborhood", 0
target5: .byte "city", 0
target6: .byte "nation", 0
target7: .byte "world", 0
target8: .byte "Solar System", 0
target9: .byte "Galaxy", 0
target10: .byte "Universe", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x477.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x485.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor4a.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor4c.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

235
site/manual/x485.html Normal file
View File

@ -0,0 +1,235 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>tutor4c.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="tutor4b.oph"
HREF="x481.html"><LINK
REL="NEXT"
TITLE="tutor5.oph"
HREF="x489.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x481.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x489.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR4C-SRC"
><TT
CLASS="FILENAME"
>tutor4c.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.include "c64-1.oph"
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
lda #lower'case
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
.charmap 'A, "abcdefghijklmnopqrstuvwxyz"
.charmap 'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
hello1: .byte "Hello, ",0
hello2: .byte "!", 13, 0
target1: .byte "programmer", 0
target2: .byte "room", 0
target3: .byte "building", 0
target4: .byte "neighborhood", 0
target5: .byte "city", 0
target6: .byte "nation", 0
target7: .byte "world", 0
target8: .byte "Solar System", 0
target9: .byte "Galaxy", 0
target10: .byte "Universe", 0
; DELAY routine. Executes 2,560*(A) NOP statements.
delay: tax
ldy #00
* nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
iny
bne -
dex
bne -
rts</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x481.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x489.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor4b.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor5.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

239
site/manual/x489.html Normal file
View File

@ -0,0 +1,239 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>tutor5.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="tutor4c.oph"
HREF="x485.html"><LINK
REL="NEXT"
TITLE="tutor6.oph"
HREF="x493.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x485.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x493.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR5-SRC"
><TT
CLASS="FILENAME"
>tutor5.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.include "c64-1.oph"
.data
.org $C000
.text
.macro print
ldx #0
_loop: lda _1, x
beq _done
jsr chrout
inx
bne _loop
_done:
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
.checkpc $A000
.data
.checkpc $D000</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x485.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x493.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor4c.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor6.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

266
site/manual/x493.html Normal file
View File

@ -0,0 +1,266 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>tutor6.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="tutor5.oph"
HREF="x489.html"><LINK
REL="NEXT"
TITLE="c64-2.oph"
HREF="x497.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x489.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x497.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR6-SRC"
><TT
CLASS="FILENAME"
>tutor6.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.include "c64-1.oph"
.data
.org $C000
.space cache 2
.text
.macro print
lda #&#60;_1
ldx #&#62;_1
jsr printstr
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
; Save the zero page locations that PRINTSTR uses.
lda $10
sta cache
lda $11
sta cache+1
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
; Restore the zero page values printstr uses.
lda cache
sta $10
lda cache+1
sta $11
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
printstr:
sta $10
stx $11
ldy #$00
_lp: lda ($10),y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend
.checkpc $A000
.data
.checkpc $D000</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x489.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x497.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor5.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>c64-2.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

204
site/manual/x497.html Normal file
View File

@ -0,0 +1,204 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>c64-2.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="tutor6.oph"
HREF="x493.html"><LINK
REL="NEXT"
TITLE="tutor7.oph"
HREF="x501.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x493.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x501.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="C64-2-SRC"
><TT
CLASS="FILENAME"
>c64-2.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.word $0801
.org $0801
.scope
.word _next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
_next: .word 0 ; End of program
.scend
.advance $0810
.require "kernal.oph"
.data zp
.org $0002
.text
.scope
; Cache BASIC's zero page at top of available RAM.
ldx #$7E
* lda $01, x
sta $CF81, x
dex
bne -
jsr _main
; Restore BASIC's zero page and return control.
ldx #$7E
* lda $CF81, x
sta $01, x
dex
bne -
rts
_main:
; Program follows...
.scend</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x493.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x501.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor6.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><TT
CLASS="FILENAME"
>tutor7.oph</TT
></TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

257
site/manual/x501.html Normal file
View File

@ -0,0 +1,257 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>tutor7.oph</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Example Programs"
HREF="a454.html"><LINK
REL="PREVIOUS"
TITLE="c64-2.oph"
HREF="x497.html"><LINK
REL="NEXT"
TITLE="Ophis Command Reference"
HREF="a505.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x497.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Example Programs</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="a505.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="TUTOR7-SRC"
><TT
CLASS="FILENAME"
>tutor7.oph</TT
></A
></H1
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.include "c64-2.oph"
.data
.org $C000
.text
.macro print
lda #&#60;_1
ldx #&#62;_1
jsr printstr
.macend
.macro greet
lda #30
jsr delay
`print hello1
`print _1
`print hello2
.macend
lda #147
jsr chrout
`greet target1
`greet target2
`greet target3
`greet target4
`greet target5
`greet target6
`greet target7
`greet target8
`greet target9
`greet target10
rts
hello1: .byte "HELLO, ",0
hello2: .byte "!", 13, 0
target1: .byte "PROGRAMMER", 0
target2: .byte "ROOM", 0
target3: .byte "BUILDING", 0
target4: .byte "NEIGHBORHOOD", 0
target5: .byte "CITY", 0
target6: .byte "NATION", 0
target7: .byte "WORLD", 0
target8: .byte "SOLAR SYSTEM", 0
target9: .byte "GALAXY", 0
target10: .byte "UNIVERSE", 0
; DELAY routine. Takes values from the Accumulator and pauses
; for that many jiffies (1/60th of a second).
.scope
.data
.space _tmp 1
.space _target 1
.text
delay: sta _tmp ; save argument (rdtim destroys it)
jsr rdtim
clc
adc _tmp ; add current time to get target
sta _target
* jsr rdtim
cmp _target
bmi - ; Buzz until target reached
rts
.scend
; PRINTSTR routine. Accumulator stores the low byte of the address,
; X register stores the high byte. Destroys the values of $10 and
; $11.
.scope
.data zp
.space _ptr 2
.text
printstr:
sta _ptr
stx _ptr+1
ldy #$00
_lp: lda (_ptr),y
beq _done
jsr chrout
iny
bne _lp
_done: rts
.scend
.checkpc $A000
.data
.checkpc $D000
.data zp
.checkpc $80</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x497.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="a505.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><TT
CLASS="FILENAME"
>c64-2.oph</TT
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a454.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Ophis Command Reference</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

428
site/manual/x51.html Normal file
View File

@ -0,0 +1,428 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Producing Commodore 64 programs</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="The basics"
HREF="c35.html"><LINK
REL="PREVIOUS"
TITLE="The basics"
HREF="c35.html"><LINK
REL="NEXT"
TITLE="Related commands and options"
HREF="x119.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c35.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>The basics</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x119.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN51"
>Producing Commodore 64 programs</A
></H1
><P
> Commodore 64 programs are stored in
the <TT
CLASS="FILENAME"
>PRG</TT
> format on disk. Some emulators
(such as CCS64 or VICE) can run <TT
CLASS="FILENAME"
>PRG</TT
>
programs directly; others need them to be transferred to
a <TT
CLASS="FILENAME"
>D64</TT
> image first.
</P
><P
> The <TT
CLASS="FILENAME"
>PRG</TT
> format is ludicrously simple. It
has two bytes of header data: This is a little-endian number
indicating the starting address. The rest of the file is a
single continuous chunk of data loaded into memory, starting at
that address. BASIC memory starts at memory location 2048, and
that's probably where we'll want to start.
</P
><P
> Well, not quite. We want our program to be callable from BASIC,
so we should have a BASIC program at the start. We guess the
size of a simple one line BASIC program to be about 16 bytes.
Thus, we start our program at memory location 2064 ($0810), and
the BASIC program looks like this:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>10 SYS 2064
</PRE
></TD
></TR
></TABLE
><P
> We <KBD
CLASS="USERINPUT"
>SAVE</KBD
> this program to a file, then
study it in a debugger. It's 15 bytes long:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="SCREEN"
>1070:0100 01 08 0C 08 0A 00 9E 20-32 30 36 34 00 00 00
</PRE
></TD
></TR
></TABLE
><P
> The first two bytes are the memory location: $0801. The rest of
the data breaks down as follows:
</P
><DIV
CLASS="TABLE"
><A
NAME="AEN65"
></A
><P
><B
>Table 1. BASIC program breakdown</B
></P
><TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
CELLSPACING="0"
CELLPADDING="4"
CLASS="CALSTABLE"
><THEAD
><TR
><TH
ALIGN="CENTER"
>Memory Locations</TH
><TH
ALIGN="CENTER"
>Value</TH
></TR
></THEAD
><TBODY
><TR
><TD
>$0801-$0802</TD
><TD
>2-byte pointer to the next line of BASIC code ($080C).</TD
></TR
><TR
><TD
>$0803-$0804</TD
><TD
>2-byte line number ($000A = 10).</TD
></TR
><TR
><TD
>$0805</TD
><TD
>Byte code for the <KBD
CLASS="USERINPUT"
>SYS</KBD
> command.</TD
></TR
><TR
><TD
>$0806-$080A</TD
><TD
>The rest of the line, which is just the string <SPAN
CLASS="QUOTE"
>" 2064"</SPAN
>.</TD
></TR
><TR
><TD
>$080B</TD
><TD
>Null byte, terminating the line.</TD
></TR
><TR
><TD
>$080C-$080D</TD
><TD
>2-byte pointer to the next line of BASIC code ($0000 = end of program).</TD
></TR
></TBODY
></TABLE
></DIV
><P
> That's 13 bytes. We started at 2049, so we need 2 more bytes of
filler to make our code actually start at location 2064. These
17 bytes will give us the file format and the BASIC code we need
to have our machine language program run.
</P
><P
> These are just bytes&#8212;indistinguishable from any other sort of
data. In Ophis, bytes of data are specified with
the <TT
CLASS="LITERAL"
>.byte</TT
> command. We'll also have to tell
Ophis what the program counter should be, so that it knows what
values to assign to our labels. The <TT
CLASS="LITERAL"
>.org</TT
>
(origin) command tells Ophis this. Thus, the Ophis code for our
header and linking info is:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.byte $01, $08, $0C, $08, $0A, $00, $9E, $20
.byte $32, $30, $36, $34, $00, $00, $00, $00
.byte $00, $00
.org $0810
</PRE
></TD
></TR
></TABLE
><P
> This gets the job done, but it's completely incomprehensible,
and it only uses two directives&#8212;not very good for a
tutorial. Here's a more complicated, but much clearer, way of
saying the same thing.
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.word $0801
.org $0801
.word next, 10 ; Next line and current line number
.byte $9e," 2064",0 ; SYS 2064
next: .word 0 ; End of program
.advance 2064
</PRE
></TD
></TR
></TABLE
><P
> This code has many advantages over the first.
<P
></P
><UL
><LI
><P
> It describes better what is actually
happening. The <TT
CLASS="LITERAL"
>.word</TT
> directive at the
beginning indicates a 16-bit value stored in the typical
65xx way (small byte first). This is followed by
an <TT
CLASS="LITERAL"
>.org</TT
> statement, so we let the
assembler know right away where everything is supposed to
be.
</P
></LI
><LI
><P
> Instead of hardcoding in the value $080C, we
instead use a label to identify the location it's pointing
to. Ophis will compute the address
of <TT
CLASS="LITERAL"
>next</TT
> and put that value in as data.
We also describe the line number in decimal since BASIC
line numbers generally <I
CLASS="EMPHASIS"
>are</I
> in decimal.
Labels are defined by putting their name, then a colon, as
seen in the definition of <TT
CLASS="LITERAL"
>next</TT
>.
</P
></LI
><LI
><P
>
Instead of putting in the hex codes for the string part of
the BASIC code, we included the string directly. Each
character in the string becomes one byte.
</P
></LI
><LI
><P
>
Instead of adding the buffer ourselves, we
used <TT
CLASS="LITERAL"
>.advance</TT
>, which outputs zeros until
the specified address is reached. Attempting
to <TT
CLASS="LITERAL"
>.advance</TT
> backwards produces an
assemble-time error.
</P
></LI
><LI
><P
>
It has comments that explain what the data are for. The
semicolon is the comment marker; everything from a semicolon
to the end of the line is ignored.
</P
></LI
></UL
>
</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c35.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x119.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>The basics</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c35.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Related commands and options</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

309
site/manual/x572.html Normal file
View File

@ -0,0 +1,309 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Basic arguments</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Ophis Command Reference"
HREF="a505.html"><LINK
REL="PREVIOUS"
TITLE="Ophis Command Reference"
HREF="a505.html"><LINK
REL="NEXT"
TITLE="Compound Arguments"
HREF="x620.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="a505.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Ophis Command Reference</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x620.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN572"
>Basic arguments</A
></H1
><P
> Most arguments are just a number or label. The formats for
these are below.
</P
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN575"
>Numeric types</A
></H2
><P
></P
><UL
><LI
><P
><I
CLASS="EMPHASIS"
>Hex:</I
> <TT
CLASS="LITERAL"
>$41</TT
> (Prefixed with $)</P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Decimal:</I
> <TT
CLASS="LITERAL"
>65</TT
> (No markings)</P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Octal:</I
> <TT
CLASS="LITERAL"
>0101</TT
> (Prefixed with zero)</P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Binary:</I
> <TT
CLASS="LITERAL"
>%01000001</TT
> (Prefixed with %)</P
></LI
><LI
><P
><I
CLASS="EMPHASIS"
>Character:</I
> <TT
CLASS="LITERAL"
>'A</TT
> (Prefixed with single quote)</P
></LI
></UL
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN598"
>Label types</A
></H2
><P
> Normal labels are simply referred to by name. Anonymous
labels may be referenced with strings of - or + signs (the
label <TT
CLASS="LITERAL"
>-</TT
> refers to the immediate
previous anonymous label, <TT
CLASS="LITERAL"
>--</TT
> the
one before that, etc., while <TT
CLASS="LITERAL"
>+</TT
>
refers to the next anonymous label), and the special
label <TT
CLASS="LITERAL"
>^</TT
> refers to the program
counter at the start of the current instruction or directive.
</P
><P
> Normal labels are <I
CLASS="EMPHASIS"
>defined</I
> by
prefixing a line with the label name and then a colon
(e.g., <TT
CLASS="LITERAL"
>label:</TT
>). Anonymous labels
are defined by prefixing a line with an asterisk
(e.g., <TT
CLASS="LITERAL"
>*</TT
>).
</P
><P
> Temporary labels are only reachable from inside the
innermost enclosing <TT
CLASS="LITERAL"
>.scope</TT
>
statement. They are identical to normal labels in every
way, except that they start with an underscore.
</P
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN611"
>String types</A
></H2
><P
> Strings are enclosed in double quotation marks. Backslashed
characters (including backslashes and double quotes) are
treated literally, so the string <TT
CLASS="LITERAL"
>"The man said,
\"The \\ character is the backslash.\""</TT
> produces
the ASCII sequence for <TT
CLASS="LITERAL"
>The man said, "The \
character is the backslash."</TT
>
</P
><P
> Strings are generally only used as arguments to assembler
directives&#8212;usually for filenames
(e.g., <TT
CLASS="LITERAL"
>.include</TT
>) but also for string
data (in association with <TT
CLASS="LITERAL"
>.byte</TT
>).
</P
><P
> 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.
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="a505.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x620.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Ophis Command Reference</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a505.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Compound Arguments</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

212
site/manual/x620.html Normal file
View File

@ -0,0 +1,212 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Compound Arguments</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Ophis Command Reference"
HREF="a505.html"><LINK
REL="PREVIOUS"
TITLE="Basic arguments"
HREF="x572.html"><LINK
REL="NEXT"
TITLE="Memory Model"
HREF="x647.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x572.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Ophis Command Reference</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x647.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN620"
>Compound Arguments</A
></H1
><P
> Compound arguments may be built up from simple ones, using the
standard +, -, *, and / operators, which carry the usual
precedence. Also, the unary operators &#62; and &#60;, which
bind more tightly than anything else, provide the high and low
bytes of 16-bit values, respectively.
</P
><P
> Use brackets [ ] instead of parentheses ( ) when grouping
arithmetic operations, as the parentheses are needed for the
indirect addressing modes.
</P
><P
> Examples:
</P
><P
></P
><UL
><LI
><P
><TT
CLASS="LITERAL"
>$D000</TT
> evaluates to $D000</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>$D000+32</TT
> evaluates to $D020</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>$D000+$20</TT
> also evaluates to $D020</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>&#60;$D000+32</TT
> evaluates to $20</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>&#62;$D000+32</TT
> evaluates to $F0</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>&#62;[$D000+32]</TT
> evaluates to $D0</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>&#62;$D000-275</TT
> evaluates to $CE</P
></LI
></UL
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x572.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x647.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Basic arguments</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a505.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Memory Model</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

373
site/manual/x647.html Normal file
View File

@ -0,0 +1,373 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Memory Model</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Ophis Command Reference"
HREF="a505.html"><LINK
REL="PREVIOUS"
TITLE="Compound Arguments"
HREF="x620.html"><LINK
REL="NEXT"
TITLE="Macros"
HREF="x692.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x620.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Ophis Command Reference</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x692.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN647"
>Memory Model</A
></H1
><P
> 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.
</P
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN650"
>Basic PC tracking</A
></H2
><P
> The primary technique Ophis uses is <I
CLASS="EMPHASIS"
>program counter
tracking</I
>. As it assembles the code, it keeps
track of a virtual program counter, and uses that to
determine where the labels should go.
</P
><P
> In the absence of an <TT
CLASS="LITERAL"
>.org</TT
> directive, it
assumes a starting PC of zero. <TT
CLASS="LITERAL"
>.org</TT
>
is a simple directive, setting the PC to the value
that <TT
CLASS="LITERAL"
>.org</TT
> specifies. In the simplest
case, one <TT
CLASS="LITERAL"
>.org</TT
> directive appears at the
beginning of the code and sets the location for the rest of
the code, which is one contiguous block.
</P
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN659"
>Basic Segmentation simulation</A
></H2
><P
> 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.
</P
><P
> It is possible, but inconvenient, to do this
with <TT
CLASS="LITERAL"
>.alias</TT
>, assigning a specific
memory location to each variable. This requires careful
coordination through your code, and makes creating reusable
libraries all but impossible.
</P
><P
> A better approach is to reserve a section at the beginning
or end of your program, put an <TT
CLASS="LITERAL"
>.org</TT
>
directive in, then use the <TT
CLASS="LITERAL"
>.space</TT
>
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.
</P
><P
> The <TT
CLASS="LITERAL"
>.text</TT
>
and <TT
CLASS="LITERAL"
>.data</TT
> 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 <TT
CLASS="LITERAL"
>.data</TT
> section (filled
with <TT
CLASS="LITERAL"
>.space</TT
> commands) and
a <TT
CLASS="LITERAL"
>.text</TT
> 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 <TT
CLASS="LITERAL"
>.included</TT
> by multiple
projects without getting in anything's way.
</P
><P
> However, any given program may have its own ideas about
where data and code go, and it's good to ensure with
a <TT
CLASS="LITERAL"
>.checkpc</TT
> at the end of your code
that you haven't accidentally overwritten code with data or
vice versa. If your <TT
CLASS="LITERAL"
>.data</TT
>
segment <I
CLASS="EMPHASIS"
>did</I
> 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).
</P
><P
> If you write code with no segment-defining statements in
it, the default segment
is <TT
CLASS="LITERAL"
>text</TT
>.
</P
><P
> The <TT
CLASS="LITERAL"
>data</TT
> segment is designed only
for organizing labels. As such, errors will be flagged if
you attempt to actually output information into
a <TT
CLASS="LITERAL"
>data</TT
> segment.
</P
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN683"
>General Segmentation Simulation</A
></H2
><P
> 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 <TT
CLASS="LITERAL"
>.text</TT
>
or <TT
CLASS="LITERAL"
>.data</TT
> produces a new segment with
the specified name.
</P
><P
> 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:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.data
.org $200
.data zp
.org $2
.text
.org $800</PRE
></TD
></TR
></TABLE
><P
> And, to be safe, we would probably want to end our code
with checks to make sure we aren't overwriting anything:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.data
.checkpc $800
.data zp
.checkpc $100</PRE
></TD
></TR
></TABLE
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x620.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x692.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Compound Arguments</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a505.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Macros</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

358
site/manual/x692.html Normal file
View File

@ -0,0 +1,358 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Macros</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Ophis Command Reference"
HREF="a505.html"><LINK
REL="PREVIOUS"
TITLE="Memory Model"
HREF="x647.html"><LINK
REL="NEXT"
TITLE="Assembler directives"
HREF="x732.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x647.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Ophis Command Reference</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x732.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN692"
>Macros</A
></H1
><P
> Assembly language is a powerful tool&#8212;however, there are
many tasks that need to be done repeatedly, and with
mind-numbing minor modifications. Ophis includes a facility
for <I
CLASS="EMPHASIS"
>macros</I
> to allow this. Ophis macros
are very similar in form to function calls in higher level
languages.
</P
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN696"
>Defining Macros</A
></H2
><P
> Macros are defined with the <TT
CLASS="LITERAL"
>.macro</TT
>
and <TT
CLASS="LITERAL"
>.macend</TT
> commands. Here's a
simple one that will clear the screen on a Commodore
64:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.macro clr'screen
lda #147
jsr $FFD2
.macend</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN702"
>Invoking Macros</A
></H2
><P
> To invoke a macro, either use
the <TT
CLASS="LITERAL"
>.invoke</TT
> 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:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.invoke clr'screen</PRE
></TD
></TR
></TABLE
><P
>or</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>`clr'screen</PRE
></TD
></TR
></TABLE
><P
>will work equally well.</P
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN710"
>Passing Arguments to Macros</A
></H2
><P
> Macros may take arguments. The arguments to a macro are
all of the <SPAN
CLASS="QUOTE"
>"word"</SPAN
> type, though byte values may
be passed and used as bytes as well. The first argument in
an invocation is bound to the label
<TT
CLASS="LITERAL"
>_1</TT
>, the second
to <TT
CLASS="LITERAL"
>_2</TT
>, and so on. Here's a macro
for storing a 16-bit value into a word pointer:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.macro store16 ; `store16 dest, src
lda #&#60;_2
sta _1
lda #&#62;_2
sta _1+1
.macend</PRE
></TD
></TR
></TABLE
><P
> Macro arguments behave, for the most part, as if they were
defined by <TT
CLASS="LITERAL"
>.alias</TT
>
commands <I
CLASS="EMPHASIS"
>in the calling context</I
>.
(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.)
</P
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN720"
>Features and Restrictions of the Ophis Macro Model</A
></H2
><P
> 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.
</P
><P
> The primary benefit of this <SPAN
CLASS="QUOTE"
>"expand-via-binding"</SPAN
>
discipline is that there are no surprises in the semantics.
The expression <TT
CLASS="LITERAL"
>_1+1</TT
> 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.
</P
><P
> 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 <TT
CLASS="LITERAL"
>LDA _1</TT
> and
accept as arguments both <TT
CLASS="LITERAL"
>$C000</TT
>
(which would put the value of memory location $C000 into
the accumulator) and <TT
CLASS="LITERAL"
>#$40</TT
> (which
would put the immediate value $40 into the accumulator).
If you <I
CLASS="EMPHASIS"
>really</I
> need this kind of
behavior, a run a C preprocessor over your Ophis source,
and use <TT
CLASS="LITERAL"
>#define</TT
> to your heart's
content.
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x647.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x732.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Memory Model</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a505.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Assembler directives</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

595
site/manual/x732.html Normal file
View File

@ -0,0 +1,595 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Assembler directives</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Ophis Command Reference"
HREF="a505.html"><LINK
REL="PREVIOUS"
TITLE="Macros"
HREF="x692.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x692.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Ophis Command Reference</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
>&nbsp;</TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN732"
>Assembler directives</A
></H1
><P
> Assembler directives are all instructions to the assembler
that are not actual instructions. Ophis's set of directives
follow.
</P
><P
></P
><UL
><LI
><P
><TT
CLASS="LITERAL"
>.advance</TT
> <I
CLASS="EMPHASIS"
>address</I
>:
Forces the program counter to
be <I
CLASS="EMPHASIS"
>address</I
>. Unlike
the <TT
CLASS="LITERAL"
>.org</TT
>
directive, <TT
CLASS="LITERAL"
>.advance</TT
> outputs zeroes until the
program counter reaches a specified address. Attempting
to <TT
CLASS="LITERAL"
>.advance</TT
> to a point behind the current
program counter is an assemble-time error.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.alias</TT
> <I
CLASS="EMPHASIS"
>label</I
> <I
CLASS="EMPHASIS"
>value</I
>: 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).</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.byte</TT
> <I
CLASS="EMPHASIS"
>arg</I
> [ , <I
CLASS="EMPHASIS"
>arg</I
>, ... ]:
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.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.checkpc</TT
> <I
CLASS="EMPHASIS"
>address</I
>: Ensures that the
program counter is less than or equal to the address
specified, and emits an assemble-time error if it is not.
<I
CLASS="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.</I
></P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.data</TT
> <I
CLASS="EMPHASIS"
>[label]</I
>: Sets the segment to
the segment name specified and disallows output. If no label
is given, switches to the default data segment.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.incbin</TT
> <I
CLASS="EMPHASIS"
>filename</I
>: Inserts the
contents of the file specified as binary data. Use it to
include graphics information, precompiled code, or other
non-assembler data.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.include</TT
> <I
CLASS="EMPHASIS"
>filename</I
>: Includes the
entirety of the file specified at that point in the program.
Use this to order your final sources.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.org</TT
> <I
CLASS="EMPHASIS"
>address</I
>: Sets the program
counter to the address specified. <I
CLASS="EMPHASIS"
>This does not emit any
code in and of itself, nor does it overwrite anything that
previously existed.</I
> If you wish to jump ahead in memory,
use <TT
CLASS="LITERAL"
>.advance</TT
>.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.require</TT
> <I
CLASS="EMPHASIS"
>filename</I
>: Includes the entirety
of the file specified at that point in the program. Unlike <TT
CLASS="LITERAL"
>.include</TT
>,
however, code included with <TT
CLASS="LITERAL"
>.require</TT
> will only be inserted once.
The <TT
CLASS="LITERAL"
>.require</TT
> 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.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.space</TT
> <I
CLASS="EMPHASIS"
>label</I
> <I
CLASS="EMPHASIS"
>size</I
>: 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 <I
CLASS="EMPHASIS"
>size</I
>
steps ahead. No actual code is produced. This is equivalent
to <TT
CLASS="LITERAL"
>label: .org ^+size</TT
>.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.text</TT
> <I
CLASS="EMPHASIS"
>[label]</I
>: Sets the segment to
the segment name specified and allows output. If no label is
given, switches to the default text segment.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.word</TT
> <I
CLASS="EMPHASIS"
>arg</I
> [ , <I
CLASS="EMPHASIS"
>arg</I
>, ... ]:
Like <TT
CLASS="LITERAL"
>.byte</TT
>, 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.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.dword</TT
> <I
CLASS="EMPHASIS"
>arg</I
> [ , <I
CLASS="EMPHASIS"
>arg</I
>, ...]:
Like <TT
CLASS="LITERAL"
>.word</TT
>, but for 32-bit values.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.wordbe</TT
> <I
CLASS="EMPHASIS"
>arg</I
> [ , <I
CLASS="EMPHASIS"
>arg</I
>, ...]:
Like <TT
CLASS="LITERAL"
>.word</TT
>, but stores the value in a big-endian format (high byte first).</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.dwordbe</TT
> <I
CLASS="EMPHASIS"
>arg</I
> [ , <I
CLASS="EMPHASIS"
>arg</I
>, ...]:
Like <TT
CLASS="LITERAL"
>.dword</TT
>, but stores the value high byte first.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.scope</TT
>: Starts a new scope block. Labels
that begin with an underscore are only reachable from within
their innermost enclosing <TT
CLASS="LITERAL"
>.scope</TT
> statement.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.scend</TT
>: Ends a scope block. Makes the
temporary labels defined since the last <TT
CLASS="LITERAL"
>.scope</TT
>
statement unreachable, and permits them to be redefined in a
new scope.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.macro</TT
> <I
CLASS="EMPHASIS"
>name</I
>: Begins a macro
definition block. This is a scope block that can be inlined
at arbitrary points with <TT
CLASS="LITERAL"
>.invoke</TT
>. Arguments to the
macro will be bound to temporary labels with names like
<TT
CLASS="LITERAL"
>_1</TT
>, <TT
CLASS="LITERAL"
>_2</TT
>, etc.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.macend</TT
>: Ends a macro definition
block.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.invoke</TT
> <I
CLASS="EMPHASIS"
>label</I
> [<I
CLASS="EMPHASIS"
>argument</I
> [,
<I
CLASS="EMPHASIS"
>argument</I
> ...]]: invokes (inlines) the specified
macro, binding the values of the arguments to the ones the
macro definition intends to read. A shorthand for <TT
CLASS="LITERAL"
>.invoke</TT
>
is the name of the macro to invoke, backquoted.</P
></LI
></UL
><P
> The following directives are deprecated, added for
compatibility with the old Perl
assembler <B
CLASS="COMMAND"
>P65</B
>. Use
the <TT
CLASS="LITERAL"
>-d</TT
> option to Ophis to enable
them.
</P
><P
></P
><UL
><LI
><P
><TT
CLASS="LITERAL"
>.ascii</TT
>: Equivalent to <TT
CLASS="LITERAL"
>.byte</TT
>,
which didn't used to be able to handle strings.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.code</TT
>: Equivalent to <TT
CLASS="LITERAL"
>.text</TT
>.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.segment</TT
>: Equivalent to <TT
CLASS="LITERAL"
>.text</TT
>,
from when there was no distinction between <TT
CLASS="LITERAL"
>.text</TT
> and
<TT
CLASS="LITERAL"
>.data</TT
> segments.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.address</TT
>: Equivalent to
<TT
CLASS="LITERAL"
>.word</TT
>.</P
></LI
><LI
><P
><TT
CLASS="LITERAL"
>.link</TT
> <I
CLASS="EMPHASIS"
>filename address</I
>: Assembles
the file specified as if it began at the address specified.
This is generally for use in <SPAN
CLASS="QUOTE"
>"top-level"</SPAN
> files, where there
is not necessarily a one-to-one correspondence between file
position and memory position. This is equivalent to an
<TT
CLASS="LITERAL"
>.org</TT
> directive followed by an <TT
CLASS="LITERAL"
>.include</TT
>.
With the introduction of the <TT
CLASS="LITERAL"
>.org</TT
> directive this one is
less useful (and in most cases, any <TT
CLASS="LITERAL"
>.org</TT
> statement
you use will actually be at the top of the <TT
CLASS="LITERAL"
>.include</TT
>d
file).</P
></LI
></UL
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x692.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>&nbsp;</TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Macros</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="a505.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>&nbsp;</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

7725
site/ophismanual.pdf Normal file

File diff suppressed because one or more lines are too long

17
src/Ophis/CmdLine.py Normal file
View File

@ -0,0 +1,17 @@
"""Command line options data.
verbose:
0: Only report errors
1: Announce each file as it is read, and data count (default)
2: As above, but also announce each pass.
3: As above, but print the IR after each pass.
4: As above, but print the labels after each pass.
6510 compatibility and deprecation are handled in Ophis.Main."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
verbose = 1;

202
src/Ophis/CorePragmas.py Normal file
View File

@ -0,0 +1,202 @@
"""Core pragmas
Provides the core assembler directives. It does not guarantee
compatibility with older versions of P65-Perl."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
from __future__ import nested_scopes
import Ophis.IR as IR
import Ophis.Frontend as FE
import Ophis.Errors as Err
loadedfiles={}
basecharmap = "".join([chr(x) for x in range(256)])
currentcharmap = basecharmap
def reset():
global loadedfiles, currentcharmap, basecharmap
loadedfiles={}
currentcharmap = basecharmap
def pragmaInclude(ppt, line, result):
"Includes a source file"
filename = line.expect("STRING").value
line.expect("EOL")
if type(filename)==str: result.append(FE.parse_file(ppt, filename))
def pragmaRequire(ppt, line, result):
"Includes a source file at most one time"
filename = line.expect("STRING").value
line.expect("EOL")
if type(filename)==str:
global loadedfiles
if filename not in loadedfiles:
loadedfiles[filename]=1
result.append(FE.parse_file(ppt, filename))
def pragmaIncbin(ppt, line, result):
"Includes a binary file"
filename = line.expect("STRING").value
line.expect("EOL")
if type(filename)==str:
f = file(filename, "rb")
bytes = f.read()
f.close()
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
result.append(IR.Node(ppt, "Byte", *bytes))
def pragmaCharmap(ppt, line, result):
"Modify the character map."
global currentcharmap, basecharmap
bytes = readData(line)
if len(bytes) == 0:
currentcharmap = basecharmap
else:
try:
base = bytes[0].data
newsubstr = "".join([chr(x.data) for x in bytes[1:]])
currentcharmap = currentcharmap[:base] + newsubstr + currentcharmap[base+len(newsubstr):]
if len(currentcharmap) != 256 or base < 0 or base > 255:
Err.log("Charmap replacement out of range")
currentcharmap = currentcharmap[:256]
except ValueError:
Err.log("Illegal character in .charmap directive")
def pragmaCharmapbin(ppt, line, result):
"Load a new character map from a file"
global currentcharmap
filename = line.expect("STRING").value
line.expect("EOL")
if type(filename)==str:
f = file(filename, "rb")
bytes = f.read()
f.close()
if len(bytes)==256:
currentcharmap = bytes
else:
Err.log("Character map "+filename+" not 256 bytes long")
def pragmaOrg(ppt, line, result):
"Relocates the PC with no output"
newPC = FE.parse_expr(line)
line.expect("EOL")
result.append(IR.Node(ppt, "SetPC", newPC))
def pragmaAdvance(ppt, line, result):
"Outputs filler until reaching the target PC"
newPC = FE.parse_expr(line)
line.expect("EOL")
result.append(IR.Node(ppt, "Advance", newPC))
def pragmaCheckpc(ppt, line, result):
"Enforces that the PC has not exceeded a certain point"
target = FE.parse_expr(line)
line.expect("EOL")
result.append(IR.Node(ppt, "CheckPC", target))
def pragmaAlias(ppt, line, result):
"Assigns an arbitrary label"
lbl = line.expect("LABEL").value
target = FE.parse_expr(line)
result.append(IR.Node(ppt, "Label", lbl, target))
def pragmaSpace(ppt, line, result):
"Reserves space in a data segment for a variable"
lbl = line.expect("LABEL").value
size = line.expect("NUM").value
line.expect("EOL")
result.append(IR.Node(ppt, "Label", lbl, IR.PCExpr()))
result.append(IR.Node(ppt, "SetPC", IR.SequenceExpr([IR.PCExpr(), "+", IR.ConstantExpr(size)])))
def pragmaText(ppt, line, result):
"Switches to a text segment"
next = line.expect("LABEL", "EOL")
if next.type == "LABEL":
line.expect("EOL")
segment = next.value
else:
segment = "*text-default*"
result.append(IR.Node(ppt, "TextSegment", segment))
def pragmaData(ppt, line, result):
"Switches to a data segment (no output allowed)"
next = line.expect("LABEL", "EOL")
if next.type == "LABEL":
line.expect("EOL")
segment = next.value
else:
segment = "*data-default*"
result.append(IR.Node(ppt, "DataSegment", segment))
def readData(line):
"Read raw data from a comma-separated list"
if line.lookahead(0).type == "STRING":
data = [IR.ConstantExpr(ord(x)) for x in line.expect("STRING").value.translate(currentcharmap)]
else:
data = [FE.parse_expr(line)]
next = line.expect(',', 'EOL').type
while next == ',':
if line.lookahead(0).type == "STRING":
data.extend([IR.ConstantExpr(ord(x)) for x in line.expect("STRING").value])
else:
data.append(FE.parse_expr(line))
next = line.expect(',', 'EOL').type
return data
def pragmaByte(ppt, line, result):
"Raw data, a byte at a time"
bytes = readData(line)
result.append(IR.Node(ppt, "Byte", *bytes))
def pragmaWord(ppt, line, result):
"Raw data, a word at a time, little-endian"
words = readData(line)
result.append(IR.Node(ppt, "Word", *words))
def pragmaDword(ppt, line, result):
"Raw data, a double-word at a time, little-endian"
dwords = readData(line)
result.append(IR.Node(ppt, "Dword", *dwords))
def pragmaWordbe(ppt, line, result):
"Raw data, a word at a time, big-endian"
words = readData(line)
result.append(IR.Node(ppt, "WordBE", *words))
def pragmaDwordbe(ppt, line, result):
"Raw data, a dword at a time, big-endian"
dwords = readData(line)
result.append(IR.Node(ppt, "DwordBE", *dwords))
def pragmaScope(ppt, line, result):
"Create a new lexical scoping block"
line.expect("EOL")
result.append(IR.Node(ppt, "ScopeBegin"))
def pragmaScend(ppt, line, result):
"End the innermost lexical scoping block"
line.expect("EOL")
result.append(IR.Node(ppt, "ScopeEnd"))
def pragmaMacro(ppt, line, result):
"Begin a macro definition"
lbl = line.expect("LABEL").value
line.expect("EOL")
result.append(IR.Node(ppt, "MacroBegin", lbl))
def pragmaMacend(ppt, line, result):
"End a macro definition"
line.expect("EOL")
result.append(IR.Node(ppt, "MacroEnd"))
def pragmaInvoke(ppt, line, result):
macro = line.expect("LABEL").value
if line.lookahead(0).type == "EOL":
args = []
else:
args = readData(line)
result.append(IR.Node(ppt, "MacroInvoke", macro, *args))

75
src/Ophis/Environment.py Normal file
View File

@ -0,0 +1,75 @@
"""Symbol tables and environments for P65.
Implements the symbol lookup, through nested environments -
any non-temporary variable is stored at the top level."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
from __future__ import nested_scopes
import Ophis.Errors as Err
class Environment:
"""Environment class.
Controls the various scopes and global abstract execution variables."""
def __init__(self):
self.dicts = [{}]
self.stack = [0]
self.pc = 0
self.segmentdict = {}
self.segment = "*text-default*"
self.scopecount = 0
def __contains__(self, item):
if item[0] == '_':
for dict in [self.dicts[i] for i in self.stack]:
if item in dict: return 1
return 0
return item in self.dicts[0]
def __getitem__(self, item):
if item[0] == '_':
for dict in [self.dicts[i] for i in self.stack]:
if item in dict: return dict[item]
else:
if item in self.dicts[0]: return self.dicts[0][item]
Err.log("Unknown label '%s'" % item)
return 0
def __setitem__(self, item, value):
if item[0] == '_':
self.dicts[self.stack[0]][item] = value
else:
self.dicts[0][item] = value
def __str__(self):
return str(self.dicts)
def getPC(self):
return self.pc
def setPC(self, value):
self.pc = value
def incPC(self, amount):
self.pc += amount
def getsegment(self):
return self.segment
def setsegment(self, segment):
self.segmentdict[self.segment] = self.pc
self.segment = segment
self.pc = self.segmentdict.get(segment, 0)
def reset(self):
"Clears out program counter, segment, and scoping information"
self.pc = 0
self.segmentdict = {}
self.segment = "*text-default*"
self.scopecount = 0
if len(self.stack) > 1:
Err.log("Unmatched .scope")
self.stack = [0]
def newscope(self):
"Enters a new scope for temporary labels."
self.scopecount += 1
self.stack.insert(0, self.scopecount)
if len(self.dicts) <= self.scopecount: self.dicts.append({})
def endscope(self):
"Leaves a scope."
if len(self.stack) == 1:
Err.log("Unmatched .scend")
self.stack.pop(0)

24
src/Ophis/Errors.py Normal file
View File

@ -0,0 +1,24 @@
"""Error logging
Keeps track of the number of errors inflicted so far, and
where in the assembly the errors are occurring."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
count = 0
currentpoint = "<Top Level>"
def log(err):
"""Reports an error at the current program point, and increases
the global error count."""
global count
count = count+1
print currentpoint+": "+err
def report():
"Print out the number of errors."
if count == 0: print "No errors"
elif count == 1: print "1 error"
else: print str(count)+" errors"

333
src/Ophis/Frontend.py Normal file
View File

@ -0,0 +1,333 @@
"""Lexer and Parser
Constructs a list of IR nodes from a list of input strings."""
from __future__ import nested_scopes
import Ophis.Errors as Err
import Ophis.Opcodes as Ops
import Ophis.IR as IR
import Ophis.CmdLine as Cmd
import os
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
class Lexeme:
"Class for lexer tokens. Used by lexer and parser."
def __init__(self, type="UNKNOWN", value=None):
self.type = type.upper()
self.value = value
def __str__(self):
if self.value == None:
return self.type
else:
return self.type+":"+str(self.value)
def __repr__(self):
return "Lexeme("+`self.type`+", "+`self.value`+")"
def matches(self, other):
"1 if Lexemes a and b have the same type."
return self.type == other.type
bases = {"$":("hexadecimal", 16),
"%":("binary", 2),
"0":("octal", 8)}
punctuation = "#,`<>():.+-*/&|^[]"
def lex(point, line):
"""Turns a line of source into a sequence of lexemes."""
Err.currentpoint = point
result = []
def is_opcode(op):
"Tests whether a string is an opcode or an identifier"
return op in Ops.opcodes
def add_token(token):
"Converts a substring into a single lexeme"
if token == "":
return
if token == "0":
result.append(Lexeme("NUM", 0))
return
firstchar = token[0]
rest = token[1:]
if firstchar == '"':
result.append(Lexeme("STRING", rest))
return
elif firstchar in bases:
try:
result.append(Lexeme("NUM", long(rest, bases[firstchar][1])))
return
except ValueError:
Err.log('Invalid '+bases[firstchar][0]+' constant: '+rest)
result.append(Lexeme("NUM", 0))
return
elif firstchar.isdigit():
try:
result.append(Lexeme("NUM", long(token)))
except ValueError:
Err.log('Identifiers may not begin with a number')
result.append(Lexeme("LABEL", "ERROR"))
return
elif firstchar == "'":
if len(rest) == 1:
result.append(Lexeme("NUM", ord(rest)))
else:
Err.log("Invalid character constant '"+rest+"'")
result.append(Lexeme("NUM", 0))
return
elif firstchar in punctuation:
if rest != "":
Err.log("Internal lexer error! '"+token+"' can't happen!")
result.append(Lexeme(firstchar))
return
else: # Label, opcode, or index register
id = token.lower()
if is_opcode(id):
result.append(Lexeme("OPCODE", id))
elif id == "x":
result.append(Lexeme("X"))
elif id == "y":
result.append(Lexeme("Y"))
else:
result.append(Lexeme("LABEL", id))
return
# should never reach here
Err.log("Internal lexer error: add_token fall-through")
def add_EOL():
"Adds an end-of-line lexeme"
result.append(Lexeme("EOL"))
# Actual routine begins here
value = ""
quotemode = 0
backslashmode = 0
for c in line.strip():
if backslashmode:
backslashmode = 0
value = value + c
elif c == "\\":
backslashmode = 1
elif quotemode:
if c == '"':
quotemode = 0
else:
value = value + c
elif c == ';':
add_token(value)
value = ""
break
elif c.isspace():
add_token(value)
value = ""
elif c in punctuation:
add_token(value)
add_token(c)
value = ""
elif c == '"':
add_token(value)
value = '"'
quotemode = 1
else:
value = value + c
if backslashmode:
Err.log("Backslashed newline")
if quotemode:
Err.log("Unterminated string constant")
add_token(value)
add_EOL()
return result
class ParseLine:
"Maintains the parse state of a line of code. Enables arbitrary lookahead."
def __init__(self, lexemes):
self.lexemes = lexemes
self.location = 0
def lookahead(self, i):
"""Returns the token i units ahead in the parse.
lookahead(0) returns the next token; trying to read off the end of
the sequence returns the last token in the sequence (usually EOL)."""
target = self.location+i
if target >= len(self.lexemes): target = -1
return self.lexemes[target]
def pop(self):
"Returns and removes the next element in the line."
old = self.location
if self.location < len(self.lexemes)-1: self.location += 1
return self.lexemes[old]
def expect(self, *tokens):
"""Reads a token from the ParseLine line and returns it if it's of a type
in the sequence tokens. Otherwise, it logs an error."""
token = self.pop()
if token.type not in tokens:
Err.log('Expected: "'+'", "'.join(tokens)+'"')
return token
pragma_modules = []
def parse_expr(line):
"Parses an Ophis arithmetic expression."
def atom():
"Parses lowest-priority expression components."
next = line.lookahead(0).type
if next == "NUM":
return IR.ConstantExpr(line.expect("NUM").value)
elif next == "LABEL":
return IR.LabelExpr(line.expect("LABEL").value)
elif next == "^":
line.expect("^")
return IR.PCExpr()
elif next == "[":
line.expect("[")
result = parse_expr(line)
line.expect("]")
return result
elif next == "+":
offset = 0
while next == "+":
offset += 1
line.expect("+")
next = line.lookahead(0).type
return IR.LabelExpr("*"+str(templabelcount+offset))
elif next == "-":
offset = 1
while next == "-":
offset -= 1
line.expect("-")
next = line.lookahead(0).type
return IR.LabelExpr("*"+str(templabelcount+offset))
elif next == ">":
line.expect(">")
return IR.HighByteExpr(atom())
elif next == "<":
line.expect("<")
return IR.LowByteExpr(atom())
else:
Err.log('Expected: expression')
def precedence_read(constructor, reader, separators):
"""Handles precedence. The reader argument is a function that returns
expressions that bind more tightly than these; separators is a list
of strings naming the operators at this precedence level. The
constructor argument is a class, indicating what node type holds
objects of this precedence level.
Returns a list of Expr objects with separator strings between them."""
result = [reader()] # first object
nextop = line.lookahead(0).type
while (nextop in separators):
line.expect(nextop)
result.append(nextop)
result.append(reader())
nextop = line.lookahead(0).type
if len(result) == 1: return result[0]
return constructor(result)
def term():
"Parses * and /"
return precedence_read(IR.SequenceExpr, atom, ["*", "/"])
def arith():
"Parses + and -"
return precedence_read(IR.SequenceExpr, term, ["+", "-"])
def bits():
"Parses &, |, and ^"
return precedence_read(IR.SequenceExpr, arith, ["&", "|", "^"])
return bits()
def parse_line(ppt, lexemelist):
"Turn a line of source into an IR Node."
Err.currentpoint = ppt
result = []
line = ParseLine(lexemelist)
def aux():
"Accumulates all IR nodes defined by this line."
if line.lookahead(0).type == "EOL":
pass
elif line.lookahead(1).type == ":":
newlabel=line.expect("LABEL").value
line.expect(":")
result.append(IR.Node(ppt, "Label", newlabel, IR.PCExpr()))
aux()
elif line.lookahead(0).type == "*":
global templabelcount
templabelcount = templabelcount + 1
result.append(IR.Node(ppt, "Label", "*"+str(templabelcount), IR.PCExpr()))
line.expect("*")
aux()
elif line.lookahead(0).type == "." or line.lookahead(0).type == "`":
which = line.expect(".", "`").type
if (which == "."): pragma = line.expect("LABEL").value
else: pragma = "invoke"
pragmaFunction = "pragma"+pragma.title()
for mod in pragma_modules:
if hasattr(mod, pragmaFunction):
getattr(mod, pragmaFunction)(ppt, line, result)
break
else:
Err.log("Unknown pragma "+pragma)
else: # Instruction
opcode = line.expect("OPCODE").value
if line.lookahead(0).type == "#":
mode = "Immediate"
line.expect("#")
arg = parse_expr(line)
line.expect("EOL")
elif line.lookahead(0).type == "(":
line.expect("(")
arg = parse_expr(line)
if line.lookahead(0).type == ",":
mode = "PointerX"
line.expect(",")
line.expect("X")
line.expect(")")
line.expect("EOL")
else:
line.expect(")")
tok = line.expect(",", "EOL").type
if tok == "EOL":
mode = "Pointer"
else:
mode = "PointerY"
line.expect("Y")
line.expect("EOL")
elif line.lookahead(0).type == "EOL":
mode = "Implied"
arg = None
else:
arg = parse_expr(line)
tok = line.expect("EOL", ",").type
if tok == ",":
tok = line.expect("X", "Y").type
if tok == "X": mode = "MemoryX"
else: mode = "MemoryY"
line.expect("EOL")
else: mode = "Memory"
result.append(IR.Node(ppt, mode, opcode, arg))
aux()
result = [node for node in result if node is not IR.NullNode]
if len(result) == 0: return IR.NullNode
if len(result) == 1: return result[0]
return IR.SequenceNode(ppt, result)
def parse_file(ppt, filename):
"Loads a .P65 source file, and returns an IR list."
Err.currentpoint = ppt
if Cmd.verbose > 0: print "Loading "+filename
try:
f = file(filename)
linelist = f.readlines()
f.close()
pptlist = ["%s:%d" % (filename, i+1) for i in range(len(linelist))]
lexlist = map(lex, pptlist, linelist)
IRlist = map(parse_line, pptlist, lexlist)
IRlist = [node for node in IRlist if node is not IR.NullNode]
return IR.SequenceNode(ppt, IRlist)
except IOError:
Err.log ("Could not read "+filename)
return IR.NullNode
def parse(filename):
"Top level parsing routine, taking a source file name and returning an IR list."
global templabelcount
templabelcount = 0
return parse_file("<Top Level>", filename)

161
src/Ophis/IR.py Normal file
View File

@ -0,0 +1,161 @@
"""P65 Intermediate Representation
Classes for representing the Intermediate nodes upon which the
assembler passes operate."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
from __future__ import nested_scopes
import Ophis.Errors as Err
class Node:
"""The default IR Node
Instances of Node always have the three fields ppt(Program Point),
nodetype(a string), and data (a list)."""
def __init__(self, ppt, nodetype, *data):
self.ppt = ppt
self.nodetype = nodetype
self.data = list(data)
def accept(self, asmpass, env=None):
"""Implements the Visitor pattern for an assembler pass.
Calls the routine 'asmpass.visitTYPE(self, env)' where
TYPE is the value of self.nodetype."""
Err.currentpoint = self.ppt
routine = getattr(asmpass, "visit"+self.nodetype, asmpass.visitUnknown)
routine(self, env)
def __str__(self):
if self.nodetype != "SEQUENCE":
return str(self.ppt)+": "+self.nodetype+" - "+" ".join(map(str, self.data))
else:
return "\n".join(map(str, self.data))
def __repr__(self):
args = [self.ppt, self.nodetype] + self.data
return "Node(" + ", ".join(map(repr, args)) + ")"
NullNode = Node("<none>", "None")
def SequenceNode(ppt, nodelist):
return Node(ppt, "SEQUENCE", *nodelist)
class Expr:
"""Base class for P65 expressions
All expressions have a field called "data" and a boolean field
called "hardcoded". An expression is hardcoded if it has no
symbolic values in it."""
def __init__(self, data):
self.data = data
self.hardcoded = 0
def __str__(self):
return "<UNKNOWN: "+`self.data`+">"
def valid(self, env=None, PCvalid=0):
"""Returns true if the the expression can be successfully
evaluated in the specified environment."""
return 0
def value(self, env=None):
"Evaluates this expression in the given environment."
return None
class ConstantExpr(Expr):
"Represents a numeric constant"
def __init__(self, data):
self.data = data
self.hardcoded = 1
def __str__(self):
return str(self.data)
def valid(self, env=None, PCvalid=0):
return 1
def value(self, env=None):
return self.data
class LabelExpr(Expr):
"Represents a symbolic constant"
def __init__(self, data):
self.data = data
self.hardcoded = 0
def __str__(self):
return self.data
def valid(self, env=None, PCvalid=0):
return (env is not None) and self.data in env
def value(self, env=None):
return env[self.data]
class PCExpr(Expr):
"Represents the current program counter: ^"
def __init__(self):
self.hardcoded = 0
def __str__(self):
return "^"
def valid(self, env=None, PCvalid=0):
return env is not None and PCvalid
def value(self, env=None):
return env.getPC()
class HighByteExpr(Expr):
"Represents the expression >{data}"
def __init__(self, data):
self.data = data
self.hardcoded = data.hardcoded
def __str__(self):
return ">"+str(self.data)
def valid(self, env=None, PCvalid=0):
return self.data.valid(env, PCvalid)
def value(self, env=None):
val = self.data.value(env)
return (val >> 8) & 0xff
class LowByteExpr(Expr):
"Represents the expression <{data}"
def __init__(self, data):
self.data = data
self.hardcoded = data.hardcoded
def __str__(self):
return "<"+str(self.data)
def valid(self, env=None, PCvalid=0):
return self.data.valid(env, PCvalid)
def value(self, env=None):
val = self.data.value(env)
return val & 0xff
class SequenceExpr(Expr):
"""Represents an interleaving of operands (of type Expr) and
operators (of type String). Subclasses must provide a routine
operate(self, firstarg, op, secondarg) that evaluates the
operator."""
def __init__(self, data):
"""Constructor for Sequence Expressions. Results will be
screwy if the data inpot isn't a list with types
[Expr, str, Expr, str, Expr, str, ... Expr, str, Expr]."""
self.data = data
self.operands = [x for x in data if isinstance(x, Expr)]
self.operators = [x for x in data if type(x)==str]
for i in self.operands:
if not i.hardcoded:
self.hardcoded = 0
break
else:
self.hardcoded = 1
def __str__(self):
return "["+" ".join(map(str, self.data))+"]"
def valid(self, env=None, PCvalid=0):
for i in self.operands:
if not i.valid(env, PCvalid):
return 0
return 1
def value(self, env=None):
subs = map((lambda x: x.value(env)), self.operands)
result = subs[0]
index = 1
for op in self.operators:
result = self.operate(result, op, subs[index])
index += 1
return result
def operate(self, start, op, other):
if op=="*": return start * other
if op=="/": return start // other
if op=="+": return start + other
if op=="-": return start - other
if op=="&": return start & other
if op=="|": return start | other
if op=="^": return start ^ other

62
src/Ophis/Macro.py Normal file
View File

@ -0,0 +1,62 @@
"""Macro support for P65.
P65 Macros are cached SequenceNodes with arguments
set via .alias commands and prevented from escaping
with .scope and .scend commands."""
import sys
import Ophis.IR as IR
import Ophis.CmdLine as Cmd
import Ophis.Errors as Err
macros = {}
currentname = None
currentbody = None
def newMacro(name):
"Start creating a new macro with the specified name."
global currentname
global currentbody
global macros
if currentname is not None:
Err.log("Internal error! Nested macro attempt!")
else:
if name in macros:
Err.log("Duplicate macro definition '%s'" % name)
currentname = name
currentbody = []
def registerNode(node):
global currentbody
currentbody.append(IR.Node(node.ppt, node.nodetype, *node.data))
def endMacro():
global currentname
global currentbody
global macros
if currentname is None:
Err.log("Internal error! Ended a non-existent macro!")
else:
macros[currentname] = currentbody
currentname = None
currentbody = None
def expandMacro(ppt, name, arglist):
global macros
if name not in macros:
Err.log("Undefined macro '%s'" % name)
return IR.NullNode
argexprs = [IR.Node(ppt, "Label", "_*%d" % i, arg) for (i, arg) in zip(xrange(1, sys.maxint), arglist)]
bindexprs = [IR.Node(ppt, "Label", "_%d" % i, IR.LabelExpr("_*%d" % i)) for i in range(1, len(arglist)+1)]
body = [IR.Node("%s->%s" % (ppt, node.ppt), node.nodetype, *node.data) for node in macros[name]]
invocation = [IR.Node(ppt, "ScopeBegin")] + argexprs + [IR.Node(ppt, "ScopeBegin")] + bindexprs + body + [IR.Node(ppt, "ScopeEnd"), IR.Node(ppt, "ScopeEnd")]
return IR.SequenceNode(ppt, invocation)
def dump():
global macros
for mac in macros:
body = macros[mac]
print "Macro: "+mac
for node in body: print node
print ""

124
src/Ophis/Main.py Normal file
View File

@ -0,0 +1,124 @@
"""Main controller routines for the P65 assembler.
When invoked as main, interprets its command line and goes from there.
Otherwise, use run_all to interpret a file set."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
from __future__ import nested_scopes
import sys
import Ophis.Frontend
import Ophis.IR
import Ophis.CorePragmas
import Ophis.OldPragmas
import Ophis.Passes
import Ophis.Errors as Err
import Ophis.Environment
import Ophis.CmdLine
import Ophis.Opcodes
def usage():
"Prints a usage message and quits."
print "Usage:"
print "\tOphis [options] infile outfile"
print ""
print "Options:"
print "\t-6510 Allow 6510 undocumented opcodes"
print "\t-65c02 Enable 65c02 extensions"
print "\t-d Allow deprecated pragmas"
print "\t-v n Set verbosity to n (0-4, 1=default)"
sys.exit(1)
def run_all(infile, outfile):
"Transforms the source infile to a binary outfile."
Err.count = 0
z = Ophis.Frontend.parse(infile)
env = Ophis.Environment.Environment()
m = Ophis.Passes.ExpandMacros()
i = Ophis.Passes.InitLabels()
l_basic = Ophis.Passes.UpdateLabels()
l = Ophis.Passes.FixPoint("label update", [l_basic], lambda: l_basic.changed == 0)
c = Ophis.Passes.Collapse()
a = Ophis.Passes.Assembler()
passes = []
passes.append(Ophis.Passes.DefineMacros())
passes.append(Ophis.Passes.FixPoint("macro expansion", [m], lambda: m.changed == 0))
passes.append(Ophis.Passes.FixPoint("label initialization", [i], lambda: i.changed == 0))
passes.extend([Ophis.Passes.CircularityCheck(), Ophis.Passes.CheckExprs(), Ophis.Passes.EasyModes()])
passes.append(Ophis.Passes.FixPoint("instruction selection", [l, c], lambda: c.collapsed == 0))
passes.extend([Ophis.Passes.NormalizeModes(), Ophis.Passes.UpdateLabels(), a])
for p in passes: p.go(z, env)
if Err.count == 0:
try:
output = file(outfile, 'wb')
output.write("".join(map(chr, a.output)))
except IOError:
print "Could not write to "+outfile
else:
Err.report()
def run_ophis():
infile = None
outfile = None
p65_compatibility_mode = 0
chip_extension = None
reading_arg = 0
for x in sys.argv[1:]:
if reading_arg:
try:
Ophis.CmdLine.verbose = int(x)
reading_arg = 0
except ValueError:
print "FATAL: Non-integer passed as argument to -v"
usage()
elif x[0] == '-':
if x == '-v':
reading_arg = 1
elif x == '-6510':
chip_extension = Ophis.Opcodes.undocops
elif x == '-65c02':
chip_extension = Ophis.Opcodes.c02extensions
elif x == '-d':
p65_compatibility_mode = 1
else:
print "FATAL: Unknown option "+x
usage()
elif infile == None:
infile = x
elif outfile == None:
outfile = x
else:
print "FATAL: Too many files specified"
usage()
if infile is None:
print "FATAL: No files specified"
usage()
if outfile is None:
print "FATAL: No output file specified"
usage()
Ophis.Frontend.pragma_modules.append(Ophis.CorePragmas)
if p65_compatibility_mode:
Ophis.Frontend.pragma_modules.append(Ophis.OldPragmas)
if chip_extension is not None:
Ophis.Opcodes.opcodes.update(chip_extension)
Ophis.CorePragmas.reset()
run_all(infile, outfile)
if __name__ == '__main__':
run_ophis()

28
src/Ophis/OldPragmas.py Normal file
View File

@ -0,0 +1,28 @@
"""P65-Perl compatibility pragmas
Additional assembler directives to permit assembly of
old P65-Perl sources. This is not, in itself, sufficient,
as the precedence of < and > vs. + and - has changed
between P65-Perl and P65-Ophis.
Supported pragmas are: .ascii (byte), .address (word),
.segment (text), .code (text), and .link."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
import Ophis.CorePragmas as core
pragmaAscii = core.pragmaByte
pragmaAddress = core.pragmaWord
pragmaSegment = core.pragmaText
pragmaCode = core.pragmaText
def pragmaLink(ppt, line, result):
"Load a file in a precise memory location."
filename = line.expect("STRING").value
newPC = FE.parse_expr(line)
line.expect("EOL")
result.append(IR.Node(ppt, "SetPC", newPC))
if type(filename)==str: result.append(FE.parse_file(ppt, filename))

168
src/Ophis/Opcodes.py Normal file
View File

@ -0,0 +1,168 @@
"""Opcodes file.
Tables for the assembly of 6502-family instructions, mapping
opcodes and addressing modes to binary instructions."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
# Names of addressing modes
modes = ["Implied", # 0
"Immediate", # 1
"Zero Page", # 2
"Zero Page, X", # 3
"Zero Page, Y", # 4
"Absolute", # 5
"Absolute, X", # 6
"Absolute, Y", # 7
"(Absolute)", # 8
"(Absolute, X)", # 9
"(Absolute), Y", # 10
"(Zero Page)", # 11
"(Zero Page, X)", # 12
"(Zero Page), Y", # 13
"Relative"] # 14
# Lengths of the argument
lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]
opcodes = {
'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79, None, None, None, None, 0x61, 0x71, None],
'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39, None, None, None, None, 0x21, 0x31, None],
'asl': [0x0A, None, 0x06, 0x16, None, 0x0E, 0x1E, None, None, None, None, None, None, None, None],
'bcc': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x90],
'bcs': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xB0],
'beq': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xF0],
'bit': [None, None, 0x24, None, None, 0x2C, None, None, None, None, None, None, None, None, None],
'bmi': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x30],
'bne': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xD0],
'bpl': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x10],
'brk': [0x00, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'bvc': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x50],
'bvs': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x70],
'clc': [0x18, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'cld': [0xD8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'cli': [0x58, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'clv': [0xB8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9, None, None, None, None, 0xC1, 0xD1, None],
'cpx': [None, 0xE0, 0xE4, None, None, 0xEC, None, None, None, None, None, None, None, None, None],
'cpy': [None, 0xC0, 0xC4, None, None, 0xCC, None, None, None, None, None, None, None, None, None],
'dec': [None, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None, None, None, None, None, None, None, None],
'dex': [0xCA, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'dey': [0x88, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59, None, None, None, None, 0x41, 0x51, None],
'inc': [None, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None, None, None, None, None, None, None, None],
'inx': [0xE8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'iny': [0xC8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'jmp': [None, None, None, None, None, 0x4C, None, None, 0x6C, None, None, None, None, None, None],
'jsr': [None, None, None, None, None, 0x20, None, None, None, None, None, None, None, None, None],
'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9, None, None, None, None, 0xA1, 0xB1, None],
'ldx': [None, 0xA2, 0xA6, None, 0xB6, 0xAE, None, 0xBE, None, None, None, None, None, None, None],
'ldy': [None, 0xA0, 0xA4, 0xB4, None, 0xAC, 0xBC, None, None, None, None, None, None, None, None],
'lsr': [0x4A, None, 0x46, 0x56, None, 0x4E, 0x5E, None, None, None, None, None, None, None, None],
'nop': [0xEA, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'ora': [None, 0x09, 0x05, 0x15, None, 0x0D, 0x1D, 0x19, None, None, None, None, 0x01, 0x11, None],
'pha': [0x48, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'php': [0x08, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'pla': [0x68, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'plp': [0x28, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'rol': [0x2A, None, 0x26, 0x36, None, 0x2E, 0x3E, None, None, None, None, None, None, None, None],
'ror': [0x6A, None, 0x66, 0x76, None, 0x6E, 0x7E, None, None, None, None, None, None, None, None],
'rti': [0x40, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'rts': [0x60, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'sbc': [None, 0xE9, 0xE5, 0xF5, None, 0xED, 0xFD, 0xF9, None, None, None, None, 0xE1, 0xF1, None],
'sec': [0x38, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'sed': [0xF8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'sei': [0x78, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'sta': [None, None, 0x85, 0x95, None, 0x8D, 0x9D, 0x99, None, None, None, None, 0x81, 0x91, None],
'stx': [None, None, 0x86, None, 0x96, 0x8E, None, None, None, None, None, None, None, None, None],
'sty': [None, None, 0x84, 0x94, None, 0x8C, None, None, None, None, None, None, None, None, None],
'tax': [0xAA, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'tay': [0xA8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'tsx': [0xBA, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'txa': [0x8A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'txs': [0x9A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'tya': [0x98, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
}
undocops = {
'anc': [None, 0x0B, None, None, None, None, None, None, None, None, None, None, None, None, None],
'ane': [None, 0x8B, None, None, None, None, None, None, None, None, None, None, None, None, None],
'arr': [None, 0x6B, None, None, None, None, None, None, None, None, None, None, None, None, None],
'asr': [None, 0x4B, None, None, None, None, None, None, None, None, None, None, None, None, None],
'dcp': [None, None, 0xC7, 0xD7, None, 0xCF, 0xDF, 0xDB, None, None, None, None, 0xC3, 0xD3, None],
'isb': [None, None, 0xE7, 0xF7, None, 0xEF, 0xFF, 0xFB, None, None, None, None, 0xE3, 0xF3, None],
'las': [None, None, None, None, None, None, None, 0xBB, None, None, None, None, None, None, None],
'lax': [None, None, 0xA7, None, 0xB7, 0xAF, None, 0xBF, None, None, None, None, 0xA3, 0xB3, None],
'lxa': [None, 0xAB, None, None, None, None, None, None, None, None, None, None, None, None, None],
'rla': [None, None, 0x27, 0x37, None, 0x2F, 0x3F, 0x3B, None, None, None, None, 0x23, 0x33, None],
'rra': [None, None, 0x67, 0x77, None, 0x6F, 0x7F, 0x7B, None, None, None, None, 0x63, 0x73, None],
'sax': [None, None, 0x87, None, 0x97, 0x8F, None, None, None, None, None, None, 0x83, None, None],
'sbx': [None, 0xCB, None, None, None, None, None, None, None, None, None, None, None, None, None],
'sha': [None, None, None, None, None, None, None, 0x9F, None, None, None, None, None, 0x93, None],
'shs': [None, None, None, None, None, None, None, 0x9B, None, None, None, None, None, None, None],
'shx': [None, None, None, None, None, None, None, 0x9E, None, None, None, None, None, None, None],
'slo': [None, None, 0x07, 0x17, None, 0x0F, 0x1F, 0x1B, None, None, None, None, 0x03, 0x13, None],
'sre': [None, None, 0x47, 0x57, None, 0x4F, 0x5F, 0x5B, None, None, None, None, 0x43, 0x53, None],
}
c02extensions = {
'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79, None, None, None, 0x72, 0x61, 0x71, None],
'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39, None, None, None, 0x32, 0x21, 0x31, None],
'bbr0': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x0F],
'bbr1': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x1F],
'bbr2': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x2F],
'bbr3': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x3F],
'bbr4': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x4F],
'bbr5': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x5F],
'bbr6': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x6F],
'bbr7': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x7F],
'bbs0': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x8F],
'bbs1': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x9F],
'bbs2': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xAF],
'bbs3': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xBF],
'bbs4': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xCF],
'bbs5': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xDF],
'bbs6': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xEF],
'bbs7': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xFF],
'bit': [None, 0x89, 0x24, 0x34, None, 0x2C, 0x3C, None, None, None, None, None, None, None, None],
'bra': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x80],
'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9, None, None, None, 0xD2, 0xC1, 0xD1, None],
'dea': [0x3A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'dec': [0x3A, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None, None, None, None, None, None, None, None],
'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59, None, None, None, 0x52, 0x41, 0x51, None],
'ina': [0x1A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'inc': [0x1A, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None, None, None, None, None, None, None, None],
'jmp': [None, None, None, None, None, 0x4C, None, None, 0x6C, 0x7C, None, None, None, None, None],
'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9, None, None, None, 0xB2, 0xA1, 0xB1, None],
'ora': [None, 0x09, 0x05, 0x15, None, 0x0D, 0x1D, 0x19, None, None, None, 0x12, 0x01, 0x11, None],
'phx': [0xDA, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'phy': [0x5A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'plx': [0xFA, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'ply': [0x7A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'rmb0': [None, None, 0x07, None, None, None, None, None, None, None, None, None, None, None, None],
'rmb1': [None, None, 0x17, None, None, None, None, None, None, None, None, None, None, None, None],
'rmb2': [None, None, 0x27, None, None, None, None, None, None, None, None, None, None, None, None],
'rmb3': [None, None, 0x37, None, None, None, None, None, None, None, None, None, None, None, None],
'rmb4': [None, None, 0x47, None, None, None, None, None, None, None, None, None, None, None, None],
'rmb5': [None, None, 0x57, None, None, None, None, None, None, None, None, None, None, None, None],
'rmb6': [None, None, 0x67, None, None, None, None, None, None, None, None, None, None, None, None],
'rmb7': [None, None, 0x77, None, None, None, None, None, None, None, None, None, None, None, None],
'sbc': [None, 0xE9, 0xE5, 0xF5, None, 0xED, 0xFD, 0xF9, None, None, None, 0xF2, 0xE1, 0xF1, None],
'smb0': [None, None, 0x87, None, None, None, None, None, None, None, None, None, None, None, None],
'smb1': [None, None, 0x97, None, None, None, None, None, None, None, None, None, None, None, None],
'smb2': [None, None, 0xA7, None, None, None, None, None, None, None, None, None, None, None, None],
'smb3': [None, None, 0xB7, None, None, None, None, None, None, None, None, None, None, None, None],
'smb4': [None, None, 0xC7, None, None, None, None, None, None, None, None, None, None, None, None],
'smb5': [None, None, 0xD7, None, None, None, None, None, None, None, None, None, None, None, None],
'smb6': [None, None, 0xE7, None, None, None, None, None, None, None, None, None, None, None, None],
'smb7': [None, None, 0xF7, None, None, None, None, None, None, None, None, None, None, None, None],
'sta': [None, None, 0x85, 0x95, None, 0x8D, 0x9D, 0x99, None, None, None, 0x92, 0x81, 0x91, None],
'stp': [0xDB, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
'stz': [None, None, 0x64, 0x74, None, 0x9C, 0x9E, None, None, None, None, None, None, None, None],
'trb': [None, None, 0x14, None, None, 0x1C, None, None, None, None, None, None, None, None, None],
'tsb': [None, None, 0x04, None, None, 0x0C, None, None, None, None, None, None, None, None, None],
'wai': [0xCB, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
}

518
src/Ophis/Passes.py Normal file
View File

@ -0,0 +1,518 @@
"""The P65 Assembler passes
P65's design philosophy is to build the IR once, then run a great
many assembler passes over the result. Thus, each pass does a
single, specialized job. When strung together, the full
translation occurs. This structure also makes the assembler
very extensible; additional analyses or optimizations may be
added as new subclasses of Pass."""
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
from __future__ import nested_scopes
import Ophis.Errors as Err
import Ophis.IR as IR
import Ophis.Opcodes as Ops
import Ophis.CmdLine as Cmd
import Ophis.Macro as Macro
# The passes themselves
class Pass:
"""Superclass for all assembler passes. Automatically handles IR
types that modify the environent's structure, and by default
raises an error on anything else. Override visitUnknown in your
extension pass to produce a pass that accepts everything."""
name = "Default Pass"
def __init__(self):
self.writeOK = 1
def visitNone(self, node, env):
pass
def visitSEQUENCE(self, node, env):
Err.currentpoint = node.ppt
for n in node.data:
n.accept(self, env)
def visitDataSegment(self, node, env):
self.writeOK = 0
env.setsegment(node.data[0])
def visitTextSegment(self, node, env):
self.writeOK = 1
env.setsegment(node.data[0])
def visitScopeBegin(self, node, env):
env.newscope()
def visitScopeEnd(self, node, env):
env.endscope()
def visitUnknown(self, node, env):
Err.log("Internal error! "+self.name+" cannot understand node type "+node.nodetype)
def prePass(self):
pass
def postPass(self):
pass
def go(self, node, env):
"""Prepares the environment and runs this pass, possibly
printing debugging information."""
if Err.count == 0:
if Cmd.verbose > 1: print "Running: "+self.name
env.reset()
self.prePass()
node.accept(self, env)
self.postPass()
env.reset()
if Cmd.verbose > 3:
print "Current labels:"
print env
if Cmd.verbose > 2:
print "Current IR:"
print node
class FixPoint:
"""A specialized class that is not a pass but can be run like one.
This class takes a list of passes and a "fixpoint" function."""
def __init__(self, name, passes, fixpoint):
self.name = name
self.passes = passes
self.fixpoint = fixpoint
def go(self, node, env):
"""Runs this FixPoint's passes, in order, until the fixpoint
is true. Always runs the passes at least once."""
for i in xrange(100):
if Err.count != 0: break
for p in self.passes:
p.go(node, env)
if Err.count != 0: break
if self.fixpoint(): break
if Cmd.verbose > 1: print "Fixpoint failed, looping back"
else:
Err.log("Can't make %s converge! Maybe there's a recursive dependency somewhere?" % self.name)
class DefineMacros(Pass):
"Extract macro definitions and remove them from the IR"
name = "Macro definition pass"
def prePass(self):
self.inDef = 0
self.nestedError = 0
def postPass(self):
if self.inDef:
Err.log("Unmatched .macro")
elif Cmd.verbose > 2:
print "Macro definitions:"
Macro.dump()
def visitMacroBegin(self, node, env):
if self.inDef:
Err.log("Nested macro definition")
self.nestedError = 1
else:
Macro.newMacro(node.data[0])
node.nodetype = "None"
node.data = []
self.inDef = 1
def visitMacroEnd(self, node, env):
if self.inDef:
Macro.endMacro()
node.nodetype = "None"
node.data = []
self.inDef = 0
elif not self.nestedError:
Err.log("Unmatched .macend")
def visitUnknown(self, node, env):
if self.inDef:
Macro.registerNode(node)
node.nodetype = "None"
node.data = []
class ExpandMacros(Pass):
"Replace macro invocations with the appropriate text"
name = "Macro expansion pass"
def prePass(self):
self.changed = 0
def visitMacroInvoke(self, node, env):
replacement = Macro.expandMacro(node.ppt, node.data[0], node.data[1:])
node.nodetype = replacement.nodetype
node.data = replacement.data
self.changed = 1
def visitUnknown(self, node, env):
pass
class InitLabels(Pass):
"Finds all reachable labels"
name = "Label initialization pass"
def __init__(self):
Pass.__init__(self)
self.labelmap = {}
def prePass(self):
self.changed = 0
self.PCvalid = 1
def visitAdvance(self, node, env):
self.PCvalid=node.data[0].valid(env, self.PCvalid)
def visitSetPC(self, node, env):
self.PCvalid=node.data[0].valid(env, self.PCvalid)
def visitLabel(self, node, env):
(label, val) = node.data
fulllabel = "%d:%s" % (env.stack[0], label)
if fulllabel in self.labelmap and self.labelmap[fulllabel] is not node:
Err.log("Duplicate label definition '%s'" % label)
if fulllabel not in self.labelmap:
self.labelmap[fulllabel] = node
if val.valid(env, self.PCvalid) and label not in env:
env[label]=0
self.changed=1
def visitUnknown(self, node, env):
pass
class CircularityCheck(Pass):
"Checks for circular label dependencies"
name = "Circularity check pass"
def prePass(self):
self.changed=0
self.PCvalid=1
def visitAdvance(self, node, env):
PCvalid = self.PCvalid
self.PCvalid=node.data[0].valid(env, self.PCvalid)
if not node.data[0].valid(env, PCvalid):
Err.log("Undefined or circular reference on .advance")
def visitSetPC(self, node, env):
PCvalid = self.PCvalid
self.PCvalid=node.data[0].valid(env, self.PCvalid)
if not node.data[0].valid(env, PCvalid):
Err.log("Undefined or circular reference on program counter set")
def visitCheckPC(self, node, env):
if not node.data[0].valid(env, self.PCvalid):
Err.log("Undefined or circular reference on program counter check")
def visitLabel(self, node, env):
(label, val) = node.data
if not val.valid(env, self.PCvalid):
Err.log("Undefined or circular dependency for label '%s'" % label)
def visitUnknown(self, node, env):
pass
class CheckExprs(Pass):
"Ensures all expressions can resolve"
name = "Expression checking pass"
def visitUnknown(self, node, env):
for i in [x for x in node.data if isinstance(x, IR.Expr)]:
i.value(env) # Throw away result, just confirm validity of all expressions
class EasyModes(Pass):
"Assigns address modes to hardcoded and branch instructions"
name = "Easy addressing modes pass"
def visitMemory(self, node, env):
if Ops.opcodes[node.data[0]][14] is not None:
node.nodetype = "Relative"
return
if node.data[1].hardcoded:
if not collapse_no_index(node, env):
node.nodetype = "Absolute"
def visitMemoryX(self, node, env):
if node.data[1].hardcoded:
if not collapse_x(node, env):
node.nodetype = "AbsoluteX"
def visitMemoryY(self, node, env):
if node.data[1].hardcoded:
if not collapse_y(node, env):
node.nodetype = "AbsoluteY"
def visitPointer(self, node, env):
if node.data[1].hardcoded:
if not collapse_no_index_ind(node, env):
node.nodetype = "Indirect"
def visitPointerX(self, node, env):
if node.data[1].hardcoded:
if not collapse_x_ind(node, env):
node.nodetype = "AbsIndX"
def visitPointerY(self, node, env):
if node.data[1].hardcoded:
if not collapse_y_ind(node, env):
node.nodetype = "AbsIndY"
def visitUnknown(self, node, env):
pass
class UpdateLabels(Pass):
"Computes the new values for all entries in the symbol table"
name = "Label Update Pass"
def prePass(self):
self.changed = 0
def visitSetPC(self, node, env): env.setPC(node.data[0].value(env))
def visitAdvance(self, node, env): env.setPC(node.data[0].value(env))
def visitImplied(self, node, env): env.incPC(1)
def visitImmediate(self, node, env): env.incPC(2)
def visitIndirectX(self, node, env): env.incPC(2)
def visitIndirectY(self, node, env): env.incPC(2)
def visitZPIndirect(self, node, env): env.incPC(2)
def visitZeroPage(self, node, env): env.incPC(2)
def visitZeroPageX(self, node, env): env.incPC(2)
def visitZeroPageY(self, node, env): env.incPC(2)
def visitRelative(self, node, env): env.incPC(2)
def visitIndirect(self, node, env): env.incPC(3)
def visitAbsolute(self, node, env): env.incPC(3)
def visitAbsoluteX(self, node, env): env.incPC(3)
def visitAbsoluteY(self, node, env): env.incPC(3)
def visitAbsIndX(self, node, env): env.incPC(3)
def visitAbsIndY(self, node, env): env.incPC(3)
def visitMemory(self, node, env): env.incPC(3)
def visitMemoryX(self, node, env): env.incPC(3)
def visitMemoryY(self, node, env): env.incPC(3)
def visitPointer(self, node, env): env.incPC(3)
def visitPointerX(self, node, env): env.incPC(3)
def visitPointerY(self, node, env): env.incPC(3)
def visitCheckPC(self, node, env): pass
def visitLabel(self, node, env):
(label, val) = node.data
old = env[label]
env[label] = val.value(env)
if old != env[label]:
self.changed = 1
def visitByte(self, node, env): env.incPC(len(node.data))
def visitWord(self, node, env): env.incPC(len(node.data)*2)
def visitDword(self, node, env): env.incPC(len(node.data)*4)
def visitWordBE(self, node, env): env.incPC(len(node.data)*2)
def visitDwordBE(self, node, env): env.incPC(len(node.data)*4)
class Collapse(Pass):
"""Selects as many zero-page instructions to convert as
possible, and tracks how many instructions have been
converted this pass."""
name = "Instruction Collapse Pass"
def prePass(self):
self.collapsed = 0
def visitMemory(self, node, env):
if collapse_no_index(node, env): self.collapsed += 1
def visitMemoryX(self, node, env):
if collapse_x(node, env): self.collapsed += 1
def visitMemoryY(self, node, env):
if collapse_y(node, env): self.collapsed += 1
def visitPointer(self, node, env):
if collapse_no_index_ind(node, env): self.collapsed += 1
def visitPointerX(self, node, env):
if collapse_x_ind(node, env): self.collapsed += 1
def visitPointerY(self, node, env):
if collapse_y_ind(node, env): self.collapsed += 1
def visitUnknown(self, node, env):
pass
def collapse_no_index(node, env):
"""Transforms a Memory node into a ZeroPage one if possible.
Returns 1 if it made the collapse, false otherwise."""
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][2] is not None:
node.nodetype = "ZeroPage"
return 1
else:
return 0
def collapse_x(node, env):
"""Transforms a MemoryX node into a ZeroPageX one if possible.
Returns 1 if it made the collapse, false otherwise."""
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][3] is not None:
node.nodetype = "ZeroPageX"
return 1
else:
return 0
def collapse_y(node, env):
"""Transforms a MemoryY node into a ZeroPageY one if possible.
Returns 1 if it made the collapse, false otherwise."""
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][4] is not None:
node.nodetype = "ZeroPageY"
return 1
else:
return 0
def collapse_no_index_ind(node, env):
"""Transforms a Pointer node into a ZPIndirect one if possible.
Returns 1 if it made the collapse, false otherwise."""
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][11] is not None:
node.nodetype = "ZPIndirect"
return 1
else:
return 0
def collapse_x_ind(node, env):
"""Transforms a PointerX node into an IndirectX one if possible.
Returns 1 if it made the collapse, false otherwise."""
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][12] is not None:
node.nodetype = "IndirectX"
return 1
else:
return 0
def collapse_y_ind(node, env):
"""Transforms a PointerY node into an IndirectY one if possible.
Returns 1 if it made the collapse, false otherwise."""
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][13] is not None:
node.nodetype = "IndirectY"
return 1
else:
return 0
class NormalizeModes(Pass):
"""Eliminates the intermediate "Memory" and "Pointer" nodes,
converting them to "Absolute"."""
name = "Mode Normalization pass"
def visitMemory(self, node, env): node.nodetype = "Absolute"
def visitMemoryX(self, node, env): node.nodetype = "AbsoluteX"
def visitMemoryY(self, node, env): node.nodetype = "AbsoluteY"
def visitPointer(self, node, env): node.nodetype = "Indirect"
def visitPointerX(self, node, env): node.nodetype = "AbsIndX"
# If we ever hit a PointerY by this point, we have a bug.
def visitPointerY(self, node, env): node.nodetype = "AbsIndY"
def visitUnknown(self, node, env): pass
class Assembler(Pass):
"""Converts the IR into a list of bytes, suitable for writing to
a file."""
name = "Assembler"
def prePass(self):
self.output = []
self.code = 0
self.data = 0
self.filler = 0
def postPass(self):
if Cmd.verbose > 0 and Err.count == 0:
print "Assembly complete: %s bytes output (%s code, %s data, %s filler)" \
% (len(self.output), self.code, self.data, self.filler)
def outputbyte(self, expr, env):
'Outputs a byte, with range checking'
if self.writeOK:
val = expr.value(env)
if val < 0x00 or val > 0xff:
Err.log("Byte constant "+str(expr)+" out of range")
val = 0
self.output.append(int(val))
else:
Err.log("Attempt to write to data segment")
def outputword(self, expr, env):
'Outputs a little-endian word, with range checking'
if self.writeOK:
val = expr.value(env)
if val < 0x0000 or val > 0xFFFF:
Err.log("Word constant "+str(expr)+" out of range")
val = 0
self.output.append(int(val & 0xFF))
self.output.append(int((val >> 8) & 0xFF))
else:
Err.log("Attempt to write to data segment")
def outputdword(self, expr, env):
'Outputs a little-endian dword, with range checking'
if self.writeOK:
val = expr.value(env)
if val < 0x00000000 or val > 0xFFFFFFFFL:
Err.log("DWord constant "+str(expr)+" out of range")
val = 0
self.output.append(int(val & 0xFF))
self.output.append(int((val >> 8) & 0xFF))
self.output.append(int((val >> 16) & 0xFF))
self.output.append(int((val >> 24) & 0xFF))
else:
Err.log("Attempt to write to data segment")
def outputword_be(self, expr, env):
'Outputs a big-endian word, with range checking'
if self.writeOK:
val = expr.value(env)
if val < 0x0000 or val > 0xFFFF:
Err.log("Word constant "+str(expr)+" out of range")
val = 0
self.output.append(int((val >> 8) & 0xFF))
self.output.append(int(val & 0xFF))
else:
Err.log("Attempt to write to data segment")
def outputdword_be(self, expr, env):
'Outputs a big-endian dword, with range checking'
if self.writeOK:
val = expr.value(env)
if val < 0x00000000 or val > 0xFFFFFFFFL:
Err.log("DWord constant "+str(expr)+" out of range")
val = 0
self.output.append(int((val >> 24) & 0xFF))
self.output.append(int((val >> 16) & 0xFF))
self.output.append(int((val >> 8) & 0xFF))
self.output.append(int(val & 0xFF))
else:
Err.log("Attempt to write to data segment")
def assemble(self, node, mode, env):
"A generic instruction called by the visitor methods themselves"
(opcode, expr) = node.data
bin_op = Ops.opcodes[opcode][mode]
if bin_op is None:
Err.log('%s does not have mode "%s"' % (opcode.upper(), Ops.modes[mode]))
return
self.outputbyte(IR.ConstantExpr(bin_op), env)
arglen = Ops.lengths[mode]
if mode == 14: # Special handling for relative mode
arg = expr.value(env)
arg = arg-(env.getPC()+2)
if arg < -128 or arg > 127:
Err.log("Branch target out of bounds")
arg = 0
if arg < 0: arg += 256
expr = IR.ConstantExpr(arg)
if arglen == 1: self.outputbyte(expr, env)
if arglen == 2: self.outputword(expr, env)
env.incPC(1+arglen)
self.code += 1+arglen
def visitImplied(self, node, env): self.assemble(node, 0, env)
def visitImmediate(self, node, env): self.assemble(node, 1, env)
def visitZeroPage(self, node, env): self.assemble(node, 2, env)
def visitZeroPageX(self, node, env): self.assemble(node, 3, env)
def visitZeroPageY(self, node, env): self.assemble(node, 4, env)
def visitAbsolute(self, node, env): self.assemble(node, 5, env)
def visitAbsoluteX(self, node, env): self.assemble(node, 6, env)
def visitAbsoluteY(self, node, env): self.assemble(node, 7, env)
def visitIndirect(self, node, env): self.assemble(node, 8, env)
def visitAbsIndX(self, node, env): self.assemble(node, 9, env)
def visitAbsIndY(self, node, env): self.assemble(node, 10, env)
def visitZPIndirect(self, node, env): self.assemble(node, 11, env)
def visitIndirectX(self, node, env): self.assemble(node, 12, env)
def visitIndirectY(self, node, env): self.assemble(node, 13, env)
def visitRelative(self, node, env): self.assemble(node, 14, env)
def visitLabel(self, node, env): pass
def visitByte(self, node, env):
for expr in node.data:
self.outputbyte(expr, env)
env.incPC(len(node.data))
self.data += len(node.data)
def visitWord(self, node, env):
for expr in node.data:
self.outputword(expr, env)
env.incPC(len(node.data)*2)
self.data += len(node.data)*2
def visitDword(self, node, env):
for expr in node.data:
self.outputdword(expr, env)
env.incPC(len(node.data)*4)
self.data += len(node.data)*4
def visitWordBE(self, node, env):
for expr in node.data:
self.outputword_be(expr, env)
env.incPC(len(node.data)*2)
self.data += len(node.data)*2
def visitDwordBE(self, node, env):
for expr in node.data:
self.outputdword_be(expr, env)
env.incPC(len(node.data)*4)
self.data += len(node.data)*4
def visitSetPC(self, node, env):
env.setPC(node.data[0].value(env))
def visitCheckPC(self, node, env):
pc = env.getPC()
target = node.data[0].value(env)
if (pc > target):
Err.log(".checkpc assertion failed: $%x > $%x" % (pc, target))
def visitAdvance(self, node, env):
pc = env.getPC()
target = node.data[0].value(env)
if (pc > target):
Err.log("Attempted to .advance backwards: $%x to $%x" % (pc, target))
else:
zero = IR.ConstantExpr(0)
for i in xrange(target-pc): self.outputbyte(zero, env)
self.filler += target-pc
env.setPC(target)

5
src/Ophis/__init__.py Normal file
View File

@ -0,0 +1,5 @@
"P65 - a cross-assembler for the 6502 series of chips"
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.

4
src/ophismain.py Normal file
View File

@ -0,0 +1,4 @@
#!/usr/local/bin/python
import Ophis.Main
Ophis.Main.run_ophis()

1
tests/test6510.bin Normal file
View File

@ -0,0 +1 @@
 ##''///3377;;;???CCGGKKOOOSSWW[[[___ccggkkooossww{{{儍噰媼弿彄摋棝洓灋灍煙Ё<EFBC83><D081><EFBFBD>撤坊换靠棵们撬讼舷佑鬃圹圻哌沣珑镲矬篦鼷<E7AFA6><E9BCB7><EFBFBD><EFBFBD>

78
tests/test6510.oph Normal file
View File

@ -0,0 +1,78 @@
; Test file for base 6510 undocumented opcode compliance
; This odd little source file uses every addressing mode
; of every opcode, and uses the opcode itself as the argument
; to each instruction that takes one. The resulting binary's
; bytes are thus in strictly increasing numerical order.
; Many mnemonics have multiple opcodes with identical
; effects; Ophis chooses one of them and the arguments
; herein assume that any assembler will choose as Ophis
; does.
; This file also doesn't include the 6502's *documented*
; opcodes - see testbase.oph for those.
SLO ($03, X)
SLO $07
ANC #$0B
SLO $0F0F
SLO ($13), Y
SLO $17, X
SLO $1B1B, Y
SLO $1F1F, X
RLA ($23, X)
RLA $27
RLA $2F2F
RLA ($33), Y
RLA $37, X
RLA $3B3B, Y
RLA $3F3F, X
SRE ($43, X)
SRE $47
ASR #$4B
SRE $4F4F
SRE ($53), Y
SRE $57, X
SRE $5B5B, Y
SRE $5F5F, X
RRA ($63, X)
RRA $67
ARR #$6B
RRA $6F6F
RRA ($73), Y
RRA $77, X
RRA $7B7B, Y
RRA $7F7F, X
SAX ($83, X)
SAX $87
ANE #$8B
SAX $8F8F
SHA ($93), Y
SAX $97, Y
SHS $9B9B, Y
SHX $9E9E, Y
SHA $9F9F, Y
LAX ($A3, X)
LAX $A7
LXA #$AB
LAX $AFAF
LAX ($B3), Y
LAX $B7, Y
LAS $BBBB, Y
LAX $BFBF, Y
DCP ($C3, X)
DCP $C7
SBX #$CB
DCP $CFCF
DCP ($D3), Y
DCP $D7, X
DCP $DBDB, Y
DCP $DFDF, X
ISB ($E3, X)
ISB $E7
ISB $EFEF
ISB ($F3), Y
ISB $F7, X
ISB $FBFB, Y
ISB $FFFF, X

1
tests/test65c02.bin Normal file
View File

@ -0,0 +1 @@
 ''//224477::<<<??GGOORRWWZ__ddggoorrttwwz|||€€‡‡‰‰<E280B0><E280B0>——œœœžžžŸŸ§§¯¯²²··¿¿ÇÇËÏÏÒÒ××ÚÛßßççïïòò÷÷úÿÿ

74
tests/test65c02.oph Normal file
View File

@ -0,0 +1,74 @@
; Test file for 65C02 extended opcode compliance
; This odd little source file uses every addressing mode
; of every opcode, and uses the opcode itself as the argument
; to each instruction that takes one. The resulting binary's
; bytes are thus in strictly increasing numerical order.
; Some opcodes have multiple mnemonics; we provide both.
; This file also doesn't include the 65C02's opcodes that
; are also available in stock 6502s - see testbase.oph for
; those.
TSB $04 ; 04: TSB - Zero Page
RMB0 $07 ; 07: RMB0 - Zero Page
TSB $0C0C ; 0C: TSB - Absolute
BBR0 ^+$11 ; 0F: BBR0 - Relative
ORA ($12) ; 12: ORA - (Zero Page)
TRB $14 ; 14: TRB - Zero Page
RMB1 $17 ; 17: RMB1 - Zero Page
INA ; 1A: INA - Implied
INC ; INC - Implied
TRB $1C1C ; 1C: TRB - Absolute
BBR1 ^+$21 ; 1F: BBR1 - Relative
RMB2 $27 ; 27: RMB2 - Zero Page
BBR2 ^+$31 ; 2F: BBR2 - Relative
AND ($32) ; 32: AND - (Zero Page)
BIT $34, X ; 34: BIT - Zero Page, X
RMB3 $37 ; 37: RMB3 - Zero Page
DEA ; 3A: DEA - Implied
DEC ; 3A: DEC - Implied
BIT $3C3C,X ; 3C: BIT - Absolute, X
BBR3 ^+$41 ; 3F: BBR3 - Relative
RMB4 $47 ; 47: RMB4 - Zero Page
BBR4 ^+$51 ; 4F: BBR4 - Relative
EOR ($52) ; 52: EOR - (Zero Page)
RMB5 $57 ; 57: RMB5 - Zero Page
PHY ; 5A: PHY - Implied
BBR5 ^+$61 ; 5F: BBR5 - Relative
STZ $64 ; 64: STZ - Zero Page
RMB6 $67 ; 67: RMB6 - Zero Page
BBR6 ^+$71 ; 6F: BBR6 - Relative
ADC ($72) ; 72: ADC - (Zero Page)
STZ $74, X ; 74: STZ - Zero Page, X
RMB7 $77 ; 77: RMB7 - Zero Page
PLY ; 7A: PLY - Implied
JMP ($7C7C, X) ; 7C: JMP - (Absolute, X)
BBR7 ^+$81 ; 7F: BBR7 - Relative
BRA ^-$7E ; 80: BRA - Relative
SMB0 $87 ; 87: SMB0 - Zero Page
BIT #$89 ; 89: BIT - Immediate
BBS0 ^-$6F ; 8F: BBS0 - Relative
STA ($92) ; 92: STA - (Zero Page)
SMB1 $97 ; 97: SMB1 - Zero Page
STZ $9C9C ; 9C: STZ - Absolute
STZ $9E9E, X ; 9E: STZ - Absolute, X
BBS1 ^-$5F ; 9F: BBS1 - Relative
SMB2 $A7 ; A7: SMB2 - Zero Page
BBS2 ^-$4F ; AF: BBS2 - Relative
LDA ($B2) ; B2: LDA - (Zero Page)
SMB3 $B7 ; B7: SMB3 - Zero Page
BBS3 ^-$3F ; BF: BBS3 - Relative
SMB4 $C7 ; C7: SMB4 - Zero Page
WAI ; CB: WAI - Implied
BBS4 ^-$2F ; CF: BBS4 - Relative
CMP ($D2) ; D2: CMP - (Zero Page)
SMB5 $D7 ; D7: SMB5 - Zero Page
PHX ; DA: PHX - Implied
STP ; DB: STP - Implied
BBS5 ^-$1F ; DF: BBS5 - Relative
SMB6 $E7 ; E7: SMB6 - Zero Page
BBS6 ^-$0F ; EF: BBS6 - Relative
SBC ($F2) ; F2: SBC - (Zero Page)
SMB7 $F7 ; F7: SMB7 - Zero Page
PLX ; FA: PLX - Implied
BBS7 ^+$01 ; FF: BBS7 - Relative

BIN
tests/testbase.bin Normal file

Binary file not shown.

157
tests/testbase.oph Normal file
View File

@ -0,0 +1,157 @@
; Test file for base 6502 opcode compliance
; This odd little source file uses every addressing mode
; of every opcode, and uses the opcode itself as the argument
; to each instruction that takes one. The resulting binary's
; bytes are thus in strictly increasing numerical order.
BRK
ORA ($01, X)
ORA $05
ASL $06
PHP
ORA #$09
ASL
ORA $0D0D
ASL $0E0E
BPL ^+$12
ORA ($11), Y
ORA $15, X
ASL $16, X
CLC
ORA $1919, Y
ORA $1D1D, X
ASL $1E1E, X
JSR $2020
AND ($21, X)
BIT $24
AND $25
ROL $26
PLP
AND #$29
ROL
BIT $2C2C
AND $2D2D
ROL $2E2E
BMI ^+$32
AND ($31), Y
AND $35, X
ROL $36, X
SEC
AND $3939, Y
AND $3D3D, X
ROL $3E3E, X
RTI
EOR ($41, X)
EOR $45
LSR $46
PHA
EOR #$49
LSR
JMP $4C4C
EOR $4D4D
LSR $4E4E
BVC ^+$52
EOR ($51), Y
EOR $55, X
LSR $56, X
CLI
EOR $5959, Y
EOR $5D5D, X
LSR $5E5E, X
RTS
ADC ($61, X)
ADC $65
ROR $66
PLA
ADC #$69
ROR
JMP ($6C6C)
ADC $6D6D
ROR $6E6E
BVS ^+$72
ADC ($71), Y
ADC $75, X
ROR $76, X
SEI
ADC $7979, Y
ADC $7D7D, X
ROR $7E7E, X
STA ($81, X)
STY $84
STA $85
STX $86
DEY
TXA
STY $8C8C
STA $8D8D
STX $8E8E
BCC ^-$6E
STA ($91), Y
STY $94, X
STA $95, X
STX $96, Y
TYA
STA $9999, Y
TXS
STA $9D9D, X
LDY #$A0
LDA ($A1, X)
LDX #$A2
LDY $A4
LDA $A5
LDX $A6
TAY
LDA #$A9
TAX
LDY $ACAC
LDA $ADAD
LDX $AEAE
BCS ^-$4e
LDA ($B1), Y
LDY $B4, X
LDA $B5, X
LDX $B6, Y
CLV
LDA $B9B9,Y
TSX
LDY $BCBC, X
LDA $BDBD, X
LDX $BEBE, Y
CPY #$C0
CMP ($C1, X)
CPY $C4
CMP $C5
DEC $C6
INY
CMP #$C9
DEX
CPY $CCCC
CMP $CDCD
DEC $CECE
BNE ^-$2E
CMP ($D1), Y
CMP $D5, X
DEC $D6, X
CLD
CMP $D9D9, Y
CMP $DDDD, X
DEC $DEDE, X
CPX #$E0
SBC ($E1, X)
CPX $E4
SBC $E5
INC $E6
INX
SBC #$E9
NOP
CPX $ECEC
SBC $EDED
INC $EEEE
BEQ ^-$0E
SBC ($F1), Y
SBC $F5, X
INC $F6, X
SED
SBC $F9F9, Y
SBC $FDFD, X
INC $FEFE, X

BIN
tests/testdata.bin Normal file

Binary file not shown.

7
tests/testdata.oph Normal file
View File

@ -0,0 +1,7 @@
; This data file just dumps out $00-$0F repeatedly with different forms.
.byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
.word 256, $0302, $0504, $0706, $0908, $0b0a, $0d0c, $0f0e
.dword $03020100, $07060504, $0b0a0908, $0f0e0d0c
.wordbe 1, $0203, $0405, $0607, $0809, $0a0b, $0c0d, $0e0f
.dwordbe $010203, $04050607, $08090a0b, $0c0d0e0f

BIN
tools/charmaps/a2blink.map Normal file

Binary file not shown.

Binary file not shown.

BIN
tools/charmaps/a2normal.map Normal file

Binary file not shown.

View File

@ -0,0 +1,20 @@
#!/usr/bin/python
import struct
x = ''.join([chr(x) for x in range(256)])
bits = struct.unpack("32s32s32s32s32s32s32s32s", x)
norm = [4, 5, 6, 7, 0, 1, 2, 3]
ivrs = [4, 1, 0, 7, 6, 5, 2, 3]
blnk = [4, 3, 2, 7, 0, 1, 6, 5]
normmap = ''.join([bits[x] for x in norm])
ivrsmap = ''.join([bits[x] for x in ivrs])
blnkmap = ''.join([bits[x] for x in blnk])
def dumpfile(n, m):
f = file(n, 'wb')
f.write(m)
f.close()
dumpfile('a2normal.map', normmap)
dumpfile('a2inverse.map', ivrsmap)
dumpfile('a2blink.map', blnkmap)

BIN
tools/charmaps/petscii.map Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
opcodes: op6502.txt
undocops: op6510.txt
c02extensions: op65c02.txt

153
tools/opcodes/gensets.py Normal file
View File

@ -0,0 +1,153 @@
#!/usr/bin/python
import sys
verbose = 0
prologue = '"""' + """Opcodes file.
Tables for the assembly of 6502-family instructions, mapping
opcodes and addressing modes to binary instructions.""" + '"""' + """
# Copyright 2002 Michael C. Martin.
# You may use, modify, and distribute this file under the BSD
# license: See LICENSE.txt for details.
# Names of addressing modes
modes = ["Implied", # 0
"Immediate", # 1
"Zero Page", # 2
"Zero Page, X", # 3
"Zero Page, Y", # 4
"Absolute", # 5
"Absolute, X", # 6
"Absolute, Y", # 7
"(Absolute)", # 8
"(Absolute, X)", # 9
"(Absolute), Y", # 10
"(Zero Page)", # 11
"(Zero Page, X)", # 12
"(Zero Page), Y", # 13
"Relative"] # 14
# Lengths of the argument
lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]
"""
# These values should match the ones in the prologue string.
modes = ["Implied", # 0
"Immediate", # 1
"Zero Page", # 2
"Zero Page, X", # 3
"Zero Page, Y", # 4
"Absolute", # 5
"Absolute, X", # 6
"Absolute, Y", # 7
"(Absolute)", # 8
"(Absolute, X)", # 9
"(Absolute), Y", # 10
"(Zero Page)", # 11
"(Zero Page, X)", # 12
"(Zero Page), Y", # 13
"Relative"] # 14
flatmodes = [x.lower() for x in modes]
# WARNING: This decommenter assumes that # never appears anywhere else
# in a line.
def decomment (l):
if '#' in l:
l = l[:l.index('#')]
return l.strip()
def decomment_readlines (fname):
result = [decomment(x) for x in file(fname).readlines()]
return [x for x in result if len(x) > 0]
def parse_chipset_file (fname):
result = [None] * 256
ls = [[x.strip() for x in y] for y in [z.split(':', 1) for z in decomment_readlines (fname)]]
for l in ls:
if len(l) == 2:
try:
op = int (l[0], 16)
syns = l[1].split(';')
for s in syns:
s_p = s.split('-')
if len(s_p) == 2:
mnem = s_p[0].lower().strip()
mode = s_p[1].lower().strip()
if mode in flatmodes:
if result[op] == None:
result[op] = []
result[op].append((mnem, flatmodes.index(mode)))
else:
print "Unknown mode '%s'" % s_p[1]
except ValueError:
print "Illegal opcode '%s'" % l[0]
return result
def collate_chipset_map (cs_list, base):
result = {}
for (opcode, insts) in zip (range(256), cs_list):
if insts != None:
for inst in insts:
(mnem, mode) = inst
if mnem not in result:
result[mnem] = [None] * len(modes)
if result[mnem][mode] is not None:
print "Warning: Reassigning %s - %s" % (mnem, modes[mode])
result[mnem][mode] = opcode
if base is not None:
todel = []
for x in result:
if x in base:
if result[x] == base[x]:
todel.append(x)
elif verbose != 0:
print "# Opcode %s changed" % x
elif verbose != 0:
print "# Opcode %s added" % x
for x in todel:
del result[x]
return result
def mapval(x):
if x is None:
return "None"
else:
return "0x%02X" % x
def dump_map (m, prologue = ''):
mnems = m.keys()
mnems.sort()
for mnem in mnems:
print "%s'%s': [%s]," % (prologue, mnem, ', '.join([mapval(x) for x in m[mnem]]))
if __name__=='__main__':
if len(sys.argv) > 1:
chipsets = argv[1:]
else:
chipsets = ['chipsets.txt']
archs = []
for x in chipsets:
try:
ls = [[x.strip() for x in y] for y in [z.split(':', 1) for z in decomment_readlines (x)]]
for l in ls:
if len(l) != 2:
print "Could not parse the chipset line '%s'" % ":".join(l)
else:
archs.append((l[0], l[1]))
except IOError:
print "Could not read file %s" % x
print prologue
baseset = None
for (field, fname) in archs:
chipset_list = parse_chipset_file(fname)
instruction_map = collate_chipset_map (chipset_list, baseset)
if baseset == None:
baseset = instruction_map
print "%s = {" % field
dump_map (instruction_map, ' ' * (len(field) + 4))
print "%s}" % (' ' * (len(field) + 3))
print ""

256
tools/opcodes/op6502.txt Normal file
View File

@ -0,0 +1,256 @@
00: BRK - Implied
01: ORA - (Zero Page, X)
02:
03:
04:
05: ORA - Zero Page
06: ASL - Zero Page
07:
08: PHP - Implied
09: ORA - Immediate
0A: ASL - Implied
0B:
0C:
0D: ORA - Absolute
0E: ASL - Absolute
0F:
10: BPL - Relative
11: ORA - (Zero Page), Y
12:
13:
14:
15: ORA - Zero Page, X
16: ASL - Zero Page, X
17:
18: CLC - Implied
19: ORA - Absolute, Y
1A:
1B:
1C:
1D: ORA - Absolute, X
1E: ASL - Absolute, X
1F:
20: JSR - Absolute
21: AND - (Zero Page, X)
22:
23:
24: BIT - Zero Page
25: AND - Zero Page
26: ROL - Zero Page
27:
28: PLP - Implied
29: AND - Immediate
2A: ROL - Implied
2B:
2C: BIT - Absolute
2D: AND - Absolute
2E: ROL - Absolute
2F:
30: BMI - Relative
31: AND - (Zero Page), Y
32:
33:
34:
35: AND - Zero Page, X
36: ROL - Zero Page, X
37:
38: SEC - Implied
39: AND - Absolute, Y
3A:
3B:
3C:
3D: AND - Absolute, X
3E: ROL - Absolute, X
3F:
40: RTI - Implied
41: EOR - (Zero Page, X)
42:
43:
44:
45: EOR - Zero Page
46: LSR - Zero Page
47:
48: PHA - Implied
49: EOR - Immediate
4A: LSR - Implied
4B:
4C: JMP - Absolute
4D: EOR - Absolute
4E: LSR - Absolute
4F:
50: BVC - Relative
51: EOR - (Zero Page), Y
52:
53:
54:
55: EOR - Zero Page, X
56: LSR - Zero Page, X
57:
58: CLI - Implied
59: EOR - Absolute, Y
5A:
5B:
5C:
5D: EOR - Absolute, X
5E: LSR - Absolute, X
5F:
60: RTS - Implied
61: ADC - (Zero Page, X)
62:
63:
64:
65: ADC - Zero Page
66: ROR - Zero Page
67:
68: PLA - Implied
69: ADC - Immediate
6A: ROR - Implied
6B:
6C: JMP - (Absolute)
6D: ADC - Absolute
6E: ROR - Absolute
6F:
70: BVS - Relative
71: ADC - (Zero Page), Y
72:
73:
74:
75: ADC - Zero Page, X
76: ROR - Zero Page, X
77:
78: SEI - Implied
79: ADC - Absolute, Y
7A:
7B:
7C:
7D: ADC - Absolute, X
7E: ROR - Absolute, X
7F:
80:
81: STA - (Zero Page, X)
82:
83:
84: STY - Zero Page
85: STA - Zero Page
86: STX - Zero Page
87:
88: DEY - Implied
89:
8A: TXA - Implied
8B:
8C: STY - Absolute
8D: STA - Absolute
8E: STX - Absolute
8F:
90: BCC - Relative
91: STA - (Zero Page), Y
92:
93:
94: STY - Zero Page, X
95: STA - Zero Page, X
96: STX - Zero Page, Y
97:
98: TYA - Implied
99: STA - Absolute, Y
9A: TXS - Implied
9B:
9C:
9D: STA - Absolute, X
9E:
9F:
A0: LDY - Immediate
A1: LDA - (Zero Page, X)
A2: LDX - Immediate
A3:
A4: LDY - Zero Page
A5: LDA - Zero Page
A6: LDX - Zero Page
A7:
A8: TAY - Implied
A9: LDA - Immediate
AA: TAX - Implied
AB:
AC: LDY - Absolute
AD: LDA - Absolute
AE: LDX - Absolute
AF:
B0: BCS - Relative
B1: LDA - (Zero Page), Y
B2:
B3:
B4: LDY - Zero Page, X
B5: LDA - Zero Page, X
B6: LDX - Zero Page, Y
B7:
B8: CLV - Implied
B9: LDA - Absolute, Y
BA: TSX - Implied
BB:
BC: LDY - Absolute, X
BD: LDA - Absolute, X
BE: LDX - Absolute, Y
BF:
C0: CPY - Immediate
C1: CMP - (Zero Page, X)
C2:
C3:
C4: CPY - Zero Page
C5: CMP - Zero Page
C6: DEC - Zero Page
C7:
C8: INY - Implied
C9: CMP - Immediate
CA: DEX - Implied
CB:
CC: CPY - Absolute
CD: CMP - Absolute
CE: DEC - Absolute
CF:
D0: BNE - Relative
D1: CMP - (Zero Page), Y
D2:
D3:
D4:
D5: CMP - Zero Page, X
D6: DEC - Zero Page, X
D7:
D8: CLD - Implied
D9: CMP - Absolute, Y
DA:
DB:
DC:
DD: CMP - Absolute, X
DE: DEC - Absolute, X
DF:
E0: CPX - Immediate
E1: SBC - (Zero Page, X)
E2:
E3:
E4: CPX - Zero Page
E5: SBC - Zero Page
E6: INC - Zero Page
E7:
E8: INX - Implied
E9: SBC - Immediate
EA: NOP - Implied
EB:
EC: CPX - Absolute
ED: SBC - Absolute
EE: INC - Absolute
EF:
F0: BEQ - Relative
F1: SBC - (Zero Page), Y
F2:
F3:
F4:
F5: SBC - Zero Page, X
F6: INC - Zero Page, X
F7:
F8: SED - Implied
F9: SBC - Absolute, Y
FA:
FB:
FC:
FD: SBC - Absolute, X
FE: INC - Absolute, X
FF:

256
tools/opcodes/op6510.txt Normal file
View File

@ -0,0 +1,256 @@
00: BRK - Implied
01: ORA - (Zero Page, X)
02:
03: SLO - (Zero Page, X)
04:
05: ORA - Zero Page
06: ASL - Zero Page
07: SLO - Zero Page
08: PHP - Implied
09: ORA - Immediate
0A: ASL - Implied
0B: ANC - Immediate
0C:
0D: ORA - Absolute
0E: ASL - Absolute
0F: SLO - Absolute
10: BPL - Relative
11: ORA - (Zero Page), Y
12:
13: SLO - (Zero Page), Y
14:
15: ORA - Zero Page, X
16: ASL - Zero Page, X
17: SLO - Zero Page, X
18: CLC - Implied
19: ORA - Absolute, Y
1A:
1B: SLO - Absolute, Y
1C:
1D: ORA - Absolute, X
1E: ASL - Absolute, X
1F: SLO - Absolute, X
20: JSR - Absolute
21: AND - (Zero Page, X)
22:
23: RLA - (Zero Page, X)
24: BIT - Zero Page
25: AND - Zero Page
26: ROL - Zero Page
27: RLA - Zero Page
28: PLP - Implied
29: AND - Immediate
2A: ROL - Implied
2B:
2C: BIT - Absolute
2D: AND - Absolute
2E: ROL - Absolute
2F: RLA - Absolute
30: BMI - Relative
31: AND - (Zero Page), Y
32:
33: RLA - (Zero Page), Y
34:
35: AND - Zero Page, X
36: ROL - Zero Page, X
37: RLA - Zero Page, X
38: SEC - Implied
39: AND - Absolute, Y
3A:
3B: RLA - Absolute, Y
3C:
3D: AND - Absolute, X
3E: ROL - Absolute, X
3F: RLA - Absolute, X
40: RTI - Implied
41: EOR - (Zero Page, X)
42:
43: SRE - (Zero Page, X)
44:
45: EOR - Zero Page
46: LSR - Zero Page
47: SRE - Zero Page
48: PHA - Implied
49: EOR - Immediate
4A: LSR - Implied
4B: ASR - Immediate
4C: JMP - Absolute
4D: EOR - Absolute
4E: LSR - Absolute
4F: SRE - Absolute
50: BVC - Relative
51: EOR - (Zero Page), Y
52:
53: SRE - (Zero Page), Y
54:
55: EOR - Zero Page, X
56: LSR - Zero Page, X
57: SRE - Zero Page, X
58: CLI - Implied
59: EOR - Absolute, Y
5A:
5B: SRE - Absolute, Y
5C:
5D: EOR - Absolute, X
5E: LSR - Absolute, X
5F: SRE - Absolute, X
60: RTS - Implied
61: ADC - (Zero Page, X)
62:
63: RRA - (Zero Page, X)
64:
65: ADC - Zero Page
66: ROR - Zero Page
67: RRA - Zero Page
68: PLA - Implied
69: ADC - Immediate
6A: ROR - Implied
6B: ARR - Immediate
6C: JMP - (Absolute)
6D: ADC - Absolute
6E: ROR - Absolute
6F: RRA - Absolute
70: BVS - Relative
71: ADC - (Zero Page), Y
72:
73: RRA - (Zero Page), Y
74:
75: ADC - Zero Page, X
76: ROR - Zero Page, X
77: RRA - Zero Page, X
78: SEI - Implied
79: ADC - Absolute, Y
7A:
7B: RRA - Absolute, Y
7C:
7D: ADC - Absolute, X
7E: ROR - Absolute, X
7F: RRA - Absolute, X
80:
81: STA - (Zero Page, X)
82:
83: SAX - (Zero Page, X)
84: STY - Zero Page
85: STA - Zero Page
86: STX - Zero Page
87: SAX - Zero Page
88: DEY - Implied
89:
8A: TXA - Implied
8B: ANE - Immediate
8C: STY - Absolute
8D: STA - Absolute
8E: STX - Absolute
8F: SAX - Absolute
90: BCC - Relative
91: STA - (Zero Page), Y
92:
93: SHA - (Zero Page), Y
94: STY - Zero Page, X
95: STA - Zero Page, X
96: STX - Zero Page, Y
97: SAX - Zero Page, Y
98: TYA - Implied
99: STA - Absolute, Y
9A: TXS - Implied
9B: SHS - Absolute, Y
9C:
9D: STA - Absolute, X
9E: SHX - Absolute, Y
9F: SHA - Absolute, Y
A0: LDY - Immediate
A1: LDA - (Zero Page, X)
A2: LDX - Immediate
A3: LAX - (Zero Page, X)
A4: LDY - Zero Page
A5: LDA - Zero Page
A6: LDX - Zero Page
A7: LAX - Zero Page
A8: TAY - Implied
A9: LDA - Immediate
AA: TAX - Implied
AB: LXA - Immediate
AC: LDY - Absolute
AD: LDA - Absolute
AE: LDX - Absolute
AF: LAX - Absolute
B0: BCS - Relative
B1: LDA - (Zero Page), Y
B2:
B3: LAX - (Zero Page), Y
B4: LDY - Zero Page, X
B5: LDA - Zero Page, X
B6: LDX - Zero Page, Y
B7: LAX - Zero Page, Y
B8: CLV - Implied
B9: LDA - Absolute, Y
BA: TSX - Implied
BB: LAS - Absolute, Y
BC: LDY - Absolute, X
BD: LDA - Absolute, X
BE: LDX - Absolute, Y
BF: LAX - Absolute, Y
C0: CPY - Immediate
C1: CMP - (Zero Page, X)
C2:
C3: DCP - (Zero Page, X)
C4: CPY - Zero Page
C5: CMP - Zero Page
C6: DEC - Zero Page
C7: DCP - Zero Page
C8: INY - Implied
C9: CMP - Immediate
CA: DEX - Implied
CB: SBX - Immediate
CC: CPY - Absolute
CD: CMP - Absolute
CE: DEC - Absolute
CF: DCP - Absolute
D0: BNE - Relative
D1: CMP - (Zero Page), Y
D2:
D3: DCP - (Zero Page), Y
D4:
D5: CMP - Zero Page, X
D6: DEC - Zero Page, X
D7: DCP - Zero Page, X
D8: CLD - Implied
D9: CMP - Absolute, Y
DA:
DB: DCP - Absolute, Y
DC:
DD: CMP - Absolute, X
DE: DEC - Absolute, X
DF: DCP - Absolute, X
E0: CPX - Immediate
E1: SBC - (Zero Page, X)
E2:
E3: ISB - (Zero Page, X)
E4: CPX - Zero Page
E5: SBC - Zero Page
E6: INC - Zero Page
E7: ISB - Zero Page
E8: INX - Implied
E9: SBC - Immediate
EA: NOP - Implied
EB:
EC: CPX - Absolute
ED: SBC - Absolute
EE: INC - Absolute
EF: ISB - Absolute
F0: BEQ - Relative
F1: SBC - (Zero Page), Y
F2:
F3: ISB - (Zero Page), Y
F4:
F5: SBC - Zero Page, X
F6: INC - Zero Page, X
F7: ISB - Zero Page, X
F8: SED - Implied
F9: SBC - Absolute, Y
FA:
FB: ISB - Absolute, Y
FC:
FD: SBC - Absolute, X
FE: INC - Absolute, X
FF: ISB - Absolute, X

256
tools/opcodes/op65c02.txt Normal file
View File

@ -0,0 +1,256 @@
00: BRK - Implied
01: ORA - (Zero Page, X)
02:
03:
04: TSB - Zero Page
05: ORA - Zero Page
06: ASL - Zero Page
07: RMB0 - Zero Page
08: PHP - Implied
09: ORA - Immediate
0A: ASL - Implied
0B:
0C: TSB - Absolute
0D: ORA - Absolute
0E: ASL - Absolute
0F: BBR0 - Relative
10: BPL - Relative
11: ORA - (Zero Page), Y
12: ORA - (Zero Page)
13:
14: TRB - Zero Page
15: ORA - Zero Page, X
16: ASL - Zero Page, X
17: RMB1 - Zero Page
18: CLC - Implied
19: ORA - Absolute, Y
1A: INA - Implied; INC - Implied
1B:
1C: TRB - Absolute
1D: ORA - Absolute, X
1E: ASL - Absolute, X
1F: BBR1 - Relative
20: JSR - Absolute
21: AND - (Zero Page, X)
22:
23:
24: BIT - Zero Page
25: AND - Zero Page
26: ROL - Zero Page
27: RMB2 - Zero Page
28: PLP - Implied
29: AND - Immediate
2A: ROL - Implied
2B:
2C: BIT - Absolute
2D: AND - Absolute
2E: ROL - Absolute
2F: BBR2 - Relative
30: BMI - Relative
31: AND - (Zero Page), Y
32: AND - (Zero Page)
33:
34: BIT - Zero Page, X
35: AND - Zero Page, X
36: ROL - Zero Page, X
37: RMB3 - Zero Page
38: SEC - Implied
39: AND - Absolute, Y
3A: DEA - Implied; DEC - Implied
3B:
3C: BIT - Absolute, X
3D: AND - Absolute, X
3E: ROL - Absolute, X
3F: BBR3 - Relative
40: RTI - Implied
41: EOR - (Zero Page, X)
42:
43:
44:
45: EOR - Zero Page
46: LSR - Zero Page
47: RMB4 - Zero Page
48: PHA - Implied
49: EOR - Immediate
4A: LSR - Implied
4B:
4C: JMP - Absolute
4D: EOR - Absolute
4E: LSR - Absolute
4F: BBR4 - Relative
50: BVC - Relative
51: EOR - (Zero Page), Y
52: EOR - (Zero Page)
53:
54:
55: EOR - Zero Page, X
56: LSR - Zero Page, X
57: RMB5 - Zero Page
58: CLI - Implied
59: EOR - Absolute, Y
5A: PHY - Implied
5B:
5C:
5D: EOR - Absolute, X
5E: LSR - Absolute, X
5F: BBR5 - Relative
60: RTS - Implied
61: ADC - (Zero Page, X)
62:
63:
64: STZ - Zero Page
65: ADC - Zero Page
66: ROR - Zero Page
67: RMB6 - Zero Page
68: PLA - Implied
69: ADC - Immediate
6A: ROR - Implied
6B:
6C: JMP - (Absolute)
6D: ADC - Absolute
6E: ROR - Absolute
6F: BBR6 - Relative
70: BVS - Relative
71: ADC - (Zero Page), Y
72: ADC - (Zero Page)
73:
74: STZ - Zero Page, X
75: ADC - Zero Page, X
76: ROR - Zero Page, X
77: RMB7 - Zero Page
78: SEI - Implied
79: ADC - Absolute, Y
7A: PLY - Implied
7B:
7C: JMP - (Absolute, X)
7D: ADC - Absolute, X
7E: ROR - Absolute, X
7F: BBR7 - Relative
80: BRA - Relative
81: STA - (Zero Page, X)
82:
83:
84: STY - Zero Page
85: STA - Zero Page
86: STX - Zero Page
87: SMB0 - Zero Page
88: DEY - Implied
89: BIT - Immediate
8A: TXA - Implied
8B:
8C: STY - Absolute
8D: STA - Absolute
8E: STX - Absolute
8F: BBS0 - Relative
90: BCC - Relative
91: STA - (Zero Page), Y
92: STA - (Zero Page)
93:
94: STY - Zero Page, X
95: STA - Zero Page, X
96: STX - Zero Page, Y
97: SMB1 - Zero Page
98: TYA - Implied
99: STA - Absolute, Y
9A: TXS - Implied
9B:
9C: STZ - Absolute
9D: STA - Absolute, X
9E: STZ - Absolute, X
9F: BBS1 - Relative
A0: LDY - Immediate
A1: LDA - (Zero Page, X)
A2: LDX - Immediate
A3:
A4: LDY - Zero Page
A5: LDA - Zero Page
A6: LDX - Zero Page
A7: SMB2 - Zero Page
A8: TAY - Implied
A9: LDA - Immediate
AA: TAX - Implied
AB:
AC: LDY - Absolute
AD: LDA - Absolute
AE: LDX - Absolute
AF: BBS2 - Relative
B0: BCS - Relative
B1: LDA - (Zero Page), Y
B2: LDA - (Zero Page)
B3:
B4: LDY - Zero Page, X
B5: LDA - Zero Page, X
B6: LDX - Zero Page, Y
B7: SMB3 - Zero Page
B8: CLV - Implied
B9: LDA - Absolute, Y
BA: TSX - Implied
BB:
BC: LDY - Absolute, X
BD: LDA - Absolute, X
BE: LDX - Absolute, Y
BF: BBS3 - Relative
C0: CPY - Immediate
C1: CMP - (Zero Page, X)
C2:
C3:
C4: CPY - Zero Page
C5: CMP - Zero Page
C6: DEC - Zero Page
C7: SMB4 - Zero Page
C8: INY - Implied
C9: CMP - Immediate
CA: DEX - Implied
CB: WAI - Implied
CC: CPY - Absolute
CD: CMP - Absolute
CE: DEC - Absolute
CF: BBS4 - Relative
D0: BNE - Relative
D1: CMP - (Zero Page), Y
D2: CMP - (Zero Page)
D3:
D4:
D5: CMP - Zero Page, X
D6: DEC - Zero Page, X
D7: SMB5 - Zero Page
D8: CLD - Implied
D9: CMP - Absolute, Y
DA: PHX - Implied
DB: STP - Implied
DC:
DD: CMP - Absolute, X
DE: DEC - Absolute, X
DF: BBS5 - Relative
E0: CPX - Immediate
E1: SBC - (Zero Page, X)
E2:
E3:
E4: CPX - Zero Page
E5: SBC - Zero Page
E6: INC - Zero Page
E7: SMB6 - Zero Page
E8: INX - Implied
E9: SBC - Immediate
EA: NOP - Implied
EB:
EC: CPX - Absolute
ED: SBC - Absolute
EE: INC - Absolute
EF: BBS6 - Relative
F0: BEQ - Relative
F1: SBC - (Zero Page), Y
F2: SBC - (Zero Page)
F3:
F4:
F5: SBC - Zero Page, X
F6: INC - Zero Page, X
F7: SMB7 - Zero Page
F8: SED - Implied
F9: SBC - Absolute, Y
FA: PLX - Implied
FB:
FC:
FD: SBC - Absolute, X
FE: INC - Absolute, X
FF: BBS7 - Relative