mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-08-10 18:28:56 +00:00
336 lines
6.2 KiB
HTML
336 lines
6.2 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>Our Goals</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="Call Stacks"
|
|
HREF="c900.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="Call Stacks"
|
|
HREF="c900.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="Example: Fibonnacci Numbers"
|
|
HREF="x967.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="c900.html"
|
|
ACCESSKEY="P"
|
|
><<< Previous</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
>Call Stacks</TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="x967.html"
|
|
ACCESSKEY="N"
|
|
>Next >>></A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H1
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN915"
|
|
>Our Goals</A
|
|
></H1
|
|
><P
|
|
> The system we develop should have all of the following
|
|
characteristics.
|
|
</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>It should be <I
|
|
CLASS="EMPHASIS"
|
|
>intuitive to program for</I
|
|
>. The procedure bodies should be easily readable and writable by humans, even in assembler form.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>It should be <I
|
|
CLASS="EMPHASIS"
|
|
>efficient</I
|
|
>. Variable accesses are very common, so procedures shouldn't cost much to run.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>It should allow <I
|
|
CLASS="EMPHASIS"
|
|
>multiple arity</I
|
|
> in both arguments and return values. We won't require that an unlimited amount of information be passable, but it should allow more than the three bytes the registers give us.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>It should permit <I
|
|
CLASS="EMPHASIS"
|
|
>tail call elimination</I
|
|
>, an optimization that will allow certain forms of recursion to actually not grow the stack.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
> Here is a system that meets all these properties.
|
|
</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Reserve two bytes of the zero page for a stack pointer. At the beginning of the program, set it to the top of memory.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Divide the remainder of Zero Page into two parts:
|
|
<P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>The <I
|
|
CLASS="EMPHASIS"
|
|
>scratch space</I
|
|
>, which is where arguments and return values go, and which may be scrambled by any function call, and</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>The <I
|
|
CLASS="EMPHASIS"
|
|
>local area</I
|
|
>, which all functions must restore to their initial state once finished.</P
|
|
></LI
|
|
></UL
|
|
>
|
|
</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Assign to each procedure a <I
|
|
CLASS="EMPHASIS"
|
|
>frame size</I
|
|
> S, which is a maximum size on the amount of the local area the procedure can use. The procedure's variables will sit in the first S bytes of the local area.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Upon entering the procedure, push the first S bytes of the local area onto the stack; upon exit, pop hose S bytes back on top of the local area.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>While the procedure is running, only touch the local area and the scratch space.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>This meets our design criteria neatly:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>It's as intuitive as such a system will get. You have to call <TT
|
|
CLASS="LITERAL"
|
|
>init'stack</TT
|
|
> at the beginning, and you need to ensure that <TT
|
|
CLASS="LITERAL"
|
|
>save'stack</TT
|
|
> and <TT
|
|
CLASS="LITERAL"
|
|
>restore'stack</TT
|
|
> are called right. The procedure's program text can pretend that it's just referring to its own variables, just like with the old style. If a procedure doesn't call <I
|
|
CLASS="EMPHASIS"
|
|
>anyone</I
|
|
>, then it can just do all its work in the scratch space.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>It's efficient; the inside of the procedure is likely to be faster and smaller than its FORTRAN-style counterpart, because all variable references are on the Zero Page.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Both arguments and return values can be as large as the scratch space. It's not infinite, but it's probably good enough.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Tail call elimination is possible; just restore the stack before making the JMP to the tail call target.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
> The necessary support code is pretty straightforward. The stack
|
|
modification routines take the size of the frame in the
|
|
accumulator, and while saving the local area, it copies over the
|
|
corresponding values from the scratch space. (This is because
|
|
most functions will be wanting to keep their arguments around
|
|
across calls.)
|
|
</P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>.scope
|
|
; Stack routines
|
|
.data zp
|
|
.space _sp $02
|
|
.space _counter $01
|
|
.space fun'args $10
|
|
.space fun'vars $40
|
|
|
|
.text
|
|
init'stack:
|
|
lda #$00
|
|
sta _sp
|
|
lda #$A0
|
|
sta _sp+1
|
|
rts
|
|
|
|
save'stack:
|
|
sta _counter
|
|
sec
|
|
lda _sp
|
|
sbc _counter
|
|
sta _sp
|
|
lda _sp+1
|
|
sbc #$00
|
|
sta _sp+1
|
|
ldy #$00
|
|
* lda fun'vars, y
|
|
sta (_sp), y
|
|
lda fun'args, y
|
|
sta fun'vars, y
|
|
iny
|
|
dec _counter
|
|
bne -
|
|
rts
|
|
|
|
restore'stack:
|
|
pha
|
|
sta _counter
|
|
ldy #$00
|
|
* lda (_sp), y
|
|
sta fun'vars, y
|
|
iny
|
|
dec _counter
|
|
bne -
|
|
pla
|
|
clc
|
|
adc _sp
|
|
sta _sp
|
|
lda _sp+1
|
|
adc #$00
|
|
sta _sp+1
|
|
rts
|
|
.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="c900.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="x967.html"
|
|
ACCESSKEY="N"
|
|
>Next >>></A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Call Stacks</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="c900.html"
|
|
ACCESSKEY="U"
|
|
>Up</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>Example: Fibonnacci Numbers</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |