<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>hello1.oph</filename></title>
<programlisting>
.word $0801
.org  $0801
.outfile "hello.prg"

        .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>hello2.oph</filename></title>
<programlisting>
.word $0801
.org  $0801
.outfile "hello.prg"

.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 "../platform/c64kernal.oph"
</programlisting>
  </section>
  <section id="kernal-src">
    <title id="kernal-fname"><filename>c64kernal.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>hello3.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.outfile "hello.prg"

.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>hello4a.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.outfile "hello.prg"

.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>hello4b.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.outfile "hello.prg"

.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>hello4c.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.outfile "hello.prg"

.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>hello5.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.outfile "hello.prg"

.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>hello6.oph</filename></title>
<programlisting>
.include "c64-1.oph"
.outfile "hello.prg"

.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_0.oph</filename></title>
<programlisting>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Commodore 64 Basic Runtime File
;;
;; Include this at the TOP of your C64 program, and it will handle
;; hiding away the BASIC ROM and data and restoring it at the end.
;;
;; You will have a contiguous block of RAM from $0800 to $CF81, and
;; Zero Page access from $02 to $7F in the segment "zp".

.word $0801
.org  $0801

; BASIC program that just calls our machine language code
.scope
        .word _next, 10         ; Next line and current line number
        .byte $9e," 2062",0     ; SYS 2062
_next:  .word 0                 ; End of program
.scend

.data zp ; Zero Page memory segment.
.org $0002

.text

.scope
        ; Cache BASIC zero page at top of available RAM
        ldx     #$7E
*       lda     $01, x
        sta     $CF81, x
        dex
        bne     -

        ; Swap out the BASIC ROM for RAM
        lda     $01
        and     #$fe
        ora     #$06
        sta     $01

        ; Run the real program
        jsr     _main

        ; Restore BASIC ROM
        lda     $01
        ora     #$07
        sta     $01

        ; Restore BASIC zero page
        ldx     #$7E
*       lda     $CF81, x
        sta     $01, x
        dex
        bne     -

        ; Back to BASIC
        rts

_main:
        ; Program follows...
.scend
</programlisting>
  </section>
  <section id="tutor7-src">
    <title id="tutor7-fname"><filename>hello7.oph</filename></title>
<programlisting>
.include "../platform/c64_0.oph"
.require "../platform/c64kernal.oph"
.outfile "hello.prg"

.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>
  <section id="structure-src">
    <title id="structure-fname"><filename>structuredemo.oph</filename></title>
<programlisting>
.include "../platform/c64_0.oph"
.require "../platform/c64kernal.oph"
.outfile "structuredemo.prg"

        jsr print'unsorted
        jsr insertion'sort
        jsr print'list
        rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Linked list data: head, next, lb, hb.
; lb/hb: Low/high bytes of the data array.  These are immutable and
;        kept with the program text.
; head:  Array index of the first element in the list, or #$FF if the
;        list is empty
; next:  Array of successor indices.  If you've just read element X,
;        the value of memory location next+X is the index of the
;        next element.  If next is #$FF, you've reached the end of
;        the list.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.data
.org    $C000
.space  head    1
.space  next    16

.text
lb:   .byte &lt;$838,&lt;$618,&lt;$205,&lt;$984,&lt;$724,&lt;$301,&lt;$249,&lt;$946
      .byte &lt;$925,&lt;$043,&lt;$114,&lt;$697,&lt;$985,&lt;$633,&lt;$312,&lt;$086
hb:   .byte &gt;$838,&gt;$618,&gt;$205,&gt;$984,&gt;$724,&gt;$301,&gt;$249,&gt;$946
      .byte &gt;$925,&gt;$043,&gt;$114,&gt;$697,&gt;$985,&gt;$633,&gt;$312,&gt;$086

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; insertion'sort:  Sorts the list defined by head, next, hb, lb.
; Arguments:  None.
; Modifies:   All registers destroyed, head and next array sorted.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

insertion'sort:
        lda #$FF        ; Clear list by storing the terminator in 'head'
        sta head
        ldx #$0         ; Loop through the lb/hb array, adding each
insertion'sort'loop:    ; element one at a time
        txa
        pha
        jsr insert_elt
        pla
        tax
        inx
        cpx #$10
        bne insertion'sort'loop
        rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; insert_elt: Insert an element into the linked list.  Maintains the
