2
;; A proof that an implementation of the Fibonacci function
3
;; on Tiny, a small stack-machine, is correct.
6
;(include-book "tiny-rewrites")
7
;(include-book "stream-fib")
9
(set-verify-guards-eagerness 0)
11
(defun tiny-loaded () t)
13
;; Addresses of fib's temporary variables
14
(defconst *fib-adr* 20)
15
(defconst *fib-1-adr* (1+ *fib-adr*))
17
;; The start-of-program address
18
(defconst *prog-start-address* 100)
20
;; Replaces label placeholders in a program fragment with
21
;; their final computed values. Label placeholders should
22
;; be negative integers, to prevent conflicts with opcodes
23
;; and address references in the program being patched.
24
(defun patch-prog-labels (prog label-map)
27
((assoc-equal (car prog) label-map)
28
(cons (cdr (assoc-equal (car prog) label-map))
29
(patch-prog-labels (cdr prog) label-map)))
32
(patch-prog-labels (cdr prog) label-map)))))
35
NOTE: I am using Hoare triples to document the pre- and post-conditions
36
of basic blocks. To describe the contents of the stack I am overloading
37
the predicate symbol (<=) to compare stacks. Given stacks xs and ys,
38
xs <= ys holds when xs is a prefix of ys. I write the contents of
39
a stack using Haskell notation, so that [1,2,3] represents a three
40
element stack with 1 as the top element. I use the special constant
41
'stack' to represent tiny's current value stack.
43
I also define an operator on memory that takes a stack of addresses
44
and returns a stack of values consisting of the current contents of
45
memory at those addresses. So if the contents of memory at address
46
1 is 3 and the contents of memory at address 5 is 12, then
52
;; {[N-1] <= stack /\ mem[*fib-adr*,*fib-adr-1*] = [1,1]}
53
(defconst *init-block*
62
;; {[N] <= stack /\ mem[*fib-adr*,*fib-adr-1*] = [M,K]}
64
;; { (N=0 /\ [0] <= stack /\ mem[*fib-adr*] = M)
65
;; \/ ([N-1] <= stack /\ mem[*fib-adr*,*fib-adr-1*] = [M+K,M])}
66
(defconst *loop-label-hole* -2)
67
(defconst *done-label-hole* -3)
68
(defconst *unpatched-loop-block*
69
(assemble `(; loop-label-hole:
71
jumpz ,*done-label-hole*
80
jump ,*loop-label-hole*
84
; Calculate the actual program labels to patch
85
(defconst *loop-label* (+ *prog-start-address*
87
(defconst *done-label* (+ *loop-label*
88
(len *unpatched-loop-block*)))
90
(defconst *label-patches*
91
`((,*loop-label-hole* . ,*loop-label*)
92
(,*done-label-hole* . ,*done-label*)))
94
(defconst *loop-block*
95
(patch-prog-labels *unpatched-loop-block* *label-patches*))
97
;; {[0] <= stack /\ mem[*fib-adr*] = M)
100
(defconst *done-block*
101
(assemble `(pushs ,*fib-adr*
105
(defconst *prog-halt-address* (+ *done-label*
106
(1- (len *done-block*))))
108
;; The Fibonacci program
115
;;; ;;========== Test harness for evaluating *fib-prog* on tiny =============
117
;; ;; Initialize the state of the tiny interpreter so
118
;; ;; that it will calculate the n'th Fibonacci number.
119
;; ;; The variable 'tiny-state' is a stobj defined in tiny.lisp.
120
;; (defun init-tiny-fib (tiny-state n)
121
;; (declare (xargs :stobjs (tiny-state)))
122
;; (load-tiny *prog-start-address*
123
;; `((,*prog-start-address* . ,*fib-prog*) ; Load program into memory
124
;; (901 . (,n))) ; Initialize TOS with n
127
;; ;; Initialize the current tiny machine state
128
;; (defconst *fib-input* 4)
129
;; (init-tiny-fib tiny-state *fib-input*)
131
;; ;;Execute exactly enough TINY steps to have the
132
;; ;; fib program halt.
133
;; (tiny tiny-state (+ (len *init-block*)
134
;; (* (1- *fib-input*) (len *loop-block*))
135
;; (len *done-block*)))
137
;; ; Examine the returned Fibonacci number
138
;; (dtos-val tiny-state 0)
140
;; ; Check that the returned number matches
141
;; ; the Fibonacci specification.
142
;; (equal (dtos-val tiny-state 0) (fib-spec *fib-input*))
144
;; ; Check that the program has halted.
145
;; (equal (memi (progc tiny-state) tiny-state) (encode 'halt))
147
;; ;;Execute these commands in ACL2's repl-loop to probe
148
;; ;; the contents of the TINY machine state.
149
;; *prog-start-address*
150
;; (memi *prog-start-address* tiny-state)
151
;; (dtos-val tiny-state 0) ; data TOS
152
;; (progc tiny-state) ; program counter
153
;; (ctos tiny-state) ; return value TOS
155
(defconst *fib-cutpoints*
156
`(,*prog-start-address*
159
,*prog-halt-address*))
161
;;The initial top-of-stack address. Note that the stack already
162
;; contains a single input value, namely the parameter to fib.
163
(defconst *init-dtos* 899)