mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-12-21 12:29:46 +00:00
402 lines
7.2 KiB
HTML
402 lines
7.2 KiB
HTML
<!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"
|
|
><<< 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 >>></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—we must ensure that no routines step on
|
|
each other. What we'd really like are two separate program
|
|
counters—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"
|
|
><<< 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 >>></A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Character maps</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
> </TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>Expressions</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |