Пример #1
0
    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)
Пример #2
0
 def __init__(self, topmodule, terms, binddict, resolved_terms,
              resolved_binddict, constlist):
     self.topmodule = topmodule
     self.terms = terms
     self.binddict = binddict
     self.resolved_terms = resolved_terms
     self.resolved_binddict = resolved_binddict
     self.constlist = constlist
     self.optimizer = VerilogOptimizer(terms, constlist)
Пример #3
0
 def __init__(self, topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist):
     self.topmodule = topmodule
     self.terms = terms
     self.binddict = binddict
     self.resolved_terms = resolved_terms
     self.resolved_binddict = resolved_binddict
     self.constlist = constlist
     self.optimizer = VerilogOptimizer(terms, constlist)
Пример #4
0
    def __init__(self, moduleinfotable, top):
        self.moduleinfotable = moduleinfotable
        self.top = top
        self.frames = FrameTable()
        self.labels = Labels()
        self.optimizer = VerilogOptimizer({}, {})

        # set the top frame of top module
        self.stackInstanceFrame(top, top)
Пример #5
0
    def __init__(self, moduleinfotable, top):
        self.moduleinfotable = moduleinfotable
        self.top = top
        self.frames = FrameTable()
        self.labels = Labels()
        self.optimizer = VerilogOptimizer({}, {})

        # set the top frame of top module
        self.stackInstanceFrame(top, top)
Пример #6
0
    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)
Пример #7
0
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)
Пример #8
0
class VerilogDataflowMerge(object):
    def __init__(self, topmodule, terms, binddict, resolved_terms, resolved_binddict, constlist):
        self.topmodule = topmodule
        self.terms = terms
        self.binddict = binddict
        self.resolved_terms = resolved_terms
        self.resolved_binddict = resolved_binddict
        self.constlist = constlist
        self.optimizer = VerilogOptimizer(terms, constlist)

    ############################################################################
    def getTerm(self, termname):
        if not termname in self.terms: return None
        return self.terms[termname]

    def getBindlist(self, termname):
        if not termname in self.binddict: return ()
        return self.binddict[termname]

    def getResolvedTerm(self, termname):
        if not termname in self.resolved_terms: return None
        return self.resolved_terms[termname]

    def getResolvedBindlist(self, termname):
        if not termname in self.resolved_binddict: return ()
        return self.resolved_binddict[termname]

    ############################################################################
    def getTermtype(self, termname):
        term = self.getTerm(termname)
        if term is None: raise verror.DefinitionError('No such Term: %s' % termname)
        return term.termtype

    ############################################################################
    def getAssignType(self, termname, bind):
        termtype = self.getTermtype(termname)
        if signaltype.isWire(termtype):
            return 'assign'
        if signaltype.isWireArray(termtype):
            return 'assign'
        if signaltype.isReg(termtype):
            if bind.isClockEdge(): return 'clockedge'
            return 'combination'
        if signaltype.isRegArray(termtype):
            if bind.isClockEdge(): return 'clockedge'
            return 'combination'
        if signaltype.isInteger(termtype):
            if bind.isClockEdge(): return 'clockedge'
            return 'combination'
        if signaltype.isParameter(termtype):
            return 'parameter'
        if signaltype.isLocalparam(termtype):
            return 'localparam'
        if signaltype.isOutput(termtype):
            return 'assign'
        if signaltype.isInput(termtype):
            return 'assign'
        if signaltype.isFunction(termtype):
            return 'assign'
        if signaltype.isRename(termtype):
            return 'assign'
        if signaltype.isGenvar(termtype):
            return 'genvar'
        raise verror.DefinitionError('Unexpected Assignment Type: %s : %s' % (str(termname), str(termtype)))

    ############################################################################
    def isCombination(self,termname):
        bindlist = self.getBindlist(termname)
        if bindlist is None: return False
        for bind in bindlist:
            if bind.isCombination(): return True
        return False

    ############################################################################
    def getTree(self, termname, ptr=None):
        bindlist = self.getResolvedBindlist(termname)
        bindlist = self.getOptimizedBindlist(bindlist)
        if bindlist is None: return None
        if len(bindlist) == 0: return None

        termtype = self.getTermtype(termname)

        if signaltype.isRegArray(termtype) or signaltype.isWireArray(termtype):
            discretebinds = {}
            for bind in bindlist:
                if isinstance(bind.ptr, DFEvalValue):
                    ptrval = bind.ptr.value
                    if not ptrval in discretebinds: discretebinds[ptrval] = []
                    discretebinds[ptrval] += [bind]
                else:
                    if not 'any' in discretebinds: discretebinds['any'] = []
                    discretebinds['any'] += [bind]

            if 'any' in discretebinds:
                return DFTerminal(termname)

            if isinstance(ptr, DFEvalValue):
                if len(discretebinds[ptr.value]) == 0:
                    return None
                if len(discretebinds[ptr.value]) == 1:
                    return discretebinds[ptr.value][0].tree
                return self.getMergedTree(discretebinds[ptr.value])

            minptr = min(list(discretebinds.keys()))
            maxptr = max(list(discretebinds.keys()))
            ret = None
            for c in range(minptr, maxptr+1):
                truetree = None
                if len(discretebinds[c]) == 0:
                    continue
                if len(discretebinds[c]) == 1:
                    truetree = discretebinds[c][0].tree
                else:
                    truetree = self.getMergedTree(discretebinds[c])
                ret = DFBranch(DFOperator((DFEvalValue(c), ptr),'Eq'), truetree, ret)
            return ret

        if len(bindlist) == 1:
            return bindlist[0].tree
        new_tree = self.getMergedTree(bindlist)
        return self.optimizer.optimize(new_tree) 

    def getResolvedTree(self, termname, ptr=None):
        raise verror.ImplementationError()

    ############################################################################        
    def isClockEdge(self, termname, msb=None, lsb=None, ptr=None):
        bind = self.binddict[termname]
        return bind[0].isClockEdge()

    ############################################################################
    def getSources(self, tree):
        if tree is None: return set()
        if isinstance(tree, DFConstant): return set()
        if isinstance(tree, DFUndefined): return set()
        if isinstance(tree, DFEvalValue): return set()
        if isinstance(tree, DFTerminal):
            return set( [tree.name,] )
        if isinstance(tree, DFBranch):
            ret = set()
            ret |= self.getSources(tree.condnode)
            ret |= self.getSources(tree.truenode)
            ret |= self.getSources(tree.falsenode)
            return ret
        if isinstance(tree, DFOperator):
            nextnodes = []
            for n in tree.nextnodes:
                nextnodes.extend(self.getSources(n))
            return set(nextnodes)
        if isinstance(tree, DFPartselect):
            ret = set()
            ret |= self.getSources(tree.var)
            ret |= self.getSources(tree.msb)
            ret |= self.getSources(tree.lsb)
            return ret
        if isinstance(tree, DFPointer):
            ret = set()
            ret |= self.getSources(tree.var)
            ret |= self.getSources(tree.ptr)
            return ret
        if isinstance(tree, DFConcat):
            nextnodes = []
            for n in tree.nextnodes:
                nextnodes.extend(self.getSources(n))
            return set(nextnodes)
        if isinstance(tree, DFDelay):
            ret = set()
            ret |= self.getSources(tree.nextnode)
            return ret
        raise verror.DefinitionError('Undefined Node Type: %s : %s' % (str(type(tree)), str(tree)))

    ################################################################################
    def getBindSources(self, termname):
        sources = set()
        sources |= self.getTermSources(termname)
        sources |= self.getBindinfoSources(termname)
        return sources

    ################################################################################
    def getTermSources(self, termname):
        term = self.getTerm(termname)
        if term is None: return set()
        sources = set()
        sources |= self.getTreeSources(term.msb)
        sources |= self.getTreeSources(term.lsb)
        sources |= self.getTreeSources(term.lenmsb)
        sources |= self.getTreeSources(term.lenlsb)
        return sources
 
    def getBindinfoSources(self, termname):
        bindlist = self.getBindlist(termname)
        sources = set()
        for bind in bindlist:
            sources |= self.getTreeSources(bind.msb)
            sources |= self.getTreeSources(bind.lsb)
            sources |= self.getTreeSources(bind.ptr)
            sources |= self.getTreeSources(bind.tree)
        return sources

    def getTreeSources(self, tree):
        if tree is None: return set()
        if isinstance(tree, DFConstant): return set()
        if isinstance(tree, DFUndefined): return set()
        if isinstance(tree, DFEvalValue): return set()
        if isinstance(tree, DFTerminal):
            return set( [tree.name,] )
        if isinstance(tree, DFBranch):
            ret = set()
            ret |= self.getTreeSources(tree.condnode)
            ret |= self.getTreeSources(tree.truenode)
            ret |= self.getTreeSources(tree.falsenode)
            return ret
        if isinstance(tree, DFOperator):
            ret = set()
            for n in tree.nextnodes:
                ret |= self.getTreeSources(n)
            return ret
        if isinstance(tree, DFPartselect):
            ret = set()
            ret |= self.getTreeSources(tree.var)
            ret |= self.getTreeSources(tree.msb)
            ret |= self.getTreeSources(tree.lsb)
            return ret
        if isinstance(tree, DFPointer):
            ret = set()
            ret |= self.getTreeSources(tree.var)
            ret |= self.getTreeSources(tree.ptr)
            return ret
        if isinstance(tree, DFConcat):
            ret = set()
            for n in tree.nextnodes:
                ret |= self.getTreeSources(n)
            return ret
        raise verror.DefinitionError('Undefined Node Type: %s : %s' % (str(type(tree)), str(tree)))

    ################################################################################
    def getMergedTree(self, optimized_bindlist):
        concatlist = []
        last_msb = -1
        last_ptr = -1
        def bindkey(x):
            lsb = 0 if x.lsb is None else x.lsb.value
            ptr = 0 if not isinstance(x.ptr, DFEvalValue) else x.ptr.value
            term = self.getTerm(x.dest)
            length = abs(self.optimizer.optimize(term.msb).value - self.optimizer.optimize(term.lsb).value) + 1
            return ptr * length + lsb
        for bind in sorted(optimized_bindlist, key=bindkey):
            lsb = 0 if bind.lsb is None else bind.lsb.value
            if last_ptr != (-1 if not isinstance(bind.ptr, DFEvalValue) else bind.ptr.value):
                continue
            if last_msb + 1 < lsb:
                concatlist.append(DFUndefined(last_msb-lsb-1))
            concatlist.append(bind.tree)
            last_msb = -1 if bind.msb is None else bind.msb.value
            last_ptr = -1 if not isinstance(bind.ptr, DFEvalValue) else bind.ptr.value
        return DFConcat(tuple(reversed(concatlist)))

    ################################################################################
    def getOptimizedBindlist(self, bindlist):
        if len(bindlist) == 0: return ()
        new_bindlist = []
        for bind in bindlist:
            tree = self.optimizer.optimize(bind.tree)
            msb = self.optimizer.optimize(bind.msb)
            lsb = self.optimizer.optimize(bind.lsb)
            ptr = self.optimizer.optimize(bind.ptr)
            new_bind = copy.deepcopy(bind)
            new_bind.tree = tree
            new_bind.msb = msb
            new_bind.lsb = lsb
            new_bind.ptr = ptr
            new_bindlist.append(new_bind)
        if len(new_bindlist) == 1: return (new_bindlist[0],)
        split_positions = self.splitPositions(tuple(new_bindlist))
        new_bindlist = self.splitBindlist(tuple(new_bindlist), split_positions)
        return self.mergeBindlist(tuple(new_bindlist))

    def mergeBindlist(self, bindlist):
        merged_bindlist = []
        last_bind = None

        def bindkey(x):
            lsb = 0 if x.lsb is None else x.lsb.value
            ptr = 0 if not isinstance(x.ptr, DFEvalValue) else x.ptr.value
            term = self.getTerm(x.dest)
            length = abs(self.optimizer.optimize(term.msb).value - self.optimizer.optimize(term.lsb).value) + 1
            return ptr * length + lsb

        for bind in sorted(bindlist, key=bindkey):
            if last_bind is None:
                merged_bindlist.append(copy.deepcopy(bind))
                last_bind = copy.deepcopy(bind)
            elif isinstance(last_bind.ptr, DFEvalValue) and isinstance(bind.ptr, DFEvalValue) and last_bind.ptr.value != bind.ptr.value:
                merged_bindlist.append(copy.deepcopy(bind))
                last_bind = copy.deepcopy(bind)
            elif last_bind.lsb is None or bind.lsb is None or last_bind is None or bind.msb is None:
                merged_bindlist.append(copy.deepcopy(bind))
                last_bind = copy.deepcopy(bind)
            elif last_bind.lsb.value == bind.lsb.value and last_bind.msb.value == bind.msb.value:
                new_tree = self.mergeTree(last_bind.tree, bind.tree)
                new_tree = self.optimizer.optimize(new_tree)
                merged_bindlist.pop()
                new_bind = copy.deepcopy(bind)
                new_bind.tree = new_tree
                merged_bindlist.append(new_bind)
                last_bind = copy.deepcopy(new_bind)
            else:
                merged_bindlist.append(copy.deepcopy(bind))
                last_bind = copy.deepcopy(bind)
        return tuple(merged_bindlist)

    def mergeTree(self, first, second):
        if isinstance(first, DFBranch) and isinstance(second, DFBranch):
            cond_fst = self.optimizer.optimize(first.condnode)
            cond_snd = self.optimizer.optimize(second.condnode)
            if cond_fst == cond_snd:
                return DFBranch(cond_fst, self.mergeTree(first.truenode, second.truenode), self.mergeTree(first.falsenode, second.falsenode))
            appended = copy.deepcopy(first)
            return DFBranch(cond_snd, self.appendTail(appended, second.truenode), self.appendTail(appended, second.falsenode))

        if first is not None and second is None:
            return first
        if first is None and second is not None:
            return second

        if isinstance(first, DFBranch) and second is None:
            return first
        if first is None and isinstance(second, DFBranch):
            return second

        if isinstance(first, DFBranch) and not isinstance(second, DFBranch):
            cond_fst = self.optimizer.optimize(first.condnode)
            appended = copy.deepcopy(second)
            return DFBranch(cond_fst, self.appendTail(appended, first.truenode), self.appendTail(appended, first.falsenode))
        if not isinstance(first, DFBranch) and isinstance(second, DFBranch):
            cond_snd = self.optimizer.optimize(second.condnode)
            appended = copy.deepcopy(first)
            return DFBranch(cond_snd, self.appendTail(appended, second.truenode), self.appendTail(appended, second.falsenode))

        if not isinstance(first, DFBranch) and not isinstance(second, DFBranch):
            return second

        raise verror.FormatError('Can not merge trees.')

    def appendTail(self, appended, target):
        if target is None:
            return copy.deepcopy(appended)
        if isinstance(target, DFBranch):
            return DFBranch(target.condnode, self.appendTail(appended, target.truenode), self.appendTail(appended, target.falsenode))
        return target

    def splitBindlist(self, bindlist, split_positions):
        if len(bindlist) == 0: return ()
        return self.splitBindPositions(bindlist[0], split_positions) + self.splitBindlist(bindlist[1:], split_positions)

    def splitBindPositions(self, bind, split_positions):
        if len(split_positions) == 0: return (copy.deepcopy(bind),)
        if bind is None: return (copy.deepcopy(bind),)
        bind_left, bind_right = self.splitBind(bind, split_positions[0])
        ret = () if bind_right is None else (bind_right,)
        return ret + self.splitBindPositions(bind_left, split_positions[1:])

    def splitBind(self, bind, splitpos):
        tree = bind.tree
        msb = self.optimizer.optimizeConstant(bind.msb)
        lsb = self.optimizer.optimizeConstant(bind.lsb)
        ptr = self.optimizer.optimizeConstant(bind.ptr)
        if ptr is not None and msb is None or lsb is None:
            termtype = self.getTermtype(bind.dest)
            if signaltype.isRegArray(termtype) or signaltype.isWireArray(termtype):
                msb = self.optimizer.optimizeConstant(copy.deepcopy(term.msb))
                lsb = self.optimizer.optimizeConstant(copy.deepcopy(term.lsb))
            else:
                msb = copy.deepcopy(ptr)
                lsb = copy.deepcopy(ptr)
        if ptr is None and msb is None or lsb is None:
            term = self.getTerm(bind.dest)
            msb = self.optimizer.optimizeConstant(copy.deepcopy(term.msb))
            lsb = self.optimizer.optimizeConstant(copy.deepcopy(term.lsb))
        if splitpos > lsb.value and splitpos <= msb.value: # split
            right_lsb = lsb.value
            right_msb = splitpos - 1
            right_width = splitpos - lsb.value
            left_lsb = splitpos
            left_msb = msb.value
            left_width = msb.value - splitpos + 1
            right_tree = reorder.reorder(DFPartselect(copy.deepcopy(tree), DFEvalValue(right_width-1), DFEvalValue(0)))
            left_tree = reorder.reorder(DFPartselect(copy.deepcopy(tree), DFEvalValue(msb.value), DFEvalValue(msb.value-left_width+1)))
            right_tree = self.optimizer.optimize(right_tree)
            left_tree = self.optimizer.optimize(left_tree)
            left_bind = copy.deepcopy(bind)
            left_bind.tree = left_tree
            left_bind.msb = DFEvalValue(left_msb)
            left_bind.lsb = DFEvalValue(left_lsb)
            right_bind = copy.deepcopy(bind)
            right_bind.tree = right_tree
            right_bind.msb = DFEvalValue(right_msb)
            right_bind.lsb = DFEvalValue(right_lsb)
            return left_bind, right_bind
        return bind, None

    def splitPositions(self, bindlist):
        split_positions = set([])
        assigned_range = [] # (msb, lsb, ptr)

        for bind in bindlist:
            ptr = self.optimizer.optimizeConstant(bind.ptr)
            msb = self.optimizer.optimizeConstant(bind.msb)
            lsb = self.optimizer.optimizeConstant(bind.lsb)
            if msb is None and lsb is None: 
                term = self.getTerm(bind.dest)
                msb = self.optimizer.optimizeConstant(term.msb)
                lsb = self.optimizer.optimizeConstant(term.lsb)
            elif not isinstance(msb, DFEvalValue) or not isinstance(lsb, DFEvalValue):
                raise FormatError('MSB and LSB should be constant.')
            
            if ptr is None or isinstance(ptr, DFEvalValue):
                ptrval = None if ptr is None else ptr.value
                matched_range = self.matchedRange(tuple(assigned_range), msb.value, lsb.value, ptrval)
                unmatched_range = self.unmatchedRange(tuple(matched_range), msb.value, lsb.value, ptrval)
                split_positions |= self.getPositionsFromRange(matched_range, ptrval)
                assigned_range += matched_range + unmatched_range

        return tuple(sorted(list(split_positions)))
    
    def getPositionsFromRange(self, matched_range, search_ptr):
        positions = set([])
        for msb, lsb, ptr in matched_range:
            if search_ptr is not None and search != ptr: continue
            positions.add(lsb)
            positions.add(msb+1)
        return positions

    def matchedRange(self, assigned_range, search_msb, search_lsb, search_ptr):
        matched_range = []
        for msb, lsb, ptr in assigned_range:
            match = False
            if search_ptr is not None and ptr != search_ptr: continue
            if lsb <= search_lsb and search_lsb <= msb:
                match = True
                match_lsb = search_lsb
            else:
                match_lsb = lsb
            if lsb <= search_msb and search_msb <= msb:
                match = True
                match_msb = search_msb
            else:
                match_msb = msb
            if match:
                matched_range.append( (match_msb, match_lsb, search_ptr) )
        return tuple(matched_range)

    def unmatchedRange(self, matched_range, search_msb, search_lsb, search_ptr):
        unmatched_range = []
        minval = None
        maxval = None
        last_msb = None
        for msb, lsb, ptr in sorted(matched_range, key=lambda x:x[0]):
            if search_ptr is not None and ptr != search_ptr: continue
            if minval is None or lsb < minval: minval = lsb
            if maxval is None or msb > maxval: maxval = msb
            if last_msb is not None and last_msb + 1 > lsb:
                unmatched_range.append( (last_msb + 1, lsb - 1, ptr) )
            last_msb = msb
        if minval is None and maxval is None: return ( (search_msb, search_lsb, search_ptr), )
        if search_lsb < minval: unmatched_range.append( (search_lsb, minval - 1, search_ptr) )
        if maxval < search_msb: unmatched_range.append( (maxval + 1, search_msb, search_ptr) )
        return tuple(unmatched_range)
Пример #9
0
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)
Пример #10
0
class VerilogDataflowMerge(object):
    def __init__(self, topmodule, terms, binddict, resolved_terms,
                 resolved_binddict, constlist):
        self.topmodule = topmodule
        self.terms = terms
        self.binddict = binddict
        self.resolved_terms = resolved_terms
        self.resolved_binddict = resolved_binddict
        self.constlist = constlist
        self.optimizer = VerilogOptimizer(terms, constlist)

    ############################################################################
    def getTerm(self, termname):
        if isinstance(termname, str):
            for scope in self.terms.keys():
                if termname == str(scope): return self.terms[scope]
        if not termname in self.terms: return None
        return self.terms[termname]

    def getBindlist(self, termname):
        if not termname in self.binddict: return ()
        return self.binddict[termname]

    def getResolvedTerm(self, termname):
        if not termname in self.resolved_terms: return None
        return self.resolved_terms[termname]

    def getResolvedBindlist(self, termname):
        if not termname in self.resolved_binddict: return ()
        return self.resolved_binddict[termname]

    ############################################################################
    def getTermtype(self, termname):
        term = self.getTerm(termname)
        if term is None:
            raise verror.DefinitionError('No such Term: %s' % termname)
        return term.termtype

    ############################################################################
    def getAssignType(self, termname, bind):
        termtype = self.getTermtype(termname)
        if signaltype.isWire(termtype):
            return 'assign'
        if signaltype.isWireArray(termtype):
            return 'assign'
        if signaltype.isReg(termtype):
            if bind.isClockEdge(): return 'clockedge'
            return 'combination'
        if signaltype.isRegArray(termtype):
            if bind.isClockEdge(): return 'clockedge'
            return 'combination'
        if signaltype.isInteger(termtype):
            if bind.isClockEdge(): return 'clockedge'
            return 'combination'
        if signaltype.isParameter(termtype):
            return 'parameter'
        if signaltype.isLocalparam(termtype):
            return 'localparam'
        if signaltype.isOutput(termtype):
            return 'assign'
        if signaltype.isInput(termtype):
            return 'assign'
        if signaltype.isFunction(termtype):
            return 'assign'
        if signaltype.isRename(termtype):
            return 'assign'
        if signaltype.isGenvar(termtype):
            return 'genvar'
        raise verror.DefinitionError('Unexpected Assignment Type: %s : %s' %
                                     (str(termname), str(termtype)))

    ############################################################################
    def isCombination(self, termname):
        bindlist = self.getBindlist(termname)
        if bindlist is None: return False
        for bind in bindlist:
            if bind.isCombination(): return True
        return False

    ############################################################################
    def getTree(self, termname, ptr=None):
        bindlist = self.getResolvedBindlist(termname)
        bindlist = self.getOptimizedBindlist(bindlist)
        if bindlist is None: return None
        if len(bindlist) == 0: return None

        termtype = self.getTermtype(termname)

        if signaltype.isRegArray(termtype) or signaltype.isWireArray(termtype):
            discretebinds = {}
            for bind in bindlist:
                if isinstance(bind.ptr, DFEvalValue):
                    ptrval = bind.ptr.value
                    if not ptrval in discretebinds: discretebinds[ptrval] = []
                    discretebinds[ptrval] += [bind]
                else:
                    if not 'any' in discretebinds: discretebinds['any'] = []
                    discretebinds['any'] += [bind]

            if 'any' in discretebinds:
                return DFTerminal(termname)

            if isinstance(ptr, DFEvalValue):
                if len(discretebinds[ptr.value]) == 0:
                    return None
                if len(discretebinds[ptr.value]) == 1:
                    return discretebinds[ptr.value][0].tree
                return self.getMergedTree(discretebinds[ptr.value])

            minptr = min(list(discretebinds.keys()))
            maxptr = max(list(discretebinds.keys()))
            ret = None
            for c in range(minptr, maxptr + 1):
                truetree = None
                if len(discretebinds[c]) == 0:
                    continue
                if len(discretebinds[c]) == 1:
                    truetree = discretebinds[c][0].tree
                else:
                    truetree = self.getMergedTree(discretebinds[c])
                ret = DFBranch(DFOperator((DFEvalValue(c), ptr), 'Eq'),
                               truetree, ret)
            return ret

        if len(bindlist) == 1:
            return bindlist[0].tree
        new_tree = self.getMergedTree(bindlist)
        return self.optimizer.optimize(new_tree)

    def getResolvedTree(self, termname, ptr=None):
        raise verror.ImplementationError()

    ############################################################################
    def isClockEdge(self, termname, msb=None, lsb=None, ptr=None):
        bind = self.binddict[termname]
        return bind[0].isClockEdge()

    ############################################################################
    def getSources(self, tree):
        if tree is None: return set()
        if isinstance(tree, DFConstant): return set()
        if isinstance(tree, DFUndefined): return set()
        if isinstance(tree, DFEvalValue): return set()
        if isinstance(tree, DFTerminal):
            return set([
                tree.name,
            ])
        if isinstance(tree, DFBranch):
            ret = set()
            ret |= self.getSources(tree.condnode)
            ret |= self.getSources(tree.truenode)
            ret |= self.getSources(tree.falsenode)
            return ret
        if isinstance(tree, DFOperator):
            nextnodes = []
            for n in tree.nextnodes:
                nextnodes.extend(self.getSources(n))
            return set(nextnodes)
        if isinstance(tree, DFPartselect):
            ret = set()
            ret |= self.getSources(tree.var)
            ret |= self.getSources(tree.msb)
            ret |= self.getSources(tree.lsb)
            return ret
        if isinstance(tree, DFPointer):
            ret = set()
            ret |= self.getSources(tree.var)
            ret |= self.getSources(tree.ptr)
            return ret
        if isinstance(tree, DFConcat):
            nextnodes = []
            for n in tree.nextnodes:
                nextnodes.extend(self.getSources(n))
            return set(nextnodes)
        if isinstance(tree, DFDelay):
            ret = set()
            ret |= self.getSources(tree.nextnode)
            return ret
        raise verror.DefinitionError('Undefined Node Type: %s : %s' %
                                     (str(type(tree)), str(tree)))

    ################################################################################
    def getBindSources(self, termname):
        sources = set()
        sources |= self.getTermSources(termname)
        sources |= self.getBindinfoSources(termname)
        return sources

    ################################################################################
    def getTermSources(self, termname):
        term = self.getTerm(termname)
        if term is None: return set()
        sources = set()
        sources |= self.getTreeSources(term.msb)
        sources |= self.getTreeSources(term.lsb)
        sources |= self.getTreeSources(term.lenmsb)
        sources |= self.getTreeSources(term.lenlsb)
        return sources

    def getBindinfoSources(self, termname):
        bindlist = self.getBindlist(termname)
        sources = set()
        for bind in bindlist:
            sources |= self.getTreeSources(bind.msb)
            sources |= self.getTreeSources(bind.lsb)
            sources |= self.getTreeSources(bind.ptr)
            sources |= self.getTreeSources(bind.tree)
        return sources

    def getTreeSources(self, tree):
        if tree is None: return set()
        if isinstance(tree, DFConstant): return set()
        if isinstance(tree, DFUndefined): return set()
        if isinstance(tree, DFEvalValue): return set()
        if isinstance(tree, DFTerminal):
            return set([
                tree.name,
            ])
        if isinstance(tree, DFBranch):
            ret = set()
            ret |= self.getTreeSources(tree.condnode)
            ret |= self.getTreeSources(tree.truenode)
            ret |= self.getTreeSources(tree.falsenode)
            return ret
        if isinstance(tree, DFOperator):
            ret = set()
            for n in tree.nextnodes:
                ret |= self.getTreeSources(n)
            return ret
        if isinstance(tree, DFPartselect):
            ret = set()
            ret |= self.getTreeSources(tree.var)
            ret |= self.getTreeSources(tree.msb)
            ret |= self.getTreeSources(tree.lsb)
            return ret
        if isinstance(tree, DFPointer):
            ret = set()
            ret |= self.getTreeSources(tree.var)
            ret |= self.getTreeSources(tree.ptr)
            return ret
        if isinstance(tree, DFConcat):
            ret = set()
            for n in tree.nextnodes:
                ret |= self.getTreeSources(n)
            return ret
        raise verror.DefinitionError('Undefined Node Type: %s : %s' %
                                     (str(type(tree)), str(tree)))

    ################################################################################
    def getMergedTree(self, optimized_bindlist):
        concatlist = []
        last_msb = -1
        last_ptr = -1

        def bindkey(x):
            lsb = 0 if x.lsb is None else x.lsb.value
            ptr = 0 if not isinstance(x.ptr, DFEvalValue) else x.ptr.value
            term = self.getTerm(x.dest)
            length = abs(
                self.optimizer.optimize(term.msb).value -
                self.optimizer.optimize(term.lsb).value) + 1
            return ptr * length + lsb

        for bind in sorted(optimized_bindlist, key=bindkey):
            lsb = 0 if bind.lsb is None else bind.lsb.value
            if last_ptr != (-1 if not isinstance(bind.ptr, DFEvalValue) else
                            bind.ptr.value):
                continue
            if last_msb + 1 < lsb:
                concatlist.append(DFUndefined(last_msb - lsb - 1))
            concatlist.append(bind.tree)
            last_msb = -1 if bind.msb is None else bind.msb.value
            last_ptr = -1 if not isinstance(bind.ptr,
                                            DFEvalValue) else bind.ptr.value
        return DFConcat(tuple(reversed(concatlist)))

    ################################################################################
    def getOptimizedBindlist(self, bindlist):
        if len(bindlist) == 0: return ()
        new_bindlist = []
        for bind in bindlist:
            tree = self.optimizer.optimize(bind.tree)
            msb = self.optimizer.optimize(bind.msb)
            lsb = self.optimizer.optimize(bind.lsb)
            ptr = self.optimizer.optimize(bind.ptr)
            new_bind = copy.deepcopy(bind)
            new_bind.tree = tree
            new_bind.msb = msb
            new_bind.lsb = lsb
            new_bind.ptr = ptr
            new_bindlist.append(new_bind)
        if len(new_bindlist) == 1: return (new_bindlist[0], )
        split_positions = self.splitPositions(tuple(new_bindlist))
        new_bindlist = self.splitBindlist(tuple(new_bindlist), split_positions)
        return self.mergeBindlist(tuple(new_bindlist))

    def mergeBindlist(self, bindlist):
        merged_bindlist = []
        last_bind = None

        def bindkey(x):
            lsb = 0 if x.lsb is None else x.lsb.value
            ptr = 0 if not isinstance(x.ptr, DFEvalValue) else x.ptr.value
            term = self.getTerm(x.dest)
            length = abs(
                self.optimizer.optimize(term.msb).value -
                self.optimizer.optimize(term.lsb).value) + 1
            return ptr * length + lsb

        for bind in sorted(bindlist, key=bindkey):
            if last_bind is None:
                merged_bindlist.append(copy.deepcopy(bind))
                last_bind = copy.deepcopy(bind)
            elif isinstance(last_bind.ptr, DFEvalValue) and isinstance(
                    bind.ptr,
                    DFEvalValue) and last_bind.ptr.value != bind.ptr.value:
                merged_bindlist.append(copy.deepcopy(bind))
                last_bind = copy.deepcopy(bind)
            elif last_bind.lsb is None or bind.lsb is None or last_bind is None or bind.msb is None:
                merged_bindlist.append(copy.deepcopy(bind))
                last_bind = copy.deepcopy(bind)
            elif last_bind.lsb.value == bind.lsb.value and last_bind.msb.value == bind.msb.value:
                new_tree = self.mergeTree(last_bind.tree, bind.tree)
                new_tree = self.optimizer.optimize(new_tree)
                merged_bindlist.pop()
                new_bind = copy.deepcopy(bind)
                new_bind.tree = new_tree
                merged_bindlist.append(new_bind)
                last_bind = copy.deepcopy(new_bind)
            else:
                merged_bindlist.append(copy.deepcopy(bind))
                last_bind = copy.deepcopy(bind)
        return tuple(merged_bindlist)

    def mergeTree(self, first, second):
        if isinstance(first, DFBranch) and isinstance(second, DFBranch):
            cond_fst = self.optimizer.optimize(first.condnode)
            cond_snd = self.optimizer.optimize(second.condnode)
            if cond_fst == cond_snd:
                return DFBranch(
                    cond_fst, self.mergeTree(first.truenode, second.truenode),
                    self.mergeTree(first.falsenode, second.falsenode))
            appended = copy.deepcopy(first)
            return DFBranch(cond_snd, self.appendTail(appended,
                                                      second.truenode),
                            self.appendTail(appended, second.falsenode))

        if first is not None and second is None:
            return first
        if first is None and second is not None:
            return second

        if isinstance(first, DFBranch) and second is None:
            return first
        if first is None and isinstance(second, DFBranch):
            return second

        if isinstance(first, DFBranch) and not isinstance(second, DFBranch):
            cond_fst = self.optimizer.optimize(first.condnode)
            appended = copy.deepcopy(second)
            return DFBranch(cond_fst, self.appendTail(appended,
                                                      first.truenode),
                            self.appendTail(appended, first.falsenode))
        if not isinstance(first, DFBranch) and isinstance(second, DFBranch):
            cond_snd = self.optimizer.optimize(second.condnode)
            appended = copy.deepcopy(first)
            return DFBranch(cond_snd, self.appendTail(appended,
                                                      second.truenode),
                            self.appendTail(appended, second.falsenode))

        if not isinstance(first, DFBranch) and not isinstance(
                second, DFBranch):
            return second

        raise verror.FormatError('Can not merge trees.')

    def appendTail(self, appended, target):
        if target is None:
            return copy.deepcopy(appended)
        if isinstance(target, DFBranch):
            return DFBranch(target.condnode,
                            self.appendTail(appended, target.truenode),
                            self.appendTail(appended, target.falsenode))
        return target

    def splitBindlist(self, bindlist, split_positions):
        if len(bindlist) == 0: return ()
        return self.splitBindPositions(bindlist[0],
                                       split_positions) + self.splitBindlist(
                                           bindlist[1:], split_positions)

    def splitBindPositions(self, bind, split_positions):
        if len(split_positions) == 0: return (copy.deepcopy(bind), )
        if bind is None: return (copy.deepcopy(bind), )
        bind_left, bind_right = self.splitBind(bind, split_positions[0])
        ret = () if bind_right is None else (bind_right, )
        return ret + self.splitBindPositions(bind_left, split_positions[1:])

    def splitBind(self, bind, splitpos):
        tree = bind.tree
        msb = self.optimizer.optimizeConstant(bind.msb)
        lsb = self.optimizer.optimizeConstant(bind.lsb)
        ptr = self.optimizer.optimizeConstant(bind.ptr)
        if ptr is not None and msb is None or lsb is None:
            termtype = self.getTermtype(bind.dest)
            if signaltype.isRegArray(termtype) or signaltype.isWireArray(
                    termtype):
                msb = self.optimizer.optimizeConstant(copy.deepcopy(term.msb))
                lsb = self.optimizer.optimizeConstant(copy.deepcopy(term.lsb))
            else:
                msb = copy.deepcopy(ptr)
                lsb = copy.deepcopy(ptr)
        if ptr is None and msb is None or lsb is None:
            term = self.getTerm(bind.dest)
            msb = self.optimizer.optimizeConstant(copy.deepcopy(term.msb))
            lsb = self.optimizer.optimizeConstant(copy.deepcopy(term.lsb))
        if splitpos > lsb.value and splitpos <= msb.value:  # split
            right_lsb = lsb.value
            right_msb = splitpos - 1
            right_width = splitpos - lsb.value
            left_lsb = splitpos
            left_msb = msb.value
            left_width = msb.value - splitpos + 1
            right_tree = reorder.reorder(
                DFPartselect(copy.deepcopy(tree), DFEvalValue(right_width - 1),
                             DFEvalValue(0)))
            left_tree = reorder.reorder(
                DFPartselect(copy.deepcopy(tree), DFEvalValue(msb.value),
                             DFEvalValue(msb.value - left_width + 1)))
            right_tree = self.optimizer.optimize(right_tree)
            left_tree = self.optimizer.optimize(left_tree)
            left_bind = copy.deepcopy(bind)
            left_bind.tree = left_tree
            left_bind.msb = DFEvalValue(left_msb)
            left_bind.lsb = DFEvalValue(left_lsb)
            right_bind = copy.deepcopy(bind)
            right_bind.tree = right_tree
            right_bind.msb = DFEvalValue(right_msb)
            right_bind.lsb = DFEvalValue(right_lsb)
            return left_bind, right_bind
        return bind, None

    def splitPositions(self, bindlist):
        split_positions = set([])
        assigned_range = []  # (msb, lsb, ptr)

        for bind in bindlist:
            ptr = self.optimizer.optimizeConstant(bind.ptr)
            msb = self.optimizer.optimizeConstant(bind.msb)
            lsb = self.optimizer.optimizeConstant(bind.lsb)
            if msb is None and lsb is None:
                term = self.getTerm(bind.dest)
                msb = self.optimizer.optimizeConstant(term.msb)
                lsb = self.optimizer.optimizeConstant(term.lsb)
            elif not isinstance(msb, DFEvalValue) or not isinstance(
                    lsb, DFEvalValue):
                raise FormatError('MSB and LSB should be constant.')

            if ptr is None or isinstance(ptr, DFEvalValue):
                ptrval = None if ptr is None else ptr.value
                matched_range = self.matchedRange(tuple(assigned_range),
                                                  msb.value, lsb.value, ptrval)
                unmatched_range = self.unmatchedRange(tuple(matched_range),
                                                      msb.value, lsb.value,
                                                      ptrval)
                split_positions |= self.getPositionsFromRange(
                    matched_range, ptrval)
                assigned_range += matched_range + unmatched_range

        return tuple(sorted(list(split_positions)))

    def getPositionsFromRange(self, matched_range, search_ptr):
        positions = set([])
        for msb, lsb, ptr in matched_range:
            if search_ptr is not None and search != ptr: continue
            positions.add(lsb)
            positions.add(msb + 1)
        return positions

    def matchedRange(self, assigned_range, search_msb, search_lsb, search_ptr):
        matched_range = []
        for msb, lsb, ptr in assigned_range:
            match = False
            if search_ptr is not None and ptr != search_ptr: continue
            if lsb <= search_lsb and search_lsb <= msb:
                match = True
                match_lsb = search_lsb
            else:
                match_lsb = lsb
            if lsb <= search_msb and search_msb <= msb:
                match = True
                match_msb = search_msb
            else:
                match_msb = msb
            if match:
                matched_range.append((match_msb, match_lsb, search_ptr))
        return tuple(matched_range)

    def unmatchedRange(self, matched_range, search_msb, search_lsb,
                       search_ptr):
        unmatched_range = []
        minval = None
        maxval = None
        last_msb = None
        for msb, lsb, ptr in sorted(matched_range, key=lambda x: x[0]):
            if search_ptr is not None and ptr != search_ptr: continue
            if minval is None or lsb < minval: minval = lsb
            if maxval is None or msb > maxval: maxval = msb
            if last_msb is not None and last_msb + 1 > lsb:
                unmatched_range.append((last_msb + 1, lsb - 1, ptr))
            last_msb = msb
        if minval is None and maxval is None:
            return ((search_msb, search_lsb, search_ptr), )
        if search_lsb < minval:
            unmatched_range.append((search_lsb, minval - 1, search_ptr))
        if maxval < search_msb:
            unmatched_range.append((maxval + 1, search_msb, search_ptr))
        return tuple(unmatched_range)
