var1 $; defaultwhere1(p) = p <= $; defaultwhere2(P) = P sub {0,...,$}; pred at_least_two(var0 A,var0 B,var0 C) = (A & B) | (A & C) | (B & C); pred mod_two(var0 A,var0 B,var0 C,var0 @d) = (A <=> B <=> C <=> @d); # "high-level" description of the addition of Cin (carry in) and vectors X # and Y with result Z and Cout (carry out); all vectors have length $+1 # and LSB is in position 0 (so LSB is set in X iff 0 in X) pred add(var2 X, var2 Y, var2 Result, var0 Cin, var0 Cout) = ex2 C1: (0 in C1 <=> Cin) & (all1 p: mod_two(p in X, p in Y, p in C1, p in Result) & (p < $ => ((p+1 in C1) <=> at_least_two(p in X, p in Y, p in C1)))) & (Cout <=> at_least_two($ in X, $ in Y, $ in C1)); # Circuit constructors as functions pred not(var0 A) = ~A; pred and(var0 A,var0 B) = A & B; pred or(var0 A,var0 B) = A | B; pred xor(var0 A,var0 B) = or(and(not(A),B),and(A,not(B))); pred nor(var0 A,var0 B) = not(or(A,B)); pred nand(var0 A,var0 B) = not(and(A,B)); # Circut constructors as relations pred notrel(var0 A,var0 B) = not(A) <=> B; pred andrel(var0 A,var0 B,var0 C) = and(A,B) <=> C; pred orrel(var0 A,var0 B,var0 C) = or(A,B) <=> C; pred xorrel(var0 A,var0 B,var0 C) = xor(A,B) <=> C; pred norrel(var0 A,var0 B,var0 C) = nor(A,B) <=> C; pred nandrel(var0 A,var0 B,var0 C) = nand(A,B) <=> C; # classical one-bit full adder circuit pred full_adder(var0 A,var0 B,var0 @out,var0 Cin,var0 Cout) = ex0 W1, W2, W3: xorrel(A,B,W1) & xorrel(W1,Cin,@out) & andrel(A,B,W2) & andrel(Cin,W1,W3) & orrel(W3,W2,Cout) ; # an n-bit adder is strung together from 1-bit adders pred n_bit_adder(var2 X, var2 Y, var2 Z, var0 Cin, var0 Cout) = ex2 C, D: all1 p: full_adder(p in X, p in Y, p in Z, p in C, p in D) & (all1 p: (p < $) => (p in D <=> (p+1 % ($+1) in C))) & (0 in C <=> Cin) & ($ in D <=> Cout); # theorems var2 X, Y, Z; assert X sub {0,...,$}; # restrict X to represent a bit-vectorsof length $+1 assert Y sub {0,...,$}; assert Z sub {0,...,$}; var0 Cin, Cout; # is an n-bit-adder equivalent to the abstract specification of add? # add(X,Y,Z,Cin,Cout) <=> n_bit_adder(X,Y,Z,Cin,Cout); # what is 7 + 12 ? 7 is 111 and 12 is 0011 (with LSB at left); # so answer should be Z=11001 (19) # X = {0,1,2} & Y = {2,3} & (Cin <=> false) & add(X,Y,Z,Cin,Cout); # can output values always be calculated? (this might not be the case # if the circuit was overconstrained) # # all2 X, Y, Z: all0 Cin: ex0 Cout: n_bit_adder(X,Y,Z,Cin,Cout); # same question as above, but we omit the leading universal # quantifiers, relying instead on global variables X, Y, and Cin # ex2 Z: ex0 Cout: n_bit_adder(X,Y,Z,Cin,Cout); # # all2 X, Y: all0 Cin: ex2 Z: ex0 Cout: add(X,Y,Z,Cin,Cout); # are these values unique? that is, does n_bit_adder denote a function # of the input values? # # all2 X, Y: all0 Cin: ex2 Z: ex0 Cout: n_bit_adder(X,Y,Z,Cin,Cout) # & all2 Z' : all0 Cout': # n_bit_adder(X,Y,Z',Cin,Cout') => (Z = Z' & (Cout<=> Cout'));