#-------------------------------------------------------------------------------
# dataflow.py
#
# Basic classes of Data flow nodes
#
# Copyright (C) 2013, Shinya Takamaeda-Yamazaki
# License: Apache 2.0
# Contributor: ryosuke fukatani
#-------------------------------------------------------------------------------
from __future__ import absolute_import
from __future__ import print_function
import sys
import os
import re
import copy

################################################################################
dfnodelist = ('DFIntConst', 'DFFloatConst', 'DFStringConst',
              'DFEvalValue', 'DFUndefined', 'DFHighImpedance',
              'DFTerminal',
              'DFBranch', 'DFOperator', 'DFPartselect', 'DFPointer',
              'DFConcat', 'DFDelay', 'DFSyscall')

def printIndent(s, indent=4):
    print((' ' * indent) + s)

def generateWalkTree(offset=1):
    base_indent = 4
    printIndent('def walkTree(tree):', base_indent*(0+offset))
    for df in dfnodelist:
        printIndent('if isinstance(tree, %s):' % df, base_indent * (1+offset))
        printIndent('pass', base_indent * (2+offset))

if __name__ == '__main__':
    generateWalkTree()
    exit()

################################################################################
import pyverilog.utils.verror as verror
import pyverilog.utils.util as util
import pyverilog.utils.signaltype as signaltype
import pyverilog.utils.op2mark as op2mark

################################################################################
class DFNode(object):
    attr_names = ()
    def __init__(self): pass
    def __repr__(self): pass
    def tostr(self): pass
    def tocode(self, dest='dest'): return self.__repr__()
    def tolabel(self): return self.__repr__()
    def children(self):
        nodelist = []
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return False
    def __ne__(self, other):
        return not self.__eq__(other)
    def __hash__(self):
        return id(self)

class DFTerminal(DFNode):
    attr_names = ('name',)
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        ret = ''
        for n in self.name:
            ret += str(n) + '.'
        return ret[:-1]
    def tostr(self):
        ret = '(Terminal '
        for n in self.name:
            ret += str(n) + '.'
        return ret[0:-1] + ')'
    def tocode(self, dest='dest'):
        #ret = ''
        #for n in self.name:
        #    ret += n.tocode() + '__'
        #return ret[:-2]
        return self.name.tocode()
    def tolabel(self):
        return self.tocode()
    def children(self):
        nodelist = []
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.name == other.name
    def __hash__(self):
        return hash(self.name)

class DFConstant(DFNode):
    attr_names = ('value',)
    def __init__(self, value):
        self.value = value
    def __repr__(self):
        return str(self.value)
    def tostr(self):
        ret = '(Constant ' + str(self.value) + ')'
        return ret
    def children(self):
        nodelist = []
        return tuple(nodelist)
    def eval(self):
        return None
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.value == other.value
    def __hash__(self):
        return hash(self.value)

class DFIntConst(DFConstant):
    def __init__(self, value):
        self.value = value
    def tostr(self):
        ret = '(IntConst ' + str(self.value) + ')'
        return ret
    def eval(self):
        targ = self.value.replace('_','')
        signed = False
        match = re.search(r's(.+)', targ)
        if match is not None:
            signed = True
        match = re.search(r'h(.+)', targ)
        if match is not None:
            return int(match.group(1), 16)
        match = re.search(r'd(.+)', targ)
        if match is not None:
            return int(match.group(1), 10)
        match = re.search(r'o(.+)', targ)
        if match is not None:
            return int(match.group(1), 8)
        match = re.search(r'b(.+)', targ)
        if match is not None:
            return int(match.group(1), 2)
        return int(targ, 10)
    def width(self):
        targ = self.value.replace('_','')
        match = re.search(r'(.+)\'h.+', targ)
        if match is not None:
            return int(match.group(1), 10)
        match = re.search(r'(.+)\'d.+', targ)
        if match is not None:
            return int(match.group(1), 10)
        match = re.search(r'(.+)\'o.+', targ)
        if match is not None:
            return int(match.group(1), 10)
        match = re.search(r'(.+)\'b.+', targ)
        if match is not None:
            return int(match.group(1), 10)
        return 32

class DFFloatConst(DFConstant):
    def __init__(self, value):
        self.value = value
    def tostr(self):
        ret = '(FloatConst ' + str(self.value) + ')'
        return ret
    def eval(self):
        return float(self.value)