;             list in sorted, ascending order.  Used by
;             insertion'sort.
; Arguments:  X register holds the index of the element to add.
; Modifies:   All registers destroyed; head and next arrays updated
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.data
.space lbtoinsert 1
.space hbtoinsert 1
.space indextoinsert 1

.text

insert_elt:
        ldy head                        ; If the list is empty, make
        cpy #$FF                        ; head point at it, and return.
        bne insert_elt'list'not'empty
        stx head
        tya
        sta next,x
        rts
insert_elt'list'not'empty:
        lda lb,x                        ; Cache the data we're inserting
        sta lbtoinsert
        lda hb,x
        sta hbtoinsert
        stx indextoinsert
        ldy head                        ; Compare the first value with
        sec                             ; the data.  If the data must
        lda lb,y                        ; be inserted at the front...
        sbc lbtoinsert
        lda hb,y
        sbc hbtoinsert
        bmi insert_elt'not'smallest
        tya                             ; Set its next pointer to the
        sta next,x                      ; old head, update the head
        stx head                        ; pointer, and return.
        rts
insert_elt'not'smallest:
        ldx head
insert_elt'loop:                        ; At this point, we know that
        lda next,x                      ; argument &gt; data[X].
        tay
        cpy #$FF                        ; if next[X] = #$FF, insert arg at end.
        beq insert_elt'insert'after'current
        lda lb,y                        ; Otherwise, compare arg to
        sec                             ; data[next[X]].  If we insert
        sbc lbtoinsert                  ; before that...
        lda hb,y
        sbc hbtoinsert
        bmi insert_elt'goto'next
insert_elt'insert'after'current:        ; Fix up all the next links
        tya
        ldy indextoinsert
        sta next,y
        tya
        sta next,x
        rts                             ; and return.
insert_elt'goto'next:                   ; Otherwise, let X = next[X]
        tya                             ; and go looping again.
        tax
        jmp insert_elt'loop

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; print'unsorted: Steps through the data array and prints each value.
; Standalone procedure.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

print'unsorted:
        lda #&lt;unsorted'hdr
        ldx #&gt;unsorted'hdr
        jsr put'string
        ldy #$00
print'unsorted'loop:
        lda hb, Y
        jsr print'hex
        lda lb, y
        jsr print'hex
        lda #$20
        jsr chrout
        iny
        cpy #$10
        bne print'unsorted'loop
        lda #$0D
        jsr chrout
        rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; print'list: Starts at head, and prints out every value in the
;             linked list.
; Standalone procedure.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

print'list:
        lda #&lt;sorted'hdr
        ldx #&gt;sorted'hdr
        jsr put'string
        ldy head
print'list'loop:
        cpy #$FF
        beq print'list'done
        lda hb, y
        jsr print'hex
        lda lb, y
        jsr print'hex
        lda #$20
        jsr chrout
        lda next, Y
        tay
        jmp print'list'loop
print'list'done:
        lda #$0d
        jsr chrout
        rts

;; String data for the above routines.

unsorted'hdr:
        .byte 147               ; Clear screen first!
        .byte "UNSORTED DATA:",13,0

sorted'hdr:
        .byte "SORTED DATA:",13,0


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; print'hex: outputs a two-character hex representation of a one-
;            byte value.
; Arguments: Byte to print in accumulator
; Modifies: .A and .X
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

print'hex:
        pha
        clc
        lsr
        lsr
        lsr
        lsr
        tax
        lda hexstr,x
        jsr chrout
        pla
        and #$0F
        tax
        lda hexstr,X
        jsr chrout
        rts

; Character data array for print'hex.
hexstr: .byte "0123456789ABCDEF"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; put'string: outputs a C-style null terminated string with length
;             less than 256 to the screen.  If 256 bytes are written
;             without finding a terminator, the routine ends quietly.
; Arguments: Low byte of string address in .A, high byte in .X
; Modifies: .A and .Y
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.data zp
.space put'string'addr 2

.text
put'string:
        sta put'string'addr
        stx put'string'addr+1
        ldy #$00
put'string'loop:
        lda (put'string'addr),y
        beq put'string'done
        jsr chrout
        iny
        bne put'string'loop
