def iterate_latches(self): for l in AIG.iterate_latches(self): if self.latch_restr is not None and\ l.lit not in self.latch_restr and\ l != self.error_fake_latch: # log.DBG_MSG("ignoring latch " + str(l.lit)) continue yield l
class Process: def __init__(self, aiger_file_name, index, data_mode=0, factor=1): self.index = index self.aig = AIG(aiger_file_name, False) # [C1,C2,D] where [C1,C2] is the exec time interval, and D relative deadline # number of modes is the size of this list #self.delays = [[5,10,15], [4,8,16]] self.delays = data[data_mode] self.delays = map(lambda tab: map(lambda x: factor * x, tab), data[data_mode]) self.lit_to_formula = dict() self._cached_transition = None def get_delays(self): return self.delays def preset1(self): # Other [C1,C2,D] values can be set here pass def set_lit2formula(self, lit, s): self.lit_to_formula[lit] = s """ Name of stripped literal which must be an input or latch """ def name_of(self, lit): assert (lit == strip_lit(lit)) (intput, latch, and_gate) = self.aig.get_lit_type(lit) # is it an input, latch, gate or constant #print >> sys.stderr, "lit", lit, (input,latch,and_gate) if latch: return "L" + self.aig.get_lit_name(lit).replace("<", "_").replace( ">", "_") elif input: # Boolean variables are encoded as 1-bit integers for now return "I" + self.aig.get_lit_name(lit).replace("<", "_").replace( ">", "_") else: raise "And gates or constant inputs have no name" def lit2formula(self, lit): if lit in self.lit_to_formula: return self.lit_to_formula[lit] # get stripped lit stripped_lit = strip_lit(lit) is_neg = lit_is_negated(lit) (input, latch, and_gate) = self.aig.get_lit_type(stripped_lit) # is it an input, latch, gate or constant if input or latch: # Boolean variables are encoded as 1-bit integers for now result = "({0})".format(self.name_of(stripped_lit)) elif and_gate: if numeric_mode: result = ("({0} * {1})".format(self.lit2formula(and_gate.rhs0), self.lit2formula( and_gate.rhs1))) else: result = ("({0} && {1})".format( self.lit2formula(and_gate.rhs0), self.lit2formula(and_gate.rhs1))) else: # 0 literal, 1 literal and errors result = "0" # this means false # cache result self.lit_to_formula[stripped_lit] = result if is_neg: if result == "0": result = "1" else: if numeric_mode: result = "(1-{0})".format(result) else: result = "!{0}".format(result) self.lit_to_formula[lit] = result return result def get_next_funcs(self): if self._cached_transition is not None: return self._cached_transition vec = dict() for x in self.aig.iterate_latches(): vec[x.lit] = self.lit2formula(x.next) self._cached_transition = vec return vec def make_template(self, nmachines): def latch_choice(name): return "state" in name or "counter" in name id = self.index latch_list = list(self.aig.iterate_latches()) latch_locations = dict() temp = Template("Process" + str(id)) # Choose here some latch which should become mode clocked_latches = filter(lambda x: latch_choice(self.name_of(x.lit)), latch_list) mode_latch = self.name_of( clocked_latches[0].lit ) # this is assumed to be non-empty of course w = Location("w", initial=True) dead = Location("dead") rel = Location("rel", committed=True) up = Location("up", committed=True) disc_up = Location("disc_up", committed=True) temp.add_locations([w, dead, rel, up]) on = [Location("on{0}".format(m)) for m in range(len(self.delays))] for m, l in enumerate(on): # delay=(c1,c2,d). invariant is that the task finishes before c2 l.set_invariant("x{0} <= {1}".format(id, self.delays[m][1])) temp.add_location(l) nmodes = len(self.delays) for m, (c1, c2, d) in enumerate(self.delays): # mg = "mode{0} == {1}".format(id, m) mg = "{0} == {1}".format(mode_latch, m) temp.add_transition( Transition(w, on[m], guard=mg, sync="go{0}?".format(id), up="x{0}:=0, w{0}:=0".format(id))) # Check deadline miss guard = "{0} && x{1} > {2}".format(mg, id, d - c2) temp.add_transition(Transition(w, dead, guard=guard)) # on -> up guard = "{0} && x{1} >= {2} && x{1} <= {3}".format( mg, id, c1, c2) tr = Transition(on[m], up, up="x{0}:=0".format(id), guard=guard) temp.add_transition(tr) last_location = up # Discrete update part decl = StringIO.StringIO() input_list = list( chain(self.aig.iterate_uncontrollable_inputs(), self.aig.iterate_controllable_inputs())) for i in input_list: print >> decl, "bool {0};".format(self.name_of(i.lit)) loc_after_i = Location("JustSet" + self.name_of(i.lit), committed=True) tr0 = Transition(last_location, loc_after_i, up="{0} := 0".format(self.name_of(i.lit))) tr1 = Transition(last_location, loc_after_i, up="{0} := 1".format(self.name_of(i.lit))) temp.add_transition(tr0) temp.add_transition(tr1) last_location = loc_after_i pass next_funcs = self.get_next_funcs() for xi, x in enumerate(latch_list): print >> decl, "bool {0};".format(self.name_of(x.lit)) latch_locations[x.lit] = Location("Updated" + self.name_of(x.lit), committed=True) up = "{0} := {1}".format(self.name_of(x.lit), next_funcs[x.lit]) temp.add_transition( Transition(last_location, latch_locations[x.lit], up=up)) last_location = latch_locations[x.lit] for j in range(nmachines): tr = Transition(last_location, w, guard="running{0} == {1}".format(j, id), sync="release{0}!".format(j), up="w{0}:=1".format(id)) temp.add_transition(tr) temp.set_declaration(decl.getvalue()) return temp
class Process: def __init__(self, aiger_file_name, index, data_mode=0, factor=1): self.index = index self.aig = AIG(aiger_file_name, False); # [C1,C2,D] where [C1,C2] is the exec time interval, and D relative deadline # number of modes is the size of this list # self.delays = [[5,10,15], [4,8,16]] self.delays = map(lambda tab: map(lambda x: factor*x, tab), data[data_mode]) self.lit_to_formula = dict() self._cached_transition = None self.input_list = list(chain(self.aig.iterate_uncontrollable_inputs(),self.aig.iterate_controllable_inputs())) self.latch_list = list(self.aig.iterate_latches()) def get_delays(self): return self.delays def preset1(self): # Other [C1,C2,D] values can be set here pass def set_lit2formula(self, lit, s): self.lit_to_formula[lit] = s """ Name of stripped literal which must be an input or latch """ def name_of(self, lit): assert(lit == strip_lit(lit)) ident = "P"+str(self.index) (intput, latch, and_gate) = self.aig.get_lit_type(lit) # is it an input, latch, gate or constant #print >> sys.stderr, "lit", lit, (input,latch,and_gate) if latch: return "L"+ident+self.aig.get_lit_name(lit).replace("<", "_").replace(">", "_"); elif input: # Boolean variables are encoded as 1-bit integers for now return "I"+ident+self.aig.get_lit_name(lit).replace("<", "_").replace(">", "_"); else: raise "And gates or constant inputs have no name" def lit2formula(self, lit): if lit in self.lit_to_formula: return self.lit_to_formula[lit] # get stripped lit stripped_lit = strip_lit(lit) is_neg = lit_is_negated(lit) (input, latch, and_gate) = self.aig.get_lit_type(stripped_lit) # is it an input, latch, gate or constant if input or latch: # Boolean variables are encoded as 1-bit integers for now result = "(_l.{0})".format(self.name_of(stripped_lit)) elif and_gate: if numeric_mode: result = ("({0} * {1})".format(self.lit2formula(and_gate.rhs0), self.lit2formula(and_gate.rhs1))) else: result = ("({0} && {1})".format(self.lit2formula(and_gate.rhs0), self.lit2formula(and_gate.rhs1))) else: # 0 literal, 1 literal and errors result = "0" # this means false # cache result self.lit_to_formula[stripped_lit] = result if is_neg: if result == "0": result = "1" else: if numeric_mode: result = "(1-{0})".format(result) else: result = "!{0}".format(result) self.lit_to_formula[lit] = result return result def get_next_funcs(self): if self._cached_transition is not None: return self._cached_transition vec = dict() for x in self.aig.iterate_latches(): vec[x.lit] = self.lit2formula(x.next) self._cached_transition = vec return vec def dump(self, nmachines): def latch_choice(name): return "state" in name or "counter" in name input_list = self.input_list latch_list = self.latch_list id = self.index latch_locations = dict() print "s.add_process(\"Process{0}\");".format(id) pr = "\"Process{0}\"".format(id) # Choose here some latch which should become mode clocked_latches = filter(lambda x: latch_choice(self.name_of(x.lit)), latch_list) mode_latch = self.name_of(clocked_latches[0].lit) # this is assumed to be non-empty of course # w = Location("w", initial=True) # dead = Location("dead", error=True) # rel = Location("rel", committed = True) # up = Location("up", committed = True) #disc_up = Location("disc_up", committed=True) print "s.add_location({0}, \"w\", \"\", \"\", syntax::loc_t::INIT);".format(pr) print "s.add_location({0}, \"dead\", \"\", \"err\");".format(pr) print "s.add_location({0}, \"rel\", \"\", \"\", syntax::loc_t::COMMITTED);".format(pr) print "s.add_location({0}, \"up\", \"\", \"\", syntax::loc_t::COMMITTED);".format(pr) print "s.add_location({0}, \"disc_up\", \"\", \"\", syntax::loc_t::COMMITTED);".format(pr) for m in range(len(self.delays)): print "s.add_location({0}, \"on{1}\", \"x{2} <= {3}\",\"\");".format(pr, m, id, self.delays[m][1]) #on = [Location("on{0}".format(m)) for m in range(len(self.delays))] #for m,l in enumerate(on): # # delay=(c1,c2,d). invariant is that the task finishes before c2 # l.set_invariant("x{0} <= {1}".format(id, self.delays[m][1])) # temp.add_location(l) nmodes = len(self.delays) for m,(c1,c2,d) in enumerate(self.delays): # mg = "mode{0} == {1}".format(id, m) mg = make_discrete_guard("_l.{0} == {1}".format(mode_latch, m)) up = make_discrete_update("_l.w{0} = 0".format(id)) # temp.add_transition(Transition(w, on[m], disc_guard=mg, sync="go{0}?".format(id), disc_up="w{0}=0;".format(id), reset="x{0}".format(id))) print "s.add_edge({0}, \"w\", \"on{1}\", \"\", \"x{2}\", \"go{2}?\", {3}, {4});".format(pr, m, id, mg, up) # Check deadline miss g="x{0} >= {1}".format(id, d - c2-1) up=make_discrete_update("_l.dead=1;") #temp.add_transition(Transition(w,dead,disc_guard=mg, disc_up="dead=1;",guard=guard)) print "s.add_edge({0}, \"w\", \"dead\", \"{1}\", \"\", \"\", {2}, {3});".format(pr, g , mg, up) # on -> up #guard = "x{1} >= {2} && x{1} <= {3}".format(mg, id, c1, c2) #tr = Transition(on[m], up, reset="x{0}".format(id), disc_guard=mg, guard=guard) #temp.add_transition(tr) guard = "x{1} >= {2} && x{1} <= {3}".format(mg, id, c1, c2) print "s.add_edge({0}, \"on{1}\", \"up\", \"{2}\", \"x{3}\", \"\", {4});".format(pr, m, guard, id, mg) last_location = "up" # Discrete update part for i in input_list: # print >> decl, "var {0} :".format(self.name_of(i.lit))+"{0..1}=0;" loc_after_i = "JustSet"+self.name_of(i.lit) print "s.add_location({0}, \"{1}\", \"\", \"\", syntax::loc_t::COMMITTED);".format(pr, loc_after_i) print "s.add_edge({0}, \"{1}\", \"{2}\", \"\", \"\", \"\", syntax::layout_true, {3});".format(pr, last_location, loc_after_i, make_discrete_update("_l.{0} = 0;".format(self.name_of(i.lit)))) print "s.add_edge({0}, \"{1}\", \"{2}\", \"\", \"\", \"\", syntax::layout_true, {3});".format(pr, last_location, loc_after_i, make_discrete_update("_l.{0} = 1;".format(self.name_of(i.lit)))) #tr0 = Transition(last_location, loc_after_i, disc_up="{0} = 0;".format(self.name_of(i.lit))) #tr1 = Transition(last_location, loc_after_i, disc_up="{0} = 1;".format(self.name_of(i.lit))) #temp.add_transition(tr0) #temp.add_transition(tr1) last_location = loc_after_i pass next_funcs = self.get_next_funcs() for xi, x in enumerate(latch_list): #print >> decl, "var {0} :".format(self.name_of(x.lit))+"{0..1}=0;" latch_locations[x.lit] = "Updated"+ self.name_of(x.lit) print "s.add_location({0}, \"{1}\", \"\", \"\", syntax::loc_t::COMMITTED);".format(pr, latch_locations[x.lit]) disc_up=make_discrete_update("_l.{0} = {1};".format(self.name_of(x.lit), next_funcs[x.lit])) #temp.add_transition(Transition(last_location, latch_locations[x.lit],disc_up=disc_up)) print "s.add_edge({0}, \"{1}\", \"{2}\", \"\", \"\", \"\", syntax::layout_true, {3});".format(pr, last_location, latch_locations[x.lit], disc_up) last_location = latch_locations[x.lit] for j in range(nmachines): up = make_discrete_update("_l.w{0} = 1;".format(id)) dg = make_discrete_guard("_l.running{0} == {1}".format(j, id)) print "s.add_edge({0}, \"{1}\", \"w\", \"\", \"\", \"release{2}!\", {3}, {4});".format(pr, last_location, j, dg, up)
class TAWRITER: def __init__(self, aiger_file_name, time_file_name, factor=1): self.aig = AIG(aiger_file_name, False) self.lit_to_formula = dict() self._cached_transition = None self.factor = factor self.delays = self._read_delays(time_file_name) def _read_delays(self, time_file_name): delays = dict() latches = [x.lit for x in self.aig.iterate_latches()] with open(time_file_name, 'r') as fp: for l in range(len(latches)): s = fp.readline() if s <> "": #print "Doing line:<{0}>".format(s) #print s.split(" ") si = map(lambda x: int(x), s.split(" ")) assert (len(si) == 2) delays[latches[l]] = (si[0] * self.factor, si[1] * self.factor) else: delays[latches[l]] = (self.factor, self.factor) log.DBG_MSG("Latch delays: " + str(delays)) return delays def set_lit2formula(self, lit, s): self.lit_to_formula[lit] = s """ Name of stripped literal which must be an input or latch """ def name_of(self, lit): assert (lit == strip_lit(lit)) (intput, latch, and_gate) = self.aig.get_lit_type(lit) # is it an input, latch, gate or constant #print >> sys.stderr, "lit", lit, (input,latch,and_gate) if latch: return "L" + self.aig.get_lit_name(lit).replace("<", "_").replace( ">", "_") elif input: # Boolean variables are encoded as 1-bit integers for now return "I" + self.aig.get_lit_name(lit).replace("<", "_").replace( ">", "_") else: raise "And gates or constant inputs have no name" def lit2formula(self, lit): if lit in self.lit_to_formula: return self.lit_to_formula[lit] # get stripped lit stripped_lit = strip_lit(lit) is_neg = lit_is_negated(lit) (input, latch, and_gate) = self.aig.get_lit_type(stripped_lit) # is it an input, latch, gate or constant if input or latch: # Boolean variables are encoded as 1-bit integers for now result = "(_l.{0})".format(self.name_of(stripped_lit)) elif and_gate: if numeric_mode: result = ("({0} * {1})".format(self.lit2formula(and_gate.rhs0), self.lit2formula( and_gate.rhs1))) else: result = ("({0} && {1})".format( self.lit2formula(and_gate.rhs0), self.lit2formula(and_gate.rhs1))) else: # 0 literal, 1 literal and errors result = "0" # this means false # cache result self.lit_to_formula[stripped_lit] = result if is_neg: if result == "0": result = "1" else: if numeric_mode: result = "(1-{0})".format(result) else: result = "!{0}".format(result) self.lit_to_formula[lit] = result return result def get_next_funcs(self): if self._cached_transition is not None: return self._cached_transition vec = dict() for x in self.aig.iterate_latches(): vec[x.lit] = self.lit2formula(x.next) self._cached_transition = vec return vec def make_discrete_guard(self, g): return """ [](syntax::layout_t const & l){{\\ monoprocess::layout_t const & _l = CAST(monoprocess::layout_t const &, l);\\ return {0};\\ }} """.format(g) def make_discrete_update(self, u): return """ [](syntax::layout_t & l){{\\ monoprocess::layout_t & _l = CAST(monoprocess::layout_t &, l);\\ {0};\\ }} """.format(u) """ Given K, make timed automaton model that restricts each cycle to K time units. """ def get_cycle_time_model(self, nb_clocked_latches, K): K = self.factor * K latch_locations = dict() # clock name associated to given lit which is a latch clock_name = dict() input_list = list( chain(self.aig.iterate_uncontrollable_inputs(), self.aig.iterate_controllable_inputs())) latch_list = list(self.aig.iterate_latches()) latch_num = len(latch_list) clocked_latches = filter(lambda x: "state" in self.name_of(x.lit), latch_list) clocked_latches = latch_list clocked_latches = clocked_latches[0:nb_clocked_latches] print """#include <iostream> #include "syntax/system.hh" #include "syntax/sync_product.hh" namespace monoprocess { class layout_t : public syntax::layout_t { public: """ for i in input_list: print "\tbool {0};".format(self.name_of(i.lit)) for x in latch_list: print "\tbool {0};".format(self.name_of(x.lit)) print "\tlayout_t(){" for i in input_list: print "\t\t{0} = 0;".format(self.name_of(i.lit)) for x in latch_list: print "\t\t{0} = 0;".format(self.name_of(x.lit)) print "\t}\nvirtual ~layout_t(){}" print "layout_t (const layout_t &l) = default;" print """ inline bool operator == (const syntax::layout_t & l) const { monoprocess::layout_t const & _l = CAST(monoprocess::layout_t const &, l); """ for i in input_list: print "\t\tif({0} != _l.{0}) return false;".format( self.name_of(i.lit)) for x in latch_list: print "\t\tif({0} != _l.{0}) return false;".format( self.name_of(x.lit)) print "return true;\n}" print """ inline size_t hash() const { size_t seed = global_t::instance().hash_seed(); """ for i in input_list + latch_list: print "\t\tboost::hash_combine(seed, {0});".format( self.name_of(i.lit)) print "return seed;\n}" print """ void output(std::ostream & os) const { """ for i in input_list + latch_list: print "\t\tos << \"{0} = \" << {0} << \",\";".format( self.name_of(i.lit)) print "\t}\n};\n}" print """void build_model(syntax::system_t & s){ \ts.name(\"Mono\"); \ts.layout_alloc< syntax::layout_T_alloc_t<monoprocess::layout_t> >(); """ for x in clocked_latches: clock_name[x.lit] = "x_" + str(x.lit) print "s.add_clock(\"{0}\");".format(clock_name[x.lit]) print "s.add_clock(\"T\");" print "s.add_label(\"err\");" print "s.add_label(\"nothing\");" print "s.add_process(\"Circuit\");" print "s.add_location(\"Circuit\", \"init\", \"\", \"\", syntax::loc_t::INIT | syntax::loc_t::URGENT);" #init = Location("Init", urgent=True,initial=True) print "s.add_location(\"Circuit\", \"dead\", \"\", \"err\");" #deadlock = Location("dead") # nta.set_query("E<>Process.dead") # for x in self.aig.iterate_latches(): last_location = "init" for i in input_list: loc_after_i = "JustSet" + self.name_of(i.lit) print "s.add_location(\"Circuit\", \"{0}\", \"\", \"\", syntax::loc_t::URGENT);".format( loc_after_i) #loc_after_i = Location("JustSet"+self.name_of(i.lit), urgent=True) #tr0 = Transition(last_location, loc_after_i, up="{0} := 0".format(self.name_of(i.lit))) print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"\", \"\", \"\", syntax::layout_true,".format( last_location, loc_after_i) print self.make_discrete_update("_l.{0}=0;".format( self.name_of(i.lit))) print ");" print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"\", \"\", \"\", syntax::layout_true,".format( last_location, loc_after_i) print self.make_discrete_update("_l.{0}=1;".format( self.name_of(i.lit))) print ");" #tr1 = Transition(last_location, loc_after_i, up="{0} := 1".format(self.name_of(i.lit))) #temp.add_transition(tr0) #temp.add_transition(tr1) last_location = loc_after_i next_funcs = self.get_next_funcs() for x in latch_list: #print >> decl, "bool {0};".format(self.name_of(x.lit)) if not x in clocked_latches: continue #latch_locations[x.lit] = Location("Updated"+ self.name_of(x.lit), urgent=True) latch_locations[x.lit] = "Updated" + self.name_of(x.lit) print "s.add_location(\"Circuit\", \"{0}\", \"\", \"\", syntax::loc_t::URGENT);".format( latch_locations[x.lit]) # if the value does not change: #g = "{0} == {1}".format(self.name_of(x.lit), next_funcs[x.lit]) #tr = Transition(last_location, latch_locations[x.lit], guard=g) #temp.add_transition(tr) disc_g = self.make_discrete_guard("_l.{0}=={1};".format( self.name_of(x.lit), next_funcs[x.lit])) print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"\", \"\", \"\", {2});".format( last_location, latch_locations[x.lit], disc_g) # if it changes but the delay is already respected, move on directly # g = "{0} == 1 && {0} != {1} && {2} >= {3}".format(self.name_of(x.lit), next_funcs[x.lit], clock_name[x.lit], self.delays[x.lit][0]) # temp.add_transition(Transition(last_location, latch_locations[x.lit], guard=g)) disc_g = self.make_discrete_guard( "_l.{0} == 1 && _l.{0} != {1}".format(self.name_of(x.lit), next_funcs[x.lit])) print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"{2} <= {3}\", \"\", \"\", {4});".format( last_location, latch_locations[x.lit], clock_name[x.lit], self.delays[x.lit][0], disc_g) disc_g = self.make_discrete_guard( "_l.{0} == 0 && _l.{0} != {1}".format(self.name_of(x.lit), next_funcs[x.lit])) print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"{2} <= {3}\", \"\", \"\", {4});".format( last_location, latch_locations[x.lit], clock_name[x.lit], self.delays[x.lit][1], disc_g) # if we have to wait to respect the delay go to specific wait state and wait precisely for the delay (matching invariant + guard) loc0 = latch_locations[x.lit] + "_becomes0" print "s.add_location(\"Circuit\", \"{0}\",\"{1}<={2}\", \"\");".format( loc0, clock_name[x.lit], self.delays[x.lit][0]) #loc0.set_invariant("{1} <= {2}".format() loc1 = latch_locations[x.lit] + "_becomes1" #loc1.set_invariant("{0} <= {1}".format(clock_name[x.lit], self.delays[x.lit][1])) print "s.add_location(\"Circuit\", \"{0}\",\"{1}<={2}\", \"\");".format( loc1, clock_name[x.lit], self.delays[x.lit][1]) # g = "{0} == 1 && {0} != {1} && {2} < {3}".format(self.name_of(x.lit), next_funcs[x.lit], clock_name[x.lit], self.delays[x.lit][0]) disc_g = self.make_discrete_guard( "_l.{0} == 1 && _l.{0} != {1}".format(self.name_of(x.lit), next_funcs[x.lit])) g = "{0} < {1}".format(clock_name[x.lit], self.delays[x.lit][0]) #tr = Transition(last_location, loc0, guard=g) #temp.add_transition(tr) if self.delays[x.lit][0] > 0: print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"{2}\", \"\", \"\", {3});".format( last_location, loc0, g, disc_g) up = self.make_discrete_update("_l.{0} = {1};".format( self.name_of(x.lit), next_funcs[x.lit])) # up="{0}:=0, {1} := {2}".format(clock_name[x.lit], self.name_of(x.lit), next_funcs[x.lit]) g = "{0} >= {1}".format(clock_name[x.lit], self.delays[x.lit][0]) #tr = Transition(loc0, latch_locations[x.lit], guard=g, up=up) #temp.add_transition(tr) print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"{2}\", \"{3}\", \"\", syntax::layout_true, {4});".format( loc0, latch_locations[x.lit], g, clock_name[x.lit], up) # g = "{0} == 0 && {0} != {1} && {2} < {3}".format(self.name_of(x.lit), next_funcs[x.lit], clock_name[x.lit], self.delays[x.lit][1]) # tr = Transition(last_location, loc1, guard=g) # temp.add_transition(tr) g = "{0} < {1}".format(clock_name[x.lit], self.delays[x.lit][1]) if self.delays[x.lit][1] > 0: disc_g = self.make_discrete_guard( "_l.{0} == 0 && _l.{0} != {1}".format( self.name_of(x.lit), next_funcs[x.lit])) print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"{2}\", \"\", \"\", {3});".format( last_location, loc1, g, disc_g) up = self.make_discrete_update("_l.{0} = {1};".format( self.name_of(x.lit), next_funcs[x.lit])) #g = "{0} >= {1}".format(clock_name[x.lit], self.delays[x.lit][1]) g = "{0} >= {1}".format(clock_name[x.lit], self.delays[x.lit][1]) print "s.add_edge(\"Circuit\", \"{0}\", \"{1}\", \"{2}\", \"{3}\", \"\", syntax::layout_true, {4});".format( loc1, latch_locations[x.lit], g, clock_name[x.lit], up) #tr = Transition(loc1, latch_locations[x.lit], guard=g, up=up) #temp.add_transition(tr) last_location = latch_locations[x.lit] #go_deadlock=Transition(last_location, deadlock, guard="T >{0}".format(str(K))) print "s.add_edge(\"Circuit\", \"{0}\", \"dead\", \"T>{1}\", \"\", \"\", syntax::layout_true);".format( last_location, str(K)) print "s.add_edge(\"Circuit\", \"{0}\", \"init\", \"T<={1}\", \"T\", \"\", syntax::layout_true);".format( last_location, str(K)) print "s.synchronizer<syntax::asynchronous_product_t>();\n}"
class TAWRITER: def __init__(self, aiger_file_name, time_file_name, factor=1): self.aig = AIG(aiger_file_name, False) self.lit_to_formula = dict() self._cached_transition = None self.factor = factor self.delays = self._read_delays(time_file_name) def _read_delays(self, time_file_name): delays = dict() latches = [x.lit for x in self.aig.iterate_latches()] with open(time_file_name, 'r') as fp: for l in range(len(latches)): s = fp.readline() if s <> "": #print "Doing line:<{0}>".format(s) #print s.split(" ") si = map(lambda x: int(x), s.split(" ")) assert (len(si) == 2) delays[latches[l]] = (si[0] * self.factor, si[1] * self.factor) else: delays[latches[l]] = (self.factor, self.factor) log.DBG_MSG("Latch delays: " + str(delays)) return delays def set_lit2formula(self, lit, s): self.lit_to_formula[lit] = s """ Name of stripped literal which must be an input or latch """ def name_of(self, lit): assert (lit == strip_lit(lit)) (intput, latch, and_gate) = self.aig.get_lit_type(lit) # is it an input, latch, gate or constant #print >> sys.stderr, "lit", lit, (input,latch,and_gate) if latch: return "L" + self.aig.get_lit_name(lit).replace( "<", "_").replace(">", "_") elif input: # Boolean variables are encoded as 1-bit integers for now return "I" + self.aig.get_lit_name(lit).replace( "<", "_").replace(">", "_") else: raise "And gates or constant inputs have no name" def lit2formula(self, lit): if lit in self.lit_to_formula: return self.lit_to_formula[lit] # get stripped lit stripped_lit = strip_lit(lit) is_neg = lit_is_negated(lit) (input, latch, and_gate) = self.aig.get_lit_type(stripped_lit) # is it an input, latch, gate or constant if input or latch: # Boolean variables are encoded as 1-bit integers for now result = "({0})".format(self.name_of(stripped_lit)) elif and_gate: if numeric_mode: result = ("({0} * {1})".format(self.lit2formula(and_gate.rhs0), self.lit2formula( and_gate.rhs1))) else: result = ("({0} && {1})".format( self.lit2formula(and_gate.rhs0), self.lit2formula(and_gate.rhs1))) else: # 0 literal, 1 literal and errors result = "0" # this means false # cache result self.lit_to_formula[stripped_lit] = result if is_neg: if result == "0": result = "1" else: if numeric_mode: result = "(1-{0})".format(result) else: result = "!{0}".format(result) self.lit_to_formula[lit] = result return result def get_next_funcs(self): if self._cached_transition is not None: return self._cached_transition vec = dict() for x in self.aig.iterate_latches(): vec[x.lit] = self.lit2formula(x.next) self._cached_transition = vec return vec """ Given K, make timed automaton model that restricts each cycle to K time units. """ def get_cycle_time_model(self, nb_clocked_latches, K): K = K * self.factor latch_locations = dict() # clock name associated to given lit which is a latch clock_name = dict() nta = NTA() temp = Template("Circuit") nta.add_template(temp) decl = StringIO.StringIO() init = Location("Init", urgent=True, initial=True) deadlock = Location("dead", error=True) latch_list = list(self.aig.iterate_latches()) latch_num = len(latch_list) clocked_latches = filter(lambda x: "state" in self.name_of(x.lit), latch_list) clocked_latches = latch_list clocked_latches = clocked_latches[0:nb_clocked_latches] clock_decl = [] print >> sys.stderr, "Clocked latches: " for x in clocked_latches: print >> sys.stderr, x.lit, " ", self.name_of( x.lit), self.delays[x.lit] clock_name[x.lit] = "x_" + str(x.lit) clock_decl.append(clock_name[x.lit]) clock_decl.append("t") temp.decl = ("clock: " + ", ".join(clock_decl) + ";") last_location = init input_list = list( chain(self.aig.iterate_uncontrollable_inputs(), self.aig.iterate_controllable_inputs())) print >> decl, "var fdead :{0..1} = 0;" for i in input_list: print >> decl, "var {0}".format(self.name_of( i.lit)), ":{0..1} = 0;" loc_after_i = Location("JustSet" + self.name_of(i.lit), urgent=True) tr0 = Transition(last_location, loc_after_i, disc_up="{0} = 0;".format(self.name_of(i.lit))) tr1 = Transition(last_location, loc_after_i, disc_up="{0} = 1;".format(self.name_of(i.lit))) temp.add_transition(tr0) temp.add_transition(tr1) last_location = loc_after_i pass next_funcs = self.get_next_funcs() for x in latch_list: print >> decl, "var {0} ".format(self.name_of( x.lit)), ":{0..1} = 0;" if not x in clocked_latches: continue latch_locations[x.lit] = Location("Updated" + self.name_of(x.lit), urgent=True) # Basically, we add the following transitions but use intermediary states # with invariants so that all transitions are urgent # updated(l_{i-1},urg) ---- f(vec(l),I) = l_i ----> updated(l_{i+1}) # updated(l_{i-1},urg) ---- f(vec(l),I) = 0 && l_i = 1, x_i >= D_i^1, l_i := 0, x_i := 0 ----> updated(l_{i},urg) # updated(l_{i-1},urg) ---- f(vec(l),I) = 0 && l_i = 1, x_i < D_i^1, l_i := 0, x_i := 0 ----> will_become1_nurg(l_{i}) # symmetrically for when the new value is 1 # will_become1_nurg(l_{i},invar:x_i<=D_i^1) ---- x_i >= D_i^0, l_i := 1, x_i := 0 ----> updated(l_{i}, urg) # if the value does not change: disc_g = "{0} == {1}".format(self.name_of(x.lit), next_funcs[x.lit]) tr = Transition(last_location, latch_locations[x.lit], disc_guard=disc_g) temp.add_transition(tr) # if it changes but the delay is already respected, move on directly disc_g = "{0} == 1 && {0} != {1}".format( self.name_of(x.lit), next_funcs[x.lit]) clock_g = "{0} >= {1}".format(clock_name[x.lit], self.delays[x.lit][0]) temp.add_transition( Transition(last_location, latch_locations[x.lit], disc_guard=disc_g, guard=clock_g)) g = "{0} == 0 && {0} != {1}".format( self.name_of(x.lit), next_funcs[x.lit]) clock_g = "{0} >= {1}".format(clock_name[x.lit], self.delays[x.lit][1]) temp.add_transition( Transition(last_location, latch_locations[x.lit], guard=clock_g, disc_guard=g)) # if we have to wait to respect the delay go to specific wait state and wait precisely for the delay (matching invariant + guard) loc0 = Location(latch_locations[x.lit].name + "_becomes0") loc0.set_invariant("{0} <= {1}".format(clock_name[x.lit], self.delays[x.lit][0])) loc1 = Location(latch_locations[x.lit].name + "_becomes1") loc1.set_invariant("{0} <= {1}".format(clock_name[x.lit], self.delays[x.lit][1])) g = "{0} == 1 && {0} != {1}".format( self.name_of(x.lit), next_funcs[x.lit]) if self.delays[x.lit][0] > 0: clock_g = "{0} <= {1}".format(clock_name[x.lit], self.delays[x.lit][0] - 1) else: clock_g = "" tr = Transition(last_location, loc0, guard=clock_g, disc_guard=g) temp.add_transition(tr) up = "{0} = {1};".format(self.name_of(x.lit), next_funcs[x.lit]) g = "{0} >= {1}".format(clock_name[x.lit], self.delays[x.lit][0]) tr = Transition(loc0, latch_locations[x.lit], guard=g, disc_up=up, reset=clock_name[x.lit]) temp.add_transition(tr) g = "{0} == 0 && {0} != {1} ".format( self.name_of(x.lit), next_funcs[x.lit]) if self.delays[x.lit][1] > 0: clock_g = "{0} <= {1}".format(clock_name[x.lit], self.delays[x.lit][1] - 1) else: clock_g = "" tr = Transition(last_location, loc1, guard=clock_g, disc_guard=g) temp.add_transition(tr) up = "{0} = {1};".format(self.name_of(x.lit), next_funcs[x.lit]) g = "{0} >= {1}".format(clock_name[x.lit], self.delays[x.lit][1]) tr = Transition(loc1, latch_locations[x.lit], guard=g, disc_up=up, reset=clock_name[x.lit]) temp.add_transition(tr) last_location = latch_locations[x.lit] pass go_deadlock = Transition(last_location, deadlock, guard="t >={0}".format(str(K + 1)), disc_up="fdead = 1;") come_back = Transition(last_location, init, guard="t <= {0}".format(str(K)), reset="t") temp.add_transition(come_back) temp.add_transition(go_deadlock) last_location = init print >> decl, "System = Circuit();" print >> decl, "#define Dead fdead==1;" print >> decl, "#assert System reaches Dead;" nta.set_declaration(decl.getvalue()) nta.dump() def test(self): vec = self.get_next_funcs() for x in vec: print >> sys.stderr, "NEXT(", x, ")" print >> sys.stderr, vec[x] print >> sys.stderr, ""