class DFStringConst(DFConstant):
    def __init__(self, value):
        self.value = value
    def tostr(self):
        ret = '(StringConst ' + str(self.value) + ')'
        return ret
    def eval(self):
        return self.value

################################################################################
class DFNotTerminal(DFNode): pass

class DFOperator(DFNotTerminal):
    attr_names = ('operator',)
    def __init__(self, nextnodes, operator):
        self.nextnodes = nextnodes
        self.operator = operator

        for n in nextnodes:
            if n is None: raise verror.DefinitionError()

    def __repr__(self):
        return self.operator
    def tostr(self):
        ret = '(Operator ' + self.operator
        ret += ' Next:'
        for n in self.nextnodes: ret += n.tostr() + ','
        ret = ret[0:-1] + ')'
        return ret
    def tocode(self, dest='dest'):
        ret = ''
        if len(self.nextnodes) > 1:
            ret += '(' + self.nextnodes[0].tocode(dest)
            ret += op2mark.op2mark(self.operator)
            ret += self.nextnodes[1].tocode(dest) + ')'
        else:
            ret += '(' + op2mark.op2mark(self.operator)
            ret += self.nextnodes[0].tocode(dest) + ')'
        return ret
    def children(self):
        nodelist = []
        if self.nextnodes is not None: nodelist.extend(self.nextnodes)
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.operator == other.operator and self.nextnodes == other.nextnodes
    def __hash__(self):
        return hash((self.operator, tuple(self.nextnodes)))

class DFPartselect(DFNotTerminal):
    attr_names = ()
    def __init__(self, var, msb, lsb):
        self.var = var
        self.msb = msb
        self.lsb = lsb
    def __repr__(self):
        return 'PartSelect'
    def tostr(self):
        ret = '(Partselect'
        ret += ' Var:' + self.var.tostr()
        ret += ' MSB:' + self.msb.tostr()
        ret += ' LSB:' + self.lsb.tostr()
        ret += ')'
        return ret
    def tocode(self, dest='dest'):
        ret = self.var.tocode(dest)
        msbcode = self.msb.tocode(dest)
        lsbcode = self.lsb.tocode(dest)
        if msbcode == lsbcode:
            ret += '[' + msbcode + ']'
        else:
            ret += '[' + msbcode
            ret += ':' + lsbcode + ']'
        return ret
    def children(self):
        nodelist = []
        if self.var is not None: nodelist.append(self.var)
        if self.msb is not None: nodelist.append(self.msb)
        if self.lsb is not None: nodelist.append(self.lsb)
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.var == other.var and self.msb == other.msb and self.lsb == other.lsb
    def __hash__(self):
        return hash((self.var, self.msb, self.lsb))

class DFPointer(DFNotTerminal):
    attr_names = ()
    def __init__(self, var, ptr):
        self.var = var
        self.ptr = ptr
    def __repr__(self):
        return 'Pointer'
    def tostr(self):
        ret = '(Pointer'
        ret += ' Var:' + self.var.tostr()
        ret += ' PTR:' + self.ptr.tostr()
        ret += ')'
        return ret
    def tocode(self, dest='dest'):
        ret = self.var.tocode(dest)
        ret += '[' + self.ptr.tocode(dest) + ']'
        return ret
    def children(self):
        nodelist = []
        if self.var is not None: nodelist.append(self.var)
        if self.ptr is not None: nodelist.append(self.ptr)
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.var == other.var and self.ptr == other.ptr
    def __hash__(self):
        return hash((self.var, self.ptr))

class DFConcat(DFNotTerminal):
    attr_names = ()
    def __init__(self, nextnodes):
        self.nextnodes = nextnodes
    def __repr__(self):
        return 'Concat'
    def tostr(self):
        ret = '(Concat'
        ret += ' Next:'
        for n in self.nextnodes: ret += n.tostr() + ','
        ret = ret[0:-1] + ')'
        return ret
    def tocode(self, dest='dest'):
        ret = '{'
        for n in self.nextnodes: ret += n.tocode(dest) + ','
        ret = ret[:-1]
        ret += '}'
        return ret
    def children(self):
        nodelist = []
        if self.nextnodes is not None: nodelist.extend(self.nextnodes)
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.nextnodes == other.nextnodes
    def __hash__(self):
        return hash(tuple(self.nextnodes))

