.include "../platform/c64_0.oph" .require "../platform/c64kernal.oph" .outfile "fibonacci.prg" lda #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 <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 < 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 #<10000 sta _step lda #>10000 sta _step+1 jsr repsub'16 lda #<1000 sta _step lda #>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