def Clock(clk): # INIT: clk = 0 # TRANS: clk' = !clk comment = "Clock (clk) = (" + clk.symbol_name() + ")" if clk.symbol_type() == BOOL: clk0 = Not(clk) clk1 = clk else: clk0 = EqualsOrIff(clk, BV(0, 1)) clk1 = EqualsOrIff(clk, BV(1, 1)) init = clk0 invar = TRUE() if False: trans = EqualsOrIff(clk0, TS.to_next(clk1)) else: # Implementation that leverages on the boolean propagation trans1 = Implies(clk0, TS.to_next(clk1)) trans2 = Implies(clk1, TS.to_next(clk0)) trans = And(trans1, trans2) if Modules.abstract_clock: invar = clk0 init = TRUE() trans = TRUE() ts = TS(comment) ts.vars, ts.state_vars = set([clk]), set([clk]) ts.set_behavior(init, trans, invar) return ts
def __encoding_memoization(self, inst_type, args): value = 0 vec_par = [] actual = [] for x in args: if x is not None: if type(x) != int: value += 1 vec_par.append(("a%s" % value, x.symbol_type().width)) actual.append(x) else: vec_par.append(x) def join(l1, l2): ret = [] for i in range(len(l1)): ret.append((l1[i], l2[i])) return ret def set_remap(in_set, remap): ret = set([]) source = False for v in in_set: if v in remap: ret.add(remap[v]) else: if source is False: base_source = ".".join( list(in_set)[0].symbol_name().split(".")[:-1]) base_dest = ".".join(remap[list( in_set)[0]].symbol_name().split(".")[:-1]) source = True ret.add( Symbol(v.symbol_name().replace(base_source, base_dest), v.symbol_type())) return ret enc_val = (inst_type, str(vec_par)) if enc_val in self.enc_map: (enc, formal) = self.enc_map[enc_val] remap = dict(join(formal, actual)) self.subwalker.set_substitute_map(remap) ts = TS() ts.vars = set_remap(enc.vars, remap) ts.set_behavior(self.subwalker.walk(enc.init), self.subwalker.walk(enc.trans), self.subwalker.walk(enc.invar)) return ts ret = self.mod_map[inst_type][0](*args) self.enc_map[enc_val] = (ret, actual) return ret
def parse_string(self, strinput): hts = HTS() ts = TS() nodemap = {} node_covered = set([]) # list of tuples of var and cond_assign_list # cond_assign_list is tuples of (condition, value) # where everything is a pysmt FNode # for btor, the condition is always True ftrans = [] initlist = [] invarlist = [] invar_props = [] ltl_props = [] prop_count = 0 # clean string input, remove special characters from names for sc, rep in special_char_replacements.items(): strinput = strinput.replace(sc, rep) def getnode(nid): node_covered.add(nid) if int(nid) < 0: return Ite(BV2B(nodemap[str(-int(nid))]), BV(0,1), BV(1,1)) return nodemap[nid] def binary_op(bvop, bop, left, right): if (get_type(left) == BOOL) and (get_type(right) == BOOL): return bop(left, right) return bvop(B2BV(left), B2BV(right)) def unary_op(bvop, bop, left): if (get_type(left) == BOOL): return bop(left) return bvop(left) for line in strinput.split(NL): linetok = line.split() if len(linetok) == 0: continue if linetok[0] == COM: continue (nid, ntype, *nids) = linetok if ntype == SORT: (stype, *attr) = nids if stype == BITVEC: nodemap[nid] = BVType(int(attr[0])) node_covered.add(nid) if stype == ARRAY: nodemap[nid] = ArrayType(getnode(attr[0]), getnode(attr[1])) node_covered.add(nid) if ntype == WRITE: nodemap[nid] = Store(*[getnode(n) for n in nids[1:4]]) if ntype == READ: nodemap[nid] = Select(getnode(nids[1]), getnode(nids[2])) if ntype == ZERO: nodemap[nid] = BV(0, getnode(nids[0]).width) if ntype == ONE: nodemap[nid] = BV(1, getnode(nids[0]).width) if ntype == ONES: width = getnode(nids[0]).width nodemap[nid] = BV((2**width)-1, width) if ntype == REDOR: width = get_type(getnode(nids[1])).width zeros = BV(0, width) nodemap[nid] = BVNot(BVComp(getnode(nids[1]), zeros)) if ntype == REDXOR: width = get_type(getnode(nids[1])).width nodemap[nid] = BV(0, width) zeros = BV(0, width) for yx_i in range(width): tmp = BV(1 << yx_i, width) tmp_2 = BVAnd(tmp, B2BV(getnode(nids[1]))) tmp_3 = BVZExt(B2BV(BVComp(tmp_2, zeros)), int(width - 1)) nodemap[nid] = BVAdd(tmp_3, nodemap[nid]) nodemap[nid] = BVComp(BVAnd(BV(1, width), nodemap[nid]), BV(1, width)) if ntype == REDAND: width = get_type(getnode(nids[1])).width ones = BV((2**width)-1, width) nodemap[nid] = BVComp(getnode(nids[1]), ones) if ntype == CONSTD: width = getnode(nids[0]).width nodemap[nid] = BV(int(nids[1]), width) if ntype == CONST: width = getnode(nids[0]).width nodemap[nid] = BV(bin_to_dec(nids[1]), width) if ntype == STATE: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN%nid), getnode(nids[0])) ts.add_state_var(nodemap[nid]) if ntype == INPUT: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN%nid), getnode(nids[0])) ts.add_input_var(nodemap[nid]) if ntype == OUTPUT: # unfortunately we need to create an extra symbol just to have the output name # we could be smarter about this, but then this parser can't be greedy original_symbol = getnode(nids[0]) output_symbol = Symbol(nids[1], original_symbol.get_type()) nodemap[nid] = EqualsOrIff(output_symbol, original_symbol) invarlist.append(nodemap[nid]) node_covered.add(nid) ts.add_output_var(output_symbol) if ntype == AND: nodemap[nid] = binary_op(BVAnd, And, getnode(nids[1]), getnode(nids[2])) if ntype == CONCAT: nodemap[nid] = BVConcat(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == XOR: nodemap[nid] = binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2])) if ntype == XNOR: nodemap[nid] = BVNot(binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2]))) if ntype == NAND: bvop = lambda x,y: BVNot(BVAnd(x, y)) bop = lambda x,y: Not(And(x, y)) nodemap[nid] = binary_op(bvop, bop, getnode(nids[1]), getnode(nids[2])) if ntype == IMPLIES: nodemap[nid] = BVOr(BVNot(getnode(nids[1])), getnode(nids[2])) if ntype == NOT: nodemap[nid] = unary_op(BVNot, Not, getnode(nids[1])) if ntype == NEG: nodemap[nid] = unary_op(BVNeg, Not, getnode(nids[1])) if ntype == UEXT: nodemap[nid] = BVZExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == SEXT: nodemap[nid] = BVSExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == OR: nodemap[nid] = binary_op(BVOr, Or, getnode(nids[1]), getnode(nids[2])) if ntype == ADD: nodemap[nid] = BVAdd(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SUB: nodemap[nid] = BVSub(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGT: nodemap[nid] = BVUGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGTE: nodemap[nid] = BVUGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULT: nodemap[nid] = BVULT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULTE: nodemap[nid] = BVULE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SGT: nodemap[nid] = BVSGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SGTE: nodemap[nid] = BVSGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLT: nodemap[nid] = BVSLT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLTE: nodemap[nid] = BVSLE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == EQ: nodemap[nid] = BVComp(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == NEQ: nodemap[nid] = BVNot(BVComp(getnode(nids[1]), getnode(nids[2]))) if ntype == MUL: nodemap[nid] = BVMul(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLICE: nodemap[nid] = BVExtract(B2BV(getnode(nids[1])), int(nids[3]), int(nids[2])) if ntype == SLL: nodemap[nid] = BVLShl(getnode(nids[1]), getnode(nids[2])) if ntype == SRA: nodemap[nid] = BVAShr(getnode(nids[1]), getnode(nids[2])) if ntype == SRL: nodemap[nid] = BVLShr(getnode(nids[1]), getnode(nids[2])) if ntype == ITE: if (get_type(getnode(nids[2])) == BOOL) or (get_type(getnode(nids[3])) == BOOL): nodemap[nid] = Ite(BV2B(getnode(nids[1])), B2BV(getnode(nids[2])), B2BV(getnode(nids[3]))) else: nodemap[nid] = Ite(BV2B(getnode(nids[1])), getnode(nids[2]), getnode(nids[3])) if ntype == NEXT: if (get_type(getnode(nids[1])) == BOOL) or (get_type(getnode(nids[2])) == BOOL): lval = TS.get_prime(getnode(nids[1])) rval = BV2B(getnode(nids[2])) else: lval = TS.get_prime(getnode(nids[1])) rval = getnode(nids[2]) nodemap[nid] = EqualsOrIff(lval, rval) ftrans.append( (lval, [(TRUE(), rval)]) ) if ntype == INIT: if (get_type(getnode(nids[1])) == BOOL) or (get_type(getnode(nids[2])) == BOOL): nodemap[nid] = EqualsOrIff(BV2B(getnode(nids[1])), BV2B(getnode(nids[2]))) else: nodemap[nid] = EqualsOrIff(getnode(nids[1]), getnode(nids[2])) initlist.append(getnode(nid)) if ntype == CONSTRAINT: nodemap[nid] = BV2B(getnode(nids[0])) invarlist.append(getnode(nid)) if ntype == BAD: nodemap[nid] = getnode(nids[0]) if ASSERTINFO in line: filename_lineno = os.path.basename(nids[3]) assert_name = 'embedded_assertion_%s'%filename_lineno description = "Embedded assertion at line {1} in {0}".format(*filename_lineno.split(COLON_REP)) else: assert_name = 'embedded_assertion_%i'%prop_count description = 'Embedded assertion number %i'%prop_count prop_count += 1 # Following problem format (name, description, strformula) invar_props.append((assert_name, description, Not(BV2B(getnode(nid))))) if nid not in nodemap: Logger.error("Unknown node type \"%s\""%ntype) # get wirename if it exists if ntype not in {STATE, INPUT, OUTPUT, BAD}: # check for wirename, if it's an integer, then it's a node ref try: a = int(nids[-1]) except: try: wire = Symbol(str(nids[-1]), getnode(nids[0])) invarlist.append(EqualsOrIff(wire, B2BV(nodemap[nid]))) ts.add_var(wire) except: pass if Logger.level(1): name = lambda x: str(nodemap[x]) if nodemap[x].is_symbol() else x uncovered = [name(x) for x in nodemap if x not in node_covered] uncovered.sort() if len(uncovered) > 0: Logger.warning("Unlinked nodes \"%s\""%",".join(uncovered)) if not self.symbolic_init: init = simplify(And(initlist)) else: init = TRUE() invar = simplify(And(invarlist)) # instead of trans, we're using the ftrans format -- see below ts.set_behavior(init, TRUE(), invar) # add ftrans for var, cond_assign_list in ftrans: ts.add_func_trans(var, cond_assign_list) hts.add_ts(ts) return (hts, invar_props, ltl_props)
def parse_string(self, strinput): hts = HTS() ts = TS() nodemap = {} node_covered = set([]) # list of tuples of var and cond_assign_list # cond_assign_list is tuples of (condition, value) # where everything is a pysmt FNode # for btor, the condition is always True ftrans = [] initlist = [] invarlist = [] invar_props = [] ltl_props = [] prop_count = 0 # clean string input, remove special characters from names for sc, rep in special_char_replacements.items(): strinput = strinput.replace(sc, rep) def getnode(nid): node_covered.add(nid) if int(nid) < 0: return Ite(BV2B(nodemap[str(-int(nid))]), BV(0, 1), BV(1, 1)) return nodemap[nid] def binary_op(bvop, bop, left, right): if (get_type(left) == BOOL) and (get_type(right) == BOOL): return bop(left, right) return bvop(B2BV(left), B2BV(right)) def unary_op(bvop, bop, left): if (get_type(left) == BOOL): return bop(left) return bvop(left) for line in strinput.split(NL): linetok = line.split() if len(linetok) == 0: continue if linetok[0] == COM: continue (nid, ntype, *nids) = linetok if ntype == SORT: (stype, *attr) = nids if stype == BITVEC: nodemap[nid] = BVType(int(attr[0])) node_covered.add(nid) if stype == ARRAY: nodemap[nid] = ArrayType(getnode(attr[0]), getnode(attr[1])) node_covered.add(nid) if ntype == WRITE: nodemap[nid] = Store(*[getnode(n) for n in nids[1:4]]) if ntype == READ: nodemap[nid] = Select(getnode(nids[1]), getnode(nids[2])) if ntype == ZERO: nodemap[nid] = BV(0, getnode(nids[0]).width) if ntype == ONE: nodemap[nid] = BV(1, getnode(nids[0]).width) if ntype == ONES: width = getnode(nids[0]).width nodemap[nid] = BV((2**width) - 1, width) if ntype == REDOR: width = get_type(getnode(nids[1])).width zeros = BV(0, width) nodemap[nid] = BVNot(BVComp(getnode(nids[1]), zeros)) if ntype == REDAND: width = get_type(getnode(nids[1])).width ones = BV((2**width) - 1, width) nodemap[nid] = BVComp(getnode(nids[1]), ones) if ntype == CONSTD: width = getnode(nids[0]).width nodemap[nid] = BV(int(nids[1]), width) if ntype == CONST: width = getnode(nids[0]).width try: nodemap[nid] = BV(bin_to_dec(nids[1]), width) except ValueError: if not all([i == 'x' or i == 'z' for i in nids[1]]): raise RuntimeError( "If not a valid number, only support " "all don't cares or high-impedance but got {}". format(nids[1])) # create a fresh variable for this non-deterministic constant nodemap[nid] = Symbol('const_' + nids[1], BVType(width)) ts.add_state_var(nodemap[nid]) Logger.warning( "Creating a fresh symbol for unsupported X/Z constant %s" % nids[1]) if ntype == STATE: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN % nid), getnode(nids[0])) ts.add_state_var(nodemap[nid]) if ntype == INPUT: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN % nid), getnode(nids[0])) ts.add_input_var(nodemap[nid]) if ntype == OUTPUT: # unfortunately we need to create an extra symbol just to have the output name # we could be smarter about this, but then this parser can't be greedy original_symbol = B2BV(getnode(nids[0])) output_symbol = Symbol(nids[1], original_symbol.get_type()) nodemap[nid] = EqualsOrIff(output_symbol, original_symbol) invarlist.append(nodemap[nid]) node_covered.add(nid) ts.add_output_var(output_symbol) if ntype == AND: nodemap[nid] = binary_op(BVAnd, And, getnode(nids[1]), getnode(nids[2])) if ntype == CONCAT: nodemap[nid] = BVConcat(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == XOR: nodemap[nid] = binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2])) if ntype == XNOR: nodemap[nid] = BVNot( binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2]))) if ntype == NAND: bvop = lambda x, y: BVNot(BVAnd(x, y)) bop = lambda x, y: Not(And(x, y)) nodemap[nid] = binary_op(bvop, bop, getnode(nids[1]), getnode(nids[2])) if ntype == IMPLIES: nodemap[nid] = BVOr(BVNot(getnode(nids[1])), getnode(nids[2])) if ntype == NOT: nodemap[nid] = unary_op(BVNot, Not, getnode(nids[1])) if ntype == NEG: nodemap[nid] = unary_op(BVNeg, Not, getnode(nids[1])) if ntype == UEXT: nodemap[nid] = BVZExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == SEXT: nodemap[nid] = BVSExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == OR: nodemap[nid] = binary_op(BVOr, Or, getnode(nids[1]), getnode(nids[2])) if ntype == ADD: nodemap[nid] = BVAdd(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SUB: nodemap[nid] = BVSub(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGT: nodemap[nid] = BVUGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGTE: nodemap[nid] = BVUGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULT: nodemap[nid] = BVULT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULTE: nodemap[nid] = BVULE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SGT: nodemap[nid] = BVSGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SGTE: nodemap[nid] = BVSGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLT: nodemap[nid] = BVSLT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLTE: nodemap[nid] = BVSLE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == EQ: nodemap[nid] = BVComp(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == NEQ: nodemap[nid] = BVNot(BVComp(getnode(nids[1]), getnode(nids[2]))) if ntype == MUL: nodemap[nid] = BVMul(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLICE: nodemap[nid] = BVExtract(B2BV(getnode(nids[1])), int(nids[3]), int(nids[2])) if ntype == SLL: nodemap[nid] = BVLShl(getnode(nids[1]), getnode(nids[2])) if ntype == SRA: nodemap[nid] = BVAShr(getnode(nids[1]), getnode(nids[2])) if ntype == SRL: nodemap[nid] = BVLShr(getnode(nids[1]), getnode(nids[2])) if ntype == ITE: if (get_type(getnode(nids[2])) == BOOL) or (get_type( getnode(nids[3])) == BOOL): nodemap[nid] = Ite(BV2B(getnode(nids[1])), B2BV(getnode(nids[2])), B2BV(getnode(nids[3]))) else: nodemap[nid] = Ite(BV2B(getnode(nids[1])), getnode(nids[2]), getnode(nids[3])) if ntype == NEXT: if (get_type(getnode(nids[1])) == BOOL) or (get_type( getnode(nids[2])) == BOOL): lval = TS.get_prime(getnode(nids[1])) rval = B2BV(getnode(nids[2])) else: lval = TS.get_prime(getnode(nids[1])) rval = getnode(nids[2]) nodemap[nid] = EqualsOrIff(lval, rval) ftrans.append((lval, [(TRUE(), rval)])) if ntype == INIT: if (get_type(getnode(nids[1])) == BOOL) or (get_type( getnode(nids[2])) == BOOL): nodemap[nid] = EqualsOrIff(BV2B(getnode(nids[1])), BV2B(getnode(nids[2]))) elif get_type(getnode(nids[1])).is_array_type(): _type = get_type(getnode(nids[1])) nodemap[nid] = EqualsOrIff( getnode(nids[1]), Array(_type.index_type, default=getnode(nids[2]))) else: nodemap[nid] = EqualsOrIff(getnode(nids[1]), getnode(nids[2])) initlist.append(getnode(nid)) if ntype == CONSTRAINT: nodemap[nid] = BV2B(getnode(nids[0])) invarlist.append(getnode(nid)) if ntype == BAD: nodemap[nid] = getnode(nids[0]) if len(nids) > 1: assert_name = nids[1] description = "Embedded assertion: {}".format(assert_name) else: assert_name = 'embedded_assertion_%i' % prop_count description = 'Embedded assertion number %i' % prop_count prop_count += 1 # Following problem format (name, description, strformula) invar_props.append( (assert_name, description, Not(BV2B(getnode(nid))))) if nid not in nodemap: Logger.error("Unknown node type \"%s\"" % ntype) # get wirename if it exists if ntype not in {STATE, INPUT, OUTPUT, BAD}: # disregard comments at the end of the line try: symbol_idx = nids.index(';') symbol_idx -= 1 # the symbol should be before the comment except: # the symbol is just the end symbol_idx = -1 # check for wirename, if it's an integer, then it's a node ref try: a = int(nids[symbol_idx]) except: try: name = str(nids[symbol_idx]) # use the exact name, unless it has already been used wire = Symbol(name, getnode(nids[0])) if wire in ts.vars: wire = FreshSymbol(getnode(nids[0]), template=name + "%d") invarlist.append(EqualsOrIff(wire, B2BV(nodemap[nid]))) ts.add_var(wire) except: pass if Logger.level(1): name = lambda x: str(nodemap[x]) if nodemap[x].is_symbol() else x uncovered = [name(x) for x in nodemap if x not in node_covered] uncovered.sort() if len(uncovered) > 0: Logger.warning("Unlinked nodes \"%s\"" % ",".join(uncovered)) if not self.symbolic_init: init = simplify(And(initlist)) else: init = TRUE() invar = simplify(And(invarlist)) # instead of trans, we're using the ftrans format -- see below ts.set_behavior(init, TRUE(), invar) # add ftrans for var, cond_assign_list in ftrans: ts.add_func_trans(var, cond_assign_list) hts.add_ts(ts) return (hts, invar_props, ltl_props)
def generate_STS(self, lines): ts = TS("Additional system") init = TRUE() trans = TRUE() invar = TRUE() states = {} assigns = set([]) varsmap = {} def def_var(name, vtype): if name in varsmap: return varsmap[name] var = Symbol(name, vtype) ts.add_state_var(var) return var for line in lines: if line.comment: continue if line.init: if T_I not in states: states[T_I] = TRUE() if line.init.varname != "": (value, typev) = self.__get_value(line.init.value) ivar = def_var(line.init.varname, typev) state = EqualsOrIff(ivar, value) else: state = TRUE() if line.init.value == T_TRUE else FALSE() states[T_I] = And(states[T_I], state) # Optimization for the initial state assignment init = And(init, state) state = TRUE() if line.state: sname = T_S + line.state.id if (line.state.varname != ""): (value, typev) = self.__get_value(line.state.value) ivar = def_var(line.state.varname, typev) state = EqualsOrIff(ivar, value) assval = (sname, line.state.varname) if assval not in assigns: assigns.add(assval) else: Logger.error( "Double assignment for variable \"%s\" at state \"%s\"" % (line.state.varname, sname)) else: state = TRUE() if line.state.value == T_TRUE else FALSE() if sname not in states: states[sname] = TRUE() states[sname] = And(states[sname], state) stateid_width = math.ceil(math.log(len(states)) / math.log(2)) stateid_var = Symbol(self.new_state_id(), BVType(stateid_width)) init = And(init, EqualsOrIff(stateid_var, BV(0, stateid_width))) invar = And( invar, Implies(EqualsOrIff(stateid_var, BV(0, stateid_width)), states[T_I])) states[T_I] = EqualsOrIff(stateid_var, BV(0, stateid_width)) count = 1 state_items = list(states.keys()) state_items.sort() for state in state_items: if state == T_I: continue invar = And( invar, Implies(EqualsOrIff(stateid_var, BV(count, stateid_width)), states[state])) states[state] = EqualsOrIff(stateid_var, BV(count, stateid_width)) count += 1 transdic = {} for line in lines: if line.comment: continue if line.trans: if states[line.trans.start] not in transdic: transdic[states[line.trans.start]] = [] transdic[states[line.trans.start]].append( states[line.trans.end]) for transition in transdic: (start, end) = (transition, transdic[transition]) trans = And(trans, Implies(start, TS.to_next(Or(end)))) vars_ = [v for v in get_free_variables(trans) if not TS.is_prime(v)] vars_ += get_free_variables(init) vars_ += get_free_variables(invar) invar = And(invar, BVULE(stateid_var, BV(count - 1, stateid_width))) ts.set_behavior(init, trans, invar) ts.add_state_var(stateid_var) hts = HTS("ETS") hts.add_ts(ts) invar_props = [] ltl_props = [] return (hts, invar_props, ltl_props)
def combine_systems(hts, hts2, k, symbolic_init, eqprop=None, inc=True, non_deterministic=False): htseq = HTS("eq") hts1_varnames = [v.symbol_name() for v in hts.vars] hts2_varnames = [v.symbol_name() for v in hts2.vars] map1 = dict([(v, TS.get_prefix_name(v, S1)) for v in hts1_varnames]+\ [(TS.get_prime_name(v), TS.get_prefix_name(TS.get_prime_name(v), S1)) for v in hts1_varnames]) map2 = dict([(v, TS.get_prefix_name(v, S2)) for v in hts2_varnames]+\ [(TS.get_prime_name(v), TS.get_prefix_name(TS.get_prime_name(v), S2)) for v in hts2_varnames]) ts1_init = TRUE() ts2_init = TRUE() if not symbolic_init: ts1_init = substitute(hts.single_init(), map1) ts2_init = substitute(hts2.single_init(), map2) ts1 = TS() ts1.vars = set([TS.get_prefix(v, S1) for v in hts.vars]) ts1.set_behavior(ts1_init,\ substitute(hts.single_trans(), map1),\ substitute(hts.single_invar(), map1)) ts1.state_vars = set([TS.get_prefix(v, S1) for v in hts.state_vars]) ts2 = TS() ts2.vars = set([TS.get_prefix(v, S2) for v in hts2.vars]) ts2.set_behavior(ts2_init,\ substitute(hts2.single_trans(), map2),\ substitute(hts2.single_invar(), map2)) ts2.state_vars = set([TS.get_prefix(v, S2) for v in hts2.state_vars]) htseq.add_ts(ts1) htseq.add_ts(ts2) assumptions = [] lemmas = [] def sets_intersect(set1, set2): for el in set1: if not el in set2: return False return True if hts.assumptions is not None: for assumption in hts.assumptions: assumptions.append(assumption) if hts.lemmas is not None: for lemma in hts.lemmas: lemmas.append(lemma) if hts2.assumptions is not None: for assumption in hts2.assumptions: assumptions.append(assumption) if hts2.lemmas is not None: for lemma in hts2.lemmas: lemmas.append(lemma) for assumption in assumptions: fv_assumption = get_free_variables(assumption) c_assumption = TRUE() if sets_intersect(fv_assumption, hts.vars): c_assumption = And(c_assumption, substitute(assumption, map1)) if sets_intersect(fv_assumption, hts2.vars): c_assumption = And(c_assumption, substitute(assumption, map2)) if c_assumption != TRUE(): htseq.add_assumption(c_assumption) for lemma in lemmas: fv_lemma = get_free_variables(lemma) c_lemma = TRUE() if sets_intersect(fv_lemma, hts.vars): c_lemma = And(c_lemma, substitute(lemma, map1)) if sets_intersect(fv_lemma, hts2.vars): c_lemma = And(c_lemma, substitute(lemma, map2)) if c_lemma != TRUE(): htseq.add_lemma(c_lemma) miter_out = Symbol(EQS, BOOL) inputs = hts.input_vars.intersection(hts2.input_vars) outputs = hts.output_vars.intersection(hts2.output_vars) htseq.input_vars = set([ TS.get_prefix(v, S1) for v in hts.input_vars ]).union(set([TS.get_prefix(v, S2) for v in hts2.input_vars])) htseq.output_vars = set([ TS.get_prefix(v, S1) for v in hts.output_vars ]).union(set([TS.get_prefix(v, S2) for v in hts2.output_vars])) if symbolic_init or (not non_deterministic): states = hts.state_vars.intersection(hts2.state_vars) else: states = [] eqinputs = TRUE() eqoutputs = TRUE() eqstates = TRUE() for inp in inputs: eqinputs = And( eqinputs, EqualsOrIff(TS.get_prefix(inp, S1), TS.get_prefix(inp, S2))) for out in outputs: eqoutputs = And( eqoutputs, EqualsOrIff(TS.get_prefix(out, S1), TS.get_prefix(out, S2))) for svar in states: eqstates = And( eqstates, EqualsOrIff(TS.get_prefix(svar, S1), TS.get_prefix(svar, S2))) if eqprop is None: if symbolic_init or (not non_deterministic): invar = And(eqinputs, Iff(miter_out, Implies(eqstates, eqoutputs))) else: invar = And(eqinputs, Iff(miter_out, eqoutputs)) Logger.log('Inferring equivalence property: {}'.format(invar), 2) else: sparser = StringParser() eqprop = sparser.parse_formulae(eqprop) if len(eqprop) > 1: Logger.error("Expecting a single equivalence property") eqprop = eqprop[0][1] invar = Iff(miter_out, eqprop) Logger.log('Using provided equivalence property: {}'.format(invar), 2) tsmo = TS() tsmo.vars = set([miter_out]) tsmo.invar = invar htseq.add_ts(tsmo) return (htseq, miter_out)
def solve_problems(self, problems_config: ProblemsManager) -> None: general_config = problems_config.general_config model_extension = general_config.model_extension assume_if_true = general_config.assume_if_true self.sparser = StringParser(general_config) self.lparser = LTLParser() self.coi = ConeOfInfluence() modifier = None if general_config.model_extension is not None: modifier = lambda hts: ModelExtension.extend( hts, ModelModifiersFactory.modifier_by_name(general_config. model_extension)) # generate main system system hts, invar_props, ltl_props = self.parse_model( general_config.model_files, problems_config.relative_path, general_config, "System 1", modifier) # Generate second models if any are necessary for problem in problems_config.problems: if problem.verification == VerificationType.EQUIVALENCE: if problem.equal_to is None: raise RuntimeError( "No second model for equivalence " "checking provided for problem {}".format( problem.name)) hts2, _, _ = self.parse_model(problem.equal_to, problems_config.relative_path, general_config, "System 2", modifier) problems_config.add_second_model(problem, hts2) # TODO : contain these types of passes in functions # they should be registered as passes if general_config.init is not None: iparser = InitParser() init_hts, inv_a, ltl_a = iparser.parse_file( general_config.init, general_config) assert inv_a is None and ltl_a is None, "Not expecting assertions from init state file" # remove old inits for ts in hts.tss: ts.init = TRUE() hts.combine(init_hts) hts.single_init(rebuild=True) # set default bit-wise initial values (0 or 1) if general_config.default_initial_value is not None: def_init_val = int(general_config.default_initial_value) try: if int(def_init_val) not in {0, 1}: raise RuntimeError except: raise RuntimeError( "Expecting 0 or 1 for default_initial_value," "but received {}".format(def_init_val)) def_init_ts = TS("Default initial values") new_init = [] initialized_vars = get_free_variables(hts.single_init()) state_vars = hts.state_vars num_def_init_vars = 0 num_state_vars = len(state_vars) const_arr_supported = True if hts.logic == L_ABV: for p in problems_config.problems: if p.solver_name not in CONST_ARRAYS_SUPPORT: const_arr_supported = False Logger.warning( "Using default_initial_value with arrays, " "but one of the selected solvers, " "{} does not support constant arrays. " "Any assumptions on initial array values will " "have to be done manually".format( problem.solver_name)) break for sv in state_vars - initialized_vars: if sv.get_type().is_bv_type(): width = sv.get_type().width if int(def_init_val) == 1: val = BV((2**width) - 1, width) else: val = BV(0, width) num_def_init_vars += 1 elif sv.get_type().is_array_type() and \ sv.get_type().elem_type.is_bv_type() and \ const_arr_supported: svtype = sv.get_type() width = svtype.elem_type.width if int(def_init_val) == 1: val = BV((2**width) - 1, width) else: val = BV(0, width) # create a constant array with a default value val = Array(svtype.index_type, val) else: continue def_init_ts.add_state_var(sv) new_init.append(EqualsOrIff(sv, val)) def_init_ts.set_behavior(simplify(And(new_init)), TRUE(), TRUE()) hts.add_ts(def_init_ts) Logger.msg( "Set {}/{} state elements to zero " "in initial state\n".format(num_def_init_vars, num_state_vars), 1) problems_config.hts = hts # TODO: Update this so that we can control whether embedded assertions are solved automatically if not general_config.skip_embedded: for invar_prop in invar_props: problems_config.add_problem( verification=VerificationType.SAFETY, name=invar_prop[0], description=invar_prop[1], properties=invar_prop[2]) self.properties.append(invar_prop[2]) for ltl_prop in ltl_props: problems_config.add_problem(verification=VerificationType.LTL, name=invar_prop[0], description=invar_prop[1], properties=invar_prop[2]) self.properties.append(ltl_prop[2]) Logger.log( "Solving with abstract_clock=%s, add_clock=%s" % (general_config.abstract_clock, general_config.add_clock), 2) # ensure the miter_out variable exists miter_out = None for problem in problems_config.problems: if problem.name is not None: Logger.log( "\n*** Analyzing problem \"%s\" ***" % (problem.name), 1) Logger.msg("Solving \"%s\" " % problem.name, 0, not (Logger.level(1))) # apply parametric behaviors (such as toggling the clock) # Note: This is supposed to be *before* creating the combined system for equivalence checking # we want this assumption to be applied to both copies of the clock problem_hts = ParametricBehavior.apply_to_problem( problems_config.hts, problem, general_config, self.model_info) if problem.verification == VerificationType.EQUIVALENCE: hts2 = problems_config.get_second_model(problem) problem_hts, miter_out = Miter.combine_systems( hts, hts2, problem.bmc_length, general_config.symbolic_init, problem.properties, True) try: # convert the formulas to PySMT FNodes # lemmas, assumptions and precondition always use the regular parser lemmas, assumptions, precondition = self.convert_formulae( [ problem.lemmas, problem.assumptions, problem.precondition ], parser=self.sparser, relative_path=problems_config.relative_path) if problem.verification != VerificationType.LTL: parser = self.sparser else: parser = self.lparser prop = None if problem.properties is not None: prop = self.convert_formula( problem.properties, relative_path=problems_config.relative_path, parser=parser) assert len(prop) == 1, "Properties should already have been split into " \ "multiple problems but found {} properties here".format(len(prop)) prop = prop[0] self.properties.append(prop) else: if problem.verification == VerificationType.SIMULATION: prop = TRUE() elif (problem.verification is not None) and (problem.verification != VerificationType.EQUIVALENCE): Logger.error( "Property not provided for problem {}".format( problem.name)) if problem.verification == VerificationType.EQUIVALENCE: assert miter_out is not None # set property to be the miter output # if user provided a different equivalence property, this has already # been incorporated in the miter_out prop = miter_out # reset the miter output miter_out = None if precondition: assert len(precondition ) == 1, "There should only be one precondition" prop = Implies(precondition[0], prop) # TODO: keep assumptions separate from the hts # IMPORTANT: CLEAR ANY PREVIOUS ASSUMPTIONS AND LEMMAS # This was previously done in __solve_problem and has been moved here # during the frontend refactor in April 2019 # this is necessary because the problem hts is just a reference to the # overall (shared) HTS problem_hts.assumptions = None problem_hts.lemmas = None # Compute the Cone Of Influence # Returns a *new* hts (not pointing to the original one anymore) if problem.coi: if Logger.level(2): timer = Logger.start_timer("COI") hts = self.coi.compute(hts, prop) if Logger.level(2): Logger.get_timer(timer) if general_config.time: timer_solve = Logger.start_timer( "Problem %s" % problem.name, False) status, trace, traces, region = self.__solve_problem( problem_hts, prop, lemmas, assumptions, problem) # set status for this problem problems_config.set_problem_status(problem, status) # TODO: Determine whether we need both trace and traces assert trace is None or traces is None, "Expecting either a trace or a list of traces" if trace is not None: problem_traces = self.__process_trace( hts, trace, general_config, problem) problems_config.set_problem_traces(problem, problem_traces) if traces is not None: traces_to_add = [] for trace in traces: problem_trace = self.__process_trace( hts, trace, general_config, problem) for pt in problem_trace: traces_to_add.append(pt) problems_config.set_problem_traces(problem, traces_to_add) if problem.verification == VerificationType.PARAMETRIC: assert region is not None problems_config.set_problem_region(problem, region) if status is not None: Logger.msg(" %s\n" % status, 0, not (Logger.level(1))) if (assume_if_true) and \ (status == VerificationStatus.TRUE) and \ (problem.assumptions == None) and \ (problem.verification == VerificationType.SAFETY): # TODO: relax the assumption on problem.assumptions # can still add it, just need to make it an implication ass_ts = TS("Previous assumption from property") if TS.has_next(prop): ass_ts.trans = prop else: ass_ts.invar = prop # add assumptions to main system problem_hts.reset_formulae() problem_hts.add_ts(ass_ts) if general_config.time: problems_config.set_problem_time( problem, Logger.get_timer(timer_solve, False)) except KeyboardInterrupt as e: Logger.msg("\b\b Skipped!\n", 0)
def parse_string(self, strinput): hts = HTS() ts = TS() nodemap = {} node_covered = set([]) translist = [] initlist = [] invarlist = [] invar_props = [] ltl_props = [] def getnode(nid): node_covered.add(nid) if int(nid) < 0: return Ite(BV2B(nodemap[str(-int(nid))]), BV(0,1), BV(1,1)) return nodemap[nid] def binary_op(bvop, bop, left, right): if (get_type(left) == BOOL) and (get_type(right) == BOOL): return bop(left, right) return bvop(B2BV(left), B2BV(right)) def unary_op(bvop, bop, left): if (get_type(left) == BOOL): return bop(left) return bvop(left) for line in strinput.split(NL): linetok = line.split() if len(linetok) == 0: continue if linetok[0] == COM: continue (nid, ntype, *nids) = linetok if ntype == SORT: (stype, *attr) = nids if stype == BITVEC: nodemap[nid] = BVType(int(attr[0])) node_covered.add(nid) if stype == ARRAY: nodemap[nid] = ArrayType(getnode(attr[0]), getnode(attr[1])) node_covered.add(nid) if ntype == WRITE: nodemap[nid] = Store(*[getnode(n) for n in nids[1:4]]) if ntype == READ: nodemap[nid] = Select(getnode(nids[1]), getnode(nids[2])) if ntype == ZERO: nodemap[nid] = BV(0, getnode(nids[0]).width) if ntype == ONE: nodemap[nid] = BV(1, getnode(nids[0]).width) if ntype == ONES: width = getnode(nids[0]).width nodemap[nid] = BV((2**width)-1, width) if ntype == REDOR: width = get_type(getnode(nids[1])).width zeros = BV(0, width) nodemap[nid] = BVNot(BVComp(getnode(nids[1]), zeros)) if ntype == REDAND: width = get_type(getnode(nids[1])).width ones = BV((2**width)-1, width) nodemap[nid] = BVComp(getnode(nids[1]), ones) if ntype == CONSTD: width = getnode(nids[0]).width nodemap[nid] = BV(int(nids[1]), width) if ntype == CONST: width = getnode(nids[0]).width nodemap[nid] = BV(bin_to_dec(nids[1]), width) if ntype == STATE: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN%nid), getnode(nids[0])) ts.add_state_var(nodemap[nid]) if ntype == INPUT: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN%nid), getnode(nids[0])) ts.add_input_var(nodemap[nid]) if ntype == OUTPUT: if len(nids) > 2: symbol = Symbol(nids[2], getnode(nids[0])) else: symbol = Symbol((SN%nid), getnode(nids[0])) nodemap[nid] = EqualsOrIff(symbol, B2BV(getnode(nids[1]))) invarlist.append(nodemap[nid]) node_covered.add(nid) ts.add_output_var(symbol) if ntype == AND: nodemap[nid] = binary_op(BVAnd, And, getnode(nids[1]), getnode(nids[2])) if ntype == CONCAT: nodemap[nid] = BVConcat(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == XOR: nodemap[nid] = binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2])) if ntype == NAND: bvop = lambda x,y: BVNot(BVAnd(x, y)) bop = lambda x,y: Not(And(x, y)) nodemap[nid] = binary_op(bvop, bop, getnode(nids[1]), getnode(nids[2])) if ntype == IMPLIES: nodemap[nid] = BVOr(BVNot(getnode(nids[1])), getnode(nids[2])) if ntype == NOT: nodemap[nid] = unary_op(BVNot, Not, getnode(nids[1])) if ntype == UEXT: nodemap[nid] = BVZExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == OR: nodemap[nid] = binary_op(BVOr, Or, getnode(nids[1]), getnode(nids[2])) if ntype == ADD: nodemap[nid] = BVAdd(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SUB: nodemap[nid] = BVSub(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGT: nodemap[nid] = BVUGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGTE: nodemap[nid] = BVUGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULT: nodemap[nid] = BVULT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULTE: nodemap[nid] = BVULE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == EQ: nodemap[nid] = BVComp(getnode(nids[1]), getnode(nids[2])) if ntype == NE: nodemap[nid] = BVNot(BVComp(getnode(nids[1]), getnode(nids[2]))) if ntype == MUL: nodemap[nid] = BVMul(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLICE: nodemap[nid] = BVExtract(B2BV(getnode(nids[1])), int(nids[3]), int(nids[2])) if ntype == SLL: nodemap[nid] = BVLShl(getnode(nids[1]), getnode(nids[2])) if ntype == SRA: nodemap[nid] = BVAShr(getnode(nids[1]), getnode(nids[2])) if ntype == SRL: nodemap[nid] = BVLShr(getnode(nids[1]), getnode(nids[2])) if ntype == ITE: if (get_type(getnode(nids[2])) == BOOL) or (get_type(getnode(nids[3])) == BOOL): nodemap[nid] = Ite(BV2B(getnode(nids[1])), BV2B(getnode(nids[2])), BV2B(getnode(nids[3]))) else: nodemap[nid] = Ite(BV2B(getnode(nids[1])), getnode(nids[2]), getnode(nids[3])) if ntype == NEXT: if (get_type(getnode(nids[1])) == BOOL) or (get_type(getnode(nids[2])) == BOOL): nodemap[nid] = EqualsOrIff(BV2B(TS.get_prime(getnode(nids[1]))), BV2B(getnode(nids[2]))) else: nodemap[nid] = EqualsOrIff(TS.get_prime(getnode(nids[1])), getnode(nids[2])) translist.append(getnode(nid)) if ntype == INIT: if (get_type(getnode(nids[1])) == BOOL) or (get_type(getnode(nids[2])) == BOOL): nodemap[nid] = EqualsOrIff(BV2B(getnode(nids[1])), BV2B(getnode(nids[2]))) else: nodemap[nid] = EqualsOrIff(getnode(nids[1]), getnode(nids[2])) initlist.append(getnode(nid)) if ntype == CONSTRAINT: nodemap[nid] = BV2B(getnode(nids[0])) invarlist.append(getnode(nid)) if ntype == BAD: nodemap[nid] = getnode(nids[0]) invar_props.append(Not(BV2B(getnode(nid)))) if nid not in nodemap: Logger.error("Unknown node type \"%s\""%ntype) if Logger.level(1): name = lambda x: str(nodemap[x]) if nodemap[x].is_symbol() else x uncovered = [name(x) for x in nodemap if x not in node_covered] uncovered.sort() if len(uncovered) > 0: Logger.warning("Unlinked nodes \"%s\""%",".join(uncovered)) if not self.symbolic_init: init = simplify(And(initlist)) else: init = TRUE() trans = simplify(And(translist)) invar = simplify(And(invarlist)) ts.set_behavior(init, trans, invar) hts.add_ts(ts) return (hts, invar_props, ltl_props)
def Mem(clk, wdata, waddr, wen, rdata, raddr): # VAR: Array BV(waddr.width) BV(wdata.width) # INIT: True (doesn't handle initial value yet) # INVAR: (rdata = Select(Array, raddr)) # do_clk = (!clk & clk') # if Modules.functional # TRANS: Array' = Ite(do_clk, Ite(wen, Store(Array, waddr, wdata), Array), Array) # else # act_trans = (Array' = Ite(wen, Store(Array, waddr, wdata), Array)) # pas_trans = (Array' = Array) # TRANS: (do_clk -> act_trans) & (!do_clk -> pas_trans) # one cycle delay on write vars_ = [clk, wdata, waddr, wen, rdata, raddr] comment = "Mem (clk, wdata, waddr, wen, rdata, raddr) = (%s, %s, %s, %s, %s, %s)" % ( tuple([str(x) for x in vars_])) Logger.log(comment, 3) init = TRUE() trans = TRUE() invar = TRUE() memname = SEP.join(rdata.symbol_name().split( SEP)[:-1]) if SEP in rdata.symbol_name() else rdata.symbol_name() arr = Symbol(memname + ".array", ArrayType(waddr.symbol_type(), wdata.symbol_type())) vars_.append(arr) if clk.symbol_type() == BOOL: clk0 = Not(clk) clk1 = clk else: clk0 = EqualsOrIff(clk, BV(0, 1)) clk1 = EqualsOrIff(clk, BV(1, 1)) if wen.symbol_type() == BOOL: wen1 = wen else: wen1 = EqualsOrIff(wen, BV(1, 1)) if Modules.abstract_clock: do_clk = TRUE() else: do_clk = And(TS.to_next(clk1), clk0) invar = EqualsOrIff(rdata, Select(arr, raddr)) if Modules.array_ite: next_arr = Ite(wen1, Store(arr, waddr, wdata), arr) else: next_arr = Store(arr, waddr, Ite(wen1, wdata, Select(arr, waddr))) if Modules.functional: trans = EqualsOrIff(TS.to_next(arr), Ite(do_clk, next_arr, arr)) else: act_trans = EqualsOrIff(TS.to_next(arr), next_arr) pas_trans = EqualsOrIff(TS.to_next(arr), arr) trans = And(Implies(do_clk, act_trans), Implies(Not(do_clk), pas_trans)) trans = simplify(trans) ts = TS(comment) ts.vars, ts.state_vars, ts.logic = set( [v for v in vars_ if v is not None]), set([arr]), L_ABV ts.set_behavior(init, trans, invar) return ts
def Reg(in_, clk, clr, rst, arst, out, initval, clk_posedge, arst_posedge): # INIT: out = initval # do_arst = Ite(arst_posedge, (!arst & arst'), (arst & !arst')) # do_clk = Ite(clk_posedge, (!clk & clk'), (clk & !clk')) # inr = Ite(clr, 0, Ite(rst, initval, in)) # if Modules.functional # TRANS: out' = Ite(do_clk, Ite(clr, 0, Ite(rst, initval, in)), Ite(rst, initval, in)) # INVAR: True # trans gives priority to clr signal over rst # else # act_trans = (out' = inr) # pas_trans = (out' = out) # TRANS: (!do_arst -> ((do_clk -> act_trans) & (!do_clk -> pas_trans))) & (do_arst -> (out' = initval)) # INVAR: True # trans gives priority to clr signal over rst vars_ = [in_, clk, clr, rst, arst, out] comment = "Reg (in, clk, clr, rst, arst, out) = (%s, %s, %s, %s, %s, %s)" % ( tuple([str(x) for x in vars_])) Logger.log(comment, 3) init = TRUE() trans = TRUE() invar = TRUE() initvar = None basename = SEP.join(out.symbol_name().split( SEP)[:-1]) if SEP in out.symbol_name() else out.symbol_name() initname = basename + SEP + INIT if initval is not None and not Modules.symbolic_init: if out.symbol_type() == BOOL: binitval = FALSE() if initval == 0 else TRUE() else: binitval = BV(initval, out.symbol_type().width) initvar = binitval else: if out.symbol_type() == BOOL: initvar = Symbol(initname, BOOL) else: initvar = Symbol(initname, BVType(out.symbol_type().width)) trans = And(trans, EqualsOrIff(initvar, TS.get_prime(initvar))) vars_.append(initvar) init = And(init, EqualsOrIff(out, initvar)) if arst_posedge is not None: arst_posedge0 = False if arst_posedge else True arst_posedge1 = True if arst_posedge else False else: arst_posedge0 = False arst_posedge1 = True if clk_posedge is not None: clk_posedge0 = False if clk_posedge else True clk_posedge1 = True if clk_posedge else False else: clk_posedge0 = False clk_posedge1 = True if clr is not None: if clr.symbol_type() == BOOL: clr0 = Not(clr) clr1 = clr else: clr0 = EqualsOrIff(clr, BV(0, 1)) clr1 = EqualsOrIff(clr, BV(1, 1)) else: clr0 = TRUE() clr1 = FALSE() if rst is not None: if rst.symbol_type() == BOOL: rst0 = Not(rst) rst1 = rst else: rst0 = EqualsOrIff(rst, BV(0, 1)) rst1 = EqualsOrIff(rst, BV(1, 1)) else: rst0 = TRUE() rst1 = FALSE() if arst is not None: if arst.symbol_type() == BOOL: arst0 = Not(arst) arst1 = arst else: arst0 = EqualsOrIff(arst, BV(0, 1)) arst1 = EqualsOrIff(arst, BV(1, 1)) else: arst0 = TRUE() arst1 = FALSE() if clk.symbol_type() == BOOL: clk0 = Not(clk) clk1 = clk else: clk0 = EqualsOrIff(clk, BV(0, 1)) clk1 = EqualsOrIff(clk, BV(1, 1)) if Modules.abstract_clock: do_clk = TRUE() else: do_clk = And(TS.to_next(clk1), clk0) if clk_posedge1 else And( TS.to_next(clk0), clk1) if out.symbol_type() == BOOL: out0 = FALSE() else: out0 = BV(0, out.symbol_type().width) inr = Ite(clr1, out0, Ite(rst1, initvar, in_)) do_arst = And(TS.to_next(arst1), arst0) if arst_posedge1 else And( TS.to_next(arst0), arst1) ndo_arst = Not(do_arst) ndo_clk = Not(do_clk) act_trans = EqualsOrIff(inr, TS.get_prime(out)) pas_trans = EqualsOrIff(out, TS.get_prime(out)) if Modules.functional: f_outr = Ite(rst1, initvar, out) f_inr = Ite(rst1, initvar, in_) f_clr_rst = Ite(clr1, out0, f_inr) trans = And( trans, EqualsOrIff(TS.get_prime(out), Ite(do_clk, f_clr_rst, f_outr))) else: trans = And(trans, And(Implies(ndo_arst, And(Implies(do_clk, act_trans), Implies(ndo_clk, pas_trans))), \ Implies(do_arst, EqualsOrIff(TS.get_prime(out), initvar)))) trans = simplify(trans) ts = TS(comment) ts.vars, ts.state_vars = set([v for v in vars_ if v is not None]), set([out]) ts.set_behavior(init, trans, invar) return ts
def parse_file(self, file_path, config, flags=None): # coreir needs a string representing the path strfile = str(file_path) self.config = config self.__reset_structures() Logger.msg("Reading CoreIR system... ", 1) top_module = self.context.load_from_file(strfile) if config.run_coreir_passes: self.run_passes() Modules.abstract_clock = self.config.abstract_clock Modules.symbolic_init = self.config.symbolic_init top_def = top_module.definition interface = list(top_module.type.items()) modules = {} sym_map = {} not_defined_mods = [] hts = HTS(top_module.name) invar_props = [] ltl_props = [] Logger.msg("Starting encoding... ", 1) count = 0 def extract_value(x, modname, inst_intr, inst_conf, inst_mod): if x in inst_intr: return self.BVVar(modname + x, inst_intr[x].size) if x in inst_conf: xval = inst_conf[x].value if type(xval) == bool: xval = 1 if xval else 0 else: if type(xval) != int: try: xval = xval.as_uint() except: xval = None return xval if inst_mod.generated: inst_args = inst_mod.generator_args if x in inst_args: return inst_args[x].value return None if Logger.level(1): timer = Logger.start_timer("IntConvertion", False) en_tprinting = False if Logger.level(2): ttimer = Logger.start_timer("Convertion", False) td_instances = top_def.instances top_def_instances = [(inst.selectpath, inst.config, inst.module) for inst in td_instances] # sorting keeps the behavior deterministic top_def_instances.sort() totalinst = len(top_def_instances) for inst in top_def_instances: if Logger.level(1): count += 1 if count % 300 == 0: dtime = Logger.get_timer(timer, False) if dtime > 2: en_tprinting = True if en_tprinting: Logger.inline( "%s" % status_bar( (float(count) / float(totalinst))), 1) timer = Logger.start_timer("IntConvertion", False) if Logger.level(2): Logger.get_timer(timer, False) ts = None (inst_name, inst_conf, inst_mod) = inst inst_type = inst_mod.name inst_intr = dict(inst_mod.type.items()) modname = (SEP.join(inst_name)) + SEP values_dic = {} for x in self.attrnames: values_dic[x] = extract_value(x, modname, inst_intr, inst_conf, inst_mod) def args(ports_list): return [values_dic[x] for x in ports_list] sym = self.__mod_to_sym(inst_type, args) if sym is not None: sym_map[sym[0].symbol_name()] = (sym[0], sym[1]) continue ts = self.__mod_to_impl(inst_type, args) if ts is not None: if flags is not None: if CoreIRModelFlags.NO_INIT in flags: ts.init = TRUE() if CoreIRModelFlags.FC_LEMMAS in flags: for v in ts.vars: v_name = v.symbol_name() if (CR in v_name) or (RCR in v_name): cons_v_name = v_name[:len( CR)] if CR in v_name else v_name[:len(RCR)] cons_v = Symbol(cons_v_name, v.symbol_type()) lemma = EqualsOrIff( cons_v, BV(values_dic[self.VALUE], cons_v.symbol_type().width)) hts.add_lemma(lemma) for v in ts.state_vars: lemma = EqualsOrIff( v, BV(values_dic[self.INIT], v.symbol_type().width)) hts.add_lemma(lemma) hts.add_ts(ts) else: if inst_type not in not_defined_mods: intface = ", ".join([ "%s" % (v) for v in values_dic if values_dic[v] is not None ]) Logger.error( "Module type \"%s\" with interface \"%s\" is not defined" % (inst_type, intface)) not_defined_mods.append(inst_type) Logger.clear_inline(1) # sorting keeps the behavior deterministic interface.sort() for var in interface: varname = SELF + SEP + var[0] bvvar = self.BVVar(varname, var[1].size) if (var[1].is_input()): hts.add_input_var(bvvar) else: hts.add_output_var(bvvar) if var[1].kind == NAMED and var[1].name == COREIR_CLK: self.clock_list.add(bvvar) if self.config.abstract_clock: self.abstract_clock_list.add( (bvvar, (BV(0, var[1].size), BV(1, var[1].size)))) else: # add state variable that stores the previous clock value # This is IMPORTANT for model checking soundness, but # it isn't obvious that this is necessary # # imagine we have an explicit clock encoding (not abstract_clock), e.g. # next(state_var) = (!clk & next(clk)) ? <state_update> : <old value> # and if we're trying to prove something using k-induction, there's a "loop free" # constraint that the state and output variables don't repeat (reach the same # state twice) in the trace # but on a negedge clock, there can be scenarios where no state or outputs # can be updated and we'll get a trivial unsat which will be interpreted as # a converged proof -- uh oh # # adding this state element just ensures that the loop free constraint won't # be violated trivially # e.g. on a neg-edge clock, this new state element will have changed # make it hidden (won't be printed) # HIDDEN_VAR is a prefix that printers check for trailing_clock_var = self.BVVar( "{}{}__prev".format(HIDDEN_VAR, varname), var[1].size) ts = TS() ts.add_state_var(trailing_clock_var) # the initial state for this trailing variable is unconstrained ts.set_behavior( TRUE(), EqualsOrIff(TS.get_prime(trailing_clock_var), bvvar), TRUE()) hts.add_ts(ts) varmap = dict([(s.symbol_name(), s) for s in hts.vars]) def split_paths(path): ret = [] for el in path: ret += el.split(CSEP) return ret def dict_select(dic, el): return dic[el] if el in dic else None eq_conns = [] eq_vars = set([]) td_connections = top_def.connections top_def_connections = [ ((conn.first.selectpath, conn.second.selectpath) if conn.first.selectpath < conn.second.selectpath else (conn.second.selectpath, conn.first.selectpath), conn) for conn in td_connections ] # sorting keeps the behavior deterministic top_def_connections.sort() for conn in top_def_connections: first_selectpath = split_paths(conn[0][0]) second_selectpath = split_paths(conn[0][1]) first = SEP.join(first_selectpath) second = SEP.join(second_selectpath) firstvar = None secondvar = None if is_number(first_selectpath[-1]): firstname = SEP.join(first_selectpath[:-1]) else: firstname = SEP.join(first_selectpath) if is_number(second_selectpath[-1]): secondname = SEP.join(second_selectpath[:-1]) else: secondname = SEP.join(second_selectpath) first = (dict_select(varmap, self.remap_or2an(firstname)), None) second = (dict_select(varmap, self.remap_or2an(secondname)), None) firstvar = first[0] secondvar = second[0] if (firstvar is None) and (self.remap_or2an(firstname) in sym_map): firstvar = sym_map[self.remap_or2an(firstname)][1] if (secondvar is None) and (self.remap_or2an(secondname) in sym_map): secondvar = sym_map[self.remap_or2an(secondname)][1] if (firstvar is None) and (secondvar is not None): Logger.error("Symbol \"%s\" is not defined" % firstname) first = (Symbol(self.remap_or2an(firstname), secondvar.symbol_type()), None) else: if firstvar.is_constant(): sel = int(first_selectpath[-1]) if (is_number( first_selectpath[-1])) else None first = (firstvar, sel) else: if (is_number(first_selectpath[-1])) and ( firstvar.symbol_type() != BOOL) and (firstvar.symbol_type().width > 1): sel = int(first_selectpath[-1]) first = (firstvar, sel) if (firstvar is not None) and (secondvar is None): Logger.error("Symbol \"%s\" is not defined" % secondname) second = (Symbol(self.remap_or2an(secondname), firstvar.symbol_type()), None) else: if secondvar.is_constant(): sel = int(second_selectpath[-1]) if (is_number( second_selectpath[-1])) else None second = (secondvar, sel) else: if (is_number(second_selectpath[-1])) and ( secondvar.symbol_type() != BOOL) and (secondvar.symbol_type().width > 1): sel = int(second_selectpath[-1]) second = (secondvar, sel) assert ((firstvar is not None) and (secondvar is not None)) eq_conns.append((first, second)) if firstvar.is_symbol(): eq_vars.add(firstvar) if secondvar.is_symbol(): eq_vars.add(secondvar) conns_len = len(eq_conns) if self.pack_connections: eq_conns = self.__pack_connections(eq_conns) if len(eq_conns) < conns_len: Logger.log("Packed %d connections" % (conns_len - len(eq_conns)), 1) eq_formula = TRUE() for eq_conn in eq_conns: (fst, snd) = eq_conn if fst[1] is None: first = fst[0] else: if len(fst) > 2: first = BVExtract(fst[0], fst[1], fst[2]) else: first = BVExtract(fst[0], fst[1], fst[1]) if snd[1] is None: second = snd[0] else: if len(snd) > 2: second = BVExtract(snd[0], snd[1], snd[2]) else: second = BVExtract(snd[0], snd[1], snd[1]) if (first.get_type() != BOOL) and (second.get_type() == BOOL): second = Ite(second, BV(1, 1), BV(0, 1)) if (first.get_type() == BOOL) and (second.get_type() != BOOL): first = Ite(first, BV(1, 1), BV(0, 1)) eq_formula = And(eq_formula, EqualsOrIff(first, second)) Logger.log(str(EqualsOrIff(first, second)), 3) ts = TS("Connections") ts.invar = eq_formula ts.vars = eq_vars hts.add_ts(ts) if self.enc_map is not None: del (self.enc_map) if Logger.level(2): Logger.get_timer(ttimer) # check that clocks were detected if there's any state if hts.state_vars: assert self.clock_list, "Expecting clocks if there are state variables" return (hts, invar_props, ltl_props)