################################################################################
class DFBranch(DFNotTerminal):
    attr_names = ()
    def __init__(self, condnode, truenode, falsenode):
        self.condnode = condnode
        self.truenode = truenode
        self.falsenode = falsenode
    def __repr__(self):
        return 'Branch'
    def tostr(self):
        ret = '(Branch'
        if self.condnode is not None: ret += ' Cond:' + self.condnode.tostr()
        if self.truenode is not None: ret += ' True:' + self.truenode.tostr()
        if self.falsenode is not None: ret += ' False:'+ self.falsenode.tostr()
        ret += ')'
        return ret
    def tocode(self, dest='dest', always=''):
        if always == 'clockedge': return self._tocode_always(dest, always)
        if always == 'combination': return self._tocode_always(dest, always)
        ret = '('
        if self.condnode is not None: ret += '(' + self.condnode.tocode(dest) + ')'
        ret += '? '
        if self.truenode is not None: ret += self.truenode.tocode(dest)
        else: ret += dest
        ret += " : "
        if self.falsenode is not None: ret += self.falsenode.tocode(dest)
        else: ret += dest
        ret += ")"
        return ret
    def _tocode_always(self, dest='dest', always='clockedge'):
        ret = 'if('
        if self.condnode is not None: ret += self.condnode.tocode(dest)
        ret += ') begin\n'
        if self.truenode is not None:
            if isinstance(self.truenode, DFBranch):
                ret += self.truenode.tocode(dest, always=always)
            elif always == 'clockedge':
                ret += dest + ' <= ' + self.truenode.tocode(dest) + ';\n'
            elif always == 'combination':
                ret += dest + ' = ' + self.truenode.tocode(dest) + ';\n'
        ret += 'end\n'
        if self.falsenode is not None:
            ret += 'else begin\n'
            if isinstance(self.falsenode, DFBranch):
                ret += self.falsenode.tocode(dest, always=always)
            elif always == 'clockedge':
                ret += dest + ' <= ' + self.falsenode.tocode(dest) + ';\n'
            elif always == 'combination':
                ret += dest + ' = ' + self.falsenode.tocode(dest) + ';\n'
            ret += 'end\n'
        return ret
    def children(self):
        nodelist = []
        if self.truenode is not None: nodelist.append(self.truenode)
        if self.condnode is not None: nodelist.append(self.condnode)
        if self.falsenode is not None: nodelist.append(self.falsenode)
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.condnode == other.condnode and self.truenode == other.truenode and self.falsenode == other.falsenode
    def __hash__(self):
        return hash((self.condnode, self.truenode, self.falsenode))

################################################################################
class DFEvalValue(DFNode):
    attr_names = ('value', 'width',)
    def __init__(self, value, width=32, isfloat=False, isstring=False):
        self.value = value
        self.width = width
        self.isfloat = isfloat
        self.isstring = isstring
    def __repr__(self):
        if self.isstring:
            return self.value
        ret = ''
        if self.value < 0: ret += '(-'
        if self.width != 32: ret += str(self.width)
        ret += "'d"
        ret += str(abs(self.value))
        if self.value < 0: ret += ')'
        return ret
    def tostr(self):
        if self.isstring:
            return self.value
        ret = ''
        if self.value < 0: ret += '(-'
        if self.width != 32: ret += str(self.width)
        ret += "'d"
        ret += str(abs(self.value))
        if self.value < 0: ret += ')'
        return ret
    def tocode(self, dest='dest'):
        return self.__repr__()
    def children(self):
        nodelist = []
        return tuple(nodelist)
    def eval(self):
        return self.value
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.value == other.value and self.width == other.width and self.isfloat == other.isfloat and self.isstring == other.isstring
    def __hash__(self):
        return hash((self.value, self.width, self.isfloat, self.isstring))

class DFUndefined(DFNode):
    attr_names = ('width',)
    def __init__(self, width):
        self.width = width
    def __repr__(self):
        ret = ''
        if self.width != 32: ret += str(self.width)
        ret += "'d"
        ret += 'x'
        return ret
    def tostr(self):
        ret = ''
        if self.width != 32: ret += str(self.width)
        ret += "'d"
        ret += 'x'
        return ret
    def children(self):
        nodelist = []
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.width == other.width
    def __hash__(self):
        return hash(self.width)