put'string'done:
        rts

</programlisting>
  </section>
  <section id="fib-src">
    <title id="fib-fname"><filename>fibonacci.oph</filename></title>
<programlisting>
.include "../platform/c64_0.oph"
.require "../platform/c64kernal.oph"
.outfile "fibonacci.prg"

        lda     #&lt;opening     ; Print opening text
        sta     fun'args
        lda     #&gt;opening
        sta     fun'args+1
        jsr     print'string

        lda     #$00
        sta     fun'vars      ; Count num from 0 to 19
*       lda     fun'vars      ; Main loop: print num, with leading space if &lt;10
        cmp     #$09
        bcs     +
        lda     #$20
        jsr     chrout
        lda     fun'vars
*       sta     fun'args      ; Copy num to args, print it, plus ": "
        inc     fun'args
        lda     #$00
        sta     fun'args+1
        jsr     print'dec
        lda     #$3A
        jsr     chrout
        lda     #$20
        jsr     chrout
        lda     fun'vars      ; Copy num to args, call fib, print result
        sta     fun'args
        jsr     fib
        jsr     print'dec
        lda     #$0D          ; Newline
        jsr     chrout
        inc     fun'vars      ; Increment num; if it's 20, we're done.
        lda     fun'vars
        cmp     #20
        bne     --            ; Otherwise, loop.
        rts

opening:
.byte   147, "           FIBONACCI SEQUENCE",13,13,0

.scope
; Uint16 fib (Uint8 x): compute Xth fibonnaci number.
; fib(0) = fib(1) = 1.
; Stack usage: 3.

fib:    lda     #$03
        jsr     save'stack

        lda     fun'vars    ; If x &lt; 2, goto _base.
        cmp     #$02
        bcc     _base

        dec     fun'args    ; Otherwise, call fib(x-1)...
        jsr     fib
        lda     fun'args    ; Copy the result to local variable...
        sta     fun'vars+1
        lda     fun'args+1
        sta     fun'vars+2
        lda     fun'vars    ; Call fib(x-2)...
        sec
        sbc     #$02
        sta     fun'args
        jsr     fib
        clc                 ; And add the old result to it, leaving it
        lda     fun'args    ; in the 'result' location.
        adc     fun'vars+1
        sta     fun'args
        lda     fun'args+1
        adc     fun'vars+2
        sta     fun'args+1
        jmp     _done       ; and then we're done.

_base:  ldy     #$01        ; In the base case, just copy 1 to the
        sty     fun'args    ; result.
        dey
        sty     fun'args+1

_done:  lda     #$03
        jsr     restore'stack
        rts
.scend

.scope
; Stack routines: init'stack, save'stack, restore'stack
.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


; Utility functions.  print'dec prints an unsigned 16-bit integer.
; It's ugly and long, mainly because we don't bother with niceties
; like "division".  print'string prints a zero-terminated string.

.scope
.data
.org    fun'args
        .space  _val            2
        .space  _step           2
        .space  _res            1
        .space  _allowzero      1
.text
print'dec:
        lda     #$00
        sta     _allowzero
        lda     #&lt;10000
        sta     _step
        lda     #&gt;10000
        sta     _step+1
        jsr     repsub'16
        lda     #&lt;1000
        sta     _step
        lda     #&gt;1000
        sta     _step+1
        jsr     repsub'16
        lda     #0
        sta     _step+1
        lda     #100
        sta     _step
        jsr     repsub'16
        lda     #10
        sta     _step
        jsr     repsub'16
        lda     _val
        jsr     _print
        rts

repsub'16:
        lda     #$00
        sta     _res
*       lda     _val
        sec
        sbc     _step
        lda     _val+1
        sbc     _step+1
        bcc     _done
        lda     _val
        sec
        sbc     _step
        sta     _val
        lda     _val+1
        sbc     _step+1
        sta     _val+1
        inc     _res
        jmp     -
_done:  lda     _res
        ora     _allowzero
        beq     _ret
        sta     _allowzero
        lda     _res
_print: clc
        adc     #'0
        jsr     chrout
_ret:   rts
.scend

print'string:
        ldy     #$00
*       lda     (fun'args), y
        beq     +
        jsr     chrout
        iny
        jmp     -
*       rts
</programlisting>
  </section>
</appendix>
