1
; Copyright (C) 2014, ForrestHunt, Inc.
3
; License: A 3-clause BSD license. See the LICENSE file distributed with ACL2.
6
Like m1-version-1 but uses stobjs.
8
I totally ignore the guard question.
10
See the README file on this directory for an overview of this work.
13
(set-difference-eq (union-eq *acl2-exports*
14
*common-lisp-symbols-from-main-lisp-package*)
15
'(push pop pc program step
16
; nth update-nth nth-update-nth ; <--- stobjs use built-ins
18
(certify-book "m1-version-3" 1)
23
; -----------------------------------------------------------------
35
; -----------------------------------------------------------------
39
(set-verify-guards-eagerness 0)
41
; I name the components with the prefix "ugly-" because I don't want
42
; to see them in proofs! I'm going to define a more uniform interface.
44
(defstobj s ugly-pc ugly-locals ugly-stack ugly-program)
46
; Basic read/write operations on state: for each field f of a stobj, defstobj
47
; provides two functions, f and update-f, for accessing and updating the field
48
; value. Now think about how messy it is to normalize a random mix of update
49
; expressions, e.g., (update-h a (update-g b (update-h c (update-f d st)))).
50
; So I define a pair of read/write functions that can hit each field of the
51
; stobj, then I prove the normalization rules, then I disable these basic
52
; functions. Finally, I use the basic functions to define the field-specific
53
; update-f versions. I define how to write to the cd field even though it is
54
; never needed. I did this to provide a uniform interface: to access or change
55
; a field, use rd or wr.
58
(declare (xargs :stobjs (s)))
60
(:pc (update-ugly-pc v s))
61
(:locals (update-ugly-locals v s))
62
(:stack (update-ugly-stack v s))
63
(:program (update-ugly-program v s))
67
(declare (xargs :stobjs (s)))
70
(:locals (ugly-locals s))
71
(:stack (ugly-stack s))
72
(:program (ugly-program s))
79
(in-theory (disable sp))
81
(defun keyp (k) (member k '(:pc :locals :stack :program)))
84
(equal (rd key1 (wr key2 v s))
85
(if (and (equal key1 key2)
90
(defthm update-nth-update-nth-diff
91
(implies (and (natp i) (natp j) (not (equal i j)))
92
(equal (update-nth i v (update-nth j w list))
93
(update-nth j w (update-nth i v list))))
94
:rule-classes ((:rewrite :loop-stopper ((i j update-nth)))))
96
(defthm update-nth-update-nth-same
97
(equal (update-nth i v (update-nth i w list))
98
(update-nth i v list)))
100
(defthm update-nth-redundant
101
(implies (and (natp i)
104
(equal (update-nth i v x) x)))
107
(implies (and (keyp key1)
109
(not (equal key1 key2)))
110
(equal (wr key1 v1 (wr key2 v2 s))
111
(wr key2 v2 (wr key1 v1 s))))
112
:hints (("Goal" :in-theory (disable nth update-nth)))
113
:rule-classes ((:rewrite :loop-stopper ((key1 key2 wr)))))
117
(equal (wr key1 v1 (wr key1 v2 s))
121
(implies (and (sp s) ; <---- added and deleted below!
123
; (equal (len s) 4) ; <----
125
(equal (wr key v s) s))
126
:hints (("Goal" :in-theory (enable sp)))) ; <---
129
; (implies (equal (len s) 4)
130
; (equal (len (wr key v s)) 4)))
132
(in-theory (disable rd wr))
134
; The following functions are just handy abbreviations to use in the semantics
135
; of the instructions. I expect them always to be expanded into rd/wr terms.
136
; They could be macros.
139
(declare (xargs :stobjs (s)))
143
(declare (xargs :stobjs (s)))
146
; There is no need to define lo and !lo since we always change indexed
147
; positions, not the whole field.
150
(declare (xargs :stobjs (s)))
151
(nth i (rd :locals s)))
154
(declare (xargs :stobjs (s)))
155
(wr :locals (update-nth i v (rd :locals s)) s))
158
(declare (xargs :stobjs (s)))
162
(declare (xargs :stobjs (s)))
165
; There is no need to define !program.
168
(declare (xargs :stobjs (s)))
172
(declare (xargs :stobjs (s)))
173
(nth (pc s) (program s)))
175
; -----------------------------------------------------------------
176
; Instruction Accessors
178
(defun op-code (inst)
184
; -----------------------------------------------------------------
188
; Now we define the semantics of each instruction. These functions are called
189
; ``semantic functions.''
191
; Each opcode will be given semantics with an ACL2 function that takes an
192
; instruction (with the given opcode) and a state and returns the state
193
; produced by executing the instruction. For example, the ILOAD instruction,
194
; which looks like this (ILOAD k), where k is the index of the local variable
195
; to be loaded, is given semantics by the function execute-ILOAD. Execute-ILOAD is
196
; the ``semantic function'' for ILOAD.
198
; Our expectation when (execute-ILOAD inst s) is called is that s is a ``good''
199
; M1 state, that inst is the next instruction in s, and that inst is an ILOAD
200
; instruction. If all that is true, we can run execute-ILOAD without error,
201
; i.e., without worrying whether the instruction is well-formed, whether the
202
; local variable of that index exists, whether incrementing the pc pushes it
203
; outside the bounds of the program, etc. Because we have analogous
204
; expectations on the semantic function for each opcode, we wrap up these
205
; expectations into a single predicate:
207
; Semantics of (ILOAD k): increment the pc and push onto the stack the value of
208
; the kth local. Aside: We will know, by guard verification, that the new pc
209
; is legal and that the value pushed is a rational number. As a rule, I will
210
; not comment here on everything we know by guard verification, I'm just trying
211
; to give you a sense of the implications of our expectations.
213
(defun execute-ILOAD (inst s)
214
(declare (xargs :stobjs (s)))
215
(let* ((s (!stack (push (loi (arg1 inst) s) (stack s))
217
(s (!pc (+ 1 (pc s)) s)))
220
; Semantics of (ICONST k): increment the pc and push k onto the stack.
222
(defun execute-ICONST (inst s)
223
(declare (xargs :stobjs (s)))
224
(let* ((s (!stack (push (arg1 inst) (stack s))
226
(s (!pc (+ 1 (pc s)) s)))
229
; Semantics of (IADD): increment the pc, pop two items off the stack and push
230
; their sum. Aside: We will know, by guard verification, that there are at
231
; least two items on the stack and that they are both rational numbers.
233
(defun execute-IADD (inst s)
234
(declare (xargs :stobjs (s))
236
(let ((u (top (stack s)))
237
(v (top (pop (stack s))))
238
(stack1 (pop (pop (stack s)))))
239
(let* ((s (!stack (push (+ v u) stack1) s))
240
(s (!pc (+ 1 (pc s)) s)))
243
; Semantics of (ISUB): increment the pc, pop two items off the stack and push
246
(defun execute-ISUB (inst s)
247
(declare (xargs :stobjs (s))
249
(let ((u (top (stack s)))
250
(v (top (pop (stack s))))
251
(stack1 (pop (pop (stack s)))))
252
(let* ((s (!stack (push (- v u) stack1) s))
253
(s (!pc (+ 1 (pc s)) s)))
256
; Semantics of (IMUL): increment the ic, pop two items off the stack and push
259
(defun execute-IMUL (inst s)
260
(declare (xargs :stobjs (s))
262
(let ((u (top (stack s)))
263
(v (top (pop (stack s))))
264
(stack1 (pop (pop (stack s)))))
265
(let* ((s (!stack (push (* v u) stack1) s))
266
(s (!pc (+ 1 (pc s)) s)))
269
; Semantics of (ISTORE k): increment the ic, pop one item off the stack, and
270
; store it as the value of local variable k.
272
(defun execute-ISTORE (inst s)
273
(declare (xargs :stobjs (s)))
274
(let ((u (top (stack s)))
275
(stack1 (pop (stack s))))
276
(let* ((s (!stack stack1 s))
277
(s (!loi (arg1 inst) u s))
278
(s (!pc (+ 1 (pc s)) s)))
281
; Semantics of (GOTO k): increment the pc by k. Aside: We will know, by guard
282
; verification, that the new pc is legal.
284
(defun execute-GOTO (inst s)
285
(declare (xargs :stobjs (s)))
286
(let* ((s (!pc (+ (arg1 inst) (pc s)) s)))
289
; Semantics of (IFEQ k): pop one item off the stack and increment the pc k if
290
; that item is 0 and by 1 if if is non-0. Aside: We will know, by guard
291
; verification, that the new pc is legal.
293
(defun execute-IFEQ (inst s)
294
(declare (xargs :stobjs (s)))
295
(let ((u (top (stack s)))
296
(stack1 (pop (stack s))))
297
(let* ((s (!stack stack1 s))
298
(s (!pc (if (equal u 0)
299
(+ (arg1 inst) (pc s))
304
(defun do-inst (inst s)
305
(declare (xargs :stobjs (s)))
306
(if (equal (op-code inst) 'ILOAD)
307
(execute-ILOAD inst s)
308
(if (equal (op-code inst) 'ICONST)
309
(execute-ICONST inst s)
310
(if (equal (op-code inst) 'IADD)
311
(execute-IADD inst s)
312
(if (equal (op-code inst) 'ISUB)
313
(execute-ISUB inst s)
314
(if (equal (op-code inst) 'IMUL)
315
(execute-IMUL inst s)
316
(if (equal (op-code inst) 'ISTORE)
317
(execute-ISTORE inst s)
318
(if (equal (op-code inst) 'GOTO)
319
(execute-GOTO inst s)
320
(if (equal (op-code inst) 'IFEQ)
321
(execute-IFEQ inst s)
324
; This is the single-step function: it executes the next instruction in a
325
; state. Aside: We will know, by guard verification, that the resulting state
329
(declare (xargs :stobjs (s)))
330
(do-inst (next-inst s) s))
333
(declare (xargs :stobjs (s)))
340
(declare (xargs :stobjs (s)))
341
(equal (next-inst s) '(HALT)))
343
; =================================================================
344
; Lemmas for Proving M1 Code
348
(include-book "arithmetic-5/top" :dir :system)
353
(equal (top (push x y)) x))
356
(equal (pop (push x y)) y))
361
(popn (- n 1) (pop stk))))
363
(defmacro push* (&rest lst)
368
`(push ,(car lst) (push* ,@(cdr lst))))))
371
(equal (len (push x y))
374
; Abstract Data Type Stuff
376
(defthm constant-stacks
379
; These next two are needed because some push expressions evaluate to
380
; list constants, e.g., (push 1 (push 2 nil)) becomes '(1 2) and '(1
381
; 2) pattern-matches with (cons x s) but not with (push x s).
383
(equal (top (cons x s)) x)
384
(equal (pop (cons x s)) s))
385
:hints (("Goal" :in-theory (enable top pop))))
388
(in-theory (disable push (:executable-counterpart push) top pop))
393
(implies (consp (next-inst s))
395
(do-inst (next-inst s) s)))
397
:hints (("Goal" :in-theory (enable step))))
399
(in-theory (disable step))
403
(defun binary-clk+ (i j)
404
(+ (nfix i) (nfix j)))
406
(defthm clk+-associative
407
(equal (binary-clk+ (binary-clk+ i j) k)
408
(binary-clk+ i (binary-clk+ j k))))
410
(defmacro clk+ (&rest argst)
413
(if (endp (cdr argst))
415
`(binary-clk+ ,(car argst)
416
(clk+ ,@(cdr argst))))))
419
(equal (m1 s (clk+ i j))
422
(in-theory (disable binary-clk+))
425
(and (equal (m1 s 0) s)
427
(equal (m1 s (+ 1 i))
430
(in-theory (disable m1))
439
; In our code proofs we need this theorem to prove that certain initial states
440
; satisfy the good-statep predicate.
443
(equal (equal (len x) 0)