class DFHighImpedance(DFNode):
    attr_names = ('width',)
    def __init__(self, width):
        self.width = width
    def __repr__(self):
        ret = ''
        if self.width != 32: ret += str(self.width)
        ret += "'d"
        ret += 'z'
        return ret
    def tostr(self):
        ret = ''
        if self.width != 32: ret += str(self.width)
        ret += "'d"
        ret += 'z'
        return ret
    def children(self):
        nodelist = []
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.width == other.width
    def __hash__(self):
        return hash(self.width)

################################################################################
class DFDelay(DFNotTerminal):
    attr_names = ()
    def __init__(self, nextnode):
        self.nextnode = nextnode
    def __repr__(self):
        return 'Delay'
    def tostr(self):
        ret = '(Delay '
        if self.nextnode is not None: ret += self.nextnode.tostr()
        ret += ')'
        return ret
    def tocode(self, dest='dest'):
        raise verror.DefinitionError('DFDelay does not support tocode()')
    def children(self):
        nodelist = []
        if self.nextnode is not None: nodelist.append(self.nextnode)
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.nextnodes == other.nextnodes
    def __hash__(self):
        return hash(tuple(self.nextnodes))

################################################################################
class DFSyscall(DFNotTerminal):
    attr_names = ()
    def __init__(self, syscall, nextnodes):
        self.syscall = syscall
        self.nextnodes = nextnodes
    def __repr__(self):
        return 'Syscall'
    def tostr(self):
        ret = '(Syscall '
        ret += self.syscall
        ret += ' Next:'
        for n in self.nextnodes: ret += n.tostr() + ','
        ret = ret[0:-1] + ')'
        return ret
    def tocode(self, dest='dest'):
        ret = '$' + self.syscall + '('
        for n in self.nextnodes: ret += n.tocode(dest) + ','
        ret = ret[:-1]
        ret += ')'
        return ret
    def children(self):
        nodelist = []
        if self.nextnodes is not None: nodelist.extend(self.nextnodes)
        return tuple(nodelist)
    def __eq__(self, other):
        if type(self) != type(other): return False
        if self.syscall != other.syscall: return False
        return self.nextnodes == other.nextnodes
    def __hash__(self):
        return hash(tuple(self.nextnodes))

################################################################################
class Term(object):
    def __init__(self,name,termtype=(),msb=None,lsb=None,lenmsb=None,lenlsb=None):
        self.name = name # tuple (str)
        self.termtype = termtype # set (str)
        self.msb = msb # DFNode
        self.lsb = lsb # DFNode
        self.lenmsb = lenmsb # DFNode
        self.lenlsb = lenlsb # DFNode
    def __repr__(self):
        return str(self.name)
    def tostr(self):
        ret = '(Term name:' + str(self.name) + ' type:' + str(sorted(self.termtype, key=lambda x:str(x)))
        if self.msb is not None: ret += ' msb:' + self.msb.tostr()
        if self.lsb is not None: ret += ' lsb:' + self.lsb.tostr()
        if self.lenmsb is not None: ret += ' lenmsb:' + self.lenmsb.tostr()
        if self.lenlsb is not None: ret += ' lenlsb:' + self.lenlsb.tostr()
        ret += ')'
        return ret
    def __ne__(self, other):
        return not self.__eq__(other)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.name == other.name and self.termtype == other.termtype and self.msb == other.msb and self.lsb == other.lsb and self.lenmsb == other.lenmsb and self.lenlsb == other.lenlsb
    def __hash__(self):
        return hash((self.name, self.termtype, self.msb, self.lsb, self.lenmsb, self.lenlsb))

    ############################################################################
    def getScope(self, termname):
        return termname[:-1]

    def isTopmodule(self, scope):
        if len(scope)==1: return True
        return False

    ############################################################################
    def tocode(self):
        flatname = util.toFlatname(self.name)
        scope = self.getScope(self.name)
        code = ''
        if self.isTopmodule(scope):
            if signaltype.isInput(self.termtype): code += 'input '
            elif signaltype.isInout(self.termtype): code += 'inout '
            elif signaltype.isOutput(self.termtype): code += 'output '
        else:
            if signaltype.isInput(self.termtype): code += 'wire '
            elif signaltype.isInout(self.termtype): code += 'wire '
            elif signaltype.isOutput(self.termtype) and not signaltype.isReg(self.termtype): code += 'wire '

        if signaltype.isReg(self.termtype): code += 'reg '
        if signaltype.isRegArray(self.termtype): code += 'reg '
        if signaltype.isWire(self.termtype): code += 'wire '
        if signaltype.isWireArray(self.termtype): code += 'wire '
        if signaltype.isInteger(self.termtype): code += 'integer '
        if signaltype.isFunction(self.termtype): code += 'wire '
        if signaltype.isRename(self.termtype): code += 'wire '

        if (not signaltype.isInteger(self.termtype) and
            self.msb is not None and self.lsb is not None):
            code += '[' + self.msb.tocode(None) + ':' + self.lsb.tocode(None) + '] '
        code += flatname # signal name
        if self.lenmsb is not None and self.lenlsb is not None:
            code += ' [' + self.lenmsb.tocode() + ':' + self.lenlsb.tocode(flatname) + ']'
        code += ';\n'
        return code

