1
;;; This file contains a proof of the 6502 multiply program using the tail
2
;;; recursion generic theory.
4
(note-lib "modularithmetic-98")
5
(load "generic-theories.events")
7
;;; The following is a Floyd-Hoare correctness specification for the multiply
10
;;; { F1=F1SAVE ^ F1<256 ^ F2<256 ^ LOW<256 }
12
;;; LDX #8 load the X register immediate with the value 8
13
;;; LDA #0 load the A register immediate with the value 0
14
;;; LOOP ROR F1 rotate F1 right circular through the carry flag
15
;;; BCC ZCOEF branch on carry flag clear to ZCOEF
16
;;; CLC clear the carry flag
17
;;; ADC F2 add with carry F2 to the contents of A
18
;;; ZCOEF ROR A rotate A right circular through the carry flag
19
;;; ROR LOW rotate LOW right circular through the carry flag
20
;;; DEX decrement the X register by 1
21
;;; BNE LOOP branch if X is non-zero to LOOP
23
;;; { LOW + 256*A = F1SAVE*F2 }
25
;;; Provide semantics for the Mostek 6502 DEX instruction. The remaining
26
;;; instructions have semantics built into the weakest precondition generation
34
;;; This is mechanically derived.
37
(F1 X C LOW A F1SAVE F2)
40
(PLUS (TIMES (PLUS (TIMES 128 C) (QUOTIENT A 2)) 256)
41
(PLUS (TIMES 128 (REMAINDER A 2))
45
(PLUS (TIMES 128 (REMAINDER LOW 2))
51
(PLUS (PLUS (TIMES 128 C) (QUOTIENT A 2)) F2)
53
(PLUS (TIMES 128 (REMAINDER A 2))
55
(IF (EQUAL (REMAINDER F1 2) 0)
56
(PLUS (TIMES 128 C) (QUOTIENT A 2))
58
(PLUS (PLUS (TIMES 128 C) (QUOTIENT A 2))
63
((lessp (dec x)))) ; This hint is user added
65
;;; This is the weakest precondition at the beginning of the program.
67
(defn wp-zcoef-1 (f1 c low f2)
69
(plus (times 128 c) (quotient f1 2))
73
(times (remainder f1 2) f2)
77
;;; (exp i b) = b**i if b > 0, otherwise 0.
84
(times b (exp (sub1 i) b)))))
86
;;; Generalize the register size in order to capture properties of the constants
89
(defn wp-zcoef-g (f1 x c low a result f2 i)
92
(plus (times (plus (times (exp (sub1 i) 2) c) (quotient a 2))
94
(plus (times (exp (sub1 i) 2) (remainder a 2))
98
(plus (times (exp (sub1 i) 2) (remainder low 2))
104
(plus (plus (times (exp (sub1 i) 2) c) (quotient a 2)) f2)
106
(plus (times (exp (sub1 i) 2) (remainder a 2))
108
(if (equal (remainder f1 2) 0)
109
(plus (times (exp (sub1 i) 2) c) (quotient a 2))
111
(plus (plus (times (exp (sub1 i) 2) c) (quotient a 2))
119
;;; Our proof strategy is to successively transform wp-zcoef-1 into instances of more
120
;;; general functions. This performs the first step.
122
(prove-lemma wp-zcoef-g-instance (rewrite)
123
(equal (wp-zcoef f1 x c low a f1save f2)
124
(wp-zcoef-g f1 x c low a (times f1save f2) f2 8))
125
((hands-off plus times quotient remainder difference)
126
(expand (wp-zcoef f1 0 c low a f1save f2)
127
(wp-zcoef-g f1 0 c low a (times f1save f2) f2 8))))
129
;;; Split the state into an "a" component that does the effective computation, and
130
;;; an "s" component that drives the computation.
132
;;; Package the "a" component into a long integer.
134
(defn c (a i) (quotient a (exp (times 2 i) 2))) ; the carry flag
135
(defn a (a i) (remainder (quotient a (exp i 2)) (exp i 2))) ; the accumulator
136
(defn low (a i) (remainder a (exp i 2))) ; lower half of product
138
;;; Package the "s" component using lists.
140
(defn x (s) (car s)) ; x register counter
141
(defn f1 (s) (cadr s)) ; first factor
142
(defn f2 (s) (caddr s)) ; second factor
143
(defn result (s) (cadddr s)) ; the result
144
(defn i (s) (caddddr s)) ; word size in bits
146
;;; Define the instantiation of h from the generic theory. wp-zcoef-h performs a
147
;;; multiply in the standard way, except that it delivers twice the product.
150
(if (equal (dec (x s)) 0)
152
(times 2 (plus (wp-zcoef-h
158
(if (equal (remainder (f1 s) 2) 0)
161
((lessp (dec (x s)))))
163
;;; Define the instantiation of hs. btm-s compute the bottom object under tau.
166
(if (equal (dec (x s)) 0)
168
(btm-s (list (dec (x s))
173
((lessp (dec (x s)))))
175
;;; An alternative to the library rule remainder-plus-arg1 with fewer case splits.
177
(prove-lemma remainder-plus-arg1-alt (rewrite)
178
(implies (equal (remainder a d) 0)
179
(and (equal (remainder (plus a b) d) (remainder b d))
180
(equal (remainder (plus b a) d) (remainder b d))
181
(equal (remainder (plus b a c) d)
182
(remainder (plus b c) d))
183
(equal (remainder (plus b c a) d)
184
(remainder (plus b c) d))))
185
((disable-theory if-normalization)
186
(hands-off difference)
187
(disable times-add1)))
189
;;; This simple fact is absent from modularithmetic-98.
191
(prove-lemma equal-even-odd (rewrite)
192
(implies (equal (remainder a 2) (remainder b 2))
193
(and (not (equal a (add1 b)))
194
(not (equal (add1 b) a))))
195
((disable-theory if-normalization)
196
(disable remainder-add1-arg2)))
199
;;; Define an induction hint which recurses on two copies of wp-zcoef-g.
201
(defn ind-2 (f1 x c low a f1p xp cp lowp ap f2 i)
202
(if (equal (dec x) 0)
205
(plus (times (exp (sub1 i) 2) (remainder low 2))
211
(plus (plus (times (exp (sub1 i) 2) c) (quotient a 2)) f2)
213
(plus (times (exp (sub1 i) 2) (remainder a 2))
215
(if (equal (remainder f1 2) 0)
216
(plus (times (exp (sub1 i) 2) c) (quotient a 2))
218
(plus (plus (times (exp (sub1 i) 2) c) (quotient a 2))
221
(plus (times (exp (sub1 i) 2) (remainder lowp 2))
227
(plus (plus (times (exp (sub1 i) 2) cp) (quotient ap 2)) f2)
229
(plus (times (exp (sub1 i) 2) (remainder ap 2))
231
(if (equal (remainder f1p 2) 0)
232
(plus (times (exp (sub1 i) 2) cp) (quotient ap 2))
234
(plus (plus (times (exp (sub1 i) 2) cp) (quotient ap 2))
241
;;; Prove equality on wp-zcoef-g by backchaining on equality of its arguments.
243
(prove-lemma equal-wp-zcoef-g (rewrite)
244
(implies (and (equal (remainder f1 (exp (sub1 x) 2))
245
(remainder f1p (exp (sub1 x) 2)))
247
(equal (plus (times c (exp i 2)) a)
248
(plus (times cp (exp i 2)) ap))
252
(equal (equal (wp-zcoef-g f1 x c low a result f2 i)
253
(wp-zcoef-g f1p xp cp lowp ap result f2 i))
255
((disable-theory if-normalization)
256
(hands-off difference)
257
(induct (ind-2 f1 x c low a f1p xp cp lowp ap f2 i))
258
(expand (exp (sub1 xp) 2))
259
(disable remainder-add1-arg2
263
remainder-plus-arg1-simple
271
remainder-difference-arg1
273
remainder-minus-one-as-0
276
lessp-quotient-arg2-linear
281
quotient-times-arg1-simple
285
;;; An alternative to the library quotient-plus-arg1 with fewer case splits.
287
(prove-lemma quotient-plus-arg1-alt (rewrite)
288
(implies (equal (remainder a d) 0)
289
(and (equal (quotient (plus a b) d)
290
(plus (quotient a d) (quotient b d)))
291
(equal (quotient (plus b a) d)
292
(plus (quotient a d) (quotient b d)))
293
(equal (quotient (plus b a c) d)
294
(plus (quotient a d) (quotient (plus b c) d)))
295
(equal (quotient (plus b c a) d)
296
(plus (quotient a d) (quotient (plus b c) d)))))
297
((disable-theory if-normalization)
298
(hands-off difference)
299
(disable lessp-transpose-meta
302
remainder-difference-arg1
303
remainder-plus-arg1)))
305
;;; A Knuth-Bendix style rule for remainder-times-arg2.
307
(prove-lemma remainder-times-arg2-kb (rewrite)
308
(equal (plus (remainder a b)
309
(times b (remainder (quotient a b) c)))
310
(plus (remainder a c)
311
(times c (remainder (quotient a c) b))))
312
((use (remainder-times-arg2 (a a) (zb b) (zc c))
313
(remainder-times-arg2 (a a) (zb c) (zc b)))
314
(disable remainder-times-arg2
319
;;; A Knuth-Bendix style rule for quotient-times-arg2.
321
(prove-lemma remainder-times-arg2-close-kb (rewrite)
322
(equal (plus (remainder (quotient a b) c)
323
(times c (quotient (quotient a c) b)))
326
;;; More properties of exp.
328
(prove-lemma exp-plus-arg1 (rewrite)
329
(equal (exp (plus i j) b) (times (exp i b) (exp j b))))
331
(prove-lemma remainder-exp-exp (rewrite)
332
(implies (not (lessp i j))
333
(equal (remainder (exp i 2) (exp j 2)) 0))
337
(prove-lemma quotient-exp-2 (rewrite)
338
(equal (quotient (exp i 2) 2)
343
;;; Use the generic tail recursion theory.
345
(functionally-instantiate wp-zcoef-g=h nil
346
(implies (and (not (zerop (x s)))
347
(not (lessp (i s) (x s)))
349
(lessp (f2 s) (exp (i s) 2)))
359
(if (equal (dec (x s)) 0)
362
(times (plus (times (exp (sub1 (i s)) 2) (c a (i s)))
363
(quotient (a a (i s)) 2))
365
(plus (times (exp (sub1 (i s)) 2)
366
(remainder (a a (i s)) 2))
367
(quotient (low a (i s)) 2)))
369
(let ((a (if (equal (dec (x s)) 0)
371
(quotient (plus a (times (exp (i s) 2)
373
(exp (sub1 (x s)) 2))))
377
(times (plus (times (exp (sub1 (i s)) 2) (c a (i s)))
378
(quotient (a a (i s)) 2))
380
(plus (times (exp (sub1 (i s)) 2)
381
(remainder (a a (i s)) 2))
382
(quotient (low a (i s)) 2)))
385
((bb (lambda (s) (equal (dec (x s)) 0)))
386
(qt (lambda (a s) (equal
388
(times (plus (times (exp (sub1 (i s)) 2) (c a (i s)))
389
(quotient (a a (i s)) 2))
391
(plus (times (exp (sub1 (i s)) 2)
392
(remainder (a a (i s)) 2))
393
(quotient (low a (i s)) 2)))
395
(g (lambda (a s) (wp-zcoef-g (f1 s)
403
(measure-g (lambda (s) (dec (x s))))
404
(tau (lambda (s) (list (dec (x s))
410
(if (equal (remainder (f1 s) 2) 0)
413
(times (f2 s) (exp (i s) 2))))))
414
(rhoh (lambda (a s) (if (equal (remainder (f1 s) 2) 0)
416
(times 2 (plus a (f2 s))))))
417
(h (lambda (s) (wp-zcoef-h s)))
418
(rt (lambda (a s) (and (not (zerop (x s)))
419
(not (lessp (i s) (x s)))
421
(lessp (f2 s) (exp (i s) 2)))))
423
(op (lambda (a x s) (if (equal (dec (x s)) 0)
425
(quotient (plus a (times (exp (i s) 2) x))
426
(exp (sub1 (x s)) 2)))))
427
(hs (lambda (s) (btm-s s))))
428
((disable-theory if-normalization)
429
(hands-off difference)
432
(disable quotient-add1-arg2
435
remainder-plus-arg1-simple
437
remainder-difference-arg1
445
lessp-quotient-arg2-linear
452
remainder-minus-one-as-0
454
lessp-odometer-simple
455
equal-odometer-simple
460
;;; Since the bottom object under tau was defined recursively this is needed.
462
(prove-lemma btm-s-destruct (rewrite)
463
(implies (and (not (zerop (x s)))
464
(not (lessp (i s) (x s))))
465
(and (equal (car (btm-s s)) 1)
466
(equal (cadr (btm-s s))
467
(if (equal (dec (x s)) 0)
469
(quotient (f1 s) (exp (sub1 (x s)) 2))))
470
(equal (caddr (btm-s s)) (f2 s))
471
(equal (cadddr (btm-s s)) (result s))
472
(equal (caddddr (btm-s s)) (i s))))
473
((disable-theory if-normalization)
474
(hands-off difference)
475
(disable quotient-add1-arg2
481
;;; Another Knuth-Bendex style rule for quotient-times-arg2.
483
(prove-lemma quotient-times-arg2-permutative (rewrite)
484
(implies (equal (remainder c b) 0)
485
(and (equal (quotient (quotient (plus a c) d) b)
486
(quotient (plus (quotient a b)
489
(equal (quotient (quotient (quotient (plus a c) d) e) b)
491
(quotient (plus (quotient a b)
495
((disable-theory if-normalization)
496
(hands-off difference)
497
(use (quotient-times-arg2-kb
498
(a (plus a c)) (b d) (c b))
499
(quotient-times-arg2-kb
500
(a (quotient (plus a c) d)) (b e) (c b))
501
(quotient-times-arg2-kb
503
(quotient-times-arg2-kb
505
(quotient-plus-arg1 (a a) (b c) (c b)))
506
(disable quotient-times-arg2-kb
511
lessp-times-single-linear
512
lessp-quotient-arg2-linear
523
(prove-lemma remainder-exp-2 (rewrite)
524
(equal (remainder (exp i 2) 2)
528
((expand (exp i 2))))
530
(prove-lemma equal-exp-0 (rewrite)
531
(equal (equal (exp i b) 0)
534
;;; Avoids an expand hint.
536
(prove-lemma quotient-is-0 (rewrite)
537
(implies (lessp a b) (equal (quotient a b) 0)))
539
;;; Convert generic theory back to flat state space.
541
(prove-lemma wp-zcoef-g=h-flat (rewrite)
542
(implies (and (not (zerop i))
548
(lessp low (exp i 2)))
549
(equal (wp-zcoef-g f1 i 0 low a result f2 i)
550
(if (equal (dec i) 0)
554
(wp-zcoef-h (list i f1 f2 result i)))
556
((disable-theory if-normalization)
558
(a (plus low (times (exp i 2) a)))
559
(s (list i f1 f2 result i))))
560
(hands-off difference)
562
(disable quotient-add1-arg2
565
remainder-plus-arg1-simple
567
remainder-difference-arg1
578
lessp-quotient-arg2-linear)))
580
;;; Prove the primitive recursive version multiplies.
582
(prove-lemma wp-zcoef-h-multiplies (rewrite)
583
(implies (and (not (zerop (x s)))
584
(not (lessp (i s) (x s))))
585
(equal (wp-zcoef-h s)
586
(times 2 (f2 s) (remainder (f1 s) (exp (sub1 (x s)) 2)))))
587
((disable-theory if-normalization)
588
(disable quotient-add1-arg2
595
remainder-difference-arg1
598
;;; Final program correctness proof.
600
(prove-lemma wp-zcoef-is-correct (rewrite)
601
(implies (and (numberp f2)
607
(wp-zcoef-1 f1 c low f2))
608
((disable-theory if-normalization)
609
(hands-off difference)