Пример #11
0
class SignalVisitor(NodeVisitor):
    def __init__(self, moduleinfotable, top):
        self.moduleinfotable = moduleinfotable
        self.top = top
        self.frames = FrameTable()
        self.labels = Labels()
        self.optimizer = VerilogOptimizer({}, {})

        # set the top frame of top module
        self.stackInstanceFrame(top, top)

    ################################################################################
    def getFrameTable(self):
        return self.frames

    ################################################################################
    def start_visit(self):
        return self.visit(self.moduleinfotable.getDefinition(self.top))

    def visit_Input(self, node):
        self.frames.addSignal(node)

    def visit_Output(self, node):
        self.frames.addSignal(node)

    def visit_Inout(self, node):
        self.frames.addSignal(node)

    def visit_Reg(self, node):
        self.frames.addSignal(node)

    def visit_Wire(self, node):
        self.frames.addSignal(node)

    def visit_Supply(self, node):
        self.frames.addSignal(node)

    def visit_RegArray(self, node):
        self.frames.addSignal(node)

    def visit_WireArray(self, node):
        self.frames.addSignal(node)

    def visit_Tri(self, node):
        self.frames.addSignal(node)

    def visit_Integer(self, node):
        self.frames.addSignal(node)

    def visit_Parameter(self, node):
        self.frames.addConst(node)
        name = self.frames.getCurrent() + ScopeLabel(node.name, 'signal')
        if not self.hasConstant(name):
            value = self.optimize(self.getTree(node.value, self.frames.getCurrent()))
            self.setConstant(name, value)

    def visit_Localparam(self, node):
        self.frames.addConst(node)
        name = self.frames.getCurrent() + ScopeLabel(node.name, 'signal')
        if not self.hasConstant(name):
            value = self.optimize(self.getTree(node.value, self.frames.getCurrent()))
            self.setConstant(name, value)

    def visit_Genvar(self, node):
        self.frames.addConst(node)
        name = self.frames.getCurrent() + ScopeLabel(node.name, 'signal')
        if not self.hasConstant(name):
            value = DFEvalValue(0)
            self.setConstant(name, value)

    def visit_Function(self, node):
        self.frames.addFunction(node)
        self.frames.setFunctionDef()
        self.generic_visit(node)
        self.frames.unsetFunctionDef()

    def visit_Task(self, node):
        self.frames.addTask(node)
        self.frames.setTaskDef()
        self.generic_visit(node)
        self.frames.unsetTaskDef()

    def visit_Initial(self, node):
        pass
        #label = self.labels.get( self.frames.getLabelKey('initial') )
        #current = self.frames.addFrame(ScopeLabel(label, 'initial'),
        #                               generate=self.frames.isGenerate(),
        #                               initial=True)
        #self.generic_visit(node)
        #self.frames.setCurrent(current)

    def visit_InstanceList(self, node):
        for i in node.instances:
            self.visit(i)

    def visit_Instance(self, node):
        if node.array: return self._visit_Instance_array(node)
        nodename = node.name
        return self._visit_Instance_body(node, nodename)

    def _visit_Instance_array(self, node):
        if node.name == '':
            raise verror.FormatError("Module %s requires an instance name" % node.module)

        current = self.frames.getCurrent()
        msb = self.optimize(self.getTree(node.array.msb, current)).value
        lsb = self.optimize(self.getTree(node.array.lsb, current)).value

        for i in range(lsb, msb+1):
            nodename = node.name + '_' + str(i)
            self._visit_Instance_body(node, nodename)

    def _visit_Instance_body(self, node, nodename):
        if node.module in primitives: return self._visit_Instance_primitive(node)

        if nodename == '':
            raise verror.FormatError("Module %s requires an instance name" % node.module)

        current = self.stackInstanceFrame(nodename, node.module)

        self.setInstanceSimpleConstantTerms()

        scope = self.frames.getCurrent()

        paramnames = self.moduleinfotable.getParamNames(node.module)
        for paramnames_i, param in enumerate(node.parameterlist):
            paramname = paramnames[paramnames_i] if param.paramname is None else param.paramname
            if paramname not in paramnames:
                raise verror.FormatError("No such parameter: %s in %s" %
                                         (paramname, nodename))
            value = self.optimize(self.getTree(param.argname, current))
            name, definition = self.searchConstantDefinition(scope, paramname)
            self.setConstant(name, value)

        self.setInstanceConstants()
        self.setInstanceConstantTerms()

        self.visit(self.moduleinfotable.getDefinition(node.module))
        self.frames.setCurrent(current)

    def _visit_Instance_primitive(self, node):
        pass

    def visit_Always(self, node):
        label = self.labels.get( self.frames.getLabelKey('always') )
        current = self.frames.addFrame(ScopeLabel(label, 'always'),
                                       generate=self.frames.isGenerate(),
                                       always=True)
        self.generic_visit(node)
        self.frames.setCurrent(current)

    def visit_IfStatement(self, node):

        if (self.frames.isGenerate() and
            not self.frames.isAlways() and not self.frames.isInitial() and
            not self.frames.isFunctioncall() and not self.frames.isTaskcall() and
            not self.frames.isFunctiondef() and not self.frames.isTaskdef()):
            # generate-if statement
            current = self.frames.getCurrent()
            tree = self.getTree(node.cond, current)
            rslt = self.optimize(tree)
            if not isinstance(rslt, DFEvalValue):
                raise verror.FormatError("Can not resolve generate-if condition")
            if rslt.value > 0:
                label = self._if_true(node)
            else:
                label = self.labels.get( self.frames.getLabelKey('if') )
                self._if_false(node, label)
            return

        label = self._if_true(node)
        self._if_false(node, label)

    def _toELSE(self, label):
        return label + '_ELSE'

    def _if_true(self, node):
        if node.true_statement is None: return None
        label = self.labels.get( self.frames.getLabelKey('if') )
        current = self.frames.addFrame(ScopeLabel(label, 'if'),
                                       frametype='ifthen',
                                       condition=node.cond,
                                       functioncall=self.frames.isFunctioncall(),
                                       taskcall=self.frames.isTaskcall(),
                                       generate=self.frames.isGenerate(),
                                       always=self.frames.isAlways(),
                                       initial=self.frames.isInitial())
        self.visit(node.true_statement)
        self.frames.setCurrent(current)
        return label

    def _if_false(self, node, label):
        if node.false_statement is None: return
        label = self._toELSE(label)
        current = self.frames.addFrame(ScopeLabel(label, 'if'),
                                       frametype='ifelse',
                                       condition=node.cond,
                                       functioncall=self.frames.isFunctioncall(),
                                       taskcall=self.frames.isTaskcall(),
                                       generate=self.frames.isGenerate(),
                                       always=self.frames.isAlways(),
                                       initial=self.frames.isInitial())
        self.visit(node.false_statement)
        self.frames.setCurrent(current)
        return label

    def visit_CaseStatement(self, node):
        start_frame = self.frames.getCurrent()
        self._case(node.comp, node.caselist)
        self.frames.setCurrent(start_frame)

    def visit_CasexStatement(self, node):
        return self.visit_CaseStatement(node)
        
    def _case(self, comp, caselist):
        if len(caselist) == 0: return
        case = caselist[0]
        cond = IntConst('1')
        if case.cond is not None:
            if len(case.cond) > 1:
                cond = Eq(comp, case.cond[0])
                for c in case.cond[1:]:
                    cond = Lor(cond, Eq(comp, c))
            else:
                cond = Eq(comp, case.cond[0])
        label = self.labels.get( self.frames.getLabelKey('if') )
        current = self.frames.addFrame(ScopeLabel(label, 'if'),
                                       frametype='ifthen',
                                       condition=cond,
                                       functioncall=self.frames.isFunctioncall(),
                                       taskcall=self.frames.isTaskcall(),
                                       generate=self.frames.isGenerate(),
                                       always=self.frames.isAlways(),
                                       initial=self.frames.isInitial())
        if case.statement is not None: self.visit(case.statement)
        self.frames.setCurrent(current)
        if len(caselist) == 1: return
        label = self._toELSE(label)
        current = self.frames.addFrame(ScopeLabel(label, 'if'),
                                       frametype='ifelse',
                                       condition=cond,
                                       functioncall=self.frames.isFunctioncall(),
                                       taskcall=self.frames.isTaskcall(),
                                       generate=self.frames.isGenerate(),
                                       always=self.frames.isAlways(),
                                       initial=self.frames.isInitial())
        self._case(comp, caselist[1:])

    def visit_ForStatement(self, node):
        ## pre-statement
        current = self.frames.getCurrent()
        pre_right = self.getTree(node.pre.right, current)
        pre_right_value = self.optimize(pre_right)
        loop = pre_right_value.value
        self.frames.setForPre()
        self.visit(node.pre)
        self.frames.unsetForPre()
        label = self.labels.get( self.frames.getLabelKey('for') )
        #loop = 0
        while True:
            ## cond-statement
            current = self.frames.getCurrent()
            tree = self.getTree(node.cond, current)
            rslt = self.optimize(tree)
            if not isinstance(rslt, DFEvalValue):
                raise verror.FormatError(("Can not process the for-statement. "
                                          "for-condition should be evaluated statically."))
            # loop termination
            if rslt.value <= 0: break

            ## main-statement
            current = self.frames.addFrame(ScopeLabel(label, 'for', loop),
                                           frametype='for',
                                           functioncall=self.frames.isFunctioncall(),
                                           taskcall=self.frames.isTaskcall(),
                                           generate=self.frames.isGenerate(),
                                           always=self.frames.isAlways(),
                                           initial=self.frames.isInitial(),
                                           loop=loop, loop_iter=self.frames.getForIter())
            self.visit(node.statement)
            self.frames.setCurrent(current)

            ## post-statement
            current = self.frames.getCurrent()
            post_right = self.getTree(node.post.right, current)
            post_right_value = self.optimize(post_right)
            loop = post_right_value.value
            self.frames.setForPost()
            self.visit(node.post)
            self.frames.unsetForPost()
            #loop += 1

    def visit_WhileStatement(self, node):
        pass

    def visit_GenerateStatement(self, node):
        label = self.labels.get( self.frames.getLabelKey('generate') )
        current = self.frames.addFrame(ScopeLabel(label, 'generate'),
                                       generate=True)
        self.generic_visit(node)
        self.frames.setCurrent(current)

    def visit_Block(self, node):
        label = None
        if node.scope is not None:
            label = node.scope
        else:
            label = self.labels.get( self.frames.getLabelKey('block') )
        current = self.frames.addFrame(ScopeLabel(label, 'block'),
                                       frametype='block',
                                       functioncall=self.frames.isFunctioncall(),
                                       taskcall=self.frames.isTaskcall(),
                                       generate=self.frames.isGenerate(),
                                       always=self.frames.isAlways(),
                                       initial=self.frames.isInitial())
        self.generic_visit(node)
        self.frames.setCurrent(current)

    def visit_Assign(self, node):
        pass

    def visit_BlockingSubstitution(self, node):
        if self.frames.isForpre() or self.frames.isForpost():
            current = self.frames.getCurrent()
            name, definition = self.searchConstantDefinition(current,
                                                             node.left.var.name)
            value = self.optimize(self.getTree(node.right.var, current))
            self.setConstant(name, value)
            self.frames.setForIter(name)

    def visit_NonblockingSubstitution(self, node):
        pass

    ############################################################################
    def optimize(self, node):
        return self.optimizer.optimize(node)

    def stackInstanceFrame(self, instname, modulename):
        current = self.frames.addFrame(ScopeLabel(instname, 'module'), module=True,
                                       modulename=modulename)
        self.frames.updateSignal(self.moduleinfotable.getSignals(modulename))
        self.frames.updateConst(self.moduleinfotable.getConsts(modulename))
        return current

    def setInstanceSimpleConstantTerms(self):
        current = self.frames.getCurrent()
        for name, definitions in self.frames.getConsts(current).items():
            if len(definitions) > 1:
                raise verror.FormatError("Multiple definitions for Constant")
            for definition in definitions:
                simple_definition = copy.deepcopy(definition)
                if simple_definition.width is not None:
                    simple_definition.width.msb = None
                    simple_definition.width.lsb = None
                term = self.makeConstantTerm(name, simple_definition, current)
                self.setConstantTerm(name, term)

    def setInstanceConstantTerms(self):
        current = self.frames.getCurrent()
        for name, definitions in self.frames.getConsts(current).items():
            if len(definitions) > 1:
                raise verror.FormatError("Multiple definitions for Constant")
            for definition in definitions:
                term = self.makeConstantTerm(name, definition, current)
                self.setConstantTerm(name, term)

    def setInstanceConstants(self):
        current = self.frames.getCurrent()

        all_passed = False
        while not all_passed:
            all_passed = True
            for name, definitions in self.frames.getConsts(current).items():
                if len(definitions) > 1:
                    raise verror.FormatError("Multiple definitions for Constant")

                if self.hasConstant(name):
                    continue

                for definition in definitions:
                    if isinstance(definition, Genvar):
                        continue
                    value = self.optimize(self.getTree(definition.value, current))
                    if not isinstance(value, DFEvalValue):
                        all_passed = False
                        continue

                    self.setConstant(name, value)

    def setConstant(self, name, value):
        self.optimizer.setConstant(name, value)

    def getConstant(self, name):
        return self.optimizer.getConstant(name)

    def hasConstant(self, name):
        return self.optimizer.hasConstant(name)

    def setConstantTerm(self, name, term):
        self.optimizer.setTerm(name, term)

    def hasConstantTerm(self, name):
        self.optimizer.hasTerm(name)

    ############################################################################
    def toScopeChain(self, blocklabel):
        scopelist = []
        for b in blocklabel.labellist:
            if b.loop is not None:
                loop = self.optimize(b.loop)
                if not isinstance(loop, DFEvalValue):
                    raise verror.FormatError('Loop iterator should be constant')
                scopelist.append( ScopeLabel(b.name, 'for', loop) )
            scopelsit.append( ScopeLabel(b.name, 'any') )
        return ScopeChain( scopelist )

    def searchScopeConstantValue(self, blocklabel, name):
        currentmodule = self.frames.getCurrentModuleScopeChain()
        localchain = currentmodule[-1:] + self.toScopeChain(blocklabel)
        matchedchain = self.frames.searchMatchedScopeChain(currentmodule, localchain)
        varname = currentmodule[:-1] + matchedchain + ScopeLabel(name, 'signal')
        const = self.getConstant(varname)
        return const

    #def searchScopeConstantDefinition(self, blocklabel, name):
    #    currentmodule = self.frames.getCurrentModuleScopeChain()
    #    localchain = currentmodule[-1:] + self.toScopeChain(blocklabel)
    #    matchedchain = self.frames.searchMatchedScopeChain(currentmodule, localchain)
    #    constdef = self.frames.getConstantDefinition(matchedchain, name)
    #    return constdef

    def searchConstantDefinition(self, key, name):
        foundkey, founddef = self.frames.searchConstantDefinition(key, name)
        if foundkey is not None:
            return foundkey + ScopeLabel(name, 'signal'), founddef
        foundkey, founddef = self.frames.searchSignalDefinition(key, name)
        if foundkey is not None:
            return foundkey + ScopeLabel(name, 'signal'), founddef
        if foundkey is None:
            raise verror.DefinitionError('constant value not found: %s' % name)

    def searchConstantValue(self, key, name):
        foundkey, founddef = self.searchConstantDefinition(key, name)
        const = self.getConstant(foundkey)
        return const

    ############################################################################
    def makeConstantTerm(self, name, node, scope):
        termtype = node.__class__.__name__
        termtypes = set([termtype])
        msb = DFIntConst('31') if node.width is None else self.makeDFTree(node.width.msb, scope)
        lsb = DFIntConst('0') if node.width is None else self.makeDFTree(node.width.lsb, scope)
        return Term(name, termtypes, msb, lsb)

    def getTree(self, node, scope):
        expr = node.var if isinstance(node, Rvalue) else node
        return self.makeDFTree(expr, scope)

    def makeDFTree(self, node, scope):
        if isinstance(node, str):
            return self.searchConstantValue(scope, node)

        if isinstance(node, Identifier):
            if node.scope is not None:
                const = self.searchScopeConstantValue(node.scope, node.name)
                return const
            return self.searchConstantValue(scope, node.name)

        if isinstance(node, IntConst):
            return DFIntConst(node.value)

        if isinstance(node, FloatConst):
            return DFFloatConst(node.value)

        if isinstance(node, StringConst):
            return DFStringConst(node.value)

        if isinstance(node, Cond):
            true_df = self.makeDFTree(node.true_value, scope)
            false_df = self.makeDFTree(node.false_value, scope)
            cond_df = self.makeDFTree(node.cond, scope)
            if isinstance(cond_df, DFBranch):
                return reorder.insertCond(cond_df, true_df, false_df)
            return DFBranch(cond_df, true_df, false_df)

        if isinstance(node, UnaryOperator):
            right_df = self.makeDFTree(node.right, scope)
            if isinstance(right_df, DFBranch):
                return reorder.insertUnaryOp(right_df, node.__class__.__name__)
            return DFOperator((right_df,), node.__class__.__name__)

        if isinstance(node, Operator):
            left_df = self.makeDFTree(node.left, scope)
            right_df = self.makeDFTree(node.right, scope)
            if isinstance(left_df, DFBranch) or isinstance(right_df, DFBranch):
                return reorder.insertOp(left_df, right_df, node.__class__.__name__)
            return DFOperator((left_df, right_df,), node.__class__.__name__)

        if isinstance(node, Partselect):
            var_df = self.makeDFTree(node.var, scope)
            msb_df = self.makeDFTree(node.msb, scope)
            lsb_df = self.makeDFTree(node.lsb, scope)

            if isinstance(var_df, DFBranch):
                return reorder.insertPartselect(var_df, msb_df, lsb_df)
            return DFPartselect(var_df, msb_df, lsb_df)

        if isinstance(node, Pointer):
            var_df = self.makeDFTree(node.var, scope)
            ptr_df = self.makeDFTree(node.ptr, scope)

            if (isinstance(var_df, DFTerminal) and
                (signaltype.isRegArray(self.getTermtype(var_df.name)) or
                 signaltype.isWireArray(self.getTermtype(var_df.name)))):
                return DFPointer(var_df, ptr_df)
            return DFPartselect(var_df, ptr_df, copy.deepcopy(ptr_df))

        if isinstance(node, Concat):
            nextnodes = []
            for n in node.list:
                nextnodes.append(self.makeDFTree(n, scope))
            for n in nextnodes:
                if isinstance(n, DFBranch):
                    return reorder.insertConcat(tuple(nextnodes))
            return DFConcat(tuple(nextnodes))

        if isinstance(node, Repeat):
            nextnodes = []
            times = self.optimize(self.getTree(node.times, scope)).value
            value = self.makeDFTree(node.value, scope)
            for i in range(int(times)):
                nextnodes.append(copy.deepcopy(value))
            return DFConcat(tuple(nextnodes))

        if isinstance(node, SystemCall):
            if node.syscall == 'unsigned':
                return self.makeDFTree(node.args[0])
            if node.syscall == 'signed':
                return self.makeDFTree(node.args[0])
            return DFIntConst('0')

        raise verror.FormatError("unsupported AST node type: %s %s" %
                                 (str(type(node)), str(node)))