################################################################################
class Bind(object):
    def __init__(self, tree, dest, msb=None, lsb=None, ptr=None, alwaysinfo=None, parameterinfo=''):
        self.tree = tree
        self.dest = dest
        self.msb = msb
        self.lsb = lsb
        self.ptr = ptr
        self.alwaysinfo = alwaysinfo
        self.parameterinfo = parameterinfo
        if dest is None: raise verror.DefinitionError('Bind dest is empty')

    def __ne__(self, other):
        return not self.__eq__(other)
    def __eq__(self, other):
        if type(self) != type(other): return False
        return self.tree == other.tree and self.dest == other.dest and self.msb == other.msb and self.lsb == other.lsb and self.ptr == other.ptr and self.alwaysinfo == other.alwaysinfo and self.parameterinfo == other.parameterinfo
    def __hash__(self):
        return hash((self.tree, self.dest, self.msb, self.lsb, self.ptr, self.alwaysinfo, self.parameterinfo))

    def isCombination(self):
        if self.alwaysinfo is None: return True
        if self.alwaysinfo.isCombination(): return True
        return False

    def tostr(self):
        ret = '(Bind'
        if self.dest is not None: ret += ' dest:' + str(self.dest)
        if self.msb is not None: ret += ' msb:' + self.msb.tostr()
        if self.lsb is not None: ret += ' lsb:' + self.lsb.tostr()
        if self.ptr is not None: ret += ' ptr:' + self.ptr.tostr()
        if self.tree is not None: ret += ' tree:' + self.tree.tostr()
        ret += ')'
        return ret

    def tocode(self):
        if self.parameterinfo == 'parameter': return self._parameter()
        if self.parameterinfo == 'localparam': return self._localparam()
        if self.alwaysinfo is None: return self._assign()
        if self.alwaysinfo.isCombination(): return self._always_combination()
        else: return self._always_clockedge()

    def getdest(self):
        dest = util.toFlatname(self.dest)
        if self.ptr is not None:
            dest += '[' + self.ptr.tocode(None) + ']'
        if self.msb is not None and self.lsb is not None:
            msbcode = self.msb.tocode(None)
            lsbcode = self.lsb.tocode(None)
            if msbcode == lsbcode:
                dest += '[' + msbcode + ']'
            else:
                dest += '[' + msbcode + ':' + lsbcode + ']'
        return dest

    def _parameter(self):
        dest = self.getdest()
        code = 'parameter ' + dest
        code += ' = ' + self.tree.tocode(dest) + ';\n'
        return code

    def _localparam(self):
        dest = self.getdest()
        code = 'localparam ' + dest
        code += ' = ' + self.tree.tocode(dest) + ';\n'
        return code

    def _assign(self):
        dest = self.getdest()
        code = 'assign ' + dest
        code += ' = ' + self.tree.tocode(dest) + ';\n'
        return code

    def _always_clockedge(self):
        dest = self.getdest()
        code = 'always @('
        if self.alwaysinfo.clock_edge is not None and self.alwaysinfo.clock_name is not None:
            code += self.alwaysinfo.clock_edge + ' '
            code += util.toFlatname(self.alwaysinfo.clock_name)
        if self.alwaysinfo.reset_edge is not None and self.alwaysinfo.reset_name is not None:
            code += ' or '
            code += self.alwaysinfo.reset_edge + ' '
            code += util.toFlatname(self.alwaysinfo.reset_name)
        code += ') begin\n'
        if isinstance(self.tree, DFBranch):
            code += self.tree.tocode(dest, always='clockedge')
        else:
            code += dest
            code += ' <= ' + self.tree.tocode(dest) + ';\n'
        code += 'end\n'
        code += '\n'
        return code

    def _always_combination(self):
        dest = self.getdest()
        code = ''
        code += 'always @*'
        code += ' begin\n'
        if isinstance(self.tree, DFBranch):
            code += self.tree.tocode(dest, always='combination')
        else:
            code += dest
            code += ' = ' + self.tree.tocode(dest) + ';\n'
        code += 'end\n'
        code += '\n'
        return code

    def isClockEdge(self):
        if self.alwaysinfo is None: return False
        return self.alwaysinfo.isClockEdge()
    def getClockName(self):
        if self.alwaysinfo is None: return ''
        return self.alwaysinfo.getClockName()
    def getClockEdge(self):
        if self.alwaysinfo is None: return ''
        return self.alwaysinfo.getClockEdge()
    def getClockBit(self):
        if self.alwaysinfo is None: return ''
        return self.alwaysinfo.getClockBit()
    def getResetName(self):
        if self.alwaysinfo is None: return ''
        return self.alwaysinfo.getResetName()
    def getResetEdge(self):
        if self.alwaysinfo is None: return ''
        return self.alwaysinfo.getResetEdge()
    def getResetBit(self):
        if self.alwaysinfo is None: return ''
        return self.alwaysinfo.getResetBit()
    def getSenslist(self):
        if self.alwaysinfo is None: return ''
        return self.alwaysinfo.getSenslist()

