def test_assemble(): @family_closure def PE_fc(family): Bit = family.Bit @family.assemble(locals(), globals()) class PESimple(Peak, typecheck=True): def __call__(self, in0: Bit, in1: Bit) -> Bit: return in0 & in1 return PESimple #verify BV works PE_bv = PE_fc(family.PyFamily()) vals = [Bit(0), Bit(1)] for i0, i1 in itertools.product(vals, vals): assert PE_bv()(i0, i1) == i0 & i1 #verify SMT works PE_smt = PE_fc(family.SMTFamily()) vals = [SMTBit(0), SMTBit(1), SMTBit(), SMTBit()] for i0, i1 in itertools.product(vals, vals): assert PE_smt()(i0, i1) == i0 & i1 #verify magma works PE_magma = PE_fc(family.MagmaFamily()) tester = fault.Tester(PE_magma) vals = [0, 1] for i0, i1 in itertools.product(vals, vals): tester.circuit.in0 = i0 tester.circuit.in1 = i1 tester.eval() tester.circuit.O.expect(i0 & i1) tester.compile_and_run("verilator", flags=["-Wno-fatal"])
def test_substitute(): a0 = SMTBit() a1 = SMTBit() b0 = SMTBit() b1 = SMTBit() expr0 = a0|b0 expr1 = expr0.substitute((a0, a1), (b0, b1)) assert expr1.value is (a1|b1).value
def test_ite_tuple(): a = SMTBitVector[8](), SMTBit(), SMTBitVector[4]() b = SMTBitVector[8](), SMTBit(), SMTBitVector[4]() c = SMTBit() res = c.ite(a, b) assert isinstance(res, tuple) assert len(res) == 3 assert isinstance(res[0], SMTBitVector[8]) assert isinstance(res[1], SMTBit) assert isinstance(res[2], SMTBitVector[4])
def test_enum(): class Op(Enum): And = 1 Or = 2 @family_closure def PE_fc(family): Bit = family.Bit @family.assemble(locals(), globals()) class PE_Enum(Peak): def __call__(self, op: Const(Op), in0: Bit, in1: Bit) -> Bit: if op == Op.And: return in0 & in1 else: #op == Op.Or return in0 | in1 return PE_Enum # verify BV works PE_bv = PE_fc(family.PyFamily()) vals = [Bit(0), Bit(1)] for op in Op.enumerate(): for i0, i1 in itertools.product(vals, vals): res = PE_bv()(op, i0, i1) gold = (i0 & i1) if (op is Op.And) else (i0 | i1) assert res == gold # verify BV works PE_smt = PE_fc(family.SMTFamily()) Op_aadt = AssembledADT[Op, Assembler, SMTBitVector] vals = [SMTBit(0), SMTBit(1), SMTBit(), SMTBit()] for op in Op.enumerate(): op = Op_aadt(op) for i0, i1 in itertools.product(vals, vals): res = PE_smt()(op, i0, i1) gold = (i0 & i1) if (op is Op.And) else (i0 | i1) assert res == gold # verify magma works asm = Assembler(Op) PE_magma = PE_fc(family.MagmaFamily()) tester = fault.Tester(PE_magma) vals = [0, 1] for op in (Op.And, Op.Or): for i0, i1 in itertools.product(vals, vals): gold = (i0 & i1) if (op is Op.And) else (i0 | i1) tester.circuit.op = int(asm.assemble(op)) tester.circuit.in0 = i0 tester.circuit.in1 = i1 tester.eval() tester.circuit.O.expect(gold) tester.compile_and_run("verilator", flags=["-Wno-fatal"])
def test_protocol_ite_smt(): Counter, CounterMeta, Word = gen_counter(SMTBitVector) init = Word(name='init') cnt1 = Counter(init) cnt2 = Counter(init) cnt1.inc() # pysmt == is structural equiv assert cnt1.val.value == (init.value + 1) assert cnt1.val.value != init.value assert cnt2.val.value == init.value cnt3 = SMTBit(0).ite(cnt1, cnt2) assert cnt3.val.value == cnt2.val.value cnt4 = SMTBit(1).ite(cnt1, cnt2) assert cnt4.val.value == cnt1.val.value cond = SMTBit(name='cond') cnt5 = cond.ite(cnt1, cnt2) assert cnt5.val.value == cond.ite(cnt1.val, cnt2.val).value
def test_poly_smt(): S = SMTSIntVector[8] U = SMTUIntVector[8] c1 = SMTBit(name='c1') u1 = U(name='u1') u2 = U(name='u2') s1 = S(name='s1') s2 = S(name='s2') # NOTE: __eq__ on pysmt terms is strict structural equivalence # for example: assert u1.value == u1.value # .value extract pysmt term assert u1.value != u2.value assert (u1 * 2).value != (u1 + u1).value assert (u1 + u2).value == (u1 + u2).value assert (u1 + u2).value != (u2 + u1).value # On to the real test expr = c1.ite(u1, s1) < 1 # get the pysmt values _c1, _u1, _s1 = c1.value, u1.value, s1.value e1 = sc.Ite(_c1, _u1, _s1) one = sc.BV(1, 8) # Here we see that `< 1` dispatches symbolically f = sc.Ite(_c1, sc.BVULT(e1, one), sc.BVSLT(e1, one)) assert expr.value == f expr = expr.ite(c1.ite(u1, s1), c1.ite(s2, u2)).ext(1) e2 = sc.Ite(_c1, s2.value, u2.value) e3 = sc.Ite(f, e1, e2) se = sc.BVSExt(e3, 1) ze = sc.BVZExt(e3, 1) g = sc.Ite( f, sc.Ite(_c1, ze, se), sc.Ite(_c1, se, ze) ) # Here we see that ext dispatches symbolically / recursively assert expr.value == g # Here we see that polymorphic types only build muxes if they need to expr = c1.ite(u1, s1) + 1 assert expr.value == sc.BVAdd(e1, one) # Note how it is not: assert expr.value != sc.Ite(_c1, sc.BVAdd(e1, one), sc.BVAdd(e1, one))
Simple = Simple_fc(Bit.get_family()) InputBV = rebind_type(Input, Bit.get_family()) OutputBV = rebind_type(Output, Bit.get_family()) for name, t in InputBV.field_dict.items(): assert Simple.input_t.field_dict[name] is t for name, t in OutputBV.field_dict.items(): assert Simple.output_t.field_dict[name] is t simple = Simple() BV16 = BitVector[16] x, y = simple(BV16(5), BV16(6), Bit(1)) assert x == BV16(5) assert y == Bit(1) @pytest.mark.parametrize("family", [Bit.get_family(), SMTBit.get_family()]) @pytest.mark.parametrize("args", [(rand_value(16), rand_value(16)) for _ in range(20)]) def test_smallir(family, args): args = [family.BitVector[16](val) for val in args] #IR ir = gen_SmallIR(16) for name, fun in ( ("Add", lambda x, y: x + y), ("Sub", lambda x, y: x - y), ("And", lambda x, y: x & y), ("Nand", lambda x, y: ~(x & y)), ("Or", lambda x, y: (x | y)), ("Nor", lambda x, y: ~(x | y)),
def test_bool(): b = SMTBit() with pytest.raises(TypeError): bool(b)
def test_ite_fail(): p = SMTBit() t = SMTBit() f = SMTBitVector[1]() with pytest.raises(TypeError): res = p.ite(t, f)