diff options
Diffstat (limited to 'backends')
| -rw-r--r-- | backends/aiger/aiger.cc | 25 | ||||
| -rw-r--r-- | backends/smt2/smtbmc.py | 195 | ||||
| -rw-r--r-- | backends/smt2/smtio.py | 12 |
3 files changed, 168 insertions, 64 deletions
diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc index 35935b847..547d131ee 100644 --- a/backends/aiger/aiger.cc +++ b/backends/aiger/aiger.cc @@ -606,7 +606,7 @@ struct AigerWriter f << stringf("c\nGenerated by %s\n", yosys_version_str); } - void write_map(std::ostream &f, bool verbose_map) + void write_map(std::ostream &f, bool verbose_map, bool no_startoffset) { dict<int, string> input_lines; dict<int, string> init_lines; @@ -627,32 +627,33 @@ struct AigerWriter continue; int a = aig_map.at(sig[i]); + int index = no_startoffset ? i : (wire->start_offset+i); if (verbose_map) - wire_lines[a] += stringf("wire %d %d %s\n", a, wire->start_offset+i, log_id(wire)); + wire_lines[a] += stringf("wire %d %d %s\n", a, index, log_id(wire)); if (wire->port_input) { log_assert((a & 1) == 0); - input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, wire->start_offset+i, log_id(wire)); + input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, index, log_id(wire)); } if (wire->port_output) { int o = ordered_outputs.at(sig[i]); - output_lines[o] += stringf("output %d %d %s\n", o, wire->start_offset+i, log_id(wire)); + output_lines[o] += stringf("output %d %d %s\n", o, index, log_id(wire)); } if (init_inputs.count(sig[i])) { int a = init_inputs.at(sig[i]); log_assert((a & 1) == 0); - init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, wire->start_offset+i, log_id(wire)); + init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, index, log_id(wire)); } if (ordered_latches.count(sig[i])) { int l = ordered_latches.at(sig[i]); if (zinit_mode && (aig_latchinit.at(l) == 1)) - latch_lines[l] += stringf("invlatch %d %d %s\n", l, wire->start_offset+i, log_id(wire)); + latch_lines[l] += stringf("invlatch %d %d %s\n", l, index, log_id(wire)); else - latch_lines[l] += stringf("latch %d %d %s\n", l, wire->start_offset+i, log_id(wire)); + latch_lines[l] += stringf("latch %d %d %s\n", l, index, log_id(wire)); } } } @@ -713,6 +714,9 @@ struct AigerBackend : public Backend { log(" -vmap <filename>\n"); log(" like -map, but more verbose\n"); log("\n"); + log(" -no-startoffset\n"); + log(" make indexes zero based, enable using map files with smt solvers.\n"); + log("\n"); log(" -I, -O, -B, -L\n"); log(" If the design contains no input/output/assert/flip-flop then create one\n"); log(" dummy input/output/bad_state-pin or latch to make the tools reading the\n"); @@ -730,6 +734,7 @@ struct AigerBackend : public Backend { bool omode = false; bool bmode = false; bool lmode = false; + bool no_startoffset = false; std::string map_filename; log_header(design, "Executing AIGER backend.\n"); @@ -762,6 +767,10 @@ struct AigerBackend : public Backend { verbose_map = true; continue; } + if (args[argidx] == "-no-startoffset") { + no_startoffset = true; + continue; + } if (args[argidx] == "-I") { imode = true; continue; @@ -804,7 +813,7 @@ struct AigerBackend : public Backend { mapf.open(map_filename.c_str(), std::ofstream::trunc); if (mapf.fail()) log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); - writer.write_map(mapf, verbose_map); + writer.write_map(mapf, verbose_map, no_startoffset); } } } AigerBackend; diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 7527f4105..137182f33 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -50,6 +50,7 @@ smtcinit = False smtctop = None noinit = False binarymode = False +keep_going = False so = SmtOpts() @@ -143,7 +144,7 @@ def usage(): --dump-all when using -g or -i, create a dump file for each - step. The character '%' is replaces in all dump + step. The character '%' is replaced in all dump filenames with the step number. --append <num_steps> @@ -153,6 +154,13 @@ def usage(): --binary dump anyconst values as raw bit strings + + --keep-going + continue BMC after the first failed assertion and report + further failed assertions. To output multiple traces + covering all found failed assertions, the character '%' is + replaced in all dump filenames with an increasing number. + """ + so.helpmsg()) sys.exit(1) @@ -161,7 +169,7 @@ try: opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts + ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat", "dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=", - "smtc-init", "smtc-top=", "noinit", "binary"]) + "smtc-init", "smtc-top=", "noinit", "binary", "keep-going"]) except: usage() @@ -234,6 +242,8 @@ for o, a in opts: topmod = a elif o == "--binary": binarymode = True + elif o == "--keep-going": + keep_going = True elif so.handle(o, a): pass else: @@ -341,13 +351,13 @@ for fn in inconstr: assert False -def get_constr_expr(db, state, final=False, getvalues=False): +def get_constr_expr(db, state, final=False, getvalues=False, individual=False): if final: if ("final-%d" % state) not in db: - return ([], [], []) if getvalues else "true" + return ([], [], []) if getvalues or individual else "true" else: if state not in db: - return ([], [], []) if getvalues else "true" + return ([], [], []) if getvalues or individual else "true" netref_regex = re.compile(r'(^|[( ])\[(-?[0-9]+:|)([^\]]*|\S*)\](?=[ )]|$)') @@ -368,15 +378,18 @@ def get_constr_expr(db, state, final=False, getvalues=False): expr_list = list() for loc, expr in db[("final-%d" % state) if final else state]: actual_expr = netref_regex.sub(replace_netref, expr) - if getvalues: + if getvalues or individual: expr_list.append((loc, expr, actual_expr)) else: expr_list.append(actual_expr) - if getvalues: - loc_list, expr_list, acual_expr_list = zip(*expr_list) - value_list = smt.get_list(acual_expr_list) - return loc_list, expr_list, value_list + if getvalues or individual: + loc_list, expr_list, actual_expr_list = zip(*expr_list) + if individual: + return loc_list, expr_list, actual_expr_list + else: + value_list = smt.get_list(actual_expr_list) + return loc_list, expr_list, value_list if len(expr_list) == 0: return "true" @@ -829,7 +842,7 @@ def char_ok_in_verilog(c,i): return False def escape_identifier(identifier): - if type(identifier) is list: + if type(identifier) is list: return map(escape_identifier, identifier) if "." in identifier: return ".".join(escape_identifier(identifier.split("."))) @@ -1071,7 +1084,7 @@ def write_trace(steps_start, steps_stop, index): write_constr_trace(steps_start, steps_stop, index) -def print_failed_asserts_worker(mod, state, path, extrainfo): +def print_failed_asserts_worker(mod, state, path, extrainfo, infomap, infokey=()): assert mod in smt.modinfo found_failed_assert = False @@ -1079,29 +1092,31 @@ def print_failed_asserts_worker(mod, state, path, extrainfo): return for cellname, celltype in smt.modinfo[mod].cells.items(): - if print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname, extrainfo): + cell_infokey = (mod, cellname, infokey) + if print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname, extrainfo, infomap, cell_infokey): found_failed_assert = True for assertfun, assertinfo in smt.modinfo[mod].asserts.items(): if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]: - print_msg("Assert failed in %s: %s%s" % (path, assertinfo, extrainfo)) + assert_key = (assertfun, infokey) + print_msg("Assert failed in %s: %s%s%s" % (path, assertinfo, extrainfo, infomap.get(assert_key, ''))) found_failed_assert = True return found_failed_assert -def print_failed_asserts(state, final=False, extrainfo=""): +def print_failed_asserts(state, final=False, extrainfo="", infomap={}): if noinfo: return loc_list, expr_list, value_list = get_constr_expr(constr_asserts, state, final=final, getvalues=True) found_failed_assert = False for loc, expr, value in zip(loc_list, expr_list, value_list): if smt.bv2int(value) == 0: - print_msg("Assert %s failed: %s%s" % (loc, expr, extrainfo)) + print_msg("Assert %s failed: %s%s%s" % (loc, expr, extrainfo, infomap.get(loc, ''))) found_failed_assert = True if not final: - if print_failed_asserts_worker(topmod, "s%d" % state, topmod, extrainfo): + if print_failed_asserts_worker(topmod, "s%d" % state, topmod, extrainfo, infomap): found_failed_assert = True return found_failed_assert @@ -1148,6 +1163,43 @@ def get_cover_list(mod, base): return cover_expr, cover_desc + +def get_assert_map(mod, base, path, key_base=()): + assert mod in smt.modinfo + + assert_map = dict() + + for expr, desc in smt.modinfo[mod].asserts.items(): + assert_map[(expr, key_base)] = ("(|%s| %s)" % (expr, base), path, desc) + + for cell, submod in smt.modinfo[mod].cells.items(): + assert_map.update(get_assert_map(submod, "(|%s_h %s| %s)" % (mod, cell, base), path + "." + cell, (mod, cell, key_base))) + + return assert_map + + +def get_assert_keys(): + keys = set() + keys.update(get_assert_map(topmod, 'state', topmod).keys()) + for step_constr_asserts in constr_asserts.values(): + keys.update(loc for loc, expr in step_constr_asserts) + + return keys + + +def get_active_assert_map(step, active): + assert_map = dict() + for key, assert_data in get_assert_map(topmod, "s%s" % step, topmod).items(): + if key in active: + assert_map[key] = assert_data + + for loc, expr, actual_expr in zip(*get_constr_expr(constr_asserts, step, individual=True)): + if loc in active: + assert_map[loc] = (actual_expr, None, (expr, loc)) + + return assert_map + + states = list() asserts_antecedent_cache = [list()] asserts_consequent_cache = [list()] @@ -1457,6 +1509,10 @@ elif covermode: print_msg("Unreached cover statement at %s." % cover_desc[i]) else: # not tempind, covermode + active_assert_keys = get_assert_keys() + failed_assert_infomap = dict() + traceidx = 0 + step = 0 retstatus = "PASSED" while step < num_steps: @@ -1510,44 +1566,83 @@ else: # not tempind, covermode break if not final_only: - if last_check_step == step: - print_msg("Checking assertions in step %d.." % (step)) - else: - print_msg("Checking assertions in steps %d to %d.." % (step, last_check_step)) - smt_push() - - smt_assert("(not (and %s))" % " ".join(["(|%s_a| s%d)" % (topmod, i) for i in range(step, last_check_step+1)] + - [get_constr_expr(constr_asserts, i) for i in range(step, last_check_step+1)])) - - if smt_check_sat() == "sat": - print("%s BMC failed!" % smt.timestamp()) - if append_steps > 0: - for i in range(last_check_step+1, last_check_step+1+append_steps): - print_msg("Appending additional step %d." % i) - smt_state(i) - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, i)) - smt_assert_consequent("(|%s_u| s%d)" % (topmod, i)) - smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i)) - smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i)) - smt_assert_consequent(get_constr_expr(constr_assumes, i)) - print_msg("Re-solving with appended steps..") - if smt_check_sat() == "unsat": - print("%s Cannot append steps without violating assumptions!" % smt.timestamp()) - retstatus = "FAILED" - break - print_anyconsts(step) + recheck_current_step = True + while recheck_current_step: + recheck_current_step = False + if last_check_step == step: + print_msg("Checking assertions in step %d.." % (step)) + else: + print_msg("Checking assertions in steps %d to %d.." % (step, last_check_step)) + smt_push() + + active_assert_maps = dict() + active_assert_exprs = list() for i in range(step, last_check_step+1): - print_failed_asserts(i) - write_trace(0, last_check_step+1+append_steps, '%') - retstatus = "FAILED" - break + assert_expr_map = get_active_assert_map(i, active_assert_keys) + active_assert_maps[i] = assert_expr_map + active_assert_exprs.extend(assert_data[0] for assert_data in assert_expr_map.values()) - smt_pop() + if active_assert_exprs: + if len(active_assert_exprs) == 1: + active_assert_expr = active_assert_exprs[0] + else: + active_assert_expr = "(and %s)" % " ".join(active_assert_exprs) + + smt_assert("(not %s)" % active_assert_expr) + else: + smt_assert("false") + + + if smt_check_sat() == "sat": + if retstatus != "FAILED": + print("%s BMC failed!" % smt.timestamp()) + + if append_steps > 0: + for i in range(last_check_step+1, last_check_step+1+append_steps): + print_msg("Appending additional step %d." % i) + smt_state(i) + smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, i)) + smt_assert_consequent("(|%s_u| s%d)" % (topmod, i)) + smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i)) + smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i)) + smt_assert_consequent(get_constr_expr(constr_assumes, i)) + print_msg("Re-solving with appended steps..") + if smt_check_sat() == "unsat": + print("%s Cannot append steps without violating assumptions!" % smt.timestamp()) + retstatus = "FAILED" + break + print_anyconsts(step) + + for i in range(step, last_check_step+1): + print_failed_asserts(i, infomap=failed_assert_infomap) + + if keep_going: + for i in range(step, last_check_step+1): + for key, (expr, path, desc) in active_assert_maps[i].items(): + if key in active_assert_keys and not smt.bv2int(smt.get(expr)): + failed_assert_infomap[key] = " [failed before]" + + active_assert_keys.remove(key) + + if active_assert_keys: + recheck_current_step = True + + write_trace(0, last_check_step+1+append_steps, "%d" % traceidx if keep_going else '%') + traceidx += 1 + retstatus = "FAILED" + + smt_pop() + if recheck_current_step: + print_msg("Checking remaining assertions..") + + if retstatus == "FAILED" and not (keep_going and active_assert_keys): + break if (constr_final_start is not None) or (last_check_step+1 != num_steps): for i in range(step, last_check_step+1): - smt_assert("(|%s_a| s%d)" % (topmod, i)) - smt_assert(get_constr_expr(constr_asserts, i)) + assert_expr_map = get_active_assert_map(i, active_assert_keys) + for assert_data in assert_expr_map.values(): + smt_assert(assert_data[0]) if constr_final_start is not None: for i in range(step, last_check_step+1): diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 3d458e6cf..14feec30d 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -20,7 +20,7 @@ import sys, re, os, signal import subprocess if os.name == "posix": import resource -from copy import deepcopy +from copy import copy from select import select from time import time from queue import Queue, Empty @@ -301,7 +301,7 @@ class SmtIo: key = tuple(stmt) if key not in self.unroll_cache: - decl = deepcopy(self.unroll_decls[key[0]]) + decl = copy(self.unroll_decls[key[0]]) self.unroll_cache[key] = "|UNROLL#%d|" % self.unroll_idcnt decl[1] = self.unroll_cache[key] @@ -442,10 +442,10 @@ class SmtIo: if stmt == "(push 1)": self.unroll_stack.append(( - deepcopy(self.unroll_sorts), - deepcopy(self.unroll_objs), - deepcopy(self.unroll_decls), - deepcopy(self.unroll_cache), + copy(self.unroll_sorts), + copy(self.unroll_objs), + copy(self.unroll_decls), + copy(self.unroll_cache), )) if stmt == "(pop 1)": |