################################################################################
class DataFlow(object):
    def __init__(self):
        self.terms = {}
        self.binddict = {}

        self.functions = {}
        self.function_ports = {}
        self.tasks = {}
        self.task_ports = {}
        self.temporal_value = {}

    ############################################################################
    def addTerm(self, name, term):
        if not name in self.terms:
            self.terms[name] = term
        else:
            self.setTerm(name, term)

    def setTerm(self, name, term):
        self.terms[name].termtype |= term.termtype
        if self.terms[name].msb is None: self.terms[name].msb = term.msb
        if self.terms[name].lsb is None: self.terms[name].lsb = term.lsb
        if self.terms[name].lenmsb is None: self.terms[name].lenmsb = term.lenmsb
        if self.terms[name].lenlsb is None: self.terms[name].lenlsb = term.lenlsb

    def hasTerm(self, name):
        return name in self.terms

    def getTerm(self, name):
        if name in self.terms: return self.terms[name]
        return None

    def getTerms(self):
        return self.terms

    ############################################################################
    def addBind(self, name, bind):
        if name is None:
            raise verror.DefinitionError('Bind name is empty')
        if not name in self.binddict:
            self.binddict[name] = [bind,]
        else:
            self.setBind(name, bind)

    def setBind(self, name, bind):
        if name is None:
            raise verror.DefinitionError('Bind name is empty')
        currentbindlist = self.binddict[name]
        c_i = 0
        for c in currentbindlist:
            if c.msb == bind.msb and c.lsb == bind.lsb and c.ptr == bind.ptr:
                self.binddict[name][c_i].tree = bind.tree
                return
            c_i += 1
        self.binddict[name] = currentbindlist + [bind,]

    def getBindlist(self, name):
        if name in self.binddict: return tuple(self.binddict[name])
        return ()

    def getBinddict(self):
        return self.binddict

    ############################################################################
    def addFunction(self, name, definition):
        self.functions[name] = definition
    def hasFunction(self, name):
        return name in self.functions
    def getFunction(self, name):
        if name in self.functions: return self.functions[name]
        return None
    def addFunctionPorts(self, name, ports):
        self.function_ports[name] = ports
    def getFunctionPorts(self, name):
        if name in self.function_ports: return self.function_ports[name]
        return ()

    ############################################################################
    def addTask(self, name, definition):
        self.tasks[name] = definition
    def hasTask(self, name):
        return name in self.tasks
    def getTask(self, name):
        if name in self.tasks: return self.tasks[name]
        return None
    def addTaskPorts(self, name, ports):
        self.task_ports[name] = ports
    def getTaskPorts(self, name):
        if name in self.task_ports: return self.task_ports[name]
        return ()

    ############################################################################
    def setTemporalValue(self, name, value):
        self.temporal_value[name] = value
    def getTemporalValue(self, name):
        return self.temporal_value[name]

