def test_syn_yosys(self): s = syn(self.s27, "yosys", suppress_output=True) m = miter(self.s27, s) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output)
def test_syn_yosys(self): # synthesize and check equiv s = syn(self.s27, "Yosys", print_output=False) m = miter(self.s27, s) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output)
def test_bench_output(self): g = cg.from_lib(f"b17_C") g2 = cg.bench_to_circuit(cg.circuit_to_bench(g), g.name) m = miter(g, g2) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output)
def test_syn_dc(self): s = syn(self.s27, "dc", suppress_output=True) m = miter(self.s27, s) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output) for f in glob.glob(f"{os.getcwd()}/command.log*"): os.remove(f) for f in glob.glob(f"{os.getcwd()}/default.svf*"): os.remove(f)
def test_syn_genus(self): s = syn(self.s27, "genus", suppress_output=True) m = miter(self.s27, s) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output) for f in glob.glob(f"{os.getcwd()}/genus.cmd*"): os.remove(f) for f in glob.glob(f"{os.getcwd()}/genus.log*"): os.remove(f) shutil.rmtree(f"{os.getcwd()}/fv")
def test_fast_verilog(self): g = cg.from_file(f"{self.test_path}/../c432.v") gf = cg.from_file(f"{self.test_path}/../c432.v", fast=True) self.assertSetEqual(g.inputs(), gf.inputs()) self.assertSetEqual(g.outputs(), gf.outputs()) self.assertSetEqual(g.nodes(), gf.nodes()) self.assertSetEqual(g.edges(), gf.edges()) m = miter(g, gf) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output)
def test_syn_genus(self): if "CIRCUITGRAPH_GENUS_LIBRARY_PATH" in os.environ: s = syn(self.s27, "Genus", print_output=False) m = miter(self.s27, s) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output) for f in glob.glob(f"{os.getcwd()}/genus.cmd*"): os.remove(f) for f in glob.glob(f"{os.getcwd()}/genus.log*"): os.remove(f) shutil.rmtree(f"{os.getcwd()}/fv")
def test_gtech_verilog(self): g = cg.from_file(f"{self.test_path}/../c432.v") with tempfile.TemporaryDirectory( prefix="circuitgraph_test_dir") as tmpdirname: g_syn = cg.syn(g, engine="dc", suppress_output=True, working_dir=tmpdirname) m = miter(g, g_syn) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output)
def test_sat(self): self.assertTrue(sat(self.c17)) self.assertTrue(sat(self.s27)) self.assertFalse(sat(self.s27, assumptions={"n_10": True, "n_7": True})) self.assertFalse(sat(self.s27, assumptions={"n_12": True, "G0": False})) self.assertFalse( sat( self.c17, assumptions={ "G16": True, "G17": True, "G1": False, "G2": False, "G3": False, "G4": False, "G5": False, }, ) ) self.assertFalse( sat( self.c17, assumptions={ "G16": True, "G1": False, "G2": False, "G3": False, "G4": False, "G5": False, }, ) ) self.assertFalse( sat( self.c17, assumptions={ "G17": True, "G1": False, "G2": False, "G3": False, "G4": False, "G5": False, }, ) ) self.assertTrue( sat( self.c17, assumptions={ "G16": False, "G17": False, "G1": False, "G2": False, "G3": False, "G4": False, "G5": False, }, ) )
def test_verilog_output(self): for g in [ cg.from_lib("test_correct_io", name="test_module_0"), cg.from_lib("test_correct_io", name="test_module_1"), cg.from_lib("test_correct_io", name="test_module_2"), cg.from_lib("test_correct_io", name="test_module_3"), ]: g2 = verilog_to_circuit(circuit_to_verilog(g), g.name) m = miter(g, g2) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) if different_output: import code code.interact(local=dict(globals(), **locals())) self.assertFalse(different_output)
def test_xor_hash(self): n = 5 m = 3 h = xor_hash(n, m) inp = {f"in_{i}": randint(0, 1) for i in range(n)} result = sat(h, inp)
def sensitize(c, n, assumptions): """ Finds an input that sensitizes n to an endpoint under assumptions. Parameters ---------- c: Circuit Circuit to compute sensitivity for n : str Node to compute sensitivity for. assumptions : dict of str:bool Assumptions for Circuit. Returns ------- dict of str:bool Input value. """ # setup circuit s = sensitization_transform(c, n) # find a sensitizing input result = sat(s, {"sat": True, **assumptions}) if not result: return None return {g: result[g] for g in s.startpoints()}
def sensitivity(c, n): """ Calculates the sensitivity of node n with respect to its startpoints. Parameters ---------- c: Circuit Circuit to compute sensitivity for n : str Node to compute sensitivity for. Returns ------- int Sensitivity of node n. """ sp = c.startpoints(n) if n in sp: return 1 sen = len(sp) s = sensitivity_transform(c, n) vs = int_to_bin(sen, clog2(len(sp)), True) while not sat(s, {f"sen_out_{i}": v for i, v in enumerate(vs)}): sen -= 1 vs = int_to_bin(sen, clog2(len(sp)), True) return sen
def sensitivity(self, n): """ Calculates the sensitivity of node n with respect to its startpoints. Parameters ---------- n : str Node to compute sensitivity for. Returns ------- int Sensitivity of node n. """ from circuitgraph.transform import sensitivity from circuitgraph.sat import sat sp = self.startpoints(n) sen = len(sp) s = sensitivity(c, n) vs = int_to_bin(sen, clog2(len(sp)), True) while not sat(s, {f"out_{i}": v for i, v in enumerate(vs)}): sen -= 1 vs = int_to_bin(sen, clog2(len(sp)), True) return sen
def test_verilog_output(self): for g in [ cg.from_file( f"{self.test_path}/test_correct_io.v", name="test_module_bb", blackboxes=self.bbs, ), cg.from_file(f"{self.test_path}/test_correct_io.v", name="test_correct_io"), ]: g2 = cg.verilog_to_circuit(cg.circuit_to_verilog(g), g.name, blackboxes=self.bbs) m = miter(cg.strip_blackboxes(g), cg.strip_blackboxes(g2)) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output)
def test_syn_dc_io(self): s = syn( self.s27, "dc", suppress_output=True, pre_syn_file="pre_syn.v", post_syn_file="post_syn.v", working_dir="syn", ) c0 = cg.from_file("pre_syn.v") c1 = cg.from_file("post_syn.v") m = miter(c0, c1) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output) os.remove("pre_syn.v") os.remove("post_syn.v") shutil.rmtree("syn")
def test_sensitize(self): # pick random node nr = choice( tuple(self.s27.nodes() - set(["clk"]) - self.s27.filter_type(["0", "1"]))) # pick startpoint ns = choice(tuple(self.s27.startpoints() - set(["clk"]))) # pick endpoint ne = choice(tuple(self.s27.endpoints() - set(["clk"]))) for n in [nr, ns, ne]: # get input input_val = sensitize(self.s27, n, {f"c0_{n}": True}) if not input_val: import code code.interact(local=dict(**globals(), **locals())) # simulate input result = sat(self.s27, input_val) if not result[n]: import code code.interact(local=dict(**globals(), **locals())) self.assertTrue(result[n]) # remove constrained input if n in input_val: input_val.pop(n) # simulate on faulty circuit c_f = cg.copy(self.s27) c_f.disconnect(c_f.fanin(n), n) c_f.set_type(n, "input") result_f = sat(c_f, {**input_val, n: False}) self.assertFalse(result_f[n]) self.assertTrue( any(result_f[e] != result[e] for e in self.s27.endpoints(n)))
def test_mux(self): p = mux(5) assumptions = { "in_0": True, "in_1": False, "in_2": False, "in_3": True, "in_4": False, "sel_0": False, "sel_1": False, "sel_2": False, } result = sat(p, assumptions) self.assertTrue(result["out"]) assumptions = { "in_0": True, "in_1": False, "in_2": False, "in_3": True, "in_4": False, "sel_0": True, "sel_1": False, "sel_2": False, } result = sat(p, assumptions) self.assertFalse(result["out"]) assumptions = { "in_0": True, "in_1": True, "in_2": False, "in_3": True, "in_4": False, "sel_0": True, "sel_1": False, "sel_2": False, } result = sat(p, assumptions) self.assertTrue(result["out"])
def test_popcount(self): w = randint(1, 66) p = popcount(w) ins = [randint(0, 1) for i in range(w)] enc_ins = {f"in_{i}": n for i, n in enumerate(ins)} result = sat(p, enc_ins) self.assertTrue(result) enc_out = [result[f"out_{i}"] for i in range(clog2(w + 1))] c = cg.bin_to_int(enc_out, lend=True) self.assertEqual(c, sum(ins))
def test_popcount(self): p = logic.popcount(5) assumptions = { "in_0": True, "in_1": False, "in_2": False, "in_3": True, "in_4": False, } result = sat(p, assumptions) self.assertFalse(result["out_0"]) self.assertTrue(result["out_1"]) self.assertFalse(result["out_2"]) self.assertFalse(result["out_3"])
def test_sensitivity_transform(self): # pick random node and input value n = choice(tuple(self.s27.nodes() - self.s27.startpoints())) nstartpoints = self.s27.startpoints(n) while len(nstartpoints) < 1: n = choice(tuple(self.s27.nodes() - self.s27.startpoints())) nstartpoints = self.s27.startpoints(n) input_val = {i: randint(0, 1) for i in nstartpoints} # build sensitivity circuit s = sensitivity_transform(self.s27, n) # find sensitivity at an input model = sat(s, input_val) sen_s = sum(model[o] for o in s.outputs() if "dif_out" in o) # try inputs Hamming distance 1 away output_val = sat(self.s27, input_val)[n] sen_sim = 0 for i in nstartpoints: neighbor_input_val = { g: v if g != i else not v for g, v in input_val.items() } neighbor_output_val = sat(self.s27, neighbor_input_val)[n] if neighbor_output_val != output_val: sen_sim += 1 # check answer self.assertEqual(sen_s, sen_sim) # find input with sensitivity vs = cg.int_to_bin(sen_s, cg.clog2(len(nstartpoints) + 1), True) model = sat(s, {f"sen_out_{i}": v for i, v in enumerate(vs)}) input_val = {i: model[i] for i in nstartpoints} # try inputs Hamming distance 1 away output_val = sat(self.s27, input_val)[n] sen_sim = 0 for i in nstartpoints: neighbor_input_val = { g: v if g != i else not v for g, v in input_val.items() } neighbor_output_val = sat(self.s27, neighbor_input_val)[n] if neighbor_output_val != output_val: sen_sim += 1 # check answer self.assertEqual(sen_s, sen_sim)
def test_adder(self): w = randint(1, 66) add = adder(w) a = randint(0, 2**w - 1) b = randint(0, 2**w - 1) enc_a = { f"a_{i}": v for i, v in enumerate(cg.int_to_bin(a, w, lend=True)) } enc_b = { f"b_{i}": v for i, v in enumerate(cg.int_to_bin(b, w, lend=True)) } result = sat(add, {**enc_a, **enc_b}) self.assertTrue(result) enc_out = [result[f"out_{i}"] for i in range(w + 1)] out = cg.bin_to_int(enc_out, lend=True) self.assertEqual(a + b, out)
def test_adder(self): a = logic.adder(5) assumptions = { "a_0": True, "a_1": False, "a_2": False, "a_3": False, "a_4": False, "b_0": True, "b_1": True, "b_2": False, "b_3": False, "b_4": False, } result = sat(a, assumptions) self.assertFalse(result["out_0"]) self.assertFalse(result["out_1"]) self.assertTrue(result["out_2"]) self.assertFalse(result["out_3"]) self.assertFalse(result["out_4"]) self.assertFalse(result["out_5"])
def test_miter(self): # check self equivalence m = miter(self.s27) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertFalse(different_output) # check equivalence with incorrect copy m = miter(self.s27, self.s27m) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertTrue(different_output) # check equivalence with free inputs startpoints = self.s27.startpoints() - set(["clk"]) startpoints.pop() m = miter(self.s27, startpoints=startpoints) live = sat(m) self.assertTrue(live) different_output = sat(m, assumptions={"sat": True}) self.assertTrue(different_output)
def test_banyan(self): bw = 32 b = banyan(bw) inp = {n: randint(0, 1) for n in b.inputs()} result = sat(b, inp)