class VerilogGraphGenerator(object): def visit(self, node, parent, color='black', edge_label=None): method = 'visit_' + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) return visitor(node, parent, color=color, edge_label=edge_label) def generic_visit(self, node, parent, color='black', edge_label=None): if node is None: return for c in node.children(): self.visit(c, parent, color=color, edge_label=edge_label) def __init__(self, topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist, filename, withcolor=False): self.topmodule = topmodule self.terms = terms self.binddict = binddict self.resolved_terms = resolved_terms self.resolved_binddict = resolved_binddict self.graph = pgv.AGraph(directed=True) # pgv.AGraph(strict=False, directed=True) self.filename = filename self.withcolor = withcolor self.renamecounter = 0 self.identical = False self.treewalker = VerilogDataflowWalker(self.topmodule, self.terms, self.binddict, self.resolved_terms, self.resolved_binddict, constlist) self.optimizer = VerilogOptimizer(terms, constlist) def generate(self, signalname, identical=False, walk=True, step=1, do_reorder=False, delay=False): termname = util.toTermname(signalname) tree = self.treewalker.getTree(termname) if tree is None: raise verror.DefinitionError('No such signals: %s' % str(signalname)) if walk: tree = self.treewalker.walkTree(tree, visited=set(), step=step, delay=delay) if do_reorder: tree = reorder.reorder(tree) tree = self.optimizer.optimize(tree) if do_reorder: tree = reorder.reorder(tree) tree = replace.replaceUndefined(tree, termname) name = self.rename(signalname) self.identical = identical self.add_node(name, label=signalname) self.visit(tree, name) def draw(self, filename=None): fn = filename if fn is None: fn = self.filename self.graph.write('file.dot') self.graph.layout(prog='dot') self.graph.draw(fn) def visit_DFOperator(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) self.generic_visit(node, name, color=color, edge_label=None) def visit_DFPartselect(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) if node.var is not None: self.visit(node.var, name, color=color, edge_label='VAR') if node.msb is not None: self.visit(node.msb, name, color='orange', edge_label='MSB') if node.lsb is not None: self.visit(node.lsb, name, color='orange', edge_label='LSB') def visit_DFPointer(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) if node.var is not None: self.visit(node.var, name, color=color, edge_label='VAR') if node.ptr is not None: self.visit(node.ptr, name, color='orange', edge_label='PTR') def visit_DFConcat(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) self.generic_visit(node, name, color=color) def visit_DFBranch(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) if node.condnode is not None: self.visit(node.condnode, name, color='blue', edge_label='COND') if node.truenode is not None: self.visit(node.truenode, name, color='green', edge_label='TRUE') if node.falsenode is not None: self.visit(node.falsenode, name, color='red', edge_label='FALSE') def visit_DFTerminal(self, node, parent, color='black', edge_label=None): if self.identical: self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) else: self.add_DF(node, parent, color=color, edge_label=edge_label) def visit_DFIntConst(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFFloatConst(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFStringConst(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFEvalValue(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFUndefined(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFHighImpedance(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFDelay(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) if node.nextnode is not None: self.visit(node.nextnode, name, color=color) def add_DF(self, node, parent, color='black', edge_label=None): #name = node.__repr__() name = node.tolabel() self.add_node(name, color=color) if edge_label: self.add_edge(parent, name, color=color, label=edge_label) else: self.add_edge(parent, name, color=color) return name def add_RenamedDF(self, node, parent, color='black', edge_label=None): #mylabel = node.__repr__() mylabel = node.tolabel() name = self.rename(mylabel) self.add_node(name, label=mylabel, color=color) if edge_label: self.add_edge(parent, name, color=color, label=edge_label) else: self.add_edge(parent, name, color=color) return name def rename(self, name): ret = name + '_graphrename_' + str(self.renamecounter) self.renamecounter += 1 return ret def add_node(self, node, label=None, color='black'): if not self.withcolor: color = 'black' if label is None: self.graph.add_node(str(node), color=color) else: self.graph.add_node(str(node), label=label, color=color) def add_edge(self, start, end, color='black', label=None): if not self.withcolor: color = 'black' if label: self.graph.add_edge(str(start), str(end), color=color, label=label) else: self.graph.add_edge(str(start), str(end), color=color)
class VerilogControlflowAnalyzer(VerilogSubset): def __init__(self, topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist, fsm_vars=('fsm', 'state', 'count', 'cnt', 'step', 'mode') ): VerilogSubset.__init__(self, topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist) self.treewalker = VerilogDataflowWalker(topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist) self.fsm_vars = fsm_vars ############################################################################ def getLoops(self): fsms = self.getFiniteStateMachines() loops = {} for signame, fsm in fsms.items(): loop_set = fsm.get_loop() if len(loop_set) == 0: continue if not signame in loops: loops[signame] = set([]) loops[signame].update(loop_set) return loops, fsms def getFiniteStateMachines(self): statemachines = {} for termname, bindlist in self.resolved_binddict.items(): if not self.isFsmVar(termname): continue funcdict, delaycnt = self.getFuncdict(termname) if len(funcdict) > 0: print("FSM signal: %s, Condition list length: %d" % (str(termname), len(funcdict))) fsm = self.getFiniteStateMachine(termname, funcdict) if fsm.size() > 0: fsm.set_delaycnt(delaycnt) fsm.resolve(self.optimizer) statemachines[termname] = fsm return statemachines ############################################################################ def getFiniteStateMachine(self, termname, funcdict): fsm = FiniteStateMachine(util.toFlatname(termname)) if len(funcdict) == 0: return fsm width = self.getWidth(termname) for condlist, func in sorted(funcdict.items(), key=lambda x:len(x[0])): if not isinstance(func, DFEvalValue): continue print("Condition: %s, Inferring transition condition" % str(condlist)) node = transition.walkCondlist(condlist, termname, width) if node is None: continue statenode_list = node.nodelist if isinstance(node, transition.StateNodeList) else [node,] for statenode in statenode_list: fsm.construct(func.value, statenode) return fsm def getFuncdict(self, termname, delaycnt=0): termtype = self.getTermtype(termname) if not self.isClockEdge(termname): return {}, 0 if signaltype.isRename(termtype): return {}, 0 if signaltype.isRegArray(termtype): return {}, 0 # currently unsupported tree = self.makeTree(termname) funcdict = splitter.split(tree) funcdict = splitter.remove_reset_condition(funcdict) if len(funcdict) == 1 and len(funcdict.keys()[0]) == 0: next_term = funcdict.values()[0] if isinstance(next_term, DFTerminal): return self.getFuncdict(next_term.name, delaycnt+1) return funcdict, delaycnt def isFsmVar(self, termname): for v in self.fsm_vars: if re.search(v, str(termname).lower()): return True return False def getWidth(self, termname): term = self.getTerm(termname) msb = self.optimizer.optimizeConstant(term.msb) lsb = self.optimizer.optimizeConstant(term.lsb) width = DFIntConst('32') if msb is not None and lsb is not None: return abs(self.optimizer.optimizeConstant(DFOperator((msb, lsb), 'Minus')).value) + 1 return self.optimizer.optimizeConstant(width).value def makeTree(self, termname): tree = self.getTree(termname) tree = self.treewalker.walkTree(tree) tree = reorder.reorder(tree) tree = self.optimizer.optimize(tree) tree = replace.replaceUndefined(tree, termname) return tree
class VerilogControlflowAnalyzer(VerilogSubset): def __init__(self, topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist, fsm_vars=('fsm', 'state', 'count', 'cnt', 'step', 'mode')): VerilogSubset.__init__(self, topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist) self.treewalker = VerilogDataflowWalker(topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist) self.fsm_vars = fsm_vars def getLoops(self): fsms = self.getFiniteStateMachines() loops = {} for signame, fsm in fsms.items(): loop_set = fsm.get_loop() if len(loop_set) == 0: continue if not signame in loops: loops[signame] = set([]) loops[signame].update(loop_set) return loops, fsms def getFiniteStateMachines(self): statemachines = {} for termname, bindlist in self.resolved_binddict.items(): if not self.isFsmVar(termname): continue funcdict, delaycnt = self.getFuncdict(termname) if len(funcdict) > 0: print("FSM signal: %s, Condition list length: %d" % (str(termname), len(funcdict))) fsm = self.getFiniteStateMachine(termname, funcdict) if fsm.size() > 0: fsm.set_delaycnt(delaycnt) fsm.resolve(self.optimizer) statemachines[termname] = fsm return statemachines def getFiniteStateMachine(self, termname, funcdict): fsm = FiniteStateMachine(util.toFlatname(termname)) if len(funcdict) == 0: return fsm width = self.getWidth(termname) for condlist, func in sorted(funcdict.items(), key=lambda x: len(x[0])): if not isinstance(func, DFEvalValue): continue print("Condition: %s, Inferring transition condition" % str(condlist)) node = transition.walkCondlist(condlist, termname, width) if node is None: continue statenode_list = node.nodelist if isinstance( node, transition.StateNodeList) else [ node, ] for statenode in statenode_list: fsm.construct(func.value, statenode) return fsm def getFuncdict(self, termname, delaycnt=0): termtype = self.getTermtype(termname) if not self.isClockEdge(termname): return {}, 0 if signaltype.isRename(termtype): return {}, 0 tree = self.makeTree(termname) funcdict = splitter.split(tree) funcdict = splitter.remove_reset_condition(funcdict) if len(funcdict) == 1 and len(list(funcdict.keys())[0]) == 0: next_term = list(funcdict.values())[0] if isinstance(next_term, DFTerminal): return self.getFuncdict(next_term.name, delaycnt + 1) return funcdict, delaycnt def isFsmVar(self, termname): for v in self.fsm_vars: if re.search(v.lower(), str(termname).lower()): return True return False def getWidth(self, termname): term = self.getTerm(termname) msb = self.optimizer.optimizeConstant(term.msb) lsb = self.optimizer.optimizeConstant(term.lsb) width = DFIntConst('32') if msb is not None and lsb is not None: return abs( self.optimizer.optimizeConstant(DFOperator( (msb, lsb), 'Minus')).value) + 1 return self.optimizer.optimizeConstant(width).value def makeTree(self, termname): tree = self.getTree(termname) tree = self.treewalker.walkTree(tree) tree = reorder.reorder(tree) tree = self.optimizer.optimize(tree) tree = replace.replaceUndefined(tree, termname) return tree
class VerilogGraphGenerator(object): def visit(self, node, parent, color='black', edge_label=None): method = 'visit_' + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) return visitor(node, parent, color=color, edge_label=edge_label) def generic_visit(self, node, parent, color='black', edge_label=None): if node is None: return for c in node.children(): self.visit(c, parent, color=color, edge_label=edge_label) def __init__(self, topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist, filename, withcolor=False): self.topmodule = topmodule self.terms = terms self.binddict = binddict self.resolved_terms = resolved_terms self.resolved_binddict = resolved_binddict self.graph = pgv.AGraph(directed=True) #pgv.AGraph(strict=False, directed=True) self.filename = filename self.withcolor = withcolor self.renamecounter = 0 self.identical = False self.treewalker = VerilogDataflowWalker(self.topmodule, self.terms, self.binddict, self.resolved_terms, self.resolved_binddict, constlist) self.optimizer = VerilogOptimizer(terms, constlist) def generate(self, signalname, identical=False, walk=True, step=1, reorder=False, delay=False): termname = util.toTermname(signalname) tree = self.treewalker.getTree(termname) if tree is None: raise verror.DefinitionError('No such signals: %s' % str(signalname)) if walk: tree = self.treewalker.walkTree(tree, visited=set(), step=step, delay=delay) if reorder: tree = reorder.reorder(tree) tree = self.optimizer.optimize(tree) if reorder: tree = reorder.reorder(tree) tree = replace.replaceUndefined(tree, termname) name = self.rename(signalname) self.identical = identical self.add_node(name, label=signalname) self.visit(tree, name) def draw(self, filename=None): fn = filename if fn is None: fn = self.filename self.graph.write('file.dot') self.graph.layout(prog='dot') self.graph.draw(fn) ############################################################################ def visit_DFOperator(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) self.generic_visit(node, name, color=color, edge_label=None) def visit_DFPartselect(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) if node.var is not None: self.visit(node.var, name, color=color, edge_label='VAR') if node.msb is not None: self.visit(node.msb, name, color='orange', edge_label='MSB') if node.lsb is not None: self.visit(node.lsb, name, color='orange', edge_label='LSB') def visit_DFPointer(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) if node.var is not None: self.visit(node.var, name, color=color, edge_label='VAR') if node.ptr is not None: self.visit(node.ptr, name, color='orange', edge_label='PTR') def visit_DFConcat(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) self.generic_visit(node, name, color=color) def visit_DFBranch(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) if node.condnode is not None: self.visit(node.condnode, name, color='blue', edge_label='COND') if node.truenode is not None: self.visit(node.truenode, name, color='green', edge_label='TRUE') if node.falsenode is not None: self.visit(node.falsenode, name, color='red', edge_label='FALSE') def visit_DFTerminal(self, node, parent, color='black', edge_label=None): if self.identical: self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) else: self.add_DF(node, parent, color=color, edge_label=edge_label) def visit_DFIntConst(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFFloatConst(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFStringConst(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFEvalValue(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFUndefined(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFHighImpedance(self, node, parent, color='black', edge_label=None): self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) def visit_DFDelay(self, node, parent, color='black', edge_label=None): name = self.add_RenamedDF(node, parent, color=color, edge_label=edge_label) if node.nextnode is not None: self.visit(node.nextnode, name, color=color) ############################################################################ def add_DF(self, node, parent, color='black', edge_label=None): #name = node.__repr__() name = node.tolabel() self.add_node(name, color=color) if edge_label: self.add_edge(parent, name, color=color, label=edge_label) else: self.add_edge(parent, name, color=color) return name def add_RenamedDF(self, node, parent, color='black', edge_label=None): #mylabel = node.__repr__() mylabel = node.tolabel() name = self.rename(mylabel) self.add_node(name, label=mylabel, color=color) if edge_label: self.add_edge(parent, name, color=color, label=edge_label) else: self.add_edge(parent, name, color=color) return name ############################################################################ def rename(self, name): ret = name + '_graphrename_' + str(self.renamecounter) self.renamecounter += 1 return ret ############################################################################ def add_node(self, node, label=None, color='black'): if not self.withcolor: color='black' if label is None: self.graph.add_node(str(node), color=color) else: self.graph.add_node(str(node), label=label, color=color) def add_edge(self, start, end, color='black', label=None): if not self.withcolor: color='black' if label: self.graph.add_edge(str(start), str(end), color=color, label=label) else: self.graph.add_edge(str(start), str(end), color=color)